Skip to content

Commit cc73152

Browse files
committed
signal: Remove kernel interal si_code magic
struct siginfo is a union and the kernel since 2.4 has been hiding a union tag in the high 16bits of si_code using the values: __SI_KILL __SI_TIMER __SI_POLL __SI_FAULT __SI_CHLD __SI_RT __SI_MESGQ __SI_SYS While this looks plausible on the surface, in practice this situation has not worked well. - Injected positive signals are not copied to user space properly unless they have these magic high bits set. - Injected positive signals are not reported properly by signalfd unless they have these magic high bits set. - These kernel internal values leaked to userspace via ptrace_peek_siginfo - It was possible to inject these kernel internal values and cause the the kernel to misbehave. - Kernel developers got confused and expected these kernel internal values in userspace in kernel self tests. - Kernel developers got confused and set si_code to __SI_FAULT which is SI_USER in userspace which causes userspace to think an ordinary user sent the signal and that it was not kernel generated. - The values make it impossible to reorganize the code to transform siginfo_copy_to_user into a plain copy_to_user. As si_code must be massaged before being passed to userspace. So remove these kernel internal si codes and make the kernel code simpler and more maintainable. To replace these kernel internal magic si_codes introduce the helper function siginfo_layout, that takes a signal number and an si_code and computes which union member of siginfo is being used. Have siginfo_layout return an enumeration so that gcc will have enough information to warn if a switch statement does not handle all of union members. A couple of architectures have a messed up ABI that defines signal specific duplications of SI_USER which causes more special cases in siginfo_layout than I would like. The good news is only problem architectures pay the cost. Update all of the code that used the previous magic __SI_ values to use the new SIL_ values and to call siginfo_layout to get those values. Escept where not all of the cases are handled remove the defaults in the switch statements so that if a new case is missed in the future the lack will show up at compile time. Modify the code that copies siginfo si_code to userspace to just copy the value and not cast si_code to a short first. The high bits are no longer used to hold a magic union member. Fixup the siginfo header files to stop including the __SI_ values in their constants and for the headers that were missing it to properly update the number of si_codes for each signal type. The fixes to copy_siginfo_from_user32 implementations has the interesting property that several of them perviously should never have worked as the __SI_ values they depended up where kernel internal. With that dependency gone those implementations should work much better. The idea of not passing the __SI_ values out to userspace and then not reinserting them has been tested with criu and criu worked without changes. Ref: 2.4.0-test1 Signed-off-by: "Eric W. Biederman" <[email protected]>
1 parent d08477a commit cc73152

File tree

23 files changed

+257
-245
lines changed

23 files changed

+257
-245
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@
1010
* SIGFPE si_codes
1111
*/
1212
#ifdef __KERNEL__
13-
#define FPE_FIXME (__SI_FAULT|0) /* Broken dup of SI_USER */
13+
#define FPE_FIXME 0 /* Broken dup of SI_USER */
1414
#endif /* __KERNEL__ */
1515

1616
/*
1717
* SIGTRAP si_codes
1818
*/
1919
#ifdef __KERNEL__
20-
#define TRAP_FIXME (__SI_FAULT|0) /* Broken dup of SI_USER */
20+
#define TRAP_FIXME 0 /* Broken dup of SI_USER */
2121
#endif /* __KERNEL__ */
2222

2323
#endif

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: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -98,30 +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
*/
110110
#ifdef __KERNEL__
111-
#define FPE_FIXME (__SI_FAULT|0) /* Broken dup of SI_USER */
111+
#define FPE_FIXME 0 /* Broken dup of SI_USER */
112112
#endif /* __KERNEL__ */
113-
#define __FPE_DECOVF (__SI_FAULT|9) /* decimal overflow */
114-
#define __FPE_DECDIV (__SI_FAULT|10) /* decimal division by zero */
115-
#define __FPE_DECERR (__SI_FAULT|11) /* packed decimal error */
116-
#define __FPE_INVASC (__SI_FAULT|12) /* invalid ASCII digit */
117-
#define __FPE_INVDEC (__SI_FAULT|13) /* invalid decimal digit */
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 */
118118
#undef NSIGFPE
119119
#define NSIGFPE 13
120120

121121
/*
122122
* SIGSEGV si_codes
123123
*/
124-
#define __SEGV_PSTKOVF (__SI_FAULT|4) /* paragraph stack overflow */
124+
#define __SEGV_PSTKOVF 4 /* paragraph stack overflow */
125125
#undef NSIGSEGV
126126
#define NSIGSEGV 4
127127

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/mips/include/uapi/asm/siginfo.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,14 +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 */
125125

