]> git.karo-electronics.de Git - karo-tx-linux.git/blob - arch/x86/kernel/signal_compat.c
40df33753bae8d71390b7f4bd81113211a7b67da
[karo-tx-linux.git] / arch / x86 / kernel / signal_compat.c
1 #include <linux/compat.h>
2 #include <linux/uaccess.h>
3 #include <linux/ptrace.h>
4
5 /*
6  * The compat_siginfo_t structure and handing code is very easy
7  * to break in several ways.  It must always be updated when new
8  * updates are made to the main siginfo_t, and
9  * copy_siginfo_to_user32() must be updated when the
10  * (arch-independent) copy_siginfo_to_user() is updated.
11  *
12  * It is also easy to put a new member in the compat_siginfo_t
13  * which has implicit alignment which can move internal structure
14  * alignment around breaking the ABI.  This can happen if you,
15  * for instance, put a plain 64-bit value in there.
16  */
17 static inline void signal_compat_build_tests(void)
18 {
19         int _sifields_offset = offsetof(compat_siginfo_t, _sifields);
20
21         /*
22          * If adding a new si_code, there is probably new data in
23          * the siginfo.  Make sure folks bumping the si_code
24          * limits also have to look at this code.  Make sure any
25          * new fields are handled in copy_siginfo_to_user32()!
26          */
27         BUILD_BUG_ON(NSIGILL  != 8);
28         BUILD_BUG_ON(NSIGFPE  != 8);
29         BUILD_BUG_ON(NSIGSEGV != 4);
30         BUILD_BUG_ON(NSIGBUS  != 5);
31         BUILD_BUG_ON(NSIGTRAP != 4);
32         BUILD_BUG_ON(NSIGCHLD != 6);
33         BUILD_BUG_ON(NSIGSYS  != 1);
34
35         /* This is part of the ABI and can never change in size: */
36         BUILD_BUG_ON(sizeof(compat_siginfo_t) != 128);
37         /*
38          * The offsets of all the (unioned) si_fields are fixed
39          * in the ABI, of course.  Make sure none of them ever
40          * move and are always at the beginning:
41          */
42         BUILD_BUG_ON(offsetof(compat_siginfo_t, _sifields) != 3 * sizeof(int));
43 #define CHECK_CSI_OFFSET(name)    BUILD_BUG_ON(_sifields_offset != offsetof(compat_siginfo_t, _sifields.name))
44
45          /*
46          * Ensure that the size of each si_field never changes.
47          * If it does, it is a sign that the
48          * copy_siginfo_to_user32() code below needs to updated
49          * along with the size in the CHECK_SI_SIZE().
50          *
51          * We repeat this check for both the generic and compat
52          * siginfos.
53          *
54          * Note: it is OK for these to grow as long as the whole
55          * structure stays within the padding size (checked
56          * above).
57          */
58 #define CHECK_CSI_SIZE(name, size) BUILD_BUG_ON(size != sizeof(((compat_siginfo_t *)0)->_sifields.name))
59 #define CHECK_SI_SIZE(name, size) BUILD_BUG_ON(size != sizeof(((siginfo_t *)0)->_sifields.name))
60
61         CHECK_CSI_OFFSET(_kill);
62         CHECK_CSI_SIZE  (_kill, 2*sizeof(int));
63         CHECK_SI_SIZE   (_kill, 2*sizeof(int));
64
65         CHECK_CSI_OFFSET(_timer);
66         CHECK_CSI_SIZE  (_timer, 5*sizeof(int));
67         CHECK_SI_SIZE   (_timer, 6*sizeof(int));
68
69         CHECK_CSI_OFFSET(_rt);
70         CHECK_CSI_SIZE  (_rt, 3*sizeof(int));
71         CHECK_SI_SIZE   (_rt, 4*sizeof(int));
72
73         CHECK_CSI_OFFSET(_sigchld);
74         CHECK_CSI_SIZE  (_sigchld, 5*sizeof(int));
75         CHECK_SI_SIZE   (_sigchld, 8*sizeof(int));
76
77         CHECK_CSI_OFFSET(_sigchld_x32);
78         CHECK_CSI_SIZE  (_sigchld_x32, 7*sizeof(int));
79         /* no _sigchld_x32 in the generic siginfo_t */
80
81         CHECK_CSI_OFFSET(_sigfault);
82         CHECK_CSI_SIZE  (_sigfault, 4*sizeof(int));
83         CHECK_SI_SIZE   (_sigfault, 8*sizeof(int));
84
85         CHECK_CSI_OFFSET(_sigpoll);
86         CHECK_CSI_SIZE  (_sigpoll, 2*sizeof(int));
87         CHECK_SI_SIZE   (_sigpoll, 4*sizeof(int));
88
89         CHECK_CSI_OFFSET(_sigsys);
90         CHECK_CSI_SIZE  (_sigsys, 3*sizeof(int));
91         CHECK_SI_SIZE   (_sigsys, 4*sizeof(int));
92
93         /* any new si_fields should be added here */
94 }
95
96 void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oact)
97 {
98         /* Don't leak in-kernel non-uapi flags to user-space */
99         if (oact)
100                 oact->sa.sa_flags &= ~(SA_IA32_ABI | SA_X32_ABI);
101
102         if (!act)
103                 return;
104
105         /* Don't let flags to be set from userspace */
106         act->sa.sa_flags &= ~(SA_IA32_ABI | SA_X32_ABI);
107
108         if (user_64bit_mode(current_pt_regs()))
109                 return;
110
111         if (in_ia32_syscall())
112                 act->sa.sa_flags |= SA_IA32_ABI;
113         if (in_x32_syscall())
114                 act->sa.sa_flags |= SA_X32_ABI;
115 }
116
117 int __copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from,
118                 bool x32_ABI)
119 {
120         int err = 0;
121
122         signal_compat_build_tests();
123
124         if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
125                 return -EFAULT;
126
127         put_user_try {
128                 /* If you change siginfo_t structure, please make sure that
129                    this code is fixed accordingly.
130                    It should never copy any pad contained in the structure
131                    to avoid security leaks, but must copy the generic
132                    3 ints plus the relevant union member.  */
133                 put_user_ex(from->si_signo, &to->si_signo);
134                 put_user_ex(from->si_errno, &to->si_errno);
135                 put_user_ex((short)from->si_code, &to->si_code);
136
137                 if (from->si_code < 0) {
138                         put_user_ex(from->si_pid, &to->si_pid);
139                         put_user_ex(from->si_uid, &to->si_uid);
140                         put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr);
141                 } else {
142                         /*
143                          * First 32bits of unions are always present:
144                          * si_pid === si_band === si_tid === si_addr(LS half)
145                          */
146                         put_user_ex(from->_sifields._pad[0],
147                                           &to->_sifields._pad[0]);
148                         switch (from->si_code >> 16) {
149                         case __SI_FAULT >> 16:
150                                 if (from->si_signo == SIGBUS &&
151                                     (from->si_code == BUS_MCEERR_AR ||
152                                      from->si_code == BUS_MCEERR_AO))
153                                         put_user_ex(from->si_addr_lsb, &to->si_addr_lsb);
154
155                                 if (from->si_signo == SIGSEGV) {
156                                         if (from->si_code == SEGV_BNDERR) {
157                                                 compat_uptr_t lower = (unsigned long)&to->si_lower;
158                                                 compat_uptr_t upper = (unsigned long)&to->si_upper;
159                                                 put_user_ex(lower, &to->si_lower);
160                                                 put_user_ex(upper, &to->si_upper);
161                                         }
162                                         if (from->si_code == SEGV_PKUERR)
163                                                 put_user_ex(from->si_pkey, &to->si_pkey);
164                                 }
165                                 break;
166                         case __SI_SYS >> 16:
167                                 put_user_ex(from->si_syscall, &to->si_syscall);
168                                 put_user_ex(from->si_arch, &to->si_arch);
169                                 break;
170                         case __SI_CHLD >> 16:
171                                 if (!x32_ABI) {
172                                         put_user_ex(from->si_utime, &to->si_utime);
173                                         put_user_ex(from->si_stime, &to->si_stime);
174                                 } else {
175                                         put_user_ex(from->si_utime, &to->_sifields._sigchld_x32._utime);
176                                         put_user_ex(from->si_stime, &to->_sifields._sigchld_x32._stime);
177                                 }
178                                 put_user_ex(from->si_status, &to->si_status);
179                                 /* FALL THROUGH */
180                         default:
181                         case __SI_KILL >> 16:
182                                 put_user_ex(from->si_uid, &to->si_uid);
183                                 break;
184                         case __SI_POLL >> 16:
185                                 put_user_ex(from->si_fd, &to->si_fd);
186                                 break;
187                         case __SI_TIMER >> 16:
188                                 put_user_ex(from->si_overrun, &to->si_overrun);
189                                 put_user_ex(ptr_to_compat(from->si_ptr),
190                                             &to->si_ptr);
191                                 break;
192                                  /* This is not generated by the kernel as of now.  */
193                         case __SI_RT >> 16:
194                         case __SI_MESGQ >> 16:
195                                 put_user_ex(from->si_uid, &to->si_uid);
196                                 put_user_ex(from->si_int, &to->si_int);
197                                 break;
198                         }
199                 }
200         } put_user_catch(err);
201
202         return err;
203 }
204
205 /* from syscall's path, where we know the ABI */
206 int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
207 {
208         return __copy_siginfo_to_user32(to, from, in_x32_syscall());
209 }
210
211 int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
212 {
213         int err = 0;
214         u32 ptr32;
215
216         if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
217                 return -EFAULT;
218
219         get_user_try {
220                 get_user_ex(to->si_signo, &from->si_signo);
221                 get_user_ex(to->si_errno, &from->si_errno);
222                 get_user_ex(to->si_code, &from->si_code);
223
224                 get_user_ex(to->si_pid, &from->si_pid);
225                 get_user_ex(to->si_uid, &from->si_uid);
226                 get_user_ex(ptr32, &from->si_ptr);
227                 to->si_ptr = compat_ptr(ptr32);
228         } get_user_catch(err);
229
230         return err;
231 }