Skip to content

Commit 64a76d0

Browse files
committed
signal: Fix sending signals with siginfo
Today sending a signal with rt_sigqueueinfo and receving it on a signalfd does not work reliably. The issue is that reading a signalfd instead of returning a siginfo returns a signalfd_siginfo and the kernel must convert from one to the other. The kernel does not currently have the code to deduce which union members of struct siginfo are in use. In this patchset I fix that by introducing a new function siginfo_layout that can look at a siginfo and report which union member of struct siginfo is in use. Before that I clean up how we populate struct siginfo. The siginfo structure has two key members si_signo and si_code. Some si_codes are signal specific and for those it takes si_signo and si_code to indicate the members of siginfo that are valid. The rest of the si_code values are signal independent like SI_USER, SI_KERNEL, SI_QUEUE, and SI_TIMER and only si_code is needed to indicate which members of siginfo are valid. At least that is how POSIX documents them, and how common sense would indicate they should function. In practice we have been rather sloppy about maintaining the ABI in linux and we have some exceptions. We have a couple of buggy architectures that make SI_USER mean something different when combined with SIGFPE or SIGTRAP. Worse we have fcntl(F_SETSIG) which results in the si_codes POLL_IN, POLL_OUT, POLL_MSG, POLL_ERR, POLL_PRI, POLL_HUP being sent with any arbitrary signal, while the values are in a range that overlaps the signal specific si_codes. Thankfully the ambiguous cases with the POLL_NNN si_codes are for things no sane persion would do that so we can rectify the situtation. AKA no one cares so we won't cause a regression fixing it. As part of fixing this I stop leaking the __SI_xxxx codes to userspace and stop storing them in the high 16bits of si_code. Making the kernel code fundamentally simpler. We have already confirmed that the one application that would see this difference in kernel behavior CRIU won't be affected by this change as it copies values verbatim from one kernel interface to another. v3: - Corrected the patches so they bisect properly v2: - Benchmarked the code to confirm no performance changes are visible. - Reworked the first couple of patches so that TRAP_FIXME and FPE_FIXME are not exported to userspace. - Rebased on top of the siginfo cleanup that came in v4.13-rc1 - Updated alpha to use both TRAP_FIXME and FPE_FIXME Eric W. Biederman (7): signal/alpha: Document a conflict with SI_USER for SIGTRAP signal/ia64: Document a conflict with SI_USER with SIGFPE signal/sparc: Document a conflict with SI_USER with SIGFPE signal/mips: Document a conflict with SI_USER with SIGFPE signal/testing: Don't look for __SI_FAULT in userspace fcntl: Don't use ambiguous SIG_POLL si_codes signal: Remove kernel interal si_code magic Signed-off-by: "Eric W. Biederman" <[email protected]>
2 parents 4d28df6 + cc73152 commit 64a76d0

File tree

31 files changed

+318
-258
lines changed

31 files changed

+318
-258
lines changed

arch/alpha/include/uapi/asm/siginfo.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,18 @@
66

77
#include <asm-generic/siginfo.h>
88

9+
/*
10+
* SIGFPE si_codes
11+
*/
12+
#ifdef __KERNEL__
13+
#define FPE_FIXME 0 /* Broken dup of SI_USER */
14+
#endif /* __KERNEL__ */
15+
16+
/*
17+
* SIGTRAP si_codes
18+
*/
19+
#ifdef __KERNEL__
20+
#define TRAP_FIXME 0 /* Broken dup of SI_USER */
21+
#endif /* __KERNEL__ */
22+
923
#endif

arch/alpha/kernel/traps.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ do_entIF(unsigned long type, struct pt_regs *regs)
278278
case 1: /* bugcheck */
279279
info.si_signo = SIGTRAP;
280280
info.si_errno = 0;
281-
info.si_code = __SI_FAULT;
281+
info.si_code = TRAP_FIXME;
282282
info.si_addr = (void __user *) regs->pc;
283283
info.si_trapno = 0;
284284
send_sig_info(SIGTRAP, &info, current);
@@ -318,7 +318,7 @@ do_entIF(unsigned long type, struct pt_regs *regs)
318318
break;
319319
case GEN_ROPRAND:
320320
signo = SIGFPE;
321-
code = __SI_FAULT;
321+
code = FPE_FIXME;
322322
break;
323323