126126
/*
127127
* SIGFPE si_codes
128128
*/
129129
#ifdef __KERNEL__
130-
#define FPE_FIXME (__SI_FAULT|0) /* Broken dup of SI_USER */
130+
#define FPE_FIXME 0 /* Broken dup of SI_USER */
131131
#endif /* __KERNEL__ */
132132

133133
#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/parisc/kernel/signal32.c

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -290,25 +290,25 @@ copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from)
290290
if (to->si_code < 0)
291291
err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
292292
else {
293-
switch (to->si_code >> 16) {
294-
case __SI_CHLD >> 16:
293+
switch (siginfo_layout(to->si_signo, to->si_code)) {
294+
case SIL_CHLD:
295295
err |= __get_user(to->si_utime, &from->si_utime);
296296
err |= __get_user(to->si_stime, &from->si_stime);
297297
err |= __get_user(to->si_status, &from->si_status);
298298
default:
299+
case SIL_KILL:
299300
err |= __get_user(to->si_pid, &from->si_pid);
300301
err |= __get_user(to->si_uid, &from->si_uid);
301302
break;
302-
case __SI_FAULT >> 16:
303+
case SIL_FAULT:
303304
err |= __get_user(addr, &from->si_addr);
304305
to->si_addr = compat_ptr(addr);
305306
break;
306-
case __SI_POLL >> 16:
307+
case SIL_POLL:
307308
err |= __get_user(to->si_band, &from->si_band);
308309
err |= __get_user(to->si_fd, &from->si_fd);
309310
break;
310-
case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
311-
case __SI_MESGQ >> 16:
311+
case SIL_RT:
312312
err |= __get_user(to->si_pid, &from->si_pid);
313313
err |= __get_user(to->si_uid, &from->si_uid);
314314
err |= __get_user(to->si_int, &from->si_int);
@@ -337,41 +337,40 @@ copy_siginfo_to_user32 (compat_siginfo_t __user *to, const siginfo_t *from)
337337
at the same time. */
338338
err = __put_user(from->si_signo, &to->si_signo);
339339
err |= __put_user(from->si_errno, &to->si_errno);
340-
err |= __put_user((short)from->si_code, &to->si_code);
340+
err |= __put_user(from->si_code, &to->si_code);
341341
if (from->si_code < 0)
342342
err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
343343
else {
344-
switch (from->si_code >> 16) {
345-
case __SI_CHLD >> 16:
344+
switch (siginfo_layout(from->si_signo, from->si_code)) {
345+
case SIL_CHLD:
346346
err |= __put_user(from->si_utime, &to->si_utime);
347347
err |= __put_user(from->si_stime, &to->si_stime);
348348
err |= __put_user(from->si_status, &to->si_status);
349-
default:
349+
case SIL_KILL:
350350
err |= __put_user(from->si_pid, &to->si_pid);
351351
err |= __put_user(from->si_uid, &to->si_uid);
352352
break;
353-
case __SI_FAULT >> 16:
353+
case SIL_FAULT:
354354
addr = ptr_to_compat(from->si_addr);
355355
err |= __put_user(addr, &to->si_addr);
356356
break;
357-
case __SI_POLL >> 16:
357+
case SIL_POLL:
358358
err |= __put_user(from->si_band, &to->si_band);
359359
err |= __put_user(from->si_fd, &to->si_fd);
360360
break;
361-
case __SI_TIMER >> 16:
361+
case SIL_TIMER:
362362
err |= __put_user(from->si_tid, &to->si_tid);
363363
err |= __put_user(from->si_overrun, &to->si_overrun);
364364
val = (compat_int_t)from->si_int;
365365
err |= __put_user(val, &to->si_int);
366366
break;
367-
case __SI_RT >> 16: /* Not generated by the kernel as of now. */
368-
case __SI_MESGQ >> 16:
367+
case SIL_RT:
369368
err |= __put_user(from->si_uid, &to->si_uid);
370369
err |= __put_user(from->si_pid, &to->si_pid);
371370
val = (compat_int_t)from->si_int;
372371
err |= __put_user(val, &to->si_int);
373372
break;
374-
case __SI_SYS >> 16:
373+
case SIL_SYS:
375374
err |= __put_user(ptr_to_compat(from->si_call_addr), &to->si_call_addr);
376375
err |= __put_user(from->si_syscall, &to->si_syscall);
377376
err |= __put_user(from->si_arch, &to->si_arch);

0 commit comments

Comments
 (0)