From patchwork Tue Jun 18 19:40:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 805290 Delivered-To: patch@linaro.org Received: by 2002:a05:6000:144:b0:362:4979:7f74 with SMTP id r4csp359514wrx; Tue, 18 Jun 2024 12:42:23 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCVZPeqU6nggJDTkkyD1mJll6/EERbjW8f8XduMy/jt1+81eU19TzPstHk+iPTa7hH8auL7BEwYPA4rJmKObuJbx X-Google-Smtp-Source: AGHT+IHJFGqHCo6aBijrmjOL9I0C/QYwkMiw0Co1ZlNAjqbNkVKwq49Y3J7iUeKL2TuGNYEIiu/3 X-Received: by 2002:a0d:e646:0:b0:630:de2f:79b8 with SMTP id 00721157ae682-63a8dfed4b9mr7869087b3.13.1718739742945; Tue, 18 Jun 2024 12:42:22 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1718739742; cv=pass; d=google.com; s=arc-20160816; b=i/M2DndSLOkz46DbuN0efU3iBy84Yb78FQ4SjzY6etyIu4A8kP24Xc7o6viCBmHfhY ZAijBmOiyOW3QiovPSb7n4E2cih7C8vNbeTdfKqefPOlg2/T6ql8gkoPGLqVjMyHjtIO dY3fqe4rKR5Wx3sJOeL2TjLM4HekLcozleT+yg0m44w2qyBhVCa9Ju1+lCkSoqAz86bt hDEx08LtSQxq5Z0u0+Jf++1rUCYjhrvHkslMNYbxxh4gEylRCrMJWXfLzuJN9inf/StA hSPVEbKNt+w3k7nqFXMqYHMicozECAo7GFiYNCW3EpQJJT/g8FtalVOiPwHOwzNOGtcT 0UBw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature:arc-filter:dmarc-filter:delivered-to; bh=chjxx9tjsBqV4FmM3sK2j+rIarvYoFXxbD0+MwtHycw=; fh=GBLwcZa3Ar5g+0nFTVWUSbowptRVTzvTc/MV+A3rhh4=; b=PjTMGWuUx4/hUWYWz3NyFbXose1oxIynefID1tj8Mzd3zpRqpyvKfc61FE5URHuAR3 g8qAhOngqF3AbnqfJQ2NgwfPp3Sndtp7Xsv+TButJkUnmwGWa06DwiMNo6xB8QM0igza 2eKfjib8exYZ7bj4CgryLacxg5ofT77+CcY22BT3ggBNY/cU8OnReURXYLmMGOQeKGVu tHsq4B9yijTysxs1VessCHYUZ7PLZxSizD5xSnX6XcTLj/k9Jcz0RywRML9i0Joc5lZp cxi1q06DXGc7C2RWVecv2xI6V/+M6JTwmrhfutRRZEtvBH//XC3IIiS9zE5xHwd4adTm LLbA==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=nP8gDaPU; arc=pass (i=1); spf=pass (google.com: domain of libc-alpha-bounces+patch=linaro.org@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="libc-alpha-bounces+patch=linaro.org@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from server2.sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id d75a77b69052e-441f2fbdfcfsi135610501cf.490.2024.06.18.12.42.22 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 18 Jun 2024 12:42:22 -0700 (PDT) Received-SPF: pass (google.com: domain of libc-alpha-bounces+patch=linaro.org@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=nP8gDaPU; arc=pass (i=1); spf=pass (google.com: domain of libc-alpha-bounces+patch=linaro.org@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="libc-alpha-bounces+patch=linaro.org@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 924753883012 for ; Tue, 18 Jun 2024 19:42:22 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-pj1-x102a.google.com (mail-pj1-x102a.google.com [IPv6:2607:f8b0:4864:20::102a]) by sourceware.org (Postfix) with ESMTPS id EC0333884506 for ; Tue, 18 Jun 2024 19:41:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org EC0333884506 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=linaro.org ARC-Filter: OpenARC Filter v1.0.0 sourceware.org EC0333884506 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::102a ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1718739683; cv=none; b=m/slEUfDIvip4JfIc+zlRkZ2JkSfXOYpR61pVUdiZ0XREXbo4Dw2sBcphY+ne3WzHXpDU4EFaXCU4G9zMqBNuDP+XIdxtQQrWs0gUqi4M84d01YNmNFBB65Ij+pSYZFafAkcLQRpr/flvyiQqBZvwikepVghrYvGpXI0JD05is8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1718739683; c=relaxed/simple; bh=AFKzKZo1EDucHVht4TnxTOev7pJpitFbdS7YPH+uRKQ=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=mVHHhwB3l6V5SC2sLIfrYsOcCpLhs5C1xrX8zepN9P8ZgnEy8WN4i33U3Cqn3/1esFeX8fJyi4TF2IIXPKQzjuhdyHNO38CUuOhqqKYdAy0T11PyNr0UVild9DbXzbH5cm+6B8WBB0uvlGulvgHR/gphL+6tUSXLsg5ii5Y1Ti0= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-pj1-x102a.google.com with SMTP id 98e67ed59e1d1-2c2c6277ef3so4710118a91.3 for ; Tue, 18 Jun 2024 12:41:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1718739679; x=1719344479; darn=sourceware.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=chjxx9tjsBqV4FmM3sK2j+rIarvYoFXxbD0+MwtHycw=; b=nP8gDaPUxFayqmbO1Gj3roceA5ZxkYsbugB/yAZVlhFjVBAXyuXSbhbnU5tC+0kGTC AacrYAJEJoVL/QdRfZE/pH58Ej2amy9+FXYn1PPNHqlNHMhPm7iGHCVBznra8mHD0GCg w8ZlcH9zUbnq9uTCkyovq1GASc+PrNo5kLiKhqULWohzXOs1G1Bmhi2ZwEv+RvzOHuLH 8GeNkF/uv/mxEZ0V5m/RH8/3gZUnx0oN4Fn/rA0vJyXVX8WFeGQht1Rbm+JOzzK+N/7j YAhB8aeU2XVpvGqovfQDEgl7YmWylztrMTBUT2z3qqcGTUpD7F28gd/NrWzuxfebtuTe Y8hA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718739679; x=1719344479; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=chjxx9tjsBqV4FmM3sK2j+rIarvYoFXxbD0+MwtHycw=; b=lMnClhhJ8kSwguycYMRrObOXXXC+kJWwCLGJNf3qSR2o5Z00nd+2LjdN3Q+mnqrYlA MVk73z4bLp74O4ItzcyTEuq6jV5mOPvJ8ychrrf0r/t8Qd4JSuvi78q4iTf4DF4ZYICl rYCe3Xq/VxbhPkLvbCWOUB73EfWDxhuBBEHQxWXGiWpoT+b8S8S9EmDvn1atGKdD1dd5 36TQPdxIcRMGIIWGQiOid/RV82XScfSaNKa88euYJiz0eUR+ZntmHnhx1P3bLB/k8hD9 c+DnRmUf6GcoL2uPuVH+a1QPZUAYkkVeydFjUkOKGybEjaNGqof5ccdQm7HPXELSoTD/ CwqA== X-Gm-Message-State: AOJu0YxnSJTob4LRe3vtXhvwi9E4xfnfIBqW7RNLgRXNoP7dqpMzpw21 HO7ra5quoBlwwXuzuA/Z/G3kpYY+iZWC5ga097xvmgtJLPYwp+4VdXGah3x/jqIlUkLtrUhXWTP Q X-Received: by 2002:a17:90a:bd8f:b0:2c7:22d6:98e with SMTP id 98e67ed59e1d1-2c7b5c82772mr716590a91.19.1718739679166; Tue, 18 Jun 2024 12:41:19 -0700 (PDT) Received: from mandiga.. ([2804:1b3:a7c1:5c0d:de56:b6f3:eeae:13e7]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-2c50c4ce173sm6209093a91.23.2024.06.18.12.41.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 18 Jun 2024 12:41:18 -0700 (PDT) From: Adhemerval Zanella To: libc-alpha@sourceware.org Cc: "H . J . Lu" , Florian Weimer , Zack Weinberg Subject: [PATCH v3 4/4] elf: Add glibc.rtld.execstack Date: Tue, 18 Jun 2024 16:40:22 -0300 Message-ID: <20240618194102.2059389-5-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240618194102.2059389-1-adhemerval.zanella@linaro.org> References: <20240618194102.2059389-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-12.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces+patch=linaro.org@sourceware.org The new tunable can be used to control whether executable stacks are allowed from either the main program or dependencies. The default is to allow executable stacks. The executable stacks default permission is checked agains the one provided by the PT_GNU_STACK from program headers (if present). The tunable also disables the stack permission change if any dependency requires an executable stack at loading time. Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu. --- NEWS | 4 ++++ elf/Makefile | 42 ++++++++++++++++++++++++++++++++++ elf/dl-load.c | 4 +++- elf/dl-support.c | 5 ++++ elf/dl-tunables.list | 6 +++++ elf/rtld.c | 4 ++++ elf/tst-rtld-list-tunables.exp | 1 + manual/tunables.texi | 19 +++++++++++++++ 8 files changed, 84 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 43ff2ee23b..a5bbf3851b 100644 --- a/NEWS +++ b/NEWS @@ -36,6 +36,10 @@ Major new features: * On Linux, update epoll header to include epoll ioctl definitions and related structure added in Linux kernel 6.9. +* A new tunable, glibc.rtld.execstack, can be used to control whether + executable stacks are allowed from either main program or dependencies. + The default is to allow executable stacks. + Deprecated and removed features, and other changes affecting compatibility: * Architectures which use a 32-bit seconds-since-epoch field in struct diff --git a/elf/Makefile b/elf/Makefile index 604b7df1cc..dba6a6ddac 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -546,6 +546,11 @@ tests-execstack-yes = \ tests-execstack-static-yes = \ tst-execstack-prog-static # tests-execstack-static-yes +tests-execstack-special-yes = \ + $(objpfx)tst-execstack-prog-noexecstack.out \ + $(objpfx)tst-execstack-needed-noexecstack.out \ + $(objpfx)tst-execstack-prog-static-noexecstack.out \ + # tests-execstack-special-yes endif ifeq ($(have-depaudit),yes) tests += \ @@ -634,6 +639,7 @@ $(objpfx)tst-rtld-does-not-exist.out: tst-rtld-does-not-exist.sh $(objpfx)ld.so tests += $(tests-execstack-$(have-z-execstack)) tests-static+= $(tests-execstack-static-$(have-z-execstack)) +tests-special += $(tests-execstack-special-$(have-z-execstack)) ifeq ($(run-built-tests),yes) tests-special += \ $(objpfx)noload-mem.out \ @@ -1863,6 +1869,42 @@ CFLAGS-tst-execstack-mod.c += -Wno-trampolines LDFLAGS-tst-execstack-prog-static = -Wl,-z,execstack CFLAGS-tst-execstack-prog-static.c += -Wno-trampolines + +ifeq (yes,$(build-hardcoded-path-in-tests)) +tst-execstack-prog-noexecstack-msg = "Fatal glibc error: executable stack is not allowed$$" +else +tst-execstack-prog-noexecstack-msg = "error while loading shared libraries:.*cannot enable executable stack as shared object requires:" +endif + +$(objpfx)tst-execstack-prog-noexecstack.out: $(objpfx)tst-execstack-prog + $(test-program-cmd-before-env) \ + $(run-program-env) \ + GLIBC_TUNABLES=glibc.rtld.execstack=0 \ + $(test-program-cmd-after-env) $< \ + > $@ 2>&1; echo "status: $$?" >> $@; \ + grep -q $(tst-execstack-prog-noexecstack-msg) $@ \ + && grep -q '^status: 127$$' $@; \ + $(evaluate-test) + +$(objpfx)tst-execstack-needed-noexecstack.out: $(objpfx)tst-execstack-needed + $(test-program-cmd-before-env) \ + $(run-program-env) \ + GLIBC_TUNABLES=glibc.rtld.execstack=0 \ + $(test-program-cmd-after-env) $< \ + > $@ 2>&1; echo "status: $$?" >> $@; \ + grep -q 'error while loading shared libraries:.*cannot enable executable stack as shared object requires:' $@ \ + && grep -q '^status: 127$$' $@; \ + $(evaluate-test) + +$(objpfx)tst-execstack-prog-static-noexecstack.out: $(objpfx)tst-execstack-prog-static + $(test-program-cmd-before-env) \ + $(run-program-env) \ + GLIBC_TUNABLES=glibc.rtld.execstack=0 \ + $< \ + > $@ 2>&1; echo "status: $$?" >> $@; \ + grep -q 'Fatal glibc error: executable stack is not allowed$$' $@ \ + && grep -q '^status: 127$$' $@; \ + $(evaluate-test) endif LDFLAGS-tst-array2 = -Wl,--no-as-needed diff --git a/elf/dl-load.c b/elf/dl-load.c index 015595aac4..75550fe089 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -32,6 +32,7 @@ #include #include #include +#include /* Type for the buffer we put the ELF header and hopefully the program header. This buffer does not really have to be too large. In most @@ -1300,7 +1301,8 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, /* The stack is presently not executable, but this module requires that it be executable. Only tries to change the stack protection during process startup. */ - if ((mode & __RTLD_DLOPEN) == 0) + if ((mode & __RTLD_DLOPEN) == 0 + && TUNABLE_GET (glibc, rtld, execstack, int32_t, NULL) == 1) #if PTHREAD_IN_LIBC errval = _dl_make_stacks_executable (stack_endp); #else diff --git a/elf/dl-support.c b/elf/dl-support.c index 451932dd03..b674468572 100644 --- a/elf/dl-support.c +++ b/elf/dl-support.c @@ -45,6 +45,7 @@ #include #include #include +#include extern char *__progname; char **_dl_argv = &__progname; /* This is checked for some error messages. */ @@ -335,6 +336,10 @@ _dl_non_dynamic_init (void) break; } + if ((__glibc_unlikely (GL(dl_stack_flags)) & PF_X) + && TUNABLE_GET (glibc, rtld, execstack, int32_t, NULL) == 0) + _dl_fatal_printf ("Fatal glibc error: executable stack is not allowed\n"); + call_function_static_weak (_dl_find_object_init); /* Setup relro on the binary itself. */ diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list index 1186272c81..2d6febc249 100644 --- a/elf/dl-tunables.list +++ b/elf/dl-tunables.list @@ -142,6 +142,12 @@ glibc { maxval: 1 default: 0 } + execstack { + type: INT_32 + minval: 0 + maxval: 1 + default: 1 + } } mem { diff --git a/elf/rtld.c b/elf/rtld.c index e9525ea987..5793f291e4 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -1668,6 +1668,10 @@ dl_main (const ElfW(Phdr) *phdr, bool has_interp = rtld_setup_main_map (main_map); + if ((__glibc_unlikely (GL(dl_stack_flags)) & PF_X) + && TUNABLE_GET (glibc, rtld, execstack, int32_t, NULL) == 0) + _dl_fatal_printf ("Fatal glibc error: executable stack is not allowed\n"); + /* If the current libname is different from the SONAME, add the latter as well. */ if (GL(dl_rtld_map).l_info[DT_SONAME] != NULL diff --git a/elf/tst-rtld-list-tunables.exp b/elf/tst-rtld-list-tunables.exp index db0e1c86e9..9f5990f340 100644 --- a/elf/tst-rtld-list-tunables.exp +++ b/elf/tst-rtld-list-tunables.exp @@ -13,5 +13,6 @@ glibc.malloc.top_pad: 0x20000 (min: 0x0, max: 0x[f]+) glibc.malloc.trim_threshold: 0x0 (min: 0x0, max: 0x[f]+) glibc.rtld.dynamic_sort: 2 (min: 1, max: 2) glibc.rtld.enable_secure: 0 (min: 0, max: 1) +glibc.rtld.execstack: 1 (min: 0, max: 1) glibc.rtld.nns: 0x4 (min: 0x1, max: 0x10) glibc.rtld.optional_static_tls: 0x200 (min: 0x0, max: 0x[f]+) diff --git a/manual/tunables.texi b/manual/tunables.texi index 8dd02d8149..f1674f31ea 100644 --- a/manual/tunables.texi +++ b/manual/tunables.texi @@ -356,6 +356,25 @@ tests for @code{AT_SECURE} programs and not meant to be a security feature. The default value of this tunable is @samp{0}. @end deftp +@deftp Tunable glibc.rtld.execstack +@theglibc{} will use either the default architecture flags (that might contain +the executable bit) or the value of @code{PT_GNU_STACK} (if present), and if +the program or any shared library dependency require an executable stack the +loader will change the main stack permission if kernel starts with a non +executable stack. + +The @code{glibc.rtld.execstack} tunable allows the user to control whether +to control executable stacks from the main program or dependencies. Setting +its value to @code{0} disable executable stacks, where @code{1} enables it. +The default value is @code{1}. + +When executable stacks are not allowed, and if the main program or dependencies +require an executable stack, the loader will fail with an error message. +@strong{NB:} Trying to load a dynamic shared library with @code{dlopen} or +@code{dlmopen} that requires an executable stack will always fail if the +default flags does not contain the executable bit. +@end deftp + @node Elision Tunables @section Elision Tunables @cindex elision tunables