324324
case GEN_DECOVF:
@@ -340,7 +340,7 @@ do_entIF(unsigned long type, struct pt_regs *regs)
340340
case GEN_SUBRNG7:
341341
default:
342342
signo = SIGTRAP;
343-
code = __SI_FAULT;
343+
code = TRAP_FIXME;
344344
break;
345345
}
346346

arch/arm64/kernel/signal32.c

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -142,25 +142,25 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
142142
*/
143143
err = __put_user(from->si_signo, &to->si_signo);
144144
err |= __put_user(from->si_errno, &to->si_errno);
145-
err |= __put_user((short)from->si_code, &to->si_code);
145+
err |= __put_user(from->si_code, &to->si_code);
146146
if (from->si_code < 0)
147147
err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad,
148148
SI_PAD_SIZE);
149-
else switch (from->si_code & __SI_MASK) {
150-
case __SI_KILL:
149+
else switch (siginfo_layout(from->si_signo, from->si_code)) {
150+
case SIL_KILL:
151151
err |= __put_user(from->si_pid, &to->si_pid);
152152
err |= __put_user(from->si_uid, &to->si_uid);
153153
break;
154-
case __SI_TIMER:
154+
case SIL_TIMER:
155155
err |= __put_user(from->si_tid, &to->si_tid);
156156
err |= __put_user(from->si_overrun, &to->si_overrun);
157157
err |= __put_user(from->si_int, &to->si_int);
158158
break;
159-
case __SI_POLL:
159+
case SIL_POLL:
160160
err |= __put_user(from->si_band, &to->si_band);
161161
err |= __put_user(from->si_fd, &to->si_fd);
162162
break;
163-
case __SI_FAULT:
163+
case SIL_FAULT:
164164
err |= __put_user((compat_uptr_t)(unsigned long)from->si_addr,
165165
&to->si_addr);
166166
#ifdef BUS_MCEERR_AO
@@ -173,29 +173,24 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
173173
err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb);
174174
#endif
175175
break;
176-
case __SI_CHLD:
176+
case SIL_CHLD:
177177
err |= __put_user(from->si_pid, &to->si_pid);
178178
err |= __put_user(from->si_uid, &to->si_uid);
179179
err |= __put_user(from->si_status, &to->si_status);
180180
err |= __put_user(from->si_utime, &to->si_utime);
181181
err |= __put_user(from->si_stime, &to->si_stime);
182182
break;
183-
case __SI_RT: /* This is not generated by the kernel as of now. */
184-
case __SI_MESGQ: /* But this is */
183+
case SIL_RT:
185184
err |= __put_user(from->si_pid, &to->si_pid);
186185
err |= __put_user(from->si_uid, &to->si_uid);
187186
err |= __put_user(from->si_int, &to->si_int);
188187
break;
189-
case __SI_SYS:
188+
case SIL_SYS:
190189
err |= __put_user((compat_uptr_t)(unsigned long)
191190
from->si_call_addr, &to->si_call_addr);
192191
err |= __put_user(from->si_syscall, &to->si_syscall);
193192
err |= __put_user(from->si_arch, &to->si_arch);
194193
break;
195-
default: /* this is just in case for now ... */
196-
err |= __put_user(from->si_pid, &to->si_pid);
197-
err |= __put_user(from->si_uid, &to->si_uid);
198-
break;
199194
}
200195
return err;
201196
}

arch/blackfin/include/uapi/asm/siginfo.h

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,36 @@
1414

1515
#define si_uid16 _sifields._kill._uid
1616

