Skip to contentSkip to conversation

arm64: expose FAR_EL1 tag bits in siginfo

PATCH Superseded Peter Collingbourne 3 participants 31 messages Aug 22, 2020 – Oct 12, 2020

Subsystems (14)

v10 of 20 Superseded Latest is v20 →

lore
Share & tools
lore
#0 lore raw

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
#1 lore raw

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
index d38563a394f2..92a1c7ea44b4 100644
@@ -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
index e9304c95ceea..ecdf6312bfa5 100644
@@ -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
maintainer Acked-by on v10 1/7
#2 lore raw

Re: [PATCH v10 1/7] parisc: start using signal-defs.h

Quoted 3 lines · Peter Collingbourne

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.

The patch is basically OK, but....

Quoted 34 lines

---
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
index d38563a394f2..92a1c7ea44b4 100644
@@ -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
index e9304c95ceea..ecdf6312bfa5 100644
@@ -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;

#3 lore raw

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.h on 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

---
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
index d38563a394f2..92a1c7ea44b4 100644
@@ -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
index e9304c95ceea..ecdf6312bfa5 100644
@@ -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.

Quoted 4 lines

Other than that you can add:

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

maintainer
#4 lore raw

Re: [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.h on 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

---
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
index d38563a394f2..92a1c7ea44b4 100644
@@ -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
index e9304c95ceea..ecdf6312bfa5 100644
@@ -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:

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
index f1fd4fa880d7..e67b1bfb82ba 100644
@@ -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

#5 lore raw

Re: [PATCH v10 1/7] parisc: start using signal-defs.h

In reply to Peter Collingbourne
Quoted 38 lines · Peter Collingbourne

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
index d38563a394f2..92a1c7ea44b4 100644
@@ -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
index e9304c95ceea..ecdf6312bfa5 100644
@@ -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

#6 lore raw

PATCH v10 2/7 arch: move SA_* definitions to generic headers

In reply to 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.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
index 74c750bf1c1a..a69dd8d080a8 100644
@@ -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
index 9b4185ba4f8a..7727f0984d26 100644
@@ -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
index e15521037348..2cd0dce2b6a6 100644
@@ -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
index aa98ff1b9e22..38166a88e4c9 100644
@@ -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
index 915cc755a184..4619291df601 100644
@@ -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
index 53104b10aae2..e6c78a15cb2f 100644
@@ -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
index 92a1c7ea44b4..32ec2e64c6ca 100644
@@ -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
index 85b0a7aa43e7..04873dd311c2 100644
@@ -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
index 9a14a611ed82..0189f326aac5 100644
@@ -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
index ff9505923b9a..53758d53ac0e 100644
@@ -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
index e5745d593dc7..164a22a72984 100644
@@ -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
index 005dec5bfde4..79ddabaa4e5d 100644
@@ -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
index 5c716a952cbe..f634822906e4 100644
@@ -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 !defined MINSIGSTKSZ || !defined SIGSTKSZ
 #define MINSIGSTKSZ	2048
 #define SIGSTKSZ	8192
Signature · 1 line
2.28.0.297.g1956fa8f8d-goog
#7 lore raw

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.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.

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

#8 lore raw

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.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.

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_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.

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_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.

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

#9 lore raw

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.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.

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_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.

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_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 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_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.

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_RESETHAND would 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

#10 lore raw

PATCH v10 3/7 signal: clear non-uapi flag bits when passing/returning sa_flags

In reply to Peter Collingbourne

Previously 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
index 65530a042009..430be7774402 100644
@@ -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
index 715c96ba2ec8..30dd1e43ef88 100644
@@ -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
index 9ccbf0576cd0..c599013ae8cb 100644
@@ -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
index f8a90ae9c6ec..a7887ad84d36 100644
@@ -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
index 42b67d2cea37..f802c82c7bcc 100644
@@ -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
#11 lore raw

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_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
index 65530a042009..430be7774402 100644
@@ -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
index 715c96ba2ec8..30dd1e43ef88 100644
@@ -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
index 9ccbf0576cd0..c599013ae8cb 100644
@@ -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
index f8a90ae9c6ec..a7887ad84d36 100644
@@ -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
index 42b67d2cea37..f802c82c7bcc 100644
@@ -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

#12 lore raw

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_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
index 65530a042009..430be7774402 100644
@@ -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
index 715c96ba2ec8..30dd1e43ef88 100644
@@ -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
index 9ccbf0576cd0..c599013ae8cb 100644
@@ -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
index f8a90ae9c6ec..a7887ad84d36 100644
@@ -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

#13 lore raw

PATCH v10 4/7 signal: define the SA_UNSUPPORTED bit in sa_flags

In reply to Peter Collingbourne

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_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
index 319628058a53..e853cbe8722d 100644
@@ -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
index f802c82c7bcc..c80e70bde11d 100644
@@ -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
Reviewed-by on v10 4/7
#14 lore raw

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_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.

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

---
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 +6 -0
index 319628058a53..e853cbe8722d 100644
@@ -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_RESETHAND
kernel/signal.c +0 -0
index f802c82c7bcc..c80e70bde11d 100644

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

#15 lore raw

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_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.

Quoted 4 lines

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.

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

---
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 +6 -0
index 319628058a53..e853cbe8722d 100644
@@ -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_RESETHAND
kernel/signal.c +0 -0
index f802c82c7bcc..c80e70bde11d 100644

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.

Quoted 4 lines

With the above rewording in the commit message to clarify that a second sigaction() is needed:

Thanks for the review.

Peter

#16 lore raw

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_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.

Quoted 4 lines

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.

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_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.

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

#17 lore raw

PATCH v10 5/7 signal: deduplicate code dealing with common _sigfault fields

In reply to Peter Collingbourne

We'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
index 6bb1a3f0258c..3edbf54493ee 100644
@@ -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
#18 lore raw

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 _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
index 6bb1a3f0258c..3edbf54493ee 100644
@@ -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
index c80e70bde11d..4ee9dc03f20f 100644
@@ -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 *addr
 	struct 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 *addr
 	struct 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 -16
 	case 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

#19 lore raw

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 _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
index 6bb1a3f0258c..3edbf54493ee 100644
@@ -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
index c80e70bde11d..4ee9dc03f20f 100644
@@ -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 *addr
      struct 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 *addr
      struct 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.

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 -16
      case 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

#20 lore raw

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 _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
index 6bb1a3f0258c..3edbf54493ee 100644
@@ -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
index c80e70bde11d..4ee9dc03f20f 100644
@@ -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 *addr
      struct 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 *addr
      struct 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.

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.

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 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.

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

#21 lore raw

PATCH v10 6/7 signal: define the field siginfo.si_xflags

In reply to Peter Collingbourne

This 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
index 3d21fce254b7..3bbb335561f5 100644
@@ -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
index c599013ae8cb..6b99f0c8a068 100644
@@ -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
index d38c4d7e83bd..55d4228dfd88 100644
@@ -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
index a7887ad84d36..75ca861d982a 100644
@@ -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
index cb3d6c267181..1fbd88d64f38 100644
@@ -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
index e853cbe8722d..bdbe1fe7a779 100644
@@ -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
index a71b6e3b03eb..de5ebd5b0fae 100644
@@ -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
index 43d6179508d6..11ee5e2d65ff 100644
@@ -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
index 4ee9dc03f20f..4259903b95cb 100644
@@ -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
#22 lore raw

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 _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

Quoted 7 lines

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.

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_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.

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 _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.

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_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.

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

---
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
index 3d21fce254b7..3bbb335561f5 100644
@@ -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
index c599013ae8cb..6b99f0c8a068 100644

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 -0
 	BUILD_BUG_ON(offsetof(siginfo_t, si_addr) != 0x10);
 	BUILD_BUG_ON(offsetof(compat_siginfo_t, si_addr) != 0x0C);
include/linux/compat.h +0 -0
index d38c4d7e83bd..55d4228dfd88 100644

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
index a7887ad84d36..75ca861d982a 100644
@@ -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
index cb3d6c267181..1fbd88d64f38 100644

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._pkey
include/uapi/asm-generic/signal-defs.h +0 -0
index e853cbe8722d..bdbe1fe7a779 100644

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

#23 lore raw

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 _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

Quoted 7 lines

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.

I would say >. 0 is SI_USER, and the fact that those other interfaces reject SI_USER seems inconsistent or a bug.

Quoted 7 lines

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.

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_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.

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_flags bit 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 _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.

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_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.

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_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.

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

---
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
index 3d21fce254b7..3bbb335561f5 100644
@@ -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
index c599013ae8cb..6b99f0c8a068 100644

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 -0
      BUILD_BUG_ON(offsetof(siginfo_t, si_addr) != 0x10);
      BUILD_BUG_ON(offsetof(compat_siginfo_t, si_addr) != 0x0C);
include/linux/compat.h +0 -0
index d38c4d7e83bd..55d4228dfd88 100644

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?

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 _xflags that 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
index a7887ad84d36..75ca861d982a 100644
@@ -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
index cb3d6c267181..1fbd88d64f38 100644

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?

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._pkey
include/uapi/asm-generic/signal-defs.h +0 -0
index e853cbe8722d..bdbe1fe7a779 100644
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

#24 lore raw

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 _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

Quoted 7 lines

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.

I would say >. 0 is SI_USER, and the fact that those other interfaces reject SI_USER seems inconsistent or a bug.

Quoted 7 lines

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.

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_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.

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_flags bit 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 _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.

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_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.

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_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.

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

---
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
index 3d21fce254b7..3bbb335561f5 100644
@@ -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
index c599013ae8cb..6b99f0c8a068 100644

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 -0
      BUILD_BUG_ON(offsetof(siginfo_t, si_addr) != 0x10);
      BUILD_BUG_ON(offsetof(compat_siginfo_t, si_addr) != 0x0C);
include/linux/compat.h +0 -0
index d38c4d7e83bd..55d4228dfd88 100644

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?

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 _xflags that 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).

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

