Skip to contentSkip to conversation

arm64: expose FAR_EL1 tag bits in siginfo

PATCH Superseded Peter Collingbourne 4 participants 26 messages Nov 3, 2020 – Nov 4, 2020

Subsystems (15)

v13 of 20 Superseded Latest is v20 →

lore
Share & tools
lore
#0 lore raw

v13 cover arm64: expose FAR_EL1 tag bits in siginfo

The kernel currently clears the tag bits (i.e. bits 56-63) in the fault address exposed via siginfo.si_addr and sigcontext.fault_address. However, the tag bits may be needed by tools in order to accurately diagnose memory errors, such as HWASan [1] or future tools based on the Memory Tagging Extension (MTE).

We should not stop clearing these bits in the existing fault address fields, because there may be existing userspace applications that are expecting the tag bits to be cleared. Instead, create a new pair of union fields in siginfo._sigfault, and store the tag bits of FAR_EL1 there, together with a mask specifying which bits are valid.

However, one does not simply add fields to siginfo, at least not without a mechanism for userspace to detect that they are present and valid. Therefore, the first seven patches in this series introduce a mechanism for userspace to detect the presence of our new siginfo fields, and the last patch uses it to advertise the presence of said fields.

The series can be viewed on Gerrit here:
https://linux-review.googlesource.com/q/Ia8876bad8c798e0a32df7c2ce1256c4771c81446

[1] http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html

Helge Deller (1):
parisc: Drop parisc special case for __sighandler_t

Peter Collingbourne (7):
parisc: start using signal-defs.h
arch: move SA_* definitions to generic headers
signal: clear non-uapi flag bits when passing/returning sa_flags
signal: define the SA_UNSUPPORTED bit in sa_flags
signal: deduplicate code dealing with common _sigfault fields
signal: define the field siginfo.si_faultflags
arm64: expose FAR_EL1 tag bits in siginfo

 Documentation/arm64/tagged-pointers.rst    |  21 +++-
 arch/alpha/include/uapi/asm/signal.h       |  14 ---
 arch/arm/include/asm/signal.h              |   2 +
 arch/arm/include/uapi/asm/signal.h         |  28 +----
 arch/arm64/include/asm/exception.h         |   2 +-
 arch/arm64/include/asm/signal.h            |  19 +++
 arch/arm64/include/asm/system_misc.h       |   2 +-
 arch/arm64/include/asm/traps.h             |   6 +-
 arch/arm64/kernel/debug-monitors.c         |   5 +-
 arch/arm64/kernel/entry-common.c           |   2 -
 arch/arm64/kernel/ptrace.c                 |   7 +-
 arch/arm64/kernel/sys_compat.c             |   5 +-
 arch/arm64/kernel/traps.c                  |  29 ++---
 arch/arm64/mm/fault.c                      |  68 ++++++-----
 arch/h8300/include/uapi/asm/signal.h       |  24 ----
 arch/ia64/include/uapi/asm/signal.h        |  24 ----
 arch/m68k/include/uapi/asm/signal.h        |  24 ----
 arch/mips/include/uapi/asm/signal.h        |  12 --
 arch/parisc/include/asm/signal.h           |   2 +
 arch/parisc/include/uapi/asm/signal.h      |  34 +-----
 arch/powerpc/include/uapi/asm/signal.h     |  24 ----
 arch/powerpc/platforms/powernv/vas-fault.c |   1 +
 arch/s390/include/uapi/asm/signal.h        |  24 ----
 arch/sparc/include/uapi/asm/signal.h       |   4 +-
 arch/x86/include/uapi/asm/signal.h         |  24 ----
 arch/x86/kernel/signal_compat.c            |  19 +--
 arch/xtensa/include/uapi/asm/signal.h      |  24 ----
 include/linux/compat.h                     |   4 +
 include/linux/signal.h                     |  29 +++++
 include/linux/signal_types.h               |  12 ++
 include/uapi/asm-generic/siginfo.h         |  14 +++
 include/uapi/asm-generic/signal-defs.h     |  58 +++++++++
 include/uapi/asm-generic/signal.h          |  29 -----
 include/uapi/linux/ptrace.h                |  12 ++
 kernel/ptrace.c                            |  33 ++++-
 kernel/signal.c                            | 134 +++++++++++----------
 36 files changed, 346 insertions(+), 429 deletions(-)
 create mode 100644 arch/arm64/include/asm/signal.h
Signature · 1 line
2.29.1.341.ge80a0c044ae-goog
#1 lore raw

PATCH v13 1/8 parisc: Drop parisc special case for __sighandler_t

From: Helge Deller <[email protected]>

I believe we can and *should* drop this parisc-specific typedef for __sighandler_t when compiling a 64-bit kernel. The reasons:

1. We don't have a 64-bit userspace yet, so nothing (on userspace side) can break.

2. Inside the Linux kernel, this is only used in kernel/signal.c, in function kernel_sigaction() where the signal handler is compared against SIG_IGN. SIG_IGN is defined as (__sighandler_t)1), so only the pointers are compared.

3. Even when a 64-bit userspace gets added at some point, I think __sighandler_t should be defined what it is: a function pointer struct.

I compiled kernel/signal.c with and without the patch, and the produced code is identical in both cases.

---
 arch/parisc/include/uapi/asm/signal.h | 8 --------
 1 file changed, 8 deletions(-)
arch/parisc/include/uapi/asm/signal.h +0 -8
index e605197b462c..d9c51769851a 100644
@@ -85,16 +85,8 @@
 struct siginfo;
 
 /* Type of a signal handler.  */
-#if defined(__LP64__)
-/* function pointers on 64-bit parisc are pointers to little structs and the
- * compiler doesn't support code which changes or tests the address of
- * the function in the little struct.  This is really ugly -PB
- */
-typedef char __user *__sighandler_t;
-#else
 typedef void __signalfn_t(int);
 typedef __signalfn_t __user *__sighandler_t;
-#endif
 
 typedef struct sigaltstack {
 	void __user *ss_sp;
Signature · 1 line
2.29.1.341.ge80a0c044ae-goog
Acked-by on v13 1/8
#2 lore raw

Re: [PATCH v13 1/8] parisc: Drop parisc special case for __sighandler_t

Quoted 16 lines · Peter Collingbourne

From: Helge Deller <[email protected]>

I believe we can and *should* drop this parisc-specific typedef for __sighandler_t when compiling a 64-bit kernel. The reasons:

1. We don't have a 64-bit userspace yet, so nothing (on userspace side) can break.

2. Inside the Linux kernel, this is only used in kernel/signal.c, in function kernel_sigaction() where the signal handler is compared against SIG_IGN. SIG_IGN is defined as (__sighandler_t)1), so only the pointers are compared.

3. Even when a 64-bit userspace gets added at some point, I think __sighandler_t should be defined what it is: a function pointer struct.

Quoted 7 lines

I compiled kernel/signal.c with and without the patch, and the produced code is identical in both cases.

Link:
https://linux-review.googlesource.com/id/I21c43f21b264f339e3aa395626af838646f62d97

Peter as you have sent this, this also needs your Signed-off-by.

Otherwise this looks reasonable to me.

While the final bits look like they are still under discussion it looks like the preceding cleanups are pretty solid at this point.

Any chance we can get the cleanups into a tree in linux-next so that the discussion can focus on the core parts of this work?

Perhaps I should pick up the clenaups?

Eric

Quoted 25 lines
---
 arch/parisc/include/uapi/asm/signal.h | 8 --------
 1 file changed, 8 deletions(-)
arch/parisc/include/uapi/asm/signal.h +0 -8
index e605197b462c..d9c51769851a 100644
@@ -85,16 +85,8 @@
 struct siginfo;
 
 /* Type of a signal handler.  */
-#if defined(__LP64__)
-/* function pointers on 64-bit parisc are pointers to little structs and the
- * compiler doesn't support code which changes or tests the address of
- * the function in the little struct.  This is really ugly -PB
- */
-typedef char __user *__sighandler_t;
-#else
 typedef void __signalfn_t(int);
 typedef __signalfn_t __user *__sighandler_t;
-#endif
 
 typedef struct sigaltstack {
 	void __user *ss_sp;
maintainer
#3 lore raw

Re: [PATCH v13 1/8] parisc: Drop parisc special case for __sighandler_t

Quoted 25 lines · Eric W. Biederman
Quoted 16 lines · Peter Collingbourne

From: Helge Deller <[email protected]>

I believe we can and *should* drop this parisc-specific typedef for __sighandler_t when compiling a 64-bit kernel. The reasons:

1. We don't have a 64-bit userspace yet, so nothing (on userspace side) can break.

2. Inside the Linux kernel, this is only used in kernel/signal.c, in function kernel_sigaction() where the signal handler is compared against SIG_IGN. SIG_IGN is defined as (__sighandler_t)1), so only the pointers are compared.

3. Even when a 64-bit userspace gets added at some point, I think __sighandler_t should be defined what it is: a function pointer struct.

Quoted 7 lines

I compiled kernel/signal.c with and without the patch, and the produced code is identical in both cases.

Link:
https://linux-review.googlesource.com/id/I21c43f21b264f339e3aa395626af838646f62d97

Quoted 7 lines

Peter as you have sent this, this also needs your Signed-off-by.

Otherwise this looks reasonable to me.

While the final bits look like they are still under discussion it looks like the preceding cleanups are pretty solid at this point.