17-
#define ILL_ILLPARAOP (__SI_FAULT|2) /* illegal opcode combine ********** */
18-
#define ILL_ILLEXCPT (__SI_FAULT|4) /* unrecoverable exception ********** */
19-
#define ILL_CPLB_VI (__SI_FAULT|9) /* D/I CPLB protect violation ******** */
20-
#define ILL_CPLB_MISS (__SI_FAULT|10) /* D/I CPLB miss ******** */
21-
#define ILL_CPLB_MULHIT (__SI_FAULT|11) /* D/I CPLB multiple hit ******** */
17+
#define ILL_ILLPARAOP 2 /* illegal opcode combine ********** */
18+
#define ILL_ILLEXCPT 4 /* unrecoverable exception ********** */
19+
#define ILL_CPLB_VI 9 /* D/I CPLB protect violation ******** */
20+
#define ILL_CPLB_MISS 10 /* D/I CPLB miss ******** */
21+
#define ILL_CPLB_MULHIT 11 /* D/I CPLB multiple hit ******** */
22+
#undef NSIGILL
23+
#define NSIGILL 11
2224

2325
/*
2426
* SIGBUS si_codes
2527
*/
26-
#define BUS_OPFETCH (__SI_FAULT|4) /* error from instruction fetch ******** */
28+
#define BUS_OPFETCH 4 /* error from instruction fetch ******** */
29+
#undef NSIGBUS
30+
#define NSIGBUS 4
2731

2832
/*
2933
* SIGTRAP si_codes
3034
*/
31-
#define TRAP_STEP (__SI_FAULT|1) /* single-step breakpoint************* */
32-
#define TRAP_TRACEFLOW (__SI_FAULT|2) /* trace buffer overflow ************* */
33-
#define TRAP_WATCHPT (__SI_FAULT|3) /* watchpoint match ************* */
34-
#define TRAP_ILLTRAP (__SI_FAULT|4) /* illegal trap ************* */
35+
#define TRAP_STEP 1 /* single-step breakpoint************* */
36+
#define TRAP_TRACEFLOW 2 /* trace buffer overflow ************* */
37+
#define TRAP_WATCHPT 3 /* watchpoint match ************* */
38+
#define TRAP_ILLTRAP 4 /* illegal trap ************* */
39+
#undef NSIGTRAP
40+
#define NSIGTRAP 4
3541

3642
/*
3743
* SIGSEGV si_codes
3844
*/
39-
#define SEGV_STACKFLOW (__SI_FAULT|3) /* stack overflow */
45+
#define SEGV_STACKFLOW 3 /* stack overflow */
46+
#undef NSIGSEGV
47+
#define NSIGSEGV 3
4048

4149
#endif /* _UAPI_BFIN_SIGINFO_H */

arch/frv/include/uapi/asm/siginfo.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include <linux/types.h>
55
#include <asm-generic/siginfo.h>
66

7-
#define FPE_MDAOVF (__SI_FAULT|9) /* media overflow */
7+
#define FPE_MDAOVF 9 /* media overflow */
88
#undef NSIGFPE
99
#define NSIGFPE 9
1010

