1 #include <linux/compat.h>
2 #include <linux/uaccess.h>
5 * The compat_siginfo_t structure and handing code is very easy
6 * to break in several ways. It must always be updated when new
7 * updates are made to the main siginfo_t, and
8 * copy_siginfo_to_user32() must be updated when the
9 * (arch-independent) copy_siginfo_to_user() is updated.
11 * It is also easy to put a new member in the compat_siginfo_t
12 * which has implicit alignment which can move internal structure
13 * alignment around breaking the ABI. This can happen if you,
14 * for instance, put a plain 64-bit value in there.
16 static inline void signal_compat_build_tests(void)
18 int _sifields_offset
= offsetof(compat_siginfo_t
, _sifields
);
21 * If adding a new si_code, there is probably new data in
22 * the siginfo. Make sure folks bumping the si_code
23 * limits also have to look at this code. Make sure any
24 * new fields are handled in copy_siginfo_to_user32()!
26 BUILD_BUG_ON(NSIGILL
!= 8);
27 BUILD_BUG_ON(NSIGFPE
!= 8);
28 BUILD_BUG_ON(NSIGSEGV
!= 4);
29 BUILD_BUG_ON(NSIGBUS
!= 5);
30 BUILD_BUG_ON(NSIGTRAP
!= 4);
31 BUILD_BUG_ON(NSIGCHLD
!= 6);
32 BUILD_BUG_ON(NSIGSYS
!= 1);
34 /* This is part of the ABI and can never change in size: */
35 BUILD_BUG_ON(sizeof(compat_siginfo_t
) != 128);
37 * The offsets of all the (unioned) si_fields are fixed
38 * in the ABI, of course. Make sure none of them ever
39 * move and are always at the beginning:
41 BUILD_BUG_ON(offsetof(compat_siginfo_t
, _sifields
) != 3 * sizeof(int));
42 #define CHECK_CSI_OFFSET(name) BUILD_BUG_ON(_sifields_offset != offsetof(compat_siginfo_t, _sifields.name))
45 * Ensure that the size of each si_field never changes.
46 * If it does, it is a sign that the
47 * copy_siginfo_to_user32() code below needs to updated
48 * along with the size in the CHECK_SI_SIZE().
50 * We repeat this check for both the generic and compat
53 * Note: it is OK for these to grow as long as the whole
54 * structure stays within the padding size (checked
57 #define CHECK_CSI_SIZE(name, size) BUILD_BUG_ON(size != sizeof(((compat_siginfo_t *)0)->_sifields.name))
58 #define CHECK_SI_SIZE(name, size) BUILD_BUG_ON(size != sizeof(((siginfo_t *)0)->_sifields.name))
60 CHECK_CSI_OFFSET(_kill
);
61 CHECK_CSI_SIZE (_kill
, 2*sizeof(int));
62 CHECK_SI_SIZE (_kill
, 2*sizeof(int));
64 CHECK_CSI_OFFSET(_timer
);
65 CHECK_CSI_SIZE (_timer
, 5*sizeof(int));
66 CHECK_SI_SIZE (_timer
, 6*sizeof(int));
68 CHECK_CSI_OFFSET(_rt
);
69 CHECK_CSI_SIZE (_rt
, 3*sizeof(int));
70 CHECK_SI_SIZE (_rt
, 4*sizeof(int));
72 CHECK_CSI_OFFSET(_sigchld
);
73 CHECK_CSI_SIZE (_sigchld
, 5*sizeof(int));
74 CHECK_SI_SIZE (_sigchld
, 8*sizeof(int));
76 CHECK_CSI_OFFSET(_sigchld_x32
);
77 CHECK_CSI_SIZE (_sigchld_x32
, 7*sizeof(int));
78 /* no _sigchld_x32 in the generic siginfo_t */
80 CHECK_CSI_OFFSET(_sigfault
);
81 CHECK_CSI_SIZE (_sigfault
, 4*sizeof(int));
82 CHECK_SI_SIZE (_sigfault
, 8*sizeof(int));
84 CHECK_CSI_OFFSET(_sigpoll
);
85 CHECK_CSI_SIZE (_sigpoll
, 2*sizeof(int));
86 CHECK_SI_SIZE (_sigpoll
, 4*sizeof(int));
88 CHECK_CSI_OFFSET(_sigsys
);
89 CHECK_CSI_SIZE (_sigsys
, 3*sizeof(int));
90 CHECK_SI_SIZE (_sigsys
, 4*sizeof(int));
92 /* any new si_fields should be added here */
95 int copy_siginfo_to_user32(compat_siginfo_t __user
*to
, const siginfo_t
*from
)
98 bool ia32
= test_thread_flag(TIF_IA32
);
100 signal_compat_build_tests();
102 if (!access_ok(VERIFY_WRITE
, to
, sizeof(compat_siginfo_t
)))
106 /* If you change siginfo_t structure, please make sure that
107 this code is fixed accordingly.
108 It should never copy any pad contained in the structure
109 to avoid security leaks, but must copy the generic
110 3 ints plus the relevant union member. */
111 put_user_ex(from
->si_signo
, &to
->si_signo
);
112 put_user_ex(from
->si_errno
, &to
->si_errno
);
113 put_user_ex((short)from
->si_code
, &to
->si_code
);
115 if (from
->si_code
< 0) {
116 put_user_ex(from
->si_pid
, &to
->si_pid
);
117 put_user_ex(from
->si_uid
, &to
->si_uid
);
118 put_user_ex(ptr_to_compat(from
->si_ptr
), &to
->si_ptr
);
121 * First 32bits of unions are always present:
122 * si_pid === si_band === si_tid === si_addr(LS half)
124 put_user_ex(from
->_sifields
._pad
[0],
125 &to
->_sifields
._pad
[0]);
126 switch (from
->si_code
>> 16) {
127 case __SI_FAULT
>> 16:
128 if (from
->si_signo
== SIGBUS
&&
129 (from
->si_code
== BUS_MCEERR_AR
||
130 from
->si_code
== BUS_MCEERR_AO
))
131 put_user_ex(from
->si_addr_lsb
, &to
->si_addr_lsb
);
133 if (from
->si_signo
== SIGSEGV
) {
134 if (from
->si_code
== SEGV_BNDERR
) {
135 compat_uptr_t lower
= (unsigned long)&to
->si_lower
;
136 compat_uptr_t upper
= (unsigned long)&to
->si_upper
;
137 put_user_ex(lower
, &to
->si_lower
);
138 put_user_ex(upper
, &to
->si_upper
);
140 if (from
->si_code
== SEGV_PKUERR
)
141 put_user_ex(from
->si_pkey
, &to
->si_pkey
);
145 put_user_ex(from
->si_syscall
, &to
->si_syscall
);
146 put_user_ex(from
->si_arch
, &to
->si_arch
);
148 case __SI_CHLD
>> 16:
150 put_user_ex(from
->si_utime
, &to
->si_utime
);
151 put_user_ex(from
->si_stime
, &to
->si_stime
);
153 put_user_ex(from
->si_utime
, &to
->_sifields
._sigchld_x32
._utime
);
154 put_user_ex(from
->si_stime
, &to
->_sifields
._sigchld_x32
._stime
);
156 put_user_ex(from
->si_status
, &to
->si_status
);
159 case __SI_KILL
>> 16:
160 put_user_ex(from
->si_uid
, &to
->si_uid
);
162 case __SI_POLL
>> 16:
163 put_user_ex(from
->si_fd
, &to
->si_fd
);
165 case __SI_TIMER
>> 16:
166 put_user_ex(from
->si_overrun
, &to
->si_overrun
);
167 put_user_ex(ptr_to_compat(from
->si_ptr
),
170 /* This is not generated by the kernel as of now. */
172 case __SI_MESGQ
>> 16:
173 put_user_ex(from
->si_uid
, &to
->si_uid
);
174 put_user_ex(from
->si_int
, &to
->si_int
);
178 } put_user_catch(err
);
183 int copy_siginfo_from_user32(siginfo_t
*to
, compat_siginfo_t __user
*from
)
188 if (!access_ok(VERIFY_READ
, from
, sizeof(compat_siginfo_t
)))
192 get_user_ex(to
->si_signo
, &from
->si_signo
);
193 get_user_ex(to
->si_errno
, &from
->si_errno
);
194 get_user_ex(to
->si_code
, &from
->si_code
);
196 get_user_ex(to
->si_pid
, &from
->si_pid
);
197 get_user_ex(to
->si_uid
, &from
->si_uid
);
198 get_user_ex(ptr32
, &from
->si_ptr
);
199 to
->si_ptr
= compat_ptr(ptr32
);
200 } get_user_catch(err
);
This page took 0.036723 seconds and 6 git commands to generate.