Minor nits, unless you nak the whole approach of SA_FAULTFLAGS and SA_UNSUPPORTED ;) (it looks a bit complicated to me but I don't have a better idea for a generic implementation).

Quoted 4 lines

Any chance we can get the cleanups into a tree in linux-next so that the discussion can focus on the core parts of this work?

Perhaps I should pick up the clenaups?

However you prefer (I usually start queuing patches at -rc3). If you pick them up, please provide a stable branch somewhere so that we can add the others on top.

Thanks.

Signature · 1 line
Catalin
#4 lore raw

Re: [PATCH v13 1/8] parisc: Drop parisc special case for __sighandler_t

Quoted 38 lines · Catalin Marinas
Quoted 25 lines · Eric W. Biederman
Quoted 16 lines · Peter Collingbourne

From: Helge Deller <[email protected]>

I believe we can and *should* drop this parisc-specific typedef for __sighandler_t when compiling a 64-bit kernel. The reasons:

1. We don't have a 64-bit userspace yet, so nothing (on userspace side) can break.

2. Inside the Linux kernel, this is only used in kernel/signal.c, in function kernel_sigaction() where the signal handler is compared against SIG_IGN. SIG_IGN is defined as (__sighandler_t)1), so only the pointers are compared.

3. Even when a 64-bit userspace gets added at some point, I think __sighandler_t should be defined what it is: a function pointer struct.

Quoted 7 lines

I compiled kernel/signal.c with and without the patch, and the produced code is identical in both cases.

Link:
https://linux-review.googlesource.com/id/I21c43f21b264f339e3aa395626af838646f62d97

Quoted 7 lines

Peter as you have sent this, this also needs your Signed-off-by.

Otherwise this looks reasonable to me.

While the final bits look like they are still under discussion it looks like the preceding cleanups are pretty solid at this point.

Minor nits, unless you nak the whole approach of SA_FAULTFLAGS and SA_UNSUPPORTED ;) (it looks a bit complicated to me but I don't have a better idea for a generic implementation).

Quoted 8 lines
Quoted 4 lines

Any chance we can get the cleanups into a tree in linux-next so that the discussion can focus on the core parts of this work?

Perhaps I should pick up the clenaups?

However you prefer (I usually start queuing patches at -rc3). If you pick them up, please provide a stable branch somewhere so that we can add the others on top.

I just want to make certain the cleanups don't get lost in the shuffle.

If we are almost there then I will focus my energy on reviewing the patches and make certain there isn't something important that has been overlooked. I don't expect there is.

Eric

#5 lore raw

Re: [PATCH v13 1/8] parisc: Drop parisc special case for __sighandler_t

In reply to Catalin Marinas
Quoted 31 lines · Catalin Marinas
Quoted 30 lines · Eric W. Biederman
Quoted 16 lines · Peter Collingbourne

From: Helge Deller <[email protected]>

I believe we can and *should* drop this parisc-specific typedef for __sighandler_t when compiling a 64-bit kernel. The reasons:

1. We don't have a 64-bit userspace yet, so nothing (on userspace side) can break.

2. Inside the Linux kernel, this is only used in kernel/signal.c, in function kernel_sigaction() where the signal handler is compared against SIG_IGN. SIG_IGN is defined as (__sighandler_t)1), so only the pointers are compared.

3. Even when a 64-bit userspace gets added at some point, I think __sighandler_t should be defined what it is: a function pointer struct.

Quoted 7 lines

I compiled kernel/signal.c with and without the patch, and the produced code is identical in both cases.

Link:
https://linux-review.googlesource.com/id/I21c43f21b264f339e3aa395626af838646f62d97

Peter as you have sent this, this also needs your Signed-off-by.

Otherwise this looks reasonable to me.

Quoted 6 lines
Quoted 2 lines

While the final bits look like they are still under discussion it looks like the preceding cleanups are pretty solid at this point.

Minor nits, unless you nak the whole approach of SA_FAULTFLAGS and SA_UNSUPPORTED ;) (it looks a bit complicated to me but I don't have a better idea for a generic implementation).

It is a bit complicated, but we didn't come up with anything better so far that can cope with the various historical quirks in the signal API.

A bigger overhaul of the whole interface might be a good idea at some point, but it would probably be a mistake to rush that.

It may be possible to make the SA_UNSUPPORTED stuff a bit more digestible via libc. I'll try to get a discussion started on that.

[...]

Cheers
---Dave

#6 lore raw

Re: [PATCH v13 1/8] parisc: Drop parisc special case for __sighandler_t

In reply to Catalin Marinas
Quoted 27 lines · Catalin Marinas
Quoted 25 lines · Eric W. Biederman
Quoted 23 lines · Peter Collingbourne

From: Helge Deller <[email protected]>

I believe we can and *should* drop this parisc-specific typedef for __sighandler_t when compiling a 64-bit kernel. The reasons:

1. We don't have a 64-bit userspace yet, so nothing (on userspace side) can break.

2. Inside the Linux kernel, this is only used in kernel/signal.c, in function kernel_sigaction() where the signal handler is compared against SIG_IGN. SIG_IGN is defined as (__sighandler_t)1), so only the pointers are compared.

3. Even when a 64-bit userspace gets added at some point, I think __sighandler_t should be defined what it is: a function pointer struct.

I compiled kernel/signal.c with and without the patch, and the produced code is identical in both cases.

Link:
https://linux-review.googlesource.com/id/I21c43f21b264f339e3aa395626af838646f62d97

Quoted 4 lines
Quoted 4 lines

Peter as you have sent this, this also needs your Signed-off-by.

Otherwise this looks reasonable to me.

Thanks, likewise for the other patches that you acked.

Quoted 7 lines
Quoted 2 lines

While the final bits look like they are still under discussion it looks like the preceding cleanups are pretty solid at this point.