arch/ia64/include/uapi/asm/siginfo.h

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -98,27 +98,30 @@ typedef struct siginfo {
9898
/*
9999
* SIGILL si_codes
100100
*/
101-
#define ILL_BADIADDR (__SI_FAULT|9) /* unimplemented instruction address */
102-
#define __ILL_BREAK (__SI_FAULT|10) /* illegal break */
103-
#define __ILL_BNDMOD (__SI_FAULT|11) /* bundle-update (modification) in progress */
101+
#define ILL_BADIADDR 9 /* unimplemented instruction address */
102+
#define __ILL_BREAK 10 /* illegal break */
103+
#define __ILL_BNDMOD 11 /* bundle-update (modification) in progress */
104104
#undef NSIGILL
105105
#define NSIGILL 11
106106

107107
/*
108108
* SIGFPE si_codes
109109
*/
110-
#define __FPE_DECOVF (__SI_FAULT|9) /* decimal overflow */
111-
#define __FPE_DECDIV (__SI_FAULT|10) /* decimal division by zero */
112-
#define __FPE_DECERR (__SI_FAULT|11) /* packed decimal error */
113-
#define __FPE_INVASC (__SI_FAULT|12) /* invalid ASCII digit */
114-
#define __FPE_INVDEC (__SI_FAULT|13) /* invalid decimal digit */
110+
#ifdef __KERNEL__
111+
#define FPE_FIXME 0 /* Broken dup of SI_USER */
112+
#endif /* __KERNEL__ */
113+
#define __FPE_DECOVF 9 /* decimal overflow */
114+
#define __FPE_DECDIV 10 /* decimal division by zero */
115+
#define __FPE_DECERR 11 /* packed decimal error */
116+
#define __FPE_INVASC 12 /* invalid ASCII digit */
117+
#define __FPE_INVDEC 13 /* invalid decimal digit */
115118
#undef NSIGFPE
116119
#define NSIGFPE 13
117120

118121
/*
119122
* SIGSEGV si_codes
120123
*/
121-
#define __SEGV_PSTKOVF (__SI_FAULT|4) /* paragraph stack overflow */
124+
#define __SEGV_PSTKOVF 4 /* paragraph stack overflow */
122125
#undef NSIGSEGV
123126
#define NSIGSEGV 4
124127

arch/ia64/kernel/signal.c

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -124,31 +124,30 @@ copy_siginfo_to_user (siginfo_t __user *to, const siginfo_t *from)
124124
*/
125125
err = __put_user(from->si_signo, &to->si_signo);
126126
err |= __put_user(from->si_errno, &to->si_errno);
127-
err |= __put_user((short)from->si_code, &to->si_code);
128-
switch (from->si_code >> 16) {
129-
case __SI_FAULT >> 16:
127+
err |= __put_user(from->si_code, &to->si_code);
128+
switch (siginfo_layout(from->si_signo, from->si_code)) {
129+
case SIL_FAULT:
130130
err |= __put_user(from->si_flags, &to->si_flags);
131131
err |= __put_user(from->si_isr, &to->si_isr);
132-
case __SI_POLL >> 16:
132+
case SIL_POLL:
133133
err |= __put_user(from->si_addr, &to->si_addr);
134134
err |= __put_user(from->si_imm, &to->si_imm);
135135
break;
136-
case __SI_TIMER >> 16:
136+
case SIL_TIMER:
137137
err |= __put_user(from->si_tid, &to->si_tid);
138138
err |= __put_user(from->si_overrun, &to->si_overrun);
139139
err |= __put_user(from->si_ptr, &to->si_ptr);
140140
break;
141-
case __SI_RT >> 16: /* Not generated by the kernel as of now. */
142-
case __SI_MESGQ >> 16:
141+
case SIL_RT:
143142
err |= __put_user(from->si_uid, &to->si_uid);
144143
err |= __put_user(from->si_pid, &to->si_pid);
145144
err |= __put_user(from->si_ptr, &to->si_ptr);
146145
break;
147-
case __SI_CHLD >> 16:
146+
case SIL_CHLD:
148147
err |= __put_user(from->si_utime, &to->si_utime);
149148
err |= __put_user(from->si_stime, &to->si_stime);
150149
err |= __put_user(from->si_status, &to->si_status);
151-
default:
150+
case SIL_KILL:
152151
err |= __put_user(from->si_uid, &to->si_uid);
153152
err |= __put_user(from->si_pid, &to->si_pid);
154153
break;

arch/ia64/kernel/traps.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr)
349349
}
350350
siginfo.si_signo = SIGFPE;
351351
siginfo.si_errno = 0;
352-
siginfo.si_code = __SI_FAULT; /* default code */
352+
siginfo.si_code = FPE_FIXME; /* default code */
353353
siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri);
354354
if (isr & 0x11) {
355355
siginfo.si_code = FPE_FLTINV;
@@ -373,7 +373,7 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr)
373373
/* raise exception */
374374
siginfo.si_signo = SIGFPE;
375375
siginfo.si_errno = 0;
376-
siginfo.si_code = __SI_FAULT; /* default code */
376+
siginfo.si_code = FPE_FIXME; /* default code */
377377
siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri);
378378
if (isr & 0x880) {
379379
siginfo.si_code = FPE_FLTOVF;

arch/mips/include/uapi/asm/siginfo.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,14 @@ typedef struct siginfo {
120120
#undef SI_TIMER
121121
#undef SI_MESGQ
122122
#define SI_ASYNCIO -2 /* sent by AIO completion */
123-
#define SI_TIMER __SI_CODE(__SI_TIMER, -3) /* sent by timer expiration */
124-
#define SI_MESGQ __SI_CODE(__SI_MESGQ, -4) /* sent by real time mesq state change */
123+
#define SI_TIMER -3 /* sent by timer expiration */
124+
#define SI_MESGQ -4 /* sent by real time mesq state change */
125+
126+
/*
127+
* SIGFPE si_codes
128+
*/
129+
#ifdef __KERNEL__
130+
#define FPE_FIXME 0 /* Broken dup of SI_USER */
131+
#endif /* __KERNEL__ */
125132

126133
#endif /* _UAPI_ASM_SIGINFO_H */

arch/mips/kernel/signal32.c

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -93,38 +93,37 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
9393
at the same time. */
9494
err = __put_user(from->si_signo, &to->si_signo);
9595
err |= __put_user(from->si_errno, &to->si_errno);
96-
err |= __put_user((short)from->si_code, &to->si_code);
96+
err |= __put_user(from->si_code, &to->si_code);
9797
if (from->si_code < 0)
9898
err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
9999
else {
100-
switch (from->si_code >> 16) {
101-
case __SI_TIMER >> 16:
100+
switch (siginfo_layout(from->si_signo, from->si_code)) {
101+
case SIL_TIMER:
102102
err |= __put_user(from->si_tid, &to->si_tid);
103103
err |= __put_user(from->si_overrun, &to->si_overrun);
104104
err |= __put_user(from->si_int, &to->si_int);
105105
break;
106-
case __SI_CHLD >> 16:
106+
case SIL_CHLD:
107107
err |= __put_user(from->si_utime, &to->si_utime);
108108
err |= __put_user(from->si_stime, &to->si_stime);
109109
err |= __put_user(from->si_status, &to->si_status);
110-
default:
110+
case SIL_KILL:
111111
err |= __put_user(from->si_pid, &to->si_pid);
112112
err |= __put_user(from->si_uid, &to->si_uid);
113113
break;
114-
case __SI_FAULT >> 16:
114+
case SIL_FAULT:
115115
err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
116116
break;
117-
case __SI_POLL >> 16:
117+
case SIL_POLL:
118118
err |= __put_user(from->si_band, &to->si_band);
119119
err |= __put_user(from->si_fd, &to->si_fd);
120120
break;
121-
case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
122-
case __SI_MESGQ >> 16:
121+
case SIL_RT:
123122
err |= __put_user(from->si_pid, &to->si_pid);
124123
err |= __put_user(from->si_uid, &to->si_uid);
125124
err |= __put_user(from->si_int, &to->si_int);
126125
break;
127-
case __SI_SYS >> 16:
126+
case SIL_SYS:
128127
err |= __copy_to_user(&to->si_call_addr, &from->si_call_addr,
129128
sizeof(compat_uptr_t));
130129
err |= __put_user(from->si_syscall, &to->si_syscall);

arch/mips/kernel/traps.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,7 @@ void force_fcr31_sig(unsigned long fcr31, void __user *fault_addr,
735735
else if (fcr31 & FPU_CSR_INE_X)
736736
si.si_code = FPE_FLTRES;
737737
else
738-
si.si_code = __SI_FAULT;
738+
si.si_code = FPE_FIXME;
739739
force_sig_info(SIGFPE, &si, tsk);
740740
}
741741

0 commit comments

Comments
 (0)