From: Chang S. Bae <hidden> Date: 2021-02-27 17:30:28
During signal entry, the kernel pushes data onto the normal userspace
stack. On x86, the data pushed onto the user stack includes XSAVE state,
which has grown over time as new features and larger registers have been
added to the architecture.
MINSIGSTKSZ is a constant provided in the kernel signal.h headers and
typically distributed in lib-dev(el) packages, e.g. [1]. Its value is
compiled into programs and is part of the user/kernel ABI. The MINSIGSTKSZ
constant indicates to userspace how much data the kernel expects to push on
the user stack, [2][3].
However, this constant is much too small and does not reflect recent
additions to the architecture. For instance, when AVX-512 states are in
use, the signal frame size can be 3.5KB while MINSIGSTKSZ remains 2KB.
The bug report [4] explains this as an ABI issue. The small MINSIGSTKSZ can
cause user stack overflow when delivering a signal.
In this series, we suggest a couple of things:
1. Provide a variable minimum stack size to userspace, as a similar
approach to [5].
2. Avoid using a too-small alternate stack.
Changes form v5 [10]:
* Fixed the overflow detection. (Andy Lutomirski)
* Reverted the AT_MINSIGSTKSZ removal on arm64. (Dave Martin)
* Added a documentation about the x86 AT_MINSIGSTKSZ.
* Supported the existing sigaltstack test to use the new aux vector.
Changes from v4 [9]:
* Moved the aux vector define to the generic header. (Carlos O'Donell)
Changes from v3 [8]:
* Updated the changelog. (Borislav Petkov)
* Revised the test messages again. (Borislav Petkov)
Changes from v2 [7]:
* Simplified the sigaltstack overflow prevention. (Jann Horn)
* Renamed fpstate size helper with cleanup. (Borislav Petkov)
* Cleaned up the signframe struct size defines. (Borislav Petkov)
* Revised the selftest messages. (Borislav Petkov)
* Revised a changelog. (Borislav Petkov)
Changes from v1 [6]:
* Took stack alignment into account for sigframe size. (Dave Martin)
[1]: https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/bits/sigstack.h;h=b9dca794da093dc4d41d39db9851d444e1b54d9b;hb=HEAD
[2]: https://www.gnu.org/software/libc/manual/html_node/Signal-Stack.html
[3]: https://man7.org/linux/man-pages/man2/sigaltstack.2.html
[4]: https://bugzilla.kernel.org/show_bug.cgi?id=153531
[5]: https://blog.linuxplumbersconf.org/2017/ocw/system/presentations/4671/original/plumbers-dm-2017.pdf
[6]: https://lore.kernel.org/lkml/20200929205746.6763-1-chang.seok.bae@intel.com/
[7]: https://lore.kernel.org/lkml/20201119190237.626-1-chang.seok.bae@intel.com/
[8]: https://lore.kernel.org/lkml/20201223015312.4882-1-chang.seok.bae@intel.com/
[9]: https://lore.kernel.org/lkml/20210115211038.2072-1-chang.seok.bae@intel.com/
[10]: https://lore.kernel.org/lkml/20210203172242.29644-1-chang.seok.bae@intel.com/
Chang S. Bae (6):
uapi: Define the aux vector AT_MINSIGSTKSZ
x86/signal: Introduce helpers to get the maximum signal frame size
x86/elf: Support a new ELF aux vector AT_MINSIGSTKSZ
selftest/sigaltstack: Use the AT_MINSIGSTKSZ aux vector if available
x86/signal: Detect and prevent an alternate signal stack overflow
selftest/x86/signal: Include test cases for validating sigaltstack
Documentation/x86/elf_auxvec.rst | 56 ++++++++++
arch/x86/include/asm/elf.h | 4 +
arch/x86/include/asm/fpu/signal.h | 2 +
arch/x86/include/asm/sigframe.h | 2 +
arch/x86/include/uapi/asm/auxvec.h | 4 +-
arch/x86/kernel/cpu/common.c | 3 +
arch/x86/kernel/fpu/signal.c | 19 ++++
arch/x86/kernel/signal.c | 72 +++++++++++-
include/uapi/linux/auxvec.h | 3 +
tools/testing/selftests/sigaltstack/sas.c | 20 +++-
tools/testing/selftests/x86/Makefile | 2 +-
tools/testing/selftests/x86/sigaltstack.c | 128 ++++++++++++++++++++++
12 files changed, 302 insertions(+), 13 deletions(-)
create mode 100644 Documentation/x86/elf_auxvec.rst
create mode 100644 tools/testing/selftests/x86/sigaltstack.c
base-commit: f40ddce88593482919761f74910f42f4b84c004b
--
2.17.1
From: Chang S. Bae <hidden> Date: 2021-02-27 17:20:33
Define the AT_MINSIGSTKSZ in generic Linux. It is already used as generic
ABI in glibc's generic elf.h, and this define will prevent future namespace
conflicts. In particular, x86 is also using this generic definition.
Signed-off-by: Chang S. Bae <redacted>
Reviewed-by: Len Brown <redacted>
Cc: Carlos O'Donell <redacted>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: libc-alpha@sourceware.org
Cc: linux-arch@vger.kernel.org
Cc: linux-api@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
Change from v5:
* Reverted the arm64 change. (Dave Martin)
* Massaged the changelog.
Change from v4:
* Added as a new patch (Carlos O'Donell)
---
include/uapi/linux/auxvec.h | 3 +++
1 file changed, 3 insertions(+)
From: Chang S. Bae <hidden> Date: 2021-02-27 17:21:08
Signal frames do not have a fixed format and can vary in size when a number
of things change: support XSAVE features, 32 vs. 64-bit apps. Add the code
to support a runtime method for userspace to dynamically discover how large
a signal stack needs to be.
Introduce a new variable, max_frame_size, and helper functions for the
calculation to be used in a new user interface. Set max_frame_size to a
system-wide worst-case value, instead of storing multiple app-specific
values.
Signed-off-by: Chang S. Bae <redacted>
Reviewed-by: Len Brown <redacted>
Acked-by: H.J. Lu <redacted>
Cc: x86@kernel.org
Cc: linux-kernel@vger.kernel.org
---
Changes from v2:
* Renamed the fpstate size helper with cleanup (Borislav Petkov)
* Moved the sigframe struct size defines to where used (Borislav Petkov)
* Removed unneeded sentence in the changelog (Borislav Petkov)
Change from v1:
* Took stack alignment into account for sigframe size (Dave Martin)
---
arch/x86/include/asm/fpu/signal.h | 2 ++
arch/x86/include/asm/sigframe.h | 2 ++
arch/x86/kernel/cpu/common.c | 3 ++
arch/x86/kernel/fpu/signal.c | 19 +++++++++++
arch/x86/kernel/signal.c | 57 +++++++++++++++++++++++++++++--
5 files changed, 81 insertions(+), 2 deletions(-)
@@ -507,6 +507,25 @@ fpu__alloc_mathframe(unsigned long sp, int ia32_frame,returnsp;}++unsignedlongfpu__get_fpstate_size(void)+{+unsignedlongret=xstate_sigframe_size();++/*+*Thisspaceisneededon(most)32-bitkernels,orwhena32-bit+*appisrunningona64-bitkernel.Tokeepthingssimple,just+*assumetheworstcaseandalwaysincludespacefor'freg_state',+*evenfor64-bitappson64-bitkernels.Thiswastesabitof+*space,butkeepsthecodesimple.+*/+if((IS_ENABLED(CONFIG_IA32_EMULATION)||+IS_ENABLED(CONFIG_X86_32))&&use_fxsr())+ret+=sizeof(structfregs_state);++returnret;+}+/**PreparetheSWreservedportionofthefxsavememorylayout,indicating*thepresenceoftheextendedstateinformationinthememorylayout
From: Chang S. Bae <hidden> Date: 2021-02-27 17:23:28
The SIGSTKSZ constant may not represent enough stack size in some
architectures as the hardware state size grows.
Use getauxval(AT_MINSIGSTKSZ) to increase the stack size.
Signed-off-by: Chang S. Bae <redacted>
Reviewed-by: Len Brown <redacted>
Cc: linux-kselftest@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
---
Changes from v5:
* Added as a new patch.
---
tools/testing/selftests/sigaltstack/sas.c | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)
@@ -47,7 +53,7 @@ void my_usr1(int sig, siginfo_t *si, void *u)#endifif(sp<(unsignedlong)sstack||-sp>=(unsignedlong)sstack+SIGSTKSZ){+sp>=(unsignedlong)sstack+stack_size){ksft_exit_fail_msg("SP is not on sigaltstack\n");}/* put some data on stack. other sighandler will try to overwrite it */
@@ -108,6 +114,10 @@ int main(void)stack_tstk;interr;+/* Make sure more than the required minimum. */+stack_size=getauxval(AT_MINSIGSTKSZ)+SIGSTKSZ;+ksft_print_msg("[NOTE]\tthe stack size is %lu\n",stack_size);+ksft_print_header();ksft_set_plan(3);
@@ -117,7 +127,7 @@ int main(void)sigaction(SIGUSR1,&act,NULL);act.sa_sigaction=my_usr2;sigaction(SIGUSR2,&act,NULL);-sstack=mmap(NULL,SIGSTKSZ,PROT_READ|PROT_WRITE,+sstack=mmap(NULL,stack_size,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK,-1,0);if(sstack==MAP_FAILED){ksft_exit_fail_msg("mmap() - %s\n",strerror(errno));
@@ -139,7 +149,7 @@ int main(void)}stk.ss_sp=sstack;-stk.ss_size=SIGSTKSZ;+stk.ss_size=stack_size;stk.ss_flags=SS_ONSTACK|SS_AUTODISARM;err=sigaltstack(&stk,NULL);if(err){
@@ -161,7 +171,7 @@ int main(void)}}-ustack=mmap(NULL,SIGSTKSZ,PROT_READ|PROT_WRITE,+ustack=mmap(NULL,stack_size,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK,-1,0);if(ustack==MAP_FAILED){ksft_exit_fail_msg("mmap() - %s\n",strerror(errno));
@@ -170,7 +180,7 @@ int main(void)getcontext(&uc);uc.uc_link=NULL;uc.uc_stack.ss_sp=ustack;-uc.uc_stack.ss_size=SIGSTKSZ;+uc.uc_stack.ss_size=stack_size;makecontext(&uc,switch_fn,0);raise(SIGUSR1);
From: Chang S. Bae <hidden> Date: 2021-02-27 17:23:28
Historically, signal.h defines MINSIGSTKSZ (2KB) and SIGSTKSZ (8KB), for
use by all architectures with sigaltstack(2). Over time, the hardware state
size grew, but these constants did not evolve. Today, literal use of these
constants on several architectures may result in signal stack overflow, and
thus user data corruption.
A few years ago, the ARM team addressed this issue by establishing
getauxval(AT_MINSIGSTKSZ). This enables the kernel to supply at runtime
value that is an appropriate replacement on the current and future
hardware.
Add getauxval(AT_MINSIGSTKSZ) support to x86, analogous to the support
added for ARM in commit 94b07c1f8c39 ("arm64: signal: Report signal frame
size to userspace via auxv").
Also, include a documentation to describe x86-specific auxiliary vectors.
Reported-by: Florian Weimer <redacted>
Fixes: c2bc11f10a39 ("x86, AVX-512: Enable AVX-512 States Context Switch")
Signed-off-by: Chang S. Bae <redacted>
Reviewed-by: Len Brown <redacted>
Cc: H.J. Lu <redacted>
Cc: Fenghua Yu <redacted>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: x86@kernel.org
Cc: libc-alpha@sourceware.org
Cc: linux-arch@vger.kernel.org
Cc: linux-api@vger.kernel.org
Cc: linux-doc@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Link: https://bugzilla.kernel.org/show_bug.cgi?id=153531
---
Changes from v5:
* Added a documentation.
---
Documentation/x86/elf_auxvec.rst | 56 ++++++++++++++++++++++++++++++
arch/x86/include/asm/elf.h | 4 +++
arch/x86/include/uapi/asm/auxvec.h | 4 +--
arch/x86/kernel/signal.c | 5 +++
4 files changed, 67 insertions(+), 2 deletions(-)
create mode 100644 Documentation/x86/elf_auxvec.rst
@@ -0,0 +1,56 @@+.. SPDX-License-Identifier: GPL-2.0++==================================+x86-specific ELF Auxiliary Vectors+==================================++This document describes the semantics of the x86 auxiliary vectors.++1. Introduction+---------------++ELF Auxiliary vectors enable the kernel to efficiently provide+configuration specific parameters to userspace. In this example, a program+allocates an alternate stack based on the kernel-provided size.++ #include <sys/auxv.h>+ #include <elf.h>++ #ifndef AT_MINSIGSTKSZ+ #define AT_MINSIGSTKSZ 51+ #endif++ stack_t ss;+ int err;++ ss.ss_size = getauxval(AT_MINSIGSTKSZ) + SIGSTKSZ;+ ss.ss_sp = malloc(ss.ss_size);+ ...++ err = sigaltstack(&ss, NULL);+ ...+++2. The exposed auxiliary vectors+---------------------------------++AT_SYSINFO+ The entry point to the system call function the virtual Dynamic Shared+ Object (vDSO), not exported on 64-bit.++AT_SYSINFO_EHDR+ The start address of the page containing vDSO.++AT_MINSIGSTKSZ+ The minimum stack size required to deliver a signal. It is a calculated+ sigframe size based on the largest possible user context. When programs+ use sigaltstack() to provide alternate signal stack, that stack must be+ at least the size to function properly on this hardware. Note that this+ is a minimum of the kernel to correctly get to the signal handler.+ Additional space must be added to handle objects pushed onto the stack+ by the signal handlers, as well as for nested signal delivery.++ The purpose of this parameter is to accommodate the different stack+ sizes required by different hardware configuration. E.g., the x86+ system supporting the Advanced Vector Extension needs at least 8KB more+ than the one without it.
@@ -312,6 +312,7 @@ do { \NEW_AUX_ENT(AT_SYSINFO,VDSO_ENTRY);\NEW_AUX_ENT(AT_SYSINFO_EHDR,VDSO_CURRENT_BASE);\}\+NEW_AUX_ENT(AT_MINSIGSTKSZ,get_sigframe_size());\}while(0)/*
@@ -328,6 +329,7 @@ extern unsigned long task_size_32bit(void);externunsignedlongtask_size_64bit(intfull_addr_space);externunsignedlongget_mmap_base(intis_legacy);externboolmmap_address_hint_valid(unsignedlongaddr,unsignedlonglen);+externunsignedlongget_sigframe_size(void);#ifdef CONFIG_X86_32
@@ -349,6 +351,7 @@ do { \if(vdso64_enabled)\NEW_AUX_ENT(AT_SYSINFO_EHDR,\(unsignedlong__force)current->mm->context.vdso);\+NEW_AUX_ENT(AT_MINSIGSTKSZ,get_sigframe_size());\}while(0)/* As a historical oddity, the x32 and x86_64 vDSOs are controlled together. */
@@ -357,6 +360,7 @@ do { \if(vdso64_enabled)\NEW_AUX_ENT(AT_SYSINFO_EHDR,\(unsignedlong__force)current->mm->context.vdso);\+NEW_AUX_ENT(AT_MINSIGSTKSZ,get_sigframe_size());\}while(0)#define AT_SYSINFO 32
From: Chang S. Bae <hidden> Date: 2021-02-27 17:26:22
The kernel pushes context on to the userspace stack to prepare for the
user's signal handler. When the user has supplied an alternate signal
stack, via sigaltstack(2), it is easy for the kernel to verify that the
stack size is sufficient for the current hardware context.
Check if writing the hardware context to the alternate stack will exceed
it's size. If yes, then instead of corrupting user-data and proceeding with
the original signal handler, an immediate SIGSEGV signal is delivered.
Instead of calling on_sig_stack(), directly check the new stack pointer
whether in the bounds.
While the kernel allows new source code to discover and use a sufficient
alternate signal stack size, this check is still necessary to protect
binaries with insufficient alternate signal stack size from data
corruption.
Suggested-by: Jann Horn <jannh@google.com>
Signed-off-by: Chang S. Bae <redacted>
Reviewed-by: Len Brown <redacted>
Reviewed-by: Jann Horn <jannh@google.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Jann Horn <jannh@google.com>
Cc: x86@kernel.org
Cc: linux-kernel@vger.kernel.org
---
Changes from v5:
* Fixed the overflow check. (Andy Lutomirski)
* Updated the changelog.
Changes from v3:
* Updated the changelog (Borislav Petkov)
Changes from v2:
* Simplified the implementation (Jann Horn)
---
arch/x86/kernel/signal.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
@@ -251,8 +251,11 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,/* This is the X/Open sanctioned signal stack switching. */if(ka->sa.sa_flags&SA_ONSTACK){-if(sas_ss_flags(sp)==0)+if(sas_ss_flags(sp)==0){sp=current->sas_ss_sp+current->sas_ss_size;+/* On the alternate signal stack */+onsigstack=true;+}}elseif(IS_ENABLED(CONFIG_X86_32)&&!onsigstack&®s->ss!=__USER_DS&&
@@ -272,7 +275,8 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,*Ifweareonthealternatesignalstackandwouldoverflowit,don't.*Returnanalways-bogusaddressinsteadsowewilldiewithSIGSEGV.*/-if(onsigstack&&!likely(on_sig_stack(sp)))+if(onsigstack&&unlikely(sp<=current->sas_ss_sp||+sp-current->sas_ss_sp>current->sas_ss_size))return(void__user*)-1L;/* save i387 and extended state */
From: Chang S. Bae <hidden> Date: 2021-02-27 17:30:28
The test measures the kernel's signal delivery with different (enough vs.
insufficient) stack sizes.
Signed-off-by: Chang S. Bae <redacted>
Reviewed-by: Len Brown <redacted>
Cc: x86@kernel.org
Cc: linux-kselftest@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
---
Changes from v3:
* Revised test messages again (Borislav Petkov)
Changes from v2:
* Revised test messages (Borislav Petkov)
---
tools/testing/selftests/x86/Makefile | 2 +-
tools/testing/selftests/x86/sigaltstack.c | 128 ++++++++++++++++++++++
2 files changed, 129 insertions(+), 1 deletion(-)
create mode 100644 tools/testing/selftests/x86/sigaltstack.c
@@ -0,0 +1,128 @@+// SPDX-License-Identifier: GPL-2.0-only++#define _GNU_SOURCE+#include<signal.h>+#include<stdio.h>+#include<stdbool.h>+#include<string.h>+#include<err.h>+#include<errno.h>+#include<limits.h>+#include<sys/mman.h>+#include<sys/auxv.h>+#include<sys/prctl.h>+#include<sys/resource.h>+#include<setjmp.h>++/* sigaltstack()-enforced minimum stack */+#define ENFORCED_MINSIGSTKSZ 2048++#ifndef AT_MINSIGSTKSZ+# define AT_MINSIGSTKSZ 51+#endif++staticintnerrs;++staticboolsigalrm_expected;++staticunsignedlongat_minstack_size;++staticvoidsethandler(intsig,void(*handler)(int,siginfo_t*,void*),+intflags)+{+structsigactionsa;++memset(&sa,0,sizeof(sa));+sa.sa_sigaction=handler;+sa.sa_flags=SA_SIGINFO|flags;+sigemptyset(&sa.sa_mask);+if(sigaction(sig,&sa,0))+err(1,"sigaction");+}++staticvoidclearhandler(intsig)+{+structsigactionsa;++memset(&sa,0,sizeof(sa));+sa.sa_handler=SIG_DFL;+sigemptyset(&sa.sa_mask);+if(sigaction(sig,&sa,0))+err(1,"sigaction");+}++staticintsetup_altstack(void*start,unsignedlongsize)+{+stack_tss;++memset(&ss,0,sizeof(ss));+ss.ss_size=size;+ss.ss_sp=start;++returnsigaltstack(&ss,NULL);+}++staticjmp_bufjmpbuf;++staticvoidsigsegv(intsig,siginfo_t*info,void*ctx_void)+{+if(sigalrm_expected){+printf("[FAIL]\tWrong signal delivered: SIGSEGV (expected SIGALRM).");+nerrs++;+}else{+printf("[OK]\tSIGSEGV signal delivered.\n");+}++siglongjmp(jmpbuf,1);+}++staticvoidsigalrm(intsig,siginfo_t*info,void*ctx_void)+{+if(!sigalrm_expected){+printf("[FAIL]\tWrong signal delivered: SIGALRM (expected SIGSEGV).");+nerrs++;+}else{+printf("[OK]\tSIGALRM signal delivered.\n");+}+}++staticvoidtest_sigaltstack(void*altstack,unsignedlongsize)+{+if(setup_altstack(altstack,size))+err(1,"sigaltstack()");++sigalrm_expected=(size>at_minstack_size)?true:false;++sethandler(SIGSEGV,sigsegv,0);+sethandler(SIGALRM,sigalrm,SA_ONSTACK);++if(!sigsetjmp(jmpbuf,1)){+printf("[RUN]\tTest an alternate signal stack of %ssufficient size.\n",+sigalrm_expected?"":"in");+printf("\tRaise SIGALRM. %s is expected to be delivered.\n",+sigalrm_expected?"It":"SIGSEGV");+raise(SIGALRM);+}++clearhandler(SIGALRM);+clearhandler(SIGSEGV);+}++intmain(void)+{+void*altstack;++at_minstack_size=getauxval(AT_MINSIGSTKSZ);++altstack=mmap(NULL,at_minstack_size+SIGSTKSZ,PROT_READ|PROT_WRITE,+MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK,-1,0);+if(altstack==MAP_FAILED)+err(1,"mmap()");++if((ENFORCED_MINSIGSTKSZ+1)<at_minstack_size)+test_sigaltstack(altstack,ENFORCED_MINSIGSTKSZ+1);++test_sigaltstack(altstack,at_minstack_size+SIGSTKSZ);++returnnerrs==0?0:1;+}
On Sat, Feb 27, 2021 at 08:59:06AM -0800, Chang S. Bae wrote:
quoted hunk
Define the AT_MINSIGSTKSZ in generic Linux. It is already used as generic
ABI in glibc's generic elf.h, and this define will prevent future namespace
conflicts. In particular, x86 is also using this generic definition.
Signed-off-by: Chang S. Bae <redacted>
Reviewed-by: Len Brown <redacted>
Cc: Carlos O'Donell <redacted>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: libc-alpha@sourceware.org
Cc: linux-arch@vger.kernel.org
Cc: linux-api@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
Change from v5:
* Reverted the arm64 change. (Dave Martin)
* Massaged the changelog.
Change from v4:
* Added as a new patch (Carlos O'Donell)
---
include/uapi/linux/auxvec.h | 3 +++
1 file changed, 3 insertions(+)
@@ -33,5 +33,8 @@#define AT_EXECFN 31 /* filename of program */+#ifndef AT_MINSIGSTKSZ+#define AT_MINSIGSTKSZ 51 /* stack needed for signal delivery */
I know glibc's comment says a similar thing but the correct thing to say
here should be "minimal stack size for signal delivery" or so. Even the
variable name alludes to that too.
--
Regards/Gruss,
Boris.
SUSE Software Solutions Germany GmbH, GF: Felix Imendörffer, HRB 36809, AG Nürnberg
On Sat, Feb 27, 2021 at 08:59:08AM -0800, Chang S. Bae wrote:
Historically, signal.h defines MINSIGSTKSZ (2KB) and SIGSTKSZ (8KB), for
use by all architectures with sigaltstack(2). Over time, the hardware state
size grew, but these constants did not evolve. Today, literal use of these
constants on several architectures may result in signal stack overflow, and
thus user data corruption.
A few years ago, the ARM team addressed this issue by establishing
getauxval(AT_MINSIGSTKSZ). This enables the kernel to supply at runtime
value that is an appropriate replacement on the current and future
hardware.
Add getauxval(AT_MINSIGSTKSZ) support to x86, analogous to the support
added for ARM in commit 94b07c1f8c39 ("arm64: signal: Report signal frame
size to userspace via auxv").
Also, include a documentation to describe x86-specific auxiliary vectors.
Reported-by: Florian Weimer <redacted>
Fixes: c2bc11f10a39 ("x86, AVX-512: Enable AVX-512 States Context Switch")
Right, so this has a Fixes: tag and points to bugzilla entry which talks
about signal stack corruption with AVX-512F.
But if this is going to be backported to stable, then the patch(es)
should be minimal and not contain documentation. And if so, one will
need all three to be backported, which means, a cc:stable should contain
a comment explaining that.
Or am I misreading and they should not need to be backported to stable
because some <non-obvious reason>?
Also, I'm not sure backporting a patch to stable which changes ABI is
ok. It probably is but I don't know.
So what's the deal here?
Signed-off-by: Chang S. Bae <redacted>
Reviewed-by: Len Brown <redacted>
Cc: H.J. Lu <redacted>
Cc: Fenghua Yu <redacted>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: x86@kernel.org
Cc: libc-alpha@sourceware.org
Cc: linux-arch@vger.kernel.org
Cc: linux-api@vger.kernel.org
Cc: linux-doc@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Link: https://bugzilla.kernel.org/show_bug.cgi?id=153531
---
Changes from v5:
* Added a documentation.
---
Documentation/x86/elf_auxvec.rst | 56 ++++++++++++++++++++++++++++++
arch/x86/include/asm/elf.h | 4 +++
arch/x86/include/uapi/asm/auxvec.h | 4 +--
arch/x86/kernel/signal.c | 5 +++
4 files changed, 67 insertions(+), 2 deletions(-)
@@ -0,0 +1,56 @@+.. SPDX-License-Identifier: GPL-2.0++==================================+x86-specific ELF Auxiliary Vectors+==================================++This document describes the semantics of the x86 auxiliary vectors.++1. Introduction+---------------++ELF Auxiliary vectors enable the kernel to efficiently provide+configuration specific parameters to userspace. In this example, a program+allocates an alternate stack based on the kernel-provided size.++ #include <sys/auxv.h>+ #include <elf.h>++ #ifndef AT_MINSIGSTKSZ+ #define AT_MINSIGSTKSZ 51+ #endif++ stack_t ss;+ int err;++ ss.ss_size = getauxval(AT_MINSIGSTKSZ) + SIGSTKSZ;+ ss.ss_sp = malloc(ss.ss_size);+ ...++ err = sigaltstack(&ss, NULL);+ ...
That source code needs some special markup to look like source code -
currently, the result looks bad.
+
+
+2. The exposed auxiliary vectors
+---------------------------------
+
+AT_SYSINFO
+ The entry point to the system call function the virtual Dynamic Shared
+ Object (vDSO), not exported on 64-bit.
I can't parse that sentence.
+
+AT_SYSINFO_EHDR
+ The start address of the page containing vDSO.
^
the
+
+AT_MINSIGSTKSZ
+ The minimum stack size required to deliver a signal. It is a calculated
+ sigframe size based on the largest possible user context. When programs
+ use sigaltstack() to provide alternate signal stack, that stack must be
+ at least the size to function properly on this hardware. Note that this
+ is a minimum of the kernel to correctly get to the signal handler.
I get what this is trying to say but it reads weird. Simplify pls.
+ Additional space must be added to handle objects pushed onto the stack
+ by the signal handlers, as well as for nested signal delivery.
+
+ The purpose of this parameter is to accommodate the different stack
+ sizes required by different hardware configuration. E.g., the x86
+ system supporting the Advanced Vector Extension needs at least 8KB more
+ than the one without it.
#define AT_EXECFN 31 /* filename of program */
+#ifndef AT_MINSIGSTKSZ
+#define AT_MINSIGSTKSZ 51 /* stack needed for signal delivery */
I know glibc's comment says a similar thing but the correct thing to say
here should be "minimal stack size for signal delivery" or so. Even the
variable name alludes to that too.
On Mar 5, 2021, at 02:43, Borislav Petkov [off-list ref] wrote:
On Sat, Feb 27, 2021 at 08:59:08AM -0800, Chang S. Bae wrote:
quoted
Historically, signal.h defines MINSIGSTKSZ (2KB) and SIGSTKSZ (8KB), for
use by all architectures with sigaltstack(2). Over time, the hardware state
size grew, but these constants did not evolve. Today, literal use of these
constants on several architectures may result in signal stack overflow, and
thus user data corruption.
A few years ago, the ARM team addressed this issue by establishing
getauxval(AT_MINSIGSTKSZ). This enables the kernel to supply at runtime
value that is an appropriate replacement on the current and future
hardware.
Add getauxval(AT_MINSIGSTKSZ) support to x86, analogous to the support
added for ARM in commit 94b07c1f8c39 ("arm64: signal: Report signal frame
size to userspace via auxv").
Also, include a documentation to describe x86-specific auxiliary vectors.
Reported-by: Florian Weimer <redacted>
Fixes: c2bc11f10a39 ("x86, AVX-512: Enable AVX-512 States Context Switch")
Right, so this has a Fixes: tag and points to bugzilla entry which talks
about signal stack corruption with AVX-512F.
But if this is going to be backported to stable, then the patch(es)
should be minimal and not contain documentation. And if so, one will
need all three to be backported, which means, a cc:stable should contain
a comment explaining that.
Or am I misreading and they should not need to be backported to stable
because some <non-obvious reason>?
Also, I'm not sure backporting a patch to stable which changes ABI is
ok. It probably is but I don't know.
So what's the deal here?
Yeah, right. While this attempts to fix the issue, it involves the ABI change.
Len and I think PATCH5 [1] is rather a backport candidate as it gives a more
reasonable behavior.
At least, I can make a new patch for this documentation if you think it is the
right way.
+2. The exposed auxiliary vectors
+---------------------------------
+
+AT_SYSINFO
+ The entry point to the system call function the virtual Dynamic Shared
+ Object (vDSO), not exported on 64-bit.
I can't parse that sentence.
quoted
+
+AT_SYSINFO_EHDR
+ The start address of the page containing vDSO.
^
the
quoted
+
+AT_MINSIGSTKSZ
+ The minimum stack size required to deliver a signal. It is a calculated
+ sigframe size based on the largest possible user context. When programs
+ use sigaltstack() to provide alternate signal stack, that stack must be
+ at least the size to function properly on this hardware. Note that this
+ is a minimum of the kernel to correctly get to the signal handler.
I get what this is trying to say but it reads weird. Simplify pls.
quoted
+ Additional space must be added to handle objects pushed onto the stack
+ by the signal handlers, as well as for nested signal delivery.
+
+ The purpose of this parameter is to accommodate the different stack
+ sizes required by different hardware configuration. E.g., the x86
+ system supporting the Advanced Vector Extension needs at least 8KB more
+ than the one without it.
That could be simplified too.
Rewrote like this:
AT_SYSINFO is used for locating the vsyscall entry point. It is not exported
on 64-bit mode.
AT_SYSINFO_EHDR is the start address of the page containing the vDSO.
AT_MINSIGSTKSZ denotes the minimum stack size required by the kernel to
deliver a signal to user-space. AT_MINSIGSTKSZ comprehends the space consumed
by the kernel to accommodate the user context for the current hardware
configuration. It does not comprehend subsequent user-space stack
consumption, which must be added by the user. (e.g. Above, user-space adds
SIGSTKSZ to AT_MINSIGSTKSZ.)
On Wed, Mar 10, 2021 at 04:34:40PM +0000, Bae, Chang Seok wrote:
Yeah, right. While this attempts to fix the issue, it involves the ABI change.
Len and I think PATCH5 [1] is rather a backport candidate as it gives a more
reasonable behavior.
Yap, patch 5 is more conservative, sure.
I guess I can take it out of the set and send it Linuswards now.
quoted
That source code needs some special markup to look like source code -
currently, the result looks bad.
How about this code:
No, build the docs by doing
make htmldocs
and look at the result.
Btw, you should always look at the result before sending it out.
Rewrote like this:
AT_SYSINFO is used for locating the vsyscall entry point. It is not exported
on 64-bit mode.
AT_SYSINFO_EHDR is the start address of the page containing the vDSO.
AT_MINSIGSTKSZ denotes the minimum stack size required by the kernel to
deliver a signal to user-space. AT_MINSIGSTKSZ comprehends the space consumed
by the kernel to accommodate the user context for the current hardware
configuration. It does not comprehend subsequent user-space stack
consumption, which must be added by the user. (e.g. Above, user-space adds
SIGSTKSZ to AT_MINSIGSTKSZ.)
Better.
Thx.
--
Regards/Gruss,
Boris.
SUSE Software Solutions Germany GmbH, GF: Felix Imendörffer, HRB 36809, AG Nürnberg