Minor nits, unless you nak the whole approach of SA_FAULTFLAGS and SA_UNSUPPORTED ;) (it looks a bit complicated to me but I don't have a better idea for a generic implementation).

Quoted 8 lines
Quoted 4 lines

Any chance we can get the cleanups into a tree in linux-next so that the discussion can focus on the core parts of this work?

Perhaps I should pick up the clenaups?

However you prefer (I usually start queuing patches at -rc3). If you pick them up, please provide a stable branch somewhere so that we can add the others on top.

Picking up the cleanups first sounds good to me and I don't mind which tree they go via. To make it easier to pick up just the cleanups I will reorder the patches a bit. I will move patch 6 to patch 4 so that 1-4 are the non-uapi-affecting cleanups and 5-8 implement the substantive changes.

Peter

#7 lore raw

PATCH v13 2/8 parisc: start using signal-defs.h

In reply to 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.

---
 arch/parisc/include/uapi/asm/signal.h | 13 +------------
 1 file changed, 1 insertion(+), 12 deletions(-)
arch/parisc/include/uapi/asm/signal.h +1 -12
index d9c51769851a..9e6f87bc8a73 100644
@@ -68,14 +68,7 @@
 #define MINSIGSTKSZ	2048
 #define SIGSTKSZ	8192
 
-
-#define SIG_BLOCK          0	/* for blocking signals */
-#define SIG_UNBLOCK        1	/* for unblocking signals */
-#define SIG_SETMASK        2	/* for setting the signal mask */
-
-#define SIG_DFL	((__sighandler_t)0)	/* default signal handling */
-#define SIG_IGN	((__sighandler_t)1)	/* ignore signal */
-#define SIG_ERR	((__sighandler_t)-1)	/* error return from signal */
+#include <asm-generic/signal-defs.h>
 
 # ifndef __ASSEMBLY__
 
@@ -84,10 +77,6 @@
 /* Avoid too many header ordering problems.  */
 struct siginfo;
 
-/* Type of a signal handler.  */
-typedef void __signalfn_t(int);
-typedef __signalfn_t __user *__sighandler_t;
-
 typedef struct sigaltstack {
 	void __user *ss_sp;
 	int ss_flags;
Signature · 1 line
2.29.1.341.ge80a0c044ae-goog
Acked-by on v13 2/8
#8 lore raw

Re: [PATCH v13 2/8] parisc: start using signal-defs.h

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

Quoted 35 lines
---
 arch/parisc/include/uapi/asm/signal.h | 13 +------------
 1 file changed, 1 insertion(+), 12 deletions(-)
arch/parisc/include/uapi/asm/signal.h +1 -12
index d9c51769851a..9e6f87bc8a73 100644
@@ -68,14 +68,7 @@
 #define MINSIGSTKSZ	2048
 #define SIGSTKSZ	8192
 
-
-#define SIG_BLOCK          0	/* for blocking signals */
-#define SIG_UNBLOCK        1	/* for unblocking signals */
-#define SIG_SETMASK        2	/* for setting the signal mask */
-
-#define SIG_DFL	((__sighandler_t)0)	/* default signal handling */
-#define SIG_IGN	((__sighandler_t)1)	/* ignore signal */
-#define SIG_ERR	((__sighandler_t)-1)	/* error return from signal */
+#include <asm-generic/signal-defs.h>
 
 # ifndef __ASSEMBLY__
 
@@ -84,10 +77,6 @@
 /* Avoid too many header ordering problems.  */
 struct siginfo;
 
-/* Type of a signal handler.  */
-typedef void __signalfn_t(int);
-typedef __signalfn_t __user *__sighandler_t;
-
 typedef struct sigaltstack {
 	void __user *ss_sp;
 	int ss_flags;
#9 lore raw

PATCH v13 3/8 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.

A consequence of this change is that on powerpc and x86, the constants' values aside from SA_RESETHAND change signedness from unsigned to signed. This is not expected to impact realistic use of these constants. In particular the typical use of the constants where they are or'ed together and assigned to sa_flags (or another int variable) would not be affected.

---
v11:
- tweak the commit message to point out the change from unsigned to signed

v10:
- move the comments around and add one for SA_SIGINFO

 arch/alpha/include/uapi/asm/signal.h   | 14 --------
 arch/arm/include/uapi/asm/signal.h     | 28 ++-------------
 arch/h8300/include/uapi/asm/signal.h   | 24 -------------
 arch/ia64/include/uapi/asm/signal.h    | 24 -------------
 arch/m68k/include/uapi/asm/signal.h    | 24 -------------
 arch/mips/include/uapi/asm/signal.h    | 12 -------
 arch/parisc/include/uapi/asm/signal.h  | 13 -------
 arch/powerpc/include/uapi/asm/signal.h | 24 -------------
 arch/s390/include/uapi/asm/signal.h    | 24 -------------
 arch/sparc/include/uapi/asm/signal.h   |  4 +--
 arch/x86/include/uapi/asm/signal.h     | 24 -------------
 arch/xtensa/include/uapi/asm/signal.h  | 24 -------------
 include/uapi/asm-generic/signal-defs.h | 47 ++++++++++++++++++++++++++
 include/uapi/asm-generic/signal.h      | 29 ----------------
 14 files changed, 51 insertions(+), 264 deletions(-)
arch/alpha/include/uapi/asm/signal.h +0 -14
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 9e6f87bc8a73..e5a2657477ac 100644
@@ -41,19 +41,6 @@
 #define SIGRTMIN	32
 #define SIGRTMAX	_NSIG
 
-/*
- * SA_FLAGS values:
- *
- * SA_ONSTACK indicates that a registered stack_t will be used.
- * SA_RESTART flag to get restarting signals (which were the default long ago)
- * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
- * SA_RESETHAND clears the handler when the signal is delivered.
- * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
- * SA_NODEFER prevents the current signal from being masked in the handler.
- *
- * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
- * Unix names RESETHAND and NODEFER respectively.
- */
 #define SA_ONSTACK	0x00000001
 #define SA_RESETHAND	0x00000004
 #define SA_NOCLDSTOP	0x00000008
arch/powerpc/include/uapi/asm/signal.h +0 -24
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.29.1.341.ge80a0c044ae-goog
Acked-by on v13 3/8
#10 lore raw

Re: [PATCH v13 3/8] arch: move SA_* definitions to generic headers

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

Quoted 6 lines

A consequence of this change is that on powerpc and x86, the constants' values aside from SA_RESETHAND change signedness from unsigned to signed. This is not expected to impact realistic use of these constants. In particular the typical use of the constants where they are or'ed together and assigned to sa_flags (or another int variable) would not be affected.

Except for the removal of SA_RESTORER on arm (see below).

Quoted 36 lines

---
v11:
- tweak the commit message to point out the change from unsigned to signed

v10:
- move the comments around and add one for SA_SIGINFO

arch/arm/include/uapi/asm/signal.h +0 -14
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.

arch/arm/include/uapi/asm/signal.h typedef unsigned long sigset_t; · line 83

Quoted 10 lines
arch/arm/include/uapi/asm/signal.h +3 -4
+ * 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

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Was removing SA_RESTOER from arm a typo?
If not it is probably better to move the removal into a separate patch.

Quoted 10 lines
arch/arm/include/uapi/asm/signal.h +0 -7
-#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

#11 lore raw

Re: [PATCH v13 3/8] arch: move SA_* definitions to generic headers

Quoted 16 lines · Eric W. Biederman
Quoted 6 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.

Quoted 6 lines

A consequence of this change is that on powerpc and x86, the constants' values aside from SA_RESETHAND change signedness from unsigned to signed. This is not expected to impact realistic use of these constants. In particular the typical use of the constants where they are or'ed together and assigned to sa_flags (or another int variable) would not be affected.

Quoted 2 lines

Except for the removal of SA_RESTORER on arm (see below).

Thanks for the review.

Quoted 45 lines
Quoted 44 lines

---
v11:
- tweak the commit message to point out the change from unsigned to signed

v10:
- move the comments around and add one for SA_SIGINFO

arch/arm/include/uapi/asm/signal.h +3 -17
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
Quoted 5 lines

arch/arm/include/uapi/asm/signal.h typedef unsigned long sigset_t; · line 82

Quoted 1 line
arch/arm/include/uapi/asm/signal.h +0 -1
-#define SA_RESTORER  0x04000000

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Was removing SA_RESTOER from arm a typo?
If not it is probably better to move the removal into a separate patch.

Yes, that was a mistake, thanks for the catch. I'll fix it in v14.

Peter

#12 lore raw

PATCH v13 4/8 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.

---
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 a7f3e12cfbdb..ddfd919be46c 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 ef8f2a28d37c..8f5bd12ee41b 100644
@@ -3985,6 +3985,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.29.1.341.ge80a0c044ae-goog
#13 lore raw

PATCH v13 5/8 signal: define the SA_UNSUPPORTED bit in sa_flags

In reply to Peter Collingbourne

Define a sa_flags bit, SA_UNSUPPORTED, which will never be supported in the uapi. The purpose of this flag bit is to allow userspace to distinguish an old kernel that does not clear unknown sa_flags bits from a kernel that supports every flag bit.

In other words, if userspace does something like:

  act.sa_flags |= SA_UNSUPPORTED;
  sigaction(SIGSEGV, &act, 0);
  sigaction(SIGSEGV, 0, &oldact);

and finds that SA_UNSUPPORTED remains set in oldact.sa_flags, it means that the kernel cannot be trusted to have cleared unknown flag bits from sa_flags, so no assumptions about flag bit support can be made.

---
v11:
- clarify the commit message

 include/uapi/asm-generic/signal-defs.h | 7 +++++++
 kernel/signal.c                        | 6 ++++++
 2 files changed, 13 insertions(+)
include/uapi/asm-generic/signal-defs.h +7 -0
index 493953fe319b..0126ebda4d31 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 8f5bd12ee41b..8f34819e80de 100644
@@ -3985,6 +3985,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.29.1.341.ge80a0c044ae-goog
#14 lore raw

PATCH v13 6/8 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.

---
 include/linux/signal.h |  13 ++++++
 kernel/signal.c        | 101 ++++++++++++++++-------------------------
 2 files changed, 53 insertions(+), 61 deletions(-)
include/linux/signal.h +13 -0
index b256f9c65661..e9fb05041e7a 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.29.1.341.ge80a0c044ae-goog
#15 lore raw

PATCH v13 7/8 signal: define the field siginfo.si_faultflags

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_tag_bits{,_mask} fields.

A new sigcontext flag, SA_FAULTFLAGS, 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_faultflags-unaware program to cause a signal handler in an si_faultflags-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_faultflags-unaware program from causing an uninitialized read of si_faultflags in the si_faultflags-aware program when it uses one of these syscalls.

The last three cases can be handled by observing that each of these syscalls fails if si_code >= 0. We also observe that kill(2) and tgkill(2) may be used to send a signal where si_code == 0 (SI_USER), so we define si_faultflags 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_faultflags field if it detects that the signal would use the _sigfault layout, and introduce a new ptrace request type, PTRACE_SETSIGINFO2, that a si_faultflags-aware program may use to opt out of this behavior.

It is also possible for the kernel to inject a signal specified to use _sigfault by calling force_sig (e.g. there are numerous calls to force_sig(SIGSEGV)). In this case si_code is set to SI_KERNEL and the _kill union member is used, so document that si_code must be < SI_KERNEL.

Ideally this field could have just been named si_flags, but that name was already taken by ia64, so a different name was chosen.

I considered making ia64's si_flags a generic field and having it appear at the end of _sigfault (in the same place as this patch has si_faultflags) on non-ia64, keeping it in the same place on ia64. ia64's si_flags is a 32-bit field with only one flag bit allocated, so we would have 31 bits to use if we do this. However, it seems simplest to avoid entangling these fields.

---
v13:
- renamed si_xflags to si_faultflags
- use fallthrough macros in kernel/ptrace.c
- fixed a style warning pointed out by checkpatch.pl

v12:
- Change type of si_xflags to u32 to avoid increasing alignment
- Add si_xflags to signal_compat.c test cases

v11:
- update comment to say that si_code must > 0
- change ptrace(PTRACE_SETSIGINFO2) to take a flags argument

v10:
- make the new field compatible with the various ways that a siginfo can be injected from another process
- eliminate some duplication by adding a refactoring patch before this one

 arch/powerpc/platforms/powernv/vas-fault.c |  1 +
 arch/x86/kernel/signal_compat.c            |  7 +++--
 include/linux/compat.h                     |  2 ++
 include/linux/signal_types.h               |  2 +-
 include/uapi/asm-generic/siginfo.h         |  4 +++
 include/uapi/asm-generic/signal-defs.h     |  4 +++
 include/uapi/linux/ptrace.h                | 12 ++++++++
 kernel/ptrace.c                            | 33 ++++++++++++++++++----
 kernel/signal.c                            |  3 ++
 9 files changed, 59 insertions(+), 9 deletions(-)
arch/powerpc/platforms/powernv/vas-fault.c +1 -0
index 3d21fce254b7..877e7d5fb4a2 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_faultflags = 0;
 
 	/*
 	 * process will be polling on csb.flags after request is sent to
arch/x86/kernel/signal_compat.c +5 -2
index ddfd919be46c..222ff6178571 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);
@@ -138,6 +138,9 @@ static inline void signal_compat_build_tests(void)
 	BUILD_BUG_ON(offsetof(siginfo_t, si_pkey) != 0x20);
 	BUILD_BUG_ON(offsetof(compat_siginfo_t, si_pkey) != 0x14);
 
+	BUILD_BUG_ON(offsetof(siginfo_t, si_faultflags) != 0x48);
+	BUILD_BUG_ON(offsetof(compat_siginfo_t, si_faultflags) != 0x28);
+
 	CHECK_CSI_OFFSET(_sigpoll);
 	CHECK_CSI_SIZE  (_sigpoll, 2*sizeof(int));
 	CHECK_SI_SIZE   (_sigpoll, 4*sizeof(int));
include/linux/compat.h +2 -0
index 14d514233e1d..84d3b72be701 100644
@@ -236,7 +236,9 @@ typedef struct compat_siginfo {
 					char _dummy_pkey[__COMPAT_ADDR_BND_PKEY_PAD];
 					u32 _pkey;
 				} _addr_pkey;
+				compat_uptr_t _pad[6];
 			};
+			u32 _faultflags;
 		} _sigfault;
 
 		/* SIGPOLL */
include/linux/signal_types.h +1 -1
index a7887ad84d36..7501209eae33 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_FAULTFLAGS | __ARCH_UAPI_SA_FLAGS)
 
 #endif /* _LINUX_SIGNAL_TYPES_H */
include/uapi/asm-generic/siginfo.h +4 -0
index 7aacf9389010..f43778355b77 100644
@@ -91,7 +91,9 @@ union __sifields {
 				char _dummy_pkey[__ADDR_BND_PKEY_PAD];
 				__u32 _pkey;
 			} _addr_pkey;
+			void *_pad[6];
 		};
+		__u32 _faultflags;
 	} _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_faultflags is only valid if 0 < si_code < SI_KERNEL */
