siginfo fixes/cleanups esp SI_USER
Subsystems (34)
cover siginfo fixes/cleanups esp SI_USER
The following changes are available at:
git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git siginfo-minor-fixesv2
While answering a question about my earlier introduction to siginfo_layout I realized that the code introduces a small number of cases where unitialized memory is copied to userspace as a result of the fact that SI_USER is sometimes confused with another si_code.
This modifies all of the places in the kernel that generate a signal with si_code == SI_USER to fully initialize all of siginfo. Further this change updates architectures that are using si_code of 0 to mean something other than SI_USER to use TRAP_FIXME, FPE_FIXME, or BUS_FIXME to document the problem.
With all these changes take together there is no danger of copying unitialized values to userspace when SI_USER is mistaken for TRAP_FIXME, FPE_FIXME or BUS_FIXME.
This series also contains a fix for sh and a fix for openrisc where they are improperly generating a signal and the fix is obvious.
Eric W. Biederman (11):
signal: Simplify and fix kdb_send_sig
signal/sh: Ensure si_signo is initialized in do_divide_error signal/openrisc: Fix do_unaligned_access to send the proper signal signal/parisc: Document a conflict with SI_USER with SIGFPE signal/metag: Document a conflict with SI_USER with SIGFPE signal/powerpc: Document conflicts with SI_USER and SIGFPE and SIGTRAP signal/arm64: Document conflicts with SI_USER and SIGFPE,SIGTRAP,SIGBUS signal/arm: Document conflicts with SI_USER and SIGFPE
signal: Reduce copy_siginfo to just a memcpy
signal: Introduce clear_siginfo
signal: Ensure generic siginfos the kernel sends have all bits initialized
arch/arm/include/uapi/asm/siginfo.h | 13 ++++ arch/arm/vfp/vfpmodule.c | 2 +- arch/arm64/include/uapi/asm/siginfo.h | 21 ++++++ arch/arm64/kernel/fpsimd.c | 2 +- arch/arm64/mm/fault.c | 114 ++++++++++++++++---------------- arch/metag/include/uapi/asm/siginfo.h | 7 ++ arch/metag/kernel/traps.c | 2 +- arch/openrisc/kernel/traps.c | 10 +-- arch/parisc/include/uapi/asm/siginfo.h | 7 ++ arch/parisc/kernel/traps.c | 2 +- arch/powerpc/include/uapi/asm/siginfo.h | 15 +++++ arch/powerpc/kernel/traps.c | 10 +-- arch/sh/kernel/traps_32.c | 3 +- fs/fcntl.c | 1 + include/linux/signal.h | 13 ++-- ipc/mqueue.c | 1 + kernel/debug/kdb/kdb_main.c | 10 +-- kernel/debug/kdb/kdb_private.h | 2 +- kernel/signal.c | 27 +++++--- 19 files changed, 167 insertions(+), 95 deletions(-)
PATCH 1/11 signal: Simplify and fix kdb_send_sig
- Rename from kdb_send_sig_info to kdb_send_sig
As there is no meaningful siginfo sent
- Use SEND_SIG_PRIV instead of generating a siginfo for a kdb signal. The generated siginfo had a bogus rationale and was not correct in the face of pid namespaces. SEND_SIG_PRIV is simpler and actually correct.
- As the code grabs siglock just send the signal with siglock held instead of dropping siglock and attempting to grab it again.
- Move the sig_valid test into kdb_kill where it can generate a good error message.
--- kernel/debug/kdb/kdb_main.c | 10 ++-------- kernel/debug/kdb/kdb_private.h | 2 +- kernel/signal.c | 14 +++++++------- 3 files changed, 10 insertions(+), 16 deletions(-)
kernel/debug/kdb/kdb_main.c +2 -8
@@ -2441,7 +2441,6 @@ static int kdb_kill(int argc, const char **argv)long sig, pid;char *endp;struct task_struct *p; -struct siginfo info;if (argc !=2 )return KDB_ARGCOUNT ;
@@ -2449,7 +2448,7 @@ static int kdb_kill(int argc, const char **argv) sig =simple_strtol (argv[1 ], &endp,0 );if (*endp)return KDB_BADINT ; -if (sig >=0 ) { +if ((sig >=0 ) || !valid_signal (-sig)) {kdb_printf ("Invalid signal parameter.<-signal>\n" );return 0 ; }
@@ -2470,12 +2469,7 @@ static int kdb_kill(int argc, const char **argv)return 0 ; } p = p->group_leader; - info.si_signo = sig; - info.si_errno =0 ; - info.si_code =SI_USER ; - info.si_pid = pid;/* same capabilities as process being signalled */ - info.si_uid =0 ;/* kdb has root authority */ -kdb_send_sig_info (p, &info); +kdb_send_sig (p, sig);return 0 ; }
kernel/debug/kdb/kdb_private.h +1 -1
@@ -208,7 +208,7 @@ extern unsigned long kdb_task_state(const struct task_struct *p,extern void kdb_ps_suppressed (void );extern void kdb_ps1 (const struct task_struct *p);extern void kdb_print_nameval (const char *name,unsigned long val); -extern void kdb_send_sig_info (struct task_struct *p,struct siginfo *info); +extern void kdb_send_sig (struct task_struct *p,int sig);extern void kdb_meminfo_proc_show (void );extern char *kdb_getstr (char *,size_t ,const char *);extern void kdb_gdb_state_pass (char *buf);
kernel/signal.c +7 -7
@@ -3684,26 +3684,25 @@ void __init signals_init(void)#ifdef CONFIG_KGDB_KDB #include <linux/kdb.h> /* -* kdb_send_sig_info - Allows kdb to send signals without exposing +* kdb_send_sig - Allows kdb to send signals without exposing * signal internals. This function checks if the required locks are * available before calling the main signal code, to avoid kdb * deadlocks. */ -void -kdb_send_sig_info (struct task_struct *t,struct siginfo *info) +void kdb_send_sig (struct task_struct *t,int sig) {static struct task_struct *kdb_prev_t; -int sig, new_t; +int new_t, ret;if (!spin_trylock (&t->sighand->siglock)) {kdb_printf ("Can't do kill command now.\n" "The sigmask lock is held somewhere else in " "kernel, try again later\n" );return ; } -spin_unlock (&t->sighand->siglock); new_t = kdb_prev_t != t; kdb_prev_t = t;if (t->state !=TASK_RUNNING && new_t) { +spin_unlock (&t->sighand->siglock);kdb_printf ("Process is not RUNNING, sending a signal from " "kdb risks deadlock\n" "on the run queue locks. "
@@ -3712,8 +3711,9 @@ kdb_send_sig_info(struct task_struct *t, struct siginfo *info) "the deadlock.\n");return ; } - sig = info->si_signo; -if (send_sig_info (sig, info, t)) + ret =send_signal (sig,SEND_SIG_PRIV , t, false); +spin_unlock (&t->sighand->siglock); +if (ret)kdb_printf ("Fail to deliver Signal %d to process %d.\n" , sig, t->pid);else
Signature · 1 line
2.14.1
PATCH 2/11 signal/sh: Ensure si_signo is initialized in do_divide_error
In reply to Eric W. BiedermanSet si_signo.
--- arch/sh/kernel/traps_32.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/sh/kernel/traps_32.c +2 -1
@@ -609,7 +609,8 @@ asmlinkage void do_divide_error(unsigned long r4) break; } -force_sig_info (SIGFPE , &info, current); + info.si_signo =SIGFPE ; +force_sig_info (info.si_signo, &info, current); }#endif
Signature · 1 line
2.14.1
PATCH 3/11 signal/openrisc: Fix do_unaligned_access to send the proper signal
In reply to Eric W. BiedermanWhile reviewing the signal sending on openrisc the do_unaligned_access function stood out because it is obviously wrong. A comment about an si_code set above when actually si_code is never set. Leading to a random si_code being sent to userspace in the event of an unaligned access.
Looking further SIGBUS BUS_ADRALN is the proper pair of signal and si_code to send for an unaligned access. That is what other architectures do and what is required by posix.
Given that do_unaligned_access is broken in a way that no one can be relying on it on openrisc fix the code to just do the right thing.
--- arch/openrisc/kernel/traps.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
arch/openrisc/kernel/traps.c +5 -5
@@ -266,12 +266,12 @@ asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address)siginfo_t info;if (user_mode (regs)) { -/* Send a SIGSEGV */ - info.si_signo =SIGSEGV ; +/* Send a SIGBUS */ + info.si_signo =SIGBUS ; info.si_errno =0 ; -/* info.si_code has been set above */ - info.si_addr = (void *)address; -force_sig_info (SIGSEGV , &info, current); + info.si_code =BUS_ADRALN ; + info.si_addr = (void __user *)address; +force_sig_info (SIGBUS , &info, current); }else {printk ("KERNEL: Unaligned Access 0x%.8lx\n" , address);show_registers (regs);
Signature · 1 line
2.14.1
Re: [PATCH 03/11] signal/openrisc: Fix do_unaligned_access to send the proper signal
Quoted 6 lines · Eric W. Biederman
While reviewing the signal sending on openrisc the
do_unaligned_accessfunction stood out because it is obviously wrong. A comment about ansi_codeset above when actuallysi_codeis never set. Leading to a randomsi_codebeing sent to userspace in the event of an unaligned access.
Quoted 6 lines
Looking further SIGBUS
BUS_ADRALNis the proper pair of signal andsi_codeto send for an unaligned access. That is what other architectures do and what is required by posix.Given that
do_unaligned_accessis broken in a way that no one can be relying on it on openrisc fix the code to just do the right thing.
Thanks, this looks good to me.
I see you have a series of related issues, so I guess you want to get them merged together. Let me know if I should put this patch onto my queue seperately.
Trivia: this looks to have been copied from the mm page fault handling code, hence the strange comment.
$ grep -r "info.si_code has been set above" arch/ arch/cris/mm/fault.c: /* info.si_code has been set above */ arch/m32r/mm/fault.c: /* info.si_code has been set above */ arch/mn10300/mm/fault.c: /* info.si_code has been set above */ arch/openrisc/mm/fault.c: /* info.si_code has been set above */ arch/openrisc/kernel/traps.c: /* info.si_code has been set above */ arch/arc/mm/fault.c: /* info.si_code has been set above */ arch/xtensa/mm/fault.c: /* info.si_code has been set above */ arch/mips/mm/fault.c: /* info.si_code has been set above */ arch/score/mm/fault.c: /* info.si_code has been set above */ arch/frv/mm/fault.c: /* info.si_code has been set above */
-Stafford
Quoted 37 lines
Fixes 769a8a96229e ("OpenRISC: Traps")Cc Jonas Bonn <[email protected]>Cc Stefan Kristiansson <[email protected]>Cc Stafford Horne <[email protected]>Cc Arnd Bergmann <[email protected]>Signed-off-by "Eric W. Biederman" <[email protected]>--- arch/openrisc/kernel/traps.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)arch/openrisc/kernel/traps.c +5
-5@@ -266,12 +266,12 @@ asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address)siginfo_t info;if (user_mode (regs)) { -/* Send a SIGSEGV */ - info.si_signo =SIGSEGV ; +/* Send a SIGBUS */ + info.si_signo =SIGBUS ; info.si_errno =0 ; -/* info.si_code has been set above */ - info.si_addr = (void *)address; -force_sig_info (SIGSEGV , &info, current); + info.si_code =BUS_ADRALN ; + info.si_addr = (void __user *)address; +force_sig_info (SIGBUS , &info, current); }else {printk ("KERNEL: Unaligned Access 0x%.8lx\n" , address);show_registers (regs);Signature · 1 line
2.14.1
Re: [PATCH 03/11] signal/openrisc: Fix do_unaligned_access to send the proper signal
Quoted 14 lines · Stafford Horne
Quoted 6 lines · Eric W. Biederman
While reviewing the signal sending on openrisc the
do_unaligned_accessfunction stood out because it is obviously wrong. A comment about ansi_codeset above when actuallysi_codeis never set. Leading to a randomsi_codebeing sent to userspace in the event of an unaligned access.Quoted 6 lines
Looking further SIGBUS
BUS_ADRALNis the proper pair of signal andsi_codeto send for an unaligned access. That is what other architectures do and what is required by posix.Given that
do_unaligned_accessis broken in a way that no one can be relying on it on openrisc fix the code to just do the right thing.
Quoted 7 lines
Thanks, this looks good to me.
Acked-by Stafford Horne <[email protected]>I see you have a series of related issues, so I guess you want to get them merged together. Let me know if I should put this patch onto my queue seperately.
Yes, I have a follow on patch that restructures the code that fills out siginfo, and makes the it a little less error prone. I am hoping to merge all of it in the next merge window. *Fingers crossed*
And having it all in one tree will facilitate that.
Quoted 15 lines
Trivia: this looks to have been copied from the mm page fault handling code, hence the strange comment.
$ grep -r "info.si_code has been set above" arch/ arch/cris/mm/fault.c: /* info.si_code has been set above */ arch/m32r/mm/fault.c: /* info.si_code has been set above */ arch/mn10300/mm/fault.c: /* info.si_code has been set above */ arch/openrisc/mm/fault.c: /* info.si_code has been set above */ arch/openrisc/kernel/traps.c: /* info.si_code has been set above */ arch/arc/mm/fault.c: /* info.si_code has been set above */ arch/xtensa/mm/fault.c: /* info.si_code has been set above */ arch/mips/mm/fault.c: /* info.si_code has been set above */ arch/score/mm/fault.c: /* info.si_code has been set above */ arch/frv/mm/fault.c: /* info.si_code has been set above */
It looks like it. When I look at those I can actually find thesi_code being set higher up in the code. It looks like the si_code value was missed when this work was done.
Eric
PATCH 4/11 signal/parisc: Document a conflict with SI_USER with SIGFPE
In reply to Eric W. BiedermanSetting si_code to 0 results in a userspace seeing an si_code of 0. This is the same si_code as SI_USER. Posix and common sense requires that SI_USER not be a signal specific si_code. As such this use of 0 for the si_code is a pretty horribly broken ABI.
Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a value of __SI_KILL and now sees a value of SIL_KILL with the result that uid and pid fields are copied and which might copying the si_addr field by accident but certainly not by design. Making this a very flakey implementation.
Utilizing FPE_FIXME siginfo_layout will now return SIL_FAULT and the appropriate fields will reliably be copied.
This bug is 13 years old and parsic machines are no longer being built so I don't know if it possible or worth fixing it. But it is at least worth documenting this so other architectures don't make the same mistake.
Possible ABI fixes includee:
- Send the signal without siginfo
- Don't generate a signal
- Possibly assign and use an appropriate si_code
- Don't handle cases which can't happen
Cc: "James E.J. Bottomley" <[email protected]>
Cc: Helge Deller <[email protected]>
Cc: [email protected]
Ref: 313c01d3e3fd ("[PATCH] PA-RISC update for 2.6.0")
Histroy Tree: https://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git
--- arch/parisc/include/uapi/asm/siginfo.h | 7 +++++++ arch/parisc/kernel/traps.c | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-)
arch/parisc/include/uapi/asm/siginfo.h +7 -0
@@ -8,4 +8,11 @@#include <asm-generic/siginfo.h> +/* +* SIGFPE si_codes +*/ +#ifdef __KERNEL__ +#define FPE_FIXME 0/* Broken dup of SI_USER */ +#endif /* __KERNEL__ */ +#endif
arch/parisc/kernel/traps.c +1 -1
@@ -629,7 +629,7 @@ void notrace handle_interruption(int code, struct pt_regs *regs) si.si_signo =SIGFPE ;/* Set to zero, and let the userspace app figure it out from the insn pointed to by si_addr */ - si.si_code =0 ; + si.si_code =FPE_FIXME ; si.si_addr = (void __user *) regs->iaoq[0 ];force_sig_info (SIGFPE , &si, current);return ;
Signature · 1 line
2.14.1
Helge Deller
maintainerRe: [PATCH 04/11] signal/parisc: Document a conflict with SI_USER with SIGFPE
* Eric W. Biederman <[email protected]>:
Quoted 11 lines
Setting
si_codeto 0 results in a userspace seeing ansi_codeof 0. This is the samesi_codeasSI_USER. Posix and common sense requires thatSI_USERnot be a signal specificsi_code. As such this use of 0 for thesi_codeis a pretty horribly broken ABI.Further use of
si_code== 0 guaranteed thatcopy_siginfo_to_usersaw a value of__SI_KILLand now sees a value ofSIL_KILLwith the result that uid and pid fields are copied and which might copying thesi_addrfield by accident but certainly not by design. Making this a very flakey implementation.
Quoted 7 lines
Utilizing
FPE_FIXMEsiginfo_layoutwill now returnSIL_FAULTand the appropriate fields will reliably be copied.This bug is 13 years old and parsic machines are no longer being built so I don't know if it possible or worth fixing it. But it is at least worth documenting this so other architectures don't make the same mistake.
I think we should fix it, even if we now break the ABI.
It's about a "conditional trap" which needs to be handled by userspace. I doubt there is any Linux code out which is utilizing this parisc-specific trap.
I'd suggest to add a new FPE trap si_code (e.g. FPE_CONDTRAP). While at it, maybe we should include the already existing FPE_MDAOVF from the frv architecture, so that arch/frv/include/uapi/asm/siginfo.h can go completely.
Suggested patch is below.
I'm willing to test the patch below on the parisc architecture for a few weeks. And it will break arch/x86/kernel/signal_compat.c which needs looking at then too.
Thoughts?
Helge
[PATCH] parisc: Add FPE_CONDTRAP for conditional trap handling
Posix and common sense requires that SI_USER not be a signal specific si_code. Thus add a new FPE_CONDTRAP si_code for conditional traps.
arch/parisc/kernel/traps.c +3 -3
@@ -627,9 +627,9 @@ void notrace handle_interruption(int code, struct pt_regs *regs)on condition */ if (user_mode (regs)){ si.si_signo =SIGFPE ; -/* Set to zero, and let the userspace app figure it out from -the insn pointed to by si_addr */ - si.si_code =0 ; +/* Let userspace app figure out from the insn pointed +* to by si_addr */ + si.si_code =FPE_CONDTRAP ; si.si_addr = (void __user *) regs->iaoq[0 ];force_sig_info (SIGFPE , &si, current);return ;
include/uapi/asm-generic/siginfo.h +3 -1
@@ -193,7 +193,9 @@ typedef struct siginfo {#define FPE_FLTRES 6/* floating point inexact result */ #define FPE_FLTINV 7/* floating point invalid operation */ #define FPE_FLTSUB 8/* subscript out of range */ -#define NSIGFPE 8 +#define FPE_MDAOVF 9/* media overflow */ +#define FPE_CONDTRAP 10/* trap on condition */ +#define NSIGFPE 10/* * SIGSEGV si_codes
Re: [PATCH 04/11] signal/parisc: Document a conflict with SI_USER with SIGFPE
Quoted 32 lines · Helge Deller
* Eric W. Biederman <[email protected]>:
Quoted 11 lines
Setting
si_codeto 0 results in a userspace seeing ansi_codeof 0. This is the samesi_codeasSI_USER. Posix and common sense requires thatSI_USERnot be a signal specificsi_code. As such this use of 0 for thesi_codeis a pretty horribly broken ABI.Further use of
si_code== 0 guaranteed thatcopy_siginfo_to_usersaw a value of__SI_KILLand now sees a value ofSIL_KILLwith the result that uid and pid fields are copied and which might copying thesi_addrfield by accident but certainly not by design. Making this a very flakey implementation.Quoted 7 lines
Utilizing
FPE_FIXMEsiginfo_layoutwill now returnSIL_FAULTand the appropriate fields will reliably be copied.This bug is 13 years old and parsic machines are no longer being built so I don't know if it possible or worth fixing it. But it is at least worth documenting this so other architectures don't make the same mistake.
I think we should fix it, even if we now break the ABI.
It's about a "conditional trap" which needs to be handled by userspace. I doubt there is any Linux code out which is utilizing this parisc-specific trap.
I'd suggest to add a new FPE trap
si_code(e.g.FPE_CONDTRAP). While at it, maybe we should include the already existingFPE_MDAOVFfrom the frv architecture, so thatarch/frv/include/uapi/asm/siginfo.hcan go completely.
Quoted 7 lines
Suggested patch is below.
I'm willing to test the patch below on the parisc architecture for a few weeks. And it will break
arch/x86/kernel/signal_compat.cwhich needs looking at then too.Thoughts?
I like it.
We have the option of bringing either the ia64 or the frv si_codes into the generic fold. Is there any reason you choose frv? Last I looked ia64 tended in many aspects to be well thought out, and thus worth a careful look.
Given that a couple of weeks likely puts on the other side of the merge window I would like to start with my patch so I can close the potential copying of unitialized memory to userspace. Then we can build yours on top.
Although I am more than happy to add new si_codes now.
What I am in the final stages of testing and reviewing internally is the change to merge all of struct siginfo, struct compat_siginfo, copy_siginfo_from_user32 and copy_siginfo_to_user32 together.
I need another couple hours and I will be ready to post that.
For long term maintenance the more we can merge together the better, as clearly some of these bugs have persisted far too long. And getting collapsing the arch specific si_codes into just a set of si_codes looks like one more good step in that direction.
Eric
Quoted 43 lines
Helge
[PATCH] parisc: Add
FPE_CONDTRAPfor conditional trap handlingPosix and common sense requires that
SI_USERnot be a signal specificsi_code. Thus add a newFPE_CONDTRAPsi_codefor conditional traps.Signed-off-by Helge Deller <[email protected]>arch/parisc/kernel/traps.c +3
-3@@ -627,9 +627,9 @@ void notrace handle_interruption(int code, struct pt_regs *regs)on condition */ if (user_mode (regs)){ si.si_signo =SIGFPE ; -/* Set to zero, and let the userspace app figure it out from -the insn pointed to by si_addr */ - si.si_code =0 ; +/* Let userspace app figure out from the insn pointed +* to by si_addr */ + si.si_code =FPE_CONDTRAP ; si.si_addr = (void __user *) regs->iaoq[0 ];force_sig_info (SIGFPE , &si, current);return ;include/uapi/asm-generic/siginfo.h +3
-1@@ -193,7 +193,9 @@ typedef struct siginfo {#define FPE_FLTRES 6/* floating point inexact result */ #define FPE_FLTINV 7/* floating point invalid operation */ #define FPE_FLTSUB 8/* subscript out of range */ -#define NSIGFPE 8 +#define FPE_MDAOVF 9/* media overflow */ +#define FPE_CONDTRAP 10/* trap on condition */ +#define NSIGFPE 10/* * SIGSEGV si_codes
Re: [PATCH 04/11] signal/parisc: Document a conflict with SI_USER with SIGFPE
Quoted 36 lines · [email protected] (Eric W. Biederman) writes:
Quoted 34 lines · Helge Deller
* Eric W. Biederman <[email protected]>:
Quoted 11 lines
Setting
si_codeto 0 results in a userspace seeing ansi_codeof 0. This is the samesi_codeasSI_USER. Posix and common sense requires thatSI_USERnot be a signal specificsi_code. As such this use of 0 for thesi_codeis a pretty horribly broken ABI.Further use of
si_code== 0 guaranteed thatcopy_siginfo_to_usersaw a value of__SI_KILLand now sees a value ofSIL_KILLwith the result that uid and pid fields are copied and which might copying thesi_addrfield by accident but certainly not by design. Making this a very flakey implementation.Quoted 7 lines
Utilizing
FPE_FIXMEsiginfo_layoutwill now returnSIL_FAULTand the appropriate fields will reliably be copied.This bug is 13 years old and parsic machines are no longer being built so I don't know if it possible or worth fixing it. But it is at least worth documenting this so other architectures don't make the same mistake.
I think we should fix it, even if we now break the ABI.
It's about a "conditional trap" which needs to be handled by userspace. I doubt there is any Linux code out which is utilizing this parisc-specific trap.
I'd suggest to add a new FPE trap
si_code(e.g.FPE_CONDTRAP). While at it, maybe we should include the already existingFPE_MDAOVFfrom the frv architecture, so thatarch/frv/include/uapi/asm/siginfo.hcan go completely.Suggested patch is below.
Quoted 7 lines
Quoted 5 lines
I'm willing to test the patch below on the parisc architecture for a few weeks. And it will break
arch/x86/kernel/signal_compat.cwhich needs looking at then too.Thoughts?
I like it.
Your comments about the si_codes caused me to look into how they differ across the architectures and realize they also all need to be merged
into uapi/asm-generic/siginfo.h for sanity sake. In doing so I found
a couple of minor issues with my other unifications.
Rebased onto my tree your patch looks like the below. If it does not cause any regressions it looks like a perfect fix. The noticable change is that the first FPE si_code available across all architectures is 14 so I have used 14 instead of 10 for FPE_CONDTRAP.
Eric
From: Helge Deller <[email protected]>
Date: Sat, 13 Jan 2018 19:32:43 -0600
Subject: [PATCH] signal/parisc: Add FPE_CONDTRAP for conditional trap handling
Posix and common sense requires that SI_USER not be a signal specific si_code. Thus add a new FPE_CONDTRAP si_code for conditional traps.
-- EWB rebased onto my tree.
--- arch/parisc/include/uapi/asm/siginfo.h | 7 ------- arch/parisc/kernel/traps.c | 7 ++++--- include/uapi/asm-generic/siginfo.h | 3 ++- 3 files changed, 6 insertions(+), 11 deletions(-)
arch/parisc/include/uapi/asm/siginfo.h +0 -7
@@ -8,11 +8,4 @@#include <asm-generic/siginfo.h> -/* -* SIGFPE si_codes -*/ -#ifdef __KERNEL__ -#define FPE_FIXME 0/* Broken dup of SI_USER */ -#endif /* __KERNEL__ */ -#endif
arch/parisc/kernel/traps.c +4 -3
@@ -627,9 +627,10 @@ void notrace handle_interruption(int code, struct pt_regs *regs)on condition */ if (user_mode (regs)){ si.si_signo =SIGFPE ; -/* Set to zero, and let the userspace app figure it out from -the insn pointed to by si_addr */ - si.si_code =FPE_FIXME ; +/* Let userspace app figure it out from the insn pointed +* to by si_addr. +*/ + si.si_code =FPE_CONDTRAP ; si.si_addr = (void __user *) regs->iaoq[0 ];force_sig_info (SIGFPE , &si, current);return ;
include/uapi/asm-generic/siginfo.h +2 -1
@@ -229,7 +229,8 @@ typedef struct siginfo {# define __FPE_INVASC 12/* invalid ASCII digit */ # define __FPE_INVDEC 13/* invalid decimal digit */ #endif -#define NSIGFPE 13 +#define FPE_CONDTRAP 14/* trap on condition */ +#define NSIGFPE 14/* * SIGSEGV si_codes
Signature · 1 line
2.14.1
Re: [PATCH 04/11] signal/parisc: Document a conflict with SI_USER with SIGFPE
In reply to Helge DellerQuoted 32 lines · Helge Deller
* Eric W. Biederman <[email protected]>:
Quoted 11 lines
Setting
si_codeto 0 results in a userspace seeing ansi_codeof 0. This is the samesi_codeasSI_USER. Posix and common sense requires thatSI_USERnot be a signal specificsi_code. As such this use of 0 for thesi_codeis a pretty horribly broken ABI.Further use of
si_code== 0 guaranteed thatcopy_siginfo_to_usersaw a value of__SI_KILLand now sees a value ofSIL_KILLwith the result that uid and pid fields are copied and which might copying thesi_addrfield by accident but certainly not by design. Making this a very flakey implementation.Quoted 7 lines
Utilizing
FPE_FIXMEsiginfo_layoutwill now returnSIL_FAULTand the appropriate fields will reliably be copied.This bug is 13 years old and parsic machines are no longer being built so I don't know if it possible or worth fixing it. But it is at least worth documenting this so other architectures don't make the same mistake.
I think we should fix it, even if we now break the ABI.
It's about a "conditional trap" which needs to be handled by userspace. I doubt there is any Linux code out which is utilizing this parisc-specific trap.
I'd suggest to add a new FPE trap
si_code(e.g.FPE_CONDTRAP). While at it, maybe we should include the already existingFPE_MDAOVFfrom the frv architecture, so thatarch/frv/include/uapi/asm/siginfo.hcan go completely.
Quoted 5 lines
Suggested patch is below.
I'm willing to test the patch below on the parisc architecture for a few weeks. And it will break
arch/x86/kernel/signal_compat.cwhich needs looking at then too.
Have you managed to test this change?
I am sitting looking at another new FPE si_code and if this has been tested I figure FPE_CONDTRAP should get the next available FPE si_code and the other change should get the one that follows.
Eric
Helge Deller
maintainerRe: [PATCH 04/11] signal/parisc: Document a conflict with SI_USER with SIGFPE
Quoted 34 lines · Eric W. Biederman
Quoted 32 lines · Helge Deller
* Eric W. Biederman <[email protected]>:
Quoted 11 lines
Setting
si_codeto 0 results in a userspace seeing ansi_codeof 0. This is the samesi_codeasSI_USER. Posix and common sense requires thatSI_USERnot be a signal specificsi_code. As such this use of 0 for thesi_codeis a pretty horribly broken ABI.Further use of
si_code== 0 guaranteed thatcopy_siginfo_to_usersaw a value of__SI_KILLand now sees a value ofSIL_KILLwith the result that uid and pid fields are copied and which might copying thesi_addrfield by accident but certainly not by design. Making this a very flakey implementation.Quoted 7 lines
Utilizing
FPE_FIXMEsiginfo_layoutwill now returnSIL_FAULTand the appropriate fields will reliably be copied.This bug is 13 years old and parsic machines are no longer being built so I don't know if it possible or worth fixing it. But it is at least worth documenting this so other architectures don't make the same mistake.
I think we should fix it, even if we now break the ABI.
It's about a "conditional trap" which needs to be handled by userspace. I doubt there is any Linux code out which is utilizing this parisc-specific trap.
I'd suggest to add a new FPE trap
si_code(e.g.FPE_CONDTRAP). While at it, maybe we should include the already existingFPE_MDAOVFfrom the frv architecture, so thatarch/frv/include/uapi/asm/siginfo.hcan go completely.
Quoted 7 lines
Quoted 5 lines
Suggested patch is below.
I'm willing to test the patch below on the parisc architecture for a few weeks. And it will break
arch/x86/kernel/signal_compat.cwhich needs looking at then too.Have you managed to test this change?
Sadly I haven't done any further testing yet.
Quoted 3 lines
I am sitting looking at another new FPE
si_codeand if this has been tested I figureFPE_CONDTRAPshould get the next available FPEsi_codeand the other change should get the one that follows.
I'm fine either way. Do you have a git tree I can pull which includes all your patches? I can then start testing.
Helge
Re: [PATCH 04/11] signal/parisc: Document a conflict with SI_USER with SIGFPE
Quoted 37 lines · Helge Deller
Quoted 36 lines · Eric W. Biederman
Quoted 34 lines · Helge Deller
* Eric W. Biederman <[email protected]>:
Quoted 11 lines
Setting
si_codeto 0 results in a userspace seeing ansi_codeof 0. This is the samesi_codeasSI_USER. Posix and common sense requires thatSI_USERnot be a signal specificsi_code. As such this use of 0 for thesi_codeis a pretty horribly broken ABI.Further use of
si_code== 0 guaranteed thatcopy_siginfo_to_usersaw a value of__SI_KILLand now sees a value ofSIL_KILLwith the result that uid and pid fields are copied and which might copying thesi_addrfield by accident but certainly not by design. Making this a very flakey implementation.Quoted 7 lines
Utilizing
FPE_FIXMEsiginfo_layoutwill now returnSIL_FAULTand the appropriate fields will reliably be copied.This bug is 13 years old and parsic machines are no longer being built so I don't know if it possible or worth fixing it. But it is at least worth documenting this so other architectures don't make the same mistake.
I think we should fix it, even if we now break the ABI.
It's about a "conditional trap" which needs to be handled by userspace. I doubt there is any Linux code out which is utilizing this parisc-specific trap.
I'd suggest to add a new FPE trap
si_code(e.g.FPE_CONDTRAP). While at it, maybe we should include the already existingFPE_MDAOVFfrom the frv architecture, so thatarch/frv/include/uapi/asm/siginfo.hcan go completely.Suggested patch is below.
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines
I'm willing to test the patch below on the parisc architecture for a few weeks. And it will break
arch/x86/kernel/signal_compat.cwhich needs looking at then too.Have you managed to test this change?
Sadly I haven't done any further testing yet.
So at this point for purposed of testing I don't think it matters which number FPE_CONDTRAP gets as long as it is non-zero.
Quoted 7 lines
Quoted 4 lines
I am sitting looking at another new FPE
si_codeand if this has been tested I figureFPE_CONDTRAPshould get the next available FPEsi_codeand the other change should get the one that follows.I'm fine either way. Do you have a git tree I can pull which includes all your patches? I can then start testing.
Everything finalized is in Linus's tree. There is a patch pending review on linux-arch that defines FPE_FLTUNK that looks to be useful on several architectures.
I had probably misread our earlier exchange. I had hoped you had tested that FPE_CONDTRAP did not cause problems.
If that level of testing was complete I would have given FPE_CONDTRAP the next FPE number and FPE_FLTUNK the one after.
As it sounds like FPE_CONDTRAP hasn't been tested enough to know if it causes problems I will encourage the patches to be merged in the other order.
Eric
PATCH 5/11 signal/metag: Document a conflict with SI_USER with SIGFPE
In reply to Eric W. BiedermanSetting si_code to 0 results in a userspace seeing an si_code of 0. This is the same si_code as SI_USER. Posix and common sense requires that SI_USER not be a signal specific si_code. As such this use of 0 for the si_code is a pretty horribly broken ABI.
Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a value of __SI_KILL and now sees a value of SIL_KILL with the result hat uid and pid fields are copied and which might copying the si_addr field by accident but certainly not by design. Making this a very flakey implementation.
Utilizing FPE_FIXME siginfo_layout will now return SIL_FAULT and the appropriate fields will reliably be copied.
Possible ABI fixes includee:
- Send the signal without siginfo
- Don't generate a signal
- Possibly assign and use an appropriate si_code
- Don't handle cases which can't happen
Cc: James Hogan <[email protected]>
Cc: [email protected]
Ref: ac919f0883e5 ("metag: Traps")
--- arch/metag/include/uapi/asm/siginfo.h | 7 +++++++ arch/metag/kernel/traps.c | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-)
arch/metag/include/uapi/asm/siginfo.h +7 -0
@@ -6,4 +6,11 @@#include <asm-generic/siginfo.h> +/* +* SIGFPE si_codes +*/ +#ifdef __KERNEL__ +#define FPE_FIXME 0/* Broken dup of SI_USER */ +#endif /* __KERNEL__ */ +#endif
arch/metag/kernel/traps.c +1 -1
@@ -735,7 +735,7 @@ TBIRES fpe_handler(TBIRES State, int SigNum, int Triggers, int Inst, PTBI pTBI)else if (error_state &TXSTAT_FPE_INEXACT_BIT ) info.si_code =FPE_FLTRES ;else - info.si_code =0 ; + info.si_code =FPE_FIXME ; info.si_errno =0 ; info.si_addr = (__force void __user *)regs->ctx.CurrPC;force_sig_info (SIGFPE , &info, current);
Signature · 1 line
2.14.1
PATCH 6/11 signal/powerpc: Document conflicts with SI_USER and SIGFPE and SIGTRAP
In reply to Eric W. BiedermanSetting si_code to 0 results in a userspace seeing an si_code of 0. This is the same si_code as SI_USER. Posix and common sense requires that SI_USER not be a signal specific si_code. As such this use of 0 for the si_code is a pretty horribly broken ABI.
Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a value of __SI_KILL and now sees a value of SIL_KILL with the result that uid and pid fields are copied and which might copying the si_addr field by accident but certainly not by design. Making this a very flakey implementation.
Utilizing FPE_FIXME and TRAP_FIXME, siginfo_layout() will now return SIL_FAULT and the appropriate fields will be reliably copied.
Possible ABI fixes includee:
- Send the signal without siginfo
- Don't generate a signal
- Possibly assign and use an appropriate si_code
- Don't handle cases which can't happen
Cc: Paul Mackerras <[email protected]>
Cc: Kumar Gala <[email protected]>
Cc: Michael Ellerman <[email protected]>
Cc: Benjamin Herrenschmidt <[email protected]>
Cc: [email protected]
Ref: 9bad068c24d7 ("[PATCH] ppc32: support for e500 and 85xx")
Ref: 0ed70f6105ef ("PPC32: Provide proper siginfo information on various exceptions.") History Tree: https://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git
--- arch/powerpc/include/uapi/asm/siginfo.h | 15 +++++++++++++++ arch/powerpc/kernel/traps.c | 10 +++++----- 2 files changed, 20 insertions(+), 5 deletions(-)
arch/powerpc/include/uapi/asm/siginfo.h +15 -0
@@ -18,4 +18,19 @@#undef NSIGTRAP#define NSIGTRAP 4 +/* +* SIGFPE si_codes +*/ +#ifdef __KERNEL__ +#define FPE_FIXME 0/* Broken dup of SI_USER */ +#endif /* __KERNEL__ */ + +/* +* SIGTRAP si_codes +*/ +#ifdef __KERNEL__ +#define TRAP_FIXME 0/* Broken dup of SI_USER */ +#endif /* __KERNEL__ */ + +#endif /* _ASM_POWERPC_SIGINFO_H */
arch/powerpc/kernel/traps.c +5 -5
@@ -917,7 +917,7 @@ void unknown_exception(struct pt_regs *regs)printk ("Bad trap at PC: %lx, SR: %lx, vector=%lx\n" , regs->nip, regs->msr, regs->trap); -_exception (SIGTRAP , regs,0 ,0 ); +_exception (SIGTRAP , regs,TRAP_FIXME ,0 );exception_exit (prev_state); }
@@ -939,7 +939,7 @@ void instruction_breakpoint_exception(struct pt_regs *regs)void RunModeException (struct pt_regs *regs) { -_exception (SIGTRAP , regs,0 ,0 ); +_exception (SIGTRAP , regs,TRAP_FIXME ,0 ); }void single_step_exception (struct pt_regs *regs)
@@ -978,7 +978,7 @@ static void emulate_single_step(struct pt_regs *regs)static inline int __parse_fpscr (unsigned long fpscr) { -int ret =0 ; +int ret =FPE_FIXME ;/* Invalid operation */ if ((fpscr &FPSCR_VE ) && (fpscr &FPSCR_VX ))
@@ -1929,7 +1929,7 @@ void SPEFloatingPointException(struct pt_regs *regs)extern int do_spe_mathemu (struct pt_regs *regs);unsigned long spefscr;int fpexc_mode; -int code =0 ; +int code =FPE_FIXME ;int err;flush_spe_to_thread (current);
@@ -1998,7 +1998,7 @@ void SPEFloatingPointRoundException(struct pt_regs *regs)printk (KERN_ERR "unrecognized spe instruction " "in %s at %lx\n" , current->comm, regs->nip); }else { -_exception (SIGFPE , regs,0 , regs->nip); +_exception (SIGFPE , regs,FPE_FIXME , regs->nip);return ; } }
Signature · 1 line
2.14.1
PATCH 7/11 signal/arm64: Document conflicts with SI_USER and SIGFPE,SIGTRAP,SIGBUS
In reply to Eric W. BiedermanSetting si_code to 0 results in a userspace seeing an si_code of 0. This is the same si_code as SI_USER. Posix and common sense requires that SI_USER not be a signal specific si_code. As such this use of 0 for the si_code is a pretty horribly broken ABI.
Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a value of __SI_KILL and now sees a value of SIL_KILL with the result that uid and pid fields are copied and which might copying the si_addr field by accident but certainly not by design. Making this a very flakey implementation.
Utilizing FPE_FIXME, BUS_FIXME, TRAP_FIXME siginfo_layout will now return SIL_FAULT and the appropriate fields will be reliably copied.
But folks this is a new and unique kind of bad. This is massively
untested code bad. This is inventing new and unique was to get siginfo wrong bad. This is don't even think about Posix or what siginfo means bad. This is lots of eyeballs all missing the fact
that the code does the wrong thing bad. This is getting stuck and keep making the same mistake bad.
I really hope we can find a non userspace breaking fix for this on a port as new as arm64.
Possible ABI fixes include:
- Send the signal without siginfo
- Don't generate a signal
- Possibly assign and use an appropriate si_code
- Don't handle cases which can't happen
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Tyler Baicar <[email protected]>
Cc: James Morse <[email protected]>
Cc: Tony Lindgren <[email protected]>
Cc: Nicolas Pitre <[email protected]>
Cc: Olof Johansson <[email protected]>
Cc: Santosh Shilimkar <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Cc: [email protected]
Ref: 53631b54c870 ("arm64: Floating point and SIMD")
Ref: 32015c235603 ("arm64: exception: handle Synchronous External Abort")
Ref: 1d18c47c735e ("arm64: MMU fault handling and page table management")
--- arch/arm64/include/uapi/asm/siginfo.h | 21 +++++++ arch/arm64/kernel/fpsimd.c | 2 +- arch/arm64/mm/fault.c | 114 +++++++++++++++++----------------- kernel/signal.c | 4 ++ 4 files changed, 83 insertions(+), 58 deletions(-)
arch/arm64/include/uapi/asm/siginfo.h +21 -0
@@ -21,4 +21,25 @@#include <asm-generic/siginfo.h> +/* +* SIGFPE si_codes +*/ +#ifdef __KERNEL__ +#define FPE_FIXME 0/* Broken dup of SI_USER */ +#endif /* __KERNEL__ */ + +/* +* SIGBUS si_codes +*/ +#ifdef __KERNEL__ +#define BUS_FIXME 0/* Broken dup of SI_USER */ +#endif /* __KERNEL__ */ + +/* +* SIGTRAP si_codes +*/ +#ifdef __KERNEL__ +#define TRAP_FIXME 0/* Broken dup of SI_USER */ +#endif /* __KERNEL__ */ +#endif
arch/arm64/kernel/fpsimd.c +1 -1
@@ -867,7 +867,7 @@ asmlinkage void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs) asmlinkage void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs) {siginfo_t info; -unsigned int si_code =0 ; +unsigned int si_code =FPE_FIXME ;if (esr &FPEXC_IOF ) si_code =FPE_FLTINV ;
arch/arm64/mm/fault.c +57 -57
145 lines not on this page · raw message
kernel/signal.c +4 -0
@@ -2711,6 +2711,10 @@ enum siginfo_layout siginfo_layout(int sig, int si_code)#ifdef FPE_FIXME if ((sig ==SIGFPE ) && (si_code ==FPE_FIXME )) layout =SIL_FAULT ; +#endif +#ifdef BUS_FIXME +if ((sig ==SIGBUS ) && (si_code ==BUS_FIXME )) + layout =SIL_FAULT ;#endif }return layout;
Signature · 1 line
2.14.1
Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS
Quoted 4 lines · Eric W. Biederman
Setting
si_codeto 0 results in a userspace seeing ansi_codeof 0. This is the samesi_codeasSI_USER. Posix and common sense requires thatSI_USERnot be a signal specificsi_code. As such this use of 0 for thesi_codeis a pretty horribly broken ABI.
I think this situation may have come about because 0 is used as a padding value for "impossible" cases -- i.e., things that can't happen unless the kernel is broken, or things that are too unrecoverable for clean error reporting to be helpful.
In general, I think these values are not expected to reach userspace in practice.
This is not an excuse though -- and not 100% true -- so it's certainly worthy of cleanup.
It would be good to approach this similarly for arm and arm64, since the arm64 fault code is derived from arm.
Quoted 16 lines
Further use of
si_code== 0 guaranteed thatcopy_siginfo_to_usersaw a value of__SI_KILLand now sees a value ofSIL_KILLwith the result that uid and pid fields are copied and which might copying thesi_addrfield by accident but certainly not by design. Making this a very flakey implementation.Utilizing
FPE_FIXME,BUS_FIXME,TRAP_FIXMEsiginfo_layoutwill now returnSIL_FAULTand the appropriate fields will be reliably copied.But folks this is a new and unique kind of bad. This is massively
untested code bad. This is inventing new and unique was to get siginfo wrong bad. This is don't even think about Posix or what siginfo means bad. This is lots of eyeballs all missing the factthat the code does the wrong thing bad. This is getting stuck and keep making the same mistake bad.
Quoted 6 lines
I really hope we can find a non userspace breaking fix for this on a port as new as arm64.
Possible ABI fixes include:
- Send the signal without siginfo
- Don't generate a signal
The above two sould like ABI breaks?
Quoted 2 lines
- Possibly assign and use an appropriate
si_code
- Don't handle cases which can't happen
I think a mixture of these two is the best approach.
In any case, si_code == 0 here doesn't seem to have any explicit meaning. I think we can translate all of the arm64 faults to proper si_codes -- see my sketch below. Probably means a bit more thought though.
The only counterargument would be if there is software relying on these bogus signal cases getting si_code == 0 for a useful purpose.
The main reason I see to check for SI_USER is to allow a process to filter out spurious signals (say, an asynchronous I/O signal for which si_value would be garbage), and to print out diagnostics before (in the case of a well-behaved program) resetting the signal to SIG_DFL and killing itself to report the signal to the waiter.
Daemons may be more discerning about who is allowed to signal them, but overloading SIGBUS (say) as an IPC channel sounds like a very odd thing to do. The same probably applies to any signal that has nontrivial metadata.
Have you found software that is impacted by this in practice?
[...]
arch/arm64/kernel/fpsimd.c asmlinkage void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs) · line 873
Quoted 10 lines
+++
b/arch/arm64/kernel/fpsimd.carch/arm64/kernel/fpsimd.c +1
-1@@ -867,7 +867,7 @@ asmlinkage void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs) asmlinkage void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs) {siginfo_t info; -unsigned int si_code =0 ; +unsigned int si_code =FPE_FIXME ;if (esr &FPEXC_IOF ) si_code =FPE_FLTINV ;
This 0 can happen for vector operations where the implementation may not be able to report exactly what happened, for example where the implementer didn't want to pay the cost of tracking exactly what went wrong in each lane.
However, the FPEXC_* bits can be garbage in such a case rather than being all zero: we should be checking the TFV bit in the ESR here. This may be a bug.
Perhaps FPE_FLTINV should be returned in si_code for such cases: it's not otherwise used on arm64 -- invalid instructions would be reported as SIGILL/ILL_ILLOPC instead).
Otherwise, we might want to define a new code or arbitrarily pick one of the existing FLT_* since this is really a more benign condition than executing an illegal instruction. Alternatively, treat the fault as spurious and suppress it, but that doesn't feel right either.
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 599
Quoted 10 lines
arch/arm64/mm/fault.c +1
-1@@ -596,7 +596,7 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) info.si_signo =SIGBUS ; info.si_errno =0 ; - info.si_code =0 ; + info.si_code =BUS_FIXME ;
Probably BUS_OBJERR.
Quoted 5 lines
arch/arm64/mm/fault.c +0
-0if (esr & ESR_ELx_FnV) info.si_addr =NULL ;else @@ -607,70 +607,70 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) }
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 613
Quoted 10 lines
arch/arm64/mm/fault.c +4
-4static const struct fault_info fault_info[] = { - { do_bad,SIGBUS ,0 ,"ttbr address size fault" }, - { do_bad,SIGBUS ,0 ,"level 1 address size fault" }, - { do_bad,SIGBUS ,0 ,"level 2 address size fault" }, - { do_bad,SIGBUS ,0 ,"level 3 address size fault" }, + { do_bad,SIGBUS ,BUS_FIXME ,"ttbr address size fault" }, + { do_bad,SIGBUS ,BUS_FIXME ,"level 1 address size fault" }, + { do_bad,SIGBUS ,BUS_FIXME ,"level 2 address size fault" }, + { do_bad,SIGBUS ,BUS_FIXME ,"level 3 address size fault" },
Pagetable screwup or kernel/system/CPU bug -> SIGKILL, or panic().
[...]
Quoted 2 lines
arch/arm64/mm/fault.c +1
-1- { do_bad, SIGBUS, 0, "unknown 8" }, + { do_bad, SIGBUS, BUS_FIXME, "unknown 8" },
[...]
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 622
Quoted 1 line
arch/arm64/mm/fault.c +1
-0+ { do_bad, SIGBUS, BUS_FIXME, "unknown 12" },
Not architected, so they could mean absolutely anything. If they can happen at all, they are probably unsafe to ignore.
-> SIGKILL, or panic().
Similary for all the "unknown" codes in the table, which I omit for brevity.
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 626
Quoted 1 line
arch/arm64/mm/fault.c +1
-0+ { do_sea, SIGBUS, BUS_FIXME, "synchronous external abort" },
This si_code seems to be a fallback for if ACPI is absent or doesn't know what to do with this error.
-> SIGBUS/BUS_OBJERR?
Can probably legitimately happen for userspace for suitable MMIO mappings.
Perhaps it's more serious though in the presence of ACPI. Do we expect that ACPI can diagnose all localisable errors?
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 633
Quoted 4 lines
arch/arm64/mm/fault.c +4
-0+ { do_sea, SIGBUS, BUS_FIXME, "level 0 (translation table walk)" }, + { do_sea, SIGBUS, BUS_FIXME, "level 1 (translation table walk)" }, + { do_sea, SIGBUS, BUS_FIXME, "level 2 (translation table walk)" }, + { do_sea, SIGBUS, BUS_FIXME, "level 3 (translation table walk)" },
Pagetable screwup or kernel/system/CPU bug -> SIGKILL, or panic().
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 634
Quoted 1 line
arch/arm64/mm/fault.c +1
-0+ { do_sea, SIGBUS, BUS_FIXME, "synchronous parity or ECC error" }, // Reserved when RAS is implemented
Possibly SIGBUS/BUS_MCEERR_AR (though I don't know exactly what userspace is supposed to do with this or whether this implies the existence or certain kernel features for managing the error that may not be present on arm64...)
Otherwise, SIGKILL.
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 641
Quoted 4 lines
arch/arm64/mm/fault.c +4
-0+ { do_sea, SIGBUS, BUS_FIXME, "level 0 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented + { do_sea, SIGBUS, BUS_FIXME, "level 1 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented + { do_sea, SIGBUS, BUS_FIXME, "level 2 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented + { do_sea, SIGBUS, BUS_FIXME, "level 3 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
Process page tables corrupt: if the kernel couldn't fix this, the process can't reasonably fix it -> SIGKILL
Since this is a RAS-type error it could be triggered by a cosmic ray rather than requiring a kernel or system bug or other major failure, so we probably shouldn't panic the system if the error is localisable to a particular process.
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 658
Quoted 2 lines
arch/arm64/mm/fault.c +1
-0{ do_alignment_fault, SIGBUS, BUS_ADRALN, "alignment fault" }, + { do_bad, SIGBUS, BUS_FIXME, "TLB conflict abort" },
Broken kernel, kernel memory corruption, CPU/system bug etc.:
SIGKILL or panic().
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 659
Quoted 1 line
arch/arm64/mm/fault.c +1
-0+ { do_bad, SIGBUS, BUS_FIXME, "Unsupported atomic hardware update fault" },
Broken kernel, kernel memory corruption, CPU/system bug etc.:
SIGKILL or panic().
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 662
Quoted 1 line
arch/arm64/mm/fault.c +1
-0+ { do_bad, SIGBUS, BUS_FIXME, "implementation fault (lockdown abort)" },
Userspace shouldn't have access to lockdown: kernel/system bug -> SIGKILL or panic().
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 663
Quoted 1 line
arch/arm64/mm/fault.c +1
-0+ { do_bad, SIGBUS, BUS_FIXME, "implementation fault (unsupported exclusive)" },
If running on an implementation where this fault can happen in response to an exclusive load/store issued by userspace may fail somewhere in the memory system, this should probably be SIGBUS/BUS_OBJERR (or possibly a new BUS_* code).
This one may need to be hardware-dependent, if this fault can mean something different depending on the hardware (I'm gussing this possibility from "implementation" -- I've not checked the docs.)
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 672
Quoted 2 lines
arch/arm64/mm/fault.c +2
-0+ { do_bad, SIGBUS, BUS_FIXME, "section domain fault" }, + { do_bad, SIGBUS, BUS_FIXME, "page domain fault" },
Broken kernel, kernel memory corruption, CPU/system bug etc.:
SIGKILL or panic().
arch/arm64/mm/fault.c static struct fault_info __refdata debug_fault_info[] = { · line 742
Quoted 8 lines
};
int
handle_guest_sea(phys_addr_t addr, unsigned int esr)arch/arm64/mm/fault.c +3
-0@@ -739,11 +739,11 @@ static struct fault_info __refdata debug_fault_info[] = { + { do_bad, SIGBUS, BUS_FIXME, "unknown 3" }, + { do_bad, SIGTRAP, TRAP_FIXME, "aarch32 vector catch" }, + { do_bad, SIGBUS, BUS_FIXME, "unknown 7" }, };
Impossible (?), or meaning unknown.
SIGKILL/panic() for these? Or possibly (since these are probably well localised errors) SIGILL/ILL_ILLOPC.
Cheers
---Dave
Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS
Quoted 14 lines · Dave Martin
Quoted 4 lines · Eric W. Biederman
Setting
si_codeto 0 results in a userspace seeing ansi_codeof 0. This is the samesi_codeasSI_USER. Posix and common sense requires thatSI_USERnot be a signal specificsi_code. As such this use of 0 for thesi_codeis a pretty horribly broken ABI.I think this situation may have come about because 0 is used as a padding value for "impossible" cases -- i.e., things that can't happen unless the kernel is broken, or things that are too unrecoverable for clean error reporting to be helpful.
In general, I think these values are not expected to reach userspace in practice.
Quoted 6 lines
This is not an excuse though -- and not 100% true -- so it's certainly worthy of cleanup.
It would be good to approach this similarly for arm and arm64, since the arm64 fault code is derived from arm.
In this case the fault_info is something I have only seen on arm64. I have been approaching all architectures the same way.
If there is insufficient information without architecture expertise to fix this class of error I have been ading FPE_FIXME to them.
Quoted 16 lines
Quoted 16 lines
Further use of
si_code== 0 guaranteed thatcopy_siginfo_to_usersaw a value of__SI_KILLand now sees a value ofSIL_KILLwith the result that uid and pid fields are copied and which might copying thesi_addrfield by accident but certainly not by design. Making this a very flakey implementation.Utilizing
FPE_FIXME,BUS_FIXME,TRAP_FIXMEsiginfo_layoutwill now returnSIL_FAULTand the appropriate fields will be reliably copied.But folks this is a new and unique kind of bad. This is massively
untested code bad. This is inventing new and unique was to get siginfo wrong bad. This is don't even think about Posix or what siginfo means bad. This is lots of eyeballs all missing the factthat the code does the wrong thing bad. This is getting stuck and keep making the same mistake bad.
Quoted 8 lines
Quoted 6 lines
I really hope we can find a non userspace breaking fix for this on a port as new as arm64.
Possible ABI fixes include:
- Send the signal without siginfo
- Don't generate a signalThe above two sould like ABI breaks?
They are ways I have seen code on other platforms deal with not information to generate siginfo. Sending the signal without siginfo is roughly equivalent to your send SIGKILL suggestion below.
A good example of that is code that calls force_sigsegv.
Calling "force_sig(SIGBUS, current);" is perfectly valid. And then the parent when it reaped the process would have a little more information to go on when guessing what happened to the process.
Quoted 8 lines
Quoted 2 lines
- Possibly assign and use an appropriate
si_code
- Don't handle cases which can't happenI think a mixture of these two is the best approach.
In any case,
si_code== 0 here doesn't seem to have any explicit meaning. I think we can translate all of the arm64 faults to propersi_codes-- see my sketch below. Probably means a bit more thought though.
Yes I would be very happy to see that.
Quoted 9 lines
The only counterargument would be if there is software relying on these bogus signal cases getting
si_code== 0 for a useful purpose.The main reason I see to check for
SI_USERis to allow a process to filter out spurious signals (say, an asynchronous I/O signal for whichsi_valuewould be garbage), and to print out diagnostics before (in the case of a well-behaved program) resetting the signal toSIG_DFLand killing itself to report the signal to the waiter.
Quoted 4 lines
Daemons may be more discerning about who is allowed to signal them, but overloading SIGBUS (say) as an IPC channel sounds like a very odd thing to do. The same probably applies to any signal that has nontrivial metadata.
Agreed. Although I have seen ltp test cases that do crazy things like that.
Quoted 1 line
Have you found software that is impacted by this in practice?
No.
I don't expect many userspace applications look at siginfo and everything I have found is some rare hard to trigger non-x86 case which limits the exposure to userspace applications tremendously.
The angle I am coming at all of this from is that the linux kernel code that filled out out struct siginfo was not comprehensible or correct. Internal to the kernel it was using a magic value (not exportable to userspace) in the upper bits of si_code. That was causing problems for signal injection and converting signals from 32bit to 64bit, and from 64bit to 32bit.
So I wrote kernel/signal.c:siginfo_layout() to figure out which fields of struct siginfo should be sent to userspace. In doing so I discovered that using 0 in si_code (aka SI_USER) is ambiguous, and problematic.
Unfortuantely in most of the cases I have spotted using 0 in the si_code requires architectural knowledge that I don't currently have to sort out. So the best I can do is change si_code from 0 to FPE_FIXME/BUS_FIXME/TRAP_FIXME and bring the architecture maintainers attention to this area.
One of the problems that results from all of this is that we copy
unitialized data to userspace. I am slowly unifying and cleaning the
code up so that the code is simple enough we can be certain we are not copying unitialized data to userspace.
With si_coes of FPE_FIXME/BUS_FIXME/TRAP_FIXME I can at least attempt to keep the craziness from happening.
My next step is to unify struct siginfo and struct compat_siginfo and the functions that copy them to userspace because there are very siginficant problems there.
All of that said I like the way you are thinking about fixing these issues.
Quoted 22 lines
[...]
arch/arm64/kernel/fpsimd.c asmlinkage void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs) · line 873
Quoted 10 lines
+++
b/arch/arm64/kernel/fpsimd.carch/arm64/kernel/fpsimd.c +1
-1@@ -867,7 +867,7 @@ asmlinkage void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs) asmlinkage void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs) {siginfo_t info; -unsigned int si_code =0 ; +unsigned int si_code =FPE_FIXME ;if (esr &FPEXC_IOF ) si_code =FPE_FLTINV ;This 0 can happen for vector operations where the implementation may not be able to report exactly what happened, for example where the implementer didn't want to pay the cost of tracking exactly what went wrong in each lane.
However, the FPEXC_* bits can be garbage in such a case rather than being all zero: we should be checking the TFV bit in the ESR here. This may be a bug.
Quoted 8 lines
Perhaps
FPE_FLTINVshould be returned insi_codefor such cases: it's not otherwise used on arm64 -- invalid instructions would be reported as SIGILL/ILL_ILLOPC instead).Otherwise, we might want to define a new code or arbitrarily pick one of the existing FLT_* since this is really a more benign condition than executing an illegal instruction. Alternatively, treat the fault as spurious and suppress it, but that doesn't feel right either.
I would love to see this sorted out. There is a very similar pattern on several different architectures. I suspect if we have a clean solution on one architecture the other architectures will be able to use that solution as well.
Quoted 67 lines
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 599
Quoted 10 lines
arch/arm64/mm/fault.c +1
-1@@ -596,7 +596,7 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) info.si_signo =SIGBUS ; info.si_errno =0 ; - info.si_code =0 ; + info.si_code =BUS_FIXME ;Probably
BUS_OBJERR.Quoted 5 lines
arch/arm64/mm/fault.c +0
-0if (esr & ESR_ELx_FnV) info.si_addr =NULL ;else @@ -607,70 +607,70 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) }arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 613
Quoted 10 lines
arch/arm64/mm/fault.c +4
-4static const struct fault_info fault_info[] = { - { do_bad,SIGBUS ,0 ,"ttbr address size fault" }, - { do_bad,SIGBUS ,0 ,"level 1 address size fault" }, - { do_bad,SIGBUS ,0 ,"level 2 address size fault" }, - { do_bad,SIGBUS ,0 ,"level 3 address size fault" }, + { do_bad,SIGBUS ,BUS_FIXME ,"ttbr address size fault" }, + { do_bad,SIGBUS ,BUS_FIXME ,"level 1 address size fault" }, + { do_bad,SIGBUS ,BUS_FIXME ,"level 2 address size fault" }, + { do_bad,SIGBUS ,BUS_FIXME ,"level 3 address size fault" },Pagetable screwup or
kernel/system/CPUbug -> SIGKILL, orpanic().[...]
Quoted 2 lines
arch/arm64/mm/fault.c +1
-1- { do_bad, SIGBUS, 0, "unknown 8" }, + { do_bad, SIGBUS, BUS_FIXME, "unknown 8" },[...]
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 622
Quoted 1 line
arch/arm64/mm/fault.c +1
-0+ { do_bad, SIGBUS, BUS_FIXME, "unknown 12" },Not architected, so they could mean absolutely anything. If they can happen at all, they are probably unsafe to ignore.
-> SIGKILL, or
panic().Similary for all the "unknown" codes in the table, which I omit for brevity.
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 626
Quoted 1 line
arch/arm64/mm/fault.c +1
-0+ { do_sea, SIGBUS, BUS_FIXME, "synchronous external abort" },This
si_codeseems to be a fallback for if ACPI is absent or doesn't know what to do with this error.-> SIGBUS/BUS_OBJERR?
Can probably legitimately happen for userspace for suitable MMIO mappings.
Perhaps it's more serious though in the presence of ACPI. Do we expect that ACPI can diagnose all localisable errors?
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 633
Quoted 4 lines
arch/arm64/mm/fault.c +4
-0+ { do_sea, SIGBUS, BUS_FIXME, "level 0 (translation table walk)" }, + { do_sea, SIGBUS, BUS_FIXME, "level 1 (translation table walk)" }, + { do_sea, SIGBUS, BUS_FIXME, "level 2 (translation table walk)" }, + { do_sea, SIGBUS, BUS_FIXME, "level 3 (translation table walk)" },Pagetable screwup or
kernel/system/CPUbug -> SIGKILL, orpanic().
Quoted 8 lines
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 634
Quoted 1 line
arch/arm64/mm/fault.c +1
-0+ { do_sea, SIGBUS, BUS_FIXME, "synchronous parity or ECC error" }, // Reserved when RAS is implementedPossibly SIGBUS/BUS_MCEERR_AR (though I don't know exactly what userspace is supposed to do with this or whether this implies the existence or certain kernel features for managing the error that may not be present on arm64...)
Otherwise, SIGKILL.
Yes. The AR Action Required and AO Action optional bits I don't quite
understand. But BUS_MCEERR_AR does sound like a good fit.
Quoted 45 lines
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 641
Quoted 4 lines
arch/arm64/mm/fault.c +4
-0+ { do_sea, SIGBUS, BUS_FIXME, "level 0 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented + { do_sea, SIGBUS, BUS_FIXME, "level 1 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented + { do_sea, SIGBUS, BUS_FIXME, "level 2 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented + { do_sea, SIGBUS, BUS_FIXME, "level 3 synchronous parity error (translation table walk)" }, // Reserved when RAS is implementedProcess page tables corrupt: if the kernel couldn't fix this, the process can't reasonably fix it -> SIGKILL
Since this is a RAS-type error it could be triggered by a cosmic ray rather than requiring a kernel or system bug or other major failure, so we probably shouldn't panic the system if the error is localisable to a particular process.
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 658
Quoted 2 lines
arch/arm64/mm/fault.c +1
-0{ do_alignment_fault, SIGBUS, BUS_ADRALN, "alignment fault" }, + { do_bad, SIGBUS, BUS_FIXME, "TLB conflict abort" },Broken kernel, kernel memory corruption, CPU/system bug etc.:
SIGKILL orpanic().arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 659
Quoted 1 line
arch/arm64/mm/fault.c +1
-0+ { do_bad, SIGBUS, BUS_FIXME, "Unsupported atomic hardware update fault" },Broken kernel, kernel memory corruption, CPU/system bug etc.:
SIGKILL orpanic().arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 662
Quoted 1 line
arch/arm64/mm/fault.c +1
-0+ { do_bad, SIGBUS, BUS_FIXME, "implementation fault (lockdown abort)" },Userspace shouldn't have access to lockdown: kernel/system bug -> SIGKILL or
panic().arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 663
Quoted 1 line
arch/arm64/mm/fault.c +1
-0+ { do_bad, SIGBUS, BUS_FIXME, "implementation fault (unsupported exclusive)" },If running on an implementation where this fault can happen in response to an exclusive load/store issued by userspace may fail somewhere in the memory system, this should probably be SIGBUS/BUS_OBJERR (or possibly a new BUS_* code).
This one may need to be hardware-dependent, if this fault can mean something different depending on the hardware (I'm gussing this possibility from "implementation" -- I've not checked the docs.)
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 672
Quoted 2 lines
arch/arm64/mm/fault.c +2
-0+ { do_bad, SIGBUS, BUS_FIXME, "section domain fault" }, + { do_bad, SIGBUS, BUS_FIXME, "page domain fault" },Broken kernel, kernel memory corruption, CPU/system bug etc.:
SIGKILL orpanic().Quoted 2 lines
};
Quoted 10 lines
arch/arm64/mm/fault.c static struct fault_info __refdata debug_fault_info[] = { · line 742
Quoted 6 lines
int
handle_guest_sea(phys_addr_t addr, unsigned int esr)arch/arm64/mm/fault.c +3
-0@@ -739,11 +739,11 @@ static struct fault_info __refdata debug_fault_info[] = { + { do_bad, SIGBUS, BUS_FIXME, "unknown 3" }, + { do_bad, SIGTRAP, TRAP_FIXME, "aarch32 vector catch" }, + { do_bad, SIGBUS, BUS_FIXME, "unknown 7" }, };Impossible (?), or meaning unknown.
SIGKILL/panic() for these? Or possibly (since these are probably well localised errors) SIGILL/ILL_ILLOPC.
I like the way you are thinking on these, and I'd love to see them fixed.
Eric
Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS
Quoted 20 lines · Eric W. Biederman
Quoted 18 lines · Dave Martin
Quoted 4 lines · Eric W. Biederman
Setting
si_codeto 0 results in a userspace seeing ansi_codeof 0. This is the samesi_codeasSI_USER. Posix and common sense requires thatSI_USERnot be a signal specificsi_code. As such this use of 0 for thesi_codeis a pretty horribly broken ABI.I think this situation may have come about because 0 is used as a padding value for "impossible" cases -- i.e., things that can't happen unless the kernel is broken, or things that are too unrecoverable for clean error reporting to be helpful.
In general, I think these values are not expected to reach userspace in practice.
This is not an excuse though -- and not 100% true -- so it's certainly worthy of cleanup.
Quoted 5 lines
Quoted 2 lines
It would be good to approach this similarly for arm and arm64, since the arm64 fault code is derived from arm.
In this case the
fault_infois something I have only seen on arm64. I have been approaching all architectures the same way.
Bad guess on my part; this table-driven approach seems to be new for arm64.
Quoted 2 lines
If there is insufficient information without architecture expertise to fix this class of error I have been ading
FPE_FIXMEto them.
Fair enough.
Quoted 61 lines
Quoted 16 lines
Quoted 16 lines
Further use of
si_code== 0 guaranteed thatcopy_siginfo_to_usersaw a value of__SI_KILLand now sees a value ofSIL_KILLwith the result that uid and pid fields are copied and which might copying thesi_addrfield by accident but certainly not by design. Making this a very flakey implementation.Utilizing
FPE_FIXME,BUS_FIXME,TRAP_FIXMEsiginfo_layoutwill now returnSIL_FAULTand the appropriate fields will be reliably copied.But folks this is a new and unique kind of bad. This is massively
untested code bad. This is inventing new and unique was to get siginfo wrong bad. This is don't even think about Posix or what siginfo means bad. This is lots of eyeballs all missing the factthat the code does the wrong thing bad. This is getting stuck and keep making the same mistake bad.
Quoted 8 lines
Quoted 6 lines
I really hope we can find a non userspace breaking fix for this on a port as new as arm64.
Possible ABI fixes include:
- Send the signal without siginfo
- Don't generate a signalThe above two sould like ABI breaks?
They are ways I have seen code on other platforms deal with not information to generate siginfo. Sending the signal without siginfo is roughly equivalent to your send SIGKILL suggestion below.
A good example of that is code that calls
force_sigsegv.Calling "
force_sig(SIGBUS, current);" is perfectly valid. And then the parent when it reaped the process would have a little more information to go on when guessing what happened to the process.Quoted 8 lines
Quoted 2 lines
- Possibly assign and use an appropriate
si_code
- Don't handle cases which can't happenI think a mixture of these two is the best approach.
In any case,
si_code== 0 here doesn't seem to have any explicit meaning. I think we can translate all of the arm64 faults to propersi_codes-- see my sketch below. Probably means a bit more thought though.Yes I would be very happy to see that.
Quoted 9 lines
The only counterargument would be if there is software relying on these bogus signal cases getting
si_code== 0 for a useful purpose.The main reason I see to check for
SI_USERis to allow a process to filter out spurious signals (say, an asynchronous I/O signal for whichsi_valuewould be garbage), and to print out diagnostics before (in the case of a well-behaved program) resetting the signal toSIG_DFLand killing itself to report the signal to the waiter.Quoted 4 lines
Daemons may be more discerning about who is allowed to signal them, but overloading SIGBUS (say) as an IPC channel sounds like a very odd thing to do. The same probably applies to any signal that has nontrivial metadata.
Quoted 6 lines
Agreed. Although I have seen ltp test cases that do crazy things like that.
Quoted 1 line
Have you found software that is impacted by this in practice?
No.
Searching for si_code on codesearch.debian.net, I looked at a few random hits. Although this is far from exhaustive, I saw no instance of code that assumes some arch-specific meaning for SI_USER (or 0).
Most code seems to check for signal-specific si_code values before assuming that signal-specific signifo fields are valid; or for SI_USER (or si_code <= 0) before assuming that si_uid and si_pid are valid.
Returning proper values for si_code values in place of "0" would fix rather than break such cases.
Quoted 6 lines
I don't expect many userspace applications look at siginfo and everything I have found is some rare hard to trigger non-x86 case which limits the exposure to userspace applications tremendously.
The angle I am coming at all of this from is that the linux kernel code that filled out out struct siginfo was not comprehensible or correct.
I think "not comprehensible or correct" is a pretty good summary of all signal-related code...
Quoted 20 lines
Internal to the kernel it was using a magic value (not exportable to userspace) in the upper bits of
si_code. That was causing problems for signal injection and converting signals from 32bit to 64bit, and from 64bit to 32bit.So I wrote kernel/signal.c:siginfo_layout() to figure out which fields of struct siginfo should be sent to userspace. In doing so I discovered that using 0 in
si_code(akaSI_USER) is ambiguous, and problematic.Unfortuantely in most of the cases I have spotted using 0 in the
si_coderequires architectural knowledge that I don't currently have to sort out. So the best I can do is changesi_codefrom 0 to FPE_FIXME/BUS_FIXME/TRAP_FIXME and bring the architecture maintainers attention to this area.One of the problems that results from all of this is that we copy
unitialized data to userspace. I am slowly unifying and cleaning the
code up so that the code is simple enough we can be certain we are not copying unitialized data to userspace.
Quoted 6 lines
With
si_coesof FPE_FIXME/BUS_FIXME/TRAP_FIXME I can at least attempt to keep the craziness from happening.My next step is to unify struct siginfo and struct
compat_siginfoand the functions that copy them to userspace because there are very siginficant problems there.
All of which sounds valuable.
Quoted 2 lines
All of that said I like the way you are thinking about fixing these issues.
Is it feasible to have a different internal constant for SI_USER? Then the generic could warn if it sees si_code == 0. If the special nonzero KERNEL_SI_USER is seen instead, it is silently translated to SI_USER (0) for userspace. This might help us track down cases where 0 is passed by accident.
It may not be worth it though: if the affected cases are ones that happen never or almost never, a runtime BUG_ON() may not be helpful for tracking them down.
Also, I'm making an assumption that si_code always flows through some generic code before reaching userspace (maybe untrue).
Quoted 29 lines
Quoted 20 lines
arch/arm64/kernel/fpsimd.c asmlinkage void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs) · line 873
Quoted 10 lines
+++
b/arch/arm64/kernel/fpsimd.carch/arm64/kernel/fpsimd.c +1
-1@@ -867,7 +867,7 @@ asmlinkage void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs) asmlinkage void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs) {siginfo_t info; -unsigned int si_code =0 ; +unsigned int si_code =FPE_FIXME ;if (esr &FPEXC_IOF ) si_code =FPE_FLTINV ;This 0 can happen for vector operations where the implementation may not be able to report exactly what happened, for example where the implementer didn't want to pay the cost of tracking exactly what went wrong in each lane.
However, the FPEXC_* bits can be garbage in such a case rather than being all zero: we should be checking the TFV bit in the ESR here. This may be a bug.
Quoted 8 lines
Perhaps
FPE_FLTINVshould be returned insi_codefor such cases: it's not otherwise used on arm64 -- invalid instructions would be reported as SIGILL/ILL_ILLOPC instead).Otherwise, we might want to define a new code or arbitrarily pick one of the existing FLT_* since this is really a more benign condition than executing an illegal instruction. Alternatively, treat the fault as spurious and suppress it, but that doesn't feel right either.
Quoted 4 lines
I would love to see this sorted out. There is a very similar pattern on several different architectures. I suspect if we have a clean solution on one architecture the other architectures will be able to use that solution as well.
Since user code that relies on checking si_code for fp exceptions will probably already break in these cases, we can probably fudge things a bit here.
I'll have a think. IEEE may also define some rules that are relevant here...
For the proposed conversion of the si_code==0 cases for arm64, I'll draft an RFC for discussion (hopefully sometime this week).
[...]
Cheers
---Dave
Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS
Quoted 164 lines · Dave Martin
Quoted 20 lines · Eric W. Biederman
Quoted 18 lines · Dave Martin
Quoted 4 lines · Eric W. Biederman
Setting
si_codeto 0 results in a userspace seeing ansi_codeof 0. This is the samesi_codeasSI_USER. Posix and common sense requires thatSI_USERnot be a signal specificsi_code. As such this use of 0 for thesi_codeis a pretty horribly broken ABI.I think this situation may have come about because 0 is used as a padding value for "impossible" cases -- i.e., things that can't happen unless the kernel is broken, or things that are too unrecoverable for clean error reporting to be helpful.
In general, I think these values are not expected to reach userspace in practice.
This is not an excuse though -- and not 100% true -- so it's certainly worthy of cleanup.
Quoted 5 lines
Quoted 2 lines
It would be good to approach this similarly for arm and arm64, since the arm64 fault code is derived from arm.
In this case the
fault_infois something I have only seen on arm64. I have been approaching all architectures the same way.Bad guess on my part; this table-driven approach seems to be new for arm64.
Quoted 2 lines
If there is insufficient information without architecture expertise to fix this class of error I have been ading
FPE_FIXMEto them.Fair enough.
Quoted 61 lines
Quoted 16 lines
Quoted 16 lines
Further use of
si_code== 0 guaranteed thatcopy_siginfo_to_usersaw a value of__SI_KILLand now sees a value ofSIL_KILLwith the result that uid and pid fields are copied and which might copying thesi_addrfield by accident but certainly not by design. Making this a very flakey implementation.Utilizing
FPE_FIXME,BUS_FIXME,TRAP_FIXMEsiginfo_layoutwill now returnSIL_FAULTand the appropriate fields will be reliably copied.But folks this is a new and unique kind of bad. This is massively
untested code bad. This is inventing new and unique was to get siginfo wrong bad. This is don't even think about Posix or what siginfo means bad. This is lots of eyeballs all missing the factthat the code does the wrong thing bad. This is getting stuck and keep making the same mistake bad.
Quoted 8 lines
Quoted 6 lines
I really hope we can find a non userspace breaking fix for this on a port as new as arm64.
Possible ABI fixes include:
- Send the signal without siginfo
- Don't generate a signalThe above two sould like ABI breaks?
They are ways I have seen code on other platforms deal with not information to generate siginfo. Sending the signal without siginfo is roughly equivalent to your send SIGKILL suggestion below.
A good example of that is code that calls
force_sigsegv.Calling "
force_sig(SIGBUS, current);" is perfectly valid. And then the parent when it reaped the process would have a little more information to go on when guessing what happened to the process.Quoted 8 lines
Quoted 2 lines
- Possibly assign and use an appropriate
si_code
- Don't handle cases which can't happenI think a mixture of these two is the best approach.
In any case,
si_code== 0 here doesn't seem to have any explicit meaning. I think we can translate all of the arm64 faults to propersi_codes-- see my sketch below. Probably means a bit more thought though.Yes I would be very happy to see that.
Quoted 9 lines
The only counterargument would be if there is software relying on these bogus signal cases getting
si_code== 0 for a useful purpose.The main reason I see to check for
SI_USERis to allow a process to filter out spurious signals (say, an asynchronous I/O signal for whichsi_valuewould be garbage), and to print out diagnostics before (in the case of a well-behaved program) resetting the signal toSIG_DFLand killing itself to report the signal to the waiter.Quoted 4 lines
Daemons may be more discerning about who is allowed to signal them, but overloading SIGBUS (say) as an IPC channel sounds like a very odd thing to do. The same probably applies to any signal that has nontrivial metadata.
Quoted 6 lines
Agreed. Although I have seen ltp test cases that do crazy things like that.
Quoted 1 line
Have you found software that is impacted by this in practice?
No.
Searching for
si_codeon codesearch.debian.net, I looked at a few random hits. Although this is far from exhaustive, I saw no instance of code that assumes some arch-specific meaning forSI_USER(or 0).Most code seems to check for signal-specific
si_codevalues before assuming that signal-specific signifo fields are valid; or forSI_USER(orsi_code<= 0) before assuming thatsi_uidandsi_pidare valid.Returning proper values for
si_codevalues in place of "0" would fix rather than break such cases.Quoted 6 lines
I don't expect many userspace applications look at siginfo and everything I have found is some rare hard to trigger non-x86 case which limits the exposure to userspace applications tremendously.
The angle I am coming at all of this from is that the linux kernel code that filled out out struct siginfo was not comprehensible or correct.
I think "not comprehensible or correct" is a pretty good summary of all signal-related code...
Quoted 20 lines
Internal to the kernel it was using a magic value (not exportable to userspace) in the upper bits of
si_code. That was causing problems for signal injection and converting signals from 32bit to 64bit, and from 64bit to 32bit.So I wrote kernel/signal.c:siginfo_layout() to figure out which fields of struct siginfo should be sent to userspace. In doing so I discovered that using 0 in
si_code(akaSI_USER) is ambiguous, and problematic.Unfortuantely in most of the cases I have spotted using 0 in the
si_coderequires architectural knowledge that I don't currently have to sort out. So the best I can do is changesi_codefrom 0 to FPE_FIXME/BUS_FIXME/TRAP_FIXME and bring the architecture maintainers attention to this area.One of the problems that results from all of this is that we copy
unitialized data to userspace. I am slowly unifying and cleaning the
code up so that the code is simple enough we can be certain we are not copying unitialized data to userspace.Quoted 6 lines
With
si_coesof FPE_FIXME/BUS_FIXME/TRAP_FIXME I can at least attempt to keep the craziness from happening.My next step is to unify struct siginfo and struct
compat_siginfoand the functions that copy them to userspace because there are very siginficant problems there.All of which sounds valuable.
Quoted 2 lines
All of that said I like the way you are thinking about fixing these issues.
Is it feasible to have a different internal constant for
SI_USER? Then the generic could warn if it seessi_code== 0. If the special nonzeroKERNEL_SI_USERis seen instead, it is silently translated toSI_USER(0) for userspace. This might help us track down cases where 0 is passed by accident.
Quoted 6 lines
It may not be worth it though: if the affected cases are ones that happen never or almost never, a runtime
BUG_ON()may not be helpful for tracking them down.Also, I'm making an assumption that
si_codealways flows through some generic code before reaching userspace (maybe untrue).
The code does flow through a generic path, and I am in the middle of tightening that up right now. As filling out siginfo is error prone, and I need a guarantee that all of struct siginfo is initialized. Adding a warning if a arch fault hander uses si_code == 0 aka SI_USER would not be hard.
Given what you have found. Given that it seems to match my experience we can almost certainly change the code to just warn when the 0 is passed in for the si_code for fault handlers.
I want to ensure that all of the fields are filled in before I do that or else I risk passing unitialized values to userspace. But I like that as the long term goal for this code.
Quoted 38 lines
Quoted 29 lines
Quoted 20 lines
arch/arm64/kernel/fpsimd.c asmlinkage void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs) · line 873
Quoted 10 lines
+++
b/arch/arm64/kernel/fpsimd.carch/arm64/kernel/fpsimd.c +1
-1@@ -867,7 +867,7 @@ asmlinkage void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs) asmlinkage void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs) {siginfo_t info; -unsigned int si_code =0 ; +unsigned int si_code =FPE_FIXME ;if (esr &FPEXC_IOF ) si_code =FPE_FLTINV ;This 0 can happen for vector operations where the implementation may not be able to report exactly what happened, for example where the implementer didn't want to pay the cost of tracking exactly what went wrong in each lane.
However, the FPEXC_* bits can be garbage in such a case rather than being all zero: we should be checking the TFV bit in the ESR here. This may be a bug.
Quoted 8 lines
Perhaps
FPE_FLTINVshould be returned insi_codefor such cases: it's not otherwise used on arm64 -- invalid instructions would be reported as SIGILL/ILL_ILLOPC instead).Otherwise, we might want to define a new code or arbitrarily pick one of the existing FLT_* since this is really a more benign condition than executing an illegal instruction. Alternatively, treat the fault as spurious and suppress it, but that doesn't feel right either.
Quoted 4 lines
I would love to see this sorted out. There is a very similar pattern on several different architectures. I suspect if we have a clean solution on one architecture the other architectures will be able to use that solution as well.
Since user code that relies on checking
si_codefor fp exceptions will probably already break in these cases, we can probably fudge things a bit here.
Quoted 5 lines
I'll have a think. IEEE may also define some rules that are relevant here...
For the proposed conversion of the si_code==0 cases for arm64, I'll draft an RFC for discussion (hopefully sometime this week).
Sounds good.
I will keep FPE_FIXME as a place holder until this gets sorted out.
There is a second issue I am looking at in this location, and maybe I don't have to address it now. But it looks like the code is calling send_sig_info instead of force_sig_info for a synchronous exception. Am I reading that correctly?
Eric
Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS
Quoted 231 lines · Eric W. Biederman
Quoted 164 lines · Dave Martin
Quoted 20 lines · Eric W. Biederman
Quoted 18 lines · Dave Martin
Quoted 4 lines · Eric W. Biederman
Setting
si_codeto 0 results in a userspace seeing ansi_codeof 0. This is the samesi_codeasSI_USER. Posix and common sense requires thatSI_USERnot be a signal specificsi_code. As such this use of 0 for thesi_codeis a pretty horribly broken ABI.I think this situation may have come about because 0 is used as a padding value for "impossible" cases -- i.e., things that can't happen unless the kernel is broken, or things that are too unrecoverable for clean error reporting to be helpful.
In general, I think these values are not expected to reach userspace in practice.
This is not an excuse though -- and not 100% true -- so it's certainly worthy of cleanup.
Quoted 5 lines
Quoted 2 lines
It would be good to approach this similarly for arm and arm64, since the arm64 fault code is derived from arm.
In this case the
fault_infois something I have only seen on arm64. I have been approaching all architectures the same way.Bad guess on my part; this table-driven approach seems to be new for arm64.
Quoted 2 lines
If there is insufficient information without architecture expertise to fix this class of error I have been ading
FPE_FIXMEto them.Fair enough.
Quoted 61 lines
Quoted 16 lines
Quoted 16 lines
Further use of
si_code== 0 guaranteed thatcopy_siginfo_to_usersaw a value of__SI_KILLand now sees a value ofSIL_KILLwith the result that uid and pid fields are copied and which might copying thesi_addrfield by accident but certainly not by design. Making this a very flakey implementation.Utilizing
FPE_FIXME,BUS_FIXME,TRAP_FIXMEsiginfo_layoutwill now returnSIL_FAULTand the appropriate fields will be reliably copied.But folks this is a new and unique kind of bad. This is massively
untested code bad. This is inventing new and unique was to get siginfo wrong bad. This is don't even think about Posix or what siginfo means bad. This is lots of eyeballs all missing the factthat the code does the wrong thing bad. This is getting stuck and keep making the same mistake bad.
Quoted 8 lines
Quoted 6 lines
I really hope we can find a non userspace breaking fix for this on a port as new as arm64.
Possible ABI fixes include:
- Send the signal without siginfo
- Don't generate a signalThe above two sould like ABI breaks?
They are ways I have seen code on other platforms deal with not information to generate siginfo. Sending the signal without siginfo is roughly equivalent to your send SIGKILL suggestion below.
A good example of that is code that calls
force_sigsegv.Calling "
force_sig(SIGBUS, current);" is perfectly valid. And then the parent when it reaped the process would have a little more information to go on when guessing what happened to the process.Quoted 8 lines
Quoted 2 lines
- Possibly assign and use an appropriate
si_code
- Don't handle cases which can't happenI think a mixture of these two is the best approach.
In any case,
si_code== 0 here doesn't seem to have any explicit meaning. I think we can translate all of the arm64 faults to propersi_codes-- see my sketch below. Probably means a bit more thought though.Yes I would be very happy to see that.
Quoted 9 lines
The only counterargument would be if there is software relying on these bogus signal cases getting
si_code== 0 for a useful purpose.The main reason I see to check for
SI_USERis to allow a process to filter out spurious signals (say, an asynchronous I/O signal for whichsi_valuewould be garbage), and to print out diagnostics before (in the case of a well-behaved program) resetting the signal toSIG_DFLand killing itself to report the signal to the waiter.Quoted 4 lines
Daemons may be more discerning about who is allowed to signal them, but overloading SIGBUS (say) as an IPC channel sounds like a very odd thing to do. The same probably applies to any signal that has nontrivial metadata.
Quoted 6 lines
Agreed. Although I have seen ltp test cases that do crazy things like that.
Quoted 1 line
Have you found software that is impacted by this in practice?
No.
Searching for
si_codeon codesearch.debian.net, I looked at a few random hits. Although this is far from exhaustive, I saw no instance of code that assumes some arch-specific meaning forSI_USER(or 0).Most code seems to check for signal-specific
si_codevalues before assuming that signal-specific signifo fields are valid; or forSI_USER(orsi_code<= 0) before assuming thatsi_uidandsi_pidare valid.Returning proper values for
si_codevalues in place of "0" would fix rather than break such cases.Quoted 6 lines
I don't expect many userspace applications look at siginfo and everything I have found is some rare hard to trigger non-x86 case which limits the exposure to userspace applications tremendously.
The angle I am coming at all of this from is that the linux kernel code that filled out out struct siginfo was not comprehensible or correct.
I think "not comprehensible or correct" is a pretty good summary of all signal-related code...
Quoted 20 lines
Internal to the kernel it was using a magic value (not exportable to userspace) in the upper bits of
si_code. That was causing problems for signal injection and converting signals from 32bit to 64bit, and from 64bit to 32bit.So I wrote kernel/signal.c:siginfo_layout() to figure out which fields of struct siginfo should be sent to userspace. In doing so I discovered that using 0 in
si_code(akaSI_USER) is ambiguous, and problematic.Unfortuantely in most of the cases I have spotted using 0 in the
si_coderequires architectural knowledge that I don't currently have to sort out. So the best I can do is changesi_codefrom 0 to FPE_FIXME/BUS_FIXME/TRAP_FIXME and bring the architecture maintainers attention to this area.One of the problems that results from all of this is that we copy
unitialized data to userspace. I am slowly unifying and cleaning the
code up so that the code is simple enough we can be certain we are not copying unitialized data to userspace.Quoted 6 lines
With
si_coesof FPE_FIXME/BUS_FIXME/TRAP_FIXME I can at least attempt to keep the craziness from happening.My next step is to unify struct siginfo and struct
compat_siginfoand the functions that copy them to userspace because there are very siginficant problems there.All of which sounds valuable.
Quoted 2 lines
All of that said I like the way you are thinking about fixing these issues.
Is it feasible to have a different internal constant for
SI_USER? Then the generic could warn if it seessi_code== 0. If the special nonzeroKERNEL_SI_USERis seen instead, it is silently translated toSI_USER(0) for userspace. This might help us track down cases where 0 is passed by accident.Quoted 6 lines
It may not be worth it though: if the affected cases are ones that happen never or almost never, a runtime
BUG_ON()may not be helpful for tracking them down.Also, I'm making an assumption that
si_codealways flows through some generic code before reaching userspace (maybe untrue).The code does flow through a generic path, and I am in the middle of tightening that up right now. As filling out siginfo is error prone, and I need a guarantee that all of struct siginfo is initialized. Adding a warning if a arch fault hander uses
si_code== 0 akaSI_USERwould not be hard.Given what you have found. Given that it seems to match my experience we can almost certainly change the code to just warn when the 0 is passed in for the
si_codefor fault handlers.I want to ensure that all of the fields are filled in before I do that or else I risk passing unitialized values to userspace. But I like that as the long term goal for this code.
Quoted 38 lines
Quoted 29 lines
Quoted 20 lines
Review asmlinkage void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs) · line 873
Quoted 10 lines
+++
b/arch/arm64/kernel/fpsimd.c(quoted diff) +1
-1@@ -867,7 +867,7 @@ asmlinkage void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs) asmlinkage void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs) { siginfo_t info; - unsigned int si_code = 0; + unsigned int si_code = FPE_FIXME; if (esr & FPEXC_IOF) si_code = FPE_FLTINV;This 0 can happen for vector operations where the implementation may not be able to report exactly what happened, for example where the implementer didn't want to pay the cost of tracking exactly what went wrong in each lane.
However, the FPEXC_* bits can be garbage in such a case rather than being all zero: we should be checking the TFV bit in the ESR here. This may be a bug.
Quoted 8 lines
Perhaps
FPE_FLTINVshould be returned insi_codefor such cases: it's not otherwise used on arm64 -- invalid instructions would be reported as SIGILL/ILL_ILLOPC instead).Otherwise, we might want to define a new code or arbitrarily pick one of the existing FLT_* since this is really a more benign condition than executing an illegal instruction. Alternatively, treat the fault as spurious and suppress it, but that doesn't feel right either.
Quoted 4 lines
I would love to see this sorted out. There is a very similar pattern on several different architectures. I suspect if we have a clean solution on one architecture the other architectures will be able to use that solution as well.
Since user code that relies on checking
si_codefor fp exceptions will probably already break in these cases, we can probably fudge things a bit here.Quoted 5 lines
I'll have a think. IEEE may also define some rules that are relevant here...
For the proposed conversion of the si_code==0 cases for arm64, I'll draft an RFC for discussion (hopefully sometime this week).
Quoted 8 lines
Sounds good.
I will keep
FPE_FIXMEas a place holder until this gets sorted out.There is a second issue I am looking at in this location, and maybe I don't have to address it now. But it looks like the code is calling
send_sig_infoinstead offorce_sig_infofor a synchronous exception. Am I reading that correctly?
You mean floating-point exception? (almost anything that is not an interrupt can be a sunchronous exception on arm64).
Interesting though. arm and arm64 have send_sig_info() here, but all other arches seem to have force_sig_info().
sigaction(2) says:
"According to POSIX, the behavior of a process is undefined after it ignores a SIGFPE, SIGILL, or SIGSEGV signal that was not generated by kill(2) or raise(3)."
I can't find the POSIX reference for this, but the above suggests we don't _have_ to kill the process. arm/arm64 do seem inconsistent on this though, compared with other architectures. force_sig_info() might be needed to avoid a spin on architectures where writeback is suppressed when a precise fp exception trap is taken and the exception return address points back to the offending instruction. I'm struggling to deduce from the ARM ARM whether this applies here.
Maybe it doesn't matter what we do: the state of the standards seems to mean that user code that attempts to recover from FP exceptions will be nonportable and probably broken in any case...
Russell, do you remember the motivation for this? I'm looking at da41119af788 ("[PATCH] ARM: Don't force SIGFPE")
Cheers
---Dave
-8<-
From: Russell King <[email protected]>
Date: Wed, 29 Jun 2005 23:02:02 +0100
Subject: [PATCH 1/1] [PATCH] ARM: Don't force SIGFPE
We were forcing SIGFPE on to a user program for no good reason. Use send_sig_info() instead.
--- arch/arm/vfp/vfpmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm/vfp/vfpmodule.c +1 -1
@@ -89,7 +89,7 @@ void vfp_raise_sigfpe(unsigned int sicode, struct pt_regs *regs) current->thread.error_code =0 ; current->thread.trap_no =6 ; -force_sig_info (SIGFPE , &info, current); +send_sig_info (SIGFPE , &info, current); }static void vfp_panic (char *reason)
Signature · 1 line
2.1.4
Russell King - ARM Linux
maintainerRe: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS
In reply to Eric W. BiedermanQuoted 6 lines · Eric W. Biederman
I will keep
FPE_FIXMEas a place holder until this gets sorted out.There is a second issue I am looking at in this location, and maybe I don't have to address it now. But it looks like the code is calling
send_sig_infoinstead offorce_sig_infofor a synchronous exception. Am I reading that correctly?
VFP used to use force_sig_info(), but it seems to be really the wrong call to use. force_sig_info() checks whether the program decided to ignore or block the signal, and if it did, replaces the signal handler with the default handler and unblocks the signal.
Are you really suggesting that FP all FP signals should get this treatment?
Signature · 3 lines
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/ FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up According to speedtest.net: 8.21Mbps down 510kbps up
Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS
Quoted 8 lines · Russell King - ARM Linux
Quoted 6 lines · Eric W. Biederman
I will keep
FPE_FIXMEas a place holder until this gets sorted out.There is a second issue I am looking at in this location, and maybe I don't have to address it now. But it looks like the code is calling
send_sig_infoinstead offorce_sig_infofor a synchronous exception. Am I reading that correctly?
Quoted 7 lines
VFP used to use
force_sig_info(), but it seems to be really the wrong call to use.force_sig_info()checks whether the program decided to ignore or block the signal, and if it did, replaces the signal handler with the default handler and unblocks the signal.Are you really suggesting that FP all FP signals should get this treatment?
feenableexcept(FE_OVERFLOW) kind of means "I can't run safely past an fp overflow exception, please signal me instead".
If the process also blocked SIGFPE, that could be taken to mean "I can't run safely past an fp overflow exception _and_ I can't take SIGFPE either" ... i.e., if an fp overflow happens there is no way to proceed and it's really fatal.
What SIG_IGN ought to mean is rather more debatable, but again, the process could be asking for two opposite things: guarantee a SIGFPE is delivered instead of running past an fp exception, and also guarantee that SIGFPE is _not_ delivered.
It looks like arm and arm64 are different from most other arches (including x86) here, but I'm not sure what is considered correct, and it looks like the answer is not standardised. There's a possibility that some software goes subtly wrong on arm/arm64 where on other arches it would get terminated with SIGKILL.
Whether this matters depends on how harmless the fp exception is to the work of the program. I think if an exception is set to trap via feenableexcept() then that's a strong hint the programmer thinks that exception is not harmless. OTOH, trapping is not always available anyway...
Was there some particular program being broken by the force_sig_info() here?
Cheers
---Dave
Russell King - ARM Linux
maintainerRe: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS
Quoted 36 lines · Dave Martin
Quoted 8 lines · Russell King - ARM Linux
Quoted 6 lines · Eric W. Biederman
I will keep
FPE_FIXMEas a place holder until this gets sorted out.There is a second issue I am looking at in this location, and maybe I don't have to address it now. But it looks like the code is calling
send_sig_infoinstead offorce_sig_infofor a synchronous exception. Am I reading that correctly?Quoted 7 lines
VFP used to use
force_sig_info(), but it seems to be really the wrong call to use.force_sig_info()checks whether the program decided to ignore or block the signal, and if it did, replaces the signal handler with the default handler and unblocks the signal.Are you really suggesting that FP all FP signals should get this treatment?
feenableexcept(FE_OVERFLOW)kind of means "I can't run safely past an fp overflow exception, please signal me instead".If the process also blocked SIGFPE, that could be taken to mean "I can't run safely past an fp overflow exception _and_ I can't take SIGFPE either" ... i.e., if an fp overflow happens there is no way to proceed and it's really fatal.
What
SIG_IGNought to mean is rather more debatable, but again, the process could be asking for two opposite things: guarantee a SIGFPE is delivered instead of running past an fp exception, and also guarantee that SIGFPE is _not_ delivered.It looks like arm and arm64 are different from most other arches (including x86) here, but I'm not sure what is considered correct, and it looks like the answer is not standardised. There's a possibility that some software goes subtly wrong on arm/arm64 where on other arches it would get terminated with SIGKILL.
Quoted 5 lines
Whether this matters depends on how harmless the fp exception is to the work of the program. I think if an exception is set to trap via
feenableexcept()then that's a strong hint the programmer thinks that exception is not harmless. OTOH, trapping is not always available anyway...
Like many of these things, there is no clear answer. It's a set of conflicting requirements, and as you point out, even if you've called feenableexcept(), you are not guaranteed to get a trap.
However, do remember that FP exceptions on ARM hardware are already asynchronous - they get reported by the _next_ FP operation to the one that caused them, which means they could be raised by a library function sometime after it occured (when the library function decides to save the FP registers to the stack before it makes use of them.) It's entirely possible that the library function has blocked FP signals temporarily (not explicitly, just decided to block all signals while it does something sensitive) and will unblock them again afterwards - at which point we get the SIGFPE, and it would be quite right to deliver that signal to the user SIGFPE handler, rather than forcing it onto the program mid-library function.
It's also possible that SIGFPE could be blocked by another signal handler having been invoked, and it triggers the latent generation of the SIGFPE.
I'd be more inclined to agree with you if VFP exceptions were synchronous but they aren't.
Quoted 2 lines
Was there some particular program being broken by the
force_sig_info()here?
I don't recall.
Signature · 3 lines
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/ FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up According to speedtest.net: 8.21Mbps down 510kbps up
Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS
Quoted 2 lines · Russell King - ARM Linux
Quoted 1 line · Dave Martin
On Wed, Jan 17, 2018 at 11:57:09AM +0000, Russell King - ARM Linux wrote:
[...]
Quoted 49 lines
Quoted 27 lines
Quoted 7 lines
VFP used to use
force_sig_info(), but it seems to be really the wrong call to use.force_sig_info()checks whether the program decided to ignore or block the signal, and if it did, replaces the signal handler with the default handler and unblocks the signal.Are you really suggesting that FP all FP signals should get this treatment?
feenableexcept(FE_OVERFLOW)kind of means "I can't run safely past an fp overflow exception, please signal me instead".If the process also blocked SIGFPE, that could be taken to mean "I can't run safely past an fp overflow exception _and_ I can't take SIGFPE either" ... i.e., if an fp overflow happens there is no way to proceed and it's really fatal.
What
SIG_IGNought to mean is rather more debatable, but again, the process could be asking for two opposite things: guarantee a SIGFPE is delivered instead of running past an fp exception, and also guarantee that SIGFPE is _not_ delivered.It looks like arm and arm64 are different from most other arches (including x86) here, but I'm not sure what is considered correct, and it looks like the answer is not standardised. There's a possibility that some software goes subtly wrong on arm/arm64 where on other arches it would get terminated with SIGKILL.
Quoted 5 lines
Whether this matters depends on how harmless the fp exception is to the work of the program. I think if an exception is set to trap via
feenableexcept()then that's a strong hint the programmer thinks that exception is not harmless. OTOH, trapping is not always available anyway...Like many of these things, there is no clear answer. It's a set of conflicting requirements, and as you point out, even if you've called
feenableexcept(), you are not guaranteed to get a trap.However, do remember that FP exceptions on ARM hardware are already asynchronous - they get reported by the _next_ FP operation to the one that caused them, which means they could be raised by a library function sometime after it occured (when the library function decides to save the FP registers to the stack before it makes use of them.) It's entirely possible that the library function has blocked FP signals temporarily (not explicitly, just decided to block all signals while it does something sensitive) and will unblock them again afterwards - at which point we get the SIGFPE, and it would be quite right to deliver that signal to the user SIGFPE handler, rather than forcing it onto the program mid-library function.
Quoted 5 lines
It's also possible that SIGFPE could be blocked by another signal handler having been invoked, and it triggers the latent generation of the SIGFPE.
I'd be more inclined to agree with you if VFP exceptions were synchronous but they aren't.
Hmmm, it looks like imprecise fp exception traps are disallowed from ARMv8 onwards. I guess they made more sense when the FPU really was a coprocessor, or at least semidetached from the integer core.
I think force_sig_info() makes sense here if and only if the traps are guaranteed to be precise, so we probably should use this on arm64. Not arm though (alpha doesn't either, if I understand the code correctly.)
Does that make sense?
Apparently, few recent cores (at least ARM's own ones) support fp exception trapping anyway... 1176 may be the most recent.
Cheers
---Dave
Russell King - ARM Linux
maintainerRe: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS
Quoted 70 lines · Dave Martin
Quoted 2 lines · Russell King - ARM Linux
Quoted 1 line · Dave Martin
On Wed, Jan 17, 2018 at 11:57:09AM +0000, Russell King - ARM Linux wrote:
[...]
Quoted 49 lines
Quoted 27 lines
Quoted 7 lines
VFP used to use
force_sig_info(), but it seems to be really the wrong call to use.force_sig_info()checks whether the program decided to ignore or block the signal, and if it did, replaces the signal handler with the default handler and unblocks the signal.Are you really suggesting that FP all FP signals should get this treatment?
feenableexcept(FE_OVERFLOW)kind of means "I can't run safely past an fp overflow exception, please signal me instead".If the process also blocked SIGFPE, that could be taken to mean "I can't run safely past an fp overflow exception _and_ I can't take SIGFPE either" ... i.e., if an fp overflow happens there is no way to proceed and it's really fatal.
What
SIG_IGNought to mean is rather more debatable, but again, the process could be asking for two opposite things: guarantee a SIGFPE is delivered instead of running past an fp exception, and also guarantee that SIGFPE is _not_ delivered.It looks like arm and arm64 are different from most other arches (including x86) here, but I'm not sure what is considered correct, and it looks like the answer is not standardised. There's a possibility that some software goes subtly wrong on arm/arm64 where on other arches it would get terminated with SIGKILL.
Quoted 5 lines
Whether this matters depends on how harmless the fp exception is to the work of the program. I think if an exception is set to trap via
feenableexcept()then that's a strong hint the programmer thinks that exception is not harmless. OTOH, trapping is not always available anyway...Like many of these things, there is no clear answer. It's a set of conflicting requirements, and as you point out, even if you've called
feenableexcept(), you are not guaranteed to get a trap.However, do remember that FP exceptions on ARM hardware are already asynchronous - they get reported by the _next_ FP operation to the one that caused them, which means they could be raised by a library function sometime after it occured (when the library function decides to save the FP registers to the stack before it makes use of them.) It's entirely possible that the library function has blocked FP signals temporarily (not explicitly, just decided to block all signals while it does something sensitive) and will unblock them again afterwards - at which point we get the SIGFPE, and it would be quite right to deliver that signal to the user SIGFPE handler, rather than forcing it onto the program mid-library function.
Quoted 5 lines
It's also possible that SIGFPE could be blocked by another signal handler having been invoked, and it triggers the latent generation of the SIGFPE.
I'd be more inclined to agree with you if VFP exceptions were synchronous but they aren't.
Hmmm, it looks like imprecise fp exception traps are disallowed from ARMv8 onwards. I guess they made more sense when the FPU really was a coprocessor, or at least semidetached from the integer core.
I think
force_sig_info()makes sense here if and only if the traps are guaranteed to be precise, so we probably should use this on arm64. Not arm though (alpha doesn't either, if I understand the code correctly.)
Quoted 4 lines
Does that make sense?
Apparently, few recent cores (at least ARM's own ones) support fp exception trapping anyway... 1176 may be the most recent.
... and that makes the feenableexcept() argument about "A program really wants to know" moot. It can enable the exceptions in the FPSCR but its never going to receive a SIGFPE on CPUs that don't do exception trapping.
Signature · 3 lines
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/ FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up According to speedtest.net: 8.21Mbps down 510kbps up
Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS
Quoted 2 lines · Russell King - ARM Linux
Quoted 1 line · Dave Martin
On Wed, Jan 17, 2018 at 12:37:52PM +0000, Russell King - ARM Linux wrote:
[...]
Quoted 14 lines
Quoted 14 lines
Quoted 2 lines
I'd be more inclined to agree with you if VFP exceptions were synchronous but they aren't.
Hmmm, it looks like imprecise fp exception traps are disallowed from ARMv8 onwards. I guess they made more sense when the FPU really was a coprocessor, or at least semidetached from the integer core.
I think
force_sig_info()makes sense here if and only if the traps are guaranteed to be precise, so we probably should use this on arm64. Not arm though (alpha doesn't either, if I understand the code correctly.)Does that make sense?
Quoted 7 lines
Quoted 2 lines
Apparently, few recent cores (at least ARM's own ones) support fp exception trapping anyway... 1176 may be the most recent.
... and that makes the
feenableexcept()argument about "A program really wants to know" moot. It can enable the exceptions in the FPSCR but its never going to receive a SIGFPE on CPUs that don't do exception trapping.
Sort of. If the hardware doesn't support traps then those FP(S)CR bits can't be set. feenableexcept() returns -1 if the requested bits don't stick, but I'll bet there's software that doesn't bother to check...
Relying on fp exception traps therefore isn't portable, but software that does so can at least portably fail safe if it checks for the -1 return.
I'll cook up some RFC patches for arm64, then I could take a look at arm is nobody else is working on it.
Cheers
---Dave
Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS
In reply to Russell King - ARM LinuxQuoted 10 lines · Russell King - ARM Linux
Quoted 9 lines · Dave Martin
Quoted 8 lines · Russell King - ARM Linux
Quoted 6 lines · Eric W. Biederman
I will keep
FPE_FIXMEas a place holder until this gets sorted out.There is a second issue I am looking at in this location, and maybe I don't have to address it now. But it looks like the code is calling
send_sig_infoinstead offorce_sig_infofor a synchronous exception. Am I reading that correctly?
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
VFP used to use
force_sig_info(), but it seems to be really the wrong call to use.force_sig_info()checks whether the program decided to ignore or block the signal, and if it did, replaces the signal handler with the default handler and unblocks the signal.
That ignored and blocked behavior is a very weird implementation, but for a synchronous signal it amounts to enforcing coredump and then exit behavior. As the process does not continue past that point the behavior is not observable by userspace.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Are you really suggesting that FP all FP signals should get this treatment?
I am only suggesting that all synchronous signals, aka signals where it helps to point at the instruction from the signal information get that treatment. As the vast majority are synchronous I was asking about this one oddball case.
Quoted 13 lines
Quoted 13 lines
feenableexcept(FE_OVERFLOW)kind of means "I can't run safely past an fp overflow exception, please signal me instead".If the process also blocked SIGFPE, that could be taken to mean "I can't run safely past an fp overflow exception _and_ I can't take SIGFPE either" ... i.e., if an fp overflow happens there is no way to proceed and it's really fatal.
What
SIG_IGNought to mean is rather more debatable, but again, the process could be asking for two opposite things: guarantee a SIGFPE is delivered instead of running past an fp exception, and also guarantee that SIGFPE is _not_ delivered.
Quoted 5 lines
Quoted 5 lines
It looks like arm and arm64 are different from most other arches (including x86) here, but I'm not sure what is considered correct, and it looks like the answer is not standardised. There's a possibility that some software goes subtly wrong on arm/arm64 where on other arches it would get terminated with SIGKILL.
I looked it up yesterday to be clear, and POSIX actually says the behavior is implemenation dependent/undefined if you try to ignore SIGFPE.
Quoted 22 lines
Quoted 5 lines
Whether this matters depends on how harmless the fp exception is to the work of the program. I think if an exception is set to trap via
feenableexcept()then that's a strong hint the programmer thinks that exception is not harmless. OTOH, trapping is not always available anyway...Like many of these things, there is no clear answer. It's a set of conflicting requirements, and as you point out, even if you've called
feenableexcept(), you are not guaranteed to get a trap.However, do remember that FP exceptions on ARM hardware are already asynchronous - they get reported by the _next_ FP operation to the one that caused them, which means they could be raised by a library function sometime after it occured (when the library function decides to save the FP registers to the stack before it makes use of them.) It's entirely possible that the library function has blocked FP signals temporarily (not explicitly, just decided to block all signals while it does something sensitive) and will unblock them again afterwards - at which point we get the SIGFPE, and it would be quite right to deliver that signal to the user SIGFPE handler, rather than forcing it onto the program mid-library function.
Quoted 5 lines
It's also possible that SIGFPE could be blocked by another signal handler having been invoked, and it triggers the latent generation of the SIGFPE.
I'd be more inclined to agree with you if VFP exceptions were synchronous but they aren't.
From your description there still seems to be an association with an instruction so I don't know if I would really call the signal asynchronous. It sounds like the exception is delayed and not asynchronous.
Quoted 9 lines
Quoted 2 lines
Was there some particular program being broken by the
force_sig_info()here?I don't recall.
commit
da41119af78864d27ccbf505949df788d5e8aaf5Author: Russell King <[email protected]> Date: Wed Jun 29 23:02:02 2005 +0100
Quoted 6 lines
[PATCH] ARM: Don't force SIGFPE
We were forcing SIGFPE on to a user program for no good reason. Use
send_sig_info()instead.Signed-off-by Russell King <[email protected]>
The commit looks like it was a case of the code not looking right and you just switching to send_sig_info.
force_sig_info really out to be called something like synchronous_sig.
I am looking at sorting that out as part of cleaning up the signal handling. There is currently a small bug where under the right circumstances these synchronous signals might be improperly delivered after a thread specific signal. To make that very unlikely there is a special case in dequeue_signal for synchronous signals but it is imperfect and slower than necessary.
The function really ought to look something like:
void synch_sig(struct siginfo *info)
{
struct task_struct *tsk = current;
int sig = info->si_signo;
struct ksignal ksig;
struct k_sigaction *ka;
bool blocked, ignored;
unsigned long flags;
WARN_ON(!siginmask(sig, SYNCHRONOUS_MASK));
copy_siginfo(info, &ksig.info);
spin_lock_irqsave(&tsk->sighand->siglock, flags);
ka = &tsk->sighand->action[sig - 1];
ignored = ka->sa.sa_handler == SIG_IGN;
blocked = sigismember(&tsk->blocked, sig);
ksig.ka = *ka;
if (blocked || ignored) {
ksig.ka.sa.sa_handler = SIG_DFL;
} else if (ka->sa.sa_flags & SA_ONESHOT) {
ka->sa.sa_handler = SIG_DFL;
}
spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
if (ksig.ka.sa.sa_handler == SIG_DFL) {
do_coredump(&ksig->info);
do_group_exit(sig);
/* NOTREACHED */
}
handle_signal(&ksig, signal_pt_regs());
}Which is both clearer and faster and less buggy than the current implementation as it delivers the signal immediately with no chance of the signal queue to reorder things.
But it is going to take a little bit to get there as there are a number of implementations of handle_signal like the ones on arm and arm64 that perform needed register adjustments outside of handle_signal.
Eric
Russell King - ARM Linux
maintainerRe: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS
Quoted 5 lines · Eric W. Biederman
Quoted 1 line · Russell King - ARM Linux
From your description there still seems to be an association with an
instruction so I don't know if I would really call the signal asynchronous. It sounds like the exception is delayed and not asynchronous.
Traps can only be passed from ARM coprocessors by a coprocessor refusing to execute an instruction. That's what happens in this case - the VFP gets offered an instruction to execute. It accepts it, and the CPU continues, leaving the VFP to execute its instruction independently. If this instruction generates an error, then nothing happens at this point.
That error remains pending until the CPU offers the coprocessor the next VFP instruction, which it refuses. That causes an undefined instruction exception, and we trap into the kernel VFP code which reads the VFP status and works out what needs to be done.
What this means is that if you execute a VFP instruction, wait 10 minutes and then execute another VFP instruction, if the first VFP instruction raised an exception, you'll get to hear about it 10 minutes later.
You can use whatever weasel words you want to describe that situation, my choice is "asynchronous", your choice is "delayed". However, it is clearly not "synchronous", and arguing that we should report something synchronously that is not reported to _us_ synchronously (where synchronous means "at the same time") is IMHO daft.
So, let's take an example:
installs SIGFPE handler
..fp instructions.. one of which raises an exception returns to main loop
main loop blocks all signals while it sets stuff up calls ppoll()
In the synchronous SIGFPE delivery case, the SIGFPE handler will be called when the exception is generated in the FP code, and delivered at that time. The fact that the main loop blocks all signals happens later, so the users handler gets called as one expects.
In the VFP case, however, the FP instructions towards the end may not end up causing the exception to be signalled until sometime later, and as I've already explained, that may be the result of a C library function accessing the VFP registers. This could well end up trying to deliver the SIGFPE while signals are blocked, and we get drastically different behaviour if force_sig_info() is used.
In the VFP case, if force_sig_info() is used, the program gets killed at this point. In the non-VFP case, the program's signal handler was called.
Using send_sig_info() results in the already delayed or asynchronous signal being held off until ppoll() drops the blocking, at which point the signal is delivered, the program handles it in its handler, and the program continues to run.
So
1. non-VFP case, program doesn't get killed but gets the opportunity to handle the signal.
2. VFP case with send_sig_info, program doesn't get killed but gets the opportunity to handle the signal.
3. VFP case with force_sig_info, the program gets killed and dumps core.
Which one of these results in a big change of behaviour in your opinion?
Signature · 3 lines
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/ FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up According to speedtest.net: 8.21Mbps down 510kbps up
Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS
Quoted 65 lines · Russell King - ARM Linux
Quoted 5 lines · Eric W. Biederman
Quoted 1 line · Russell King - ARM Linux
From your description there still seems to be an association with an
instruction so I don't know if I would really call the signal asynchronous. It sounds like the exception is delayed and not asynchronous.
Traps can only be passed from ARM coprocessors by a coprocessor refusing to execute an instruction. That's what happens in this case - the VFP gets offered an instruction to execute. It accepts it, and the CPU continues, leaving the VFP to execute its instruction independently. If this instruction generates an error, then nothing happens at this point.
That error remains pending until the CPU offers the coprocessor the next VFP instruction, which it refuses. That causes an undefined instruction exception, and we trap into the kernel VFP code which reads the VFP status and works out what needs to be done.
What this means is that if you execute a VFP instruction, wait 10 minutes and then execute another VFP instruction, if the first VFP instruction raised an exception, you'll get to hear about it 10 minutes later.
You can use whatever weasel words you want to describe that situation, my choice is "asynchronous", your choice is "delayed". However, it is clearly not "synchronous", and arguing that we should report something synchronously that is not reported to _us_ synchronously (where synchronous means "at the same time") is IMHO daft.
So, let's take an example:
installs SIGFPE handler
..fp instructions.. one of which raises an exception returns to main loop
main loop blocks all signals while it sets stuff up callsppoll()In the synchronous SIGFPE delivery case, the SIGFPE handler will be called when the exception is generated in the FP code, and delivered at that time. The fact that the main loop blocks all signals happens later, so the users handler gets called as one expects.
In the VFP case, however, the FP instructions towards the end may not end up causing the exception to be signalled until sometime later, and as I've already explained, that may be the result of a C library function accessing the VFP registers. This could well end up trying to deliver the SIGFPE while signals are blocked, and we get drastically different behaviour if
force_sig_info()is used.In the VFP case, if
force_sig_info()is used, the program gets killed at this point. In the non-VFP case, the program's signal handler was called.Using
send_sig_info()results in the already delayed or asynchronous signal being held off untilppoll()drops the blocking, at which point the signal is delivered, the program handles it in its handler, and the program continues to run.So
1. non-VFP case, program doesn't get killed but gets the opportunity to handle the signal.
2. VFP case withsend_sig_info, program doesn't get killed but gets the opportunity to handle the signal.
3. VFP case withforce_sig_info, the program gets killed and dumps core.
Quoted 2 lines
Which one of these results in a big change of behaviour in your opinion?
I want to apologize for the disagreement. In part of my due diligence for cleaning up the signal handling I am introducing some helpers for generating siginfo. I decided to ask which kind of helpers should I introduce.
Very basic generic helpers that just wrap the current functionality today. Or some slightly smarter helpers that solve some other problems as well. After consideration I am shelving the smarter helpers for now, as the need to introduce the helpers universally is strong, so that I can guarantee struct siginfo is always fully initialized before being passed to userspace.
Given the choice between force_sig_info and send_sig_info I agree that send_sig_info is the right choice for signals that can be ignored.
The problem I was focusing on is the problem where force_sig_info and send_sig_info can be tricked into causing the instruction pointer to point to the wrong instruction (even when the signal is not blocked), due to the delivery of another signal.
So I was wondering if in practice we could introduce a singal delivery function that would operation synchronously and would solve the instruction pointer problem.
It looks to me like this location on arm where we are using send_sig_info is a clear candidate for such a function as long as it has a mode where you can say deliverly the signal like send_sig_info if the signal is blocked.
Still like I said such a smarter helper is not the priority and I don't intend any semantic changes when I introduce helpers into the signal deliver path. Just fewer places initializing struct siginfo.
Eric
Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS
In reply to Eric W. BiedermanQuoted 3 lines · Eric W. Biederman
Quoted 1 line · Dave Martin
On Thu, Jan 11, 2018 at 06:59:36PM -0600, Eric W. Biederman wrote:
[...]
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Possible ABI fixes include:
- Send the signal without siginfo
- Don't generate a signal
[...]
Quoted 8 lines
Quoted 8 lines
Quoted 2 lines
- Possibly assign and use an appropriate
si_code
- Don't handle cases which can't happenI think a mixture of these two is the best approach.
In any case,
si_code== 0 here doesn't seem to have any explicit meaning. I think we can translate all of the arm64 faults to propersi_codes-- see my sketch below. Probably means a bit more thought though.
[...]
Quoted 1 line
Quoted 1 line
Quoted 1 line
arch/arm64/mm/fault.c +0
-0
[...]
Quoted 8 lines
Quoted 8 lines
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 613
Quoted 8 lines
arch/arm64/mm/fault.c +0
-4@@ -607,70 +607,70 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) }static const struct fault_info fault_info[] = { - { do_bad,SIGBUS ,0 ,"ttbr address size fault" }, - { do_bad,SIGBUS ,0 ,"level 1 address size fault" }, - { do_bad,SIGBUS ,0 ,"level 2 address size fault" }, - { do_bad,SIGBUS ,0 ,"level 3 address size fault" },
If I convert this kind of thing to SIGKILL there really is nothing sensible to put in si_code, except possibly SI_KERNEL (indicating that the kill did not come from userspace). Even so, it hardly seems worth filling in fields like si_pid and si_uid just to make this "correct".
In any case, if siginfo is never seen by userspace for SIGKILL this is moot.
Obviously, siginfo is never copied to the user stack in that case, but is it also guaranteed not to be visible to userspace by other means? For ptrace I'm hoping not, since SIGKILL should nuke the tracee immediately instead of being reported to the tracer as a signal-delivery-stop -- so the tracer should get WIFSIGNALED() && WTERMSIG() == SIGKILL. A subsequent PTRACE_GETSIGINFO would fail with ESRCH.
Does that match your understanding?
If so, there is some merit in not pretending to pass a reall value for si_code.
Should si_code simply be ignored for the SIGKILL case?
Cheers
---Dave
Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS
Quoted 53 lines · Dave Martin
Quoted 3 lines · Eric W. Biederman
Quoted 1 line · Dave Martin
On Thu, Jan 11, 2018 at 06:59:36PM -0600, Eric W. Biederman wrote:
[...]
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Possible ABI fixes include:
- Send the signal without siginfo
- Don't generate a signal[...]
Quoted 8 lines
Quoted 8 lines
Quoted 2 lines
- Possibly assign and use an appropriate
si_code
- Don't handle cases which can't happenI think a mixture of these two is the best approach.
In any case,
si_code== 0 here doesn't seem to have any explicit meaning. I think we can translate all of the arm64 faults to propersi_codes-- see my sketch below. Probably means a bit more thought though.[...]
Quoted 1 line
Quoted 1 line
Quoted 1 line
arch/arm64/mm/fault.c +0
-0[...]
Quoted 8 lines
Quoted 8 lines
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 613
Quoted 8 lines
arch/arm64/mm/fault.c +0
-4@@ -607,70 +607,70 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) }static const struct fault_info fault_info[] = { - { do_bad,SIGBUS ,0 ,"ttbr address size fault" }, - { do_bad,SIGBUS ,0 ,"level 1 address size fault" }, - { do_bad,SIGBUS ,0 ,"level 2 address size fault" }, - { do_bad,SIGBUS ,0 ,"level 3 address size fault" },If I convert this kind of thing to SIGKILL there really is nothing sensible to put in
si_code, except possiblySI_KERNEL(indicating that the kill did not come from userspace). Even so, it hardly seems worth filling in fields likesi_pidandsi_uidjust to make this "correct".In any case, if siginfo is never seen by userspace for SIGKILL this is moot.
Obviously, siginfo is never copied to the user stack in that case, but is it also guaranteed not to be visible to userspace by other means? For ptrace I'm hoping not, since SIGKILL should nuke the tracee immediately instead of being reported to the tracer as a signal-delivery-stop -- so the tracer should get
WIFSIGNALED()&&WTERMSIG()== SIGKILL. A subsequentPTRACE_GETSIGINFOwould fail with ESRCH.
Quoted 6 lines
Does that match your understanding?
If so, there is some merit in not pretending to pass a reall value for
si_code.Should
si_codesimply be ignored for the SIGKILL case?
I know what x86 does in a similar case is it uses force_sig instead of force_sig_info. Then the generic code gets to worry about
If the appropriate paths generic paths get to worry about what siginfo to fill in in that case. Which for SI_KERNEL is zero for everything except the si_code and the si_signo.
That seems perfectly reasonable.
Eric
Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS
Quoted 1 line · Eric W. Biederman
Dave Martin <[email protected]> writes:
[...]
Quoted 10 lines
Quoted 1 line
Should
si_codesimply be ignored for the SIGKILL case?I know what x86 does in a similar case is it uses
force_siginstead offorce_sig_info. Then the generic code gets to worry aboutIf the appropriate paths generic paths get to worry about what siginfo to fill in in that case. Which for
SI_KERNELis zero for everything except thesi_codeand thesi_signo.That seems perfectly reasonable.
OK, I'll go with SI_KERNEL then.
Cheers
---Dave
Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS
In reply to Dave MartinHi Dave,
Thanks for going through all these,
Quoted 7 lines · Dave Martin
Quoted 5 lines · Eric W. Biederman
arch/arm64/mm/fault.c +0
-0@@ -596,7 +596,7 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
Quoted 8 lines
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 626
Quoted 1 line
arch/arm64/mm/fault.c +1
-0+ { do_sea, SIGBUS, BUS_FIXME, "synchronous external abort" },This
si_codeseems to be a fallback for if ACPI is absent or doesn't know what to do with this error.-> SIGBUS/BUS_OBJERR?
Can probably legitimately happen for userspace for suitable MMIO mappings.
It can happen for normal memory too, there are specific ESR values for parity/checksum errors when read/writing memory. I think this first one is 'other/unknown', and its up to the CPU how to classify them.
Quoted 2 lines
Perhaps it's more serious though in the presence of ACPI. Do we expect that ACPI can diagnose all localisable errors?
Its not just ACPI, the CPU's v8.2 RAS Extensions use this synchronous-external-abort as notification of a RAS error, (the other details are written to to memory-mapped nodes). With the v8.2 RAS Extensions the ESR tells us if the error was contained.
For ACPI we rely on firmware to set an appropriate severity in the CPER records generated by firmware. The APEI helpers will call panic() if they find a fatal error.
For systems with neither {firmware,kernel}-first RAS, BUS_OBJERR looks like a good choice.
Quoted 6 lines
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 633
Quoted 4 lines
arch/arm64/mm/fault.c +4
-0+ { do_sea, SIGBUS, BUS_FIXME, "level 0 (translation table walk)" }, + { do_sea, SIGBUS, BUS_FIXME, "level 1 (translation table walk)" }, + { do_sea, SIGBUS, BUS_FIXME, "level 2 (translation table walk)" }, + { do_sea, SIGBUS, BUS_FIXME, "level 3 (translation table walk)" },Pagetable screwup or
kernel/system/CPUbug -> SIGKILL, orpanic().
(RAS mechanisms may claim this and send their own signals, if not:)
SIGKILL is probably a better choice here, while we do have an address, there is nothing user-space can do about it.
Quoted 6 lines
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 634
Quoted 1 line
arch/arm64/mm/fault.c +1
-0+ { do_sea, SIGBUS, BUS_FIXME, "synchronous parity or ECC error" }, // Reserved when RAS is implementedPossibly SIGBUS/BUS_MCEERR_AR (though I don't know exactly what userspace is supposed to do with this or whether this implies the existence or certain kernel features for managing the error that may not be present on arm64...)
I'd like to keep the MCEERR signals to errors that we know are contained, the kernel has understood and handled.
(These features do exist for arm64, enabling CONFIG_MEMORY_FAILURE and a few APEI options allows all this to work today with suitable firmware. My Seattle claims to support it).
Quoted 1 line
Otherwise, SIGKILL.
Sounds good,
Quoted 8 lines
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 641
Quoted 4 lines
arch/arm64/mm/fault.c +4
-0+ { do_sea, SIGBUS, BUS_FIXME, "level 0 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented + { do_sea, SIGBUS, BUS_FIXME, "level 1 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented + { do_sea, SIGBUS, BUS_FIXME, "level 2 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented + { do_sea, SIGBUS, BUS_FIXME, "level 3 synchronous parity error (translation table walk)" }, // Reserved when RAS is implementedProcess page tables corrupt: if the kernel couldn't fix this, the process can't reasonably fix it -> SIGKILL
Quoted 4 lines
Since this is a RAS-type error it could be triggered by a cosmic ray rather than requiring a kernel or system bug or other major failure, so we probably shouldn't panic the system if the error is localisable to a particular process.
Without the RAS-Extensions severity to tell us the error is contained I'm not sure what we can expect. But given the page-tables are per-process, and we never swap them to disk etc, its probably a safe bet that it doesn't matter either way for these.
Thanks,
James
PATCH 8/11 signal/arm: Document conflicts with SI_USER and SIGFPE
In reply to Eric W. BiedermanSetting si_code to 0 results in a userspace seeing an si_code of 0. This is the same si_code as SI_USER. Posix and common sense requires that SI_USER not be a signal specific si_code. As such this use of 0 for the si_code is a pretty horribly broken ABI.
Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a value of __SI_KILL and now sees a value of SIL_KILL with the result that uid and pid fields are copied and which might copying the si_addr field by accident but certainly not by design. Making this a very flakey implementation.
Utilizing FPE_FIXME, siginfo_layout will now return SIL_FAULT and the appropriate fields will be reliably copied.
Possible ABI fixes includee:
- Send the signal without siginfo
- Don't generate a signal
- Possibly assign and use an appropriate si_code
- Don't handle cases which can't happen
Cc: Russell King <[email protected]>
Cc: [email protected]
Ref: 451436b7bbb2 ("[ARM] Add support code for ARM hardware vector floating point") History Tree: https://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git
--- arch/arm/include/uapi/asm/siginfo.h | 13 +++++++++++++ arch/arm/vfp/vfpmodule.c | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 arch/arm/include/uapi/asm/siginfo.h
arch/arm/include/uapi/asm/siginfo.h new file +13 -0
@@ -0,0 +1,13 @@ +#ifndef __ASM_SIGINFO_H +#define __ASM_SIGINFO_H + +#include <asm-generic/siginfo.h> + +/* +* SIGFPE si_codes +*/ +#ifdef __KERNEL__ +#define FPE_FIXME 0/* Broken dup of SI_USER */ +#endif /* __KERNEL__ */ + +#endif
arch/arm/vfp/vfpmodule.c +1 -1
@@ -257,7 +257,7 @@ static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_if (exceptions ==VFP_EXCEPTION_ERROR ) {vfp_panic ("unhandled bounce" , inst); -vfp_raise_sigfpe (0 , regs); +vfp_raise_sigfpe (FPE_FIXME , regs);return ; }
Signature · 1 line
2.14.1
Russell King - ARM Linux
maintainerRe: [PATCH 08/11] signal/arm: Document conflicts with SI_USER and SIGFPE
Quoted 5 lines · Eric W. Biederman
Setting
si_codeto 0 results in a userspace seeing ansi_codeof 0. This is the samesi_codeasSI_USER. Posix and common sense requires thatSI_USERnot be a signal specificsi_code. As such this use of 0 for thesi_codeis a pretty horribly broken ABI.
Quoted 8 lines
Further use of
si_code== 0 guaranteed thatcopy_siginfo_to_usersaw a value of__SI_KILLand now sees a value ofSIL_KILLwith the result that uid and pid fields are copied and which might copying thesi_addrfield by accident but certainly not by design. Making this a very flakey implementation.Utilizing
FPE_FIXME,siginfo_layoutwill now returnSIL_FAULTand the appropriate fields will be reliably copied.
So what do you suggest when none of the SIGFPE FPE_xxx codes match the condition that "we don't know what happened" ? Raise a SIGKILL instead maybe? We will have dumped the VFP state into the kernel log at this point, things are pretty much fscked.
It's probably an impossible condition unless the hardware has failed, no one has knowingly reported getting such a dump in their kernel log, so it's something that could very likely be changed in some way without anyone noticing.
Signature · 3 lines
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/ FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up According to speedtest.net: 8.21Mbps down 510kbps up
Re: [PATCH 08/11] signal/arm: Document conflicts with SI_USER and SIGFPE
Quoted 20 lines · Russell King - ARM Linux
Quoted 5 lines · Eric W. Biederman
Setting
si_codeto 0 results in a userspace seeing ansi_codeof 0. This is the samesi_codeasSI_USER. Posix and common sense requires thatSI_USERnot be a signal specificsi_code. As such this use of 0 for thesi_codeis a pretty horribly broken ABI.Quoted 8 lines
Further use of
si_code== 0 guaranteed thatcopy_siginfo_to_usersaw a value of__SI_KILLand now sees a value ofSIL_KILLwith the result that uid and pid fields are copied and which might copying thesi_addrfield by accident but certainly not by design. Making this a very flakey implementation.Utilizing
FPE_FIXME,siginfo_layoutwill now returnSIL_FAULTand the appropriate fields will be reliably copied.So what do you suggest when none of the SIGFPE
FPE_xxxcodes match the condition that "we don't know what happened" ? Raise a SIGKILL instead maybe? We will have dumped the VFP state into the kernel log at this point, things are pretty much fscked.
Quoted 4 lines
It's probably an impossible condition unless the hardware has failed, no one has knowingly reported getting such a dump in their kernel log, so it's something that could very likely be changed in some way without anyone noticing.
It sounds like we have two equally valid possible solutions:
1) force_sig(SIGKILL, current);
2) Allocate a new FPE_xxx code in asm-generic/siginfo.h I believe the next available number is 15.
If no one is going to notice this should be comparatively easy to fix. I just don't have the knowledge of arm to make the judgement myself.
Eric
Re: [PATCH 08/11] signal/arm: Document conflicts with SI_USER and SIGFPE
In reply to Russell King - ARM LinuxQuoted 20 lines · Russell King - ARM Linux
Quoted 5 lines · Eric W. Biederman
Setting
si_codeto 0 results in a userspace seeing ansi_codeof 0. This is the samesi_codeasSI_USER. Posix and common sense requires thatSI_USERnot be a signal specificsi_code. As such this use of 0 for thesi_codeis a pretty horribly broken ABI.Quoted 8 lines
Further use of
si_code== 0 guaranteed thatcopy_siginfo_to_usersaw a value of__SI_KILLand now sees a value ofSIL_KILLwith the result that uid and pid fields are copied and which might copying thesi_addrfield by accident but certainly not by design. Making this a very flakey implementation.Utilizing
FPE_FIXME,siginfo_layoutwill now returnSIL_FAULTand the appropriate fields will be reliably copied.So what do you suggest when none of the SIGFPE
FPE_xxxcodes match the condition that "we don't know what happened" ? Raise a SIGKILL instead maybe? We will have dumped the VFP state into the kernel log at this point, things are pretty much fscked.
Quoted 4 lines
It's probably an impossible condition unless the hardware has failed, no one has knowingly reported getting such a dump in their kernel log, so it's something that could very likely be changed in some way without anyone noticing.
arm64 can optionally not tell you exactly what exception(s) happened for vector operations. This may also be true for 32-bit.
Unfortunately, there's nothing sensible to report in this case, and there is no such constant as FPE_UNKNOWN.
Currently arm64 sets si_code to 0, which doesn't match any FPE_* constant (but unfortunately matches SI_USER) -- defining a new, distinct FPE_UNKNOWN is probably no worse than that.
I'm not sure yet whether a similar argument applies for 32-bit.
Cheers
---Dave
Re: [PATCH 08/11] signal/arm: Document conflicts with SI_USER and SIGFPE
In reply to Russell King - ARM LinuxQuoted 20 lines · Russell King - ARM Linux
Quoted 5 lines · Eric W. Biederman
Setting
si_codeto 0 results in a userspace seeing ansi_codeof 0. This is the samesi_codeasSI_USER. Posix and common sense requires thatSI_USERnot be a signal specificsi_code. As such this use of 0 for thesi_codeis a pretty horribly broken ABI.Quoted 8 lines
Further use of
si_code== 0 guaranteed thatcopy_siginfo_to_usersaw a value of__SI_KILLand now sees a value ofSIL_KILLwith the result that uid and pid fields are copied and which might copying thesi_addrfield by accident but certainly not by design. Making this a very flakey implementation.Utilizing
FPE_FIXME,siginfo_layoutwill now returnSIL_FAULTand the appropriate fields will be reliably copied.So what do you suggest when none of the SIGFPE
FPE_xxxcodes match the condition that "we don't know what happened" ? Raise a SIGKILL instead maybe? We will have dumped the VFP state into the kernel log at this point, things are pretty much fscked.
Quoted 4 lines
It's probably an impossible condition unless the hardware has failed, no one has knowingly reported getting such a dump in their kernel log, so it's something that could very likely be changed in some way without anyone noticing.
Relating to this, what's your view on how to clean up the si_code zeros in fsr-2level.c and fsr-3level.c?
Due to the historical evolution of the fault codes I'm less confident of getting these right than for arm64.
Many are things that shouldn't happen and likely indicate a kernel bug or system failure if they do, so at least some of the
{ do_bad, SIGxxx, 0, ... } entries can probably be changed to { do_bad, SIGKILL, SI_KERNEL, ... } with no ill effects. But there are many fault codes whose meaning has changed over time.
Cheers
---Dave
PATCH 9/11 signal: Reduce copy_siginfo to just a memcpy
In reply to Eric W. BiedermanThe savings for copying just part of struct siginfo appears to be in the noise on modern machines. So remove this ``optimization'' and simplify the code.
At the same time mark the second parameter as constant so there is no confusion as to which direction the copy will go.
This ensures that a fully initialized siginfo that is sent ends up as a fully initialized siginfo on the signal queue. This full initialization ensures even confused code won't copy unitialized data to userspace, and it prepares for turning copy_siginfo_to_user into a simple copy_to_user.
--- include/linux/signal.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-)
include/linux/signal.h +2 -6
@@ -11,13 +11,9 @@ struct task_struct;/* for sysctl */ extern int print_fatal_signals; -static inline void copy_siginfo (struct siginfo *to,struct siginfo *from) +static inline void copy_siginfo (struct siginfo *to,const struct siginfo *from) { -if (from->si_code <0 ) -memcpy (to, from,sizeof (*to)); -else -/* _sigchld is currently the largest know union member */ -memcpy (to, from, __ARCH_SI_PREAMBLE_SIZE +sizeof (from->_sifields._sigchld)); +memcpy (to, from,sizeof (*to)); }int copy_siginfo_to_user (struct siginfo __user *to,const struct siginfo *from);
Signature · 1 line
2.14.1
PATCH 10/11 signal: Introduce clear_siginfo
In reply to Eric W. BiedermanUnfortunately struct siginfo has holes both in the common part of the structure, in the union members, and in the lack of padding of the union members. The result of those wholes is that the C standard does not guarantee those bits will be initialized. As struct siginfo is for communication between the kernel and userspace that is a problem.
Add the helper function clear_siginfo that is guaranteed to clear all of the bits in struct siginfo so when the structure is copied there is no danger of copying old kernel data and causing a leak of information from kernel space to userspace.
--- include/linux/signal.h | 5 +++++ 1 file changed, 5 insertions(+)
include/linux/signal.h +5 -0
@@ -16,6 +16,11 @@ static inline void copy_siginfo(struct siginfo *to, const struct siginfo *from)memcpy (to, from,sizeof (*to)); } +static inline void clear_siginfo (struct siginfo *info) +{ +memset (info,0 ,sizeof (*info)); +} +int copy_siginfo_to_user (struct siginfo __user *to,const struct siginfo *from);enum siginfo_layout {
Signature · 1 line
2.14.1
PATCH 11/11 signal: Ensure generic siginfos the kernel sends have all bits initialized
In reply to Eric W. BiedermanCall clear_siginfo to ensure stack allocated siginfos are fully initialized before being passed to the signal sending functions.
This ensures that if there is the kind of confusion documented by TRAP_FIXME, FPE_FIXME, or BUS_FIXME the kernel won't send unitialized data to userspace when the kernel generates a signal with SI_USER but the copy to userspace assumes it is a different kind of signal, and different fields are initialized.
This also prepares the way for turning copy_siginfo_to_user into a copy_to_user, by removing the need in many cases to perform a field by field copy simply to skip the uninitialized fields.
--- fs/fcntl.c | 1 + ipc/mqueue.c | 1 + kernel/signal.c | 9 ++++++++- 3 files changed, 10 insertions(+), 1 deletion(-)
fs/fcntl.c +1 -0
@@ -737,6 +737,7 @@ static void send_sigio_to_task(struct task_struct *p,delivered even if we can't queue. Failure to queue in this case _should_ be reported; we fall back to SIGIO in that case. --sct */ +clear_siginfo (&si); si.si_signo = signum; si.si_errno =0 ; si.si_code = reason;
ipc/mqueue.c +1 -0
@@ -639,6 +639,7 @@ static void __do_notify(struct mqueue_inode_info *info)case SIGEV_SIGNAL :/* sends signal */ +clear_siginfo (&sig_i); sig_i.si_signo = info->notify.sigev_signo; sig_i.si_errno =0 ; sig_i.si_code =SI_MESGQ ;
kernel/signal.c +8 -1
@@ -549,6 +549,7 @@ static void collect_signal(int sig, struct sigpending *list, siginfo_t *info,* a fast-pathed signal or we must have been * out of queue space. So zero out the info. */ +clear_siginfo (info); info->si_signo = sig; info->si_errno =0 ; info->si_code =SI_USER ;
@@ -1043,6 +1044,7 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,list_add_tail (&q->list, &pending->list);switch ((unsigned long ) info) {case (unsigned long )SEND_SIG_NOINFO : +clear_siginfo (&q->info); q->info.si_signo = sig; q->info.si_errno =0 ; q->info.si_code =SI_USER ;
@@ -1051,6 +1053,7 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t, q->info.si_uid =from_kuid_munged (current_user_ns (),current_uid ());break ;case (unsigned long )SEND_SIG_PRIV : +clear_siginfo (&q->info); q->info.si_signo = sig; q->info.si_errno =0 ; q->info.si_code =SI_KERNEL ;
@@ -1623,6 +1626,7 @@ bool do_notify_parent(struct task_struct *tsk, int sig) sig =SIGCHLD ; } +clear_siginfo (&info); info.si_signo = sig; info.si_errno =0 ;/*
@@ -1717,6 +1721,7 @@ static void do_notify_parent_cldstop(struct task_struct *tsk, parent = tsk->real_parent; } +clear_siginfo (&info); info.si_signo =SIGCHLD ; info.si_errno =0 ;/*
@@ -1929,7 +1934,7 @@ static void ptrace_do_notify(int signr, int exit_code, int why) {siginfo_t info; -memset (&info,0 ,sizeof info); +clear_siginfo (&info); info.si_signo = signr; info.si_code = exit_code; info.si_pid =task_pid_vnr (current);
@@ -2136,6 +2141,7 @@ static int ptrace_signal(int signr, siginfo_t *info)* have updated *info via PTRACE_SETSIGINFO. */ if (signr != info->si_signo) { +clear_siginfo (info); info->si_signo = signr; info->si_errno =0 ; info->si_code =SI_USER ;
@@ -2941,6 +2947,7 @@ SYSCALL_DEFINE2(kill, pid_t, pid, int, sig) {struct siginfo info; +clear_siginfo (&info); info.si_signo = sig; info.si_errno =0 ; info.si_code =SI_USER ;
Signature · 1 line
2.14.1
cover siginfo fixes
In reply to Eric W. BiedermanThese are two additional siginfo fixes I overlooked yesterday. Thankfully the confusion was not arch specific, and did not set an ABI to userspace that I had to worry about breaking, so I could fix these two issues properly.
Eric W. Biederman (2):
mn10300/misalignment: Use SIGSEGV SEGV_MAPERR to report a failed user copy x86/mm/pkeys: Fix fill_sig_info_pkey
arch/mn10300/mm/misalignment.c | 2 +- arch/x86/mm/fault.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-)
PATCH 1/2 mn10300/misalignment: Use SIGSEGV SEGV_MAPERR to report a failed user copy
Setting si_code to 0 is the same a setting si_code to SI_USER which is definitely not correct. With si_code set to SI_USER si_pid and si_uid will be copied to userspace instead of si_addr. Which is very wrong.
So fix this by using a sensible si_code (SEGV_MAPERR) for this failure.
--- arch/mn10300/mm/misalignment.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/mn10300/mm/misalignment.c +1 -1
@@ -437,7 +437,7 @@ asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code) info.si_signo =SIGSEGV ; info.si_errno =0 ; - info.si_code =0 ; + info.si_code =SEGV_MAPERR ; info.si_addr = (void *) regs->pc;force_sig_info (SIGSEGV , &info, current);return ;
Signature · 1 line
2.14.1
PATCH 2/2 x86/mm/pkeys: Fix fill_sig_info_pkey
In reply to Eric W. BiedermanSEGV_PKUERR is a signal specific si_code which happens to have the same numeric value as several others: BUS_MCEERR_AR, ILL_ILLTRP, FPE_FLTOVF, TRAP_HWBKPT, CLD_TRAPPED, POLL_ERR, SEGV_THREAD_ID, as such it is not safe to just test the si_code the signal number must also be tested to prevent a false positive in fill_sig_info_pkey.
I found this error by inspection, and BUS_MCEERR_AR appears to be a real candidate for confusion. So pass in si_signo and fix it.
--- arch/x86/mm/fault.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
arch/x86/mm/fault.c +4 -3
@@ -172,14 +172,15 @@ is_prefetch(struct pt_regs *regs, unsigned long error_code, unsigned long addr)* 6. T1 : reaches here, sees vma_pkey(vma)=5, when we really * faulted on a pte with its pkey=4. */ -static void fill_sig_info_pkey (int si_code,siginfo_t *info,u32 *pkey) +static void fill_sig_info_pkey (int si_signo,int si_code,siginfo_t *info, +u32 *pkey) {/* This is effectively an #ifdef */ if (!boot_cpu_has (X86_FEATURE_OSPKE ))return ;/* Fault not from Protection Keys: nothing to do */ -if (si_code !=SEGV_PKUERR ) +if ((si_code !=SEGV_PKUERR ) || (si_signo !=SIGSEGV ))return ;/* * force_sig_info_fault() is called from a number of
@@ -218,7 +219,7 @@ force_sig_info_fault(int si_signo, int si_code, unsigned long address, lsb =PAGE_SHIFT ; info.si_addr_lsb = lsb; -fill_sig_info_pkey (si_code, &info, pkey); +fill_sig_info_pkey (si_signo, si_code, &info, pkey);force_sig_info (si_signo, &info, tsk); }
Signature · 1 line
2.14.1
tip-bot for Eric W. Biederman
merge bot[tip:x86/urgent] x86/mm/pkeys: Fix fill_sig_info_pkey
x86/mm/pkeys: Fix fill_sig_info_pkey
Commit-ID: beacd6f7ed5e2915959442245b3b2480c2e37490 Gitweb: https://git.kernel.org/tip/beacd6f7ed5e2915959442245b3b2480c2e37490 Author: Eric W. Biederman <[email protected]> AuthorDate: Fri, 12 Jan 2018 14:31:35 -0600 Committer: Thomas Gleixner <[email protected]> CommitDate: Sun, 14 Jan 2018 12:14:51 +0100
x86/mm/pkeys: Fix fill_sig_info_pkey
SEGV_PKUERR is a signal specific si_code which happens to have the same numeric value as several others: BUS_MCEERR_AR, ILL_ILLTRP, FPE_FLTOVF, TRAP_HWBKPT, CLD_TRAPPED, POLL_ERR, SEGV_THREAD_ID, as such it is not safe to just test the si_code the signal number must also be tested to prevent a false positive in fill_sig_info_pkey.
This error was by inspection, and BUS_MCEERR_AR appears to be a real candidate for confusion. So pass in si_signo and check for SIG_SEGV to verify that it is actually a SEGV_PKUERR
--- arch/x86/mm/fault.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
arch/x86/mm/fault.c +4 -3
@@ -172,14 +172,15 @@ is_prefetch(struct pt_regs *regs, unsigned long error_code, unsigned long addr)* 6. T1 : reaches here, sees vma_pkey(vma)=5, when we really * faulted on a pte with its pkey=4. */ -static void fill_sig_info_pkey (int si_code,siginfo_t *info,u32 *pkey) +static void fill_sig_info_pkey (int si_signo,int si_code,siginfo_t *info, +u32 *pkey) {/* This is effectively an #ifdef */ if (!boot_cpu_has (X86_FEATURE_OSPKE ))return ;/* Fault not from Protection Keys: nothing to do */ -if (si_code !=SEGV_PKUERR ) +if ((si_code !=SEGV_PKUERR ) || (si_signo !=SIGSEGV ))return ;/* * force_sig_info_fault() is called from a number of
@@ -218,7 +219,7 @@ force_sig_info_fault(int si_signo, int si_code, unsigned long address, lsb =PAGE_SHIFT ; info.si_addr_lsb = lsb; -fill_sig_info_pkey (si_code, &info, pkey); +fill_sig_info_pkey (si_signo, si_code, &info, pkey);force_sig_info (si_signo, &info, tsk); }
cover siginfo unification
In reply to Eric W. BiedermanThe following changes are available at:
git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git siginfo-testing
This set of changes unifies struct siginfo and struct compat_siginfo so that there is only one definition of each. Additionally this ends up with a single implementation of copy_siginfo_to_user32 and copy_siginfo_from_user32.
This results in much less code, that might be slightly less readable as it handles all of the cases it needs to deal with instead of just a few. Not a single implementation of copy_siginfo_to_user32 or copy_siginfo_from_user32 handled all of the ways data is encoded in struct siginfo today.
Hopefully this will result in much more maintainable code.
Al Viro (3):
signal/mips: switch mips to generic siginfo
signal: kill __ARCH_SI_UID_T
signal: unify compat_siginfo_t
Eric W. Biederman (19):
signal: Document all of the signals that use the _sigfault union member
signal: Document the strange si_codes used by ptrace event stops
signal: Document glibc's si_code of SI_ASYNCNL
signal: Ensure no siginfo union member increases the size of struct siginfo
signal: Clear si_sys_private before copying siginfo to userspace
signal: Remove _sys_private and _overrun_incr from struct compat_siginfo ia64/signal: switch to generic struct siginfo
signal/ia64: switch the last arch-specific copy_siginfo_to_user() to generic version
signal: Remove unnecessary ifdefs now that there is only one struct siginfo
signal: Move addr_lsb into the _sigfault union for clarity signal/powerpc: Remove redefinition of NSIGTRAP on powerpc signal/ia64: Move the ia64 specific si_codes to asm-generic/siginfo.h signal/frv: Move the frv specific si_codes to asm-generic/siginfo.h signal/tile: Move the tile specific si_codes to asm-generic/siginfo.h signal/blackfin: Move the blackfin specific si_codes to asm-generic/siginfo.h signal/blackfin: Remove pointless UID16_SIGINFO_COMPAT_NEEDED
signal: Unify and correct copy_siginfo_from_user32
signal: Remove the code to clear siginfo before calling copy_siginfo_from_user32
signal: Unify and correct copy_siginfo_to_user32
arch/arm64/include/asm/compat.h | 64 ---------- arch/arm64/kernel/signal32.c | 80 ------------- arch/blackfin/include/uapi/asm/siginfo.h | 34 ------ arch/frv/include/uapi/asm/Kbuild | 1 + arch/frv/include/uapi/asm/siginfo.h | 13 -- arch/ia64/include/uapi/asm/siginfo.h | 96 --------------- arch/ia64/kernel/signal.c | 52 -------- arch/mips/include/asm/compat.h | 73 ------------ arch/mips/include/uapi/asm/siginfo.h | 86 +------------- arch/mips/kernel/signal32.c | 67 ----------- arch/parisc/include/asm/compat.h | 64 ---------- arch/parisc/kernel/signal32.c | 106 ----------------- arch/parisc/kernel/signal32.h | 3 - arch/powerpc/include/asm/compat.h | 65 ---------- arch/powerpc/include/uapi/asm/siginfo.h | 3 - arch/powerpc/kernel/signal_32.c | 66 ----------- arch/s390/include/asm/compat.h | 73 ------------ arch/s390/kernel/compat_signal.c | 100 ---------------- arch/sparc/include/asm/compat.h | 59 --------- arch/sparc/kernel/signal32.c | 69 ----------- arch/tile/include/asm/compat.h | 62 ---------- arch/tile/include/uapi/asm/siginfo.h | 8 -- arch/tile/kernel/compat_signal.c | 73 ------------ arch/x86/include/asm/compat.h | 86 +------------- arch/x86/include/asm/fpu/signal.h | 6 - arch/x86/kernel/signal_compat.c | 123 ++----------------- include/linux/compat.h | 100 +++++++++++++++- include/linux/signal.h | 2 - include/uapi/asm-generic/siginfo.h | 109 +++++++++++++---- kernel/ptrace.c | 1 - kernel/signal.c | 197 +++++++++++++++++++++++++++++-- 31 files changed, 382 insertions(+), 1559 deletions(-)
Eric
PATCH 1/22 signal: Document all of the signals that use the _sigfault union member
--- include/uapi/asm-generic/siginfo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
include/uapi/asm-generic/siginfo.h +1 -1
@@ -85,7 +85,7 @@ typedef struct siginfo {__ARCH_SI_CLOCK_T _stime; } _sigchld; -/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ +/* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP, SIGEMT */ struct {void __user *_addr;/* faulting insn/memory ref. */ #ifdef __ARCH_SI_TRAPNO
Signature · 1 line
2.14.1
PATCH 2/22 signal: Document the strange si_codes used by ptrace event stops
In reply to Eric W. Biederman--- include/uapi/asm-generic/siginfo.h | 5 +++++ 1 file changed, 5 insertions(+)
include/uapi/asm-generic/siginfo.h +5 -0
@@ -225,6 +225,11 @@ typedef struct siginfo {#define TRAP_HWBKPT 4/* hardware breakpoint/watchpoint */ #define NSIGTRAP 4 +/* +* There are an additional set of SIGTRAP si_codes used by ptrace +* that of the form: ((PTRACE_EVENT_XXX << 8) | SIGTRAP) +*/ +/* * SIGCHLD si_codes */
Signature · 1 line
2.14.1
PATCH 3/22 signal: Document glibc's si_code of SI_ASYNCNL
In reply to Eric W. BiedermanThe header uapi/asm-generic/siginfo.h appears to the the repository of all of these definitions in linux so collect up glibcs additions as well. Just to prevent someone from accidentally creating a conflict in the future.
--- include/uapi/asm-generic/siginfo.h | 1 + 1 file changed, 1 insertion(+)
include/uapi/asm-generic/siginfo.h +1 -0
@@ -165,6 +165,7 @@ typedef struct siginfo {#define SI_SIGIO -5/* sent by queued SIGIO */ #define SI_TKILL -6/* sent by tkill system call */ #define SI_DETHREAD -7/* sent by execve() killing subsidiary threads */ +#define SI_ASYNCNL -60/* sent by glibc async name lookup completion */ #define SI_FROMUSER (siptr) ((siptr)->si_code <= 0)#define SI_FROMKERNEL (siptr) ((siptr)->si_code > 0)
Signature · 1 line
2.14.1
PATCH 4/22 signal: Ensure no siginfo union member increases the size of struct siginfo
In reply to Eric W. Biederman--- kernel/signal.c | 1 + 1 file changed, 1 insertion(+)
kernel/signal.c +1 -0
@@ -3688,6 +3688,7 @@ void __init signals_init(void)/* If this check fails, the __ARCH_SI_PREAMBLE_SIZE value is wrong! */ BUILD_BUG_ON (__ARCH_SI_PREAMBLE_SIZE != offsetof(struct siginfo, _sifields._pad)); +BUILD_BUG_ON (sizeof (struct siginfo ) !=SI_MAX_SIZE ); sigqueue_cachep =KMEM_CACHE (sigqueue,SLAB_PANIC ); }
Signature · 1 line
2.14.1
PATCH 5/22 signal: Clear si_sys_private before copying siginfo to userspace
In reply to Eric W. BiedermanIn preparation for unconditionally copying the whole of siginfo to userspace clear si_sys_private. So this kernel internal value is guaranteed not to make it to userspace.
--- kernel/signal.c | 3 +++ 1 file changed, 3 insertions(+)
kernel/signal.c +3 -0
@@ -643,6 +643,9 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)spin_unlock (&tsk->sighand->siglock);posixtimer_rearm (info);spin_lock (&tsk->sighand->siglock); + +/* Don't expose the si_sys_private value to userspace */ + info->si_sys_private = 0; }#endif return signr;
Signature · 1 line
2.14.1
PATCH 6/22 signal: Remove _sys_private and _overrun_incr from struct compat_siginfo
In reply to Eric W. BiedermanWe have never passed either field to or from userspace so just remove them.
--- arch/arm64/include/asm/compat.h | 1 - arch/parisc/include/asm/compat.h | 1 - arch/powerpc/include/asm/compat.h | 1 - arch/s390/include/asm/compat.h | 1 - arch/sparc/include/asm/compat.h | 1 - arch/tile/include/asm/compat.h | 2 -- arch/x86/include/asm/compat.h | 2 -- arch/x86/kernel/signal_compat.c | 2 +- 8 files changed, 1 insertion(+), 10 deletions(-)
arch/arm64/include/asm/compat.h +0 -1
@@ -174,7 +174,6 @@ typedef struct compat_siginfo {compat_timer_t _tid;/* timer id */ int _overrun;/* overrun count */ compat_sigval_t _sigval;/* same as below */ -int _sys_private;/* not to be passed to user */ } _timer;/* POSIX.1b signals */
arch/parisc/include/asm/compat.h +0 -1
@@ -155,7 +155,6 @@ typedef struct compat_siginfo {int _overrun;/* overrun count */ char _pad[sizeof (unsigned int ) -sizeof (int )];compat_sigval_t _sigval;/* same as below */ -int _sys_private;/* not to be passed to user */ } _timer;/* POSIX.1b signals */
arch/powerpc/include/asm/compat.h +0 -1
@@ -145,7 +145,6 @@ typedef struct compat_siginfo {compat_timer_t _tid;/* timer id */ int _overrun;/* overrun count */ compat_sigval_t _sigval;/* same as below */ -int _sys_private;/* not to be passed to user */ } _timer;/* POSIX.1b signals */
arch/s390/include/asm/compat.h +0 -1
@@ -213,7 +213,6 @@ typedef struct compat_siginfo {compat_timer_t _tid;/* timer id */ int _overrun;/* overrun count */ compat_sigval_t _sigval;/* same as below */ -int _sys_private;/* not to be passed to user */ } _timer;/* POSIX.1b signals */
arch/sparc/include/asm/compat.h +0 -1
@@ -175,7 +175,6 @@ typedef struct compat_siginfo {compat_timer_t _tid;/* timer id */ int _overrun;/* overrun count */ compat_sigval_t _sigval;/* same as below */ -int _sys_private;/* not to be passed to user */ } _timer;/* POSIX.1b signals */
arch/tile/include/asm/compat.h +0 -2
@@ -136,8 +136,6 @@ typedef struct compat_siginfo {compat_timer_t _tid;/* timer id */ int _overrun;/* overrun count */ compat_sigval_t _sigval;/* same as below */ -int _sys_private;/* not to be passed to user */ -int _overrun_incr;/* amount to add to overrun */ } _timer;/* POSIX.1b signals */
arch/x86/include/asm/compat.h +0 -2
@@ -151,8 +151,6 @@ typedef struct compat_siginfo {compat_timer_t _tid;/* timer id */ int _overrun;/* overrun count */ compat_sigval_t _sigval;/* same as below */ -int _sys_private;/* not to be passed to user */ -int _overrun_incr;/* amount to add to overrun */ } _timer;/* POSIX.1b signals */
arch/x86/kernel/signal_compat.c +1 -1
@@ -64,7 +64,7 @@ static inline void signal_compat_build_tests(void)CHECK_SI_SIZE (_kill,2 *sizeof (int ));CHECK_CSI_OFFSET (_timer); -CHECK_CSI_SIZE (_timer,5 *sizeof (int )); +CHECK_CSI_SIZE (_timer,3 *sizeof (int ));CHECK_SI_SIZE (_timer,6 *sizeof (int ));CHECK_CSI_OFFSET (_rt);
Signature · 1 line
2.14.1
PATCH 7/22 ia64/signal: switch to generic struct siginfo
In reply to Eric W. Biederman... at a cost of added small ifdef __ia64__ in asm-generic siginfo.h, that is.
-- EWB Corrected the comment on _flags to reflect the move
--- arch/ia64/include/uapi/asm/siginfo.h | 67 ------------------------------------ include/uapi/asm-generic/siginfo.h | 5 +++ 2 files changed, 5 insertions(+), 67 deletions(-)
arch/ia64/include/uapi/asm/siginfo.h +0 -67
@@ -11,77 +11,10 @@#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) -#define HAVE_ARCH_SIGINFO_T #define HAVE_ARCH_COPY_SIGINFO_TO_USER #include <asm-generic/siginfo.h> -typedef struct siginfo { -int si_signo; -int si_errno; -int si_code; -int __pad0; - -union { -int _pad[SI_PAD_SIZE ]; - -/* kill() */ -struct { -pid_t _pid;/* sender's pid */ -uid_t _uid;/* sender's uid */ - } _kill; - -/* POSIX.1b timers */ -struct { -timer_t _tid;/* timer id */ -int _overrun;/* overrun count */ -char _pad[sizeof (__ARCH_SI_UID_T) -sizeof (int )]; -sigval_t _sigval;/* must overlay ._rt._sigval! */ -int _sys_private;/* not to be passed to user */ - } _timer; - -/* POSIX.1b signals */ -struct { -pid_t _pid;/* sender's pid */ -uid_t _uid;/* sender's uid */ -sigval_t _sigval; - } _rt; - -/* SIGCHLD */ -struct { -pid_t _pid;/* which child */ -uid_t _uid;/* sender's uid */ -int _status;/* exit code */ -clock_t _utime; -clock_t _stime; - } _sigchld; - -/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ -struct { -void __user *_addr;/* faulting insn/memory ref. */ -int _imm;/* immediate value for "break" */ -unsigned int _flags;/* see below */ -unsigned long _isr;/* isr */ -short _addr_lsb;/* lsb of faulting address */ -union { -/* used when si_code=SEGV_BNDERR */ -struct { -void __user *_lower; -void __user *_upper; - } _addr_bnd; -/* used when si_code=SEGV_PKUERR */ -__u32 _pkey; - }; - } _sigfault; - -/* SIGPOLL */ -struct { -long _band;/* POLL_IN, POLL_OUT, POLL_MSG (XPG requires a "long") */ -int _fd; - } _sigpoll; - } _sifields; -}siginfo_t ; -#define si_imm _sifields._sigfault._imm/* as per UNIX SysV ABI spec */ #define si_flags _sifields._sigfault._flags/*
include/uapi/asm-generic/siginfo.h +5 -0
@@ -90,6 +90,11 @@ typedef struct siginfo {void __user *_addr;/* faulting insn/memory ref. */ #ifdef __ARCH_SI_TRAPNOint _trapno;/* TRAP # which caused the signal */ +#endif +#ifdef __ia64__ +int _imm;/* immediate value for "break" */ +unsigned int _flags;/* see ia64 si_flags */ +unsigned long _isr;/* isr */ #endif short _addr_lsb;/* LSB of the reported address */ union {
Signature · 1 line
2.14.1
PATCH 8/22 signal/ia64: switch the last arch-specific copy_siginfo_to_user() to generic version
In reply to Eric W. Biederman--- arch/ia64/include/uapi/asm/siginfo.h | 2 -- arch/ia64/kernel/signal.c | 52 ------------------------------------ kernel/signal.c | 9 ++++--- 3 files changed, 5 insertions(+), 58 deletions(-)
arch/ia64/include/uapi/asm/siginfo.h +0 -2
@@ -11,8 +11,6 @@#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) -#define HAVE_ARCH_COPY_SIGINFO_TO_USER -#include <asm-generic/siginfo.h> #define si_imm _sifields._sigfault._imm/* as per UNIX SysV ABI spec */
arch/ia64/kernel/signal.c +0 -52
58 lines not on this page · raw message
kernel/signal.c +5 -4
@@ -2729,8 +2729,6 @@ enum siginfo_layout siginfo_layout(int sig, int si_code)return layout; } -#ifndef HAVE_ARCH_COPY_SIGINFO_TO_USER -int copy_siginfo_to_user (siginfo_t __user *to,const siginfo_t *from) {int err;
@@ -2769,6 +2767,11 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)#ifdef __ARCH_SI_TRAPNO err |=__put_user (from->si_trapno, &to->si_trapno);#endif +#ifdef __ia64__ + err |=__put_user (from->si_imm, &to->si_imm); + err |=__put_user (from->si_flags, &to->si_flags); + err |=__put_user (from->si_isr, &to->si_isr); +#endif #ifdef BUS_MCEERR_AO /* * Other callers might not initialize the si_lsb field,
@@ -2812,8 +2815,6 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)return err; } -#endif -/** * do_sigtimedwait - wait for queued signals specified in @which * @which: queued signals to wait for
Signature · 1 line
2.14.1
PATCH 9/22 signal/mips: switch mips to generic siginfo
In reply to Eric W. BiedermanFrom: Al Viro <[email protected]>
... having taught the latter that si_errno and si_code might be swapped.
--- arch/mips/include/uapi/asm/siginfo.h | 86 +----------------------------------- include/uapi/asm-generic/siginfo.h | 5 +++ 2 files changed, 6 insertions(+), 85 deletions(-)
arch/mips/include/uapi/asm/siginfo.h +1 -85
@@ -14,8 +14,6 @@#define __ARCH_SIGEV_PREAMBLE_SIZE (sizeof(long) + 2*sizeof(int))#undef __ARCH_SI_TRAPNO/* exception code needs to fill this ... */ -#define HAVE_ARCH_SIGINFO_T -/* * Careful to keep union _sifields from shifting ... */
@@ -27,92 +25,10 @@#error _MIPS_SZLONG neither 32 nor 64#endif -#define __ARCH_SIGSYS +#define __ARCH_HAS_SWAPPED_SIGINFO#include <asm-generic/siginfo.h> -/* We can't use generic siginfo_t, because our si_code and si_errno are swapped */ -typedef struct siginfo { -int si_signo; -int si_code; -int si_errno; -int __pad0[SI_MAX_SIZE /sizeof (int ) -SI_PAD_SIZE -3 ]; - -union { -int _pad[SI_PAD_SIZE ]; - -/* kill() */ -struct { -__kernel_pid_t _pid;/* sender's pid */ -__ARCH_SI_UID_T _uid;/* sender's uid */ - } _kill; - -/* POSIX.1b timers */ -struct { -__kernel_timer_t _tid;/* timer id */ -int _overrun;/* overrun count */ -char _pad[sizeof ( __ARCH_SI_UID_T) -sizeof (int )]; -sigval_t _sigval;/* same as below */ -int _sys_private;/* not to be passed to user */ - } _timer; - -/* POSIX.1b signals */ -struct { -__kernel_pid_t _pid;/* sender's pid */ -__ARCH_SI_UID_T _uid;/* sender's uid */ -sigval_t _sigval; - } _rt; - -/* SIGCHLD */ -struct { -__kernel_pid_t _pid;/* which child */ -__ARCH_SI_UID_T _uid;/* sender's uid */ -int _status;/* exit code */ -__kernel_clock_t _utime; -__kernel_clock_t _stime; - } _sigchld; - -/* IRIX SIGCHLD */ -struct { -__kernel_pid_t _pid;/* which child */ -__kernel_clock_t _utime; -int _status;/* exit code */ -__kernel_clock_t _stime; - } _irix_sigchld; - -/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ -struct { -void __user *_addr;/* faulting insn/memory ref. */ -#ifdef __ARCH_SI_TRAPNO -int _trapno;/* TRAP # which caused the signal */ -#endif -short _addr_lsb; -union { -/* used when si_code=SEGV_BNDERR */ -struct { -void __user *_lower; -void __user *_upper; - } _addr_bnd; -/* used when si_code=SEGV_PKUERR */ -__u32 _pkey; - }; - } _sigfault; - -/* SIGPOLL, SIGXFSZ (To do ...) */ -struct { -__ARCH_SI_BAND_T _band;/* POLL_IN, POLL_OUT, POLL_MSG */ -int _fd; - } _sigpoll; - -/* SIGSYS */ -struct { -void __user *_call_addr;/* calling user insn */ -int _syscall;/* triggering system call number */ -unsigned int _arch;/* AUDIT_ARCH_* of syscall */ - } _sigsys; - } _sifields; -}siginfo_t ; -/* * si_code values * Again these have been chosen to be IRIX compatible.
include/uapi/asm-generic/siginfo.h +5 -0
@@ -48,8 +48,13 @@ typedef union sigval { typedef struct siginfo { int si_signo; +#ifndef __ARCH_HAS_SWAPPED_SIGINFO int si_errno; int si_code; +#else + int si_code; + int si_errno; +#endif union { int _pad[SI_PAD_SIZE];
Signature · 1 line
2.14.1
PATCH 10/22 signal: Remove unnecessary ifdefs now that there is only one struct siginfo
In reply to Eric W. BiedermanRemove HAVE_ARCH_SIGINFO_T
Remove __ARCH_SIGSYS
--- include/linux/signal.h | 2 -- include/uapi/asm-generic/siginfo.h | 8 -------- kernel/signal.c | 4 ---- 3 files changed, 14 deletions(-)
include/linux/signal.h +0 -2
@@ -30,9 +30,7 @@ enum siginfo_layout {SIL_FAULT ,SIL_CHLD ,SIL_RT , -#ifdef __ARCH_SIGSYS SIL_SYS, -#endif };enum siginfo_layout siginfo_layout (int sig,int si_code);
include/uapi/asm-generic/siginfo.h +0 -8
@@ -44,8 +44,6 @@ typedef union sigval {#define __ARCH_SI_ATTRIBUTES#endif -#ifndef HAVE_ARCH_SIGINFO_T - typedef struct siginfo { int si_signo; #ifndef __ARCH_HAS_SWAPPED_SIGINFO
@@ -128,10 +126,6 @@ typedef struct siginfo { } _sifields; }__ARCH_SI_ATTRIBUTES siginfo_t; -/* If the arch shares siginfo, then it has SIGSYS. */ -#define __ARCH_SIGSYS -#endif -/* * How these fields are to be accessed. */
@@ -156,11 +150,9 @@ typedef struct siginfo {#define si_pkey _sifields._sigfault._pkey#define si_band _sifields._sigpoll._band#define si_fd _sifields._sigpoll._fd -#ifdef __ARCH_SIGSYS#define si_call_addr _sifields._sigsys._call_addr#define si_syscall _sifields._sigsys._syscall#define si_arch _sifields._sigsys._arch -#endif /* * si_code values
kernel/signal.c +0 -4
@@ -2697,9 +2697,7 @@ enum siginfo_layout siginfo_layout(int sig, int si_code) #endif [SIGCHLD] = { NSIGCHLD, SIL_CHLD }, [SIGPOLL] = { NSIGPOLL, SIL_POLL }, -#ifdef __ARCH_SIGSYS [SIGSYS] = { NSIGSYS, SIL_SYS }, -#endif };if ((sig <ARRAY_SIZE (filter)) && (si_code <= filter[sig].limit)) layout = filter[sig].layout;
@@ -2804,13 +2802,11 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from) err |=__put_user (from->si_uid, &to->si_uid); err |=__put_user (from->si_ptr, &to->si_ptr);break ; -#ifdef __ARCH_SIGSYScase SIL_SYS : err |=__put_user (from->si_call_addr, &to->si_call_addr); err |=__put_user (from->si_syscall, &to->si_syscall); err |=__put_user (from->si_arch, &to->si_arch);break ; -#endif }return err; }
Signature · 1 line
2.14.1
PATCH 11/22 signal: kill __ARCH_SI_UID_T
In reply to Eric W. BiedermanFrom: Al Viro <[email protected]>
it's always __kernel_uid32_t
--- include/uapi/asm-generic/siginfo.h | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-)
include/uapi/asm-generic/siginfo.h +3 -8
@@ -23,10 +23,6 @@ typedef union sigval {#define SI_PAD_SIZE ((SI_MAX_SIZE - __ARCH_SI_PREAMBLE_SIZE) / sizeof(int))#endif -#ifndef __ARCH_SI_UID_T -#define __ARCH_SI_UID_T __kernel_uid32_t -#endif -/* * The default "si_band" type is "long", as specified by POSIX. * However, some architectures want to override this to "int"
@@ -60,14 +56,13 @@ typedef struct siginfo {/* kill() */ struct {__kernel_pid_t _pid;/* sender's pid */ -__ARCH_SI_UID_T _uid;/* sender's uid */ +__kernel_uid32_t _uid;/* sender's uid */ } _kill;/* POSIX.1b timers */ struct {__kernel_timer_t _tid;/* timer id */ int _overrun;/* overrun count */ -char _pad[sizeof ( __ARCH_SI_UID_T) -sizeof (int )];sigval_t _sigval;/* same as below */ int _sys_private;/* not to be passed to user */ } _timer;
@@ -75,14 +70,14 @@ typedef struct siginfo {/* POSIX.1b signals */ struct {__kernel_pid_t _pid;/* sender's pid */ -__ARCH_SI_UID_T _uid;/* sender's uid */ +__kernel_uid32_t _uid;/* sender's uid */ sigval_t _sigval; } _rt;/* SIGCHLD */ struct {__kernel_pid_t _pid;/* which child */ -__ARCH_SI_UID_T _uid;/* sender's uid */ +__kernel_uid32_t _uid;/* sender's uid */ int _status;/* exit code */ __ARCH_SI_CLOCK_T _utime;__ARCH_SI_CLOCK_T _stime;
Signature · 1 line
2.14.1
PATCH 12/22 signal: unify compat_siginfo_t
In reply to Eric W. BiedermanFrom: Al Viro <[email protected]>
--EWB Added #ifdef CONFIG_X86_X32_ABI to arch/x86/kernel/signal_compat.c
Changed #ifdef CONFIG_X86_X32 to #ifdef CONFIG_X86_X32_ABI in linux/compat.h
CONFIG_X86_X32 is set when the user requests X32 support.
CONFIG_X86_X32_ABI is set when the user requests X32 support and the tool-chain has X32 allowing X32 support to be built.
--- arch/arm64/include/asm/compat.h | 63 --------------------------- arch/mips/include/asm/compat.h | 71 ------------------------------ arch/parisc/include/asm/compat.h | 63 --------------------------- arch/powerpc/include/asm/compat.h | 62 --------------------------- arch/s390/include/asm/compat.h | 72 ------------------------------- arch/sparc/include/asm/compat.h | 56 ------------------------ arch/tile/include/asm/compat.h | 58 ------------------------- arch/x86/include/asm/compat.h | 80 ---------------------------------- arch/x86/kernel/signal_compat.c | 4 ++ include/linux/compat.h | 90 +++++++++++++++++++++++++++++++++++++++ 10 files changed, 94 insertions(+), 525 deletions(-)
arch/arm64/include/asm/compat.h +0 -63
@@ -150,69 +150,6 @@ typedef u32 compat_old_sigset_t;typedef u32 compat_sigset_word ; -typedef union compat_sigval { -compat_int_t sival_int; -compat_uptr_t sival_ptr; -}compat_sigval_t ; - -typedef struct compat_siginfo { -int si_signo; -int si_errno; -int si_code; - -union { -int _pad[128 /sizeof (int ) -3 ]; - -/* kill() */ -struct { -compat_pid_t _pid;/* sender's pid */ -__compat_uid32_t _uid;/* sender's uid */ - } _kill; - -/* POSIX.1b timers */ -struct { -compat_timer_t _tid;/* timer id */ -int _overrun;/* overrun count */ -compat_sigval_t _sigval;/* same as below */ - } _timer; - -/* POSIX.1b signals */ -struct { -compat_pid_t _pid;/* sender's pid */ -__compat_uid32_t _uid;/* sender's uid */ -compat_sigval_t _sigval; - } _rt; - -/* SIGCHLD */ -struct { -compat_pid_t _pid;/* which child */ -__compat_uid32_t _uid;/* sender's uid */ -int _status;/* exit code */ -compat_clock_t _utime; -compat_clock_t _stime; - } _sigchld; - -/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ -struct { -compat_uptr_t _addr;/* faulting insn/memory ref. */ -short _addr_lsb;/* LSB of the reported address */ - } _sigfault; - -/* SIGPOLL */ -struct { -compat_long_t _band;/* POLL_IN, POLL_OUT, POLL_MSG */ -int _fd; - } _sigpoll; - -/* SIGSYS */ -struct { -compat_uptr_t _call_addr;/* calling user insn */ -int _syscall;/* triggering system call number */ -compat_uint_t _arch;/* AUDIT_ARCH_* of syscall */ - } _sigsys; - } _sifields; -}compat_siginfo_t ; -#define COMPAT_OFF_T_MAX 0x7fffffff/*
arch/mips/include/asm/compat.h +0 -71
79 lines not on this page · raw message
arch/parisc/include/asm/compat.h +0 -63
69 lines not on this page · raw message
arch/powerpc/include/asm/compat.h +0 -62
70 lines not on this page · raw message
arch/s390/include/asm/compat.h +0 -72
78 lines not on this page · raw message
arch/sparc/include/asm/compat.h +0 -56
64 lines not on this page · raw message
arch/tile/include/asm/compat.h +0 -58
66 lines not on this page · raw message
arch/x86/include/asm/compat.h +0 -80
86 lines not on this page · raw message
arch/x86/kernel/signal_compat.c +4 -0
@@ -75,9 +75,11 @@ static inline void signal_compat_build_tests(void)CHECK_CSI_SIZE (_sigchld,5 *sizeof (int ));CHECK_SI_SIZE (_sigchld,8 *sizeof (int )); +#ifdef CONFIG_X86_X32_ABI CHECK_CSI_OFFSET (_sigchld_x32);CHECK_CSI_SIZE (_sigchld_x32,7 *sizeof (int ));/* no _sigchld_x32 in the generic siginfo_t */ +#endif CHECK_CSI_OFFSET (_sigfault);CHECK_CSI_SIZE (_sigfault,4 *sizeof (int ));
@@ -169,9 +171,11 @@ int __copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from,if (!x32_ABI) {put_user_ex (from->si_utime, &to->si_utime);put_user_ex (from->si_stime, &to->si_stime); +#ifdef CONFIG_X86_X32_ABI }else {put_user_ex (from->si_utime, &to->_sifields._sigchld_x32._utime);put_user_ex (from->si_stime, &to->_sifields._sigchld_x32._stime); +#endif }put_user_ex (from->si_status, &to->si_status);/* FALL THROUGH */
include/linux/compat.h +90 -0
96 lines not on this page · raw message
Signature · 1 line
2.14.1
PATCH 13/22 signal: Move addr_lsb into the _sigfault union for clarity
In reply to Eric W. BiedermanThe addr_lsb fields is only valid and available when the signal is SIGBUS and the si_code is BUS_MCEERR_AR or BUS_MCEERR_AO. Document this with a comment and place the field in the _sigfault union to make this clear.
All of the fields stay in the same physical location so both the old and new definitions of struct siginfo will continue to work.
--- include/linux/compat.h | 12 ++++++++++-- include/uapi/asm-generic/siginfo.h | 14 +++++++++++--- 2 files changed, 21 insertions(+), 5 deletions(-)
include/linux/compat.h +10 -2
@@ -221,15 +221,23 @@ typedef struct compat_siginfo {#ifdef __ARCH_SI_TRAPNOint _trapno;/* TRAP # which caused the signal */ #endif -short int _addr_lsb;/* Valid LSB of the reported address. */ union { +/* +* used when si_code=BUS_MCEERR_AR or +* used when si_code=BUS_MCEERR_AO +*/ +short int _addr_lsb;/* Valid LSB of the reported address. */ /* used when si_code=SEGV_BNDERR */ struct { +short _dummy_bnd;compat_uptr_t _lower;compat_uptr_t _upper; } _addr_bnd;/* used when si_code=SEGV_PKUERR */ -u32 _pkey; +struct { +short _dummy_pkey; +u32 _pkey; + } _addr_pkey; }; } _sigfault;
include/uapi/asm-generic/siginfo.h +11 -3
@@ -94,15 +94,23 @@ typedef struct siginfo {unsigned int _flags;/* see ia64 si_flags */ unsigned long _isr;/* isr */ #endif -short _addr_lsb;/* LSB of the reported address */ union { +/* +* used when si_code=BUS_MCEERR_AR or +* used when si_code=BUS_MCEERR_AO +*/ +short _addr_lsb;/* LSB of the reported address */ /* used when si_code=SEGV_BNDERR */ struct { +short _dummy_bnd;void __user *_lower;void __user *_upper; } _addr_bnd;/* used when si_code=SEGV_PKUERR */ -__u32 _pkey; +struct { +short _dummy_pkey; +__u32 _pkey; + } _addr_pkey; }; } _sigfault;
@@ -142,7 +150,7 @@ typedef struct siginfo {#define si_addr_lsb _sifields._sigfault._addr_lsb#define si_lower _sifields._sigfault._addr_bnd._lower#define si_upper _sifields._sigfault._addr_bnd._upper -#define si_pkey _sifields._sigfault._pkey +#define si_pkey _sifields._sigfault._addr_pkey._pkey#define si_band _sifields._sigpoll._band#define si_fd _sifields._sigpoll._fd#define si_call_addr _sifields._sigsys._call_addr
Signature · 1 line
2.14.1
Re: [PATCH 13/22] signal: Move addr_lsb into the _sigfault union for clarity
Quoted 7 lines · Eric W. Biederman
The
addr_lsbfields is only valid and available when the signal is SIGBUS and thesi_codeisBUS_MCEERR_ARorBUS_MCEERR_AO. Document this with a comment and place the field in the_sigfaultunion to make this clear.All of the fields stay in the same physical location so both the old and new definitions of struct siginfo will continue to work.
This breaks the ABI and breaks protection keys. The physical locations *DO* change.
Before this patch:
#define si_pkey _sifields._sigfault._pkey
(gdb) print &((siginfo_t *)0)->_sifields._sigfault._pkey $1 = (__u32 *) 0x20 <irq_stack_union+32>
and after:
+#define si_pkey _sifields._sigfault._addr_pkey._pkey
(gdb) print &((siginfo_t *)0)->_sifields._sigfault._addr_pkey._pkey $1 = (__u32 *) 0x1c
Can we revert this, please?
Re: [PATCH 13/22] signal: Move addr_lsb into the _sigfault union for clarity
Quoted 18 lines · Dave Hansen
Quoted 7 lines · Eric W. Biederman
The
addr_lsbfields is only valid and available when the signal is SIGBUS and thesi_codeisBUS_MCEERR_ARorBUS_MCEERR_AO. Document this with a comment and place the field in the_sigfaultunion to make this clear.All of the fields stay in the same physical location so both the old and new definitions of struct siginfo will continue to work.
This breaks the ABI and breaks protection keys. The physical locations *DO* change.
Before this patch:
#define
si_pkey_sifields._sigfault._pkey
(gdb) print &((siginfo_t *)0)->_sifields._sigfault._pkey $1 = (__u32*)0x20<irq_stack_union+32>
Quoted 7 lines
and after:
+#define
si_pkey_sifields._sigfault._addr_pkey._pkey
(gdb) print &((siginfo_t *)0)->_sifields._sigfault._addr_pkey._pkey $1 = (__u32*)0x1cCan we revert this, please?
It does not revert cleanly so I reverted it manually. Patch doing that is attached. Should we do this, or is there a better option?
index e698ec1..8f8e3ef 100644
---
b/include/linux/compat.h | 12 ++---------- b/include/uapi/asm-generic/siginfo.h | 14 +++----------- 2 files changed, 5 insertions(+), 21 deletions(-)
include/linux/compat.h renamed from include/linux/compat.h~revert-b68a68d3dcc15ebbf23cbe91af1abf57591bd96b +2 -10
@@ -222,23 +222,15 @@ typedef struct compat_siginfo {#ifdef __ARCH_SI_TRAPNOint _trapno;/* TRAP # which caused the signal */ #endif +short int _addr_lsb;/* Valid LSB of the reported address. */ union { -/* -* used when si_code=BUS_MCEERR_AR or -* used when si_code=BUS_MCEERR_AO -*/ -short int _addr_lsb;/* Valid LSB of the reported address. */ /* used when si_code=SEGV_BNDERR */ struct { -compat_uptr_t _dummy_bnd;compat_uptr_t _lower;compat_uptr_t _upper; } _addr_bnd;/* used when si_code=SEGV_PKUERR */ -struct { -compat_uptr_t _dummy_pkey; -u32 _pkey; - } _addr_pkey; +u32 _pkey; }; } _sigfault;
include/uapi/asm-generic/siginfo.h renamed from include/uapi/asm-generic/siginfo.h~revert-b68a68d3dcc15ebbf23cbe91af1abf57591bd96b +3 -11
@@ -94,23 +94,15 @@ typedef struct siginfo {unsigned int _flags;/* see ia64 si_flags */ unsigned long _isr;/* isr */ #endif +short _addr_lsb;/* LSB of the reported address */ union { -/* -* used when si_code=BUS_MCEERR_AR or -* used when si_code=BUS_MCEERR_AO -*/ -short _addr_lsb;/* LSB of the reported address */ /* used when si_code=SEGV_BNDERR */ struct { -void *_dummy_bnd;void __user *_lower;void __user *_upper; } _addr_bnd;/* used when si_code=SEGV_PKUERR */ -struct { -void *_dummy_pkey; -__u32 _pkey; - } _addr_pkey; +__u32 _pkey; }; } _sigfault;
@@ -150,7 +142,7 @@ typedef struct siginfo {#define si_addr_lsb _sifields._sigfault._addr_lsb#define si_lower _sifields._sigfault._addr_bnd._lower#define si_upper _sifields._sigfault._addr_bnd._upper -#define si_pkey _sifields._sigfault._addr_pkey._pkey +#define si_pkey _sifields._sigfault._pkey#define si_band _sifields._sigpoll._band#define si_fd _sifields._sigpoll._fd#define si_call_addr _sifields._sigsys._call_addr
_
Re: [PATCH 13/22] signal: Move addr_lsb into the _sigfault union for clarity
Quoted 21 lines · Dave Hansen
Quoted 20 lines · Dave Hansen
Quoted 7 lines · Eric W. Biederman
The
addr_lsbfields is only valid and available when the signal is SIGBUS and thesi_codeisBUS_MCEERR_ARorBUS_MCEERR_AO. Document this with a comment and place the field in the_sigfaultunion to make this clear.All of the fields stay in the same physical location so both the old and new definitions of struct siginfo will continue to work.
This breaks the ABI and breaks protection keys. The physical locations *DO* change.
Before this patch:
#define
si_pkey_sifields._sigfault._pkey
(gdb) print &((siginfo_t *)0)->_sifields._sigfault._pkey $1 = (__u32*)0x20<irq_stack_union+32>and after:
Quoted 8 lines
Quoted 5 lines
+#define
si_pkey_sifields._sigfault._addr_pkey._pkey
(gdb) print &((siginfo_t *)0)->_sifields._sigfault._addr_pkey._pkey $1 = (__u32*)0x1cCan we revert this, please?
It does not revert cleanly so I reverted it manually. Patch doing that is attached. Should we do this, or is there a better option?
Please see:859d880cf544 ("signal: Correct the offset of si_pkey in struct siginfo")
Eric
Re: [PATCH 13/22] signal: Move addr_lsb into the _sigfault union for clarity
Quoted 4 lines · Eric W. Biederman
Quoted 2 lines
It does not revert cleanly so I reverted it manually. Patch doing that is attached. Should we do this, or is there a better option?
Please see:
859d880cf544("signal: Correct the offset ofsi_pkeyin struct siginfo")
It would be really nice to actually cc the folks that wrote and maintain the code when you both break their stuff and fix it. I don't see myself or the x86 maintainers cc'd on any of this: the patch that caused the breakage *or* the fix.
Re: [PATCH 13/22] signal: Move addr_lsb into the _sigfault union for clarity
Quoted 10 lines · Dave Hansen
Quoted 4 lines · Eric W. Biederman
Quoted 2 lines
It does not revert cleanly so I reverted it manually. Patch doing that is attached. Should we do this, or is there a better option?
Please see:
859d880cf544("signal: Correct the offset ofsi_pkeyin struct siginfo")It would be really nice to actually cc the folks that wrote and maintain the code when you both break their stuff and fix it. I don't see myself or the x86 maintainers cc'd on any of this: the patch that caused the breakage *or* the fix.
What I touched was in no way x86 or pkey specific code. The email alias for all of the arch maintainers in the kernel is called linux-arch. It is hard to find who cares bits of essentially unmaintained code in the kernel.
The fix was merged via the usual process and is available to everyone, and is not hard to find. It was labeled with an appropriate fixes tag.
I was also very careful to ensure that I fixed the regression I accidentally introduced and did not introduce another ABI regression with any other field:
f6a015498dca ("signal/x86: Include the field offsets in the build time checks")
Eric
PATCH 14/22 signal/powerpc: Remove redefinition of NSIGTRAP on powerpc
In reply to Eric W. BiedermanNSIGTRAP is 4 in the generic siginfo and powerpc just undefines NSGTRAP and redefine it as 4. That accomplishes nothing so remove the duplication.
--- arch/powerpc/include/uapi/asm/siginfo.h | 3 --- 1 file changed, 3 deletions(-)
arch/powerpc/include/uapi/asm/siginfo.h +0 -3
@@ -15,9 +15,6 @@#include <asm-generic/siginfo.h> -#undef NSIGTRAP -#define NSIGTRAP 4 -/* * SIGFPE si_codes */
Signature · 1 line
2.14.1
PATCH 15/22 signal/ia64: Move the ia64 specific si_codes to asm-generic/siginfo.h
In reply to Eric W. BiedermanHaving si_codes in many different files simply encourages duplicate definitions that can cause problems later. To avoid that merge the ia64 specific si_codes into uapi/asm-generic/siginfo.h
Update the sanity checks in arch/x86/kernel/signal_compat.c to expect the now lager NSIGILL and NSIGFPE. As nothing excpe the larger count is exposed on x86 no additional code needs to be updated.
--- arch/ia64/include/uapi/asm/siginfo.h | 27 --------------------------- arch/x86/kernel/signal_compat.c | 4 ++-- include/uapi/asm-generic/siginfo.h | 22 +++++++++++++++++++--- 3 files changed, 21 insertions(+), 32 deletions(-)
arch/ia64/include/uapi/asm/siginfo.h +0 -27
@@ -27,38 +27,11 @@#define __ISR_VALID_BIT 0#define __ISR_VALID (1 << __ISR_VALID_BIT) -/* -* SIGILL si_codes -*/ -#define ILL_BADIADDR 9/* unimplemented instruction address */ -#define __ILL_BREAK 10/* illegal break */ -#define __ILL_BNDMOD 11/* bundle-update (modification) in progress */ -#undef NSIGILL -#define NSIGILL 11 -/* * SIGFPE si_codes */ #ifdef __KERNEL__#define FPE_FIXME 0/* Broken dup of SI_USER */ #endif /* __KERNEL__ */ -#define __FPE_DECOVF 9/* decimal overflow */ -#define __FPE_DECDIV 10/* decimal division by zero */ -#define __FPE_DECERR 11/* packed decimal error */ -#define __FPE_INVASC 12/* invalid ASCII digit */ -#define __FPE_INVDEC 13/* invalid decimal digit */ -#undef NSIGFPE -#define NSIGFPE 13 - -/* -* SIGSEGV si_codes -*/ -#define __SEGV_PSTKOVF 4/* paragraph stack overflow */ -#undef NSIGSEGV -#define NSIGSEGV 4 - -#undef NSIGTRAP -#define NSIGTRAP 4 -#endif /* _UAPI_ASM_IA64_SIGINFO_H */
arch/x86/kernel/signal_compat.c +2 -2
@@ -25,8 +25,8 @@ static inline void signal_compat_build_tests(void)* limits also have to look at this code. Make sure any * new fields are handled in copy_siginfo_to_user32()! */ -BUILD_BUG_ON (NSIGILL !=8 ); -BUILD_BUG_ON (NSIGFPE !=8 ); +BUILD_BUG_ON (NSIGILL !=11 ); +BUILD_BUG_ON (NSIGFPE !=13 );BUILD_BUG_ON (NSIGSEGV !=4 );BUILD_BUG_ON (NSIGBUS !=5 );BUILD_BUG_ON (NSIGTRAP !=4 );
include/uapi/asm-generic/siginfo.h +19 -3
@@ -186,7 +186,12 @@ typedef struct siginfo {#define ILL_PRVREG 6/* privileged register */ #define ILL_COPROC 7/* coprocessor error */ #define ILL_BADSTK 8/* internal stack error */ -#define NSIGILL 8 +#ifdef __ia64__ +# define ILL_BADIADDR 9/* unimplemented instruction address */ +# define __ILL_BREAK 10/* illegal break */ +# define __ILL_BNDMOD 11/* bundle-update (modification) in progress */ +#endif +#define NSIGILL 11/* * SIGFPE si_codes
@@ -199,7 +204,14 @@ typedef struct siginfo {#define FPE_FLTRES 6/* floating point inexact result */ #define FPE_FLTINV 7/* floating point invalid operation */ #define FPE_FLTSUB 8/* subscript out of range */ -#define NSIGFPE 8 +#ifdef __ia64__ +# define __FPE_DECOVF 9/* decimal overflow */ +# define __FPE_DECDIV 10/* decimal division by zero */ +# define __FPE_DECERR 11/* packed decimal error */ +# define __FPE_INVASC 12/* invalid ASCII digit */ +# define __FPE_INVDEC 13/* invalid decimal digit */ +#endif +#define NSIGFPE 13/* * SIGSEGV si_codes
@@ -207,7 +219,11 @@ typedef struct siginfo {#define SEGV_MAPERR 1/* address not mapped to object */ #define SEGV_ACCERR 2/* invalid permissions for mapped object */ #define SEGV_BNDERR 3/* failed address bound checks */ -#define SEGV_PKUERR 4/* failed protection key checks */ +#ifdef __ia64__ +# define __SEGV_PSTKOVF 4/* paragraph stack overflow */ +#else +# define SEGV_PKUERR 4/* failed protection key checks */ +#endif #define NSIGSEGV 4/*
Signature · 1 line
2.14.1
PATCH 16/22 signal/frv: Move the frv specific si_codes to asm-generic/siginfo.h
In reply to Eric W. BiedermanHaving si_codes in many different files simply encourages duplicate definitions that can cause problems later. To avoid that merce the frv specific si_codes into uapi/asm-generic/siginfo.h
This allows the removal of arch/frv/uapi/include/asm/siginfo.h as the last last meaningful definition it held was FPE_MDAOVF.
--- arch/frv/include/uapi/asm/Kbuild | 1 + arch/frv/include/uapi/asm/siginfo.h | 13 ------------- include/uapi/asm-generic/siginfo.h | 3 +++ 3 files changed, 4 insertions(+), 13 deletions(-) delete mode 100644 arch/frv/include/uapi/asm/siginfo.h
arch/frv/include/uapi/asm/Kbuild +1 -0
@@ -1,4 +1,5 @@ # UAPI Header export list include include/uapi/asm-generic/Kbuild.asm +generic-y += siginfo.h generic-y += bpf_perf_event.h
arch/frv/include/uapi/asm/siginfo.h deleted +0 -13
@@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#ifndef _ASM_SIGINFO_H -#define _ASM_SIGINFO_H - -#include <linux/types.h> -#include <asm-generic/siginfo.h> - -#define FPE_MDAOVF 9/* media overflow */ -#undef NSIGFPE -#define NSIGFPE 9 - -#endif -
include/uapi/asm-generic/siginfo.h +3 -0
@@ -204,6 +204,9 @@ typedef struct siginfo {#define FPE_FLTRES 6/* floating point inexact result */ #define FPE_FLTINV 7/* floating point invalid operation */ #define FPE_FLTSUB 8/* subscript out of range */ +#ifdef __frv__ +# define FPE_MDAOVF 9/* media overflow */ +#endif #ifdef __ia64__# define __FPE_DECOVF 9/* decimal overflow */ # define __FPE_DECDIV 10/* decimal division by zero */
Signature · 1 line
2.14.1
PATCH 17/22 signal/tile: Move the tile specific si_codes to asm-generic/siginfo.h
In reply to Eric W. BiedermanHaving si_codes in many different files simply encourages duplicate definitions that can cause problems later. To avoid that merge the tile specific si_codes into uapi/asm-generic/siginfo.h
--- arch/tile/include/uapi/asm/siginfo.h | 8 -------- include/uapi/asm-generic/siginfo.h | 4 ++++ 2 files changed, 4 insertions(+), 8 deletions(-)
arch/tile/include/uapi/asm/siginfo.h +0 -8
@@ -24,12 +24,4 @@#include <asm-generic/siginfo.h> -/* -* Additional Tile-specific SIGILL si_codes -*/ -#define ILL_DBLFLT 9/* double fault */ -#define ILL_HARDWALL 10/* user networks hardwall violation */ -#undef NSIGILL -#define NSIGILL 10 -#endif /* _ASM_TILE_SIGINFO_H */
include/uapi/asm-generic/siginfo.h +4 -0
@@ -186,6 +186,10 @@ typedef struct siginfo {#define ILL_PRVREG 6/* privileged register */ #define ILL_COPROC 7/* coprocessor error */ #define ILL_BADSTK 8/* internal stack error */ +#ifdef __tile__ +# define ILL_DBLFLT 9/* double fault */ +# define ILL_HARDWALL 10/* user networks hardwall violation */ +#endif #ifdef __ia64__# define ILL_BADIADDR 9/* unimplemented instruction address */ # define __ILL_BREAK 10/* illegal break */
Signature · 1 line
2.14.1
PATCH 18/22 signal/blackfin: Move the blackfin specific si_codes to asm-generic/siginfo.h
In reply to Eric W. BiedermanHaving si_codes in many different files simply encourages duplicate definitions that can cause problems later. To avoid that merge the blackfin specific si_codes into uapi/asm-generic/siginfo.h
Update copy_siginfo_to_user to copy with the absence of BUS_MCEERR_AR that blackfin defines to be something else.
--- arch/blackfin/include/uapi/asm/siginfo.h | 32 -------------------------------- include/uapi/asm-generic/siginfo.h | 29 +++++++++++++++++++++++++++-- kernel/signal.c | 9 ++++++--- 3 files changed, 33 insertions(+), 37 deletions(-)
arch/blackfin/include/uapi/asm/siginfo.h +0 -32
@@ -15,36 +15,4 @@#define si_uid16 _sifields._kill._uid -#define ILL_ILLPARAOP 2/* illegal opcode combine ********** */ -#define ILL_ILLEXCPT 4/* unrecoverable exception ********** */ -#define ILL_CPLB_VI 9/* D/I CPLB protect violation ******** */ -#define ILL_CPLB_MISS 10/* D/I CPLB miss ******** */ -#define ILL_CPLB_MULHIT 11/* D/I CPLB multiple hit ******** */ -#undef NSIGILL -#define NSIGILL 11 - -/* -* SIGBUS si_codes -*/ -#define BUS_OPFETCH 4/* error from instruction fetch ******** */ -#undef NSIGBUS -#define NSIGBUS 4 - -/* -* SIGTRAP si_codes -*/ -#define TRAP_STEP 1/* single-step breakpoint************* */ -#define TRAP_TRACEFLOW 2/* trace buffer overflow ************* */ -#define TRAP_WATCHPT 3/* watchpoint match ************* */ -#define TRAP_ILLTRAP 4/* illegal trap ************* */ -#undef NSIGTRAP -#define NSIGTRAP 4 - -/* -* SIGSEGV si_codes -*/ -#define SEGV_STACKFLOW 3/* stack overflow */ -#undef NSIGSEGV -#define NSIGSEGV 3 -#endif /* _UAPI_BFIN_SIGINFO_H */
include/uapi/asm-generic/siginfo.h +27 -2
@@ -179,13 +179,24 @@ typedef struct siginfo {* SIGILL si_codes */ #define ILL_ILLOPC 1/* illegal opcode */ +#ifdef __bfin__ +# define ILL_ILLPARAOP 2/* illegal opcode combine */ +#endif #define ILL_ILLOPN 2/* illegal operand */ #define ILL_ILLADR 3/* illegal addressing mode */ #define ILL_ILLTRP 4/* illegal trap */ +#ifdef __bfin__ +# define ILL_ILLEXCPT 4/* unrecoverable exception */ +#endif #define ILL_PRVOPC 5/* privileged opcode */ #define ILL_PRVREG 6/* privileged register */ #define ILL_COPROC 7/* coprocessor error */ #define ILL_BADSTK 8/* internal stack error */ +#ifdef __bfin__ +# define ILL_CPLB_VI 9/* D/I CPLB protect violation */ +# define ILL_CPLB_MISS 10/* D/I CPLB miss */ +# define ILL_CPLB_MULHIT 11/* D/I CPLB multiple hit */ +#endif #ifdef __tile__# define ILL_DBLFLT 9/* double fault */ # define ILL_HARDWALL 10/* user networks hardwall violation */
@@ -225,7 +236,11 @@ typedef struct siginfo {*/ #define SEGV_MAPERR 1/* address not mapped to object */ #define SEGV_ACCERR 2/* invalid permissions for mapped object */ -#define SEGV_BNDERR 3/* failed address bound checks */ +#ifdef __bfin__ +# define SEGV_STACKFLOW 3/* stack overflow */ +#else +# define SEGV_BNDERR 3/* failed address bound checks */ +#endif #ifdef __ia64__# define __SEGV_PSTKOVF 4/* paragraph stack overflow */ #else
@@ -239,8 +254,12 @@ typedef struct siginfo {#define BUS_ADRALN 1/* invalid address alignment */ #define BUS_ADRERR 2/* non-existent physical address */ #define BUS_OBJERR 3/* object specific hardware error */ +#ifdef __bfin__ +# define BUS_OPFETCH 4/* error from instruction fetch */ +#else /* hardware memory error consumed on a machine check: action required */ -#define BUS_MCEERR_AR 4 +# define BUS_MCEERR_AR 4 +#endif /* hardware memory error detected in process but not consumed: action optional*/ #define BUS_MCEERR_AO 5#define NSIGBUS 5
@@ -252,6 +271,12 @@ typedef struct siginfo {#define TRAP_TRACE 2/* process trace trap */ #define TRAP_BRANCH 3/* process taken branch trap */ #define TRAP_HWBKPT 4/* hardware breakpoint/watchpoint */ +#ifdef __bfin__ +# define TRAP_STEP 1/* single-step breakpoint */ +# define TRAP_TRACEFLOW 2/* trace buffer overflow */ +# define TRAP_WATCHPT 3/* watchpoint match */ +# define TRAP_ILLTRAP 4/* illegal trap */ +#endif #define NSIGTRAP 4/*
kernel/signal.c +6 -3
@@ -2770,13 +2770,16 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from) err |=__put_user (from->si_flags, &to->si_flags); err |=__put_user (from->si_isr, &to->si_isr);#endif -#ifdef BUS_MCEERR_AO /* * Other callers might not initialize the si_lsb field, * so check explicitly for the right codes here. */ -if (from->si_signo ==SIGBUS && - (from->si_code ==BUS_MCEERR_AR || from->si_code ==BUS_MCEERR_AO )) +#ifdef BUS_MCEERR_AR +if (from->si_signo ==SIGBUS && from->si_code ==BUS_MCEERR_AR ) + err |=__put_user (from->si_addr_lsb, &to->si_addr_lsb); +#endif +#ifdef BUS_MCEERR_AO +if (from->si_signo ==SIGBUS && from->si_code ==BUS_MCEERR_AO ) err |=__put_user (from->si_addr_lsb, &to->si_addr_lsb);#endif #ifdef SEGV_BNDERR
Signature · 1 line
2.14.1
PATCH 19/22 signal/blackfin: Remove pointless UID16_SIGINFO_COMPAT_NEEDED
In reply to Eric W. BiedermanNothing tests this define so just remove it.
I suspect the intention was to make the uid field in siginfo 16bit however I can't find any code that ever tested this defined, and even if it did it the layout has been this way for 8 years so changing it now would break the ABI with userspace.
--- arch/blackfin/include/uapi/asm/siginfo.h | 2 -- 1 file changed, 2 deletions(-)
arch/blackfin/include/uapi/asm/siginfo.h +0 -2
@@ -11,8 +11,6 @@#include <linux/types.h> #include <asm-generic/siginfo.h> -#define UID16_SIGINFO_COMPAT_NEEDED -#define si_uid16 _sifields._kill._uid#endif /* _UAPI_BFIN_SIGINFO_H */
Signature · 1 line
2.14.1
PATCH 20/22 signal: Unify and correct copy_siginfo_from_user32
In reply to Eric W. BiedermanThe function copy_siginfo_from_user32 is used for two things, in ptrace since the dawn of siginfo for arbirarily modifying a signal that user space sees, and in sigqueueinfo to send a signal with arbirary siginfo data.
Create a single copy of copy_siginfo_from_user32 that all architectures share, and teach it to handle all of the cases in the siginfo union.
In the generic version of copy_siginfo_from_user32 ensure that all of the fields in siginfo are initialized so that the siginfo structure can be safely copied to userspace if necessary.
When copying the embedded sigval union copy the si_int member. That ensures the 32bit values passes through the kernel unchanged.
--- arch/arm64/kernel/signal32.c | 10 ----- arch/mips/kernel/signal32.c | 10 ----- arch/parisc/kernel/signal32.c | 44 ---------------------- arch/parisc/kernel/signal32.h | 1 - arch/powerpc/kernel/signal_32.c | 9 ----- arch/s390/kernel/compat_signal.c | 48 ------------------------ arch/sparc/kernel/signal32.c | 16 -------- arch/tile/kernel/compat_signal.c | 18 --------- arch/x86/kernel/signal_compat.c | 21 ----------- include/linux/compat.h | 2 +- kernel/signal.c | 81 ++++++++++++++++++++++++++++++++++++++++ 11 files changed, 82 insertions(+), 178 deletions(-)
arch/arm64/kernel/signal32.c +0 -10
@@ -195,16 +195,6 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)return err; } -int copy_siginfo_from_user32 (siginfo_t *to,compat_siginfo_t __user *from) -{ -if (copy_from_user (to, from, __ARCH_SI_PREAMBLE_SIZE) || -copy_from_user (to->_sifields._pad, - from->_sifields._pad,SI_PAD_SIZE )) -return -EFAULT ; - -return 0 ; -} -/* * VFP save/restore code. *
arch/mips/kernel/signal32.c +0 -10
@@ -133,13 +133,3 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) }return err; } - -int copy_siginfo_from_user32 (siginfo_t *to,compat_siginfo_t __user *from) -{ -if (copy_from_user (to, from,3 *sizeof (int )) || -copy_from_user (to->_sifields._pad, - from->_sifields._pad,SI_PAD_SIZE32 )) -return -EFAULT ; - -return 0 ; -}
arch/parisc/kernel/signal32.c +0 -44
50 lines not on this page · raw message
arch/parisc/kernel/signal32.h +0 -1
@@ -35,7 +35,6 @@ struct compat_ucontext {/* ELF32 signal handling */ int copy_siginfo_to_user32 (compat_siginfo_t __user *to,const siginfo_t *from); -int copy_siginfo_from_user32 (siginfo_t *to,compat_siginfo_t __user *from);/* In a deft move of uber-hackery, we decide to carry the top half of all * 64-bit registers in a non-portable, non-ABI, hidden structure.
arch/powerpc/kernel/signal_32.c +0 -9
@@ -933,15 +933,6 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *d, const siginfo_t *s)#define copy_siginfo_to_user copy_siginfo_to_user32 -int copy_siginfo_from_user32 (siginfo_t *to,struct compat_siginfo __user *from) -{ -if (copy_from_user (to, from,3 *sizeof (int )) || -copy_from_user (to->_sifields._pad, - from->_sifields._pad,SI_PAD_SIZE32 )) -return -EFAULT ; - -return 0 ; -}#endif /* CONFIG_PPC64 */ /*
arch/s390/kernel/compat_signal.c +0 -48
54 lines not on this page · raw message
arch/sparc/kernel/signal32.c +0 -16
@@ -123,22 +123,6 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)return err; } -/* CAUTION: This is just a very minimalist implementation for the -* sake of compat_sys_rt_sigqueueinfo() -*/ -int copy_siginfo_from_user32 (siginfo_t *to,compat_siginfo_t __user *from) -{ -if (!access_ok (VERIFY_WRITE , from,sizeof (compat_siginfo_t))) -return -EFAULT ; - -if (copy_from_user (to, from,3 *sizeof (int )) || -copy_from_user (to->_sifields._pad, from->_sifields._pad, -SI_PAD_SIZE )) -return -EFAULT ; - -return 0 ; -} -/* Checks if the fp is valid. We always build signal frames which are * 16-byte aligned, therefore we can always enforce that the restore * frame has that property as well.
arch/tile/kernel/compat_signal.c +0 -18
@@ -105,24 +105,6 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *frreturn err; } -int copy_siginfo_from_user32 (siginfo_t *to,struct compat_siginfo __user *from) -{ -int err; - -if (!access_ok (VERIFY_READ , from,sizeof (struct compat_siginfo ))) -return -EFAULT ; - - err =__get_user (to->si_signo, &from->si_signo); - err |=__get_user (to->si_errno, &from->si_errno); - err |=__get_user (to->si_code, &from->si_code); - - err |=__get_user (to->si_pid, &from->si_pid); - err |=__get_user (to->si_uid, &from->si_uid); - err |=__get_user (to->si_int, &from->si_int); - -return err; -} -/* The assembly shim for this function arranges to ignore the return value. */ long compat_sys_rt_sigreturn (void ) {
arch/x86/kernel/signal_compat.c +0 -21
@@ -207,24 +207,3 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)return __copy_siginfo_to_user32 (to, from,in_x32_syscall ()); } -int copy_siginfo_from_user32 (siginfo_t *to,compat_siginfo_t __user *from) -{ -int err =0 ; -u32 ptr32; - -if (!access_ok (VERIFY_READ , from,sizeof (compat_siginfo_t))) -return -EFAULT ; - - get_user_try { -get_user_ex (to->si_signo, &from->si_signo); -get_user_ex (to->si_errno, &from->si_errno); -get_user_ex (to->si_code, &from->si_code); - -get_user_ex (to->si_pid, &from->si_pid); -get_user_ex (to->si_uid, &from->si_uid); -get_user_ex (ptr32, &from->si_ptr); - to->si_ptr =compat_ptr (ptr32); - }get_user_catch (err); - -return err; -}
include/linux/compat.h +1 -1
@@ -510,7 +510,7 @@ long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask, unsigned long bitmap_size);long compat_put_bitmap (compat_ulong_t __user *umask,unsigned long *mask,unsigned long bitmap_size); -int copy_siginfo_from_user32 (siginfo_t *to,struct compat_siginfo __user *from); +int copy_siginfo_from_user32 (siginfo_t *to,const struct compat_siginfo __user *from);int copy_siginfo_to_user32 (struct compat_siginfo __user *to,const siginfo_t *from);int get_compat_sigevent (struct sigevent *event,const struct compat_sigevent __user *u_event);
kernel/signal.c +81 -0
87 lines not on this page · raw message
Signature · 1 line
2.14.1
PATCH 21/22 signal: Remove the code to clear siginfo before calling copy_siginfo_from_user32
In reply to Eric W. BiedermanThe new unified copy_siginfo_from_user32 takes care of this.
--- kernel/ptrace.c | 1 - kernel/signal.c | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-)
kernel/ptrace.c +0 -1
@@ -1226,7 +1226,6 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,break ;case PTRACE_SETSIGINFO : -memset (&siginfo,0 ,sizeof siginfo);if (copy_siginfo_from_user32 ( &siginfo, (struct compat_siginfo __user *) datap)) ret = -EFAULT ;
kernel/signal.c +2 -2
@@ -3155,7 +3155,7 @@ COMPAT_SYSCALL_DEFINE3(rt_sigqueueinfo, int, sig, struct compat_siginfo __user *, uinfo) { - siginfo_t info = {}; + siginfo_t info;int ret =copy_siginfo_from_user32 (&info, uinfo);if (unlikely (ret))return ret;
@@ -3199,7 +3199,7 @@ COMPAT_SYSCALL_DEFINE4(rt_tgsigqueueinfo, int, sig, struct compat_siginfo __user *, uinfo) { - siginfo_t info = {}; + siginfo_t info;if (copy_siginfo_from_user32 (&info, uinfo))return -EFAULT ;
Signature · 1 line
2.14.1
PATCH 22/22 signal: Unify and correct copy_siginfo_to_user32
In reply to Eric W. BiedermanAmong the existing architecture specific versions of copy_siginfo_to_user32 there are several different implementation problems. Some architectures fail to handle all of the cases in in the siginfo union. Some architectures perform a blind copy of the siginfo union when the si_code is negative. A blind copy suggests the data is expected to be in 32bit siginfo format, which means that receiving such a signal via signalfd won't work, or that the data is in 64bit siginfo and the code is copying nonsense to userspace.
Create a single instance of copy_siginfo_to_user32 that all of the architectures can share, and teach it to handle all of the cases in the siginfo union correctly, with the assumption that siginfo is stored internally to the kernel is 64bit siginfo format.
A special case is made for x86 x32 format. This is needed as presence of both x32 and ia32 on x86_64 results in two different 32bit signal formats. By allowing this small special case there winds up being exactly one code base that needs to be maintained between all of the architectures. Vastly increasing the testing base and the chances of finding bugs.
As the x86 copy of copy_siginfo_to_user32 the call of the x86 signal_compat_build_tests were moved into sigaction_compat_abi, so that they will keep running.
--- arch/arm64/kernel/signal32.c | 70 ---------------------------- arch/mips/include/asm/compat.h | 2 - arch/mips/kernel/signal32.c | 57 ----------------------- arch/parisc/kernel/signal32.c | 62 ------------------------- arch/parisc/kernel/signal32.h | 2 - arch/powerpc/include/asm/compat.h | 2 - arch/powerpc/kernel/signal_32.c | 57 ----------------------- arch/s390/kernel/compat_signal.c | 52 --------------------- arch/sparc/include/asm/compat.h | 2 - arch/sparc/kernel/signal32.c | 53 --------------------- arch/tile/include/asm/compat.h | 2 - arch/tile/kernel/compat_signal.c | 55 ---------------------- arch/x86/include/asm/compat.h | 4 ++ arch/x86/include/asm/fpu/signal.h | 6 --- arch/x86/kernel/signal_compat.c | 96 +-------------------------------------- kernel/signal.c | 90 ++++++++++++++++++++++++++++++++++++ 16 files changed, 96 insertions(+), 516 deletions(-)
arch/arm64/kernel/signal32.c +0 -70
@@ -125,76 +125,6 @@ static inline int get_sigset_t(sigset_t *set,return 0 ; } -int copy_siginfo_to_user32 (compat_siginfo_t __user *to,const siginfo_t *from) -{ -int err; - -if (!access_ok (VERIFY_WRITE , to,sizeof (*to))) -return -EFAULT ; - -/* If you change siginfo_t structure, please be sure -* this code is fixed accordingly. -* It should never copy any pad contained in the structure -* to avoid security leaks, but must copy the generic -* 3 ints plus the relevant union member. -* This routine must convert siginfo from 64bit to 32bit as well -* at the same time. -*/ - err =__put_user (from->si_signo, &to->si_signo); - err |=__put_user (from->si_errno, &to->si_errno); - err |=__put_user (from->si_code, &to->si_code); -if (from->si_code <0 ) - err |=__copy_to_user (&to->_sifields._pad, &from->_sifields._pad, -SI_PAD_SIZE ); -else switch (siginfo_layout (from->si_signo, from->si_code)) { -case SIL_KILL : - err |=__put_user (from->si_pid, &to->si_pid); - err |=__put_user (from->si_uid, &to->si_uid); -break ; -case SIL_TIMER : - err |=__put_user (from->si_tid, &to->si_tid); - err |=__put_user (from->si_overrun, &to->si_overrun); - err |=__put_user (from->si_int, &to->si_int); -break ; -case SIL_POLL : - err |=__put_user (from->si_band, &to->si_band); - err |=__put_user (from->si_fd, &to->si_fd); -break ; -case SIL_FAULT : - err |=__put_user ((compat_uptr_t )(unsigned long )from->si_addr, - &to->si_addr); -#ifdef BUS_MCEERR_AO -/* -* Other callers might not initialize the si_lsb field, -* so check explicitly for the right codes here. -*/ -if (from->si_signo ==SIGBUS && - (from->si_code ==BUS_MCEERR_AR || from->si_code ==BUS_MCEERR_AO )) - err |=__put_user (from->si_addr_lsb, &to->si_addr_lsb); -#endif -break ; -case SIL_CHLD : - err |=__put_user (from->si_pid, &to->si_pid); - err |=__put_user (from->si_uid, &to->si_uid); - err |=__put_user (from->si_status, &to->si_status); - err |=__put_user (from->si_utime, &to->si_utime); - err |=__put_user (from->si_stime, &to->si_stime); -break ; -case SIL_RT : - err |=__put_user (from->si_pid, &to->si_pid); - err |=__put_user (from->si_uid, &to->si_uid); - err |=__put_user (from->si_int, &to->si_int); -break ; -case SIL_SYS : - err |=__put_user ((compat_uptr_t )(unsigned long ) - from->si_call_addr, &to->si_call_addr); - err |=__put_user (from->si_syscall, &to->si_syscall); - err |=__put_user (from->si_arch, &to->si_arch); -break ; - } -return err; -} -/* * VFP save/restore code. *
arch/mips/include/asm/compat.h +0 -2
@@ -126,8 +126,6 @@ typedef u32 compat_old_sigset_t; /* at least 32 bits */typedef u32 compat_sigset_word ; -#define SI_PAD_SIZE32 (128/sizeof(int) - 3) -#define COMPAT_OFF_T_MAX 0x7fffffff/*
arch/mips/kernel/signal32.c +0 -57
60 lines not on this page · raw message
arch/parisc/kernel/signal32.c +0 -62
65 lines not on this page · raw message
arch/parisc/kernel/signal32.h +0 -2
@@ -34,8 +34,6 @@ struct compat_ucontext {/* ELF32 signal handling */ -int copy_siginfo_to_user32 (compat_siginfo_t __user *to,const siginfo_t *from); -/* In a deft move of uber-hackery, we decide to carry the top half of all * 64-bit registers in a non-portable, non-ABI, hidden structure. * Userspace can read the hidden structure if it *wants* but is never
arch/powerpc/include/asm/compat.h +0 -2
@@ -119,8 +119,6 @@ typedef u32 compat_old_sigset_t;typedef u32 compat_sigset_word ; -#define SI_PAD_SIZE32 (128/sizeof(int) - 3) -#define COMPAT_OFF_T_MAX 0x7fffffff/*
arch/powerpc/kernel/signal_32.c +0 -57
63 lines not on this page · raw message
arch/s390/kernel/compat_signal.c +0 -52
58 lines not on this page · raw message
arch/sparc/include/asm/compat.h +0 -2
@@ -149,8 +149,6 @@ typedef u32 compat_old_sigset_t;typedef u32 compat_sigset_word ; -#define SI_PAD_SIZE32 (128/sizeof(int) - 3) -#define COMPAT_OFF_T_MAX 0x7fffffff/*
arch/sparc/kernel/signal32.c +0 -53
59 lines not on this page · raw message
arch/tile/include/asm/compat.h +0 -2
@@ -110,8 +110,6 @@ struct compat_flock64 {typedef u32 compat_sigset_word ; -#define COMPAT_SI_PAD_SIZE (128/sizeof(int) - 3) -#define COMPAT_OFF_T_MAX 0x7fffffffstruct compat_ipc64_perm {
arch/tile/kernel/compat_signal.c +0 -55
61 lines not on this page · raw message
arch/x86/include/asm/compat.h +4 -0
@@ -249,4 +249,8 @@ static inline bool in_compat_syscall(void) }#define in_compat_syscall in_compat_syscall/* override the generic impl */ +struct compat_siginfo ; +int __copy_siginfo_to_user32 (struct compat_siginfo __user *to, +const siginfo_t *from,bool x32_ABI); +#endif /* _ASM_X86_COMPAT_H */
arch/x86/include/asm/fpu/signal.h +0 -6
@@ -20,12 +20,6 @@ int ia32_setup_frame(int sig, struct ksignal *ksig,# define ia32_setup_rt_frame __setup_rt_frame#endif -#ifdef CONFIG_COMPAT -int __copy_siginfo_to_user32 (compat_siginfo_t __user *to, -const siginfo_t *from,bool x32_ABI); -#endif - -extern void convert_from_fxsr (struct user_i387_ia32_struct *env,struct task_struct *tsk); extern void convert_to_fxsr(struct task_struct *tsk,
arch/x86/kernel/signal_compat.c +2 -94
105 lines not on this page · raw message
kernel/signal.c +90 -0
96 lines not on this page · raw message
Signature · 1 line
2.14.1
Al Viro
maintainerRe: [PATCH 22/22] signal: Unify and correct copy_siginfo_to_user32
Quoted 8 lines · Eric W. Biederman
Among the existing architecture specific versions of
copy_siginfo_to_user32there are several different implementation problems. Some architectures fail to handle all of the cases in in the siginfo union. Some architectures perform a blind copy of the siginfo union when thesi_codeis negative. A blind copy suggests the data is expected to be in 32bit siginfo format, which means that receiving such a signal via signalfd won't work, or that the data is in 64bit siginfo and the code is copying nonsense to userspace.
Huh? Negative si_code comes from rt_sigqueueinfo(2); in that case the sucker is supposed to pass user-supplied opaque chunk of data in ->_sifields._pad. "Copy everything when ->si_code is negative" is exactly the right behaviour. Failing to copy it out (and in, for copy_siginfo_from_user32()) is a bug.
32bit tasks should behave on 64bit host like they would on 32bit one when we have biarch compat. And "application using sigqueueinfo() to pass data might be using different layouts of the payload" is not an excuse for failing to transmit it in the first place.
Re: [PATCH 22/22] signal: Unify and correct copy_siginfo_to_user32
Quoted 16 lines · Al Viro
Quoted 8 lines · Eric W. Biederman
Among the existing architecture specific versions of
copy_siginfo_to_user32there are several different implementation problems. Some architectures fail to handle all of the cases in in the siginfo union. Some architectures perform a blind copy of the siginfo union when thesi_codeis negative. A blind copy suggests the data is expected to be in 32bit siginfo format, which means that receiving such a signal via signalfd won't work, or that the data is in 64bit siginfo and the code is copying nonsense to userspace.Huh? Negative
si_codecomes fromrt_sigqueueinfo(2); in that case the sucker is supposed to pass user-supplied opaque chunk of data in ->_sifields._pad. "Copy everything when ->si_code is negative" is exactly the right behaviour. Failing to copy it out (and in, forcopy_siginfo_from_user32()) is a bug.
Quoted 4 lines
32bit tasks should behave on 64bit host like they would on 32bit one when we have biarch compat. And "application using
sigqueueinfo()to pass data might be using different layouts of the payload" is not an excuse for failing to transmit it in the first place.
If glibc actually offered rt_sigqueueinfo or any function that would queue a full siginfo that would be a compelling argument.
As it is the only users of rt_sigqueueinfo that I am aware of is CRIU and the implementation of sigqueue.
A couple of months ago I went hunting for users and for anyone who was defining si_codes and I did not find a single instance of anything defining signals that would pass more information than is known to the kernel, and except for CRIU all I found was limited to what you can do with sigqueue.
So no I do not think my choice will cause a regression.
Further SI_TIMER which the kernel does send is also negative. The difference between negative and positive is that negative si_codes are supposed to be signal agnostic and positive si_codes are signal specific.
If this causes a single regression, or if anyone can point me at the code of an application this will cause a regression for. I will change the code right then and there.
My concern is that people have not been careful when defining new signals. What looks like rules in one place are not the rules in another place. If we had been careful struct siginfo would be the same on both 32bit and 64bit, and in singalfd. As it is I am battling accidental redefinitions of SI_USER by the kernel to be something else.
I think it is far more likley that someone will define a signal layout that needs help going from 64bit to 32bit that my choice not copying all of the bits will catch, rather than I will break some existing userspace application. And if we catch it and the siginfo needs translation because we are not commited to copying everything we can fix it.
Which is a long way of saying I think it would be gravely irresponsible to just copy all of the bits of struct siginfo when si_code is negative.
Eric
cover siginfo infrastructure
In reply to Eric W. BiedermanThe following changes are available at:
git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git siginfo-testing
This updates the signal sending infrastructure to make it easier to get to the point where we are certain every struct siginfo we send to userspace is fully initialized and thus can be copied verbatim to userspace.
Today copy_siginfo_to_user performs a piecewise copy of siginfo to userspace because we don't know that all of the struct siginfo has been initialized.
Unfortunately do to bugs not even knowing the proper union member is enough to know that the fields we copy to userspace have all been initialized in every case.
The core idiom that needs to be used is:
struct siginfo si;
clear_siginfo(&si);
si.xxx = yyy;
...
force_sig_info(SIG_sss, &si, tsk);As the fields for the different union members all need to be initialized this patchset works to make this less error prone by introducing a series of helpers that take the needed fields and properly initialize siginfo before sending it deeper into the signal stack.
The helpers are:force_sig_faultforce_sig_mceerrforce_sig_bnderrforce_sig_pkuerrsend_sig_faultsend_sig_mceer
Today I count 227 calls of force_sig_info and send_sig_info in the kernel. After the helpers introduced here are used in the obvious places to use them the count shrinks to just 43. Something that is much more reasonable to maintain and to audit to ensure all of the details are just so.
This changeset does not include all of the architecture changes as that is still a large set of changes that needs to be reviewed carefully. I expect those to be post 4.17 material. While the infrastrcture can go in in 4.16.
In addition to the helpers a several general cleanups happen to help ensure that all instances of struct siginfo are intialized.
Eric W. Biederman (10):
ptrace: Use copy_siginfo in setsiginfo and getsiginfo signal/arm64: Better isolate the COMPAT_TASK portion of ptrace_hbptriggered
signal: Don't use structure initializers for struct siginfo
signal: Replace memset(info,...) with clear_siginfo for clarity
signal: Add send_sig_fault and force_sig_fault
signal: Helpers for faults with specialized siginfo layouts signal/powerpc: Remove unnecessary signal_code parameter of do_send_trap signal/ptrace: Add force_sig_ptrace_errno_trap and use it where needed mm/memory_failure: Remove unused trapno from memory_failure signal/memory-failure: Use force_sig_mceerr and send_sig_mceerr
arch/arc/kernel/traps.c | 14 ++- arch/arm/kernel/ptrace.c | 8 +- arch/arm64/kernel/debug-monitors.c | 13 ++- arch/arm64/kernel/ptrace.c | 42 +++---- arch/m68k/mm/fault.c | 3 +- arch/mips/kernel/traps.c | 29 +++-- arch/parisc/kernel/pdt.c | 2 +- arch/powerpc/include/asm/debug.h | 2 +- arch/powerpc/kernel/process.c | 13 +-- arch/powerpc/kernel/traps.c | 12 +- .../powerpc/platforms/powernv/opal-memory-errors.c | 2 +- arch/tile/kernel/single_step.c | 24 ++-- arch/tile/kernel/traps.c | 4 +- arch/tile/kernel/unaligned.c | 46 ++++---- arch/um/kernel/trap.c | 2 +- arch/x86/kernel/cpu/mcheck/mce.c | 6 +- arch/xtensa/kernel/ptrace.c | 8 +- drivers/acpi/apei/ghes.c | 2 +- drivers/base/memory.c | 2 +- drivers/ras/cec.c | 2 +- drivers/usb/core/devio.c | 4 +- include/linux/mm.h | 4 +- include/linux/sched/signal.h | 28 +++++ kernel/ptrace.c | 4 +- kernel/seccomp.c | 2 +- kernel/signal.c | 126 ++++++++++++++++++++- kernel/time/posix-timers.c | 2 +- mm/hwpoison-inject.c | 2 +- mm/madvise.c | 2 +- mm/memory-failure.c | 48 ++++---- 30 files changed, 305 insertions(+), 153 deletions(-)
Eric
PATCH 1/10 ptrace: Use copy_siginfo in setsiginfo and getsiginfo
Now that copy_siginfo copies all of the fields this is safe, safer (as all of the bits are guaranteed to be copied), clearer, and less error prone than using a structure copy.
--- kernel/ptrace.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/ptrace.c +2 -2
@@ -659,7 +659,7 @@ static int ptrace_getsiginfo(struct task_struct *child, siginfo_t *info)if (lock_task_sighand (child, &flags)) { error = -EINVAL ;if (likely (child->last_siginfo !=NULL )) { - *info = *child->last_siginfo; +copy_siginfo (info, child->last_siginfo); error =0 ; }unlock_task_sighand (child, &flags);
@@ -675,7 +675,7 @@ static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info)if (lock_task_sighand (child, &flags)) { error = -EINVAL ;if (likely (child->last_siginfo !=NULL )) { - *child->last_siginfo = *info; +copy_siginfo (child->last_siginfo, info); error =0 ; }unlock_task_sighand (child, &flags);
Signature · 1 line
2.14.1
PATCH 2/10 signal/arm64: Better isolate the COMPAT_TASK portion of ptrace_hbptriggered
In reply to Eric W. BiedermanInstead of jumpping while !is_compat_task placee all of the code inside of an if (is_compat_task) block. This allows the int i variable to be properly limited to the compat block no matter how the rest of ptrace_hbptriggered changes.
In a following change a non-variable declaration will preceed was made independent to ensure the code is easy to review.
--- arch/arm64/kernel/ptrace.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-)
arch/arm64/kernel/ptrace.c +12 -15
@@ -188,26 +188,23 @@ static void ptrace_hbptriggered(struct perf_event *bp, };#ifdef CONFIG_COMPAT -int i; - -if (!is_compat_task ()) - goto send_sig; +if (is_compat_task ()) { +int i; -for (i =0 ; i <ARM_MAX_BRP ; ++i) { -if (current->thread.debug.hbp_break[i] == bp) { - info.si_errno = (i <<1 ) +1 ; -break ; +for (i =0 ; i <ARM_MAX_BRP ; ++i) { +if (current->thread.debug.hbp_break[i] == bp) { + info.si_errno = (i <<1 ) +1 ; +break ; + } } - } -for (i =0 ; i <ARM_MAX_WRP ; ++i) { -if (current->thread.debug.hbp_watch[i] == bp) { - info.si_errno = -((i <<1 ) +1 ); -break ; +for (i =0 ; i <ARM_MAX_WRP ; ++i) { +if (current->thread.debug.hbp_watch[i] == bp) { + info.si_errno = -((i <<1 ) +1 ); +break ; + } } } - -send_sig:#endif force_sig_info (SIGTRAP , &info, current); }
Signature · 1 line
2.14.1
PATCH 3/10 signal: Don't use structure initializers for struct siginfo
In reply to Eric W. BiedermanThe siginfo structure has all manners of holes with the result that a structure initializer is not guaranteed to initialize all of the bits. As we have to copy the structure to userspace don't even try to use a structure initializer. Instead use clear_siginfo followed by initializing selected fields. This gives a guarantee that uninitialized kernel memory is not copied to userspace.
--- arch/arc/kernel/traps.c | 14 +++++++----- arch/arm64/kernel/debug-monitors.c | 13 ++++++----- arch/arm64/kernel/ptrace.c | 13 ++++++----- arch/m68k/mm/fault.c | 3 ++- arch/mips/kernel/traps.c | 29 ++++++++++++++++-------- arch/tile/kernel/single_step.c | 24 +++++++++++--------- arch/tile/kernel/traps.c | 4 +++- arch/tile/kernel/unaligned.c | 46 +++++++++++++++++++++----------------- kernel/signal.c | 3 ++- 9 files changed, 89 insertions(+), 60 deletions(-)
arch/arc/kernel/traps.c +8 -6
@@ -65,12 +65,14 @@ unhandled_exception(const char *str, struct pt_regs *regs, siginfo_t *info)#define DO_ERROR_INFO (signr, str, name, sicode) \ int name(unsigned long address, struct pt_regs *regs) \ { \ - siginfo_t info = { \ - .si_signo = signr, \ - .si_errno = 0, \ - .si_code = sicode, \ - .si_addr = (void __user *)address, \ - }; \ + siginfo_t info; \ + \ + clear_siginfo(&info); \ + info.si_signo = signr; \ + info.si_errno = 0; \ + info.si_code = sicode; \ + info.si_addr = (void __user *)address; \ + \ return unhandled_exception(str, regs, &info);\ }
arch/arm64/kernel/debug-monitors.c +7 -6
@@ -209,12 +209,13 @@ NOKPROBE_SYMBOL(call_step_hook);static void send_user_sigtrap (int si_code) {struct pt_regs *regs =current_pt_regs (); -siginfo_t info = { - .si_signo =SIGTRAP , - .si_errno =0 , - .si_code = si_code, - .si_addr = (void __user *)instruction_pointer (regs), - }; +siginfo_t info; + +clear_siginfo (&info); + info.si_signo =SIGTRAP ; + info.si_errno =0 ; + info.si_code = si_code; + info.si_addr = (void __user *)instruction_pointer (regs);if (WARN_ON (!user_mode (regs)))return ;
arch/arm64/kernel/ptrace.c +7 -6
@@ -180,12 +180,13 @@ static void ptrace_hbptriggered(struct perf_event *bp, struct pt_regs *regs) {struct arch_hw_breakpoint *bkpt =counter_arch_bp (bp); -siginfo_t info = { - .si_signo =SIGTRAP , - .si_errno =0 , - .si_code =TRAP_HWBKPT , - .si_addr = (void __user *)(bkpt->trigger), - }; +siginfo_t info; + +clear_siginfo (&info); + info.si_signo =SIGTRAP ; + info.si_errno =0 ; + info.si_code =TRAP_HWBKPT ; + info.si_addr = (void __user *)(bkpt->trigger);#ifdef CONFIG_COMPAT if (is_compat_task ()) {
arch/m68k/mm/fault.c +2 -1
@@ -21,8 +21,9 @@ extern void die_if_kernel(char *, struct pt_regs *, long);int send_fault_sig (struct pt_regs *regs) { -siginfo_t siginfo = {0 ,0 ,0 , }; +siginfo_t siginfo; +clear_siginfo (&siginfo); siginfo.si_signo = current->thread.signo; siginfo.si_code = current->thread.code; siginfo.si_addr = (void *)current->thread.faddr;
arch/mips/kernel/traps.c +20 -9
@@ -699,11 +699,12 @@ static int simulate_sync(struct pt_regs *regs, unsigned int opcode) asmlinkage void do_ov(struct pt_regs *regs) {enum ctx_state prev_state; -siginfo_t info = { - .si_signo =SIGFPE , - .si_code =FPE_INTOVF , - .si_addr = (void __user *)regs->cp0_epc, - }; +siginfo_t info; + +clear_siginfo (&info); + info.si_signo =SIGFPE ; + info.si_code =FPE_INTOVF ; + info.si_addr = (void __user *)regs->cp0_epc; prev_state =exception_enter ();die_if_kernel ("Integer overflow" , regs);
@@ -721,7 +722,11 @@ asmlinkage void do_ov(struct pt_regs *regs)void force_fcr31_sig (unsigned long fcr31,void __user *fault_addr,struct task_struct *tsk) { -struct siginfo si = { .si_addr = fault_addr, .si_signo =SIGFPE }; +struct siginfo si; + +clear_siginfo (&si); + si.si_addr = fault_addr; + si.si_signo =SIGFPE ;if (fcr31 &FPU_CSR_INV_X ) si.si_code =FPE_FLTINV ;
@@ -739,9 +744,10 @@ void force_fcr31_sig(unsigned long fcr31, void __user *fault_addr,int process_fpemu_return (int sig,void __user *fault_addr,unsigned long fcr31) { -struct siginfo si = {0 }; +struct siginfo si;struct vm_area_struct *vma; +clear_siginfo (&si);switch (sig) {case 0 :return 0 ;
@@ -890,9 +896,10 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)void do_trap_or_bp (struct pt_regs *regs,unsigned int code,int si_code,const char *str) { -siginfo_t info = {0 }; +siginfo_t info;char b[40 ]; +clear_siginfo (&info);#ifdef CONFIG_KGDB_LOW_LEVEL_TRAP if (kgdb_ll_trap (DIE_TRAP , str, regs, code, current->thread.trap_nr,SIGTRAP ) ==NOTIFY_STOP )
@@ -1499,9 +1506,13 @@ asmlinkage void do_mdmx(struct pt_regs *regs)*/ asmlinkage void do_watch(struct pt_regs *regs) { -siginfo_t info = { .si_signo =SIGTRAP , .si_code =TRAP_HWBKPT }; +siginfo_t info;enum ctx_state prev_state; +clear_siginfo (&info); + info.si_signo =SIGTRAP ; + info.si_code =TRAP_HWBKPT ; + prev_state =exception_enter ();/* * Clear WP (bit 22) bit of cause register so we don't loop
arch/tile/kernel/single_step.c +14 -10
@@ -163,11 +163,13 @@ static tilepro_bundle_bits rewrite_load_store_unaligned(* actual bad address in an SPR, which it doesn't. */ if (align_ctl ==0 ) { -siginfo_t info = { - .si_signo =SIGBUS , - .si_code =BUS_ADRALN , - .si_addr = addr - }; +siginfo_t info; + +clear_siginfo (&info); + info.si_signo =SIGBUS ; + info.si_code =BUS_ADRALN ; + info.si_addr = addr; +trace_unhandled_signal ("unaligned trap" , regs, (unsigned long )addr,SIGBUS );force_sig_info (info.si_signo, &info, current);
@@ -210,11 +212,13 @@ static tilepro_bundle_bits rewrite_load_store_unaligned( }if (err) { -siginfo_t info = { - .si_signo =SIGBUS , - .si_code =BUS_ADRALN , - .si_addr = addr - }; +siginfo_t info; + +clear_siginfo (&info); + info.si_signo =SIGBUS ; + info.si_code =BUS_ADRALN ; + info.si_addr = addr; +trace_unhandled_signal ("bad address for unaligned fixup" , regs, (unsigned long )addr,SIGBUS );force_sig_info (info.si_signo, &info, current);
arch/tile/kernel/traps.c +3 -1
@@ -256,12 +256,14 @@ static int do_bpt(struct pt_regs *regs)void __kprobes do_trap (struct pt_regs *regs,int fault_num,unsigned long reason) { -siginfo_t info = {0 }; +siginfo_t info;int signo, code;unsigned long address =0 ;tile_bundle_bits instr;int is_kernel = !user_mode (regs); +clear_siginfo (&info); +/* Handle breakpoints, etc. */ if (is_kernel && fault_num ==INT_ILL &&do_bpt (regs))return ;
arch/tile/kernel/unaligned.c +26 -20
70 lines not on this page · raw message
kernel/signal.c +2 -1
@@ -3163,8 +3163,9 @@ do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info)static int do_tkill (pid_t tgid,pid_t pid,int sig) { -struct siginfo info = {}; +struct siginfo info; +clear_siginfo (&info); info.si_signo = sig; info.si_errno =0 ; info.si_code =SI_TKILL ;
Signature · 1 line
2.14.1
PATCH 4/10 signal: Replace memset(info,...) with clear_siginfo for clarity
In reply to Eric W. BiedermanThe function clear_siginfo is just a nice wrapper around memset so this results in no functional change. This change makes mistakes a little more difficult and it makes it clearer what is going on.
--- arch/um/kernel/trap.c | 2 +- drivers/usb/core/devio.c | 4 ++-- kernel/seccomp.c | 2 +- kernel/time/posix-timers.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-)
arch/um/kernel/trap.c +1 -1
@@ -306,7 +306,7 @@ void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs)arch_examine_signal (sig, regs); -memset (&clean_si,0 ,sizeof (clean_si)); +clear_siginfo (&clean_si); clean_si.si_signo = si->si_signo; clean_si.si_errno = si->si_errno; clean_si.si_code = si->si_code;
drivers/usb/core/devio.c +2 -2
@@ -595,7 +595,7 @@ static void async_completed(struct urb *urb) as->status = urb->status; signr = as->signr;if (signr) { -memset (&sinfo,0 ,sizeof (sinfo)); +clear_siginfo (&sinfo); sinfo.si_signo = as->signr; sinfo.si_errno = as->status; sinfo.si_code =SI_ASYNCIO ;
@@ -2613,7 +2613,7 @@ static void usbdev_remove(struct usb_device *udev)wake_up_all (&ps->wait);list_del_init (&ps->list);if (ps->discsignr) { -memset (&sinfo,0 ,sizeof (sinfo)); +clear_siginfo (&sinfo); sinfo.si_signo = ps->discsignr; sinfo.si_errno =EPIPE ; sinfo.si_code =SI_ASYNCIO ;
kernel/seccomp.c +1 -1
@@ -515,7 +515,7 @@ void put_seccomp_filter(struct task_struct *tsk)static void seccomp_init_siginfo (siginfo_t *info,int syscall,int reason) { -memset (info,0 ,sizeof (*info)); +clear_siginfo (info); info->si_signo =SIGSYS ; info->si_code =SYS_SECCOMP ; info->si_call_addr = (void __user *)KSTK_EIP (current);
kernel/time/posix-timers.c +1 -1
@@ -462,7 +462,7 @@ static struct k_itimer * alloc_posix_timer(void)kmem_cache_free (posix_timers_cache, tmr);return NULL ; } -memset (&tmr->sigq->info,0 ,sizeof (siginfo_t)); +clear_siginfo (&tmr->sigq->info);return tmr; }
Signature · 1 line
2.14.1
PATCH 5/10 signal: Add send_sig_fault and force_sig_fault
In reply to Eric W. BiedermanThe vast majority of signals sent from architecture specific code are simple faults. Encapsulate this reality with two helper functions so that the nit-picky implementation of preparing a siginfo does not need to be repeated many times on each architecture.
As only some architectures support the trapno field, make the trapno arguement only present on those architectures.
Similary as ia64 has three fields: imm, flags, and isr that are specific to it. Have those arguments always present on ia64 and no where else.
This ensures the architecture specific code always remembers which fields it needs to pass into the siginfo structure.
--- include/linux/sched/signal.h | 20 +++++++++++++++++++ kernel/signal.c | 47 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+)
include/linux/sched/signal.h +20 -0
@@ -285,6 +285,26 @@ static inline void kernel_signal_stop(void)schedule (); } +#ifdef __ARCH_SI_TRAPNO +# define ___ARCH_SI_TRAPNO (_a1) , _a1 +#else +# define ___ARCH_SI_TRAPNO (_a1) +#endif +#ifdef __ia64__ +# define ___ARCH_SI_IA64 (_a1, _a2, _a3) , _a1, _a2, _a3 +#else +# define ___ARCH_SI_IA64 (_a1, _a2, _a3) +#endif + +int force_sig_fault(int sig, int code, void __user *addr +___ARCH_SI_TRAPNO (int trapno) + ___ARCH_SI_IA64(int imm, unsigned int flags, unsigned long isr) + , struct task_struct *t); +int send_sig_fault(int sig, int code, void __user *addr +___ARCH_SI_TRAPNO (int trapno) + ___ARCH_SI_IA64(int imm, unsigned int flags, unsigned long isr) + , struct task_struct *t); +extern int send_sig_info (int ,struct siginfo *,struct task_struct *);extern int force_sigsegv (int ,struct task_struct *);extern int force_sig_info (int ,struct siginfo *,struct task_struct *);
kernel/signal.c +47 -0
53 lines not on this page · raw message
Signature · 1 line
2.14.1
PATCH 6/10 signal: Helpers for faults with specialized siginfo layouts
In reply to Eric W. BiedermanThe helpers added are:send_sig_mceerrforce_sig_mceerrforce_sig_bnderrforce_sig_pkuerr
Filling out siginfo properly can ge tricky. Especially for these specialized cases where the temptation is to share code with other cases which use a different subset of siginfo fields. Unfortunately that code sharing frequently results in bugs with the wrong siginfo fields filled in, and makes it harder to verify that the siginfo structure was properly initialized.
Provide these helpers instead that get all of the details right, and guarantee that siginfo is properly initialized.
send_sig_mceerr and force_sig_mceer are a little special as two si codes BUS_MCEERR_AO and BUS_MCEER_AR both use the same extended signinfo layout.
--- include/linux/sched/signal.h | 6 +++++ kernel/signal.c | 61 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+)
include/linux/sched/signal.h +6 -0
@@ -305,6 +305,12 @@ int send_sig_fault(int sig, int code, void __user *addr ___ARCH_SI_IA64(int imm, unsigned int flags, unsigned long isr) , struct task_struct *t); +int force_sig_mceerr (int code,void __user *,short ,struct task_struct *); +int send_sig_mceerr (int code,void __user *,short ,struct task_struct *); + +int force_sig_bnderr (void __user *addr,void __user *lower,void __user *upper); +int force_sig_pkuerr (void __user *addr,u32 pkey); +extern int send_sig_info (int ,struct siginfo *,struct task_struct *);extern int force_sigsegv (int ,struct task_struct *);extern int force_sig_info (int ,struct siginfo *,struct task_struct *);
kernel/signal.c +61 -0
67 lines not on this page · raw message
Signature · 1 line
2.14.1
Re: [PATCH 06/10] signal: Helpers for faults with specialized siginfo layouts
Quoted 13 lines · Eric W. Biederman
The helpers added are:
send_sig_mceerrforce_sig_mceerrforce_sig_bnderrforce_sig_pkuerrFilling out siginfo properly can ge tricky. Especially for these specialized cases where the temptation is to share code with other cases which use a different subset of siginfo fields. Unfortunately that code sharing frequently results in bugs with the wrong siginfo fields filled in, and makes it harder to verify that the siginfo structure was properly initialized.
Quoted 6 lines
Provide these helpers instead that get all of the details right, and guarantee that siginfo is properly initialized.
send_sig_mceerrandforce_sig_mceerare a little special as two si codesBUS_MCEERR_AOandBUS_MCEER_ARboth use the same extended signinfo layout.
nice. i can make use of these helpers in the memory-key implementation.
One small nit-pick below though...
Quoted 8 lines
Signed-off-by "Eric W. Biederman" <[email protected]>--- include/linux/sched/signal.h | 6 +++++ kernel/signal.c | 61 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+)include/linux/sched/signal.h +0
-0
...snip..
include/linux/sched/signal.h
Quoted 2 lines
include/linux/sched/signal.h +2
-0+ +#ifdef SEGV_PKUERR
Should this really be under SEGV_PKUERR ? that macro is defined unconditionally anyway.
Quoted 13 lines
include/linux/sched/signal.h +13
-0+int force_sig_pkuerr (void __user *addr,u32 pkey) +{ +struct siginfo info; + +clear_siginfo (&info); + info.si_signo =SIGSEGV ; + info.si_errno =0 ; + info.si_code =SEGV_PKUERR ; + info.si_addr = addr; + info.si_pkey = pkey; +return force_sig_info (info.si_signo, &info, current); +} +#endif
Re: [PATCH 06/10] signal: Helpers for faults with specialized siginfo layouts
Quoted 36 lines · Ram Pai
Quoted 13 lines · Eric W. Biederman
The helpers added are:
send_sig_mceerrforce_sig_mceerrforce_sig_bnderrforce_sig_pkuerrFilling out siginfo properly can ge tricky. Especially for these specialized cases where the temptation is to share code with other cases which use a different subset of siginfo fields. Unfortunately that code sharing frequently results in bugs with the wrong siginfo fields filled in, and makes it harder to verify that the siginfo structure was properly initialized.
Quoted 6 lines
Provide these helpers instead that get all of the details right, and guarantee that siginfo is properly initialized.
send_sig_mceerrandforce_sig_mceerare a little special as two si codesBUS_MCEERR_AOandBUS_MCEER_ARboth use the same extended signinfo layout.nice. i can make use of these helpers in the memory-key implementation.
One small nit-pick below though...
Quoted 8 lines
Signed-off-by "Eric W. Biederman" <[email protected]>--- include/linux/sched/signal.h | 6 +++++ kernel/signal.c | 61 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+)include/linux/sched/signal.h +0
-0...snip..
Quoted 5 lines
include/linux/sched/signal.h
Quoted 2 lines
include/linux/sched/signal.h +2
-0+ +#ifdef SEGV_PKUERR Should this really be under
SEGV_PKUERR? that macro is defined unconditionally anyway.
Unless you are running my unified siginfo.h (from an earlier patchset which I build upon). It turns out that ia64 has a conflict for that number. So ia64 really can't use the define and this infrastructure.
We might decide to sort that out and always have SEGV_PKUERR always defined. Sadly for the moment the #ifdef is necessary.
Quoted 5 lines
Quoted 5 lines
include/linux/sched/signal.h +5
-0+int force_sig_pkuerr (void __user *addr,u32 pkey) +{ +struct siginfo info; + +clear_siginfo (&info);
Quoted 8 lines
include/linux/sched/signal.h
Quoted 8 lines
include/linux/sched/signal.h +8
-0+ info.si_signo =SIGSEGV ; + info.si_errno =0 ; + info.si_code =SEGV_PKUERR ; + info.si_addr = addr; + info.si_pkey = pkey; + return force_sig_info(info.si_signo, &info, current); +} +#endif
Eric
PATCH 7/10 signal/powerpc: Remove unnecessary signal_code parameter of do_send_trap
In reply to Eric W. Biedermansignal_code is always TRAP_HWBKPT
--- arch/powerpc/include/asm/debug.h | 2 +- arch/powerpc/kernel/process.c | 6 +++--- arch/powerpc/kernel/traps.c | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-)
arch/powerpc/include/asm/debug.h +1 -1
@@ -49,7 +49,7 @@ void set_breakpoint(struct arch_hw_breakpoint *brk);void __set_breakpoint (struct arch_hw_breakpoint *brk);#ifdef CONFIG_PPC_ADV_DEBUG_REGS extern void do_send_trap (struct pt_regs *regs,unsigned long address, -unsigned long error_code,int signal_code,int brkpt); +unsigned long error_code,int brkpt);#else extern void do_break(struct pt_regs *regs, unsigned long address,
arch/powerpc/kernel/process.c +3 -3
@@ -601,11 +601,11 @@ EXPORT_SYMBOL(flush_all_to_thread);#ifdef CONFIG_PPC_ADV_DEBUG_REGS void do_send_trap (struct pt_regs *regs,unsigned long address, -unsigned long error_code,int signal_code,int breakpt) +unsigned long error_code,int breakpt) {siginfo_t info; - current->thread.trap_nr = signal_code; + current->thread.trap_nr =TRAP_HWBKPT ;if (notify_die (DIE_DABR_MATCH ,"dabr_match" , regs, error_code,11 ,SIGSEGV ) ==NOTIFY_STOP )return ;
@@ -613,7 +613,7 @@ void do_send_trap(struct pt_regs *regs, unsigned long address,/* Deliver the signal to userspace */ info.si_signo =SIGTRAP ; info.si_errno = breakpt;/* breakpoint or watchpoint id */ - info.si_code = signal_code; + info.si_code =TRAP_HWBKPT ; info.si_addr = (void __user *)address;force_sig_info (SIGTRAP , &info, current); }
arch/powerpc/kernel/traps.c +6 -6
@@ -1750,34 +1750,34 @@ static void handle_debug(struct pt_regs *regs, unsigned long debug_status)#ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE current->thread.debug.dbcr2 &= ~DBCR2_DAC12MODE ;#endif -do_send_trap (regs,mfspr (SPRN_DAC1 ), debug_status,TRAP_HWBKPT , +do_send_trap (regs,mfspr (SPRN_DAC1 ), debug_status,5 ); changed |=0x01 ; }else if (debug_status & (DBSR_DAC2R |DBSR_DAC2W )) {dbcr_dac (current) &= ~(DBCR_DAC2R |DBCR_DAC2W ); -do_send_trap (regs,mfspr (SPRN_DAC2 ), debug_status,TRAP_HWBKPT , +do_send_trap (regs,mfspr (SPRN_DAC2 ), debug_status,6 ); changed |=0x01 ; }else if (debug_status &DBSR_IAC1 ) { current->thread.debug.dbcr0 &= ~DBCR0_IAC1 ;dbcr_iac_range (current) &= ~DBCR_IAC12MODE ; -do_send_trap (regs,mfspr (SPRN_IAC1 ), debug_status,TRAP_HWBKPT , +do_send_trap (regs,mfspr (SPRN_IAC1 ), debug_status,1 ); changed |=0x01 ; }else if (debug_status &DBSR_IAC2 ) { current->thread.debug.dbcr0 &= ~DBCR0_IAC2 ; -do_send_trap (regs,mfspr (SPRN_IAC2 ), debug_status,TRAP_HWBKPT , +do_send_trap (regs,mfspr (SPRN_IAC2 ), debug_status,2 ); changed |=0x01 ; }else if (debug_status &DBSR_IAC3 ) { current->thread.debug.dbcr0 &= ~DBCR0_IAC3 ;dbcr_iac_range (current) &= ~DBCR_IAC34MODE ; -do_send_trap (regs,mfspr (SPRN_IAC3 ), debug_status,TRAP_HWBKPT , +do_send_trap (regs,mfspr (SPRN_IAC3 ), debug_status,3 ); changed |=0x01 ; }else if (debug_status &DBSR_IAC4 ) { current->thread.debug.dbcr0 &= ~DBCR0_IAC4 ; -do_send_trap (regs,mfspr (SPRN_IAC4 ), debug_status,TRAP_HWBKPT , +do_send_trap (regs,mfspr (SPRN_IAC4 ), debug_status,4 ); changed |=0x01 ; }
Signature · 1 line
2.14.1
PATCH 8/10 signal/ptrace: Add force_sig_ptrace_errno_trap and use it where needed
In reply to Eric W. BiedermanThere are so many places that build struct siginfo by hand that at least one of them is bound to get it wrong. A handful of cases in the kernel arguably did just that when using the errno field of siginfo to pass no errno values to userspace. The usage is limited to a single si_code so at least does not mess up anything else.
Encapsulate this questionable pattern in a helper function so that the userspace ABI is preserved.
Update all of the places that use this pattern to use the new helper function.
--- arch/arm/kernel/ptrace.c | 8 +------- arch/arm64/kernel/ptrace.c | 6 ++++-- arch/powerpc/kernel/process.c | 9 ++------- arch/xtensa/kernel/ptrace.c | 8 +------- include/linux/sched/signal.h | 2 ++ kernel/signal.c | 15 +++++++++++++++ 6 files changed, 25 insertions(+), 23 deletions(-)
arch/arm/kernel/ptrace.c +1 -7
@@ -390,7 +390,6 @@ static void ptrace_hbptriggered(struct perf_event *bp,struct arch_hw_breakpoint *bkpt =counter_arch_bp (bp);long num;int i; -siginfo_t info;for (i =0 ; i <ARM_MAX_HBP_SLOTS ; ++i)if (current->thread.debug.hbp[i] == bp)
@@ -398,12 +397,7 @@ static void ptrace_hbptriggered(struct perf_event *bp, num = (i ==ARM_MAX_HBP_SLOTS ) ?0 :ptrace_hbp_idx_to_num (i); - info.si_signo =SIGTRAP ; - info.si_errno = (int )num; - info.si_code =TRAP_HWBKPT ; - info.si_addr = (void __user *)(bkpt->trigger); - -force_sig_info (SIGTRAP , &info, current); +force_sig_ptrace_errno_trap ((int )num, (void __user *)(bkpt->trigger)); }/*
arch/arm64/kernel/ptrace.c +4 -2
@@ -190,21 +190,23 @@ static void ptrace_hbptriggered(struct perf_event *bp,#ifdef CONFIG_COMPAT if (is_compat_task ()) { +int si_errno =0 ;int i;for (i =0 ; i <ARM_MAX_BRP ; ++i) {if (current->thread.debug.hbp_break[i] == bp) { - info.si_errno = (i <<1 ) +1 ; + si_errno = (i <<1 ) +1 ;break ; } }for (i =0 ; i <ARM_MAX_WRP ; ++i) {if (current->thread.debug.hbp_watch[i] == bp) { - info.si_errno = -((i <<1 ) +1 ); + si_errno = -((i <<1 ) +1 );break ; } } +force_sig_ptrace_errno_trap (si_errno, (void __user *)bkpt->trigger); }#endif force_sig_info (SIGTRAP , &info, current);
arch/powerpc/kernel/process.c +2 -7
@@ -603,19 +603,14 @@ EXPORT_SYMBOL(flush_all_to_thread);void do_send_trap (struct pt_regs *regs,unsigned long address,unsigned long error_code,int breakpt) { -siginfo_t info; - current->thread.trap_nr =TRAP_HWBKPT ;if (notify_die (DIE_DABR_MATCH ,"dabr_match" , regs, error_code,11 ,SIGSEGV ) ==NOTIFY_STOP )return ;/* Deliver the signal to userspace */ - info.si_signo =SIGTRAP ; - info.si_errno = breakpt;/* breakpoint or watchpoint id */ - info.si_code =TRAP_HWBKPT ; - info.si_addr = (void __user *)address; -force_sig_info (SIGTRAP , &info, current); +force_sig_ptrace_errno_trap (breakpt,/* breakpoint or watchpoint id */ + (void __user *)address); }#else /* !CONFIG_PPC_ADV_DEBUG_REGS */ void do_break (struct pt_regs *regs, unsigned long address,
arch/xtensa/kernel/ptrace.c +1 -7
@@ -278,7 +278,6 @@ static void ptrace_hbptriggered(struct perf_event *bp, struct pt_regs *regs) {int i; -siginfo_t info;struct arch_hw_breakpoint *bkpt =counter_arch_bp (bp);if (bp->attr.bp_type &HW_BREAKPOINT_X ) {
@@ -293,12 +292,7 @@ static void ptrace_hbptriggered(struct perf_event *bp, i = (i <<1 ) |1 ; } - info.si_signo =SIGTRAP ; - info.si_errno = i; - info.si_code =TRAP_HWBKPT ; - info.si_addr = (void __user *)bkpt->address; - -force_sig_info (SIGTRAP , &info, current); +force_sig_ptrace_errno_trap (i, (void __user *)bkpt->address); }static struct perf_event *ptrace_hbp_create (struct task_struct *tsk,int type)
include/linux/sched/signal.h +2 -0
@@ -311,6 +311,8 @@ int send_sig_mceerr(int code, void __user *, short, struct task_struct *);int force_sig_bnderr (void __user *addr,void __user *lower,void __user *upper);int force_sig_pkuerr (void __user *addr,u32 pkey); +int force_sig_ptrace_errno_trap (int errno,void __user *addr); +extern int send_sig_info (int ,struct siginfo *,struct task_struct *);extern int force_sigsegv (int ,struct task_struct *);extern int force_sig_info (int ,struct siginfo *,struct task_struct *);
kernel/signal.c +15 -0
@@ -1599,6 +1599,21 @@ int force_sig_pkuerr(void __user *addr, u32 pkey) }#endif +/* For the crazy architectures that include trap information in +* the errno field, instead of an actual errno value. +*/ +int force_sig_ptrace_errno_trap (int errno,void __user *addr) +{ +struct siginfo info; + +clear_siginfo (&info); + info.si_signo =SIGTRAP ; + info.si_errno = errno; + info.si_code =TRAP_HWBKPT ; + info.si_addr = addr; +return force_sig_info (info.si_signo, &info, current); +} +int kill_pgrp (struct pid *pid,int sig,int priv) {int ret;
Signature · 1 line
2.14.1
PATCH 9/10 mm/memory_failure: Remove unused trapno from memory_failure
In reply to Eric W. BiedermanToday 4 architectures set ARCH_SUPPORTS_MEMORY_FAILURE (arm64, parisc, powerpc, and x86), while 4 other architectures set __ARCH_SI_TRAPNO (alpha, metag, sparc, and tile). These two sets of architectures do not interesect so remove the trapno paramater to remove confusion.
--- arch/parisc/kernel/pdt.c | 2 +- .../powerpc/platforms/powernv/opal-memory-errors.c | 2 +- arch/x86/kernel/cpu/mcheck/mce.c | 6 ++-- drivers/acpi/apei/ghes.c | 2 +- drivers/base/memory.c | 2 +- drivers/ras/cec.c | 2 +- include/linux/mm.h | 4 +-- mm/hwpoison-inject.c | 2 +- mm/madvise.c | 2 +- mm/memory-failure.c | 33 +++++++++------------- 10 files changed, 25 insertions(+), 32 deletions(-)
arch/parisc/kernel/pdt.c +1 -1
@@ -325,7 +325,7 @@ static int pdt_mainloop(void *unused)#ifdef CONFIG_MEMORY_FAILURE if ((pde &PDT_ADDR_PERM_ERR ) || ((pde &PDT_ADDR_SINGLE_ERR ) ==0 )) -memory_failure (pde >>PAGE_SHIFT ,0 ,0 ); +memory_failure (pde >>PAGE_SHIFT ,0 );else soft_offline_page (pfn_to_page (pde >>PAGE_SHIFT ),0 );
arch/powerpc/platforms/powernv/opal-memory-errors.c +1 -1
@@ -60,7 +60,7 @@ static void handle_memory_error_event(struct OpalMemoryErrorData *merr_evt) }for (; paddr_start < paddr_end; paddr_start +=PAGE_SIZE ) { -memory_failure (paddr_start >>PAGE_SHIFT ,0 ,0 ); +memory_failure (paddr_start >>PAGE_SHIFT ,0 ); } }
arch/x86/kernel/cpu/mcheck/mce.c +3 -3
@@ -582,7 +582,7 @@ static int srao_decode_notifier(struct notifier_block *nb, unsigned long val,if (mce_usable_address (mce) && (mce->severity ==MCE_AO_SEVERITY )) { pfn = mce->addr >>PAGE_SHIFT ; -memory_failure (pfn,MCE_VECTOR ,0 ); +memory_failure (pfn,0 ); }return NOTIFY_OK ;
@@ -1046,7 +1046,7 @@ static int do_memory_failure(struct mce *m)pr_err ("Uncorrected hardware memory error in user-access at %llx" , m->addr);if (!(m->mcgstatus &MCG_STATUS_RIPV )) flags |=MF_MUST_KILL ; - ret =memory_failure (m->addr >>PAGE_SHIFT ,MCE_VECTOR , flags); + ret =memory_failure (m->addr >>PAGE_SHIFT , flags);if (ret)pr_err ("Memory error not recovered" );return ret;
@@ -1325,7 +1325,7 @@ void do_machine_check(struct pt_regs *regs, long error_code)EXPORT_SYMBOL_GPL (do_machine_check);#ifndef CONFIG_MEMORY_FAILURE -int memory_failure (unsigned long pfn,int vector,int flags) +int memory_failure (unsigned long pfn,int flags) {/* mce_severity() should not hand us an ACTION_REQUIRED error */ BUG_ON (flags &MF_ACTION_REQUIRED );
drivers/acpi/apei/ghes.c +1 -1
@@ -410,7 +410,7 @@ static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int flags =0 ;if (flags !=-1 ) -memory_failure_queue (pfn,0 , flags); +memory_failure_queue (pfn, flags);#endif }
drivers/base/memory.c +1 -1
@@ -569,7 +569,7 @@ store_hard_offline_page(struct device *dev,if (kstrtoull (buf,0 , &pfn) <0 )return -EINVAL ; pfn >>=PAGE_SHIFT ; - ret =memory_failure (pfn,0 ,0 ); + ret =memory_failure (pfn,0 );return ret ? ret : count; }
drivers/ras/cec.c +1 -1
@@ -327,7 +327,7 @@ int cec_add_elem(u64 pfn) }else {/* We have reached max count for this page, soft-offline it. */ pr_err ("Soft-offlining pfn: 0x%llx\n" , pfn); -memory_failure_queue (pfn,0 ,MF_SOFT_OFFLINE ); +memory_failure_queue (pfn,MF_SOFT_OFFLINE ); ca->pfns_poisoned++; }
include/linux/mm.h +2 -2
@@ -2570,8 +2570,8 @@ enum mf_flags {MF_MUST_KILL =1 <<2 , MF_SOFT_OFFLINE = 1 << 3, }; -extern int memory_failure (unsigned long pfn,int trapno,int flags); -extern void memory_failure_queue (unsigned long pfn,int trapno,int flags); +extern int memory_failure (unsigned long pfn,int flags); +extern void memory_failure_queue (unsigned long pfn,int flags);extern int unpoison_memory (unsigned long pfn);extern int get_hwpoison_page (struct page *page);#define put_hwpoison_page (page) put_page(page)
mm/hwpoison-inject.c +1 -1
@@ -52,7 +52,7 @@ static int hwpoison_inject(void *data, u64 val) inject:pr_info ("Injecting memory failure at pfn %#lx\n" , pfn); -return memory_failure (pfn,18 ,MF_COUNT_INCREASED ); +return memory_failure (pfn,MF_COUNT_INCREASED ); put_out:put_hwpoison_page (p);return 0 ;
mm/madvise.c +1 -1
@@ -661,7 +661,7 @@ static int madvise_inject_error(int behavior,pr_info ("Injecting memory failure for pfn %#lx at process virtual address %#lx\n" ,page_to_pfn (page), start); - ret =memory_failure (page_to_pfn (page),0 ,MF_COUNT_INCREASED ); + ret =memory_failure (page_to_pfn (page),MF_COUNT_INCREASED );if (ret)return ret; }
mm/memory-failure.c +13 -20
@@ -178,7 +178,7 @@ EXPORT_SYMBOL_GPL(hwpoison_filter);* ``action optional'' if they are not immediately affected by the error * ``action required'' if error happened in current execution context */ -static int kill_proc (struct task_struct *t,unsigned long addr,int trapno, +static int kill_proc (struct task_struct *t,unsigned long addr,unsigned long pfn,struct page *page,int flags) {struct siginfo si;
@@ -189,9 +189,6 @@ static int kill_proc(struct task_struct *t, unsigned long addr, int trapno, si.si_signo =SIGBUS ; si.si_errno =0 ; si.si_addr = (void *)addr; -#ifdef __ARCH_SI_TRAPNO - si.si_trapno = trapno; -#endif si.si_addr_lsb =compound_order (compound_head (page)) +PAGE_SHIFT ;if ((flags &MF_ACTION_REQUIRED ) && t->mm == current->mm) {
@@ -323,7 +320,7 @@ static void add_to_kill(struct task_struct *tsk, struct page *p,* Also when FAIL is set do a force kill because something went * wrong earlier. */ -static void kill_procs (struct list_head *to_kill,int forcekill,int trapno, +static void kill_procs (struct list_head *to_kill,int forcekill,bool fail,struct page *page,unsigned long pfn,int flags) {
@@ -348,7 +345,7 @@ static void kill_procs(struct list_head *to_kill, int forcekill, int trapno,* check for that, but we need to tell the * process anyways. */ - else if (kill_proc(tk->tsk, tk->addr, trapno, + else if (kill_proc(tk->tsk, tk->addr, pfn, page, flags) < 0) pr_err("Memory failure: %#lx: Cannot send advisory machine check signal to %s:%d\n", pfn, tk->tsk->comm, tk->tsk->pid);
@@ -927,7 +924,7 @@ EXPORT_SYMBOL_GPL(get_hwpoison_page);* the pages and send SIGBUS to the processes if the data was dirty. */ static bool hwpoison_user_mappings (struct page *p,unsigned long pfn, -int trapno,int flags,struct page **hpagep) +int flags,struct page **hpagep) {enum ttu_flags ttu =TTU_IGNORE_MLOCK |TTU_IGNORE_ACCESS ;struct address_space *mapping;
@@ -1017,7 +1014,7 @@ static bool hwpoison_user_mappings(struct page *p, unsigned long pfn,* any accesses to the poisoned memory. */ forcekill =PageDirty (hpage) || (flags &MF_MUST_KILL ); -kill_procs (&tokill, forcekill, trapno, !unmap_success, p, pfn, flags); +kill_procs (&tokill, forcekill, !unmap_success, p, pfn, flags);return unmap_success; }
@@ -1045,7 +1042,7 @@ static int identify_page_state(unsigned long pfn, struct page *p,return page_action (ps, p, pfn); } -static int memory_failure_hugetlb (unsigned long pfn,int trapno,int flags) +static int memory_failure_hugetlb (unsigned long pfn,int flags) {struct page *p =pfn_to_page (pfn);struct page *head =compound_head (p);
@@ -1090,7 +1087,7 @@ static int memory_failure_hugetlb(unsigned long pfn, int trapno, int flags)return 0 ; } -if (!hwpoison_user_mappings (p, pfn, trapno, flags, &head)) { +if (!hwpoison_user_mappings (p, pfn, flags, &head)) {action_result (pfn,MF_MSG_UNMAP_FAILED ,MF_IGNORED ); res = -EBUSY ; goto out;
@@ -1105,7 +1102,6 @@ static int memory_failure_hugetlb(unsigned long pfn, int trapno, int flags)/** * memory_failure - Handle memory failure of a page. * @pfn: Page Number of the corrupted page -* @trapno: Trap number reported in the signal to user space. * @flags: fine tune action taken * * This function is called by the low level machine check code
@@ -1120,7 +1116,7 @@ static int memory_failure_hugetlb(unsigned long pfn, int trapno, int flags)* Must run in process context (e.g. a work queue) with interrupts * enabled and no spinlocks hold. */ -int memory_failure (unsigned long pfn,int trapno,int flags) +int memory_failure (unsigned long pfn,int flags) {struct page *p;struct page *hpage;
@@ -1129,7 +1125,7 @@ int memory_failure(unsigned long pfn, int trapno, int flags)unsigned long page_flags;if (!sysctl_memory_failure_recovery) -panic ("Memory failure from trap %d on page %lx" , trapno, pfn); +panic ("Memory failure on page %lx" , pfn);if (!pfn_valid (pfn)) { pr_err("Memory failure: %#lx: memory outside kernel control\n",
@@ -1139,7 +1135,7 @@ int memory_failure(unsigned long pfn, int trapno, int flags) p =pfn_to_page (pfn);if (PageHuge (p)) -return memory_failure_hugetlb (pfn, trapno, flags); +return memory_failure_hugetlb (pfn, flags);if (TestSetPageHWPoison (p)) {pr_err ("Memory failure: %#lx: already hardware poisoned\n" , pfn);
@@ -1268,7 +1264,7 @@ int memory_failure(unsigned long pfn, int trapno, int flags)* When the raw error page is thp tail page, hpage points to the raw * page after thp split. */ -if (!hwpoison_user_mappings (p, pfn, trapno, flags, &hpage)) { +if (!hwpoison_user_mappings (p, pfn, flags, &hpage)) {action_result (pfn,MF_MSG_UNMAP_FAILED ,MF_IGNORED ); res = -EBUSY ; goto out;
@@ -1296,7 +1292,6 @@ EXPORT_SYMBOL_GPL(memory_failure);struct memory_failure_entry {unsigned long pfn; -int trapno;int flags; };
@@ -1312,7 +1307,6 @@ static DEFINE_PER_CPU(struct memory_failure_cpu, memory_failure_cpu);/** * memory_failure_queue - Schedule handling memory failure of a page. * @pfn: Page Number of the corrupted page -* @trapno: Trap number reported in the signal to user space. * @flags: Flags for memory failure handling * * This function is called by the low level hardware error handler
@@ -1326,13 +1320,12 @@ static DEFINE_PER_CPU(struct memory_failure_cpu, memory_failure_cpu);* * Can run in IRQ context. */ -void memory_failure_queue (unsigned long pfn,int trapno,int flags) +void memory_failure_queue (unsigned long pfn,int flags) {struct memory_failure_cpu *mf_cpu;unsigned long proc_flags;struct memory_failure_entry entry = { .pfn = pfn, - .trapno = trapno, .flags = flags, };
@@ -1365,7 +1358,7 @@ static void memory_failure_work_func(struct work_struct *work)if (entry.flags &MF_SOFT_OFFLINE )soft_offline_page (pfn_to_page (entry.pfn), entry.flags);else -memory_failure (entry.pfn, entry.trapno, entry.flags); +memory_failure (entry.pfn, entry.flags); } }
Signature · 1 line
2.14.1
PATCH 10/10 signal/memory-failure: Use force_sig_mceerr and send_sig_mceerr
In reply to Eric W. BiedermanDelegate filling out struct siginfo to functions in kernel/signal.c to simplify the code.
--- mm/memory-failure.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-)
mm/memory-failure.c +6 -9
@@ -181,19 +181,16 @@ EXPORT_SYMBOL_GPL(hwpoison_filter);static int kill_proc (struct task_struct *t,unsigned long addr,unsigned long pfn,struct page *page,int flags) { -struct siginfo si; +short addr_lsb;int ret;pr_err ("Memory failure: %#lx: Killing %s:%d due to hardware memory corruption\n" , pfn, t->comm, t->pid); - si.si_signo =SIGBUS ; - si.si_errno =0 ; - si.si_addr = (void *)addr; - si.si_addr_lsb =compound_order (compound_head (page)) +PAGE_SHIFT ; + addr_lsb =compound_order (compound_head (page)) +PAGE_SHIFT ;if ((flags &MF_ACTION_REQUIRED ) && t->mm == current->mm) { - si.si_code =BUS_MCEERR_AR ; - ret =force_sig_info (SIGBUS , &si, current); + ret =force_sig_mceerr (BUS_MCEERR_AR , (void __user *)addr, + addr_lsb, current); }else {/* * Don't use force here, it's convenient if the signal
@@ -201,8 +198,8 @@ static int kill_proc(struct task_struct *t, unsigned long addr,* This could cause a loop when the user sets SIGBUS * to SIG_IGN, but hopefully no one will do that? */ - si.si_code =BUS_MCEERR_AO ; - ret =send_sig_info (SIGBUS , &si, t);/* synchronous? */ + ret =send_sig_mceerr (BUS_MCEERR_AO , (void __user *)addr, + addr_lsb, t);/* synchronous? */ }if (ret <0 ) pr_info("Memory failure: Error sending signal to %s:%d: %d\n",
Signature · 1 line
2.14.1