arm64: expose FAR_EL1 tag bits in siginfo
Subsystems (15)
v12 cover arm64: expose FAR_EL1 tag bits in siginfo
The kernel currently clears the tag bits (i.e. bits 56-63) in the fault address exposed via siginfo.si_addr and sigcontext.fault_address. However, the tag bits may be needed by tools in order to accurately diagnose memory errors, such as HWASan [1] or future tools based on the Memory Tagging Extension (MTE).
We should not stop clearing these bits in the existing fault address fields, because there may be existing userspace applications that are expecting the tag bits to be cleared. Instead, create a new pair of union fields in siginfo._sigfault, and store the tag bits of FAR_EL1 there, together with a mask specifying which bits are valid.
However, one does not simply add fields to siginfo, at least not without a mechanism for userspace to detect that they are present and valid. Therefore, the first seven patches in this series introduce a mechanism for userspace to detect the presence of our new siginfo fields, and the last patch uses it to advertise the presence of said fields.
The series can be viewed on Gerrit here:
https://linux-review.googlesource.com/q/Ia8876bad8c798e0a32df7c2ce1256c4771c81446
[1] http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
Helge Deller (1):
parisc: Drop parisc special case for __sighandler_t
Peter Collingbourne (7):
parisc: start using signal-defs.h
arch: move SA_* definitions to generic headers
signal: clear non-uapi flag bits when passing/returning sa_flags
signal: define the SA_UNSUPPORTED bit in sa_flags
signal: deduplicate code dealing with common _sigfault fields
signal: define the field siginfo.si_xflags
arm64: expose FAR_EL1 tag bits in siginfo
Documentation/arm64/tagged-pointers.rst | 21 +++- arch/alpha/include/uapi/asm/signal.h | 14 --- arch/arm/include/asm/signal.h | 2 + arch/arm/include/uapi/asm/signal.h | 28 +---- arch/arm64/include/asm/exception.h | 2 +- arch/arm64/include/asm/signal.h | 19 +++ arch/arm64/include/asm/system_misc.h | 2 +- arch/arm64/include/asm/traps.h | 6 +- arch/arm64/kernel/debug-monitors.c | 5 +- arch/arm64/kernel/entry-common.c | 2 - arch/arm64/kernel/ptrace.c | 7 +- arch/arm64/kernel/sys_compat.c | 5 +- arch/arm64/kernel/traps.c | 29 ++--- arch/arm64/mm/fault.c | 68 ++++++----- arch/h8300/include/uapi/asm/signal.h | 24 ---- arch/ia64/include/uapi/asm/signal.h | 24 ---- arch/m68k/include/uapi/asm/signal.h | 24 ---- arch/mips/include/uapi/asm/signal.h | 12 -- arch/parisc/include/asm/signal.h | 2 + arch/parisc/include/uapi/asm/signal.h | 34 +----- arch/powerpc/include/uapi/asm/signal.h | 24 ---- arch/powerpc/platforms/powernv/vas-fault.c | 1 + arch/s390/include/uapi/asm/signal.h | 24 ---- arch/sparc/include/uapi/asm/signal.h | 4 +- arch/x86/include/uapi/asm/signal.h | 24 ---- arch/x86/kernel/signal_compat.c | 19 +-- arch/xtensa/include/uapi/asm/signal.h | 24 ---- include/linux/compat.h | 4 + include/linux/signal.h | 29 +++++ include/linux/signal_types.h | 12 ++ include/uapi/asm-generic/siginfo.h | 14 +++ include/uapi/asm-generic/signal-defs.h | 58 +++++++++ include/uapi/asm-generic/signal.h | 29 ----- include/uapi/linux/ptrace.h | 12 ++ kernel/ptrace.c | 32 ++++- kernel/signal.c | 134 +++++++++++---------- 36 files changed, 345 insertions(+), 429 deletions(-) create mode 100644 arch/arm64/include/asm/signal.h
Signature · 7 lines
2.29.0.rc1.297.gfa9743e501-goog _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
PATCH v12 1/8 parisc: Drop parisc special case for __sighandler_t
From: Helge Deller <[email protected]>
I believe we can and *should* drop this parisc-specific typedef for __sighandler_t when compiling a 64-bit kernel. The reasons:
1. We don't have a 64-bit userspace yet, so nothing (on userspace side) can break.
2. Inside the Linux kernel, this is only used in kernel/signal.c, in function kernel_sigaction() where the signal handler is compared against SIG_IGN. SIG_IGN is defined as (__sighandler_t)1), so only the pointers are compared.
3. Even when a 64-bit userspace gets added at some point, I think __sighandler_t should be defined what it is: a function pointer struct.
I compiled kernel/signal.c with and without the patch, and the produced code is identical in both cases.
--- arch/parisc/include/uapi/asm/signal.h | 8 -------- 1 file changed, 8 deletions(-)
arch/parisc/include/uapi/asm/signal.h +0 -8
@@ -85,16 +85,8 @@struct siginfo ;/* Type of a signal handler. */ -#if defined(__LP64__) -/* function pointers on 64-bit parisc are pointers to little structs and the -* compiler doesn't support code which changes or tests the address of -* the function in the little struct. This is really ugly -PB -*/ -typedef char __user *__sighandler_t ; -#else typedef void __signalfn_t (int );typedef __signalfn_t __user *__sighandler_t ; -#endif typedef struct sigaltstack { void __user *ss_sp;
Signature · 7 lines
2.29.0.rc1.297.gfa9743e501-goog _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
PATCH v12 2/8 parisc: start using signal-defs.h
In reply to Peter CollingbourneWe currently include signal-defs.h on all architectures except parisc. Make parisc fall in line. This will make maintenance easier once the flag bits are moved here.
--- arch/parisc/include/uapi/asm/signal.h | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-)
arch/parisc/include/uapi/asm/signal.h +1 -12
@@ -68,14 +68,7 @@#define MINSIGSTKSZ 2048#define SIGSTKSZ 8192 - -#define SIG_BLOCK 0/* for blocking signals */ -#define SIG_UNBLOCK 1/* for unblocking signals */ -#define SIG_SETMASK 2/* for setting the signal mask */ - -#define SIG_DFL ((__sighandler_t)0)/* default signal handling */ -#define SIG_IGN ((__sighandler_t)1)/* ignore signal */ -#define SIG_ERR ((__sighandler_t)-1)/* error return from signal */ +#include <asm-generic/signal-defs.h> # ifndef __ASSEMBLY__
@@ -84,10 +77,6 @@/* Avoid too many header ordering problems. */ struct siginfo ; -/* Type of a signal handler. */ -typedef void __signalfn_t (int ); -typedef __signalfn_t __user *__sighandler_t ; - typedef struct sigaltstack { void __user *ss_sp; int ss_flags;
Signature · 7 lines
2.29.0.rc1.297.gfa9743e501-goog _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
PATCH v12 3/8 arch: move SA_* definitions to generic headers
In reply to Peter CollingbourneMost architectures with the exception of alpha, mips, parisc and sparc use the same values for these flags. Move their definitions into asm-generic/signal-defs.h and allow the architectures with non-standard values to override them. Also, document the non-standard flag values in order to make it easier to add new generic flags in the future.
A consequence of this change is that on powerpc and x86, the constants' values aside from SA_RESETHAND change signedness from unsigned to signed. This is not expected to impact realistic use of these constants. In particular the typical use of the constants where they are or'ed together and assigned to sa_flags (or another int variable) would not be affected.
---
v11:
- tweak the commit message to point out the change from unsigned to signed
v10:
- move the comments around and add one for SA_SIGINFO
arch/alpha/include/uapi/asm/signal.h | 14 -------- arch/arm/include/uapi/asm/signal.h | 28 ++------------- arch/h8300/include/uapi/asm/signal.h | 24 ------------- arch/ia64/include/uapi/asm/signal.h | 24 ------------- arch/m68k/include/uapi/asm/signal.h | 24 ------------- arch/mips/include/uapi/asm/signal.h | 12 ------- arch/parisc/include/uapi/asm/signal.h | 13 ------- arch/powerpc/include/uapi/asm/signal.h | 24 ------------- arch/s390/include/uapi/asm/signal.h | 24 ------------- arch/sparc/include/uapi/asm/signal.h | 4 +-- arch/x86/include/uapi/asm/signal.h | 24 ------------- arch/xtensa/include/uapi/asm/signal.h | 24 ------------- include/uapi/asm-generic/signal-defs.h | 47 ++++++++++++++++++++++++++ include/uapi/asm-generic/signal.h | 29 ---------------- 14 files changed, 51 insertions(+), 264 deletions(-)
arch/alpha/include/uapi/asm/signal.h +0 -14
@@ -60,20 +60,6 @@ typedef unsigned long sigset_t;#define SIGRTMIN 32#define SIGRTMAX _NSIG -/* -* SA_FLAGS values: -* -* SA_ONSTACK indicates that a registered stack_t will be used. -* SA_RESTART flag to get restarting signals (which were the default long ago) -* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -* SA_RESETHAND clears the handler when the signal is delivered. -* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -* SA_NODEFER prevents the current signal from being masked in the handler. -* -* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -* Unix names RESETHAND and NODEFER respectively. -*/ -#define SA_ONSTACK 0x00000001#define SA_RESTART 0x00000002#define SA_NOCLDSTOP 0x00000004
arch/arm/include/uapi/asm/signal.h +3 -25
@@ -60,33 +60,11 @@ typedef unsigned long sigset_t;#define SIGSWI 32/* -* SA_FLAGS values: -* -* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -* SA_SIGINFO deliver the signal with SIGINFO structs -* SA_THIRTYTWO delivers the signal in 32-bit mode, even if the task -* is running in 26-bit. -* SA_ONSTACK allows alternate signal stacks (see sigaltstack(2)). -* SA_RESTART flag to get restarting signals (which were the default long ago) -* SA_NODEFER prevents the current signal from being masked in the handler. -* SA_RESETHAND clears the handler when the signal is delivered. -* -* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -* Unix names RESETHAND and NODEFER respectively. +* SA_THIRTYTWO historically meant deliver the signal in 32-bit mode, even if +* the task is running in 26-bit. But since the kernel no longer supports +* 26-bit mode, the flag has no effect. */ -#define SA_NOCLDSTOP 0x00000001 -#define SA_NOCLDWAIT 0x00000002 -#define SA_SIGINFO 0x00000004#define SA_THIRTYTWO 0x02000000 -#define SA_RESTORER 0x04000000 -#define SA_ONSTACK 0x08000000 -#define SA_RESTART 0x10000000 -#define SA_NODEFER 0x40000000 -#define SA_RESETHAND 0x80000000 - -#define SA_NOMASK SA_NODEFER -#define SA_ONESHOT SA_RESETHAND#define MINSIGSTKSZ 2048#define SIGSTKSZ 8192
arch/h8300/include/uapi/asm/signal.h +0 -24
@@ -57,30 +57,6 @@ typedef unsigned long sigset_t;#define SIGRTMIN 32#define SIGRTMAX _NSIG -/* -* SA_FLAGS values: -* -* SA_ONSTACK indicates that a registered stack_t will be used. -* SA_RESTART flag to get restarting signals (which were the default long ago) -* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -* SA_RESETHAND clears the handler when the signal is delivered. -* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -* SA_NODEFER prevents the current signal from being masked in the handler. -* -* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -* Unix names RESETHAND and NODEFER respectively. -*/ -#define SA_NOCLDSTOP 0x00000001 -#define SA_NOCLDWAIT 0x00000002/* not supported yet */ -#define SA_SIGINFO 0x00000004 -#define SA_ONSTACK 0x08000000 -#define SA_RESTART 0x10000000 -#define SA_NODEFER 0x40000000 -#define SA_RESETHAND 0x80000000 - -#define SA_NOMASK SA_NODEFER -#define SA_ONESHOT SA_RESETHAND -#define SA_RESTORER 0x04000000#define MINSIGSTKSZ 2048
arch/ia64/include/uapi/asm/signal.h +0 -24
@@ -53,30 +53,6 @@#define SIGRTMIN 32#define SIGRTMAX _NSIG -/* -* SA_FLAGS values: -* -* SA_ONSTACK indicates that a registered stack_t will be used. -* SA_RESTART flag to get restarting signals (which were the default long ago) -* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -* SA_RESETHAND clears the handler when the signal is delivered. -* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -* SA_NODEFER prevents the current signal from being masked in the handler. -* -* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -* Unix names RESETHAND and NODEFER respectively. -*/ -#define SA_NOCLDSTOP 0x00000001 -#define SA_NOCLDWAIT 0x00000002 -#define SA_SIGINFO 0x00000004 -#define SA_ONSTACK 0x08000000 -#define SA_RESTART 0x10000000 -#define SA_NODEFER 0x40000000 -#define SA_RESETHAND 0x80000000 - -#define SA_NOMASK SA_NODEFER -#define SA_ONESHOT SA_RESETHAND -#define SA_RESTORER 0x04000000/*
arch/m68k/include/uapi/asm/signal.h +0 -24
@@ -57,30 +57,6 @@ typedef unsigned long sigset_t;#define SIGRTMIN 32#define SIGRTMAX _NSIG -/* -* SA_FLAGS values: -* -* SA_ONSTACK indicates that a registered stack_t will be used. -* SA_RESTART flag to get restarting signals (which were the default long ago) -* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -* SA_RESETHAND clears the handler when the signal is delivered. -* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -* SA_NODEFER prevents the current signal from being masked in the handler. -* -* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -* Unix names RESETHAND and NODEFER respectively. -*/ -#define SA_NOCLDSTOP 0x00000001 -#define SA_NOCLDWAIT 0x00000002 -#define SA_SIGINFO 0x00000004 -#define SA_ONSTACK 0x08000000 -#define SA_RESTART 0x10000000 -#define SA_NODEFER 0x40000000 -#define SA_RESETHAND 0x80000000 - -#define SA_NOMASK SA_NODEFER -#define SA_ONESHOT SA_RESETHAND -#define MINSIGSTKSZ 2048#define SIGSTKSZ 8192
arch/mips/include/uapi/asm/signal.h +0 -12
@@ -62,18 +62,6 @@ typedef unsigned long old_sigset_t; /* at least 32 bits */#define SIGRTMAX _NSIG/* -* SA_FLAGS values: -* -* SA_ONSTACK indicates that a registered stack_t will be used. -* SA_RESTART flag to get restarting signals (which were the default long ago) -* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -* SA_RESETHAND clears the handler when the signal is delivered. -* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -* SA_NODEFER prevents the current signal from being masked in the handler. -* -* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -* Unix names RESETHAND and NODEFER respectively. -* * SA_RESTORER used to be defined as 0x04000000 but only the O32 ABI ever * supported its use and no libc was using it, so the entire sa-restorer * functionality was removed with lmo commit 39bffc12c3580ab for 2.5.48
arch/parisc/include/uapi/asm/signal.h +0 -13
@@ -41,19 +41,6 @@#define SIGRTMIN 32#define SIGRTMAX _NSIG -/* -* SA_FLAGS values: -* -* SA_ONSTACK indicates that a registered stack_t will be used. -* SA_RESTART flag to get restarting signals (which were the default long ago) -* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -* SA_RESETHAND clears the handler when the signal is delivered. -* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -* SA_NODEFER prevents the current signal from being masked in the handler. -* -* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -* Unix names RESETHAND and NODEFER respectively. -*/ #define SA_ONSTACK 0x00000001#define SA_RESETHAND 0x00000004#define SA_NOCLDSTOP 0x00000008
arch/powerpc/include/uapi/asm/signal.h +0 -24
@@ -60,30 +60,6 @@ typedef struct {#define SIGRTMIN 32#define SIGRTMAX _NSIG -/* -* SA_FLAGS values: -* -* SA_ONSTACK is not currently supported, but will allow sigaltstack(2). -* SA_RESTART flag to get restarting signals (which were the default long ago) -* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -* SA_RESETHAND clears the handler when the signal is delivered. -* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -* SA_NODEFER prevents the current signal from being masked in the handler. -* -* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -* Unix names RESETHAND and NODEFER respectively. -*/ -#define SA_NOCLDSTOP 0x00000001U -#define SA_NOCLDWAIT 0x00000002U -#define SA_SIGINFO 0x00000004U -#define SA_ONSTACK 0x08000000U -#define SA_RESTART 0x10000000U -#define SA_NODEFER 0x40000000U -#define SA_RESETHAND 0x80000000U - -#define SA_NOMASK SA_NODEFER -#define SA_ONESHOT SA_RESETHAND -#define SA_RESTORER 0x04000000U#define MINSIGSTKSZ 2048
arch/s390/include/uapi/asm/signal.h +0 -24
@@ -65,30 +65,6 @@ typedef unsigned long sigset_t;#define SIGRTMIN 32#define SIGRTMAX _NSIG -/* -* SA_FLAGS values: -* -* SA_ONSTACK indicates that a registered stack_t will be used. -* SA_RESTART flag to get restarting signals (which were the default long ago) -* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -* SA_RESETHAND clears the handler when the signal is delivered. -* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -* SA_NODEFER prevents the current signal from being masked in the handler. -* -* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -* Unix names RESETHAND and NODEFER respectively. -*/ -#define SA_NOCLDSTOP 0x00000001 -#define SA_NOCLDWAIT 0x00000002 -#define SA_SIGINFO 0x00000004 -#define SA_ONSTACK 0x08000000 -#define SA_RESTART 0x10000000 -#define SA_NODEFER 0x40000000 -#define SA_RESETHAND 0x80000000 - -#define SA_NOMASK SA_NODEFER -#define SA_ONESHOT SA_RESETHAND -#define SA_RESTORER 0x04000000#define MINSIGSTKSZ 2048
arch/sparc/include/uapi/asm/signal.h +1 -3
@@ -137,13 +137,11 @@ struct sigstack {#define SA_STACK _SV_SSTACK#define SA_ONSTACK _SV_SSTACK#define SA_RESTART _SV_INTR -#define SA_ONESHOT _SV_RESET +#define SA_RESETHAND _SV_RESET#define SA_NODEFER 0x20u#define SA_NOCLDWAIT 0x100u#define SA_SIGINFO 0x200u -#define SA_NOMASK SA_NODEFER -#define SIG_BLOCK 0x01/* for blocking signals */ #define SIG_UNBLOCK 0x02/* for unblocking signals */ #define SIG_SETMASK 0x04/* for setting the signal mask */
arch/x86/include/uapi/asm/signal.h +0 -24
@@ -62,30 +62,6 @@ typedef unsigned long sigset_t;#define SIGRTMIN 32#define SIGRTMAX _NSIG -/* -* SA_FLAGS values: -* -* SA_ONSTACK indicates that a registered stack_t will be used. -* SA_RESTART flag to get restarting signals (which were the default long ago) -* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -* SA_RESETHAND clears the handler when the signal is delivered. -* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -* SA_NODEFER prevents the current signal from being masked in the handler. -* -* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -* Unix names RESETHAND and NODEFER respectively. -*/ -#define SA_NOCLDSTOP 0x00000001u -#define SA_NOCLDWAIT 0x00000002u -#define SA_SIGINFO 0x00000004u -#define SA_ONSTACK 0x08000000u -#define SA_RESTART 0x10000000u -#define SA_NODEFER 0x40000000u -#define SA_RESETHAND 0x80000000u - -#define SA_NOMASK SA_NODEFER -#define SA_ONESHOT SA_RESETHAND -#define SA_RESTORER 0x04000000#define MINSIGSTKSZ 2048
arch/xtensa/include/uapi/asm/signal.h +0 -24
@@ -72,30 +72,6 @@ typedef struct {#define SIGRTMIN 32#define SIGRTMAX (_NSIG-1) -/* -* SA_FLAGS values: -* -* SA_ONSTACK indicates that a registered stack_t will be used. -* SA_RESTART flag to get restarting signals (which were the default long ago) -* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -* SA_RESETHAND clears the handler when the signal is delivered. -* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -* SA_NODEFER prevents the current signal from being masked in the handler. -* -* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -* Unix names RESETHAND and NODEFER respectively. -*/ -#define SA_NOCLDSTOP 0x00000001 -#define SA_NOCLDWAIT 0x00000002/* not supported yet */ -#define SA_SIGINFO 0x00000004 -#define SA_ONSTACK 0x08000000 -#define SA_RESTART 0x10000000 -#define SA_NODEFER 0x40000000 -#define SA_RESETHAND 0x80000000 - -#define SA_NOMASK SA_NODEFER -#define SA_ONESHOT SA_RESETHAND -#define SA_RESTORER 0x04000000#define MINSIGSTKSZ 2048
include/uapi/asm-generic/signal-defs.h +47 -0
53 lines not on this page · raw message
include/uapi/asm-generic/signal.h +0 -29
@@ -52,35 +52,6 @@#define SIGRTMAX _NSIG#endif -/* -* SA_FLAGS values: -* -* SA_ONSTACK indicates that a registered stack_t will be used. -* SA_RESTART flag to get restarting signals (which were the default long ago) -* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -* SA_RESETHAND clears the handler when the signal is delivered. -* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -* SA_NODEFER prevents the current signal from being masked in the handler. -* -* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -* Unix names RESETHAND and NODEFER respectively. -*/ -#define SA_NOCLDSTOP 0x00000001 -#define SA_NOCLDWAIT 0x00000002 -#define SA_SIGINFO 0x00000004 -#define SA_ONSTACK 0x08000000 -#define SA_RESTART 0x10000000 -#define SA_NODEFER 0x40000000 -#define SA_RESETHAND 0x80000000 - -#define SA_NOMASK SA_NODEFER -#define SA_ONESHOT SA_RESETHAND - -/* -* New architectures should not define the obsolete -* SA_RESTORER 0x04000000 -*/ -#if !definedMINSIGSTKSZ || !definedSIGSTKSZ #define MINSIGSTKSZ 2048#define SIGSTKSZ 8192
Signature · 7 lines
2.29.0.rc1.297.gfa9743e501-goog _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Re: [PATCH v12 3/8] arch: move SA_* definitions to generic headers
Quoted 13 lines · Peter Collingbourne
Most architectures with the exception of alpha, mips, parisc and sparc use the same values for these flags. Move their definitions into
asm-generic/signal-defs.hand allow the architectures with non-standard values to override them. Also, document the non-standard flag values in order to make it easier to add new generic flags in the future.A consequence of this change is that on powerpc and x86, the constants' values aside from
SA_RESETHANDchange signedness from unsigned to signed. This is not expected to impact realistic use of these constants. In particular the typical use of the constants where they are or'ed together and assigned tosa_flags(or another int variable) would not be affected.
Quoted 2 lines
Signed-off-by Peter Collingbourne <[email protected]>
I haven't checked exhaustively that all the constant values definitely match up, or that every arch to which this change is applicable has been patched, but where I have looked, it checks out.
But otherwise, this looks reasonable to me.
Quoted 508 lines
---
v11:
- tweak the commit message to point out the change from unsigned to signedv10:
- move the comments around and add one forSA_SIGINFOarch/alpha/include/uapi/asm/signal.h | 14 -------- arch/arm/include/uapi/asm/signal.h | 28 ++------------- arch/h8300/include/uapi/asm/signal.h | 24 ------------- arch/ia64/include/uapi/asm/signal.h | 24 ------------- arch/m68k/include/uapi/asm/signal.h | 24 ------------- arch/mips/include/uapi/asm/signal.h | 12 ------- arch/parisc/include/uapi/asm/signal.h | 13 ------- arch/powerpc/include/uapi/asm/signal.h | 24 ------------- arch/s390/include/uapi/asm/signal.h | 24 ------------- arch/sparc/include/uapi/asm/signal.h | 4 +-- arch/x86/include/uapi/asm/signal.h | 24 ------------- arch/xtensa/include/uapi/asm/signal.h | 24 ------------- include/uapi/asm-generic/signal-defs.h | 47 ++++++++++++++++++++++++++ include/uapi/asm-generic/signal.h | 29 ---------------- 14 files changed, 51 insertions(+), 264 deletions(-)arch/alpha/include/uapi/asm/signal.h +0
-14@@ -60,20 +60,6 @@ typedef unsigned long sigset_t;#define SIGRTMIN 32#define SIGRTMAX _NSIG -/* -* SA_FLAGS values: -* -* SA_ONSTACK indicates that a registered stack_t will be used. -* SA_RESTART flag to get restarting signals (which were the default long ago) -* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -* SA_RESETHAND clears the handler when the signal is delivered. -* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -* SA_NODEFER prevents the current signal from being masked in the handler. -* -* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -* Unix names RESETHAND and NODEFER respectively. -*/ -#define SA_ONSTACK 0x00000001#define SA_RESTART 0x00000002#define SA_NOCLDSTOP 0x00000004arch/arm/include/uapi/asm/signal.h +3
-25@@ -60,33 +60,11 @@ typedef unsigned long sigset_t;#define SIGSWI 32/* -* SA_FLAGS values: -* -* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -* SA_SIGINFO deliver the signal with SIGINFO structs -* SA_THIRTYTWO delivers the signal in 32-bit mode, even if the task -* is running in 26-bit. -* SA_ONSTACK allows alternate signal stacks (see sigaltstack(2)). -* SA_RESTART flag to get restarting signals (which were the default long ago) -* SA_NODEFER prevents the current signal from being masked in the handler. -* SA_RESETHAND clears the handler when the signal is delivered. -* -* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -* Unix names RESETHAND and NODEFER respectively. +* SA_THIRTYTWO historically meant deliver the signal in 32-bit mode, even if +* the task is running in 26-bit. But since the kernel no longer supports +* 26-bit mode, the flag has no effect. */ -#define SA_NOCLDSTOP 0x00000001 -#define SA_NOCLDWAIT 0x00000002 -#define SA_SIGINFO 0x00000004#define SA_THIRTYTWO 0x02000000 -#define SA_RESTORER 0x04000000 -#define SA_ONSTACK 0x08000000 -#define SA_RESTART 0x10000000 -#define SA_NODEFER 0x40000000 -#define SA_RESETHAND 0x80000000 - -#define SA_NOMASK SA_NODEFER -#define SA_ONESHOT SA_RESETHAND#define MINSIGSTKSZ 2048#define SIGSTKSZ 8192arch/h8300/include/uapi/asm/signal.h +0
-24@@ -57,30 +57,6 @@ typedef unsigned long sigset_t;#define SIGRTMIN 32#define SIGRTMAX _NSIG -/* -* SA_FLAGS values: -* -* SA_ONSTACK indicates that a registered stack_t will be used. -* SA_RESTART flag to get restarting signals (which were the default long ago) -* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -* SA_RESETHAND clears the handler when the signal is delivered. -* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -* SA_NODEFER prevents the current signal from being masked in the handler. -* -* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -* Unix names RESETHAND and NODEFER respectively. -*/ -#define SA_NOCLDSTOP 0x00000001 -#define SA_NOCLDWAIT 0x00000002/* not supported yet */ -#define SA_SIGINFO 0x00000004 -#define SA_ONSTACK 0x08000000 -#define SA_RESTART 0x10000000 -#define SA_NODEFER 0x40000000 -#define SA_RESETHAND 0x80000000 - -#define SA_NOMASK SA_NODEFER -#define SA_ONESHOT SA_RESETHAND -#define SA_RESTORER 0x04000000#define MINSIGSTKSZ 2048arch/ia64/include/uapi/asm/signal.h +0
-24@@ -53,30 +53,6 @@#define SIGRTMIN 32#define SIGRTMAX _NSIG -/* -* SA_FLAGS values: -* -* SA_ONSTACK indicates that a registered stack_t will be used. -* SA_RESTART flag to get restarting signals (which were the default long ago) -* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -* SA_RESETHAND clears the handler when the signal is delivered. -* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -* SA_NODEFER prevents the current signal from being masked in the handler. -* -* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -* Unix names RESETHAND and NODEFER respectively. -*/ -#define SA_NOCLDSTOP 0x00000001 -#define SA_NOCLDWAIT 0x00000002 -#define SA_SIGINFO 0x00000004 -#define SA_ONSTACK 0x08000000 -#define SA_RESTART 0x10000000 -#define SA_NODEFER 0x40000000 -#define SA_RESETHAND 0x80000000 - -#define SA_NOMASK SA_NODEFER -#define SA_ONESHOT SA_RESETHAND -#define SA_RESTORER 0x04000000/* arch/m68k/include/uapi/asm/signal.h +0
-24@@ -57,30 +57,6 @@ typedef unsigned long sigset_t;#define SIGRTMIN 32#define SIGRTMAX _NSIG -/* -* SA_FLAGS values: -* -* SA_ONSTACK indicates that a registered stack_t will be used. -* SA_RESTART flag to get restarting signals (which were the default long ago) -* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -* SA_RESETHAND clears the handler when the signal is delivered. -* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -* SA_NODEFER prevents the current signal from being masked in the handler. -* -* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -* Unix names RESETHAND and NODEFER respectively. -*/ -#define SA_NOCLDSTOP 0x00000001 -#define SA_NOCLDWAIT 0x00000002 -#define SA_SIGINFO 0x00000004 -#define SA_ONSTACK 0x08000000 -#define SA_RESTART 0x10000000 -#define SA_NODEFER 0x40000000 -#define SA_RESETHAND 0x80000000 - -#define SA_NOMASK SA_NODEFER -#define SA_ONESHOT SA_RESETHAND -#define MINSIGSTKSZ 2048#define SIGSTKSZ 8192arch/mips/include/uapi/asm/signal.h +0
-12@@ -62,18 +62,6 @@ typedef unsigned long old_sigset_t; /* at least 32 bits */#define SIGRTMAX _NSIG/* -* SA_FLAGS values: -* -* SA_ONSTACK indicates that a registered stack_t will be used. -* SA_RESTART flag to get restarting signals (which were the default long ago) -* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -* SA_RESETHAND clears the handler when the signal is delivered. -* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -* SA_NODEFER prevents the current signal from being masked in the handler. -* -* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -* Unix names RESETHAND and NODEFER respectively. -* * SA_RESTORER used to be defined as 0x04000000 but only the O32 ABI ever * supported its use and no libc was using it, so the entire sa-restorer * functionality was removed with lmo commit 39bffc12c3580ab for 2.5.48 arch/parisc/include/uapi/asm/signal.h +0
-13@@ -41,19 +41,6 @@#define SIGRTMIN 32#define SIGRTMAX _NSIG -/* -* SA_FLAGS values: -* -* SA_ONSTACK indicates that a registered stack_t will be used. -* SA_RESTART flag to get restarting signals (which were the default long ago) -* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -* SA_RESETHAND clears the handler when the signal is delivered. -* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -* SA_NODEFER prevents the current signal from being masked in the handler. -* -* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -* Unix names RESETHAND and NODEFER respectively. -*/ #define SA_ONSTACK 0x00000001#define SA_RESETHAND 0x00000004#define SA_NOCLDSTOP 0x00000008arch/powerpc/include/uapi/asm/signal.h +0
-24@@ -60,30 +60,6 @@ typedef struct {#define SIGRTMIN 32#define SIGRTMAX _NSIG -/* -* SA_FLAGS values: -* -* SA_ONSTACK is not currently supported, but will allow sigaltstack(2). -* SA_RESTART flag to get restarting signals (which were the default long ago) -* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -* SA_RESETHAND clears the handler when the signal is delivered. -* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -* SA_NODEFER prevents the current signal from being masked in the handler. -* -* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -* Unix names RESETHAND and NODEFER respectively. -*/ -#define SA_NOCLDSTOP 0x00000001U -#define SA_NOCLDWAIT 0x00000002U -#define SA_SIGINFO 0x00000004U -#define SA_ONSTACK 0x08000000U -#define SA_RESTART 0x10000000U -#define SA_NODEFER 0x40000000U -#define SA_RESETHAND 0x80000000U - -#define SA_NOMASK SA_NODEFER -#define SA_ONESHOT SA_RESETHAND -#define SA_RESTORER 0x04000000U#define MINSIGSTKSZ 2048arch/s390/include/uapi/asm/signal.h +0
-24@@ -65,30 +65,6 @@ typedef unsigned long sigset_t;#define SIGRTMIN 32#define SIGRTMAX _NSIG -/* -* SA_FLAGS values: -* -* SA_ONSTACK indicates that a registered stack_t will be used. -* SA_RESTART flag to get restarting signals (which were the default long ago) -* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -* SA_RESETHAND clears the handler when the signal is delivered. -* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -* SA_NODEFER prevents the current signal from being masked in the handler. -* -* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -* Unix names RESETHAND and NODEFER respectively. -*/ -#define SA_NOCLDSTOP 0x00000001 -#define SA_NOCLDWAIT 0x00000002 -#define SA_SIGINFO 0x00000004 -#define SA_ONSTACK 0x08000000 -#define SA_RESTART 0x10000000 -#define SA_NODEFER 0x40000000 -#define SA_RESETHAND 0x80000000 - -#define SA_NOMASK SA_NODEFER -#define SA_ONESHOT SA_RESETHAND -#define SA_RESTORER 0x04000000#define MINSIGSTKSZ 2048arch/sparc/include/uapi/asm/signal.h +1
-3@@ -137,13 +137,11 @@ struct sigstack {#define SA_STACK _SV_SSTACK#define SA_ONSTACK _SV_SSTACK#define SA_RESTART _SV_INTR -#define SA_ONESHOT _SV_RESET +#define SA_RESETHAND _SV_RESET#define SA_NODEFER 0x20u#define SA_NOCLDWAIT 0x100u#define SA_SIGINFO 0x200u -#define SA_NOMASK SA_NODEFER -#define SIG_BLOCK 0x01/* for blocking signals */ #define SIG_UNBLOCK 0x02/* for unblocking signals */ #define SIG_SETMASK 0x04/* for setting the signal mask */ arch/x86/include/uapi/asm/signal.h +0
-24@@ -62,30 +62,6 @@ typedef unsigned long sigset_t;#define SIGRTMIN 32#define SIGRTMAX _NSIG -/* -* SA_FLAGS values: -* -* SA_ONSTACK indicates that a registered stack_t will be used. -* SA_RESTART flag to get restarting signals (which were the default long ago) -* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -* SA_RESETHAND clears the handler when the signal is delivered. -* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -* SA_NODEFER prevents the current signal from being masked in the handler. -* -* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -* Unix names RESETHAND and NODEFER respectively. -*/ -#define SA_NOCLDSTOP 0x00000001u -#define SA_NOCLDWAIT 0x00000002u -#define SA_SIGINFO 0x00000004u -#define SA_ONSTACK 0x08000000u -#define SA_RESTART 0x10000000u -#define SA_NODEFER 0x40000000u -#define SA_RESETHAND 0x80000000u - -#define SA_NOMASK SA_NODEFER -#define SA_ONESHOT SA_RESETHAND -#define SA_RESTORER 0x04000000#define MINSIGSTKSZ 2048arch/xtensa/include/uapi/asm/signal.h +0
-24@@ -72,30 +72,6 @@ typedef struct {#define SIGRTMIN 32#define SIGRTMAX (_NSIG-1) -/* -* SA_FLAGS values: -* -* SA_ONSTACK indicates that a registered stack_t will be used. -* SA_RESTART flag to get restarting signals (which were the default long ago) -* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -* SA_RESETHAND clears the handler when the signal is delivered. -* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -* SA_NODEFER prevents the current signal from being masked in the handler. -* -* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -* Unix names RESETHAND and NODEFER respectively. -*/ -#define SA_NOCLDSTOP 0x00000001 -#define SA_NOCLDWAIT 0x00000002/* not supported yet */ -#define SA_SIGINFO 0x00000004 -#define SA_ONSTACK 0x08000000 -#define SA_RESTART 0x10000000 -#define SA_NODEFER 0x40000000 -#define SA_RESETHAND 0x80000000 - -#define SA_NOMASK SA_NODEFER -#define SA_ONESHOT SA_RESETHAND -#define SA_RESTORER 0x04000000#define MINSIGSTKSZ 2048include/uapi/asm-generic/signal-defs.h +47
-0@@ -4,6 +4,53 @@#include <linux/compiler.h> +/* +* SA_FLAGS values: +* +* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. +* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. +* SA_SIGINFO delivers the signal with SIGINFO structs. +* SA_ONSTACK indicates that a registered stack_t will be used. +* SA_RESTART flag to get restarting signals (which were the default long ago) +* SA_NODEFER prevents the current signal from being masked in the handler. +* SA_RESETHAND clears the handler when the signal is delivered. +* +* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single +* Unix names RESETHAND and NODEFER respectively. +* +* The following bits are used in architecture-specific SA_* definitions and +* should be avoided for new generic flags: 3, 4, 5, 6, 7, 8, 9, 16, 24, 25, 26. +*/ +#ifndef SA_NOCLDSTOP +#define SA_NOCLDSTOP 0x00000001 +#endif +#ifndef SA_NOCLDWAIT +#define SA_NOCLDWAIT 0x00000002 +#endif +#ifndef SA_SIGINFO +#define SA_SIGINFO 0x00000004 +#endif +#ifndef SA_ONSTACK +#define SA_ONSTACK 0x08000000 +#endif +#ifndef SA_RESTART +#define SA_RESTART 0x10000000 +#endif +#ifndef SA_NODEFER +#define SA_NODEFER 0x40000000 +#endif +#ifndef SA_RESETHAND +#define SA_RESETHAND 0x80000000 +#endif + +#define SA_NOMASK SA_NODEFER +#define SA_ONESHOT SA_RESETHAND + +/* +* New architectures should not define the obsolete +* SA_RESTORER 0x04000000 +*/ +#ifndef SIG_BLOCK #define SIG_BLOCK 0/* for blocking signals */ #endif include/uapi/asm-generic/signal.h +0
-29@@ -52,35 +52,6 @@#define SIGRTMAX _NSIG#endif -/* -* SA_FLAGS values: -* -* SA_ONSTACK indicates that a registered stack_t will be used. -* SA_RESTART flag to get restarting signals (which were the default long ago) -* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -* SA_RESETHAND clears the handler when the signal is delivered. -* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -* SA_NODEFER prevents the current signal from being masked in the handler. -* -* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -* Unix names RESETHAND and NODEFER respectively. -*/ -#define SA_NOCLDSTOP 0x00000001 -#define SA_NOCLDWAIT 0x00000002 -#define SA_SIGINFO 0x00000004 -#define SA_ONSTACK 0x08000000 -#define SA_RESTART 0x10000000 -#define SA_NODEFER 0x40000000 -#define SA_RESETHAND 0x80000000 - -#define SA_NOMASK SA_NODEFER -#define SA_ONESHOT SA_RESETHAND - -/* -* New architectures should not define the obsolete -* SA_RESTORER 0x04000000 -*/ -#if !definedMINSIGSTKSZ || !definedSIGSTKSZ #define MINSIGSTKSZ 2048#define SIGSTKSZ 8192Signature · 7 lines
2.29.0.rc1.297.gfa9743e501-goog _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
PATCH v12 4/8 signal: clear non-uapi flag bits when passing/returning sa_flags
In reply to Peter CollingbournePreviously we were not clearing non-uapi flag bits in sigaction.sa_flags when storing the userspace-provided sa_flags or when returning them via oldact. Start doing so.
This allows userspace to detect missing support for flag bits and allows the kernel to use non-uapi bits internally, as we are already doing in arch/x86 for two flag bits. Now that this change is in place, we no longer need the code in arch/x86 that was hiding these bits from userspace, so remove it.
This is technically a userspace-visible behavior change for sigaction, as the unknown bits returned via oldact.sa_flags are no longer set. However, we are free to define the behavior for unknown bits exactly because their behavior is currently undefined, so for now we can define the meaning of each of them to be "clear the bit in oldact.sa_flags unless the bit becomes known in the future". Furthermore, this behavior is consistent with OpenBSD [1], illumos [2] and XNU [3] (FreeBSD [4] and NetBSD [5] fail the syscall if unknown bits are set). So there is some precedent for this behavior in other kernels, and in particular in XNU, which is probably the most popular kernel among those that I looked at, which means that this change is less likely to be a compatibility issue.
---
v10:
- rename SA_UAPI_FLAGS -> UAPI_SA_FLAGS
- refactor how we define it to avoid mentioning flags more than once
arch/arm/include/asm/signal.h | 2 ++ arch/parisc/include/asm/signal.h | 2 ++ arch/x86/kernel/signal_compat.c | 7 ------- include/linux/signal_types.h | 12 ++++++++++++ kernel/signal.c | 10 ++++++++++ 5 files changed, 26 insertions(+), 7 deletions(-)
arch/arm/include/asm/signal.h +2 -0
@@ -17,6 +17,8 @@ typedef struct {unsigned long sig[_NSIG_WORDS]; } sigset_t; +#define __ARCH_UAPI_SA_FLAGS (SA_THIRTYTWO | SA_RESTORER) +#define __ARCH_HAS_SA_RESTORER#include <asm/sigcontext.h>
arch/parisc/include/asm/signal.h +2 -0
@@ -21,6 +21,8 @@ typedef struct { unsigned long sig[_NSIG_WORDS]; } sigset_t; +#define __ARCH_UAPI_SA_FLAGS _SA_SIGGFAULT +#include <asm/sigcontext.h> #endif /* !__ASSEMBLY */
arch/x86/kernel/signal_compat.c +0 -7
@@ -165,16 +165,9 @@ void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oact) {signal_compat_build_tests (); -/* Don't leak in-kernel non-uapi flags to user-space */ -if (oact) - oact->sa.sa_flags &= ~(SA_IA32_ABI |SA_X32_ABI ); -if (!act)return ; -/* Don't let flags to be set from userspace */ - act->sa.sa_flags &= ~(SA_IA32_ABI |SA_X32_ABI ); -if (in_ia32_syscall ()) act->sa.sa_flags |=SA_IA32_ABI ;if (in_x32_syscall ())
include/linux/signal_types.h +12 -0
@@ -68,4 +68,16 @@ struct ksignal { int sig; }; +#ifndef __ARCH_UAPI_SA_FLAGS +#ifdef SA_RESTORER +#define __ARCH_UAPI_SA_FLAGS SA_RESTORER +#else +#define __ARCH_UAPI_SA_FLAGS 0 +#endif +#endif + +#define UAPI_SA_FLAGS \ + (SA_NOCLDSTOP | SA_NOCLDWAIT | SA_SIGINFO | SA_ONSTACK | SA_RESTART | \ + SA_NODEFER | SA_RESETHAND | __ARCH_UAPI_SA_FLAGS) +#endif /* _LINUX_SIGNAL_TYPES_H */
kernel/signal.c +10 -0
@@ -3984,6 +3984,16 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)if (oact) *oact = *k; +/* +* Clear unknown flag bits in order to allow userspace to detect missing +* support for flag bits and to allow the kernel to use non-uapi bits +* internally. +*/ +if (act) + act->sa.sa_flags &=UAPI_SA_FLAGS ; +if (oact) + oact->sa.sa_flags &=UAPI_SA_FLAGS ; +sigaction_compat_abi (act, oact);if (act) {
Signature · 7 lines
2.29.0.rc1.297.gfa9743e501-goog _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Re: [PATCH v12 4/8] signal: clear non-uapi flag bits when passing/returning sa_flags
Quoted 22 lines · Peter Collingbourne
Previously we were not clearing non-uapi flag bits in sigaction.sa_flags when storing the userspace-provided
sa_flagsor when returning them via oldact. Start doing so.This allows userspace to detect missing support for flag bits and allows the kernel to use non-uapi bits internally, as we are already doing in
arch/x86for two flag bits. Now that this change is in place, we no longer need the code inarch/x86that was hiding these bits from userspace, so remove it.This is technically a userspace-visible behavior change for sigaction, as the unknown bits returned via oldact.sa_flags are no longer set. However, we are free to define the behavior for unknown bits exactly because their behavior is currently undefined, so for now we can define the meaning of each of them to be "clear the bit in oldact.sa_flags unless the bit becomes known in the future". Furthermore, this behavior is consistent with OpenBSD [1], illumos [2] and XNU [3] (FreeBSD [4] and NetBSD [5] fail the syscall if unknown bits are set). So there is some precedent for this behavior in other kernels, and in particular in XNU, which is probably the most popular kernel among those that I looked at, which means that this change is less likely to be a compatibility issue.
Quoted 7 lines
Quoted 110 lines
---
v10:
- renameSA_UAPI_FLAGS->UAPI_SA_FLAGS
- refactor how we define it to avoid mentioning flags more than oncearch/arm/include/asm/signal.h | 2 ++ arch/parisc/include/asm/signal.h | 2 ++ arch/x86/kernel/signal_compat.c | 7 ------- include/linux/signal_types.h | 12 ++++++++++++ kernel/signal.c | 10 ++++++++++ 5 files changed, 26 insertions(+), 7 deletions(-)arch/arm/include/asm/signal.h +2
-0@@ -17,6 +17,8 @@ typedef struct {unsigned long sig[_NSIG_WORDS]; } sigset_t; +#define __ARCH_UAPI_SA_FLAGS (SA_THIRTYTWO | SA_RESTORER) +#define __ARCH_HAS_SA_RESTORER#include <asm/sigcontext.h> arch/parisc/include/asm/signal.h +2
-0@@ -21,6 +21,8 @@ typedef struct { unsigned long sig[_NSIG_WORDS]; } sigset_t; +#define __ARCH_UAPI_SA_FLAGS _SA_SIGGFAULT +#include <asm/sigcontext.h> #endif /* !__ASSEMBLY */ arch/x86/kernel/signal_compat.c +0
-7@@ -165,16 +165,9 @@ void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oact) {signal_compat_build_tests (); -/* Don't leak in-kernel non-uapi flags to user-space */ -if (oact) - oact->sa.sa_flags &= ~(SA_IA32_ABI |SA_X32_ABI ); -if (!act)return ; -/* Don't let flags to be set from userspace */ - act->sa.sa_flags &= ~(SA_IA32_ABI |SA_X32_ABI ); -if (in_ia32_syscall ()) act->sa.sa_flags |=SA_IA32_ABI ;if (in_x32_syscall ())include/linux/signal_types.h +12
-0@@ -68,4 +68,16 @@ struct ksignal { int sig; }; +#ifndef __ARCH_UAPI_SA_FLAGS +#ifdef SA_RESTORER +#define __ARCH_UAPI_SA_FLAGS SA_RESTORER +#else +#define __ARCH_UAPI_SA_FLAGS 0 +#endif +#endif + +#define UAPI_SA_FLAGS \ + (SA_NOCLDSTOP | SA_NOCLDWAIT | SA_SIGINFO | SA_ONSTACK | SA_RESTART | \ + SA_NODEFER | SA_RESETHAND | __ARCH_UAPI_SA_FLAGS) +#endif /* _LINUX_SIGNAL_TYPES_H */ kernel/signal.c +10
-0@@ -3984,6 +3984,16 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)if (oact) *oact = *k; +/* +* Clear unknown flag bits in order to allow userspace to detect missing +* support for flag bits and to allow the kernel to use non-uapi bits +* internally. +*/ +if (act) + act->sa.sa_flags &=UAPI_SA_FLAGS ; +if (oact) + oact->sa.sa_flags &=UAPI_SA_FLAGS ; +sigaction_compat_abi (act, oact);if (act) {Signature · 7 lines
2.29.0.rc1.297.gfa9743e501-goog _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
PATCH v12 5/8 signal: define the SA_UNSUPPORTED bit in sa_flags
In reply to Peter CollingbourneDefine a sa_flags bit, SA_UNSUPPORTED, which will never be supported in the uapi. The purpose of this flag bit is to allow userspace to distinguish an old kernel that does not clear unknown sa_flags bits from a kernel that supports every flag bit.
In other words, if userspace does something like:
act.sa_flags |= SA_UNSUPPORTED; sigaction(SIGSEGV, &act, 0); sigaction(SIGSEGV, 0, &oldact);
and finds that SA_UNSUPPORTED remains set in oldact.sa_flags, it means that the kernel cannot be trusted to have cleared unknown flag bits from sa_flags, so no assumptions about flag bit support can be made.
---
v11:
- clarify the commit message
include/uapi/asm-generic/signal-defs.h | 7 +++++++ kernel/signal.c | 6 ++++++ 2 files changed, 13 insertions(+)
include/uapi/asm-generic/signal-defs.h +7 -0
@@ -14,6 +14,12 @@* SA_RESTART flag to get restarting signals (which were the default long ago) * SA_NODEFER prevents the current signal from being masked in the handler. * SA_RESETHAND clears the handler when the signal is delivered. +* SA_UNSUPPORTED is a flag bit that will never be supported. Kernels from +* before the introduction of SA_UNSUPPORTED did not clear unknown bits from +* sa_flags when read using the oldact argument to sigaction and rt_sigaction, +* so this bit allows flag bit support to be detected from userspace while +* allowing an old kernel to be distinguished from a kernel that supports every +* flag bit. * * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single * Unix names RESETHAND and NODEFER respectively.
@@ -42,6 +48,7 @@#ifndef SA_RESETHAND #define SA_RESETHAND 0x80000000#endif +#define SA_UNSUPPORTED 0x00000400#define SA_NOMASK SA_NODEFER#define SA_ONESHOT SA_RESETHAND
kernel/signal.c +6 -0
@@ -3984,6 +3984,12 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)if (oact) *oact = *k; +/* +* Make sure that we never accidentally claim to support SA_UNSUPPORTED, +* e.g. by having an architecture use the bit in their uapi. +*/ +BUILD_BUG_ON (UAPI_SA_FLAGS &SA_UNSUPPORTED ); +/* * Clear unknown flag bits in order to allow userspace to detect missing * support for flag bits and to allow the kernel to use non-uapi bits
Signature · 7 lines
2.29.0.rc1.297.gfa9743e501-goog _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
PATCH v12 6/8 signal: deduplicate code dealing with common _sigfault fields
In reply to Peter CollingbourneWe're about to add more common _sigfault fields, so deduplicate the existing code for initializing _sigfault fields in {send,force}_sig_*, and for copying _sigfault fields in copy_siginfo_to_external32 and post_copy_siginfo_from_user32, to reduce the number of places that will need to be updated by upcoming changes.
--- include/linux/signal.h | 13 ++++++ kernel/signal.c | 101 ++++++++++++++++------------------------- 2 files changed, 53 insertions(+), 61 deletions(-)
include/linux/signal.h +13 -0
@@ -50,6 +50,19 @@ enum siginfo_layout {enum siginfo_layout siginfo_layout (unsigned sig,int si_code); +static inline bool siginfo_layout_is_fault (enum siginfo_layout layout) +{ +switch (layout) { +case SIL_FAULT : +case SIL_FAULT_MCEERR : +case SIL_FAULT_BNDERR : +case SIL_FAULT_PKUERR : +return true; +default : +return false; + } +} +/* * Define some primitives to manipulate sigset_t. */
kernel/signal.c +40 -61
201 lines not on this page · raw message
Signature · 7 lines
2.29.0.rc1.297.gfa9743e501-goog _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
PATCH v12 7/8 signal: define the field siginfo.si_xflags
In reply to Peter CollingbourneThis field will contain flags that may be used by signal handlers to determine whether other fields in the _sigfault portion of siginfo are valid. An example use case is the following patch, which introduces the si_addr_tag_bits{,_mask} fields.
A new sigcontext flag, SA_XFLAGS, is introduced in order to allow a signal handler to require the kernel to set the field (but note that the field will be set anyway if the kernel supports the flag, regardless of its value). In combination with the previous patches, this allows a userspace program to determine whether the kernel will set the field.
It is possible for an si_xflags-unaware program to cause a signal handler in an si_xflags-aware program to be called with a provided siginfo data structure by using one of the following syscalls:
- ptrace(PTRACE_SETSIGINFO)
- pidfd_send_signal
- rt_sigqueueinfo
- rt_tgsigqueueinfo
So we need to prevent the si_xflags-unaware program from causing an uninitialized read of si_xflags in the si_xflags-aware program when it uses one of these syscalls.
The last three cases can be handled by observing that each of these syscalls fails if si_code >= 0. We also observe that kill(2) and tgkill(2) may be used to send a signal where si_code == 0 (SI_USER), so we define si_xflags to only be valid if si_code > 0.
There is no such check on si_code in ptrace(PTRACE_SETSIGINFO), so we make ptrace(PTRACE_SETSIGINFO) clear the si_xflags field if it detects that the signal would use the _sigfault layout, and introduce a new ptrace request type, PTRACE_SETSIGINFO2, that a si_xflags-aware program may use to opt out of this behavior.
It is also possible for the kernel to inject a signal specified to use _sigfault by calling force_sig (e.g. there are numerous calls to force_sig(SIGSEGV)). In this case si_code is set to SI_KERNEL and the _kill union member is used, so document that si_code must be < SI_KERNEL.
Ideally this field could have just been named si_flags, but that name was already taken by ia64, so a different name was chosen.
I considered making ia64's si_flags a generic field and having it appear at the end of _sigfault (in the same place as this patch has si_xflags) on non-ia64, keeping it in the same place on ia64. ia64's si_flags is a 32-bit field with only one flag bit allocated, so we would have 31 bits to use if we do this. However, it seems simplest to avoid entangling these fields.
---
v12:
- Change type of si_xflags to u32 to avoid increasing alignment
- Add si_xflags to signal_compat.c test cases
v11:
- update comment to say that si_code must > 0
- change ptrace(PTRACE_SETSIGINFO2) to take a flags argument
v10:
- make the new field compatible with the various ways that a siginfo can be injected from another process
- eliminate some duplication by adding a refactoring patch before this one
arch/powerpc/platforms/powernv/vas-fault.c | 1 + arch/x86/kernel/signal_compat.c | 7 +++-- include/linux/compat.h | 2 ++ include/linux/signal_types.h | 2 +- include/uapi/asm-generic/siginfo.h | 4 +++ include/uapi/asm-generic/signal-defs.h | 4 +++ include/uapi/linux/ptrace.h | 12 ++++++++ kernel/ptrace.c | 32 ++++++++++++++++++---- kernel/signal.c | 3 ++ 9 files changed, 58 insertions(+), 9 deletions(-)
arch/powerpc/platforms/powernv/vas-fault.c +1 -0
@@ -154,6 +154,7 @@ static void update_csb(struct vas_window *window, info.si_errno =EFAULT ; info.si_code =SEGV_MAPERR ; info.si_addr = csb_addr; + info.si_xflags =0 ;/* * process will be polling on csb.flags after request is sent to
arch/x86/kernel/signal_compat.c +5 -2
@@ -121,8 +121,8 @@ static inline void signal_compat_build_tests(void)#endif CHECK_CSI_OFFSET (_sigfault); -CHECK_CSI_SIZE (_sigfault,4 *sizeof (int )); -CHECK_SI_SIZE (_sigfault,8 *sizeof (int )); +CHECK_CSI_SIZE (_sigfault,8 *sizeof (int )); +CHECK_SI_SIZE (_sigfault,16 *sizeof (int ));BUILD_BUG_ON (offsetof(siginfo_t , si_addr) !=0x10 );BUILD_BUG_ON (offsetof(compat_siginfo_t , si_addr) !=0x0C );
@@ -138,6 +138,9 @@ static inline void signal_compat_build_tests(void)BUILD_BUG_ON (offsetof(siginfo_t , si_pkey) !=0x20 );BUILD_BUG_ON (offsetof(compat_siginfo_t , si_pkey) !=0x14 ); +BUILD_BUG_ON (offsetof(siginfo_t , si_xflags) !=0x48 ); +BUILD_BUG_ON (offsetof(compat_siginfo_t , si_xflags) !=0x28 ); +CHECK_CSI_OFFSET (_sigpoll);CHECK_CSI_SIZE (_sigpoll,2 *sizeof (int ));CHECK_SI_SIZE (_sigpoll,4 *sizeof (int ));
include/linux/compat.h +2 -0
@@ -236,7 +236,9 @@ typedef struct compat_siginfo {char _dummy_pkey[__COMPAT_ADDR_BND_PKEY_PAD];u32 _pkey; } _addr_pkey; +compat_uptr_t _pad[6 ]; }; +u32 _xflags; } _sigfault;/* SIGPOLL */
include/linux/signal_types.h +1 -1
@@ -78,6 +78,6 @@ struct ksignal {#define UAPI_SA_FLAGS \ (SA_NOCLDSTOP | SA_NOCLDWAIT | SA_SIGINFO | SA_ONSTACK | SA_RESTART | \ - SA_NODEFER | SA_RESETHAND | __ARCH_UAPI_SA_FLAGS) + SA_NODEFER | SA_RESETHAND | SA_XFLAGS | __ARCH_UAPI_SA_FLAGS)#endif /* _LINUX_SIGNAL_TYPES_H */
include/uapi/asm-generic/siginfo.h +4 -0
@@ -91,7 +91,9 @@ union __sifields {char _dummy_pkey[__ADDR_BND_PKEY_PAD];__u32 _pkey; } _addr_pkey; +void *_pad[6 ]; }; +__u32 _xflags; } _sigfault;/* SIGPOLL */
@@ -152,6 +154,8 @@ typedef struct siginfo {#define si_trapno _sifields._sigfault._trapno#endif #define si_addr_lsb _sifields._sigfault._addr_lsb +/* si_xflags is only valid if 0 < si_code < SI_KERNEL */ +#define si_xflags _sifields._sigfault._xflags#define si_lower _sifields._sigfault._addr_bnd._lower#define si_upper _sifields._sigfault._addr_bnd._upper#define si_pkey _sifields._sigfault._addr_pkey._pkey
include/uapi/asm-generic/signal-defs.h +4 -0
@@ -20,6 +20,9 @@* so this bit allows flag bit support to be detected from userspace while * allowing an old kernel to be distinguished from a kernel that supports every * flag bit. +* SA_XFLAGS indicates that the signal handler requires the siginfo.si_xflags +* field to be valid. Note that if the kernel supports SA_XFLAGS, the field will +* be valid regardless of the value of this flag. * * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single * Unix names RESETHAND and NODEFER respectively.
@@ -49,6 +52,7 @@#define SA_RESETHAND 0x80000000#endif #define SA_UNSUPPORTED 0x00000400 +#define SA_XFLAGS 0x00000800#define SA_NOMASK SA_NODEFER#define SA_ONESHOT SA_RESETHAND
include/uapi/linux/ptrace.h +12 -0
@@ -101,6 +101,18 @@ struct ptrace_syscall_info { }; }; +#define PTRACE_SETSIGINFO2 0x420f +/* +* These flags are passed as the addr argument to ptrace. +*/ + +/* +* Asserts that the caller is aware of the field siginfo.si_xflags. Prevents +* the kernel from automatically setting the field to 0 when the signal uses +* a sigfault layout. +*/ +#define PTRACE_SIGINFO_XFLAGS 0x1 +/* * These values are stored in task->ptrace_message * by tracehook_report_syscall_* to describe the current syscall-stop.
kernel/ptrace.c +26 -6
@@ -687,18 +687,32 @@ static int ptrace_getsiginfo(struct task_struct *child, kernel_siginfo_t *info)return error; } -static int ptrace_setsiginfo (struct task_struct *child,const kernel_siginfo_t *info) +static int ptrace_setsiginfo (struct task_struct *child,unsigned long flags, +kernel_siginfo_t *info) { -unsigned long flags; +unsigned long lock_flags;int error = -ESRCH ; -if (lock_task_sighand (child, &flags)) { +if (flags & ~PTRACE_SIGINFO_XFLAGS ) { +return -EINVAL ; + } + +/* +* If the caller is unaware of si_xflags and we're using a layout that +* requires it, set it to 0 which means "no fields are available". +*/ +if (!(flags &PTRACE_SIGINFO_XFLAGS ) && +siginfo_layout_is_fault ( +siginfo_layout (info->si_signo, info->si_code))) + info->si_xflags =0 ; + +if (lock_task_sighand (child, &lock_flags)) { error = -EINVAL ;if (likely (child->last_siginfo !=NULL )) {copy_siginfo (child->last_siginfo, info); error =0 ; } -unlock_task_sighand (child, &flags); +unlock_task_sighand (child, &lock_flags); }return error; }
@@ -1038,9 +1052,12 @@ int ptrace_request(struct task_struct *child, long request,break ;case PTRACE_SETSIGINFO : + addr =0 ; + +case PTRACE_SETSIGINFO2 : ret =copy_siginfo_from_user (&siginfo, datavp);if (!ret) - ret =ptrace_setsiginfo (child, &siginfo); + ret =ptrace_setsiginfo (child, addr, &siginfo);break ;case PTRACE_GETSIGMASK : {
@@ -1347,10 +1364,13 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,break ;case PTRACE_SETSIGINFO : + addr =0 ; + +case PTRACE_SETSIGINFO2 : ret =copy_siginfo_from_user32 ( &siginfo, (struct compat_siginfo __user *) datap);if (!ret) - ret =ptrace_setsiginfo (child, &siginfo); + ret =ptrace_setsiginfo (child, addr, &siginfo);break ;#ifdef CONFIG_HAVE_ARCH_TRACEHOOK case PTRACE_GETREGSET :
kernel/signal.c +3 -0
@@ -1656,6 +1656,7 @@ static void set_sigfault_common_fields(struct kernel_siginfo *info, int sig, info->si_errno =0 ; info->si_code = code; info->si_addr = addr; + info->si_xflags =0 ; } int force_sig_fault_to_task(int sig, int code, void __user *addr
@@ -3269,6 +3270,7 @@ void copy_siginfo_to_external32(struct compat_siginfo *to,#ifdef __ARCH_SI_TRAPNO to->si_trapno = from->si_trapno;#endif + to->si_xflags = from->si_xflags; }switch (layout) {
@@ -3344,6 +3346,7 @@ static int post_copy_siginfo_from_user32(kernel_siginfo_t *to,#ifdef __ARCH_SI_TRAPNO to->si_trapno = from->si_trapno;#endif + to->si_xflags = from->si_xflags; }switch (layout) {
Signature · 7 lines
2.29.0.rc1.297.gfa9743e501-goog _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Re: [PATCH v12 7/8] signal: define the field siginfo.si_xflags
Quoted 11 lines · Peter Collingbourne
This field will contain flags that may be used by signal handlers to determine whether other fields in the
_sigfaultportion of siginfo are valid. An example use case is the following patch, which introduces the si_addr_tag_bits{,_mask} fields.A new sigcontext flag,
SA_XFLAGS, is introduced in order to allow a signal handler to require the kernel to set the field (but note that the field will be set anyway if the kernel supports the flag, regardless of its value). In combination with the previous patches, this allows a userspace program to determine whether the kernel will set the field.
Apologies for this coming rather late:
It occurs to me that we might want a more specific name, since this only applies to fault signals -- say, SA_FAULTFLAGS.
If we end up wanting to add flags fields for other signal types, then we might end up needing a SA_ flag for each, which would be a bit annoying.
So, alternatively. I wonder whether it's worth preemptively adding an extra flags to every kind of kernel-generated siginfo. If so, then having a single SA_XFLAGS would be fine.
If added flags fields all over the place is considered overkill, then I guess it's sufficient to rename this flag.
If renaming, the actual flags field in siginfo should also be renamed to match.
Quoted 241 lines
It is possible for an si_xflags-unaware program to cause a signal handler in an si_xflags-aware program to be called with a provided siginfo data structure by using one of the following syscalls:
-
ptrace(PTRACE_SETSIGINFO)
-pidfd_send_signal
-rt_sigqueueinfo
-rt_tgsigqueueinfoSo we need to prevent the si_xflags-unaware program from causing an uninitialized read of
si_xflagsin the si_xflags-aware program when it uses one of these syscalls.The last three cases can be handled by observing that each of these syscalls fails if
si_code>= 0. We also observe that kill(2) and tgkill(2) may be used to send a signal wheresi_code== 0 (SI_USER), so we definesi_xflagsto only be valid ifsi_code> 0.There is no such check on
si_codeinptrace(PTRACE_SETSIGINFO), so we makeptrace(PTRACE_SETSIGINFO)clear thesi_xflagsfield if it detects that the signal would use the_sigfaultlayout, and introduce a new ptrace request type,PTRACE_SETSIGINFO2, that a si_xflags-aware program may use to opt out of this behavior.It is also possible for the kernel to inject a signal specified to use
_sigfaultby callingforce_sig(e.g. there are numerous calls toforce_sig(SIGSEGV)). In this casesi_codeis set toSI_KERNELand the_killunion member is used, so document thatsi_codemust be <SI_KERNEL.Ideally this field could have just been named
si_flags, but that name was already taken by ia64, so a different name was chosen.I considered making ia64's
si_flagsa generic field and having it appear at the end of_sigfault(in the same place as this patch hassi_xflags) on non-ia64, keeping it in the same place on ia64. ia64'ssi_flagsis a 32-bit field with only one flag bit allocated, so we would have 31 bits to use if we do this. However, it seems simplest to avoid entangling these fields.Signed-off-by Peter Collingbourne <[email protected]>---
v12:
- Change type ofsi_xflagsto u32 to avoid increasing alignment
- Addsi_xflagstosignal_compat.ctest casesv11:
- update comment to say thatsi_codemust > 0
- changeptrace(PTRACE_SETSIGINFO2)to take a flags argumentv10:
- make the new field compatible with the various ways that a siginfo can be injected from another process
- eliminate some duplication by adding a refactoring patch before this onearch/powerpc/platforms/powernv/vas-fault.c | 1 + arch/x86/kernel/signal_compat.c | 7 +++-- include/linux/compat.h | 2 ++ include/linux/signal_types.h | 2 +- include/uapi/asm-generic/siginfo.h | 4 +++ include/uapi/asm-generic/signal-defs.h | 4 +++ include/uapi/linux/ptrace.h | 12 ++++++++ kernel/ptrace.c | 32 ++++++++++++++++++---- kernel/signal.c | 3 ++ 9 files changed, 58 insertions(+), 9 deletions(-)arch/powerpc/platforms/powernv/vas-fault.c +1
-0@@ -154,6 +154,7 @@ static void update_csb(struct vas_window *window, info.si_errno =EFAULT ; info.si_code =SEGV_MAPERR ; info.si_addr = csb_addr; + info.si_xflags =0 ;/* * process will be polling on csb.flags after request is sent to arch/x86/kernel/signal_compat.c +5
-2@@ -121,8 +121,8 @@ static inline void signal_compat_build_tests(void)#endif CHECK_CSI_OFFSET (_sigfault); -CHECK_CSI_SIZE (_sigfault,4 *sizeof (int )); -CHECK_SI_SIZE (_sigfault,8 *sizeof (int )); +CHECK_CSI_SIZE (_sigfault,8 *sizeof (int )); +CHECK_SI_SIZE (_sigfault,16 *sizeof (int ));BUILD_BUG_ON (offsetof(siginfo_t , si_addr) !=0x10 );BUILD_BUG_ON (offsetof(compat_siginfo_t , si_addr) !=0x0C );@@ -138,6 +138,9 @@ static inline void signal_compat_build_tests(void)BUILD_BUG_ON (offsetof(siginfo_t , si_pkey) !=0x20 );BUILD_BUG_ON (offsetof(compat_siginfo_t , si_pkey) !=0x14 ); +BUILD_BUG_ON (offsetof(siginfo_t , si_xflags) !=0x48 ); +BUILD_BUG_ON (offsetof(compat_siginfo_t , si_xflags) !=0x28 ); +CHECK_CSI_OFFSET (_sigpoll);CHECK_CSI_SIZE (_sigpoll,2 *sizeof (int ));CHECK_SI_SIZE (_sigpoll,4 *sizeof (int ));include/linux/compat.h +2
-0@@ -236,7 +236,9 @@ typedef struct compat_siginfo {char _dummy_pkey[__COMPAT_ADDR_BND_PKEY_PAD];u32 _pkey; } _addr_pkey; +compat_uptr_t _pad[6 ]; }; +u32 _xflags; } _sigfault;/* SIGPOLL */ include/linux/signal_types.h +1
-1@@ -78,6 +78,6 @@ struct ksignal {#define UAPI_SA_FLAGS \ (SA_NOCLDSTOP | SA_NOCLDWAIT | SA_SIGINFO | SA_ONSTACK | SA_RESTART | \ - SA_NODEFER | SA_RESETHAND | __ARCH_UAPI_SA_FLAGS) + SA_NODEFER | SA_RESETHAND | SA_XFLAGS | __ARCH_UAPI_SA_FLAGS)#endif /* _LINUX_SIGNAL_TYPES_H */ include/uapi/asm-generic/siginfo.h +4
-0@@ -91,7 +91,9 @@ union __sifields {char _dummy_pkey[__ADDR_BND_PKEY_PAD];__u32 _pkey; } _addr_pkey; +void *_pad[6 ]; }; +__u32 _xflags; } _sigfault;/* SIGPOLL */ @@ -152,6 +154,8 @@ typedef struct siginfo {#define si_trapno _sifields._sigfault._trapno#endif #define si_addr_lsb _sifields._sigfault._addr_lsb +/* si_xflags is only valid if 0 < si_code < SI_KERNEL */ +#define si_xflags _sifields._sigfault._xflags#define si_lower _sifields._sigfault._addr_bnd._lower#define si_upper _sifields._sigfault._addr_bnd._upper#define si_pkey _sifields._sigfault._addr_pkey._pkeyinclude/uapi/asm-generic/signal-defs.h +4
-0@@ -20,6 +20,9 @@* so this bit allows flag bit support to be detected from userspace while * allowing an old kernel to be distinguished from a kernel that supports every * flag bit. +* SA_XFLAGS indicates that the signal handler requires the siginfo.si_xflags +* field to be valid. Note that if the kernel supports SA_XFLAGS, the field will +* be valid regardless of the value of this flag. * * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single * Unix names RESETHAND and NODEFER respectively. @@ -49,6 +52,7 @@#define SA_RESETHAND 0x80000000#endif #define SA_UNSUPPORTED 0x00000400 +#define SA_XFLAGS 0x00000800#define SA_NOMASK SA_NODEFER#define SA_ONESHOT SA_RESETHANDinclude/uapi/linux/ptrace.h +12
-0@@ -101,6 +101,18 @@ struct ptrace_syscall_info { }; }; +#define PTRACE_SETSIGINFO2 0x420f +/* +* These flags are passed as the addr argument to ptrace. +*/ + +/* +* Asserts that the caller is aware of the field siginfo.si_xflags. Prevents +* the kernel from automatically setting the field to 0 when the signal uses +* a sigfault layout. +*/ +#define PTRACE_SIGINFO_XFLAGS 0x1 +/* * These values are stored in task->ptrace_message * by tracehook_report_syscall_* to describe the current syscall-stop. kernel/ptrace.c +18
-4@@ -687,18 +687,32 @@ static int ptrace_getsiginfo(struct task_struct *child, kernel_siginfo_t *info)return error; } -static int ptrace_setsiginfo (struct task_struct *child,const kernel_siginfo_t *info) +static int ptrace_setsiginfo (struct task_struct *child,unsigned long flags, +kernel_siginfo_t *info) { -unsigned long flags; +unsigned long lock_flags;int error = -ESRCH ; -if (lock_task_sighand (child, &flags)) { +if (flags & ~PTRACE_SIGINFO_XFLAGS ) { +return -EINVAL ; + } + +/* +* If the caller is unaware of si_xflags and we're using a layout that +* requires it, set it to 0 which means "no fields are available". +*/ +if (!(flags &PTRACE_SIGINFO_XFLAGS ) && +siginfo_layout_is_fault ( +siginfo_layout (info->si_signo, info->si_code))) + info->si_xflags =0 ; + +if (lock_task_sighand (child, &lock_flags)) { error = -EINVAL ;if (likely (child->last_siginfo !=NULL )) {copy_siginfo (child->last_siginfo, info); error =0 ; } -unlock_task_sighand (child, &flags); +unlock_task_sighand (child, &lock_flags); }return error; }
kernel/ptrace.c int ptrace_request(struct task_struct *child, long request, · line 1055
Quoted 4 lines
kernel/ptrace.c +1
-0@@ -1038,9 +1052,12 @@ int ptrace_request(struct task_struct *child, long request,break ;case PTRACE_SETSIGINFO : + addr =0 ;
If this is intended to fall through, please add a
/* fall through */
comment here (newer GCC has warnings to catch this; not sure about clang, but I'd be surprised if no version warns).
[...]
Otherwise, the patch looks reasonable, but I'll wait for your response on the above points before reviewing in detail.
Cheers
---Dave
Re: [PATCH v12 7/8] signal: define the field siginfo.si_xflags
Quoted 27 lines · Dave Martin
Quoted 11 lines · Peter Collingbourne
This field will contain flags that may be used by signal handlers to determine whether other fields in the
_sigfaultportion of siginfo are valid. An example use case is the following patch, which introduces the si_addr_tag_bits{,_mask} fields.A new sigcontext flag,
SA_XFLAGS, is introduced in order to allow a signal handler to require the kernel to set the field (but note that the field will be set anyway if the kernel supports the flag, regardless of its value). In combination with the previous patches, this allows a userspace program to determine whether the kernel will set the field.Apologies for this coming rather late:
It occurs to me that we might want a more specific name, since this only applies to fault signals -- say,
SA_FAULTFLAGS.If we end up wanting to add flags fields for other signal types, then we might end up needing a
SA_flag for each, which would be a bit annoying.So, alternatively. I wonder whether it's worth preemptively adding an extra flags to every kind of kernel-generated siginfo. If so, then having a single
SA_XFLAGSwould be fine.
Quoted 5 lines
If added flags fields all over the place is considered overkill, then I guess it's sufficient to rename this flag.
If renaming, the actual flags field in siginfo should also be renamed to match.
I'd prefer not to add flags fields to every union member at this point. I agree that faultflags is a better name, and I guess it's one more reason not to try and reuse the ia64 field. Renamed in v13.
Quoted 248 lines
Quoted 241 lines
It is possible for an si_xflags-unaware program to cause a signal handler in an si_xflags-aware program to be called with a provided siginfo data structure by using one of the following syscalls:
-
ptrace(PTRACE_SETSIGINFO)
-pidfd_send_signal
-rt_sigqueueinfo
-rt_tgsigqueueinfoSo we need to prevent the si_xflags-unaware program from causing an uninitialized read of
si_xflagsin the si_xflags-aware program when it uses one of these syscalls.The last three cases can be handled by observing that each of these syscalls fails if
si_code>= 0. We also observe that kill(2) and tgkill(2) may be used to send a signal wheresi_code== 0 (SI_USER), so we definesi_xflagsto only be valid ifsi_code> 0.There is no such check on
si_codeinptrace(PTRACE_SETSIGINFO), so we makeptrace(PTRACE_SETSIGINFO)clear thesi_xflagsfield if it detects that the signal would use the_sigfaultlayout, and introduce a new ptrace request type,PTRACE_SETSIGINFO2, that a si_xflags-aware program may use to opt out of this behavior.It is also possible for the kernel to inject a signal specified to use
_sigfaultby callingforce_sig(e.g. there are numerous calls toforce_sig(SIGSEGV)). In this casesi_codeis set toSI_KERNELand the_killunion member is used, so document thatsi_codemust be <SI_KERNEL.Ideally this field could have just been named
si_flags, but that name was already taken by ia64, so a different name was chosen.I considered making ia64's
si_flagsa generic field and having it appear at the end of_sigfault(in the same place as this patch hassi_xflags) on non-ia64, keeping it in the same place on ia64. ia64'ssi_flagsis a 32-bit field with only one flag bit allocated, so we would have 31 bits to use if we do this. However, it seems simplest to avoid entangling these fields.Signed-off-by Peter Collingbourne <[email protected]>---
v12:
- Change type ofsi_xflagsto u32 to avoid increasing alignment
- Addsi_xflagstosignal_compat.ctest casesv11:
- update comment to say thatsi_codemust > 0
- changeptrace(PTRACE_SETSIGINFO2)to take a flags argumentv10:
- make the new field compatible with the various ways that a siginfo can be injected from another process
- eliminate some duplication by adding a refactoring patch before this onearch/powerpc/platforms/powernv/vas-fault.c | 1 + arch/x86/kernel/signal_compat.c | 7 +++-- include/linux/compat.h | 2 ++ include/linux/signal_types.h | 2 +- include/uapi/asm-generic/siginfo.h | 4 +++ include/uapi/asm-generic/signal-defs.h | 4 +++ include/uapi/linux/ptrace.h | 12 ++++++++ kernel/ptrace.c | 32 ++++++++++++++++++---- kernel/signal.c | 3 ++ 9 files changed, 58 insertions(+), 9 deletions(-)arch/powerpc/platforms/powernv/vas-fault.c +1
-0@@ -154,6 +154,7 @@ static void update_csb(struct vas_window *window, info.si_errno =EFAULT ; info.si_code =SEGV_MAPERR ; info.si_addr = csb_addr; + info.si_xflags =0 ;/* * process will be polling on csb.flags after request is sent to arch/x86/kernel/signal_compat.c +5
-2@@ -121,8 +121,8 @@ static inline void signal_compat_build_tests(void)#endif CHECK_CSI_OFFSET (_sigfault); -CHECK_CSI_SIZE (_sigfault,4 *sizeof (int )); -CHECK_SI_SIZE (_sigfault,8 *sizeof (int )); +CHECK_CSI_SIZE (_sigfault,8 *sizeof (int )); +CHECK_SI_SIZE (_sigfault,16 *sizeof (int ));BUILD_BUG_ON (offsetof(siginfo_t , si_addr) !=0x10 );BUILD_BUG_ON (offsetof(compat_siginfo_t , si_addr) !=0x0C );@@ -138,6 +138,9 @@ static inline void signal_compat_build_tests(void)BUILD_BUG_ON (offsetof(siginfo_t , si_pkey) !=0x20 );BUILD_BUG_ON (offsetof(compat_siginfo_t , si_pkey) !=0x14 ); +BUILD_BUG_ON (offsetof(siginfo_t , si_xflags) !=0x48 ); +BUILD_BUG_ON (offsetof(compat_siginfo_t , si_xflags) !=0x28 ); +CHECK_CSI_OFFSET (_sigpoll);CHECK_CSI_SIZE (_sigpoll,2 *sizeof (int ));CHECK_SI_SIZE (_sigpoll,4 *sizeof (int ));include/linux/compat.h +2
-0@@ -236,7 +236,9 @@ typedef struct compat_siginfo {char _dummy_pkey[__COMPAT_ADDR_BND_PKEY_PAD];u32 _pkey; } _addr_pkey; +compat_uptr_t _pad[6 ]; }; +u32 _xflags; } _sigfault;/* SIGPOLL */ include/linux/signal_types.h +1
-1@@ -78,6 +78,6 @@ struct ksignal {#define UAPI_SA_FLAGS \ (SA_NOCLDSTOP | SA_NOCLDWAIT | SA_SIGINFO | SA_ONSTACK | SA_RESTART | \ - SA_NODEFER | SA_RESETHAND | __ARCH_UAPI_SA_FLAGS) + SA_NODEFER | SA_RESETHAND | SA_XFLAGS | __ARCH_UAPI_SA_FLAGS)#endif /* _LINUX_SIGNAL_TYPES_H */ include/uapi/asm-generic/siginfo.h +4
-0@@ -91,7 +91,9 @@ union __sifields {char _dummy_pkey[__ADDR_BND_PKEY_PAD];__u32 _pkey; } _addr_pkey; +void *_pad[6 ]; }; +__u32 _xflags; } _sigfault;/* SIGPOLL */ @@ -152,6 +154,8 @@ typedef struct siginfo {#define si_trapno _sifields._sigfault._trapno#endif #define si_addr_lsb _sifields._sigfault._addr_lsb +/* si_xflags is only valid if 0 < si_code < SI_KERNEL */ +#define si_xflags _sifields._sigfault._xflags#define si_lower _sifields._sigfault._addr_bnd._lower#define si_upper _sifields._sigfault._addr_bnd._upper#define si_pkey _sifields._sigfault._addr_pkey._pkeyinclude/uapi/asm-generic/signal-defs.h +4
-0@@ -20,6 +20,9 @@* so this bit allows flag bit support to be detected from userspace while * allowing an old kernel to be distinguished from a kernel that supports every * flag bit. +* SA_XFLAGS indicates that the signal handler requires the siginfo.si_xflags +* field to be valid. Note that if the kernel supports SA_XFLAGS, the field will +* be valid regardless of the value of this flag. * * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single * Unix names RESETHAND and NODEFER respectively. @@ -49,6 +52,7 @@#define SA_RESETHAND 0x80000000#endif #define SA_UNSUPPORTED 0x00000400 +#define SA_XFLAGS 0x00000800#define SA_NOMASK SA_NODEFER#define SA_ONESHOT SA_RESETHANDinclude/uapi/linux/ptrace.h +12
-0@@ -101,6 +101,18 @@ struct ptrace_syscall_info { }; }; +#define PTRACE_SETSIGINFO2 0x420f +/* +* These flags are passed as the addr argument to ptrace. +*/ + +/* +* Asserts that the caller is aware of the field siginfo.si_xflags. Prevents +* the kernel from automatically setting the field to 0 when the signal uses +* a sigfault layout. +*/ +#define PTRACE_SIGINFO_XFLAGS 0x1 +/* * These values are stored in task->ptrace_message * by tracehook_report_syscall_* to describe the current syscall-stop. kernel/ptrace.c +18
-4@@ -687,18 +687,32 @@ static int ptrace_getsiginfo(struct task_struct *child, kernel_siginfo_t *info)return error; } -static int ptrace_setsiginfo (struct task_struct *child,const kernel_siginfo_t *info) +static int ptrace_setsiginfo (struct task_struct *child,unsigned long flags, +kernel_siginfo_t *info) { -unsigned long flags; +unsigned long lock_flags;int error = -ESRCH ; -if (lock_task_sighand (child, &flags)) { +if (flags & ~PTRACE_SIGINFO_XFLAGS ) { +return -EINVAL ; + } + +/* +* If the caller is unaware of si_xflags and we're using a layout that +* requires it, set it to 0 which means "no fields are available". +*/ +if (!(flags &PTRACE_SIGINFO_XFLAGS ) && +siginfo_layout_is_fault ( +siginfo_layout (info->si_signo, info->si_code))) + info->si_xflags =0 ; + +if (lock_task_sighand (child, &lock_flags)) { error = -EINVAL ;if (likely (child->last_siginfo !=NULL )) {copy_siginfo (child->last_siginfo, info); error =0 ; } -unlock_task_sighand (child, &flags); +unlock_task_sighand (child, &lock_flags); }return error; }kernel/ptrace.c int ptrace_request(struct task_struct *child, long request, · line 1055
Quoted 4 lines
kernel/ptrace.c +1
-0@@ -1038,9 +1052,12 @@ int ptrace_request(struct task_struct *child, long request,break ;case PTRACE_SETSIGINFO : + addr =0 ;If this is intended to fall through, please add a
Quoted 4 lines
/* fall through */comment here (newer GCC has warnings to catch this; not sure about clang, but I'd be surprised if no version warns).
Yes, clang has this warning, but it looks like it is currently disabled in clang due to differences between the compilers [1] so I didn't see it.
It looks like the kernel is moving towards using the fallthrough macro/attribute defined in include/linux/compiler_attributes.h (and to me this personally seems better than relying on parsing comments), so I've used that macro in v13.
Peter
Re: [PATCH v12 7/8] signal: define the field siginfo.si_xflags
Quoted 31 lines · Peter Collingbourne
Quoted 30 lines · Dave Martin
Quoted 11 lines · Peter Collingbourne
This field will contain flags that may be used by signal handlers to determine whether other fields in the
_sigfaultportion of siginfo are valid. An example use case is the following patch, which introduces the si_addr_tag_bits{,_mask} fields.A new sigcontext flag,
SA_XFLAGS, is introduced in order to allow a signal handler to require the kernel to set the field (but note that the field will be set anyway if the kernel supports the flag, regardless of its value). In combination with the previous patches, this allows a userspace program to determine whether the kernel will set the field.Apologies for this coming rather late:
It occurs to me that we might want a more specific name, since this only applies to fault signals -- say,
SA_FAULTFLAGS.If we end up wanting to add flags fields for other signal types, then we might end up needing a
SA_flag for each, which would be a bit annoying.So, alternatively. I wonder whether it's worth preemptively adding an extra flags to every kind of kernel-generated siginfo. If so, then having a single
SA_XFLAGSwould be fine.If added flags fields all over the place is considered overkill, then I guess it's sufficient to rename this flag.
Quoted 6 lines
Quoted 2 lines
If renaming, the actual flags field in siginfo should also be renamed to match.
I'd prefer not to add flags fields to every union member at this point. I agree that faultflags is a better name, and I guess it's one more reason not to try and reuse the ia64 field. Renamed in v13.
Ack -- I thought I should make the point, but we've got enough spare sa_flags bits for now to make this one SIL_FAULT-specific, providing the SA_foo name looks equally specific -- so just renaming that should be OK.
If we end up adding a flags field to another siginfo union member in the future, it's probably worth adding all the rest at the same time ... but it may never happen.
[...]
Quoted 54 lines
Quoted 49 lines
Quoted 42 lines
kernel/ptrace.c +18
-4@@ -687,18 +687,32 @@ static int ptrace_getsiginfo(struct task_struct *child, kernel_siginfo_t *info)return error; } -static int ptrace_setsiginfo (struct task_struct *child,const kernel_siginfo_t *info) +static int ptrace_setsiginfo (struct task_struct *child,unsigned long flags, +kernel_siginfo_t *info) { -unsigned long flags; +unsigned long lock_flags;int error = -ESRCH ; -if (lock_task_sighand (child, &flags)) { +if (flags & ~PTRACE_SIGINFO_XFLAGS ) { +return -EINVAL ; + } + +/* +* If the caller is unaware of si_xflags and we're using a layout that +* requires it, set it to 0 which means "no fields are available". +*/ +if (!(flags &PTRACE_SIGINFO_XFLAGS ) && +siginfo_layout_is_fault ( +siginfo_layout (info->si_signo, info->si_code))) + info->si_xflags =0 ; + +if (lock_task_sighand (child, &lock_flags)) { error = -EINVAL ;if (likely (child->last_siginfo !=NULL )) {copy_siginfo (child->last_siginfo, info); error =0 ; } -unlock_task_sighand (child, &flags); +unlock_task_sighand (child, &lock_flags); }return error; }kernel/ptrace.c int ptrace_request(struct task_struct *child, long request, · line 1055
Quoted 4 lines
kernel/ptrace.c +1
-0@@ -1038,9 +1052,12 @@ int ptrace_request(struct task_struct *child, long request,break ;case PTRACE_SETSIGINFO : + addr =0 ;If this is intended to fall through, please add a
Quoted 4 lines
/* fall through */comment here (newer GCC has warnings to catch this; not sure about clang, but I'd be surprised if no version warns).
Quoted 8 lines
Yes, clang has this warning, but it looks like it is currently disabled in clang due to differences between the compilers [1] so I didn't see it.
It looks like the kernel is moving towards using the fallthrough macro/attribute defined in
include/linux/compiler_attributes.h(and to me this personally seems better than relying on parsing comments), so I've used that macro in v13.
Ah, I wasn't aware of that. Sounds better!
Cheers
---Dave
PATCH v12 8/8 arm64: expose FAR_EL1 tag bits in siginfo
In reply to Peter CollingbourneThe kernel currently clears the tag bits (i.e. bits 56-63) in the fault address exposed via siginfo.si_addr and sigcontext.fault_address. However, the tag bits may be needed by tools in order to accurately diagnose memory errors, such as HWASan [1] or future tools based on the Memory Tagging Extension (MTE).
We should not stop clearing these bits in the existing fault address fields, because there may be existing userspace applications that are expecting the tag bits to be cleared. Instead, create a new pair of union fields in siginfo._sigfault, and store the tag bits of FAR_EL1 there, together with a mask specifying which bits are valid.
A flag is added to si_xflags to allow userspace to determine whether the values in the fields are valid.
[1] http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
---
v12:
- add new fields to signal_compat.c test cases
- rebased to 5.10-rc1
- mask out bits 63:60 for tag check faults
v11:
- add a comment explaining what the arch hook should do
- rename ignored bits to tag bits
v10:
- rename the flag to SIXFLAG_ADDR_IGNORED_BITS
- use an arch hook to specify which bits are ignored, instead of passing them explicitly
- while refactoring for the arch hook, noticed that my previous patches missed a case involving cache maintenance instructions, so expose the tag bits for that signal as well
v9:
- make the ignored bits fields generic
- add some new dependent patches that prepare us to store the field in such a way that userspace can detect their presence
v8:
- rebase onto 5.8rc2
v7:
- switch to a new siginfo field instead of using sigcontext
- merge the patch back into one since the other patches are now unnecessary
v6:
- move fault address and fault code into the kernel_siginfo data structure
- split the patch in three since it was getting large and now has generic and arch-specific parts
v5:
- add padding to fault_addr_top_byte_context in order to ensure the correct size and preserve sp alignment
v4:
- expose only the tag bits in the context instead of the entire FAR_EL1
- remove mention of the new context from the sigcontext.__reserved[] note
v3:
- add documentation to tagged-pointers.rst
- update comments in sigcontext.h
v2:
- revert changes to hw_breakpoint.c
- rename set_thread_esr to set_thread_far_esr
Documentation/arm64/tagged-pointers.rst | 21 +++++--- arch/arm64/include/asm/exception.h | 2 +- arch/arm64/include/asm/signal.h | 19 +++++++ arch/arm64/include/asm/system_misc.h | 2 +- arch/arm64/include/asm/traps.h | 6 +-- arch/arm64/kernel/debug-monitors.c | 5 +- arch/arm64/kernel/entry-common.c | 2 - arch/arm64/kernel/ptrace.c | 7 +-- arch/arm64/kernel/sys_compat.c | 5 +- arch/arm64/kernel/traps.c | 29 ++++++----- arch/arm64/mm/fault.c | 68 ++++++++++++++----------- arch/x86/kernel/signal_compat.c | 9 +++- include/linux/compat.h | 2 + include/linux/signal.h | 16 ++++++ include/uapi/asm-generic/siginfo.h | 10 ++++ kernel/signal.c | 18 ++++++- 16 files changed, 148 insertions(+), 73 deletions(-) create mode 100644 arch/arm64/include/asm/signal.h
Documentation/arm64/tagged-pointers.rst +15 -6
@@ -53,12 +53,21 @@ visibility. Preserving tags --------------- -Non-zero tags are not preserved when delivering signals. This means that -signal handlers in applications making use of tags cannot rely on the -tag information for user virtual addresses being maintained for fields -inside siginfo_t. One exception to this rule is for signals raised in -response to watchpoint debug exceptions, where the tag information will -be preserved. +Non-zero tags are not preserved in the fault address fields +siginfo.si_addr or sigcontext.fault_address when delivering +signals. This means that signal handlers in applications making use +of tags cannot rely on the tag information for user virtual addresses +being maintained in these fields. One exception to this rule is for +signals raised in response to watchpoint debug exceptions, where the +tag information will be preserved. + +The fault address tag is preserved in the si_addr_tag_bits field +of siginfo, which is set for signals raised in response to data aborts +and instruction aborts. The si_addr_tag_bits_mask field indicates +which bits of the field are valid. The validity of these fields is +indicated by the SIXFLAG_ADDR_TAG_BITS flag in siginfo.si_xflags, +and the validity of si_xflags in turn is indicated by the kernel +indicating support for the sigaction.sa_flags flag SA_XFLAGS. The architecture prevents the use of a tagged PC, so the upper byte will be set to a sign-extension of bit 55 on exception return.
arch/arm64/include/asm/exception.h +1 -1
@@ -32,7 +32,7 @@ static inline u32 disr_to_esr(u64 disr) } asmlinkage void enter_from_user_mode(void); -void do_mem_abort (unsigned long addr,unsigned int esr,struct pt_regs *regs); +void do_mem_abort (unsigned long far,unsigned int esr,struct pt_regs *regs);void do_undefinstr (struct pt_regs *regs);void do_bti (struct pt_regs *regs); asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr);
arch/arm64/include/asm/signal.h new file +19 -0
@@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ARM64_ASM_SIGNAL_H +#define __ARM64_ASM_SIGNAL_H + +#include <uapi/asm/signal.h> +#include <uapi/asm/siginfo.h> + +static inline unsigned long arch_addr_tag_bits_mask (unsigned long sig, +unsigned long si_code) +{ +if (sig ==SIGTRAP && si_code ==TRAP_BRKPT ) +return 0 ; +if (sig ==SIGSEGV && si_code ==SEGV_MTESERR ) +return 0xfUL <<56 ; +return 0xffUL <<56 ; +} +#define arch_addr_tag_bits_mask arch_addr_tag_bits_mask + +#endif
arch/arm64/include/asm/system_misc.h +1 -1
@@ -22,7 +22,7 @@ void die(const char *msg, struct pt_regs *regs, int err);struct siginfo ;void arm64_notify_die (const char *str,struct pt_regs *regs, -int signo,int sicode,void __user *addr, +int signo,int sicode,unsigned long far,int err); void hook_debug_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
arch/arm64/include/asm/traps.h +3 -3
@@ -26,9 +26,9 @@ void register_undef_hook(struct undef_hook *hook);void unregister_undef_hook (struct undef_hook *hook);void force_signal_inject (int signal,int code,unsigned long address,unsigned int err);void arm64_notify_segfault (unsigned long addr); -void arm64_force_sig_fault (int signo,int code,void __user *addr,const char *str); -void arm64_force_sig_mceerr (int code,void __user *addr,short lsb,const char *str); -void arm64_force_sig_ptrace_errno_trap (int errno,void __user *addr,const char *str); +void arm64_force_sig_fault (int signo,int code,unsigned long far,const char *str); +void arm64_force_sig_mceerr (int code,unsigned long far,short lsb,const char *str); +void arm64_force_sig_ptrace_errno_trap (int errno,unsigned long far,const char *str);/* * Move regs->pc to next instruction and do necessary setup before it
arch/arm64/kernel/debug-monitors.c +2 -3
@@ -234,9 +234,8 @@ static void send_user_sigtrap(int si_code)if (interrupts_enabled (regs))local_irq_enable (); -arm64_force_sig_fault (SIGTRAP , si_code, - (void __user *)instruction_pointer (regs), -"User debug trap" ); +arm64_force_sig_fault (SIGTRAP , si_code,instruction_pointer (regs), +"User debug trap" ); } static int single_step_handler(unsigned long unused, unsigned int esr,
arch/arm64/kernel/entry-common.c +0 -2
@@ -22,7 +22,6 @@ static void notrace el1_abort(struct pt_regs *regs, unsigned long esr)unsigned long far =read_sysreg (far_el1);local_daif_inherit (regs); - far =untagged_addr (far);do_mem_abort (far, esr, regs); }NOKPROBE_SYMBOL (el1_abort);
@@ -114,7 +113,6 @@ static void notrace el0_da(struct pt_regs *regs, unsigned long esr)user_exit_irqoff ();local_daif_restore (DAIF_PROCCTX ); - far =untagged_addr (far);do_mem_abort (far, esr, regs); }NOKPROBE_SYMBOL (el0_da);
arch/arm64/kernel/ptrace.c +2 -5
@@ -192,14 +192,11 @@ static void ptrace_hbptriggered(struct perf_event *bp, break; } } -arm64_force_sig_ptrace_errno_trap (si_errno, - (void __user *)bkpt->trigger, +arm64_force_sig_ptrace_errno_trap (si_errno, bkpt->trigger, desc); }#endif -arm64_force_sig_fault (SIGTRAP ,TRAP_HWBKPT , - (void __user *)(bkpt->trigger), - desc); +arm64_force_sig_fault (SIGTRAP ,TRAP_HWBKPT , bkpt->trigger, desc); }/*
arch/arm64/kernel/sys_compat.c +2 -3
@@ -68,7 +68,7 @@ do_compat_cache_op(unsigned long start, unsigned long end, int flags)*/ long compat_arm_syscall (struct pt_regs *regs,int scno) { -void __user *addr; +unsigned long addr;switch (scno) {/*
@@ -111,8 +111,7 @@ long compat_arm_syscall(struct pt_regs *regs, int scno)break ; } - addr = (void __user *)instruction_pointer (regs) - - (compat_thumb_mode (regs) ?2 :4 ); + addr =instruction_pointer (regs) - (compat_thumb_mode (regs) ?2 :4 );arm64_notify_die ("Oops - bad compat syscall(2)" , regs,SIGILL ,ILL_ILLTRP , addr, scno);
arch/arm64/kernel/traps.c +15 -14
@@ -170,32 +170,32 @@ static void arm64_show_signal(int signo, const char *str)__show_regs (regs); } -void arm64_force_sig_fault (int signo,int code,void __user *addr, +void arm64_force_sig_fault (int signo,int code,unsigned long far,const char *str) {arm64_show_signal (signo, str);if (signo ==SIGKILL )force_sig (SIGKILL );else -force_sig_fault (signo, code, addr); +force_sig_fault (signo, code, (void __user *)far); } -void arm64_force_sig_mceerr (int code,void __user *addr,short lsb, +void arm64_force_sig_mceerr (int code,unsigned long far,short lsb,const char *str) {arm64_show_signal (SIGBUS , str); -force_sig_mceerr (code, addr, lsb); +force_sig_mceerr (code, (void __user *)far, lsb); } -void arm64_force_sig_ptrace_errno_trap (int errno,void __user *addr, +void arm64_force_sig_ptrace_errno_trap (int errno,unsigned long far,const char *str) {arm64_show_signal (SIGTRAP , str); -force_sig_ptrace_errno_trap (errno, addr); +force_sig_ptrace_errno_trap (errno, (void __user *)far); }void arm64_notify_die (const char *str,struct pt_regs *regs, -int signo,int sicode,void __user *addr, +int signo,int sicode,unsigned long far,int err) {if (user_mode (regs)) {
@@ -203,7 +203,7 @@ void arm64_notify_die(const char *str, struct pt_regs *regs, current->thread.fault_address =0 ; current->thread.fault_code = err; -arm64_force_sig_fault (signo, sicode, addr, str); +arm64_force_sig_fault (signo, sicode, far, str); }else {die (str, regs, err); }
@@ -374,7 +374,7 @@ void force_signal_inject(int signal, int code, unsigned long address, unsigned i signal =SIGKILL ; } -arm64_notify_die (desc, regs, signal, code, (void __user *)address, err); +arm64_notify_die (desc, regs, signal, code, address, err); }/*
@@ -385,7 +385,7 @@ void arm64_notify_segfault(unsigned long addr)int code;mmap_read_lock (current->mm); -if (find_vma (current->mm, addr) ==NULL ) +if (find_vma (current->mm,untagged_addr (addr)) ==NULL ) code =SEGV_MAPERR ;else code =SEGV_ACCERR ;
@@ -448,12 +448,13 @@ NOKPROBE_SYMBOL(do_ptrauth_fault);static void user_cache_maint_handler (unsigned int esr,struct pt_regs *regs) { -unsigned long address; +unsigned long tagged_address, address;int rt =ESR_ELx_SYS64_ISS_RT (esr);int crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT;int ret =0 ; - address =untagged_addr (pt_regs_read_reg (regs, rt)); + tagged_address =pt_regs_read_reg (regs, rt); + address =untagged_addr (tagged_address);switch (crm) {case ESR_ELx_SYS64_ISS_CRM_DC_CVAU:/* DC CVAU, gets promoted */
@@ -480,7 +481,7 @@ static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs) }if (ret) -arm64_notify_segfault (address); +arm64_notify_segfault (tagged_address);else arm64_skip_faulting_instruction (regs,AARCH64_INSN_SIZE ); }
@@ -772,7 +773,7 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr)*/ void bad_el0_sync (struct pt_regs *regs,int reason,unsigned int esr) { -void __user *pc = (void __user *)instruction_pointer (regs); +unsigned long pc =instruction_pointer (regs); current->thread.fault_address =0 ; current->thread.fault_code = esr;
arch/arm64/mm/fault.c +37 -31
183 lines not on this page · raw message
arch/x86/kernel/signal_compat.c +7 -2
@@ -121,8 +121,8 @@ static inline void signal_compat_build_tests(void)#endif CHECK_CSI_OFFSET (_sigfault); -CHECK_CSI_SIZE (_sigfault,8 *sizeof (int )); -CHECK_SI_SIZE (_sigfault,16 *sizeof (int )); +CHECK_CSI_SIZE (_sigfault,10 *sizeof (int )); +CHECK_SI_SIZE (_sigfault,20 *sizeof (int ));BUILD_BUG_ON (offsetof(siginfo_t , si_addr) !=0x10 );BUILD_BUG_ON (offsetof(compat_siginfo_t , si_addr) !=0x0C );
@@ -141,6 +141,11 @@ static inline void signal_compat_build_tests(void)BUILD_BUG_ON (offsetof(siginfo_t , si_xflags) !=0x48 );BUILD_BUG_ON (offsetof(compat_siginfo_t , si_xflags) !=0x28 ); +BUILD_BUG_ON (offsetof(siginfo_t , si_addr_tag_bits) !=0x50 ); +BUILD_BUG_ON (offsetof(siginfo_t , si_addr_tag_bits_mask) !=0x58 ); +BUILD_BUG_ON (offsetof(compat_siginfo_t , si_addr_tag_bits) !=0x2C ); +BUILD_BUG_ON (offsetof(compat_siginfo_t , si_addr_tag_bits_mask) !=0x30 ); +CHECK_CSI_OFFSET (_sigpoll);CHECK_CSI_SIZE (_sigpoll,2 *sizeof (int ));CHECK_SI_SIZE (_sigpoll,4 *sizeof (int ));
include/linux/compat.h +2 -0
@@ -239,6 +239,8 @@ typedef struct compat_siginfo {compat_uptr_t _pad[6 ]; };u32 _xflags; +compat_uptr_t _addr_tag_bits; +compat_uptr_t _addr_tag_bits_mask; } _sigfault;/* SIGPOLL */
include/linux/signal.h +16 -0
@@ -480,4 +480,20 @@ struct seq_file;extern void render_sigset_t (struct seq_file *,const char *,sigset_t *);#endif +#ifndef arch_addr_tag_bits_mask +/* +* Given a signal and si_code which correspond to the _sigfault union member, +* if tag bits are present in the fault address which must appear in +* si_addr_tag_bits instead of si_addr, this hook must return a bitmask where 1 +* corresponds to bits appearing in si_addr_tag_bits and 0 corresponds to bits +* appearing in si_addr. The value returned by this function will also be +* available in si_addr_tag_bits_mask. +*/ +static inline unsigned long arch_addr_tag_bits_mask (unsigned long sig, +unsigned long si_code) +{ +return 0 ; +} +#endif +#endif /* _LINUX_SIGNAL_H */
include/uapi/asm-generic/siginfo.h +10 -0
@@ -94,6 +94,8 @@ union __sifields {void *_pad[6 ]; };__u32 _xflags; +unsigned long _addr_tag_bits; +unsigned long _addr_tag_bits_mask; } _sigfault;/* SIGPOLL */
@@ -156,6 +158,8 @@ typedef struct siginfo {#define si_addr_lsb _sifields._sigfault._addr_lsb/* si_xflags is only valid if 0 < si_code < SI_KERNEL */ #define si_xflags _sifields._sigfault._xflags +#define si_addr_tag_bits _sifields._sigfault._addr_tag_bits +#define si_addr_tag_bits_mask _sifields._sigfault._addr_tag_bits_mask#define si_lower _sifields._sigfault._addr_bnd._lower#define si_upper _sifields._sigfault._addr_bnd._upper#define si_pkey _sifields._sigfault._addr_pkey._pkey
@@ -298,6 +302,12 @@ typedef struct siginfo {#define EMT_TAGOVF 1/* tag overflow */ #define NSIGEMT 1 +/* +* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP, SIGEMT si_xflags +*/ +#define SIXFLAG_ADDR_TAG_BITS 1 +/* si_addr_tag_bits{,_mask} fields valid */ +/* * sigevent definitions *
kernel/signal.c +16 -2
@@ -1652,11 +1652,16 @@ void force_sigsegv(int sig)static void set_sigfault_common_fields (struct kernel_siginfo *info,int sig,int code,void __user *addr) { +unsigned long addr_long = (unsigned long )addr; +unsigned long tag_bits_mask =arch_addr_tag_bits_mask (sig, code); + info->si_signo = sig; info->si_errno =0 ; info->si_code = code; - info->si_addr = addr; - info->si_xflags =0 ; + info->si_addr = (void __user *)(addr_long & ~tag_bits_mask); + info->si_xflags =SIXFLAG_ADDR_TAG_BITS ; + info->si_addr_tag_bits = addr_long & tag_bits_mask; + info->si_addr_tag_bits_mask = tag_bits_mask; } int force_sig_fault_to_task(int sig, int code, void __user *addr
@@ -3271,6 +3276,13 @@ void copy_siginfo_to_external32(struct compat_siginfo *to, to->si_trapno = from->si_trapno;#endif to->si_xflags = from->si_xflags; +/* +* These assignments involve a truncation, but as with si_addr +* they will be derived from a 32-bit fault address so we +* should not expect any truncation in practice. +*/ + to->si_addr_tag_bits = from->si_addr_tag_bits; + to->si_addr_tag_bits_mask = from->si_addr_tag_bits_mask; }switch (layout) {
@@ -3347,6 +3359,8 @@ static int post_copy_siginfo_from_user32(kernel_siginfo_t *to, to->si_trapno = from->si_trapno;#endif to->si_xflags = from->si_xflags; + to->si_addr_tag_bits = from->si_addr_tag_bits; + to->si_addr_tag_bits_mask = from->si_addr_tag_bits_mask; }switch (layout) {
Signature · 7 lines
2.29.0.rc1.297.gfa9743e501-goog _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Quoted 145 lines · Peter Collingbourne
The kernel currently clears the tag bits (i.e. bits 56-63) in the fault address exposed via siginfo.si_addr and sigcontext.fault_address. However, the tag bits may be needed by tools in order to accurately diagnose memory errors, such as HWASan [1] or future tools based on the Memory Tagging Extension (MTE).
We should not stop clearing these bits in the existing fault address fields, because there may be existing userspace applications that are expecting the tag bits to be cleared. Instead, create a new pair of union fields in siginfo._sigfault, and store the tag bits of
FAR_EL1there, together with a mask specifying which bits are valid.A flag is added to
si_xflagsto allow userspace to determine whether the values in the fields are valid.[1] http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
Signed-off-by Peter Collingbourne <[email protected]>---
v12:
- add new fields tosignal_compat.ctest cases
- rebased to 5.10-rc1
- mask out bits 63:60 for tag check faultsv11:
- add a comment explaining what the arch hook should do
- rename ignored bits to tag bitsv10:
- rename the flag toSIXFLAG_ADDR_IGNORED_BITS
- use an arch hook to specify which bits are ignored, instead of passing them explicitly
- while refactoring for the arch hook, noticed that my previous patches missed a case involving cache maintenance instructions, so expose the tag bits for that signal as wellv9:
- make the ignored bits fields generic
- add some new dependent patches that prepare us to store the field in such a way that userspace can detect their presencev8:
- rebase onto 5.8rc2v7:
- switch to a new siginfo field instead of using sigcontext
- merge the patch back into one since the other patches are now unnecessaryv6:
- move fault address and fault code into thekernel_siginfodata structure
- split the patch in three since it was getting large and now has generic and arch-specific partsv5:
- add padding tofault_addr_top_byte_contextin order to ensure the correct size and preserve sp alignmentv4:
- expose only the tag bits in the context instead of the entireFAR_EL1
- remove mention of the new context from the sigcontext.__reserved[] notev3:
- add documentation totagged-pointers.rst
- update comments insigcontext.hv2:
- revert changes tohw_breakpoint.c
- renameset_thread_esrtoset_thread_far_esrDocumentation/arm64/tagged-pointers.rst | 21 +++++--- arch/arm64/include/asm/exception.h | 2 +- arch/arm64/include/asm/signal.h | 19 +++++++ arch/arm64/include/asm/system_misc.h | 2 +- arch/arm64/include/asm/traps.h | 6 +-- arch/arm64/kernel/debug-monitors.c | 5 +- arch/arm64/kernel/entry-common.c | 2 - arch/arm64/kernel/ptrace.c | 7 +-- arch/arm64/kernel/sys_compat.c | 5 +- arch/arm64/kernel/traps.c | 29 ++++++----- arch/arm64/mm/fault.c | 68 ++++++++++++++----------- arch/x86/kernel/signal_compat.c | 9 +++- include/linux/compat.h | 2 + include/linux/signal.h | 16 ++++++ include/uapi/asm-generic/siginfo.h | 10 ++++ kernel/signal.c | 18 ++++++- 16 files changed, 148 insertions(+), 73 deletions(-) create mode 100644 arch/arm64/include/asm/signal.hDocumentation/arm64/tagged-pointers.rst +15
-6@@ -53,12 +53,21 @@ visibility. Preserving tags --------------- -Non-zero tags are not preserved when delivering signals. This means that -signal handlers in applications making use of tags cannot rely on the -tag information for user virtual addresses being maintained for fields -inside siginfo_t. One exception to this rule is for signals raised in -response to watchpoint debug exceptions, where the tag information will -be preserved. +Non-zero tags are not preserved in the fault address fields +siginfo.si_addr or sigcontext.fault_address when delivering +signals. This means that signal handlers in applications making use +of tags cannot rely on the tag information for user virtual addresses +being maintained in these fields. One exception to this rule is for +signals raised in response to watchpoint debug exceptions, where the +tag information will be preserved. + +The fault address tag is preserved in the si_addr_tag_bits field +of siginfo, which is set for signals raised in response to data aborts +and instruction aborts. The si_addr_tag_bits_mask field indicates +which bits of the field are valid. The validity of these fields is +indicated by the SIXFLAG_ADDR_TAG_BITS flag in siginfo.si_xflags, +and the validity of si_xflags in turn is indicated by the kernel +indicating support for the sigaction.sa_flags flag SA_XFLAGS. The architecture prevents the use of a tagged PC, so the upper byte will be set to a sign-extension of bit 55 on exception return.arch/arm64/include/asm/exception.h +1
-1@@ -32,7 +32,7 @@ static inline u32 disr_to_esr(u64 disr) } asmlinkage void enter_from_user_mode(void); -void do_mem_abort (unsigned long addr,unsigned int esr,struct pt_regs *regs); +void do_mem_abort (unsigned long far,unsigned int esr,struct pt_regs *regs);void do_undefinstr (struct pt_regs *regs);void do_bti (struct pt_regs *regs); asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr);arch/arm64/include/asm/signal.h new file +4
-0@@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ARM64_ASM_SIGNAL_H +#define __ARM64_ASM_SIGNAL_H +
arch/arm64/include/asm/signal.h line 14
Quoted 10 lines
arch/arm64/include/asm/signal.h new file +10
-0+#include <uapi/asm/signal.h> +#include <uapi/asm/siginfo.h> + +static inline unsigned long arch_addr_tag_bits_mask (unsigned long sig, +unsigned long si_code) +{ +if (sig ==SIGTRAP && si_code ==TRAP_BRKPT ) +return 0 ; +if (sig ==SIGSEGV && si_code ==SEGV_MTESERR ) +return 0xfUL <<56 ;
Should this be 0xffUL << 56?
I thought MTE ignored bits 63:60, rather than requiring them to be 0?
The whole tag byte may be relevant for debugging purposes, even if only some of the bits are checked in hardware.
For consistency, I wonder whether it makes sense to expose the bits as tag bits for watchpoint execeptions, even if they are left un-cleared in si_addr for historical reasons.
arch/arm64/include/asm/signal.h line 17
Quoted 3 lines
arch/arm64/include/asm/signal.h new file +3
-0+return 0xffUL <<56 ; +} +#define arch_addr_tag_bits_mask arch_addr_tag_bits_mask
[...]
Cheers
---Dave
Quoted 160 lines · Dave Martin
Quoted 145 lines · Peter Collingbourne
The kernel currently clears the tag bits (i.e. bits 56-63) in the fault address exposed via siginfo.si_addr and sigcontext.fault_address. However, the tag bits may be needed by tools in order to accurately diagnose memory errors, such as HWASan [1] or future tools based on the Memory Tagging Extension (MTE).
We should not stop clearing these bits in the existing fault address fields, because there may be existing userspace applications that are expecting the tag bits to be cleared. Instead, create a new pair of union fields in siginfo._sigfault, and store the tag bits of
FAR_EL1there, together with a mask specifying which bits are valid.A flag is added to
si_xflagsto allow userspace to determine whether the values in the fields are valid.[1] http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
Signed-off-by Peter Collingbourne <[email protected]>---
v12:
- add new fields tosignal_compat.ctest cases
- rebased to 5.10-rc1
- mask out bits 63:60 for tag check faultsv11:
- add a comment explaining what the arch hook should do
- rename ignored bits to tag bitsv10:
- rename the flag toSIXFLAG_ADDR_IGNORED_BITS
- use an arch hook to specify which bits are ignored, instead of passing them explicitly
- while refactoring for the arch hook, noticed that my previous patches missed a case involving cache maintenance instructions, so expose the tag bits for that signal as wellv9:
- make the ignored bits fields generic
- add some new dependent patches that prepare us to store the field in such a way that userspace can detect their presencev8:
- rebase onto 5.8rc2v7:
- switch to a new siginfo field instead of using sigcontext
- merge the patch back into one since the other patches are now unnecessaryv6:
- move fault address and fault code into thekernel_siginfodata structure
- split the patch in three since it was getting large and now has generic and arch-specific partsv5:
- add padding tofault_addr_top_byte_contextin order to ensure the correct size and preserve sp alignmentv4:
- expose only the tag bits in the context instead of the entireFAR_EL1
- remove mention of the new context from the sigcontext.__reserved[] notev3:
- add documentation totagged-pointers.rst
- update comments insigcontext.hv2:
- revert changes tohw_breakpoint.c
- renameset_thread_esrtoset_thread_far_esrDocumentation/arm64/tagged-pointers.rst | 21 +++++--- arch/arm64/include/asm/exception.h | 2 +- arch/arm64/include/asm/signal.h | 19 +++++++ arch/arm64/include/asm/system_misc.h | 2 +- arch/arm64/include/asm/traps.h | 6 +-- arch/arm64/kernel/debug-monitors.c | 5 +- arch/arm64/kernel/entry-common.c | 2 - arch/arm64/kernel/ptrace.c | 7 +-- arch/arm64/kernel/sys_compat.c | 5 +- arch/arm64/kernel/traps.c | 29 ++++++----- arch/arm64/mm/fault.c | 68 ++++++++++++++----------- arch/x86/kernel/signal_compat.c | 9 +++- include/linux/compat.h | 2 + include/linux/signal.h | 16 ++++++ include/uapi/asm-generic/siginfo.h | 10 ++++ kernel/signal.c | 18 ++++++- 16 files changed, 148 insertions(+), 73 deletions(-) create mode 100644 arch/arm64/include/asm/signal.hDocumentation/arm64/tagged-pointers.rst +15
-6@@ -53,12 +53,21 @@ visibility. Preserving tags --------------- -Non-zero tags are not preserved when delivering signals. This means that -signal handlers in applications making use of tags cannot rely on the -tag information for user virtual addresses being maintained for fields -inside siginfo_t. One exception to this rule is for signals raised in -response to watchpoint debug exceptions, where the tag information will -be preserved. +Non-zero tags are not preserved in the fault address fields +siginfo.si_addr or sigcontext.fault_address when delivering +signals. This means that signal handlers in applications making use +of tags cannot rely on the tag information for user virtual addresses +being maintained in these fields. One exception to this rule is for +signals raised in response to watchpoint debug exceptions, where the +tag information will be preserved. + +The fault address tag is preserved in the si_addr_tag_bits field +of siginfo, which is set for signals raised in response to data aborts +and instruction aborts. The si_addr_tag_bits_mask field indicates +which bits of the field are valid. The validity of these fields is +indicated by the SIXFLAG_ADDR_TAG_BITS flag in siginfo.si_xflags, +and the validity of si_xflags in turn is indicated by the kernel +indicating support for the sigaction.sa_flags flag SA_XFLAGS. The architecture prevents the use of a tagged PC, so the upper byte will be set to a sign-extension of bit 55 on exception return.arch/arm64/include/asm/exception.h +1
-1@@ -32,7 +32,7 @@ static inline u32 disr_to_esr(u64 disr) } asmlinkage void enter_from_user_mode(void); -void do_mem_abort (unsigned long addr,unsigned int esr,struct pt_regs *regs); +void do_mem_abort (unsigned long far,unsigned int esr,struct pt_regs *regs);void do_undefinstr (struct pt_regs *regs);void do_bti (struct pt_regs *regs); asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr);arch/arm64/include/asm/signal.h new file +4
-0@@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ARM64_ASM_SIGNAL_H +#define __ARM64_ASM_SIGNAL_H +arch/arm64/include/asm/signal.h line 14
Quoted 10 lines
arch/arm64/include/asm/signal.h new file +10
-0+#include <uapi/asm/signal.h> +#include <uapi/asm/siginfo.h> + +static inline unsigned long arch_addr_tag_bits_mask (unsigned long sig, +unsigned long si_code) +{ +if (sig ==SIGTRAP && si_code ==TRAP_BRKPT ) +return 0 ; +if (sig ==SIGSEGV && si_code ==SEGV_MTESERR ) +return 0xfUL <<56 ;Should this be
0xffUL<< 56?
Quoted 1 line
I thought MTE ignored bits 63:60, rather than requiring them to be 0?
Yes, but the architecture defines FAR_EL1[63:60] as UNKNOWN for tag check faults. As such the bits are masked out in do_tag_check_fault and excluded from the mask here to indicate that they are not present.
Quoted 2 lines
The whole tag byte may be relevant for debugging purposes, even if only some of the bits are checked in hardware.
Yes and that's why it's a bit of a shame that the bits were defined as UNKNOWN. We had an idea for how to improve error reports by using those bits to link tag check faults to previous allocations, which was precluded by the missing bits.
Hopefully a future revision of the architecture will define these bits for tag check faults (at least optionally). If that ever happens and support for the architecture extension is detected we could stop masking the bits out in do_tag_check_fault and set si_addr_tag_bits_mask to 0xffUL << 56, which would let userspace know that the bits are now present.
Quoted 3 lines
For consistency, I wonder whether it makes sense to expose the bits as tag bits for watchpoint execeptions, even if they are left un-cleared in
si_addrfor historical reasons.
I don't have a strong opinion on whether to do this or not, but it seems like a nice property that the bits are either defined in si_addr or in si_addr_tag_bits. I think we could leave the watchpoint exception on arm64 as "weird for historical reasons" and insist that any future architectures adopting tagged addresses handle the tag bits uniformly.
Peter
Quoted 161 lines · Peter Collingbourne
Quoted 160 lines · Dave Martin
Quoted 145 lines · Peter Collingbourne
The kernel currently clears the tag bits (i.e. bits 56-63) in the fault address exposed via siginfo.si_addr and sigcontext.fault_address. However, the tag bits may be needed by tools in order to accurately diagnose memory errors, such as HWASan [1] or future tools based on the Memory Tagging Extension (MTE).
We should not stop clearing these bits in the existing fault address fields, because there may be existing userspace applications that are expecting the tag bits to be cleared. Instead, create a new pair of union fields in siginfo._sigfault, and store the tag bits of
FAR_EL1there, together with a mask specifying which bits are valid.A flag is added to
si_xflagsto allow userspace to determine whether the values in the fields are valid.[1] http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
Signed-off-by Peter Collingbourne <[email protected]>---
v12:
- add new fields tosignal_compat.ctest cases
- rebased to 5.10-rc1
- mask out bits 63:60 for tag check faultsv11:
- add a comment explaining what the arch hook should do
- rename ignored bits to tag bitsv10:
- rename the flag toSIXFLAG_ADDR_IGNORED_BITS
- use an arch hook to specify which bits are ignored, instead of passing them explicitly
- while refactoring for the arch hook, noticed that my previous patches missed a case involving cache maintenance instructions, so expose the tag bits for that signal as wellv9:
- make the ignored bits fields generic
- add some new dependent patches that prepare us to store the field in such a way that userspace can detect their presencev8:
- rebase onto 5.8rc2v7:
- switch to a new siginfo field instead of using sigcontext
- merge the patch back into one since the other patches are now unnecessaryv6:
- move fault address and fault code into thekernel_siginfodata structure
- split the patch in three since it was getting large and now has generic and arch-specific partsv5:
- add padding tofault_addr_top_byte_contextin order to ensure the correct size and preserve sp alignmentv4:
- expose only the tag bits in the context instead of the entireFAR_EL1
- remove mention of the new context from the sigcontext.__reserved[] notev3:
- add documentation totagged-pointers.rst
- update comments insigcontext.hv2:
- revert changes tohw_breakpoint.c
- renameset_thread_esrtoset_thread_far_esrDocumentation/arm64/tagged-pointers.rst | 21 +++++--- arch/arm64/include/asm/exception.h | 2 +- arch/arm64/include/asm/signal.h | 19 +++++++ arch/arm64/include/asm/system_misc.h | 2 +- arch/arm64/include/asm/traps.h | 6 +-- arch/arm64/kernel/debug-monitors.c | 5 +- arch/arm64/kernel/entry-common.c | 2 - arch/arm64/kernel/ptrace.c | 7 +-- arch/arm64/kernel/sys_compat.c | 5 +- arch/arm64/kernel/traps.c | 29 ++++++----- arch/arm64/mm/fault.c | 68 ++++++++++++++----------- arch/x86/kernel/signal_compat.c | 9 +++- include/linux/compat.h | 2 + include/linux/signal.h | 16 ++++++ include/uapi/asm-generic/siginfo.h | 10 ++++ kernel/signal.c | 18 ++++++- 16 files changed, 148 insertions(+), 73 deletions(-) create mode 100644 arch/arm64/include/asm/signal.hDocumentation/arm64/tagged-pointers.rst +15
-6@@ -53,12 +53,21 @@ visibility. Preserving tags --------------- -Non-zero tags are not preserved when delivering signals. This means that -signal handlers in applications making use of tags cannot rely on the -tag information for user virtual addresses being maintained for fields -inside siginfo_t. One exception to this rule is for signals raised in -response to watchpoint debug exceptions, where the tag information will -be preserved. +Non-zero tags are not preserved in the fault address fields +siginfo.si_addr or sigcontext.fault_address when delivering +signals. This means that signal handlers in applications making use +of tags cannot rely on the tag information for user virtual addresses +being maintained in these fields. One exception to this rule is for +signals raised in response to watchpoint debug exceptions, where the +tag information will be preserved. + +The fault address tag is preserved in the si_addr_tag_bits field +of siginfo, which is set for signals raised in response to data aborts +and instruction aborts. The si_addr_tag_bits_mask field indicates +which bits of the field are valid. The validity of these fields is +indicated by the SIXFLAG_ADDR_TAG_BITS flag in siginfo.si_xflags, +and the validity of si_xflags in turn is indicated by the kernel +indicating support for the sigaction.sa_flags flag SA_XFLAGS. The architecture prevents the use of a tagged PC, so the upper byte will be set to a sign-extension of bit 55 on exception return.arch/arm64/include/asm/exception.h +1
-1@@ -32,7 +32,7 @@ static inline u32 disr_to_esr(u64 disr) } asmlinkage void enter_from_user_mode(void); -void do_mem_abort (unsigned long addr,unsigned int esr,struct pt_regs *regs); +void do_mem_abort (unsigned long far,unsigned int esr,struct pt_regs *regs);void do_undefinstr (struct pt_regs *regs);void do_bti (struct pt_regs *regs); asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr);arch/arm64/include/asm/signal.h new file +4
-0@@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ARM64_ASM_SIGNAL_H +#define __ARM64_ASM_SIGNAL_H +arch/arm64/include/asm/signal.h line 14
Quoted 10 lines
arch/arm64/include/asm/signal.h new file +10
-0+#include <uapi/asm/signal.h> +#include <uapi/asm/siginfo.h> + +static inline unsigned long arch_addr_tag_bits_mask (unsigned long sig, +unsigned long si_code) +{ +if (sig ==SIGTRAP && si_code ==TRAP_BRKPT ) +return 0 ; +if (sig ==SIGSEGV && si_code ==SEGV_MTESERR ) +return 0xfUL <<56 ;Should this be
0xffUL<< 56?
Quoted 5 lines
Quoted 1 line
I thought MTE ignored bits 63:60, rather than requiring them to be 0?
Yes, but the architecture defines FAR_EL1[63:60] as UNKNOWN for tag check faults. As such the bits are masked out in
do_tag_check_faultand excluded from the mask here to indicate that they are not present.
Ah, OK. I'd forgotten that.
So long as these bits are also zeroed in si_addr, I guess that's fine.
Quoted 8 lines
Quoted 3 lines
The whole tag byte may be relevant for debugging purposes, even if only some of the bits are checked in hardware.
Yes and that's why it's a bit of a shame that the bits were defined as UNKNOWN. We had an idea for how to improve error reports by using those bits to link tag check faults to previous allocations, which was precluded by the missing bits.
Presumably if some future arch version propagated this information, we could add those bits into the tag bits mask when running on new enough hardware?
Either way, I think we could do with a comment here.
Quoted 12 lines
Hopefully a future revision of the architecture will define these bits for tag check faults (at least optionally). If that ever happens and support for the architecture extension is detected we could stop masking the bits out in
do_tag_check_faultand setsi_addr_tag_bits_maskto0xffUL<< 56, which would let userspace know that the bits are now present.Quoted 3 lines
For consistency, I wonder whether it makes sense to expose the bits as tag bits for watchpoint execeptions, even if they are left un-cleared in
si_addrfor historical reasons.
Quoted 6 lines
I don't have a strong opinion on whether to do this or not, but it seems like a nice property that the bits are either defined in
si_addror insi_addr_tag_bits. I think we could leave the watchpoint exception on arm64 as "weird for historical reasons" and insist that any future architectures adopting tagged addresses handle the tag bits uniformly.
Ack -- I guess I don't have a strong opinion either.
There's a risk of inventing problems here in order to solve them, so I agree we should keep things as simple and follow your current design.
Cheers
---Dave