+#define si_faultflags	_sifields._sigfault._faultflags
 #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 0126ebda4d31..e27bf959d4c4 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_FAULTFLAGS indicates that the signal handler requires the siginfo.si_faultflags
+ * field to be valid. Note that if the kernel supports SA_FAULTFLAGS, 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_FAULTFLAGS	0x00000800
 
 #define SA_NOMASK	SA_NODEFER
 #define SA_ONESHOT	SA_RESETHAND
include/uapi/linux/ptrace.h +12 -0
index a71b6e3b03eb..722a2c8a4d3d 100644
@@ -101,6 +101,18 @@ struct ptrace_syscall_info {
 	};
 };
 
+#define PTRACE_SETSIGINFO2	0x420f
+/*
+ * These flags are passed as the addr argument to ptrace.
+ */
+
+/*
+ * Asserts that the caller is aware of the field siginfo.si_faultflags. Prevents
+ * the kernel from automatically setting the field to 0 when the signal uses
+ * a sigfault layout.
+ */
+#define PTRACE_SIGINFO_FAULTFLAGS	0x1
+
 /*
  * These values are stored in task->ptrace_message
  * by tracehook_report_syscall_* to describe the current syscall-stop.
kernel/ptrace.c +27 -6
index 43d6179508d6..ab0618b4602c 100644
@@ -687,18 +687,31 @@ static int ptrace_getsiginfo(struct task_struct *child, kernel_siginfo_t *info)
 	return error;
 }
 
-static int ptrace_setsiginfo(struct task_struct *child, const kernel_siginfo_t *info)
+static int ptrace_setsiginfo(struct task_struct *child, unsigned long flags,
+			     kernel_siginfo_t *info)
 {
-	unsigned long flags;
+	unsigned long lock_flags;
 	int error = -ESRCH;
 
-	if (lock_task_sighand(child, &flags)) {
+	if (flags & ~PTRACE_SIGINFO_FAULTFLAGS)
+		return -EINVAL;
+
+	/*
+	 * If the caller is unaware of si_faultflags and we're using a layout that
+	 * requires it, set it to 0 which means "no fields are available".
+	 */
+	if (!(flags & PTRACE_SIGINFO_FAULTFLAGS) &&
+	    siginfo_layout_is_fault(
+		    siginfo_layout(info->si_signo, info->si_code)))
+		info->si_faultflags = 0;
+
+	if (lock_task_sighand(child, &lock_flags)) {
 		error = -EINVAL;
 		if (likely(child->last_siginfo != NULL)) {
 			copy_siginfo(child->last_siginfo, info);
 			error = 0;
 		}
-		unlock_task_sighand(child, &flags);
+		unlock_task_sighand(child, &lock_flags);
 	}
 	return error;
 }
@@ -1038,9 +1051,13 @@ int ptrace_request(struct task_struct *child, long request,
 		break;
 
 	case PTRACE_SETSIGINFO:
+		addr = 0;
+		fallthrough;
+
+	case PTRACE_SETSIGINFO2:
 		ret = copy_siginfo_from_user(&siginfo, datavp);
 		if (!ret)
-			ret = ptrace_setsiginfo(child, &siginfo);
+			ret = ptrace_setsiginfo(child, addr, &siginfo);
 		break;
 
 	case PTRACE_GETSIGMASK: {
@@ -1347,10 +1364,14 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,
 		break;
 
 	case PTRACE_SETSIGINFO:
+		addr = 0;
+		fallthrough;
+
+	case PTRACE_SETSIGINFO2:
 		ret = copy_siginfo_from_user32(
 			&siginfo, (struct compat_siginfo __user *) datap);
 		if (!ret)
-			ret = ptrace_setsiginfo(child, &siginfo);
+			ret = ptrace_setsiginfo(child, addr, &siginfo);
 		break;
 #ifdef CONFIG_HAVE_ARCH_TRACEHOOK
 	case PTRACE_GETREGSET:
kernel/signal.c +3 -0
index d18930aafbf4..1fd1f0d12174 100644
@@ -1657,6 +1657,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_faultflags = 0;
 }
 
 int force_sig_fault_to_task(int sig, int code, void __user *addr
@@ -3270,6 +3271,7 @@ void copy_siginfo_to_external32(struct compat_siginfo *to,
 #ifdef __ARCH_SI_TRAPNO
 		to->si_trapno = from->si_trapno;
 #endif
+		to->si_faultflags = from->si_faultflags;
 	}
 
 	switch (layout) {
@@ -3345,6 +3347,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_faultflags = from->si_faultflags;
 	}
 
 	switch (layout) {
Signature · 1 line
2.29.1.341.ge80a0c044ae-goog
maintainer
#16 lore raw

Re: [PATCH v13 7/8] signal: define the field siginfo.si_faultflags

Hi Peter,

Quoted 11 lines · 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_tag_bits{,_mask} fields.

A new sigcontext flag, SA_FAULTFLAGS, 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.

As per patch 5, a user is supposed to call sigaction() twice to figure out whether _faultflags is meaningful. That's the part I'm not particularly fond of. Are the unused parts of siginfo always zeroed when the kernel delivers a signal? If yes, we could simply check the new field for non-zero bits.

Quoted 18 lines

It is possible for an si_faultflags-unaware program to cause a signal handler in an si_faultflags-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_faultflags-unaware program from causing an uninitialized read of si_faultflags in the si_faultflags-aware program when it uses one of these syscalls.

The last three cases can be handled by observing that each of these syscalls fails if si_code >= 0. We also observe that kill(2) and tgkill(2) may be used to send a signal where si_code == 0 (SI_USER), so we define si_faultflags to only be valid if si_code > 0.

Quoted 5 lines

There is no such check on si_code in ptrace(PTRACE_SETSIGINFO), so we make ptrace(PTRACE_SETSIGINFO) clear the si_faultflags field if it detects that the signal would use the _sigfault layout, and introduce a new ptrace request type, PTRACE_SETSIGINFO2, that a si_faultflags-aware program may use to opt out of this behavior.

I find this pretty fragile but maybe I have to read it a few more times to fully understand the implications ;).

Could we instead copy all the fields, potentially uninitialised, and instead filter them when delivering the signal based on the SA_FAULTFLAGS? That means that the kernel only writes si_faultflags if the user requested it.

Quoted 2 lines

v12:
- Change type of si_xflags to u32 to avoid increasing alignment

[...]

include/uapi/asm-generic/siginfo.h union __sifields { · line 97

Quoted 12 lines
include/uapi/asm-generic/siginfo.h +2 -0
index 7aacf9389010..f43778355b77 100644
@@ -91,7 +91,9 @@ union __sifields {
 				char _dummy_pkey[__ADDR_BND_PKEY_PAD];
 				__u32 _pkey;
 			} _addr_pkey;
+			void *_pad[6];
 		};
+		__u32 _faultflags;
 } _sigfault;

Sorry, I haven't checked the previous discussion on alignment here but don't we already require 64-bit alignment because of other members in the _sigfault union? We already have void * throughout this and with the next patch we just have a gap (unless I miscalculated the offsets).

Signature · 1 line
Catalin
#17 lore raw

Re: [PATCH v13 7/8] signal: define the field siginfo.si_faultflags

Quoted 16 lines · Catalin Marinas

Hi Peter,

Quoted 11 lines · 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_tag_bits{,_mask} fields.

A new sigcontext flag, SA_FAULTFLAGS, 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.

Quoted 5 lines

As per patch 5, a user is supposed to call sigaction() twice to figure out whether _faultflags is meaningful. That's the part I'm not particularly fond of. Are the unused parts of siginfo always zeroed when the kernel delivers a signal? If yes, we could simply check the new field for non-zero bits.

The unused parts of siginfo are zeroed in current kernels, but unfortunately not in older kernels. The zeroing behavior was introduced in commit c999b933faa5e281e3af2e110eccaf91698b0a81 which first appeared in kernel version 4.18, and at least in Android land we do need to support kernel versions older than that.

Quoted 24 lines
Quoted 18 lines

It is possible for an si_faultflags-unaware program to cause a signal handler in an si_faultflags-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_faultflags-unaware program from causing an uninitialized read of si_faultflags in the si_faultflags-aware program when it uses one of these syscalls.

The last three cases can be handled by observing that each of these syscalls fails if si_code >= 0. We also observe that kill(2) and tgkill(2) may be used to send a signal where si_code == 0 (SI_USER), so we define si_faultflags to only be valid if si_code > 0.

Quoted 5 lines

There is no such check on si_code in ptrace(PTRACE_SETSIGINFO), so we make ptrace(PTRACE_SETSIGINFO) clear the si_faultflags field if it detects that the signal would use the _sigfault layout, and introduce a new ptrace request type, PTRACE_SETSIGINFO2, that a si_faultflags-aware program may use to opt out of this behavior.

Quoted 7 lines

I find this pretty fragile but maybe I have to read it a few more times to fully understand the implications ;).

Could we instead copy all the fields, potentially uninitialised, and instead filter them when delivering the signal based on the SA_FAULTFLAGS? That means that the kernel only writes si_faultflags if the user requested it.

