arm64: expose FAR_EL1 tag bits in siginfo
Subsystems (14)
v10 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, especially since userspace would have no way to detect that they are present and valid. Therefore, the first five 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
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 | 17 +++ 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 | 59 +++++----- 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 | 22 +--- 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 | 11 +- arch/xtensa/include/uapi/asm/signal.h | 24 ---- include/linux/compat.h | 4 + include/linux/signal.h | 21 ++++ include/linux/signal_types.h | 12 ++ include/uapi/asm-generic/siginfo.h | 14 +++ include/uapi/asm-generic/signal-defs.h | 64 ++++++++++ include/uapi/asm-generic/signal.h | 29 ----- include/uapi/linux/ptrace.h | 2 + kernel/ptrace.c | 29 +++++ kernel/signal.c | 130 +++++++++++---------- 36 files changed, 315 insertions(+), 409 deletions(-) create mode 100644 arch/arm64/include/asm/signal.h
Signature · 1 line
2.28.0.297.g1956fa8f8d-goog
PATCH v10 1/7 parisc: start using signal-defs.h
We 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.
---
View this change in Gerrit: https://linux-review.googlesource.com/q/If03a5135fb514fe96548fb74610e6c3586a04064
arch/parisc/include/uapi/asm/signal.h | 9 +-------- include/uapi/asm-generic/signal-defs.h | 6 ++++++ 2 files changed, 7 insertions(+), 8 deletions(-)
arch/parisc/include/uapi/asm/signal.h +1 -8
@@ -69,14 +69,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/signal-defs.h> # ifndef __ASSEMBLY__
include/uapi/asm-generic/signal-defs.h +6 -0
@@ -15,8 +15,14 @@#endif #ifndef __ASSEMBLY__ +#ifndef __hppa__ +/* +* These have a special definition on parisc, see: +* arch/parisc/include/uapi/asm/signal.h +*/ typedef void __signalfn_t (int );typedef __signalfn_t __user *__sighandler_t ; +#endif typedef void __restorefn_t (void );typedef __restorefn_t __user *__sigrestore_t ;
Signature · 1 line
2.28.0.297.g1956fa8f8d-goog
Re: [PATCH v10 1/7] parisc: start using signal-defs.h
Quoted 3 lines · Peter Collingbourne
We currently include
signal-defs.hon all architectures except parisc. Make parisc fall in line. This will make maintenance easier once the flag bits are moved here.
The patch is basically OK, but....
Quoted 34 lines
Signed-off-by Peter Collingbourne <[email protected]>---
View this change in Gerrit: https://linux-review.googlesource.com/q/If03a5135fb514fe96548fb74610e6c3586a04064arch/parisc/include/uapi/asm/signal.h | 9 +-------- include/uapi/asm-generic/signal-defs.h | 6 ++++++ 2 files changed, 7 insertions(+), 8 deletions(-)arch/parisc/include/uapi/asm/signal.h +1
-8@@ -69,14 +69,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/signal-defs.h> # ifndef __ASSEMBLY__include/uapi/asm-generic/signal-defs.h +0
-0@@ -15,8 +15,14 @@#endif
include/uapi/asm-generic/signal-defs.h line 25
Quoted 10 lines
include/uapi/asm-generic/signal-defs.h +5
-0#ifndef __ASSEMBLY__ +#ifndef __hppa__ +/* +* These have a special definition on parisc, see: +* arch/parisc/include/uapi/asm/signal.h +*/ typedef void __signalfn_t (int );typedef __signalfn_t __user *__sighandler_t ;
please drop this special-case/#ifdef for hppa/parisc.
Instead please drop the typedef in arch/parisc/include/uapi/asm/signal.h, same as you did for the other architectures.
I've committed this patch to my tree, which will collide with yours:
https://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux.git/commit/?h=for-next
If you like I can drop mine, and you fix it up on your side. Just let me know.
Other than that you can add:
Thanks!
Helge
Quoted 5 lines
include/uapi/asm-generic/signal-defs.h +1
-0+#endif typedef void __restorefn_t (void );typedef
__restorefn_t__user*__sigrestore_t;
Re: [PATCH v10 1/7] parisc: start using signal-defs.h
Quoted 62 lines · Helge Deller
Quoted 3 lines · Peter Collingbourne
We currently include
signal-defs.hon all architectures except parisc. Make parisc fall in line. This will make maintenance easier once the flag bits are moved here.The patch is basically OK, but....
Quoted 34 lines
Signed-off-by Peter Collingbourne <[email protected]>---
View this change in Gerrit: https://linux-review.googlesource.com/q/If03a5135fb514fe96548fb74610e6c3586a04064arch/parisc/include/uapi/asm/signal.h | 9 +-------- include/uapi/asm-generic/signal-defs.h | 6 ++++++ 2 files changed, 7 insertions(+), 8 deletions(-)arch/parisc/include/uapi/asm/signal.h +1
-8@@ -69,14 +69,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/signal-defs.h> # ifndef __ASSEMBLY__include/uapi/asm-generic/signal-defs.h +0
-0@@ -15,8 +15,14 @@#endif include/uapi/asm-generic/signal-defs.h line 25
Quoted 10 lines
include/uapi/asm-generic/signal-defs.h +5
-0#ifndef __ASSEMBLY__ +#ifndef __hppa__ +/* +* These have a special definition on parisc, see: +* arch/parisc/include/uapi/asm/signal.h +*/ typedef void __signalfn_t (int );typedef __signalfn_t __user *__sighandler_t ;please drop this special-case/#ifdef for hppa/parisc.
Instead please drop the typedef inarch/parisc/include/uapi/asm/signal.h, same as you did for the other architectures.I've committed this patch to my tree, which will collide with yours:
https://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux.git/commit/?h=for-next
If you like I can drop mine, and you fix it up on your side. Just let me know.
Quoted 4 lines
Other than that you can add:
Acked-by Helge Deller <[email protected]>Thanks!
Thanks for the review and apologies for the delay in getting back to you. I've picked up your patch from your for-next branch into my series before this change, and removed the special case for hppa. I also build tested my series on hppa which revealed a typo in the #include directive which I fixed. The new patch looks like this and it will be included in v11 which I will try to send out soon.
(quoted diff) +0 -0
b/arch/parisc/include/uapi/asm/signal.h
index f1fd4fa880d7..e67b1bfb82ba 100644
arch/parisc/include/uapi/asm/signal.h +1 -12
@@ -69,14 +69,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__
@@ -85,10 +78,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;
Peter
Helge Deller
maintainerRe: [PATCH v10 1/7] parisc: start using signal-defs.h
Quoted 66 lines · Peter Collingbourne
Quoted 65 lines · Helge Deller
Quoted 3 lines · Peter Collingbourne
We currently include
signal-defs.hon all architectures except parisc. Make parisc fall in line. This will make maintenance easier once the flag bits are moved here.The patch is basically OK, but....
Quoted 34 lines
Signed-off-by Peter Collingbourne <[email protected]>---
View this change in Gerrit: https://linux-review.googlesource.com/q/If03a5135fb514fe96548fb74610e6c3586a04064arch/parisc/include/uapi/asm/signal.h | 9 +-------- include/uapi/asm-generic/signal-defs.h | 6 ++++++ 2 files changed, 7 insertions(+), 8 deletions(-)arch/parisc/include/uapi/asm/signal.h +1
-8@@ -69,14 +69,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/signal-defs.h> # ifndef __ASSEMBLY__include/uapi/asm-generic/signal-defs.h +0
-0@@ -15,8 +15,14 @@#endif include/uapi/asm-generic/signal-defs.h line 25
Quoted 10 lines
include/uapi/asm-generic/signal-defs.h +5
-0#ifndef __ASSEMBLY__ +#ifndef __hppa__ +/* +* These have a special definition on parisc, see: +* arch/parisc/include/uapi/asm/signal.h +*/ typedef void __signalfn_t (int );typedef __signalfn_t __user *__sighandler_t ;please drop this special-case/#ifdef for hppa/parisc.
Instead please drop the typedef inarch/parisc/include/uapi/asm/signal.h, same as you did for the other architectures.I've committed this patch to my tree, which will collide with yours:
https://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux.git/commit/?h=for-next
If you like I can drop mine, and you fix it up on your side. Just let me know.Other than that you can add:
Acked-by Helge Deller <[email protected]>
Quoted 8 lines
Quoted 1 line
Thanks!
Thanks for the review and apologies for the delay in getting back to you. I've picked up your patch from your for-next branch into my series before this change, and removed the special case for hppa. I also build tested my series on hppa which revealed a typo in the #include directive which I fixed. The new patch looks like this and it will be included in v11 which I will try to send out soon.
Thanks!
Ok, I've now dropped my patch from my for-next series.
Helge
Quoted 35 lines
arch/parisc/include/uapi/asm/signal.h +1
-12@@ -69,14 +69,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__@@ -85,10 +78,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;Peter
Re: [PATCH v10 1/7] parisc: start using signal-defs.h
In reply to Peter CollingbourneQuoted 38 lines · Peter Collingbourne
We currently include
signal-defs.hon all architectures except parisc. Make parisc fall in line. This will make maintenance easier once the flag bits are moved here.Signed-off-by Peter Collingbourne <[email protected]>---
View this change in Gerrit: https://linux-review.googlesource.com/q/If03a5135fb514fe96548fb74610e6c3586a04064arch/parisc/include/uapi/asm/signal.h | 9 +-------- include/uapi/asm-generic/signal-defs.h | 6 ++++++ 2 files changed, 7 insertions(+), 8 deletions(-)arch/parisc/include/uapi/asm/signal.h +1
-8@@ -69,14 +69,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/signal-defs.h> # ifndef __ASSEMBLY__include/uapi/asm-generic/signal-defs.h +0
-0@@ -15,8 +15,14 @@#endif
include/uapi/asm-generic/signal-defs.h line 25
Quoted 10 lines
include/uapi/asm-generic/signal-defs.h +6
-0#ifndef __ASSEMBLY__ +#ifndef __hppa__ +/* +* These have a special definition on parisc, see: +* arch/parisc/include/uapi/asm/signal.h +*/ typedef void __signalfn_t (int );typedef __signalfn_t __user *__sighandler_t ; +#endif
Could we do something like
#ifndef __sighandler_t /* ... */ #define __sighandler_t __sighandler_t #endif
Then we don't have to have anything parisc-specific in the common header, and arches can override this definition independently.
Not a big deal either way, though, and best to keep the comment about why this is here in any case.
Cheers
---Dave
_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
PATCH v10 2/7 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.
---
View this change in Gerrit: https://linux-review.googlesource.com/q/Ia3849f18b8009bf41faca374e701cdca36974528
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/* it's 44 under HP/UX */ -/* -* 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 · 1 line
2.28.0.297.g1956fa8f8d-goog
Re: [PATCH v10 2/7] arch: move SA_* definitions to generic headers
Quoted 7 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.Signed-off-by Peter Collingbourne <[email protected]>
While this looks reasonable, I've just realised that you strip the "U" from some arches' definitions here.
So, on powerpc and x86, this changes the type of flags other than SA_RESETHAND from unsigned int to int.
While I can't see this breaking any sensible use of these flags, there's a chance that there is software relying on this distinction by accident.
I wonder whether it's worth doing something like
#ifdef ARCH_WANT_STRICTLY_UNSIGNED_SA_FLAGS #define __SA_FLAG_VAL(x) x ## U #else #define __SA_FLAG_VAL(x) x #endif #ifndef SA_NOCLDSTOP #define SA_NOCLDSTOP __SA_FLAG_VAL(0x00000001) #endif /* ... */
Mind you, the historical situation also has issues, e.g. because sa_flags in struct sigaction is an int, assigning
struct sigaction sa; sa.sa_flags = SA_RESETHAND;
implies an overflow and so isn't portably safe (at least in theory). I guess we are getting away with it today. Preserving the situation by keeping the "U"s where appropriate would at least avoid making the situation worse.
[...]
Cheers
---Dave
_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Re: [PATCH v10 2/7] arch: move SA_* definitions to generic headers
Quoted 13 lines · Dave Martin
Quoted 7 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.Signed-off-by Peter Collingbourne <[email protected]>While this looks reasonable, I've just realised that you strip the "U" from some arches' definitions here.
Quoted 6 lines
So, on powerpc and x86, this changes the type of flags other than
SA_RESETHANDfrom unsigned int to int.While I can't see this breaking any sensible use of these flags, there's a chance that there is software relying on this distinction by accident.
While it's true that it's technically possible that making these signed could change semantics, I'm having trouble seeing a realistic way in which software could be relying on this. Can you see one? I can think of cases like if the code does something like left shifts one of the flag bits into the sign bit (technically undefined behavior) and then right shifts it back (in C this would need to all be done in a single expression without storing to a variable; in C++ I suppose you could use auto to preserve the signedness in a variable's type). For example:
int x = (SA_NODEFER << 1) >> 1;
would give a different value to x if we made SA_NODEFER signed. But I wouldn't really expect software to be doing this sort of thing even accidentally, or much more than or'ing the flags together and assigning them to a variable, or passing them as a parameter, or some other operation which would fix the type.
I believe that the kernel's uapi guarantee applies at the binary level, not at the source level. If that were not the case, I think we would not be allowed to add any new declaration to an existing .h file for fear of conflicting with a user program's identically spelled declaration. And that seems more likely to me than software that would do this sort of thing.
Quoted 13 lines
I wonder whether it's worth doing something like
#ifdef ARCH_WANT_STRICTLY_UNSIGNED_SA_FLAGS #define __SA_FLAG_VAL(x) x ## U #else #define __SA_FLAG_VAL(x) x #endif #ifndef SA_NOCLDSTOP #define SA_NOCLDSTOP __SA_FLAG_VAL(0x00000001) #endif /* ... */
If we do this I would mildly prefer to keep the existing #defines in the arch-specific headers as if the arch had different flag values, as this would leave the arch-specific legacy cruft in the arch-specific headers where it belongs.
Quoted 11 lines
Mind you, the historical situation also has issues, e.g. because
sa_flagsin struct sigaction is an int, assigningstruct sigaction sa; sa.sa_flags = SA_RESETHAND;implies an overflow and so isn't portably safe (at least in theory). I guess we are getting away with it today. Preserving the situation by keeping the "U"s where appropriate would at least avoid making the situation worse.
I believe that the result of this assignment (involving an unsigned to signed conversion) is implementation defined and not undefined (which would be problematic). And in all the implementations that matter, as well as the C++ standard starting with C++20, this is a no-op cast assuming two's complement. I'm not sure what this has to do with making the constants signed because, as you pointed out, SA_RESETHAND would remain unsigned despite the absence of 'U' because its value does not fit in an int.
Peter
Re: [PATCH v10 2/7] arch: move SA_* definitions to generic headers
Quoted 31 lines · Peter Collingbourne
Quoted 13 lines · Dave Martin
Quoted 7 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.Signed-off-by Peter Collingbourne <[email protected]>While this looks reasonable, I've just realised that you strip the "U" from some arches' definitions here.
Quoted 6 lines
So, on powerpc and x86, this changes the type of flags other than
SA_RESETHANDfrom unsigned int to int.While I can't see this breaking any sensible use of these flags, there's a chance that there is software relying on this distinction by accident.
While it's true that it's technically possible that making these signed could change semantics, I'm having trouble seeing a realistic way in which software could be relying on this. Can you see one? I can think of cases like if the code does something like left shifts one of the flag bits into the sign bit (technically undefined behavior) and then right shifts it back (in C this would need to all be done in a single expression without storing to a variable; in C++ I suppose you could use auto to preserve the signedness in a variable's type). For example:
Quoted 7 lines
int x = (
SA_NODEFER<< 1) >> 1;would give a different value to x if we made
SA_NODEFERsigned. But I wouldn't really expect software to be doing this sort of thing even accidentally, or much more than or'ing the flags together and assigning them to a variable, or passing them as a parameter, or some other operation which would fix the type.
I couldn't come up with a very good, non-contrived example I admit.
Quoted 6 lines
I believe that the kernel's uapi guarantee applies at the binary level, not at the source level. If that were not the case, I think we would not be allowed to add any new declaration to an existing .h file for fear of conflicting with a user program's identically spelled declaration. And that seems more likely to me than software that would do this sort of thing.
The behaviour of source code making legitimate use of the kernel headers still shouldn't be changed without good reason, especially if the change could lead to subtle bugs that the compiler won't detect.
However this doesn't mean that decrufting unintentional inconsistencies in the headers is a bad idea ... and see my response below.
Quoted 31 lines
Quoted 13 lines
I wonder whether it's worth doing something like
#ifdef ARCH_WANT_STRICTLY_UNSIGNED_SA_FLAGS #define __SA_FLAG_VAL(x) x ## U #else #define __SA_FLAG_VAL(x) x #endif #ifndef SA_NOCLDSTOP #define SA_NOCLDSTOP __SA_FLAG_VAL(0x00000001) #endif /* ... */If we do this I would mildly prefer to keep the existing #defines in the arch-specific headers as if the arch had different flag values, as this would leave the arch-specific legacy cruft in the arch-specific headers where it belongs.
Quoted 11 lines
Mind you, the historical situation also has issues, e.g. because
sa_flagsin struct sigaction is an int, assigningstruct sigaction sa; sa.sa_flags = SA_RESETHAND;implies an overflow and so isn't portably safe (at least in theory). I guess we are getting away with it today. Preserving the situation by keeping the "U"s where appropriate would at least avoid making the situation worse.
Quoted 8 lines
I believe that the result of this assignment (involving an unsigned to signed conversion) is implementation defined and not undefined (which would be problematic). And in all the implementations that matter, as well as the C++ standard starting with C++20, this is a no-op cast assuming two's complement. I'm not sure what this has to do with making the constants signed because, as you pointed out,
SA_RESETHANDwould remain unsigned despite the absence of 'U' because its value does not fit in an int.
I generally agree with your analysis here, and yes, the de facto langue does define the behaviour for signed integer overflow in practice, even if the C standards demur on this issue.
I actually got my argument a little backwards: the problem here is not that SA_RESETHAND unexpectedly becomes a (negative) int, but that the other values become ints: but those nonetheless remain positive because they aren't big enough to alias the sign bit.
So the main way for things to go wrong seems to be if the values are shifted up, as you observe. But (a) that is a strange thing to do, and
(b) there is an obvious need for a cast if doing things like:
#define ENCODE_SIGNAL(int sig, int flags) ((u64)(flags) << 8 | (sig))
Code lacking the cast would already be wrong, since SA_RESETHAND etc. would simply get shifted off.
I think it's worth drawing attention to the issue in the commit message, but if nobody else objects then I guess I am not too concerned about the change.
Cheers
---Dave
PATCH v10 3/7 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.
---
View this change in Gerrit: https://linux-review.googlesource.com/q/I35aab6f5be932505d90f3b3450c083b4db1eca86
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 · 1 line
2.28.0.297.g1956fa8f8d-goog
Re: [PATCH v10 3/7] signal: clear non-uapi flag bits when passing/returning sa_flags
Quoted 100 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.
Link [5] https://github.com/NetBSD/src/blob/3365779becdcedfca206091a645a0e8e22b2946e/sys/kern/sys_sig.c#L473Signed-off-by Peter Collingbourne <[email protected]>---
View this change in Gerrit: https://linux-review.googlesource.com/q/I35aab6f5be932505d90f3b3450c083b4db1eca86v10:
- 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 +2
-0@@ -68,4 +68,16 @@ struct ksignal {int sig; }; +#ifndef __ARCH_UAPI_SA_FLAGS +#ifdef SA_RESTORER
include/linux/signal_types.h struct ksignal { · line 82
Quoted 10 lines
include/linux/signal_types.h +10
-0+#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) +
Part of me wants this to be closer to the common flag definitions. But we don't really want to define this in the UAPI headers.
Unless you can think of another good place to put it, this is probably OK as-is.
Quoted 9 lines
include/linux/signal_types.h +0
-0#endif /* _LINUX_SIGNAL_TYPES_H */ kernel/signal.c +0
-0@@ -3984,6 +3984,16 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)if (oact) *oact = *k;
kernel/signal.c int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact) · line 3996
Quoted 10 lines
kernel/signal.c +10
-0+/* +* 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 ; +
Seems reasonable.
[...]
Cheers
---Dave
_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Re: [PATCH v10 3/7] signal: clear non-uapi flag bits when passing/returning sa_flags
Quoted 100 lines · Dave Martin
Quoted 98 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.
Link [5] https://github.com/NetBSD/src/blob/3365779becdcedfca206091a645a0e8e22b2946e/sys/kern/sys_sig.c#L473Signed-off-by Peter Collingbourne <[email protected]>---
View this change in Gerrit: https://linux-review.googlesource.com/q/I35aab6f5be932505d90f3b3450c083b4db1eca86v10:
- 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 +0
-0@@ -68,4 +68,16 @@ struct ksignal {int sig; };
Quoted 15 lines
include/linux/signal_types.h struct ksignal { · line 82
Quoted 12 lines
include/linux/signal_types.h +12
-0+#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) +Part of me wants this to be closer to the common flag definitions. But we don't really want to define this in the UAPI headers.
Agreed on keeping this out of uapi, otherwise I would have defined this inline.
Quoted 2 lines
Unless you can think of another good place to put it, this is probably OK as-is.
Ack.
Peter
PATCH v10 4/7 signal: define the SA_UNSUPPORTED bit in sa_flags
In reply to Peter CollingbourneThis bit 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 finds that this bit 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.
---
View this change in Gerrit: https://linux-review.googlesource.com/q/Ic2501ad150a3a79c1cf27fb8c99be342e9dffbcb
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 · 1 line
2.28.0.297.g1956fa8f8d-goog
Re: [PATCH v10 4/7] signal: define the SA_UNSUPPORTED bit in sa_flags
On Fri, Aug 21, 2020 at 10:10:14PM -0700, Peter Collingbourne wrote:
Nit: no statement of the chage being made (other than in the subject line).
Quoted 8 lines
This bit 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_flagsbits from a kernel that supports every flag bit.In other words, if userspace finds that this bit 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.
This isn't quite right? After a single sigaction() call, oact will contain the sa_flags for the previously registered handler. So a second sigaction() call would be needed to find out the newly effective sa_flags.
Quoted 27 lines
Signed-off-by Peter Collingbourne <[email protected]>---
View this change in Gerrit: https://linux-review.googlesource.com/q/Ic2501ad150a3a79c1cf27fb8c99be342e9dffbcbinclude/uapi/asm-generic/signal-defs.h | 7 +++++++ kernel/signal.c | 6 ++++++ 2 files changed, 13 insertions(+)include/uapi/asm-generic/signal-defs.h +6
-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.
include/uapi/asm-generic/signal-defs.h line 51
Quoted 4 lines
include/uapi/asm-generic/signal-defs.h +1
-0@@ -42,6 +48,7 @@#ifndef SA_RESETHAND #define SA_RESETHAND 0x80000000#endif +#define SA_UNSUPPORTED 0x00000400
I guess people may debate which bit is chosen, but your consolidation of these definitions should help to reduce the possibility of future collisions. This bit appears unused for now, so I guess I don't have a strong opinion.
Quoted 7 lines
include/uapi/asm-generic/signal-defs.h +0
-0#define SA_NOMASK SA_NODEFER#define SA_ONESHOT SA_RESETHANDkernel/signal.c +0
-0
kernel/signal.c int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact) · line 3992
Quoted 9 lines
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 ); +
Seems reasonable.
With the above rewording in the commit message to clarify that a second sigaction() is needed:
[...]
Cheers
---Dave
_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Re: [PATCH v10 4/7] signal: define the SA_UNSUPPORTED bit in sa_flags
Quoted 5 lines · Dave Martin
On Fri, Aug 21, 2020 at 10:10:14PM -0700, Peter Collingbourne wrote:
Nit: no statement of the chage being made (other than in the subject line).
Will fix.
Quoted 9 lines
Quoted 8 lines
This bit 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_flagsbits from a kernel that supports every flag bit.In other words, if userspace finds that this bit 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.
Quoted 4 lines
This isn't quite right? After a single
sigaction()call, oact will contain thesa_flagsfor the previously registered handler. So a secondsigaction()call would be needed to find out the newly effectivesa_flags.
You're right, this is unclear to say the least. In v11 I will reword like so:
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.
Quoted 56 lines
Quoted 27 lines
Signed-off-by Peter Collingbourne <[email protected]>---
View this change in Gerrit: https://linux-review.googlesource.com/q/Ic2501ad150a3a79c1cf27fb8c99be342e9dffbcbinclude/uapi/asm-generic/signal-defs.h | 7 +++++++ kernel/signal.c | 6 ++++++ 2 files changed, 13 insertions(+)include/uapi/asm-generic/signal-defs.h +6
-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. include/uapi/asm-generic/signal-defs.h line 51
Quoted 4 lines
include/uapi/asm-generic/signal-defs.h +1
-0@@ -42,6 +48,7 @@#ifndef SA_RESETHAND #define SA_RESETHAND 0x80000000#endif +#define SA_UNSUPPORTED 0x00000400I guess people may debate which bit is chosen, but your consolidation of these definitions should help to reduce the possibility of future collisions. This bit appears unused for now, so I guess I don't have a strong opinion.
Quoted 7 lines
include/uapi/asm-generic/signal-defs.h +0
-0#define SA_NOMASK SA_NODEFER#define SA_ONESHOT SA_RESETHANDkernel/signal.c +0
-0kernel/signal.c int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact) · line 3992
Quoted 9 lines
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 ); +Seems reasonable.
Quoted 4 lines
With the above rewording in the commit message to clarify that a second
sigaction()is needed:Reviewed-by Dave Martin <[email protected]>
Thanks for the review.
Peter
Re: [PATCH v10 4/7] signal: define the SA_UNSUPPORTED bit in sa_flags
Quoted 27 lines · Peter Collingbourne
Quoted 5 lines · Dave Martin
On Fri, Aug 21, 2020 at 10:10:14PM -0700, Peter Collingbourne wrote:
Nit: no statement of the chage being made (other than in the subject line).
Will fix.
Quoted 9 lines
Quoted 8 lines
This bit 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_flagsbits from a kernel that supports every flag bit.In other words, if userspace finds that this bit 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.Quoted 4 lines
This isn't quite right? After a single
sigaction()call, oact will contain thesa_flagsfor the previously registered handler. So a secondsigaction()call would be needed to find out the newly effectivesa_flags.You're right, this is unclear to say the least. In v11 I will reword like so:
In other words, if userspace does something like:
Quoted 7 lines
act.sa_flags |=
SA_UNSUPPORTED;
sigaction(SIGSEGV, &act, 0);
sigaction(SIGSEGV, 0, &oldact);and finds that
SA_UNSUPPORTEDremains set in oldact.sa_flags, it means that the kernel cannot be trusted to have cleared unknown flag bits fromsa_flags, so no assumptions about flag bit support can be made.
Seems reasonable. We'd need to make sure we're clear about which flags this applies for, though. The pre-existing flags can be assumed to be supported irrespective of whether SA_UNSUPPORTED remains set.
Cheers
---Dave
_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
PATCH v10 5/7 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.
---
View this change in Gerrit: https://linux-review.googlesource.com/q/I4f56174e1b7b2bf4a3c8139e6879cbfd52750a24
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 · 1 line
2.28.0.297.g1956fa8f8d-goog
Re: [PATCH v10 5/7] signal: deduplicate code dealing with common _sigfault fields
Quoted 154 lines · Peter Collingbourne
We're about to add more common
_sigfaultfields, so deduplicate the existing code for initializing_sigfaultfields in {send,force}_sig_*, and for copying_sigfaultfields incopy_siginfo_to_external32andpost_copy_siginfo_from_user32, to reduce the number of places that will need to be updated by upcoming changes.Signed-off-by Peter Collingbourne <[email protected]>---
View this change in Gerrit: https://linux-review.googlesource.com/q/I4f56174e1b7b2bf4a3c8139e6879cbfd52750a24include/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 +19
-27@@ -1649,6 +1649,15 @@ void force_sigsegv(int sig)force_sig (SIGSEGV ); } +static void set_sigfault_common_fields (struct kernel_siginfo *info,int sig, +int code,void __user *addr) +{ + info->si_signo = sig; + info->si_errno =0 ; + info->si_code = code; + info->si_addr = addr; +} + int force_sig_fault_to_task(int sig, int code, void __user *addr___ARCH_SI_TRAPNO (int trapno) ___ARCH_SI_IA64(int imm, unsigned int flags, unsigned long isr)@@ -1657,10 +1666,7 @@ int force_sig_fault_to_task(int sig, int code, void __user *addrstruct kernel_siginfo info;clear_siginfo (&info); - info.si_signo = sig; - info.si_errno =0 ; - info.si_code = code; - info.si_addr = addr; +set_sigfault_common_fields (&info, sig, code, addr);#ifdef __ARCH_SI_TRAPNO info.si_trapno = trapno;#endif @@ -1689,10 +1695,7 @@ int send_sig_fault(int sig, int code, void __user *addrstruct kernel_siginfo info;clear_siginfo (&info); - info.si_signo = sig; - info.si_errno =0 ; - info.si_code = code; - info.si_addr = addr; +set_sigfault_common_fields (&info, sig, code, addr);#ifdef __ARCH_SI_TRAPNO info.si_trapno = trapno;#endif @@ -1710,10 +1713,7 @@ int force_sig_mceerr(int code, void __user *addr, short lsb)WARN_ON ((code !=BUS_MCEERR_AO ) && (code !=BUS_MCEERR_AR ));clear_siginfo (&info); - info.si_signo =SIGBUS ; - info.si_errno =0 ; - info.si_code = code; - info.si_addr = addr; +set_sigfault_common_fields (&info,SIGBUS , code, addr); info.si_addr_lsb = lsb;return force_sig_info (&info); }@@ -1724,10 +1724,7 @@ int send_sig_mceerr(int code, void __user *addr, short lsb, struct task_struct *WARN_ON ((code !=BUS_MCEERR_AO ) && (code !=BUS_MCEERR_AR ));clear_siginfo (&info); - info.si_signo =SIGBUS ; - info.si_errno =0 ; - info.si_code = code; - info.si_addr = addr; +set_sigfault_common_fields (&info,SIGBUS , code, addr); info.si_addr_lsb = lsb;return send_sig_info (info.si_signo, &info, t); }@@ -1738,10 +1735,7 @@ int force_sig_bnderr(void __user *addr, void __user *lower, void __user *upper)struct kernel_siginfo info;clear_siginfo (&info); - info.si_signo =SIGSEGV ; - info.si_errno =0 ; - info.si_code =SEGV_BNDERR ; - info.si_addr = addr; +set_sigfault_common_fields (&info,SIGSEGV ,SEGV_BNDERR , addr); info.si_lower = lower; info.si_upper = upper;return force_sig_info (&info);@@ -1753,10 +1747,7 @@ int force_sig_pkuerr(void __user *addr, u32 pkey)struct kernel_siginfo info;clear_siginfo (&info); - info.si_signo =SIGSEGV ; - info.si_errno =0 ; - info.si_code =SEGV_PKUERR ; - info.si_addr = addr; +set_sigfault_common_fields (&info,SIGSEGV ,SEGV_PKUERR , addr); info.si_pkey = pkey;return force_sig_info (&info); }@@ -1770,10 +1761,8 @@ int force_sig_ptrace_errno_trap(int errno, void __user *addr)struct kernel_siginfo info;clear_siginfo (&info); - info.si_signo =SIGTRAP ; +set_sigfault_common_fields (&info,SIGTRAP ,TRAP_HWBKPT , addr); info.si_errno = errno; - info.si_code =TRAP_HWBKPT ; - info.si_addr = addr;return force_sig_info (&info); }@@ -3266,12 +3255,23 @@ int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from)void copy_siginfo_to_external32 (struct compat_siginfo *to,const struct kernel_siginfo *from) { +enum siginfo_layout layout = +siginfo_layout (from->si_signo, from->si_code); +memset (to,0 ,sizeof (*to)); to->si_signo = from->si_signo; to->si_errno = from->si_errno; to->si_code = from->si_code;
kernel/signal.c int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from) · line 3274
Quoted 10 lines
kernel/signal.c +9
-1-switch (siginfo_layout (from->si_signo, from->si_code)) { + +if (siginfo_layout_is_fault (layout)) { + to->si_addr =ptr_to_compat (from->si_addr); +#ifdef __ARCH_SI_TRAPNO + to->si_trapno = from->si_trapno; +#endif + } + +switch (layout) {
I find the code flow slightly awkward with this change, because the fault signal fields are populated partly in the if() above and partly in the switch(). Previously, only the universal stuff was done outside.
Would this be easier on future maintainers if we pulled the common stuff out into a helper and then called it from the appropriate switch cases? The compiler will probably output some duplicated code in that case (depending on how clever it is at undoing the duplication), but the amount of affected code is small.
Quoted 46 lines
kernel/signal.c +3
-16case SIL_KILL : to->si_pid = from->si_pid; to->si_uid = from->si_uid;@@ -3286,31 +3286,15 @@ void copy_siginfo_to_external32(struct compat_siginfo *to, to->si_fd = from->si_fd;break ;case SIL_FAULT : - to->si_addr =ptr_to_compat (from->si_addr); -#ifdef __ARCH_SI_TRAPNO - to->si_trapno = from->si_trapno; -#endif break ;case SIL_FAULT_MCEERR : - to->si_addr =ptr_to_compat (from->si_addr); -#ifdef __ARCH_SI_TRAPNO - to->si_trapno = from->si_trapno; -#endif to->si_addr_lsb = from->si_addr_lsb;break ;case SIL_FAULT_BNDERR : - to->si_addr =ptr_to_compat (from->si_addr); -#ifdef __ARCH_SI_TRAPNO - to->si_trapno = from->si_trapno; -#endif to->si_lower =ptr_to_compat (from->si_lower); to->si_upper =ptr_to_compat (from->si_upper);break ;case SIL_FAULT_PKUERR : - to->si_addr =ptr_to_compat (from->si_addr); -#ifdef __ARCH_SI_TRAPNO - to->si_trapno = from->si_trapno; -#endif to->si_pkey = from->si_pkey;break ;case SIL_CHLD :@@ -3347,11 +3331,22 @@ int __copy_siginfo_to_user32(struct compat_siginfo __user *to,static int post_copy_siginfo_from_user32 (kernel_siginfo_t *to,const struct compat_siginfo *from) { +enum siginfo_layout layout = +siginfo_layout (from->si_signo, from->si_code); +clear_siginfo (to); to->si_signo = from->si_signo; to->si_errno = from->si_errno; to->si_code = from->si_code;
kernel/signal.c int __copy_siginfo_to_user32(struct compat_siginfo __user *to, · line 3349
Quoted 10 lines
kernel/signal.c +9
-1-switch (siginfo_layout (from->si_signo, from->si_code)) { + +if (siginfo_layout_is_fault (layout)) { + to->si_addr =compat_ptr (from->si_addr); +#ifdef __ARCH_SI_TRAPNO + to->si_trapno = from->si_trapno; +#endif + } + +switch (layout) {
Same comment as for copy_siginfo_to_external32()?
[...]
Otherwise, looks reasonable.
Cheers
---Dave
_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Re: [PATCH v10 5/7] signal: deduplicate code dealing with common _sigfault fields
Quoted 171 lines · Dave Martin
Quoted 154 lines · Peter Collingbourne
We're about to add more common
_sigfaultfields, so deduplicate the existing code for initializing_sigfaultfields in {send,force}_sig_*, and for copying_sigfaultfields incopy_siginfo_to_external32andpost_copy_siginfo_from_user32, to reduce the number of places that will need to be updated by upcoming changes.Signed-off-by Peter Collingbourne <[email protected]>---
View this change in Gerrit: https://linux-review.googlesource.com/q/I4f56174e1b7b2bf4a3c8139e6879cbfd52750a24include/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 +19
-27@@ -1649,6 +1649,15 @@ void force_sigsegv(int sig)force_sig (SIGSEGV ); } +static void set_sigfault_common_fields (struct kernel_siginfo *info,int sig, +int code,void __user *addr) +{ + info->si_signo = sig; + info->si_errno =0 ; + info->si_code = code; + info->si_addr = addr; +} + int force_sig_fault_to_task(int sig, int code, void __user *addr___ARCH_SI_TRAPNO (int trapno) ___ARCH_SI_IA64(int imm, unsigned int flags, unsigned long isr)@@ -1657,10 +1666,7 @@ int force_sig_fault_to_task(int sig, int code, void __user *addrstruct kernel_siginfo info;clear_siginfo (&info); - info.si_signo = sig; - info.si_errno =0 ; - info.si_code = code; - info.si_addr = addr; +set_sigfault_common_fields (&info, sig, code, addr);#ifdef __ARCH_SI_TRAPNO info.si_trapno = trapno;#endif @@ -1689,10 +1695,7 @@ int send_sig_fault(int sig, int code, void __user *addrstruct kernel_siginfo info;clear_siginfo (&info); - info.si_signo = sig; - info.si_errno =0 ; - info.si_code = code; - info.si_addr = addr; +set_sigfault_common_fields (&info, sig, code, addr);#ifdef __ARCH_SI_TRAPNO info.si_trapno = trapno;#endif @@ -1710,10 +1713,7 @@ int force_sig_mceerr(int code, void __user *addr, short lsb)WARN_ON ((code !=BUS_MCEERR_AO ) && (code !=BUS_MCEERR_AR ));clear_siginfo (&info); - info.si_signo =SIGBUS ; - info.si_errno =0 ; - info.si_code = code; - info.si_addr = addr; +set_sigfault_common_fields (&info,SIGBUS , code, addr); info.si_addr_lsb = lsb;return force_sig_info (&info); }@@ -1724,10 +1724,7 @@ int send_sig_mceerr(int code, void __user *addr, short lsb, struct task_struct *WARN_ON ((code !=BUS_MCEERR_AO ) && (code !=BUS_MCEERR_AR ));clear_siginfo (&info); - info.si_signo =SIGBUS ; - info.si_errno =0 ; - info.si_code = code; - info.si_addr = addr; +set_sigfault_common_fields (&info,SIGBUS , code, addr); info.si_addr_lsb = lsb;return send_sig_info (info.si_signo, &info, t); }@@ -1738,10 +1735,7 @@ int force_sig_bnderr(void __user *addr, void __user *lower, void __user *upper)struct kernel_siginfo info;clear_siginfo (&info); - info.si_signo =SIGSEGV ; - info.si_errno =0 ; - info.si_code =SEGV_BNDERR ; - info.si_addr = addr; +set_sigfault_common_fields (&info,SIGSEGV ,SEGV_BNDERR , addr); info.si_lower = lower; info.si_upper = upper;return force_sig_info (&info);@@ -1753,10 +1747,7 @@ int force_sig_pkuerr(void __user *addr, u32 pkey)struct kernel_siginfo info;clear_siginfo (&info); - info.si_signo =SIGSEGV ; - info.si_errno =0 ; - info.si_code =SEGV_PKUERR ; - info.si_addr = addr; +set_sigfault_common_fields (&info,SIGSEGV ,SEGV_PKUERR , addr); info.si_pkey = pkey;return force_sig_info (&info); }@@ -1770,10 +1761,8 @@ int force_sig_ptrace_errno_trap(int errno, void __user *addr)struct kernel_siginfo info;clear_siginfo (&info); - info.si_signo =SIGTRAP ; +set_sigfault_common_fields (&info,SIGTRAP ,TRAP_HWBKPT , addr); info.si_errno = errno; - info.si_code =TRAP_HWBKPT ; - info.si_addr = addr;return force_sig_info (&info); }@@ -3266,12 +3255,23 @@ int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from)void copy_siginfo_to_external32 (struct compat_siginfo *to,const struct kernel_siginfo *from) { +enum siginfo_layout layout = +siginfo_layout (from->si_signo, from->si_code); +memset (to,0 ,sizeof (*to)); to->si_signo = from->si_signo; to->si_errno = from->si_errno; to->si_code = from->si_code;kernel/signal.c int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from) · line 3274
Quoted 10 lines
kernel/signal.c +9
-1-switch (siginfo_layout (from->si_signo, from->si_code)) { + +if (siginfo_layout_is_fault (layout)) { + to->si_addr =ptr_to_compat (from->si_addr); +#ifdef __ARCH_SI_TRAPNO + to->si_trapno = from->si_trapno; +#endif + } + +switch (layout) {I find the code flow slightly awkward with this change, because the fault signal fields are populated partly in the
if()above and partly in theswitch(). Previously, only the universal stuff was done outside.
Quoted 5 lines
Would this be easier on future maintainers if we pulled the common stuff out into a helper and then called it from the appropriate switch cases? The compiler will probably output some duplicated code in that case (depending on how clever it is at undoing the duplication), but the amount of affected code is small.
I'm not sure about that. One advantage of the current code structure is that we end up with siginfo_layout_is_fault containing our single canonical list of layouts that use the sigfault union member. With your proposed code structure, the only caller of siginfo_layout_is_fault would be the code that the next patch adds to kernel/ptrace.c, which needs to know which layouts use sigfault so that it can clear si_xflags, and that could relatively easily get out of sync by accident since it's dealing with a less common case.
That being said, perhaps we could say that a caller of ptrace(PTRACE_SETSIGINFO) is by definition old, so it wouldn't be using that API to send signals with new siginfo layouts. That would preclude a client from upgrading its knowledge of si_xflags independently of its knowledge of new layouts though, and there would be nothing preventing a new caller of siginfo_layout_is_fault being added that would be exposed to new user code.
Peter
Quoted 65 lines
Quoted 46 lines
kernel/signal.c +3
-16case SIL_KILL : to->si_pid = from->si_pid; to->si_uid = from->si_uid;@@ -3286,31 +3286,15 @@ void copy_siginfo_to_external32(struct compat_siginfo *to, to->si_fd = from->si_fd;break ;case SIL_FAULT : - to->si_addr =ptr_to_compat (from->si_addr); -#ifdef __ARCH_SI_TRAPNO - to->si_trapno = from->si_trapno; -#endif break ;case SIL_FAULT_MCEERR : - to->si_addr =ptr_to_compat (from->si_addr); -#ifdef __ARCH_SI_TRAPNO - to->si_trapno = from->si_trapno; -#endif to->si_addr_lsb = from->si_addr_lsb;break ;case SIL_FAULT_BNDERR : - to->si_addr =ptr_to_compat (from->si_addr); -#ifdef __ARCH_SI_TRAPNO - to->si_trapno = from->si_trapno; -#endif to->si_lower =ptr_to_compat (from->si_lower); to->si_upper =ptr_to_compat (from->si_upper);break ;case SIL_FAULT_PKUERR : - to->si_addr =ptr_to_compat (from->si_addr); -#ifdef __ARCH_SI_TRAPNO - to->si_trapno = from->si_trapno; -#endif to->si_pkey = from->si_pkey;break ;case SIL_CHLD :@@ -3347,11 +3331,22 @@ int __copy_siginfo_to_user32(struct compat_siginfo __user *to,static int post_copy_siginfo_from_user32 (kernel_siginfo_t *to,const struct compat_siginfo *from) { +enum siginfo_layout layout = +siginfo_layout (from->si_signo, from->si_code); +clear_siginfo (to); to->si_signo = from->si_signo; to->si_errno = from->si_errno; to->si_code = from->si_code;kernel/signal.c int __copy_siginfo_to_user32(struct compat_siginfo __user *to, · line 3349
Quoted 10 lines
kernel/signal.c +9
-1-switch (siginfo_layout (from->si_signo, from->si_code)) { + +if (siginfo_layout_is_fault (layout)) { + to->si_addr =compat_ptr (from->si_addr); +#ifdef __ARCH_SI_TRAPNO + to->si_trapno = from->si_trapno; +#endif + } + +switch (layout) {Same comment as for
copy_siginfo_to_external32()?[...]
Otherwise, looks reasonable.
Cheers
---Dave
Re: [PATCH v10 5/7] signal: deduplicate code dealing with common _sigfault fields
Quoted 187 lines · Peter Collingbourne
Quoted 171 lines · Dave Martin
Quoted 154 lines · Peter Collingbourne
We're about to add more common
_sigfaultfields, so deduplicate the existing code for initializing_sigfaultfields in {send,force}_sig_*, and for copying_sigfaultfields incopy_siginfo_to_external32andpost_copy_siginfo_from_user32, to reduce the number of places that will need to be updated by upcoming changes.Signed-off-by Peter Collingbourne <[email protected]>---
View this change in Gerrit: https://linux-review.googlesource.com/q/I4f56174e1b7b2bf4a3c8139e6879cbfd52750a24include/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 +19
-27@@ -1649,6 +1649,15 @@ void force_sigsegv(int sig)force_sig (SIGSEGV ); } +static void set_sigfault_common_fields (struct kernel_siginfo *info,int sig, +int code,void __user *addr) +{ + info->si_signo = sig; + info->si_errno =0 ; + info->si_code = code; + info->si_addr = addr; +} + int force_sig_fault_to_task(int sig, int code, void __user *addr___ARCH_SI_TRAPNO (int trapno) ___ARCH_SI_IA64(int imm, unsigned int flags, unsigned long isr)@@ -1657,10 +1666,7 @@ int force_sig_fault_to_task(int sig, int code, void __user *addrstruct kernel_siginfo info;clear_siginfo (&info); - info.si_signo = sig; - info.si_errno =0 ; - info.si_code = code; - info.si_addr = addr; +set_sigfault_common_fields (&info, sig, code, addr);#ifdef __ARCH_SI_TRAPNO info.si_trapno = trapno;#endif @@ -1689,10 +1695,7 @@ int send_sig_fault(int sig, int code, void __user *addrstruct kernel_siginfo info;clear_siginfo (&info); - info.si_signo = sig; - info.si_errno =0 ; - info.si_code = code; - info.si_addr = addr; +set_sigfault_common_fields (&info, sig, code, addr);#ifdef __ARCH_SI_TRAPNO info.si_trapno = trapno;#endif @@ -1710,10 +1713,7 @@ int force_sig_mceerr(int code, void __user *addr, short lsb)WARN_ON ((code !=BUS_MCEERR_AO ) && (code !=BUS_MCEERR_AR ));clear_siginfo (&info); - info.si_signo =SIGBUS ; - info.si_errno =0 ; - info.si_code = code; - info.si_addr = addr; +set_sigfault_common_fields (&info,SIGBUS , code, addr); info.si_addr_lsb = lsb;return force_sig_info (&info); }@@ -1724,10 +1724,7 @@ int send_sig_mceerr(int code, void __user *addr, short lsb, struct task_struct *WARN_ON ((code !=BUS_MCEERR_AO ) && (code !=BUS_MCEERR_AR ));clear_siginfo (&info); - info.si_signo =SIGBUS ; - info.si_errno =0 ; - info.si_code = code; - info.si_addr = addr; +set_sigfault_common_fields (&info,SIGBUS , code, addr); info.si_addr_lsb = lsb;return send_sig_info (info.si_signo, &info, t); }@@ -1738,10 +1735,7 @@ int force_sig_bnderr(void __user *addr, void __user *lower, void __user *upper)struct kernel_siginfo info;clear_siginfo (&info); - info.si_signo =SIGSEGV ; - info.si_errno =0 ; - info.si_code =SEGV_BNDERR ; - info.si_addr = addr; +set_sigfault_common_fields (&info,SIGSEGV ,SEGV_BNDERR , addr); info.si_lower = lower; info.si_upper = upper;return force_sig_info (&info);@@ -1753,10 +1747,7 @@ int force_sig_pkuerr(void __user *addr, u32 pkey)struct kernel_siginfo info;clear_siginfo (&info); - info.si_signo =SIGSEGV ; - info.si_errno =0 ; - info.si_code =SEGV_PKUERR ; - info.si_addr = addr; +set_sigfault_common_fields (&info,SIGSEGV ,SEGV_PKUERR , addr); info.si_pkey = pkey;return force_sig_info (&info); }@@ -1770,10 +1761,8 @@ int force_sig_ptrace_errno_trap(int errno, void __user *addr)struct kernel_siginfo info;clear_siginfo (&info); - info.si_signo =SIGTRAP ; +set_sigfault_common_fields (&info,SIGTRAP ,TRAP_HWBKPT , addr); info.si_errno = errno; - info.si_code =TRAP_HWBKPT ; - info.si_addr = addr;return force_sig_info (&info); }@@ -3266,12 +3255,23 @@ int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from)void copy_siginfo_to_external32 (struct compat_siginfo *to,const struct kernel_siginfo *from) { +enum siginfo_layout layout = +siginfo_layout (from->si_signo, from->si_code); +memset (to,0 ,sizeof (*to)); to->si_signo = from->si_signo; to->si_errno = from->si_errno; to->si_code = from->si_code;kernel/signal.c int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from) · line 3274
Quoted 10 lines
kernel/signal.c +9
-1-switch (siginfo_layout (from->si_signo, from->si_code)) { + +if (siginfo_layout_is_fault (layout)) { + to->si_addr =ptr_to_compat (from->si_addr); +#ifdef __ARCH_SI_TRAPNO + to->si_trapno = from->si_trapno; +#endif + } + +switch (layout) {I find the code flow slightly awkward with this change, because the fault signal fields are populated partly in the
if()above and partly in theswitch(). Previously, only the universal stuff was done outside.Quoted 5 lines
Would this be easier on future maintainers if we pulled the common stuff out into a helper and then called it from the appropriate switch cases? The compiler will probably output some duplicated code in that case (depending on how clever it is at undoing the duplication), but the amount of affected code is small.
I'm not sure about that. One advantage of the current code structure is that we end up with
siginfo_layout_is_faultcontaining our single canonical list of layouts that use the sigfault union member. With your proposed code structure, the only caller ofsiginfo_layout_is_faultwould be the code that the next patch adds tokernel/ptrace.c, which needs to know which layouts use sigfault so that it can clearsi_xflags, and that could relatively easily get out of sync by accident since it's dealing with a less common case.
Quoted 7 lines
That being said, perhaps we could say that a caller of
ptrace(PTRACE_SETSIGINFO)is by definition old, so it wouldn't be using that API to send signals with new siginfo layouts. That would preclude a client from upgrading its knowledge ofsi_xflagsindependently of its knowledge of new layouts though, and there would be nothing preventing a new caller ofsiginfo_layout_is_faultbeing added that would be exposed to new user code.
OK, I guess I don't have a strong view on this for now.
I suppose that clear_siginfo() could be moved into set_sigfault_common_fields() (perhaps warranting a rename to init_sigfault() or similar).
But that's just one line per case, so probably not worth getting excited about. There is also some virtue in keeping the clear_siginfo() explicit everywhere, so that people are reminded about the need for it.
Anyway, that's not essential.
[...]
Cheers
---Dave
PATCH v10 6/7 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_ignored_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, 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.
Alternatively, we may consider 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.
---
View this change in Gerrit: https://linux-review.googlesource.com/q/Ide155ce29366c3eab2a944ae4c51205982e5b8b2
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 | 4 +-- 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 | 2 ++ kernel/ptrace.c | 29 ++++++++++++++++++++++ kernel/signal.c | 3 +++ 9 files changed, 48 insertions(+), 3 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 +2 -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 );
include/linux/compat.h +2 -0
@@ -231,7 +231,9 @@ typedef struct compat_siginfo {char _dummy_pkey[__COMPAT_ADDR_BND_PKEY_PAD];u32 _pkey; } _addr_pkey; +compat_uptr_t _pad[6 ]; }; +compat_uptr_t _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 ]; }; +unsigned long _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 +2 -0
@@ -101,6 +101,8 @@ struct ptrace_syscall_info { }; }; +#define PTRACE_SETSIGINFO2 0x420f +/* * These values are stored in task->ptrace_message * by tracehook_report_syscall_* to describe the current syscall-stop.
kernel/ptrace.c +29 -0
@@ -1038,6 +1038,20 @@ int ptrace_request(struct task_struct *child, long request,break ;case PTRACE_SETSIGINFO : + ret =copy_siginfo_from_user (&siginfo, datavp); +if (!ret) { +/* +* Assume that the caller is unaware of si_xflags, so +* fill it in if we're using a layout that requires it. +*/ +if (siginfo_layout_is_fault (siginfo_layout ( + siginfo.si_signo, siginfo.si_code))) + siginfo.si_xflags =0 ; + ret =ptrace_setsiginfo (child, &siginfo); + } +break ; + +case PTRACE_SETSIGINFO2 : ret =copy_siginfo_from_user (&siginfo, datavp);if (!ret) ret =ptrace_setsiginfo (child, &siginfo);
@@ -1347,6 +1361,21 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,break ;case PTRACE_SETSIGINFO : + ret =copy_siginfo_from_user32 ( + &siginfo, (struct compat_siginfo __user *) datap); +if (!ret) { +/* +* Assume that the caller is unaware of si_xflags, so +* fill it in if we're using a layout that requires it. +*/ +if (siginfo_layout_is_fault (siginfo_layout ( + siginfo.si_signo, siginfo.si_code))) + siginfo.si_xflags =0 ; + ret =ptrace_setsiginfo (child, &siginfo); + } +break ; + +case PTRACE_SETSIGINFO2 : ret =copy_siginfo_from_user32 ( &siginfo, (struct compat_siginfo __user *) datap);if (!ret)
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 · 1 line
2.28.0.297.g1956fa8f8d-goog
Re: [PATCH v10 6/7] signal: define the field siginfo.si_xflags
On Fri, Aug 21, 2020 at 10:10:16PM -0700, Peter Collingbourne wrote:
[ Add a new siginfo member sa_xflags, for fault signals. ]
Quoted 21 lines
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_ignored_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
Quoted 7 lines
So 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, so we definesi_xflagsto only be valid ifsi_code>= 0.
I would say >. 0 is SI_USER, and the fact that those other interfaces reject SI_USER seems inconsistent or a bug.
We can always relax the rule later.
Since si_xflags only makes sense for "real" fault signals, it would never be applicable in combination with SI_USER. Or am I missing something?
Either way, I think this is just a documentation ossue in practice.
Quoted 6 lines
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.
Will we need to introduce PTRACE_SETSIGINFO3, 4 etc., every time a new field comes up?
I wonder whether we should make this more flexible, say accepting some flags argument to say which fields the caller understands (and so doesn't want clobbered). Maybe we can (ab)use the sa_flags bit definitions for indicating which extensions the caller understands.
Quoted 4 lines
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.
Ack. I'm still wondering if some of those SIGSEGV/SI_KERNEL instances should be changed to one of the standard SIGSEGV codes, but either way, having si_xflags validity require si_code < SI_KERNEL seems appropriate.
Quoted 8 lines
Ideally this field could have just been named
si_flags, but that name was already taken by ia64, so a different name was chosen.Alternatively, we may consider 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.
Hmm, that might be an idea.
It would mean that x86 would have different rules from other architectures regarding how to know when the field is valid, which might lull x86-first projects into a false sense of security. Perhaps we could refuse to expose any of the arch-independent flags in si_flags unless explicitly requested via SA_XFLAGS, but that would be a departure from what this series implements today.
So maybe it's simpler to keep the two fields separate, unless somebody objects.
Quoted 39 lines
Signed-off-by Peter Collingbourne <[email protected]>---
View this change in Gerrit: https://linux-review.googlesource.com/q/Ide155ce29366c3eab2a944ae4c51205982e5b8b2v10:
- 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 | 4 +-- 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 | 2 ++ kernel/ptrace.c | 29 ++++++++++++++++++++++ kernel/signal.c | 3 +++ 9 files changed, 48 insertions(+), 3 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 +0
-0
arch/x86/kernel/signal_compat.c static inline void signal_compat_build_tests(void) · line 125
Quoted 7 lines
arch/x86/kernel/signal_compat.c +2
-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 ));
(Yuk, but at least you make this no worse.)
Quoted 8 lines
arch/x86/kernel/signal_compat.c +0
-0BUILD_BUG_ON (offsetof(siginfo_t , si_addr) !=0x10 );BUILD_BUG_ON (offsetof(compat_siginfo_t , si_addr) !=0x0C );include/linux/compat.h +0
-0
include/linux/compat.h typedef struct compat_siginfo { · line 236
Quoted 6 lines
include/linux/compat.h +2
-0@@ -231,7 +231,9 @@ typedef struct compat_siginfo {char _dummy_pkey[__COMPAT_ADDR_BND_PKEY_PAD];u32 _pkey; } _addr_pkey; +compat_uptr_t _pad[6 ]; }; +compat_uptr_t _xflags;
Should we have the same type here for native and compat?
I don't have a very strong opinion on this, but currently native on 64-bit arches will have 32 extra bits in _xflags that can never be used (or have to be defined differently for compat).
Quoted 20 lines
include/linux/compat.h +0
-0} _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 +0
-0
include/uapi/asm-generic/siginfo.h union __sifields { · line 94
Quoted 4 lines
include/uapi/asm-generic/siginfo.h +1
-0@@ -91,7 +91,9 @@ union __sifields {char _dummy_pkey[__ADDR_BND_PKEY_PAD];__u32 _pkey; } _addr_pkey; +void *_pad[6 ];
6?
Obviously we'll need something here, but I'm curious as to where this value came from.
(Same for compat.)
Quoted 19 lines
include/uapi/asm-generic/siginfo.h +3
-0}; +unsigned long _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 +0
-0
include/uapi/asm-generic/signal-defs.h line 24
Quoted 5 lines
include/uapi/asm-generic/signal-defs.h +2
-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
Maybe "valid for fault signals (SIGSEGV etc.)"
[...]
Otherwise, this looks sensible overall to me.
Cheers
---Dave
_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Re: [PATCH v10 6/7] signal: define the field siginfo.si_xflags
Quoted 4 lines · Dave Martin
On Fri, Aug 21, 2020 at 10:10:16PM -0700, Peter Collingbourne wrote:
[ Add a new siginfo member
sa_xflags, for fault signals. ]
Will fix.
Quoted 32 lines
Quoted 21 lines
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_ignored_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_tgsigqueueinfoQuoted 7 lines
So 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, so we definesi_xflagsto only be valid ifsi_code>= 0.I would say >. 0 is
SI_USER, and the fact that those other interfaces rejectSI_USERseems inconsistent or a bug.
Quoted 7 lines
We can always relax the rule later.
Since
si_xflagsonly makes sense for "real" fault signals, it would never be applicable in combination withSI_USER. Or am I missing something?Either way, I think this is just a documentation ossue in practice.
I think you're right. kill(2) and tgkill(2) set si_code to SI_USER, so excluding SI_USER seems to be necessary to avoid an invalid read via either of these syscalls. I will update the comment to say > 0.
Quoted 7 lines
Quoted 6 lines
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.
Quoted 7 lines
Will we need to introduce
PTRACE_SETSIGINFO3, 4 etc., every time a new field comes up?I wonder whether we should make this more flexible, say accepting some flags argument to say which fields the caller understands (and so doesn't want clobbered). Maybe we can (ab)use the
sa_flagsbit definitions for indicating which extensions the caller understands.
I'd be okay with adding a flags argument here, to be passed via the addr argument to PTRACE_SETSIGINFO2. (Confusingly, in some of the ptrace request types including the ones that deal with siginfo "data" is the argument that takes an address and "addr" is the one that takes something else! My new request type will do the same to make things consistently confusing.)
I guess we would only require a new "out of band" signaling mechanism if we were adding a field to a different union member (presumably a flags field to support the kind of future expansion that we anticipate for sigfault), since for sigfault we may indicate presence of new fields using si_xflags. Presumably such a field would come at the same time as a new SA_* bit for detecting its presence, so I suppose that we could use the sa_flags bits here as well. I'm not entirely comfortable with that though because the other SA_* bits wouldn't make sense to be passed as an argument here (and because of the architecture dependence that made it so hard to find free SA_* bits to add, we would be unnecessarily restricted in the number of bits that we could easily add here), and in the future someone may come up with a reason to pass a new flag here that wouldn't correspond to an SA_* bit. So I would mildly prefer a new set of bit definitions.
It's unfortunate that the addr argument for PTRACE_SETSIGINFO was specified to be ignored rather than causing an error for non-zero values, as otherwise we could have used it as the flags argument to the existing request type and avoided adding a new one. Of course, this is the same issue that has caused us so much grief with sigaction. But for the new request type we can do things properly and require addr to have only recognized bits set.
Quoted 19 lines
Quoted 4 lines
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.Ack. I'm still wondering if some of those SIGSEGV/SI_KERNEL instances should be changed to one of the standard SIGSEGV codes, but either way, having
si_xflagsvalidity requiresi_code<SI_KERNELseems appropriate.Quoted 8 lines
Ideally this field could have just been named
si_flags, but that name was already taken by ia64, so a different name was chosen.Alternatively, we may consider 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.
Quoted 5 lines
Hmm, that might be an idea.
It would mean that x86 would have different rules from other architectures regarding how to know when the field is valid, which might lull x86-first projects into a false sense of security. Perhaps we could
ia64 is Itanium, not x86. And ia64 is almost dead (I heard that gcc was planning to remove support some time next year [1], which I expect would be followed soon after by dropping kernel support). So I wouldn't expect there to be a lot of ia64-first projects out there.
[1] https://www.phoronix.com/scan.php?page=news_item&px=Intel-IA-64-GCC-Deprecation
Quoted 6 lines
refuse to expose any of the arch-independent flags in
si_flagsunless explicitly requested viaSA_XFLAGS, but that would be a departure from what this series implements today.So maybe it's simpler to keep the two fields separate, unless somebody objects.
Notwithstanding the above, I would be mildly in favor of keeping them separate in order to avoid the complexity implied by entangling them, since it's complex enough to add fields here as it is.
Quoted 66 lines
Quoted 39 lines
Signed-off-by Peter Collingbourne <[email protected]>---
View this change in Gerrit: https://linux-review.googlesource.com/q/Ide155ce29366c3eab2a944ae4c51205982e5b8b2v10:
- 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 | 4 +-- 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 | 2 ++ kernel/ptrace.c | 29 ++++++++++++++++++++++ kernel/signal.c | 3 +++ 9 files changed, 48 insertions(+), 3 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 +0
-0arch/x86/kernel/signal_compat.c static inline void signal_compat_build_tests(void) · line 125
Quoted 7 lines
arch/x86/kernel/signal_compat.c +2
-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 ));(Yuk, but at least you make this no worse.)
Quoted 8 lines
arch/x86/kernel/signal_compat.c +0
-0BUILD_BUG_ON (offsetof(siginfo_t , si_addr) !=0x10 );BUILD_BUG_ON (offsetof(compat_siginfo_t , si_addr) !=0x0C );include/linux/compat.h +0
-0include/linux/compat.h typedef struct compat_siginfo { · line 236
Quoted 6 lines
include/linux/compat.h +2
-0@@ -231,7 +231,9 @@ typedef struct compat_siginfo {char _dummy_pkey[__COMPAT_ADDR_BND_PKEY_PAD];u32 _pkey; } _addr_pkey; +compat_uptr_t _pad[6 ]; }; +compat_uptr_t _xflags;Should we have the same type here for native and compat?
Quoted 3 lines
I don't have a very strong opinion on this, but currently native on 64-bit arches will have 32 extra bits in
_xflagsthat can never be used (or have to be defined differently for compat).
Good point. I will make this a u64 (although I think 32 bits will probably be more than enough, the distance between si_xflags and si_addr_ignored_bits will be 8 bytes on 64-bit architectures due to alignment so we may as well make all of the bits available).
Quoted 27 lines
Quoted 20 lines
include/linux/compat.h +0
-0} _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 +0
-0include/uapi/asm-generic/siginfo.h union __sifields { · line 94
Quoted 4 lines
include/uapi/asm-generic/siginfo.h +1
-0@@ -91,7 +91,9 @@ union __sifields {char _dummy_pkey[__ADDR_BND_PKEY_PAD];__u32 _pkey; } _addr_pkey; +void *_pad[6 ];6?
Quoted 4 lines
Obviously we'll need something here, but I'm curious as to where this value came from.
(Same for compat.)
I think it came from Eric's suggestion in [1], i.e. 2 words from the existing fields plus the 4 words of padding suggested by Eric.
[1] https://www.spinics.net/lists/arm-kernel/msg808618.html
Quoted 18 lines
Quoted 18 lines
include/uapi/asm-generic/siginfo.h +3
-0}; +unsigned long _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 +0
-0
Quoted 8 lines
include/uapi/asm-generic/signal-defs.h line 24
Quoted 6 lines
include/uapi/asm-generic/signal-defs.h +2
-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 Maybe "valid for fault signals (SIGSEGV etc.)"
Will add.
Quoted 3 lines
[...]
Otherwise, this looks sensible overall to me.
Thanks for the review. (And apologies for being slow to respond to your reviews. I got preempted by another task right after sending out v10 and only now did I get a chance to get back to this.)
Peter
Re: [PATCH v10 6/7] signal: define the field siginfo.si_xflags
Quoted 207 lines · Peter Collingbourne
Quoted 4 lines · Dave Martin
On Fri, Aug 21, 2020 at 10:10:16PM -0700, Peter Collingbourne wrote:
[ Add a new siginfo member
sa_xflags, for fault signals. ]Will fix.
Quoted 32 lines
Quoted 21 lines
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_ignored_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_tgsigqueueinfoQuoted 7 lines
So 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, so we definesi_xflagsto only be valid ifsi_code>= 0.I would say >. 0 is
SI_USER, and the fact that those other interfaces rejectSI_USERseems inconsistent or a bug.Quoted 7 lines
We can always relax the rule later.
Since
si_xflagsonly makes sense for "real" fault signals, it would never be applicable in combination withSI_USER. Or am I missing something?Either way, I think this is just a documentation ossue in practice.
I think you're right. kill(2) and tgkill(2) set
si_codetoSI_USER, so excludingSI_USERseems to be necessary to avoid an invalid read via either of these syscalls. I will update the comment to say > 0.Quoted 7 lines
Quoted 6 lines
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.Quoted 7 lines
Will we need to introduce
PTRACE_SETSIGINFO3, 4 etc., every time a new field comes up?I wonder whether we should make this more flexible, say accepting some flags argument to say which fields the caller understands (and so doesn't want clobbered). Maybe we can (ab)use the
sa_flagsbit definitions for indicating which extensions the caller understands.I'd be okay with adding a flags argument here, to be passed via the addr argument to
PTRACE_SETSIGINFO2. (Confusingly, in some of the ptrace request types including the ones that deal with siginfo "data" is the argument that takes an address and "addr" is the one that takes something else! My new request type will do the same to make things consistently confusing.)I guess we would only require a new "out of band" signaling mechanism if we were adding a field to a different union member (presumably a flags field to support the kind of future expansion that we anticipate for sigfault), since for sigfault we may indicate presence of new fields using
si_xflags. Presumably such a field would come at the same time as a new SA_* bit for detecting its presence, so I suppose that we could use thesa_flagsbits here as well. I'm not entirely comfortable with that though because the other SA_* bits wouldn't make sense to be passed as an argument here (and because of the architecture dependence that made it so hard to find free SA_* bits to add, we would be unnecessarily restricted in the number of bits that we could easily add here), and in the future someone may come up with a reason to pass a new flag here that wouldn't correspond to an SA_* bit. So I would mildly prefer a new set of bit definitions.It's unfortunate that the addr argument for
PTRACE_SETSIGINFOwas specified to be ignored rather than causing an error for non-zero values, as otherwise we could have used it as the flags argument to the existing request type and avoided adding a new one. Of course, this is the same issue that has caused us so much grief with sigaction. But for the new request type we can do things properly and require addr to have only recognized bits set.Quoted 19 lines
Quoted 4 lines
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.Ack. I'm still wondering if some of those SIGSEGV/SI_KERNEL instances should be changed to one of the standard SIGSEGV codes, but either way, having
si_xflagsvalidity requiresi_code<SI_KERNELseems appropriate.Quoted 8 lines
Ideally this field could have just been named
si_flags, but that name was already taken by ia64, so a different name was chosen.Alternatively, we may consider 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.Quoted 5 lines
Hmm, that might be an idea.
It would mean that x86 would have different rules from other architectures regarding how to know when the field is valid, which might lull x86-first projects into a false sense of security. Perhaps we could
ia64 is Itanium, not x86. And ia64 is almost dead (I heard that gcc was planning to remove support some time next year [1], which I expect would be followed soon after by dropping kernel support). So I wouldn't expect there to be a lot of ia64-first projects out there.
[1] https://www.phoronix.com/scan.php?page=news_item&px=Intel-IA-64-GCC-Deprecation
Quoted 6 lines
refuse to expose any of the arch-independent flags in
si_flagsunless explicitly requested viaSA_XFLAGS, but that would be a departure from what this series implements today.So maybe it's simpler to keep the two fields separate, unless somebody objects.
Notwithstanding the above, I would be mildly in favor of keeping them separate in order to avoid the complexity implied by entangling them, since it's complex enough to add fields here as it is.
Quoted 66 lines
Quoted 39 lines
Signed-off-by Peter Collingbourne <[email protected]>---
View this change in Gerrit: https://linux-review.googlesource.com/q/Ide155ce29366c3eab2a944ae4c51205982e5b8b2v10:
- 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 | 4 +-- 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 | 2 ++ kernel/ptrace.c | 29 ++++++++++++++++++++++ kernel/signal.c | 3 +++ 9 files changed, 48 insertions(+), 3 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 +0
-0arch/x86/kernel/signal_compat.c static inline void signal_compat_build_tests(void) · line 125
Quoted 7 lines
arch/x86/kernel/signal_compat.c +2
-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 ));(Yuk, but at least you make this no worse.)
Quoted 8 lines
arch/x86/kernel/signal_compat.c +0
-0BUILD_BUG_ON (offsetof(siginfo_t , si_addr) !=0x10 );BUILD_BUG_ON (offsetof(compat_siginfo_t , si_addr) !=0x0C );include/linux/compat.h +0
-0include/linux/compat.h typedef struct compat_siginfo { · line 236
Quoted 6 lines
include/linux/compat.h +2
-0@@ -231,7 +231,9 @@ typedef struct compat_siginfo {char _dummy_pkey[__COMPAT_ADDR_BND_PKEY_PAD];u32 _pkey; } _addr_pkey; +compat_uptr_t _pad[6 ]; }; +compat_uptr_t _xflags;Should we have the same type here for native and compat?
Quoted 8 lines
Quoted 3 lines
I don't have a very strong opinion on this, but currently native on 64-bit arches will have 32 extra bits in
_xflagsthat can never be used (or have to be defined differently for compat).Good point. I will make this a u64 (although I think 32 bits will probably be more than enough, the distance between
si_xflagsandsi_addr_ignored_bitswill be 8 bytes on 64-bit architectures due to alignment so we may as well make all of the bits available).
It turns out that we can't actually make this a u64 because on 32-bit platforms this increases the alignment of the union to 8, which breaks layout for the other fields in the union. In v12 I will make this a u32 so that we don't end up with unusable bits.
Peter
Re: [PATCH v10 6/7] signal: define the field siginfo.si_xflags
Quoted 5 lines · Peter Collingbourne
Quoted 4 lines · Peter Collingbourne
Quoted 2 lines · Dave Martin
On Fri, Aug 21, 2020 at 10:10:16PM -0700, Peter Collingbourne wrote:
[...]
Quoted 23 lines
Quoted 14 lines
Quoted 14 lines
include/linux/compat.h typedef struct compat_siginfo { · line 236
Quoted 11 lines
include/linux/compat.h +2
-0@@ -231,7 +231,9 @@ typedef struct compat_siginfo {char _dummy_pkey[__COMPAT_ADDR_BND_PKEY_PAD];u32 _pkey; } _addr_pkey; +compat_uptr_t _pad[6 ]; }; +compat_uptr_t _xflags;Should we have the same type here for native and compat?
Quoted 8 lines
Quoted 3 lines
I don't have a very strong opinion on this, but currently native on 64-bit arches will have 32 extra bits in
_xflagsthat can never be used (or have to be defined differently for compat).Good point. I will make this a u64 (although I think 32 bits will probably be more than enough, the distance between
si_xflagsandsi_addr_ignored_bitswill be 8 bytes on 64-bit architectures due to alignment so we may as well make all of the bits available).
Quoted 4 lines
It turns out that we can't actually make this a u64 because on 32-bit platforms this increases the alignment of the union to 8, which breaks layout for the other fields in the union. In v12 I will make this a u32 so that we don't end up with unusable bits.
u32 seems fine to me.
If we need more bits later, we can always use one of the 32 xflags bits to indicate that the new field(s) exist.
Cheers
---Dave
Re: [PATCH v10 6/7] signal: define the field siginfo.si_xflags
In reply to Peter CollingbourneQuoted 46 lines · Peter Collingbourne
Quoted 4 lines · Dave Martin
On Fri, Aug 21, 2020 at 10:10:16PM -0700, Peter Collingbourne wrote:
[ Add a new siginfo member
sa_xflags, for fault signals. ]Will fix.
Quoted 38 lines
Quoted 21 lines
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_ignored_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_tgsigqueueinfoQuoted 7 lines
So 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, so we definesi_xflagsto only be valid ifsi_code>= 0.I would say >. 0 is
SI_USER, and the fact that those other interfaces rejectSI_USERseems inconsistent or a bug.We can always relax the rule later.
Since
si_xflagsonly makes sense for "real" fault signals, it would never be applicable in combination withSI_USER. Or am I missing something?
Quoted 5 lines
Quoted 1 line
Either way, I think this is just a documentation ossue in practice.
I think you're right. kill(2) and tgkill(2) set
si_codetoSI_USER, so excludingSI_USERseems to be necessary to avoid an invalid read via either of these syscalls. I will update the comment to say > 0.
OK, makes sense.
Quoted 14 lines
Quoted 6 lines
Quoted 5 lines
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.Quoted 7 lines
Will we need to introduce
PTRACE_SETSIGINFO3, 4 etc., every time a new field comes up?I wonder whether we should make this more flexible, say accepting some flags argument to say which fields the caller understands (and so doesn't want clobbered). Maybe we can (ab)use the
sa_flagsbit definitions for indicating which extensions the caller understands.
Quoted 6 lines
I'd be okay with adding a flags argument here, to be passed via the addr argument to
PTRACE_SETSIGINFO2. (Confusingly, in some of the ptrace request types including the ones that deal with siginfo "data" is the argument that takes an address and "addr" is the one that takes something else! My new request type will do the same to make things consistently confusing.)
So long as we try to follow the existing pattern for similar ptrace calls, I guess people will cope with it.
If we make the argument a struct pointer, we have the option to expand it later if needed, provided that the initial definition of the struct members provides a way to discover such extensions (i.e., the initial struct needs space for a flag indicating this, or an indication of the struct size, or similar).
Quoted 6 lines
I guess we would only require a new "out of band" signaling mechanism if we were adding a field to a different union member (presumably a flags field to support the kind of future expansion that we anticipate for sigfault), since for sigfault we may indicate presence of new fields using
si_xflags. Presumably such a field would come at the same time as a new SA_* bit for detecting its presence, so I suppose that
Quoted 8 lines
we could use the
sa_flagsbits here as well. I'm not entirely comfortable with that though because the other SA_* bits wouldn't make sense to be passed as an argument here (and because of the architecture dependence that made it so hard to find free SA_* bits to add, we would be unnecessarily restricted in the number of bits that we could easily add here), and in the future someone may come up with a reason to pass a new flag here that wouldn't correspond to an SA_* bit. So I would mildly prefer a new set of bit definitions.
We don't need to use the sa_flags bit definitions here if that's likely to be problematic.
I don't really have a strong opinion either way though.
Quoted 7 lines
It's unfortunate that the addr argument for
PTRACE_SETSIGINFOwas specified to be ignored rather than causing an error for non-zero values, as otherwise we could have used it as the flags argument to the existing request type and avoided adding a new one. Of course, this is the same issue that has caused us so much grief with sigaction. But for the new request type we can do things properly and require addr to have only recognized bits set.
Ack
Quoted 25 lines
Quoted 19 lines
Quoted 4 lines
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.Ack. I'm still wondering if some of those SIGSEGV/SI_KERNEL instances should be changed to one of the standard SIGSEGV codes, but either way, having
si_xflagsvalidity requiresi_code<SI_KERNELseems appropriate.Quoted 8 lines
Ideally this field could have just been named
si_flags, but that name was already taken by ia64, so a different name was chosen.Alternatively, we may consider 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.Quoted 5 lines
Hmm, that might be an idea.
It would mean that x86 would have different rules from other architectures regarding how to know when the field is valid, which might lull x86-first projects into a false sense of security. Perhaps we could
Quoted 6 lines
ia64 is Itanium, not x86. And ia64 is almost dead (I heard that gcc was planning to remove support some time next year [1], which I expect would be followed soon after by dropping kernel support). So I wouldn't expect there to be a lot of ia64-first projects out there.
[1] https://www.phoronix.com/scan.php?page=news_item&px=Intel-IA-64-GCC-Deprecation
Ack, I knew this but I guess I skim-read your text too quickly and only saw the "64"...
Quoted 77 lines
Quoted 6 lines
refuse to expose any of the arch-independent flags in
si_flagsunless explicitly requested viaSA_XFLAGS, but that would be a departure from what this series implements today.So maybe it's simpler to keep the two fields separate, unless somebody objects.
Notwithstanding the above, I would be mildly in favor of keeping them separate in order to avoid the complexity implied by entangling them, since it's complex enough to add fields here as it is.
Quoted 66 lines
Quoted 39 lines
Signed-off-by Peter Collingbourne <[email protected]>---
View this change in Gerrit: https://linux-review.googlesource.com/q/Ide155ce29366c3eab2a944ae4c51205982e5b8b2v10:
- 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 | 4 +-- 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 | 2 ++ kernel/ptrace.c | 29 ++++++++++++++++++++++ kernel/signal.c | 3 +++ 9 files changed, 48 insertions(+), 3 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 +0
-0arch/x86/kernel/signal_compat.c static inline void signal_compat_build_tests(void) · line 125
Quoted 7 lines
arch/x86/kernel/signal_compat.c +2
-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 ));(Yuk, but at least you make this no worse.)
Quoted 8 lines
arch/x86/kernel/signal_compat.c +0
-0BUILD_BUG_ON (offsetof(siginfo_t , si_addr) !=0x10 );BUILD_BUG_ON (offsetof(compat_siginfo_t , si_addr) !=0x0C );include/linux/compat.h +0
-0include/linux/compat.h typedef struct compat_siginfo { · line 236
Quoted 6 lines
include/linux/compat.h +2
-0@@ -231,7 +231,9 @@ typedef struct compat_siginfo {char _dummy_pkey[__COMPAT_ADDR_BND_PKEY_PAD];u32 _pkey; } _addr_pkey; +compat_uptr_t _pad[6 ]; }; +compat_uptr_t _xflags;Should we have the same type here for native and compat?
Quoted 8 lines
Quoted 3 lines
I don't have a very strong opinion on this, but currently native on 64-bit arches will have 32 extra bits in
_xflagsthat can never be used (or have to be defined differently for compat).Good point. I will make this a u64 (although I think 32 bits will probably be more than enough, the distance between
si_xflagsandsi_addr_ignored_bitswill be 8 bytes on 64-bit architectures due to alignment so we may as well make all of the bits available).
Ack
Quoted 30 lines
Quoted 30 lines
Quoted 20 lines
include/linux/compat.h +0
-0} _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 +0
-0include/uapi/asm-generic/siginfo.h union __sifields { · line 94
Quoted 4 lines
include/uapi/asm-generic/siginfo.h +1
-0@@ -91,7 +91,9 @@ union __sifields {char _dummy_pkey[__ADDR_BND_PKEY_PAD];__u32 _pkey; } _addr_pkey; +void *_pad[6 ];6?
Obviously we'll need something here, but I'm curious as to where this value came from.
Quoted 6 lines
Quoted 1 line
(Same for compat.)
I think it came from Eric's suggestion in [1], i.e. 2 words from the existing fields plus the 4 words of padding suggested by Eric.
So long as there's a reason for it, I guess I don't have a strong opinion.
Quoted 30 lines
Quoted 19 lines
Quoted 19 lines
include/uapi/asm-generic/siginfo.h +3
-0}; +unsigned long _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 +0
-0Quoted 8 lines
include/uapi/asm-generic/signal-defs.h line 24
Quoted 6 lines
include/uapi/asm-generic/signal-defs.h +2
-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 Maybe "valid for fault signals (SIGSEGV etc.)"
Will add.
Quoted 7 lines
Quoted 3 lines
[...]
Otherwise, this looks sensible overall to me.
Thanks for the review. (And apologies for being slow to respond to your reviews. I got preempted by another task right after sending out v10 and only now did I get a chance to get back to this.)
No worries, I've had other stuff to do too...
Cheers
---Dave
PATCH v10 7/7 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
---
View this change in Gerrit: https://linux-review.googlesource.com/q/Ia8876bad8c798e0a32df7c2ce1256c4771c81446
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 | 17 +++++++ 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 | 59 +++++++++++++------------ arch/x86/kernel/signal_compat.c | 4 +- include/linux/compat.h | 2 + include/linux/signal.h | 8 ++++ include/uapi/asm-generic/siginfo.h | 10 +++++ kernel/signal.c | 14 +++++- 16 files changed, 122 insertions(+), 71 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_ignored_bits field +of siginfo, which is set for signals raised in response to data aborts +and instruction aborts. The si_addr_ignored_bits_mask field indicates +which bits of the field are valid. The validity of these fields is +indicated by the SIXFLAG_ADDR_IGNORED_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 +17 -0
@@ -0,0 +1,17 @@ +/* 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_ignored_bits_mask (unsigned long sig, +unsigned long si_code) +{ +if (sig ==SIGTRAP && si_code ==TRAP_BRKPT ) +return 0 ; +return 0xffUL <<56 ; +} +#define arch_addr_ignored_bits_mask arch_addr_ignored_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);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);
@@ -104,7 +103,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
@@ -191,14 +191,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
@@ -234,32 +234,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)) {
@@ -267,7 +267,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); }
@@ -438,7 +438,7 @@ void force_signal_inject(int signal, int code, unsigned long address) signal =SIGKILL ; } -arm64_notify_die (desc, regs, signal, code, (void __user *)address,0 ); +arm64_notify_die (desc, regs, signal, code, address,0 ); }/*
@@ -449,7 +449,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 ;
@@ -501,12 +501,13 @@ NOKPROBE_SYMBOL(do_bti);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 */
@@ -533,7 +534,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 ); }
@@ -824,7 +825,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 +30 -29
167 lines not on this page · raw message
arch/x86/kernel/signal_compat.c +2 -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 );
include/linux/compat.h +2 -0
@@ -234,6 +234,8 @@ typedef struct compat_siginfo {compat_uptr_t _pad[6 ]; };compat_uptr_t _xflags; +compat_uptr_t _addr_ignored_bits; +compat_uptr_t _addr_ignored_bits_mask; } _sigfault;/* SIGPOLL */
include/linux/signal.h +8 -0
@@ -480,4 +480,12 @@ struct seq_file;extern void render_sigset_t (struct seq_file *,const char *,sigset_t *);#endif +#ifndef arch_addr_ignored_bits_mask +static inline unsigned long arch_addr_ignored_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 ]; };unsigned long _xflags; +unsigned long _addr_ignored_bits; +unsigned long _addr_ignored_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_ignored_bits _sifields._sigfault._addr_ignored_bits +#define si_addr_ignored_bits_mask _sifields._sigfault._addr_ignored_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
@@ -296,6 +300,12 @@ typedef struct siginfo {#define EMT_TAGOVF 1/* tag overflow */ #define NSIGEMT 1 +/* +* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP, SIGEMT si_xflags +*/ +#define SIXFLAG_ADDR_IGNORED_BITS 1 +/* si_addr_ignored_bits{,_mask} fields valid */ +/* * sigevent definitions *
kernel/signal.c +12 -2
@@ -1652,11 +1652,17 @@ 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 ignored_bits_mask = +arch_addr_ignored_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 & ~ignored_bits_mask); + info->si_xflags =SIXFLAG_ADDR_IGNORED_BITS ; + info->si_addr_ignored_bits = addr_long & ignored_bits_mask; + info->si_addr_ignored_bits_mask = ignored_bits_mask; } int force_sig_fault_to_task(int sig, int code, void __user *addr
@@ -3271,6 +3277,8 @@ void copy_siginfo_to_external32(struct compat_siginfo *to, to->si_trapno = from->si_trapno;#endif to->si_xflags = from->si_xflags; + to->si_addr_ignored_bits = from->si_addr_ignored_bits; + to->si_addr_ignored_bits_mask = from->si_addr_ignored_bits_mask; }switch (layout) {
@@ -3347,6 +3355,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_ignored_bits = from->si_addr_ignored_bits; + to->si_addr_ignored_bits_mask = from->si_addr_ignored_bits_mask; }switch (layout) {
Signature · 1 line
2.28.0.297.g1956fa8f8d-goog
Quoted 127 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]>---
View this change in Gerrit: https://linux-review.googlesource.com/q/Ia8876bad8c798e0a32df7c2ce1256c4771c81446v10:
- 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 | 17 +++++++ 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 | 59 +++++++++++++------------ arch/x86/kernel/signal_compat.c | 4 +- include/linux/compat.h | 2 + include/linux/signal.h | 8 ++++ include/uapi/asm-generic/siginfo.h | 10 +++++ kernel/signal.c | 14 +++++- 16 files changed, 122 insertions(+), 71 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_ignored_bits field +of siginfo, which is set for signals raised in response to data aborts +and instruction aborts. The si_addr_ignored_bits_mask field indicates +which bits of the field are valid. The validity of these fields is +indicated by the SIXFLAG_ADDR_IGNORED_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);
[...]
Quoted 18 lines
include/linux/compat.h +2
-0@@ -234,6 +234,8 @@ typedef struct compat_siginfo {compat_uptr_t _pad[6 ]; };compat_uptr_t _xflags; +compat_uptr_t _addr_ignored_bits; +compat_uptr_t _addr_ignored_bits_mask; } _sigfault;/* SIGPOLL */ include/linux/signal.h +0
-0
include/linux/signal.h struct seq_file; · line 481
Quoted 2 lines
include/linux/signal.h +0
-0@@ -480,4 +480,12 @@ struct seq_file;extern void render_sigset_t (struct seq_file *,const char *,sigset_t *);#endif
Can we have a comment here explaining what this helper needs to do, if defined?
Quoted 32 lines
include/linux/signal.h +8
-0+#ifndef arch_addr_ignored_bits_mask +static inline unsigned long arch_addr_ignored_bits_mask (unsigned long sig, +unsigned long si_code) +{ +return 0 ; +} +#endif +#endif /* _LINUX_SIGNAL_H */ include/uapi/asm-generic/siginfo.h +4
-0@@ -94,6 +94,8 @@ union __sifields {void *_pad[6 ]; };unsigned long _xflags; +unsigned long _addr_ignored_bits; +unsigned long _addr_ignored_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_ignored_bits _sifields._sigfault._addr_ignored_bits +#define si_addr_ignored_bits_mask _sifields._sigfault._addr_ignored_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
include/uapi/asm-generic/siginfo.h typedef struct siginfo { · line 308
Quoted 9 lines
include/uapi/asm-generic/siginfo.h +6
-0@@ -296,6 +300,12 @@ typedef struct siginfo {#define EMT_TAGOVF 1/* tag overflow */ #define NSIGEMT 1 +/* +* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP, SIGEMT si_xflags +*/ +#define SIXFLAG_ADDR_IGNORED_BITS 1 +/* si_addr_ignored_bits{,_mask} fields valid */ +
I'm still uneasy about the "ignored bits" nomenclature, because the bits aren't ignored, and because at the C language level above, they generally _are_ considered part of the address.
I don't have a great suggestion for a new name, though. If we just consider the si_addr_ignored_bits to be attributes that accompany the address, it might make sense to call it
si_addr_attr_bits_mask
or similar.
That may or may not be considered to be less confusing.
Quoted 14 lines
include/uapi/asm-generic/siginfo.h +0
-0/* * sigevent definitions * kernel/signal.c +3
-0@@ -1652,11 +1652,17 @@ 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 ignored_bits_mask = +arch_addr_ignored_bits_mask (sig, code);
kernel/signal.c void force_sigsegv(int sig) · line 1665
Quoted 10 lines
kernel/signal.c +5
-2+ 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 & ~ignored_bits_mask); + info->si_xflags =SIXFLAG_ADDR_IGNORED_BITS ; + info->si_addr_ignored_bits = addr_long & ignored_bits_mask; + info->si_addr_ignored_bits_mask = ignored_bits_mask;
Could we report the ignored bits optionally?
i.e., if arch_addr_ignored_bits_mask() == 0, then we could perhaps leave SIXFLAG_ADDR_IGNORED_BITS clear in si_xflags, and just set si_addr_ignored_bits{,_mask} to zeros.
I can't decide myself whether this would be a good idea or not...
kernel/signal.c void copy_siginfo_to_external32(struct compat_siginfo *to, · line 3281
Quoted 9 lines
kernel/signal.c +2
-0} int force_sig_fault_to_task(int sig, int code, void __user *addr@@ -3271,6 +3277,8 @@ void copy_siginfo_to_external32(struct compat_siginfo *to, to->si_trapno = from->si_trapno;#endif to->si_xflags = from->si_xflags; + to->si_addr_ignored_bits = from->si_addr_ignored_bits; + to->si_addr_ignored_bits_mask = from->si_addr_ignored_bits_mask;
What happens if we're delivering a signal to a compat process?
It looks like we apply all the usual logic, but si_addr_ignored_bits and si_addr_ignored_bits_mask simply get truncated.
That might be reasonable -- we don't care about bits that don't exist for compat, irrespective of what they mean for native -- but it's probably worth a comment.
kernel/signal.c static int post_copy_siginfo_from_user32(kernel_siginfo_t *to, · line 3359
Quoted 9 lines
kernel/signal.c +2
-0}switch (layout) {@@ -3347,6 +3355,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_ignored_bits = from->si_addr_ignored_bits; + to->si_addr_ignored_bits_mask = from->si_addr_ignored_bits_mask;
Otherwise, the patch looks reasonable.
Cheers
---Dave
_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Quoted 144 lines · Dave Martin
Quoted 127 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]>---
View this change in Gerrit: https://linux-review.googlesource.com/q/Ia8876bad8c798e0a32df7c2ce1256c4771c81446v10:
- 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 | 17 +++++++ 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 | 59 +++++++++++++------------ arch/x86/kernel/signal_compat.c | 4 +- include/linux/compat.h | 2 + include/linux/signal.h | 8 ++++ include/uapi/asm-generic/siginfo.h | 10 +++++ kernel/signal.c | 14 +++++- 16 files changed, 122 insertions(+), 71 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_ignored_bits field +of siginfo, which is set for signals raised in response to data aborts +and instruction aborts. The si_addr_ignored_bits_mask field indicates +which bits of the field are valid. The validity of these fields is +indicated by the SIXFLAG_ADDR_IGNORED_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);[...]
Quoted 12 lines
include/linux/compat.h +2
-0@@ -234,6 +234,8 @@ typedef struct compat_siginfo {compat_uptr_t _pad[6 ]; };compat_uptr_t _xflags; +compat_uptr_t _addr_ignored_bits; +compat_uptr_t _addr_ignored_bits_mask; } _sigfault;
Quoted 11 lines
include/linux/signal.h struct seq_file; · line 481
Quoted 8 lines
include/linux/compat.h +0
-0/* SIGPOLL */ include/linux/signal.h +0
-0@@ -480,4 +480,12 @@ struct seq_file;extern void render_sigset_t (struct seq_file *,const char *,sigset_t *);#endif Can we have a comment here explaining what this helper needs to do, if defined?
Will add.
Quoted 50 lines
Quoted 32 lines
include/linux/signal.h +8
-0+#ifndef arch_addr_ignored_bits_mask +static inline unsigned long arch_addr_ignored_bits_mask (unsigned long sig, +unsigned long si_code) +{ +return 0 ; +} +#endif +#endif /* _LINUX_SIGNAL_H */ include/uapi/asm-generic/siginfo.h +4
-0@@ -94,6 +94,8 @@ union __sifields {void *_pad[6 ]; };unsigned long _xflags; +unsigned long _addr_ignored_bits; +unsigned long _addr_ignored_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_ignored_bits _sifields._sigfault._addr_ignored_bits +#define si_addr_ignored_bits_mask _sifields._sigfault._addr_ignored_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._pkeyinclude/uapi/asm-generic/siginfo.h typedef struct siginfo { · line 308
Quoted 9 lines
include/uapi/asm-generic/siginfo.h +6
-0@@ -296,6 +300,12 @@ typedef struct siginfo {#define EMT_TAGOVF 1/* tag overflow */ #define NSIGEMT 1 +/* +* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP, SIGEMT si_xflags +*/ +#define SIXFLAG_ADDR_IGNORED_BITS 1 +/* si_addr_ignored_bits{,_mask} fields valid */ +I'm still uneasy about the "ignored bits" nomenclature, because the bits aren't ignored, and because at the C language level above, they generally _are_ considered part of the address.
I don't have a great suggestion for a new name, though. If we just consider the
si_addr_ignored_bitsto be attributes that accompany the address, it might make sense to call it
Quoted 5 lines
si_addr_attr_bits_maskor similar.
That may or may not be considered to be less confusing.
Hmm, I wasn't entirely comfortable with "ignored" either because, as you point out, once MTE arrives some of the bits won't be ignored any more. Maybe since folks who are going to be working with these bits will probably be at least a little familiar with their use on arm64 with MTE and the tagged address ABI, we should just borrow the nomenclature from arm64 and call it:
si_addr_tag_bits
si_addr_tag_bits_mask
SIXFLAG_ADDR_TAG_BITS
Quoted 27 lines
Quoted 14 lines
include/uapi/asm-generic/siginfo.h +0
-0/* * sigevent definitions * kernel/signal.c +3
-0@@ -1652,11 +1652,17 @@ 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 ignored_bits_mask = +arch_addr_ignored_bits_mask (sig, code);kernel/signal.c void force_sigsegv(int sig) · line 1665
Quoted 10 lines
kernel/signal.c +5
-2+ 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 & ~ignored_bits_mask); + info->si_xflags =SIXFLAG_ADDR_IGNORED_BITS ; + info->si_addr_ignored_bits = addr_long & ignored_bits_mask; + info->si_addr_ignored_bits_mask = ignored_bits_mask;Could we report the ignored bits optionally?
Quoted 5 lines
i.e., if
arch_addr_ignored_bits_mask()== 0, then we could perhaps leaveSIXFLAG_ADDR_IGNORED_BITSclear insi_xflags, and just set si_addr_ignored_bits{,_mask} to zeros.I can't decide myself whether this would be a good idea or not...
Since having the bit clear should be equivalent from the user's point of view to having it set with the mask equal to 0, I think I would favor the solution that would make the kernel code simpler, i.e. what I have implemented.
Quoted 12 lines
kernel/signal.c void copy_siginfo_to_external32(struct compat_siginfo *to, · line 3281
Quoted 9 lines
kernel/signal.c +2
-0} int force_sig_fault_to_task(int sig, int code, void __user *addr@@ -3271,6 +3277,8 @@ void copy_siginfo_to_external32(struct compat_siginfo *to, to->si_trapno = from->si_trapno;#endif to->si_xflags = from->si_xflags; + to->si_addr_ignored_bits = from->si_addr_ignored_bits; + to->si_addr_ignored_bits_mask = from->si_addr_ignored_bits_mask;What happens if we're delivering a signal to a compat process?
Quoted 6 lines
It looks like we apply all the usual logic, but
si_addr_ignored_bitsandsi_addr_ignored_bits_masksimply get truncated.That might be reasonable -- we don't care about bits that don't exist for compat, irrespective of what they mean for native -- but it's probably worth a comment.
If the signal originates from a compat process then I would expect the addresses involved in the fault to be 32 bits wide, so I would not expect there to be any truncation in practice. The situation is the same for si_addr I think. I can leave a comment here.
Quoted 11 lines
kernel/signal.c static int post_copy_siginfo_from_user32(kernel_siginfo_t *to, · line 3359
Quoted 9 lines
kernel/signal.c +2
-0}switch (layout) {@@ -3347,6 +3355,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_ignored_bits = from->si_addr_ignored_bits; + to->si_addr_ignored_bits_mask = from->si_addr_ignored_bits_mask;Otherwise, the patch looks reasonable.
Thanks for the review.
Peter
Quoted 222 lines · Peter Collingbourne
Quoted 144 lines · Dave Martin
Quoted 127 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]>---
View this change in Gerrit: https://linux-review.googlesource.com/q/Ia8876bad8c798e0a32df7c2ce1256c4771c81446v10:
- 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 | 17 +++++++ 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 | 59 +++++++++++++------------ arch/x86/kernel/signal_compat.c | 4 +- include/linux/compat.h | 2 + include/linux/signal.h | 8 ++++ include/uapi/asm-generic/siginfo.h | 10 +++++ kernel/signal.c | 14 +++++- 16 files changed, 122 insertions(+), 71 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_ignored_bits field +of siginfo, which is set for signals raised in response to data aborts +and instruction aborts. The si_addr_ignored_bits_mask field indicates +which bits of the field are valid. The validity of these fields is +indicated by the SIXFLAG_ADDR_IGNORED_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);[...]
Quoted 12 lines
include/linux/compat.h +2
-0@@ -234,6 +234,8 @@ typedef struct compat_siginfo {compat_uptr_t _pad[6 ]; };compat_uptr_t _xflags; +compat_uptr_t _addr_ignored_bits; +compat_uptr_t _addr_ignored_bits_mask; } _sigfault;Quoted 11 lines
include/linux/signal.h struct seq_file; · line 481
Quoted 8 lines
include/linux/compat.h +0
-0/* SIGPOLL */ include/linux/signal.h +0
-0@@ -480,4 +480,12 @@ struct seq_file;extern void render_sigset_t (struct seq_file *,const char *,sigset_t *);#endif Can we have a comment here explaining what this helper needs to do, if defined?
Will add.
Quoted 50 lines
Quoted 32 lines
include/linux/signal.h +8
-0+#ifndef arch_addr_ignored_bits_mask +static inline unsigned long arch_addr_ignored_bits_mask (unsigned long sig, +unsigned long si_code) +{ +return 0 ; +} +#endif +#endif /* _LINUX_SIGNAL_H */ include/uapi/asm-generic/siginfo.h +4
-0@@ -94,6 +94,8 @@ union __sifields {void *_pad[6 ]; };unsigned long _xflags; +unsigned long _addr_ignored_bits; +unsigned long _addr_ignored_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_ignored_bits _sifields._sigfault._addr_ignored_bits +#define si_addr_ignored_bits_mask _sifields._sigfault._addr_ignored_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._pkeyinclude/uapi/asm-generic/siginfo.h typedef struct siginfo { · line 308
Quoted 9 lines
include/uapi/asm-generic/siginfo.h +6
-0@@ -296,6 +300,12 @@ typedef struct siginfo {#define EMT_TAGOVF 1/* tag overflow */ #define NSIGEMT 1 +/* +* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP, SIGEMT si_xflags +*/ +#define SIXFLAG_ADDR_IGNORED_BITS 1 +/* si_addr_ignored_bits{,_mask} fields valid */ +I'm still uneasy about the "ignored bits" nomenclature, because the bits aren't ignored, and because at the C language level above, they generally _are_ considered part of the address.
I don't have a great suggestion for a new name, though. If we just consider the
si_addr_ignored_bitsto be attributes that accompany the address, it might make sense to call itQuoted 5 lines
si_addr_attr_bits_maskor similar.
That may or may not be considered to be less confusing.
Hmm, I wasn't entirely comfortable with "ignored" either because, as you point out, once MTE arrives some of the bits won't be ignored any more. Maybe since folks who are going to be working with these bits will probably be at least a little familiar with their use on arm64 with MTE and the tagged address ABI, we should just borrow the nomenclature from arm64 and call it:
Quoted 3 lines
si_addr_tag_bits
si_addr_tag_bits_mask
SIXFLAG_ADDR_TAG_BITS
My view on this is that the affected bits are really not address bits.
They can be thrown away precisely because they never distinguish one valid memory location from another valid memory location, nor an unmapped address from a mapped address: i.e, they make no difference to the vma (if any) the address maps to or the page within the vma, nor the offset within page (down to some granularity not coarser than the access size).
Addresses that differ only in these bits would either behave identically, be at least partially coherent (in the case of attribute flags that influence caching, for example), or would trigger some kind of check failure.
That might motivate names such as
si_addr_non_addr_bits
si_addr_valid_bits
si_addr_attr_bits
My line of reasoning might be a bit obscure though, so perhaps names of this sort are not as helpful as I'd like to think.
Quoted 32 lines
Quoted 32 lines
Quoted 15 lines
include/uapi/asm-generic/siginfo.h +0
-0/* * sigevent definitions * kernel/signal.c +3
-0@@ -1652,11 +1652,17 @@ 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 ignored_bits_mask = +arch_addr_ignored_bits_mask (sig, code);kernel/signal.c void force_sigsegv(int sig) · line 1665
Quoted 10 lines
kernel/signal.c +5
-2+ 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 & ~ignored_bits_mask); + info->si_xflags =SIXFLAG_ADDR_IGNORED_BITS ; + info->si_addr_ignored_bits = addr_long & ignored_bits_mask; + info->si_addr_ignored_bits_mask = ignored_bits_mask;Could we report the ignored bits optionally?
i.e., if
arch_addr_ignored_bits_mask()== 0, then we could perhaps leaveSIXFLAG_ADDR_IGNORED_BITSclear insi_xflags, and just set si_addr_ignored_bits{,_mask} to zeros.
Quoted 6 lines
Quoted 1 line
I can't decide myself whether this would be a good idea or not...
Since having the bit clear should be equivalent from the user's point of view to having it set with the mask equal to 0, I think I would favor the solution that would make the kernel code simpler, i.e. what I have implemented.
OK, that's reasonable.
Quoted 15 lines
Quoted 15 lines
kernel/signal.c void copy_siginfo_to_external32(struct compat_siginfo *to, · line 3281
Quoted 9 lines
kernel/signal.c +2
-0} int force_sig_fault_to_task(int sig, int code, void __user *addr@@ -3271,6 +3277,8 @@ void copy_siginfo_to_external32(struct compat_siginfo *to, to->si_trapno = from->si_trapno;#endif to->si_xflags = from->si_xflags; + to->si_addr_ignored_bits = from->si_addr_ignored_bits; + to->si_addr_ignored_bits_mask = from->si_addr_ignored_bits_mask;What happens if we're delivering a signal to a compat process?
It looks like we apply all the usual logic, but
si_addr_ignored_bitsandsi_addr_ignored_bits_masksimply get truncated.
Quoted 8 lines
Quoted 3 lines
That might be reasonable -- we don't care about bits that don't exist for compat, irrespective of what they mean for native -- but it's probably worth a comment.
If the signal originates from a compat process then I would expect the addresses involved in the fault to be 32 bits wide, so I would not expect there to be any truncation in practice. The situation is the same for
si_addrI think. I can leave a comment here.
OK, sounds fair.
We generally don't see 32-bit arches repurposing bits in the address, since they tend to need all of them for addressing (unless, possibly, when running some kind of low-footprint binary environment where backwards compatibility isn't a concern -- not likely to be applicable to Linux userspace).
Quoted 12 lines
Quoted 11 lines
kernel/signal.c static int post_copy_siginfo_from_user32(kernel_siginfo_t *to, · line 3359
Quoted 9 lines
kernel/signal.c +2
-0}switch (layout) {@@ -3347,6 +3355,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_ignored_bits = from->si_addr_ignored_bits; + to->si_addr_ignored_bits_mask = from->si_addr_ignored_bits_mask;Otherwise, the patch looks reasonable.
Quoted 3 lines
Thanks for the review.
Peter
Cheers
---Dave