#25 lore raw

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
index d38c4d7e83bd..55d4228dfd88 100644
@@ -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 _xflags that 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 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

#26 lore raw

Re: [PATCH v10 6/7] signal: define the field siginfo.si_xflags

In reply to Peter Collingbourne
Quoted 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 _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

Quoted 7 lines

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.

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?

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_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.

OK, makes sense.

Quoted 14 lines
Quoted 6 lines
Quoted 5 lines

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.

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_flags bit 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_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.

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_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.

Ack

Quoted 25 lines
Quoted 19 lines
Quoted 4 lines

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.

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_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.

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_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.

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

---
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
index 3d21fce254b7..3bbb335561f5 100644
@@ -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
index c599013ae8cb..6b99f0c8a068 100644

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 -0
      BUILD_BUG_ON(offsetof(siginfo_t, si_addr) != 0x10);
      BUILD_BUG_ON(offsetof(compat_siginfo_t, si_addr) != 0x0C);
include/linux/compat.h +0 -0
index d38c4d7e83bd..55d4228dfd88 100644

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?

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 _xflags that 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).

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
index a7887ad84d36..75ca861d982a 100644
@@ -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
index cb3d6c267181..1fbd88d64f38 100644

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.

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.

[1] https://www.spinics.net/lists/arm-kernel/msg808618.html

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._pkey
include/uapi/asm-generic/signal-defs.h +0 -0
index e853cbe8722d..bdbe1fe7a779 100644
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 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