I don't see how that would help. The goal is to protect new signal handlers from old signal "injectors" that will have potentially uninitialized data where the si_faultflags field is. The new signal handler will have SA_FAULTFLAGS set so that wouldn't prevent the signal handler from seeing the uninitialized data.

Quoted 12 lines
Quoted 2 lines

v12:
- Change type of si_xflags to u32 to avoid increasing alignment

[...]

Quoted 9 lines
include/uapi/asm-generic/siginfo.h +1 -0
index 7aacf9389010..f43778355b77 100644
@@ -91,7 +91,9 @@ union __sifields {
                              char _dummy_pkey[__ADDR_BND_PKEY_PAD];
                              __u32 _pkey;
                      } _addr_pkey;
+                     void *_pad[6];
Quoted 8 lines

include/uapi/asm-generic/siginfo.h union __sifields { · line 97

Quoted 3 lines
include/uapi/asm-generic/siginfo.h +1 -0
              };
+             __u32 _faultflags;
 } _sigfault;

Sorry, I haven't checked the previous discussion on alignment here but don't we already require 64-bit alignment because of other members in the _sigfault union? We already have void * throughout this and with the next patch we just have a gap (unless I miscalculated the offsets).

This is about avoiding increasing alignment on 32-bit platforms. Currently the alignment is 4 but a u64 field would bump it to 8.

Unfortunately we can't do much about the gap on 64-bit platforms. This was previously a uintptr_t but that would mean that the upper 32 bits cannot be used safely on all platforms so we would effectively end up with a gap anyway.

Peter

#18 lore raw

Re: [PATCH v13 7/8] signal: define the field siginfo.si_faultflags

Quoted 88 lines · Peter Collingbourne
Quoted 16 lines · Catalin Marinas

Hi Peter,

Quoted 11 lines · 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_tag_bits{,_mask} fields.

A new sigcontext flag, SA_FAULTFLAGS, 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.

Quoted 5 lines

As per patch 5, a user is supposed to call sigaction() twice to figure out whether _faultflags is meaningful. That's the part I'm not particularly fond of. Are the unused parts of siginfo always zeroed when the kernel delivers a signal? If yes, we could simply check the new field for non-zero bits.

The unused parts of siginfo are zeroed in current kernels, but unfortunately not in older kernels. The zeroing behavior was introduced in commit c999b933faa5e281e3af2e110eccaf91698b0a81 which first appeared in kernel version 4.18, and at least in Android land we do need to support kernel versions older than that.

Quoted 24 lines
Quoted 18 lines

It is possible for an si_faultflags-unaware program to cause a signal handler in an si_faultflags-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_faultflags-unaware program from causing an uninitialized read of si_faultflags in the si_faultflags-aware program when it uses one of these syscalls.

The last three cases can be handled by observing that each of these syscalls fails if si_code >= 0. We also observe that kill(2) and tgkill(2) may be used to send a signal where si_code == 0 (SI_USER), so we define si_faultflags to only be valid if si_code > 0.

Quoted 5 lines

There is no such check on si_code in ptrace(PTRACE_SETSIGINFO), so we make ptrace(PTRACE_SETSIGINFO) clear the si_faultflags field if it detects that the signal would use the _sigfault layout, and introduce a new ptrace request type, PTRACE_SETSIGINFO2, that a si_faultflags-aware program may use to opt out of this behavior.

Quoted 7 lines

I find this pretty fragile but maybe I have to read it a few more times to fully understand the implications ;).

Could we instead copy all the fields, potentially uninitialised, and instead filter them when delivering the signal based on the SA_FAULTFLAGS? That means that the kernel only writes si_faultflags if the user requested it.

I don't see how that would help. The goal is to protect new signal handlers from old signal "injectors" that will have potentially uninitialized data where the si_faultflags field is. The new signal handler will have SA_FAULTFLAGS set so that wouldn't prevent the signal handler from seeing the uninitialized data.

Quoted 12 lines
Quoted 2 lines

v12:
- Change type of si_xflags to u32 to avoid increasing alignment

[...]

Quoted 9 lines
include/uapi/asm-generic/siginfo.h +1 -0
index 7aacf9389010..f43778355b77 100644
@@ -91,7 +91,9 @@ union __sifields {
                              char _dummy_pkey[__ADDR_BND_PKEY_PAD];
                              __u32 _pkey;
                      } _addr_pkey;
+                     void *_pad[6];
Quoted 8 lines

include/uapi/asm-generic/siginfo.h union __sifields { · line 97

Quoted 3 lines
include/uapi/asm-generic/siginfo.h +1 -0
              };
+             __u32 _faultflags;
 } _sigfault;

Sorry, I haven't checked the previous discussion on alignment here but don't we already require 64-bit alignment because of other members in the _sigfault union? We already have void * throughout this and with the next patch we just have a gap (unless I miscalculated the offsets).

Quoted 7 lines

This is about avoiding increasing alignment on 32-bit platforms. Currently the alignment is 4 but a u64 field would bump it to 8.

Unfortunately we can't do much about the gap on 64-bit platforms. This was previously a uintptr_t but that would mean that the upper 32 bits cannot be used safely on all platforms so we would effectively end up with a gap anyway.

I suppose we could make this an int or long if that feels more natural, but unless we have different flag definitions for 32-bit and 64-bit platforms, it would be hard to make use of the high 32 bits on 64-bit.

Cheers
---Dave

maintainer
#19 lore raw

Re: [PATCH v13 7/8] signal: define the field siginfo.si_faultflags

In reply to Peter Collingbourne
Quoted 20 lines · Peter Collingbourne
Quoted 13 lines · Catalin Marinas
Quoted 11 lines · 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_tag_bits{,_mask} fields.

A new sigcontext flag, SA_FAULTFLAGS, 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.

Quoted 5 lines

As per patch 5, a user is supposed to call sigaction() twice to figure out whether _faultflags is meaningful. That's the part I'm not particularly fond of. Are the unused parts of siginfo always zeroed when the kernel delivers a signal? If yes, we could simply check the new field for non-zero bits.

Quoted 5 lines

The unused parts of siginfo are zeroed in current kernels, but unfortunately not in older kernels. The zeroing behavior was introduced in commit c999b933faa5e281e3af2e110eccaf91698b0a81 which first appeared in kernel version 4.18, and at least in Android land we do need to support kernel versions older than that.

I see. I was hoping for an easy way out.

Now, with always populating the si_faultflags field, you are going back to writing non-zero stuff in siginfo for unaware apps. I don't think that's an issue (the alternative is to only write it of SA_FAULTFLAGS was set).

Yet another option would be to pass a new AT_ZEROED_SI via AT_FLAGS (we don't use them for anything) so that the user can infer whether si_faultflags has meaningful information without two sigaction() calls.

Quoted 32 lines
Quoted 24 lines
Quoted 18 lines

It is possible for an si_faultflags-unaware program to cause a signal handler in an si_faultflags-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_faultflags-unaware program from causing an uninitialized read of si_faultflags in the si_faultflags-aware program when it uses one of these syscalls.

The last three cases can be handled by observing that each of these syscalls fails if si_code >= 0. We also observe that kill(2) and tgkill(2) may be used to send a signal where si_code == 0 (SI_USER), so we define si_faultflags to only be valid if si_code > 0.

Quoted 5 lines

There is no such check on si_code in ptrace(PTRACE_SETSIGINFO), so we make ptrace(PTRACE_SETSIGINFO) clear the si_faultflags field if it detects that the signal would use the _sigfault layout, and introduce a new ptrace request type, PTRACE_SETSIGINFO2, that a si_faultflags-aware program may use to opt out of this behavior.

Quoted 7 lines

I find this pretty fragile but maybe I have to read it a few more times to fully understand the implications ;).

Could we instead copy all the fields, potentially uninitialised, and instead filter them when delivering the signal based on the SA_FAULTFLAGS? That means that the kernel only writes si_faultflags if the user requested it.

Quoted 5 lines

I don't see how that would help. The goal is to protect new signal handlers from old signal "injectors" that will have potentially uninitialized data where the si_faultflags field is. The new signal handler will have SA_FAULTFLAGS set so that wouldn't prevent the signal handler from seeing the uninitialized data.

You are right, it doesn't help if the handler will have set SA_FAULTFLAGS.

Quoted 21 lines
Quoted 12 lines
Quoted 2 lines

v12:
- Change type of si_xflags to u32 to avoid increasing alignment

[...]

Quoted 9 lines
include/uapi/asm-generic/siginfo.h +1 -0
index 7aacf9389010..f43778355b77 100644
@@ -91,7 +91,9 @@ union __sifields {
                              char _dummy_pkey[__ADDR_BND_PKEY_PAD];
                              __u32 _pkey;
                      } _addr_pkey;
+                     void *_pad[6];
Quoted 8 lines

include/uapi/asm-generic/siginfo.h union __sifields { · line 97

Quoted 3 lines
include/uapi/asm-generic/siginfo.h +1 -0
              };
+             __u32 _faultflags;
 } _sigfault;

Sorry, I haven't checked the previous discussion on alignment here but don't we already require 64-bit alignment because of other members in the _sigfault union? We already have void * throughout this and with the next patch we just have a gap (unless I miscalculated the offsets).

Quoted 7 lines

This is about avoiding increasing alignment on 32-bit platforms. Currently the alignment is 4 but a u64 field would bump it to 8.

Unfortunately we can't do much about the gap on 64-bit platforms. This was previously a uintptr_t but that would mean that the upper 32 bits cannot be used safely on all platforms so we would effectively end up with a gap anyway.

We could add a dummy pad on 64-bit. BTW, the tags only make sense on 64-bit hardware, 32-bit doesn't have enough room.

Signature · 1 line
Catalin
#20 lore raw

Re: [PATCH v13 7/8] signal: define the field siginfo.si_faultflags

