From patchwork Mon Feb 10 19:30:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 208801 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.9 required=3.0 tests=DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C2D33C3B186 for ; Mon, 10 Feb 2020 19:31:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9407124672 for ; Mon, 10 Feb 2020 19:31:03 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="mqEHj3cJ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727695AbgBJTbD (ORCPT ); Mon, 10 Feb 2020 14:31:03 -0500 Received: from mail-oi1-f195.google.com ([209.85.167.195]:40426 "EHLO mail-oi1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727682AbgBJTbC (ORCPT ); Mon, 10 Feb 2020 14:31:02 -0500 Received: by mail-oi1-f195.google.com with SMTP id a142so10342368oii.7 for ; Mon, 10 Feb 2020 11:31:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Hedv3uQpLYtG/8d40iSwsTwWwbRFJKr8vrN4ZiDg04Q=; b=mqEHj3cJctfFXlmy16cRdbd3ZRwBg+PBoqBPYVmqQH/qHbN5NUcjIYDQxGJmRKQ7wa Gh/oTcwv3s+WJTQGeN5oXvRGmYE52sD2Oy62uw9zNjtHK9oLi+CKMUz2V13jB1bNCceN HKebkK1prPWHrTSh29Rcs3l4gWJQcq2tOzhxQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Hedv3uQpLYtG/8d40iSwsTwWwbRFJKr8vrN4ZiDg04Q=; b=aK6UjWR9FYZtDTR09eE2Ugh0mww48F88BsKGuieZDDO64ONBCsGCx0Iu2ovAUl7afN aAslFnxazx0APtklzs94tJPCSMkGmgT5rs9dQZfMfmtGpxMt6zmwKwf3SxiNxGDQt/uW GsB8O3gPVaZJE0+2AEmD49D8v/iOg8lS02qI2TtaAm2WXUBWKd7hCsiHG+3scA/ry78v j6DOx6G1qEzUc/0EECaY4WjR2+pVOwUxL2JN7odWZHvZcQt96TWxAPavz0eEkvLHikI9 pcd8P8geBiyEKQtpM4Wl9LHKo8pgptDQJHAES5zx9kti/cxCZm26F4gsiQUoqR4hnf/j kbVA== X-Gm-Message-State: APjAAAX5IcSmSACO/PjRS/JANG3jlsZ27uH2hPbtgSi70KitDA+THf77 Oxt+gSyRRl30tiyoUp0uiuDMZg== X-Google-Smtp-Source: APXvYqxzrrMjKkyUG9U1mzxeIF/mXf4CdliJjd23xPg8Q25YEpKS/E/iAhQV5XTWVKedZ6gqCTRpxg== X-Received: by 2002:aca:be57:: with SMTP id o84mr419172oif.138.1581363061318; Mon, 10 Feb 2020 11:31:01 -0800 (PST) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id v23sm359350otj.61.2020.02.10.11.30.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 10 Feb 2020 11:30:58 -0800 (PST) From: Kees Cook To: Ingo Molnar Cc: Kees Cook , Hector Marco-Gisbert , Catalin Marinas , Will Deacon , Jason Gunthorpe , Jann Horn , Russell King , x86@kernel.org, kernel-hardening@lists.openwall.com, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH v3 3/7] x86/elf: Disable automatic READ_IMPLIES_EXEC for 64-bit address spaces Date: Mon, 10 Feb 2020 11:30:45 -0800 Message-Id: <20200210193049.64362-4-keescook@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200210193049.64362-1-keescook@chromium.org> References: <20200210193049.64362-1-keescook@chromium.org> MIME-Version: 1.0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org With modern x86 64-bit environments, there should never be a need for automatic READ_IMPLIES_EXEC, as the architecture is intended to always be execute-bit aware (as in, the default memory protection should be NX unless a region explicitly requests to be executable). There were very old x86_64 systems that lacked the NX bit, but for those, the NX bit is, obviously, unenforceable, so these changes should have no impact on them. Suggested-by: Hector Marco-Gisbert Signed-off-by: Kees Cook --- arch/x86/include/asm/elf.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h index a7035065377c..c9b7be0bcad3 100644 --- a/arch/x86/include/asm/elf.h +++ b/arch/x86/include/asm/elf.h @@ -287,7 +287,7 @@ extern u32 elf_hwcap2; *              CPU: | lacks NX*  | has NX, ia32     | has NX, x86_64 | * ELF:              |            |                  |                | * -------------------------------|------------------|----------------| - * missing GNU_STACK | exec-all   | exec-all         | exec-all       | + * missing GNU_STACK | exec-all   | exec-all         | exec-none      | * GNU_STACK == RWX  | exec-stack | exec-stack       | exec-stack     | * GNU_STACK == RW   | exec-none  | exec-none        | exec-none      | * @@ -303,7 +303,7 @@ extern u32 elf_hwcap2; * */ #define elf_read_implies_exec(ex, executable_stack) \ - (executable_stack == EXSTACK_DEFAULT) + (mmap_is_ia32() && executable_stack == EXSTACK_DEFAULT) struct task_struct; From patchwork Mon Feb 10 19:30:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 208800 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.9 required=3.0 tests=DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6A011C3B188 for ; Mon, 10 Feb 2020 19:31:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 3963421569 for ; Mon, 10 Feb 2020 19:31:04 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="L4WYG666" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727707AbgBJTbD (ORCPT ); Mon, 10 Feb 2020 14:31:03 -0500 Received: from mail-ot1-f65.google.com ([209.85.210.65]:46190 "EHLO mail-ot1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727692AbgBJTbC (ORCPT ); Mon, 10 Feb 2020 14:31:02 -0500 Received: by mail-ot1-f65.google.com with SMTP id g64so7521617otb.13 for ; Mon, 10 Feb 2020 11:31:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Xgo1yExYE1FoOrHi/q0yB3FWShMft6x5k4WGrQxm170=; b=L4WYG666B6q1Et3bcdlnVISVkOrsiaz/021i2HOtSDO+5jbbvUU8qOhFuAJpImd9Of tHvcCRS71nZ2E2PCYI1v1I7/5Fx8qC14IBkh3bZudUkhVCFVSTRXv68LgS4rolJ8b7NO oy2IjZYniOec+89rewQ3DeqzhHAbfLUi9rvdA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Xgo1yExYE1FoOrHi/q0yB3FWShMft6x5k4WGrQxm170=; b=p04vkuCAlGXjT6423ohmZ0eXyJ+bOhyT4CxoZquJFEaoWDlpzstsK+TZTofYo2ELWI fWoIUDI9g9aNOaN+P3dXV3hVCIah0fpbdWFS8tEmHCHX+Ch1UzXm6hbflInOn7AHptyf N27cfYGk1T6TN8jYVgQ5Ye70jgrWyGH0Q6fJoatNDkeUCoQ3a5cPR1inWPFI4Mer5mPo /1cx9Pae3D6vu8XHWQoQrdIkDoccF49JVYmiOMidqsegt50eLmG4ept6czv6pgsZu3Lr ZNI1YpuGFBdRjPRz1hxqif9Nr1JtCj5dqClIXeiOkNhrD0Gtsb3wXt0gG9bn8fEHKQ9j cJfg== X-Gm-Message-State: APjAAAVo3yjyQADS7x5Wfo7evzYOFjptasNGZu7hwSjCijaaKBGnGnMN YHWpQXP1NrhmMQBL6dRBnXMP/g== X-Google-Smtp-Source: APXvYqxrCRbeRObAKsREPcdxJmg1NESdR+jwjL0VLXI5HeLb3NvoJQshGJ4OJNNqOglQAXv1YayQEA== X-Received: by 2002:a9d:6e8f:: with SMTP id a15mr2204441otr.178.1581363060517; Mon, 10 Feb 2020 11:31:00 -0800 (PST) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id b145sm356027oii.31.2020.02.10.11.30.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 10 Feb 2020 11:30:58 -0800 (PST) From: Kees Cook To: Ingo Molnar Cc: Kees Cook , Hector Marco-Gisbert , Catalin Marinas , Will Deacon , Jason Gunthorpe , Jann Horn , Russell King , x86@kernel.org, kernel-hardening@lists.openwall.com, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH v3 4/7] arm32/64, elf: Add tables to document READ_IMPLIES_EXEC Date: Mon, 10 Feb 2020 11:30:46 -0800 Message-Id: <20200210193049.64362-5-keescook@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200210193049.64362-1-keescook@chromium.org> References: <20200210193049.64362-1-keescook@chromium.org> MIME-Version: 1.0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org Add tables to document the current behavior of READ_IMPLIES_EXEC in preparation for changing the behavior for both arm64 and arm. Signed-off-by: Kees Cook --- arch/arm/kernel/elf.c | 24 +++++++++++++++++++++--- arch/arm64/include/asm/elf.h | 20 ++++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/arch/arm/kernel/elf.c b/arch/arm/kernel/elf.c index 182422981386..2f69cf978fe3 100644 --- a/arch/arm/kernel/elf.c +++ b/arch/arm/kernel/elf.c @@ -78,9 +78,27 @@ void elf_set_personality(const struct elf32_hdr *x) EXPORT_SYMBOL(elf_set_personality); /* - * Set READ_IMPLIES_EXEC if: - * - the binary requires an executable stack - * - we're running on a CPU which doesn't support NX. + * An executable for which elf_read_implies_exec() returns TRUE will + * have the READ_IMPLIES_EXEC personality flag set automatically. + * + * The decision process for determining the results are: + * + *              CPU: | lacks NX*  | has NX | + * ELF:              |            |           | + * -------------------------------|------------| + * missing GNU_STACK | exec-all   | exec-all  | + * GNU_STACK == RWX  | exec-all   | exec-all  | + * GNU_STACK == RW   | exec-all  | exec-none | + * + * exec-all : all PROT_READ user mappings are executable, except when + * backed by files on a noexec-filesystem. + * exec-none : only PROT_EXEC user mappings are executable. + * + * *this column has no architectural effect: NX markings are ignored by + * hardware, but may have behavioral effects when "wants X" collides with + * "cannot be X" constraints in memory permission flags, as in + * https://lkml.kernel.org/r/20190418055759.GA3155@mellanox.com + * */ int arm_elf_read_implies_exec(int executable_stack) { diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h index b618017205a3..7fc779e3f1ec 100644 --- a/arch/arm64/include/asm/elf.h +++ b/arch/arm64/include/asm/elf.h @@ -96,6 +96,26 @@ */ #define elf_check_arch(x) ((x)->e_machine == EM_AARCH64) +/* + * An executable for which elf_read_implies_exec() returns TRUE will + * have the READ_IMPLIES_EXEC personality flag set automatically. + * + * The decision process for determining the results are: + * + *             CPU*: | arm32    | arm64 | + * ELF:              |            |            | + * -------------------------------|------------| + * missing GNU_STACK | exec-all   | exec-all   | + * GNU_STACK == RWX  | exec-all   | exec-all   | + * GNU_STACK == RW   | exec-none | exec-none | + * + * exec-all : all PROT_READ user mappings are executable, except when + * backed by files on a noexec-filesystem. + * exec-none : only PROT_EXEC user mappings are executable. + * + * *all arm64 CPUs support NX, so there is no "lacks NX" column. + * + */ #define elf_read_implies_exec(ex,stk) (stk != EXSTACK_DISABLE_X) #define CORE_DUMP_USE_REGSET From patchwork Mon Feb 10 19:30:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 208799 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.1 required=3.0 tests=DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS, UNWANTED_LANGUAGE_BODY, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 42066C3F68F for ; Mon, 10 Feb 2020 19:31:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 09AEF215A4 for ; Mon, 10 Feb 2020 19:31:07 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="kD5EGiWm" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727779AbgBJTbG (ORCPT ); Mon, 10 Feb 2020 14:31:06 -0500 Received: from mail-ot1-f65.google.com ([209.85.210.65]:33971 "EHLO mail-ot1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727752AbgBJTbF (ORCPT ); Mon, 10 Feb 2020 14:31:05 -0500 Received: by mail-ot1-f65.google.com with SMTP id a15so7598577otf.1 for ; Mon, 10 Feb 2020 11:31:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Dy7V9n1SJWAfsimqdnx79gIWJx+OE4CfcWEJjNElzkw=; b=kD5EGiWmI843sCuCafTUWkInv63C7SrnPb5eYa/PNLKeGUkbgs8l0tKEsrbARmFeO3 WnDV5WSszUbzwfAhGPPrFN3uYkvvUZgZNfPv/RmgJGj1O3LaHMDNKg2LDgAb2xaw9T6a jtQyquGSSoFjFpvv8I0f9WMF2jMQbyTYs6jqo= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Dy7V9n1SJWAfsimqdnx79gIWJx+OE4CfcWEJjNElzkw=; b=j0XDVbd3hOsMH8hCbNK3Ab2v+4gh4PA49vBy8ozdBwf6eMaUK+qzUICYFvEEshr/lc IJWrVp4R1igFqHI0zj/VtBU/vayAiZukWFF+U1pca+O/W9IGwn65XGLhCw6xtGM+InLe aQGR3wlPzK698+wHMtdOQRH5nNyV/ln4RQEtuj4kNeQ6KDBfXuV8pDcqWkMBI7EBUIFG YjZPx6DV7KKs1dX6Rgqmw7jKgGXC4wGcnrS0dqtbI1lFXLceaAVo921qLEjJ8jStP/ii RA1if3LD+1bcYFQF4FhgUNhrAlioNISTO9otOv7FkNcad9IWL/CGHd2GVe2nx9i6JGEG X0RQ== X-Gm-Message-State: APjAAAWZDo1cOcNhE586q6wUlUNZgbz3XQQ/zFV6i+1m8Mr810fHBb5h okz2ATgtCkZGlo9t6NcIinIkiQ== X-Google-Smtp-Source: APXvYqytQ6Tq8ED/M4IZzD6H8znkZODeLSYS85Lxv1Mg2ykDKGTymMbliK1RJrYqSv3Cgm5yBLjtiw== X-Received: by 2002:a9d:5a09:: with SMTP id v9mr2153543oth.214.1581363064328; Mon, 10 Feb 2020 11:31:04 -0800 (PST) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id p24sm358258otq.64.2020.02.10.11.31.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 10 Feb 2020 11:31:02 -0800 (PST) From: Kees Cook To: Ingo Molnar Cc: Kees Cook , Hector Marco-Gisbert , Catalin Marinas , Will Deacon , Jason Gunthorpe , Jann Horn , Russell King , x86@kernel.org, kernel-hardening@lists.openwall.com, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH v3 7/7] selftests/exec: Add READ_IMPLIES_EXEC tests Date: Mon, 10 Feb 2020 11:30:49 -0800 Message-Id: <20200210193049.64362-8-keescook@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200210193049.64362-1-keescook@chromium.org> References: <20200210193049.64362-1-keescook@chromium.org> MIME-Version: 1.0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org In order to check the matrix of possible states for handling READ_IMPLIES_EXEC across native, compat, and the state of PT_GNU_STACK, add tests for these execution conditions. Signed-off-by: Kees Cook --- tools/testing/selftests/exec/Makefile | 42 +++++- .../selftests/exec/read_implies_exec.c | 121 ++++++++++++++++++ .../selftests/exec/strip-gnu-stack-bits.c | 34 +++++ .../testing/selftests/exec/strip-gnu-stack.c | 69 ++++++++++ 4 files changed, 265 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/exec/read_implies_exec.c create mode 100644 tools/testing/selftests/exec/strip-gnu-stack-bits.c create mode 100644 tools/testing/selftests/exec/strip-gnu-stack.c diff --git a/tools/testing/selftests/exec/Makefile b/tools/testing/selftests/exec/Makefile index 33339e31e365..085d0e4422ea 100644 --- a/tools/testing/selftests/exec/Makefile +++ b/tools/testing/selftests/exec/Makefile @@ -10,7 +10,19 @@ TEST_FILES := Makefile TEST_GEN_PROGS += recursion-depth -EXTRA_CLEAN := $(OUTPUT)/subdir.moved $(OUTPUT)/execveat.moved $(OUTPUT)/xxxxx* +TEST_GEN_FILES += strip-gnu-stack +TEST_GEN_PROGS += rie-nx-gnu-stack rie-x-gnu-stack rie-missing-gnu-stack + +# While it would be nice to not build "compat" binaries on 32-bit builders, +# there's no harm: they're just redundant to the native binaries, so skip +# performing any detection for now, as it gets complex quickly. +TEST_GEN_PROGS += rie-compat-nx-gnu-stack \ + rie-compat-x-gnu-stack \ + rie-compat-missing-gnu-stack + +EXTRA_CLEAN := $(OUTPUT)/subdir.moved $(OUTPUT)/execveat.moved \ + $(OUTPUT)/rie-*.new \ + $(OUTPUT)/xxxxx* include ../lib.mk @@ -26,3 +38,31 @@ $(OUTPUT)/execveat.denatured: $(OUTPUT)/execveat cp $< $@ chmod -x $@ +$(OUTPUT)/strip-gnu-stack: strip-gnu-stack.c strip-gnu-stack-bits.c + $(CC) $(CFLAGS) -o $@ $< + +$(OUTPUT)/rie-nx-gnu-stack: read_implies_exec.c + $(CC) $(CFLAGS) -Wl,-z,noexecstack -o $@.new $< + readelf -Wl $@.new | grep GNU_STACK | grep -q 'RW ' && \ + mv $@.new $@ +$(OUTPUT)/rie-x-gnu-stack: read_implies_exec.c + $(CC) $(CFLAGS) -Wl,-z,execstack -o $@.new $< + readelf -Wl $@.new | grep GNU_STACK | grep -q 'RWE' && \ + mv $@.new $@ +$(OUTPUT)/rie-missing-gnu-stack: read_implies_exec.c $(OUTPUT)/strip-gnu-stack + $(CC) $(CFLAGS) -o $@.new $< + $(OUTPUT)/strip-gnu-stack $@.new && \ + mv $@.new $@ + +$(OUTPUT)/rie-compat-nx-gnu-stack: read_implies_exec.c + $(CC) -m32 $(CFLAGS) -Wl,-z,noexecstack -o $@.new $< + readelf -Wl $@.new | grep GNU_STACK | grep -q 'RW ' && \ + mv $@.new $@ +$(OUTPUT)/rie-compat-x-gnu-stack: read_implies_exec.c + $(CC) -m32 $(CFLAGS) -Wl,-z,execstack -o $@.new $< + readelf -Wl $@.new | grep GNU_STACK | grep -q 'RWE' && \ + mv $@.new $@ +$(OUTPUT)/rie-compat-missing-gnu-stack: read_implies_exec.c $(OUTPUT)/strip-gnu-stack + $(CC) -m32 $(CFLAGS) -o $@.new $< + $(OUTPUT)/strip-gnu-stack $@.new && \ + mv $@.new $@ diff --git a/tools/testing/selftests/exec/read_implies_exec.c b/tools/testing/selftests/exec/read_implies_exec.c new file mode 100644 index 000000000000..4b253a84dd27 --- /dev/null +++ b/tools/testing/selftests/exec/read_implies_exec.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * This just examines a PROT_READ mapping to report if it see it gain + * PROT_EXEC too (which means that READ_IMPLIES_EXEC has been enabled). + */ +#include +#include +#include +#include +#include +#include +#include + +const char maps_path[] = "/proc/self/maps"; + +int main(int argc, char *argv[]) +{ + char maps_line[1024]; + FILE *maps; + void *region; + int flags = MAP_PRIVATE | MAP_ANONYMOUS; + int ret = -1; + int perms = -1; + int vma_64bit; + + region = mmap(NULL, getpagesize(), PROT_READ, flags, -1, 0); + if (region == MAP_FAILED) { + perror("mmap"); + return 128; + } + maps = fopen(maps_path, "r"); + if (!maps) { + perror(maps_path); + ret = 127; + goto out_munmap; + } + + memset(maps_line, 0, sizeof(maps_line)); + while (fgets(maps_line, sizeof(maps_line), maps)) { + unsigned long long low, high; + char *end; + + low = strtoull(maps_line, &end, 16); + if (*end != '-') { + fprintf(stderr, "Missing '-' separator, line: %s", + maps_line); + ret = 126; + goto out_close; + } + end++; + + high = strtoull(end, &end, 16); + if (*end != ' ') { + fprintf(stderr, "Missing ' ' separator, line: %s", + maps_line); + ret = 125; + goto out_close; + } + end++; + + if ((uintptr_t)region >= low && (uintptr_t)region < high) { + perms = 0; + perms |= end[0] == 'r' ? PROT_READ : 0; + perms |= end[1] == 'w' ? PROT_WRITE : 0; + perms |= end[2] == 'x' ? PROT_EXEC : 0; + + break; + } + } + if (perms == -1) { + fprintf(stderr, "Could not find mmap region\n"); + ret = 124; + goto out_close; + } + + vma_64bit = sizeof(void *) == 8; + fprintf(stderr, "%s-bit, ", vma_64bit ? "64" : "32"); + + ret = 1; + if (strstr(argv[0], "missing-gnu-stack")) { + fprintf(stderr, "missing-gnu-stack, "); + + /* Missing PT_GNU_STACK on 64-bit: not READ_IMPLIES_EXEC */ + if (vma_64bit && (perms & PROT_EXEC) == 0) + ret = 0; + /* Missing PT_GNU_STACK on 32-bit enables READ_IMPLIES_EXEC */ + if (!vma_64bit && (perms & PROT_EXEC) == PROT_EXEC) + ret = 0; + } else if (strstr(argv[0], "x-gnu-stack")) { + fprintf(stderr, "executable gnu-stack, "); + + /* X PT_GNU_STACK should always leave READ_IMPLIES_EXEC off */ + if ((perms & PROT_EXEC) == 0) + ret = 0; + } else if (strstr(argv[0], "nx-gnu-stack")) { + fprintf(stderr, "non-executable PT_GNU_STACK, "); + + /* NX PT_GNU_STACK should always leave READ_IMPLIES_EXEC off */ + if ((perms & PROT_EXEC) == 0) + ret = 0; + } else { + fprintf(stderr, "Unknown invocation\n"); + ret = 123; + goto out_close; + } + + fprintf(stderr, "READ_IMPLIES_EXEC is %s: ", + (perms & PROT_EXEC) ? "on" : "off"); + + if (ret) + fprintf(stderr, "FAIL: %s", maps_line); + else + fprintf(stderr, "ok\n"); + +out_close: + fclose(maps); +out_munmap: + munmap(region, getpagesize()); + + return ret; +} diff --git a/tools/testing/selftests/exec/strip-gnu-stack-bits.c b/tools/testing/selftests/exec/strip-gnu-stack-bits.c new file mode 100644 index 000000000000..907e959c3477 --- /dev/null +++ b/tools/testing/selftests/exec/strip-gnu-stack-bits.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * word-size agnostic routines to scan ELF program headers for PT_GNU_STACK + * and rewrite it as PT_NULL to emulate old toolchains that did not include + * the PT_GNU_STACK program header. + */ + +int strip_bits(char *elf, size_t size) +{ + unsigned int i; + Elf_Ehdr *eh; + + eh = (Elf_Ehdr *)elf; + if (sizeof(*eh) > size) { + fprintf(stderr, "Elf Header too small\n"); + return 124; + } + + for (i = 0; i < eh->e_phnum; i++) { + Elf_Phdr *ph = (Elf_Phdr *)(elf + (eh->e_phoff + eh->e_phentsize * i)); + + if (ph->p_type == PT_GNU_STACK) { + ph->p_type = PT_NULL; + return 0; + } + } + + fprintf(stderr, "PT_GNU_STACK missing\n"); + return 123; +} + +#undef strip_bits +#undef Elf_Ehdr +#undef Elf_Phdr diff --git a/tools/testing/selftests/exec/strip-gnu-stack.c b/tools/testing/selftests/exec/strip-gnu-stack.c new file mode 100644 index 000000000000..529e60cf0e6e --- /dev/null +++ b/tools/testing/selftests/exec/strip-gnu-stack.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Converts an ELF's PT_GNU_STACK program header to PT_NULL. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define strip_bits strip64 +#define Elf_Ehdr Elf64_Ehdr +#define Elf_Phdr Elf64_Phdr +#include "strip-gnu-stack-bits.c" + +#define strip_bits strip32 +#define Elf_Ehdr Elf32_Ehdr +#define Elf_Phdr Elf32_Phdr +#include "strip-gnu-stack-bits.c" + +int strip(char *elf, size_t size) +{ + if (size < 4 || elf[0] != '\x7f' || strncmp(elf + 1, "ELF", 3) != 0) { + fprintf(stderr, "Not an ELF file\n"); + return 128; + } + switch (elf[EI_CLASS]) { + case ELFCLASS64: + return strip64(elf, size); + case ELFCLASS32: + return strip32(elf, size); + default: + fprintf(stderr, "Unknown EI_CLASS: 0x%02x\n", elf[EI_CLASS]); + return 127; + } +} + +int main(int argc, char *argv[]) +{ + int fd, ret; + struct stat info; + char *elf; + + fd = open(argv[1], O_RDWR); + if (fd < 0) { + perror(argv[1]); + return 1; + } + + if (fstat(fd, &info)) { + perror(argv[1]); + return 2; + } + + elf = mmap(NULL, info.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, + fd, 0); + if (elf == MAP_FAILED) { + perror(argv[1]); + return 3; + } + + ret = strip(elf, info.st_size); + + munmap(elf, info.st_size); + close(fd); + return ret; +}