#27 lore raw

PATCH v10 7/7 arm64: expose FAR_EL1 tag bits in siginfo

In reply to 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_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
index eab4323609b9..14273160b38b 100644
@@ -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
index 7577a754d443..950d55dae948 100644
@@ -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
new file mode 100644
index 000000000000..038cc9784c57
@@ -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
index 1ab63cfbbaf1..673be2d1263c 100644
@@ -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
index cee5928e1b7d..9bb5376608d3 100644
@@ -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
index 7310a4f7f993..943e932def37 100644
@@ -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
index d3be9dbf5490..65ed01606480 100644
@@ -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
index d8ebfd813e28..3f12c731fa9a 100644
@@ -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
index 3c18c2454089..265fe3eb1069 100644
@@ -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
index 13ebd5ca2070..8f8105076f92 100644
@@ -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
index 6b99f0c8a068..9a40c47f66c2 100644
@@ -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
index 55d4228dfd88..273146cf30fd 100644
@@ -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
index 3edbf54493ee..b4c473c12a9b 100644
@@ -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
index 1fbd88d64f38..e314a38ce2d0 100644
@@ -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
index 4259903b95cb..29654652d3aa 100644
@@ -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
#28 lore raw
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_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
index eab4323609b9..14273160b38b 100644
@@ -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
index 7577a754d443..950d55dae948 100644
@@ -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
index 55d4228dfd88..273146cf30fd 100644
@@ -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
index 3edbf54493ee..b4c473c12a9b 100644

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
index 1fbd88d64f38..e314a38ce2d0 100644
@@ -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
index 4259903b95cb..29654652d3aa 100644
@@ -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

#29 lore raw
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_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
index eab4323609b9..14273160b38b 100644
@@ -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
index 7577a754d443..950d55dae948 100644
@@ -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
index 55d4228dfd88..273146cf30fd 100644
@@ -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
index 3edbf54493ee..b4c473c12a9b 100644
@@ -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
index 1fbd88d64f38..e314a38ce2d0 100644
@@ -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

Quoted 5 lines

si_addr_attr_bits_mask

or 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
index 4259903b95cb..29654652d3aa 100644
@@ -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 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...

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_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.

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

#30 lore raw
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_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
index eab4323609b9..14273160b38b 100644
@@ -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
index 7577a754d443..950d55dae948 100644
@@ -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
index 55d4228dfd88..273146cf30fd 100644
@@ -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
index 3edbf54493ee..b4c473c12a9b 100644
@@ -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
index 1fbd88d64f38..e314a38ce2d0 100644
@@ -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

Quoted 5 lines

si_addr_attr_bits_mask

or 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
index 4259903b95cb..29654652d3aa 100644
@@ -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.

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_bits and si_addr_ignored_bits_mask simply 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_addr I 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