Quoted 30 lines · Catalin Marinas
Quoted 20 lines · Peter Collingbourne
Quoted 13 lines · Catalin Marinas
Quoted 11 lines · 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_tag_bits{,_mask} fields.

A new sigcontext flag, SA_FAULTFLAGS, 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.

Quoted 5 lines

As per patch 5, a user is supposed to call sigaction() twice to figure out whether _faultflags is meaningful. That's the part I'm not particularly fond of. Are the unused parts of siginfo always zeroed when the kernel delivers a signal? If yes, we could simply check the new field for non-zero bits.

Quoted 5 lines

The unused parts of siginfo are zeroed in current kernels, but unfortunately not in older kernels. The zeroing behavior was introduced in commit c999b933faa5e281e3af2e110eccaf91698b0a81 which first appeared in kernel version 4.18, and at least in Android land we do need to support kernel versions older than that.

I see. I was hoping for an easy way out.

Quoted 8 lines

Now, with always populating the si_faultflags field, you are going back to writing non-zero stuff in siginfo for unaware apps. I don't think that's an issue (the alternative is to only write it of SA_FAULTFLAGS was set).

Yet another option would be to pass a new AT_ZEROED_SI via AT_FLAGS (we don't use them for anything) so that the user can infer whether si_faultflags has meaningful information without two sigaction() calls.

That's one option, although one benefit of having this involve sigaction is that in many cases where sigaction is wrapped or interposed we end up with correct behavior. Imagine a wrapper that stashes the provided struct sigaction somewhere and provides its own struct sigaction with its own handler to the kernel, and that handler copies siginfo field by field before calling the user's handler. In this scenario the handler would observe an uninitialized faultflags. With the SA_UNSUPPORTED/SA_FAULTFLAGS protocol we would detect this scenario in the same way as an old kernel and avoid reading faultflags.

Of course this isn't a perfect defense but it's probably the best we can do.

Quoted 65 lines
Quoted 32 lines
Quoted 24 lines
Quoted 18 lines

It is possible for an si_faultflags-unaware program to cause a signal handler in an si_faultflags-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_faultflags-unaware program from causing an uninitialized read of si_faultflags in the si_faultflags-aware program when it uses one of these syscalls.

The last three cases can be handled by observing that each of these syscalls fails if si_code >= 0. We also observe that kill(2) and tgkill(2) may be used to send a signal where si_code == 0 (SI_USER), so we define si_faultflags to only be valid if si_code > 0.

Quoted 5 lines

There is no such check on si_code in ptrace(PTRACE_SETSIGINFO), so we make ptrace(PTRACE_SETSIGINFO) clear the si_faultflags field if it detects that the signal would use the _sigfault layout, and introduce a new ptrace request type, PTRACE_SETSIGINFO2, that a si_faultflags-aware program may use to opt out of this behavior.

Quoted 7 lines

I find this pretty fragile but maybe I have to read it a few more times to fully understand the implications ;).

Could we instead copy all the fields, potentially uninitialised, and instead filter them when delivering the signal based on the SA_FAULTFLAGS? That means that the kernel only writes si_faultflags if the user requested it.

Quoted 5 lines

I don't see how that would help. The goal is to protect new signal handlers from old signal "injectors" that will have potentially uninitialized data where the si_faultflags field is. The new signal handler will have SA_FAULTFLAGS set so that wouldn't prevent the signal handler from seeing the uninitialized data.

You are right, it doesn't help if the handler will have set SA_FAULTFLAGS.

Quoted 24 lines
Quoted 12 lines
Quoted 2 lines

v12:
- Change type of si_xflags to u32 to avoid increasing alignment

[...]

Quoted 9 lines
include/uapi/asm-generic/siginfo.h +1 -0
index 7aacf9389010..f43778355b77 100644
@@ -91,7 +91,9 @@ union __sifields {
                              char _dummy_pkey[__ADDR_BND_PKEY_PAD];
                              __u32 _pkey;
                      } _addr_pkey;
+                     void *_pad[6];
Quoted 8 lines

include/uapi/asm-generic/siginfo.h union __sifields { · line 97

Quoted 3 lines
include/uapi/asm-generic/siginfo.h +1 -0
              };
+             __u32 _faultflags;
 } _sigfault;

Sorry, I haven't checked the previous discussion on alignment here but don't we already require 64-bit alignment because of other members in the _sigfault union? We already have void * throughout this and with the next patch we just have a gap (unless I miscalculated the offsets).

This is about avoiding increasing alignment on 32-bit platforms. Currently the alignment is 4 but a u64 field would bump it to 8.

Quoted 6 lines
Quoted 4 lines

Unfortunately we can't do much about the gap on 64-bit platforms. This was previously a uintptr_t but that would mean that the upper 32 bits cannot be used safely on all platforms so we would effectively end up with a gap anyway.

We could add a dummy pad on 64-bit.

And then later once we add a 32-bit field here we use it like so?

__u32 _faultflags;
#ifdef __LP64__
__u32 _newfield;
#endif
unsigned long _addr_tag_bits, _addr_tag_bits_mask; #ifndef __LP64__
__u32 _newfield;
#endif

Okay, I'll go ahead with that for now.

Quoted 2 lines

BTW, the tags only make sense on
64-bit hardware, 32-bit doesn't have enough room.

From an architectural perspective it really depends on which kinds of applications you are targeting. For example if you have something like a 32-bit microcontroller you might not need all of the address space for memory so it may be worthwhile to allow some bits to be used for tags. According to the comments on [1] RISC-V is planning to have their first implementation only support 64-bit but they haven't ruled out 32-bit in the future.

[1] https://docs.google.com/document/d/1RZcEgljHY9ACeKKoLebBNPLqjl6nMMyG/edit#heading=h.1fob9te

Peter

#21 lore raw

PATCH v13 8/8 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_faultflags to allow userspace to determine whether the values in the fields are valid.

[1] http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html

---
v13:
- renamed si_xflags to si_faultflags
- rebased to 5.10-rc2

v12:
- add new fields to signal_compat.c test cases
- rebased to 5.10-rc1
- mask out bits 63:60 for tag check faults

v11:
- add a comment explaining what the arch hook should do
- rename ignored bits to tag bits

v10:
- rename the flag to SIFAULTFLAG_ADDR_IGNORED_BITS
- use an arch hook to specify which bits are ignored, instead of passing them explicitly
- while refactoring for the arch hook, noticed that my previous patches missed a case involving cache maintenance instructions, so expose the tag bits for that signal as well

v9:
- make the ignored bits fields generic
- add some new dependent patches that prepare us to store the field in such a way that userspace can detect their presence

v8:
- rebase onto 5.8rc2

v7:
- switch to a new siginfo field instead of using sigcontext
- merge the patch back into one since the other patches are now unnecessary

v6:
- move fault address and fault code into the kernel_siginfo data structure
- split the patch in three since it was getting large and now has generic and arch-specific parts

v5:
- add padding to fault_addr_top_byte_context in order to ensure the correct size and preserve sp alignment

v4:
- expose only the tag bits in the context instead of the entire FAR_EL1
- remove mention of the new context from the sigcontext.__reserved[] note

v3:
- add documentation to tagged-pointers.rst
- update comments in sigcontext.h

v2:
- revert changes to hw_breakpoint.c
- rename set_thread_esr to set_thread_far_esr

 Documentation/arm64/tagged-pointers.rst | 21 +++++---
 arch/arm64/include/asm/exception.h      |  2 +-
 arch/arm64/include/asm/signal.h         | 19 +++++++
 arch/arm64/include/asm/system_misc.h    |  2 +-
 arch/arm64/include/asm/traps.h          |  6 +--
 arch/arm64/kernel/debug-monitors.c      |  5 +-
 arch/arm64/kernel/entry-common.c        |  2 -
 arch/arm64/kernel/ptrace.c              |  7 +--
 arch/arm64/kernel/sys_compat.c          |  5 +-
 arch/arm64/kernel/traps.c               | 29 ++++++-----
 arch/arm64/mm/fault.c                   | 68 ++++++++++++++-----------
 arch/x86/kernel/signal_compat.c         |  9 +++-
 include/linux/compat.h                  |  2 +
 include/linux/signal.h                  | 16 ++++++
 include/uapi/asm-generic/siginfo.h      | 10 ++++
 kernel/signal.c                         | 18 ++++++-
 16 files changed, 148 insertions(+), 73 deletions(-)
 create mode 100644 arch/arm64/include/asm/signal.h
Documentation/arm64/tagged-pointers.rst +15 -6
index eab4323609b9..7d07987ad85a 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_tag_bits field
+of siginfo, which is set for signals raised in response to data aborts
+and instruction aborts. The si_addr_tag_bits_mask field indicates
+which bits of the field are valid. The validity of these fields is
+indicated by the SIFAULTFLAG_ADDR_TAG_BITS flag in siginfo.si_faultflags,
+and the validity of si_faultflags in turn is indicated by the kernel
+indicating support for the sigaction.sa_flags flag SA_FAULTFLAGS.
 
 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 99b9383cd036..2a8aa1884d8a 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 +19 -0
new file mode 100644
index 000000000000..46f9b3c61896
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ARM64_ASM_SIGNAL_H
+#define __ARM64_ASM_SIGNAL_H
+
+#include <uapi/asm/signal.h>
+#include <uapi/asm/siginfo.h>
+
+static inline unsigned long arch_addr_tag_bits_mask(unsigned long sig,
+						    unsigned long si_code)
+{
+	if (sig == SIGTRAP && si_code == TRAP_BRKPT)
+		return 0;
+	if (sig == SIGSEGV && si_code == SEGV_MTESERR)
+		return 0xfUL << 56;
+	return 0xffUL << 56;
+}
+#define arch_addr_tag_bits_mask arch_addr_tag_bits_mask
+
+#endif
arch/arm64/include/asm/system_misc.h +1 -1
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 d96dc2c7c09d..54f32a0675df 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, unsigned int err);
 void arm64_notify_segfault(unsigned long addr);
-void arm64_force_sig_fault(int signo, int code, void __user *addr, const char *str);
-void arm64_force_sig_mceerr(int code, void __user *addr, short lsb, const char *str);
-void arm64_force_sig_ptrace_errno_trap(int errno, void __user *addr, const char *str);
+void arm64_force_sig_fault(int signo, int code, unsigned long far, const char *str);
+void arm64_force_sig_mceerr(int code, unsigned long far, short lsb, const char *str);
+void arm64_force_sig_ptrace_errno_trap(int errno, unsigned long far, const char *str);
 
 /*
  * Move regs->pc to next instruction and do necessary setup before it
arch/arm64/kernel/debug-monitors.c +2 -3
index fa76151de6ff..4f3661eeb7ec 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 43d4c329775f..dbbddfbf4a72 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);
@@ -114,7 +113,6 @@ static void notrace el0_da(struct pt_regs *regs, unsigned long esr)
 
 	user_exit_irqoff();
 	local_daif_restore(DAIF_PROCCTX);
-	far = untagged_addr(far);
 	do_mem_abort(far, esr, regs);
 }
 NOKPROBE_SYMBOL(el0_da);
arch/arm64/kernel/ptrace.c +2 -5
index f49b349e16a3..8ac487c84e37 100644
@@ -192,14 +192,11 @@ static void ptrace_hbptriggered(struct perf_event *bp,
 				break;
 			}
 		}
-		arm64_force_sig_ptrace_errno_trap(si_errno,
-						  (void __user *)bkpt->trigger,
+		arm64_force_sig_ptrace_errno_trap(si_errno, bkpt->trigger,
 						  desc);
 	}
 #endif
-	arm64_force_sig_fault(SIGTRAP, TRAP_HWBKPT,
-			      (void __user *)(bkpt->trigger),
-			      desc);
+	arm64_force_sig_fault(SIGTRAP, TRAP_HWBKPT, bkpt->trigger, desc);
 }
 
 /*
arch/arm64/kernel/sys_compat.c +2 -3
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 8af4e0e85736..f4ddbe9ed3f1 100644
@@ -170,32 +170,32 @@ static void arm64_show_signal(int signo, const char *str)
 	__show_regs(regs);
 }
 
-void arm64_force_sig_fault(int signo, int code, void __user *addr,
+void arm64_force_sig_fault(int signo, int code, unsigned long far,
 			   const char *str)
 {
 	arm64_show_signal(signo, str);
 	if (signo == SIGKILL)
 		force_sig(SIGKILL);
 	else
-		force_sig_fault(signo, code, addr);
+		force_sig_fault(signo, code, (void __user *)far);
 }
 
-void arm64_force_sig_mceerr(int code, void __user *addr, short lsb,
+void arm64_force_sig_mceerr(int code, unsigned long far, short lsb,
 			    const char *str)
 {
 	arm64_show_signal(SIGBUS, str);
-	force_sig_mceerr(code, addr, lsb);
+	force_sig_mceerr(code, (void __user *)far, lsb);
 }
 
-void arm64_force_sig_ptrace_errno_trap(int errno, void __user *addr,
+void arm64_force_sig_ptrace_errno_trap(int errno, unsigned long far,
 				       const char *str)
 {
 	arm64_show_signal(SIGTRAP, str);
-	force_sig_ptrace_errno_trap(errno, addr);
+	force_sig_ptrace_errno_trap(errno, (void __user *)far);
 }
 
 void arm64_notify_die(const char *str, struct pt_regs *regs,
-		      int signo, int sicode, void __user *addr,
+		      int signo, int sicode, unsigned long far,
 		      int err)
 {
 	if (user_mode(regs)) {
@@ -203,7 +203,7 @@ void arm64_notify_die(const char *str, struct pt_regs *regs,
 		current->thread.fault_address = 0;
 		current->thread.fault_code = err;
 
-		arm64_force_sig_fault(signo, sicode, addr, str);
+		arm64_force_sig_fault(signo, sicode, far, str);
 	} else {
 		die(str, regs, err);
 	}
@@ -374,7 +374,7 @@ void force_signal_inject(int signal, int code, unsigned long address, unsigned i
 		signal = SIGKILL;
 	}
 
-	arm64_notify_die(desc, regs, signal, code, (void __user *)address, err);
+	arm64_notify_die(desc, regs, signal, code, address, err);
 }
 
 /*
@@ -385,7 +385,7 @@ void arm64_notify_segfault(unsigned long addr)
 	int code;
 
 	mmap_read_lock(current->mm);
-	if (find_vma(current->mm, addr) == NULL)
+	if (find_vma(current->mm, untagged_addr(addr)) == NULL)
 		code = SEGV_MAPERR;
 	else
 		code = SEGV_ACCERR;
@@ -448,12 +448,13 @@ NOKPROBE_SYMBOL(do_ptrauth_fault);
 
 static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs)
 {
-	unsigned long address;
+	unsigned long tagged_address, address;
 	int rt = ESR_ELx_SYS64_ISS_RT(esr);
 	int crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT;
 	int ret = 0;
 
-	address = untagged_addr(pt_regs_read_reg(regs, rt));
+	tagged_address = pt_regs_read_reg(regs, rt);
+	address = untagged_addr(tagged_address);
 
 	switch (crm) {
 	case ESR_ELx_SYS64_ISS_CRM_DC_CVAU:	/* DC CVAU, gets promoted */
@@ -480,7 +481,7 @@ static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs)
 	}
 
 	if (ret)
-		arm64_notify_segfault(address);
+		arm64_notify_segfault(tagged_address);
 	else
 		arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
 }
@@ -772,7 +773,7 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr)
  */
 void bad_el0_sync(struct pt_regs *regs, int reason, unsigned int esr)
 {
-	void __user *pc = (void __user *)instruction_pointer(regs);
+	unsigned long pc = instruction_pointer(regs);
 
 	current->thread.fault_address = 0;
 	current->thread.fault_code = esr;
arch/arm64/mm/fault.c +37 -31

183 lines not on this page · raw message

arch/x86/kernel/signal_compat.c +7 -2
index 222ff6178571..41cbef515b95 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);
@@ -141,6 +141,11 @@ static inline void signal_compat_build_tests(void)
 	BUILD_BUG_ON(offsetof(siginfo_t, si_faultflags) != 0x48);
 	BUILD_BUG_ON(offsetof(compat_siginfo_t, si_faultflags) != 0x28);
 
+	BUILD_BUG_ON(offsetof(siginfo_t, si_addr_tag_bits) != 0x50);
+	BUILD_BUG_ON(offsetof(siginfo_t, si_addr_tag_bits_mask) != 0x58);
+	BUILD_BUG_ON(offsetof(compat_siginfo_t, si_addr_tag_bits) != 0x2C);
+	BUILD_BUG_ON(offsetof(compat_siginfo_t, si_addr_tag_bits_mask) != 0x30);
+
 	CHECK_CSI_OFFSET(_sigpoll);
 	CHECK_CSI_SIZE  (_sigpoll, 2*sizeof(int));
 	CHECK_SI_SIZE   (_sigpoll, 4*sizeof(int));
include/linux/compat.h +2 -0
index 84d3b72be701..f3c83a6d6623 100644
@@ -239,6 +239,8 @@ typedef struct compat_siginfo {
 				compat_uptr_t _pad[6];
 			};
 			u32 _faultflags;
+			compat_uptr_t _addr_tag_bits;
+			compat_uptr_t _addr_tag_bits_mask;
 		} _sigfault;
 
 		/* SIGPOLL */
include/linux/signal.h +16 -0
index e9fb05041e7a..7fe7ce1d252e 100644
@@ -482,4 +482,20 @@ struct seq_file;
 extern void render_sigset_t(struct seq_file *, const char *, sigset_t *);
 #endif
 
+#ifndef arch_addr_tag_bits_mask
+/*
+ * Given a signal and si_code which correspond to the _sigfault union member,
+ * if tag bits are present in the fault address which must appear in
+ * si_addr_tag_bits instead of si_addr, this hook must return a bitmask where 1
+ * corresponds to bits appearing in si_addr_tag_bits and 0 corresponds to bits
+ * appearing in si_addr. The value returned by this function will also be
+ * available in si_addr_tag_bits_mask.
+ */
+static inline unsigned long arch_addr_tag_bits_mask(unsigned long sig,
+						    unsigned long si_code)
+{
+	return 0;
+}
+#endif
+
 #endif /* _LINUX_SIGNAL_H */
include/uapi/asm-generic/siginfo.h +10 -0
index f43778355b77..2b2ed0394457 100644
@@ -94,6 +94,8 @@ union __sifields {
 			void *_pad[6];
 		};
 		__u32 _faultflags;
+		unsigned long _addr_tag_bits;
+		unsigned long _addr_tag_bits_mask;
 	} _sigfault;
 
 	/* SIGPOLL */
@@ -156,6 +158,8 @@ typedef struct siginfo {
 #define si_addr_lsb	_sifields._sigfault._addr_lsb
 /* si_faultflags is only valid if 0 < si_code < SI_KERNEL */
 #define si_faultflags	_sifields._sigfault._faultflags
+#define si_addr_tag_bits	_sifields._sigfault._addr_tag_bits
+#define si_addr_tag_bits_mask	_sifields._sigfault._addr_tag_bits_mask
 #define si_lower	_sifields._sigfault._addr_bnd._lower
 #define si_upper	_sifields._sigfault._addr_bnd._upper
 #define si_pkey		_sifields._sigfault._addr_pkey._pkey
@@ -298,6 +302,12 @@ typedef struct siginfo {
 #define EMT_TAGOVF	1	/* tag overflow */
 #define NSIGEMT		1
 
+/*
+ * SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP, SIGEMT si_faultflags
+ */
+#define SIFAULTFLAG_ADDR_TAG_BITS	1
+/* si_addr_tag_bits{,_mask} fields valid */
+
 /*
  * sigevent definitions
  * 
kernel/signal.c +16 -2
index 1fd1f0d12174..aa69dd312bd5 100644
@@ -1653,11 +1653,16 @@ void force_sigsegv(int sig)
 static void set_sigfault_common_fields(struct kernel_siginfo *info, int sig,
 				       int code, void __user *addr)
 {
+	unsigned long addr_long = (unsigned long)addr;
+	unsigned long tag_bits_mask = arch_addr_tag_bits_mask(sig, code);
+
 	info->si_signo = sig;
 	info->si_errno = 0;
 	info->si_code = code;
-	info->si_addr = addr;
-	info->si_faultflags = 0;
+	info->si_addr = (void __user *)(addr_long & ~tag_bits_mask);
+	info->si_faultflags = SIFAULTFLAG_ADDR_TAG_BITS;
+	info->si_addr_tag_bits = addr_long & tag_bits_mask;
+	info->si_addr_tag_bits_mask = tag_bits_mask;
 }
 
 int force_sig_fault_to_task(int sig, int code, void __user *addr
@@ -3272,6 +3277,13 @@ void copy_siginfo_to_external32(struct compat_siginfo *to,
 		to->si_trapno = from->si_trapno;
 #endif
 		to->si_faultflags = from->si_faultflags;
+		/*
+		 * These assignments involve a truncation, but as with si_addr
+		 * they will be derived from a 32-bit fault address so we
+		 * should not expect any truncation in practice.
+		 */
+		to->si_addr_tag_bits = from->si_addr_tag_bits;
+		to->si_addr_tag_bits_mask = from->si_addr_tag_bits_mask;
 	}
 
 	switch (layout) {
@@ -3348,6 +3360,8 @@ static int post_copy_siginfo_from_user32(kernel_siginfo_t *to,
 		to->si_trapno = from->si_trapno;
 #endif
 		to->si_faultflags = from->si_faultflags;
+		to->si_addr_tag_bits = from->si_addr_tag_bits;
+		to->si_addr_tag_bits_mask = from->si_addr_tag_bits_mask;
 	}
 
 	switch (layout) {
Signature · 1 line
2.29.1.341.ge80a0c044ae-goog
maintainer
#22 lore raw
Quoted 11 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.

This comment is slightly confusing as they are not union fields in _sigfault.

include/uapi/asm-generic/siginfo.h union __sifields { · line 99

Quoted 11 lines
include/uapi/asm-generic/siginfo.h +2 -0
index f43778355b77..2b2ed0394457 100644
@@ -94,6 +94,8 @@ union __sifields {
 			void *_pad[6];
 		};
 		__u32 _faultflags;
+		unsigned long _addr_tag_bits;
+		unsigned long _addr_tag_bits_mask;
 	} _sigfault;

Can we not actually add these as a struct to the union? Do we expect the other fields to be valid?

Also there's a 32-bit gap I mentioned on the previous patch between _faultflags and _addr_tag_bits.

That said, I wonder whether we could solve this for MTE without new fields by always setting the tag in si_addr when si_code is SEGV_MTE*. Alternatively, we could add a prctl() bit to require tagged si_addr.

Well, I don't mind the _addr_tag_bits* fields if they are part of the union and keep si_addr intact.

Signature · 1 line
Catalin
#23 lore raw
Quoted 8 lines · Catalin Marinas
Quoted 6 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).

Quoted 8 lines
Quoted 5 lines

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.

This comment is slightly confusing as they are not union fields in _sigfault.

Good catch, I will remove the word "union" here.

Quoted 6 lines
Quoted 6 lines
include/uapi/asm-generic/siginfo.h +0 -0
index f43778355b77..2b2ed0394457 100644
@@ -94,6 +94,8 @@ union __sifields {
                      void *_pad[6];
Quoted 8 lines

include/uapi/asm-generic/siginfo.h union __sifields { · line 99

Quoted 5 lines
include/uapi/asm-generic/siginfo.h +2 -0
              };
              __u32 _faultflags;
+             unsigned long _addr_tag_bits;
+             unsigned long _addr_tag_bits_mask;
      } _sigfault;

Can we not actually add these as a struct to the union? Do we expect the other fields to be valid?

The idea is that the fields would be available for all si_codes, including SEGV_MAPERR (which is important as I mention below). There's no fundamental reason why the information shouldn't be made available for BUS_MCEERR_*, SEGV_BNDERR or SEGV_PKUERR either, or other union members that we may introduce in the future, just because they happen to use a union member. Although we could retroactively add a union member for currently non-union si_codes, and add new fields to the current union members, that would basically be the same thing as adding the new struct fields that I am adding here.

Quoted 2 lines

Also there's a 32-bit gap I mentioned on the previous patch between _faultflags and _addr_tag_bits.

As I mentioned on the previous patch, I think the gap is unavoidable.

Quoted 2 lines

That said, I wonder whether we could solve this for MTE without new fields by always setting the tag in si_addr when si_code is SEGV_MTE*.

This wouldn't solve the problem for MTE in the case where there is a non-linear buffer overflow that extends into an unmapped page, in which case we would get a SEGV_MAPERR that we would still need the tag bits for.

Quoted 1 line

Alternatively, we could add a prctl() bit to require tagged si_addr.

It's an option that we considered but I would be concerned about the compatibility implications of this. In practice, on Android we would always have this bit set, so applications would be exposed to the tag bits in si_addr. If applications have previously relied on the documented behavior that the tag bits are unset, they may get confused by them now being set. It also wouldn't provide a way for the kernel to communicate which tag bits are valid.

Peter

Quoted 5 lines

Well, I don't mind the _addr_tag_bits* fields if they are part of the union and keep si_addr intact.

--
Catalin

maintainer
#24 lore raw
Quoted 8 lines · Peter Collingbourne
Quoted 2 lines · Catalin Marinas

That said, I wonder whether we could solve this for MTE without new fields by always setting the tag in si_addr when si_code is SEGV_MTE*.

This wouldn't solve the problem for MTE in the case where there is a non-linear buffer overflow that extends into an unmapped page, in which case we would get a SEGV_MAPERR that we would still need the tag bits for.

What I was thinking of is to only present the tags for SEGV_MTE* faults (tag check faults). Is the tag relevant for a SEGV_MAPERR fault?

Quoted 9 lines
Quoted 1 line

Alternatively, we could add a prctl() bit to require tagged si_addr.

It's an option that we considered but I would be concerned about the compatibility implications of this. In practice, on Android we would always have this bit set, so applications would be exposed to the tag bits in si_addr. If applications have previously relied on the documented behavior that the tag bits are unset, they may get confused by them now being set. It also wouldn't provide a way for the kernel to communicate which tag bits are valid.

It depends what you mean by application. If the MTE enabling and signal handling is done from zygote, I suspect the rest of the app won't install its own signal handlers, so they can't get confused.

For standard Linux processes and glibc, the feature wouldn't be enabled by default even if MTE was turned on (we'd add a new prctl() bit).

Anyway, I'm not saying we should go for this approach, just making sure that we explored all the options (sorry, should have read the previous 12 series ;)).

Signature · 1 line
Catalin
#25 lore raw
Quoted 6 lines · Catalin Marinas
Quoted 4 lines · Peter Collingbourne
Quoted 2 lines · Catalin Marinas

That said, I wonder whether we could solve this for MTE without new fields by always setting the tag in si_addr when si_code is SEGV_MTE*.

Quoted 7 lines
Quoted 4 lines

This wouldn't solve the problem for MTE in the case where there is a non-linear buffer overflow that extends into an unmapped page, in which case we would get a SEGV_MAPERR that we would still need the tag bits for.

What I was thinking of is to only present the tags for SEGV_MTE* faults (tag check faults). Is the tag relevant for a SEGV_MAPERR fault?

Yes, because in the case that I mentioned with a non-linear buffer overflow into an unmapped page, the error reporting mechanism would still need to know the address tag in order to associate the access with an allocation.

Quoted 10 lines
Quoted 9 lines
Quoted 1 line

Alternatively, we could add a prctl() bit to require tagged si_addr.

It's an option that we considered but I would be concerned about the compatibility implications of this. In practice, on Android we would always have this bit set, so applications would be exposed to the tag bits in si_addr. If applications have previously relied on the documented behavior that the tag bits are unset, they may get confused by them now being set. It also wouldn't provide a way for the kernel to communicate which tag bits are valid.

Quoted 3 lines

It depends what you mean by application. If the MTE enabling and signal handling is done from zygote, I suspect the rest of the app won't install its own signal handlers, so they can't get confused.

This isn't the case for every Android application. For example, some applications, such as Chrome, have their own crash reporting mechanism (Crashpad in Chrome's case) and install their own signal handlers. Google also offers Firebase Crashlytics for third-party applications to use. Although the systems that I've mentioned are open source and/or owned by Google so we could fix them if necessary, there's nothing stopping apps from using their own third-party crash reporting systems.

It's also possible for application-supplied language implementations, such as Mono and Unity, to install their own signal handler to implement fast null checks. You could also imagine a userspace page fault handler being implemented this way as an alternative to using userfaultfd.

Quoted 2 lines

For standard Linux processes and glibc, the feature wouldn't be enabled by default even if MTE was turned on (we'd add a new prctl() bit).

Regardless of whether it's Android or not, you might still run into a situation where one part of the system needs the bits and another gets confused by them. (This could be something like two libraries sharing a signal handler with something like Android's libsigchain, or one process monitoring another's signals via ptrace.) Having this controlled by a prctl seems like a global solution to a local problem, which is the sort of thing that should be avoided if possible.

Peter

Quoted 6 lines

Anyway, I'm not saying we should go for this approach, just making sure that we explored all the options (sorry, should have read the previous 12 series ;)).

--
Catalin