1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <linux/sched.h>
16#include <linux/mm.h>
17#include <linux/smp.h>
18#include <linux/kernel.h>
19#include <linux/signal.h>
20#include <linux/errno.h>
21#include <linux/wait.h>
22#include <linux/unistd.h>
23#include <linux/stddef.h>
24#include <linux/personality.h>
25#include <linux/suspend.h>
26#include <linux/ptrace.h>
27#include <linux/elf.h>
28#include <linux/compat.h>
29#include <linux/syscalls.h>
30#include <linux/uaccess.h>
31#include <asm/processor.h>
32#include <asm/ucontext.h>
33#include <asm/sigframe.h>
34#include <asm/syscalls.h>
35#include <arch/interrupts.h>
36
37struct compat_sigaction {
38 compat_uptr_t sa_handler;
39 compat_ulong_t sa_flags;
40 compat_uptr_t sa_restorer;
41 sigset_t sa_mask __packed;
42};
43
44struct compat_sigaltstack {
45 compat_uptr_t ss_sp;
46 int ss_flags;
47 compat_size_t ss_size;
48};
49
50struct compat_ucontext {
51 compat_ulong_t uc_flags;
52 compat_uptr_t uc_link;
53 struct compat_sigaltstack uc_stack;
54 struct sigcontext uc_mcontext;
55 sigset_t uc_sigmask;
56};
57
58#define COMPAT_SI_PAD_SIZE ((SI_MAX_SIZE - 3 * sizeof(int)) / sizeof(int))
59
60struct compat_siginfo {
61 int si_signo;
62 int si_errno;
63 int si_code;
64
65 union {
66 int _pad[COMPAT_SI_PAD_SIZE];
67
68
69 struct {
70 unsigned int _pid;
71 unsigned int _uid;
72 } _kill;
73
74
75 struct {
76 compat_timer_t _tid;
77 int _overrun;
78 compat_sigval_t _sigval;
79 int _sys_private;
80 int _overrun_incr;
81 } _timer;
82
83
84 struct {
85 unsigned int _pid;
86 unsigned int _uid;
87 compat_sigval_t _sigval;
88 } _rt;
89
90
91 struct {
92 unsigned int _pid;
93 unsigned int _uid;
94 int _status;
95 compat_clock_t _utime;
96 compat_clock_t _stime;
97 } _sigchld;
98
99
100 struct {
101 unsigned int _addr;
102#ifdef __ARCH_SI_TRAPNO
103 int _trapno;
104#endif
105 } _sigfault;
106
107
108 struct {
109 int _band;
110 int _fd;
111 } _sigpoll;
112 } _sifields;
113};
114
115struct compat_rt_sigframe {
116 unsigned char save_area[C_ABI_SAVE_AREA_SIZE];
117 struct compat_siginfo info;
118 struct compat_ucontext uc;
119};
120
121long compat_sys_rt_sigaction(int sig, struct compat_sigaction __user *act,
122 struct compat_sigaction __user *oact,
123 size_t sigsetsize)
124{
125 struct k_sigaction new_sa, old_sa;
126 int ret = -EINVAL;
127
128
129 if (sigsetsize != sizeof(sigset_t))
130 goto out;
131
132 if (act) {
133 compat_uptr_t handler, restorer;
134
135 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
136 __get_user(handler, &act->sa_handler) ||
137 __get_user(new_sa.sa.sa_flags, &act->sa_flags) ||
138 __get_user(restorer, &act->sa_restorer) ||
139 __copy_from_user(&new_sa.sa.sa_mask, &act->sa_mask,
140 sizeof(sigset_t)))
141 return -EFAULT;
142 new_sa.sa.sa_handler = compat_ptr(handler);
143 new_sa.sa.sa_restorer = compat_ptr(restorer);
144 }
145
146 ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
147
148 if (!ret && oact) {
149 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
150 __put_user(ptr_to_compat(old_sa.sa.sa_handler),
151 &oact->sa_handler) ||
152 __put_user(ptr_to_compat(old_sa.sa.sa_restorer),
153 &oact->sa_restorer) ||
154 __put_user(old_sa.sa.sa_flags, &oact->sa_flags) ||
155 __copy_to_user(&oact->sa_mask, &old_sa.sa.sa_mask,
156 sizeof(sigset_t)))
157 return -EFAULT;
158 }
159out:
160 return ret;
161}
162
163long compat_sys_rt_sigqueueinfo(int pid, int sig,
164 struct compat_siginfo __user *uinfo)
165{
166 siginfo_t info;
167 int ret;
168 mm_segment_t old_fs = get_fs();
169
170 if (copy_siginfo_from_user32(&info, uinfo))
171 return -EFAULT;
172 set_fs(KERNEL_DS);
173 ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __force __user *)&info);
174 set_fs(old_fs);
175 return ret;
176}
177
178int copy_siginfo_to_user32(struct compat_siginfo __user *to, siginfo_t *from)
179{
180 int err;
181
182 if (!access_ok(VERIFY_WRITE, to, sizeof(struct compat_siginfo)))
183 return -EFAULT;
184
185
186
187
188
189
190 err = __put_user(from->si_signo, &to->si_signo);
191 err |= __put_user(from->si_errno, &to->si_errno);
192 err |= __put_user((short)from->si_code, &to->si_code);
193
194 if (from->si_code < 0) {
195 err |= __put_user(from->si_pid, &to->si_pid);
196 err |= __put_user(from->si_uid, &to->si_uid);
197 err |= __put_user(ptr_to_compat(from->si_ptr), &to->si_ptr);
198 } else {
199
200
201
202
203 err |= __put_user(from->_sifields._pad[0],
204 &to->_sifields._pad[0]);
205 switch (from->si_code >> 16) {
206 case __SI_FAULT >> 16:
207 break;
208 case __SI_CHLD >> 16:
209 err |= __put_user(from->si_utime, &to->si_utime);
210 err |= __put_user(from->si_stime, &to->si_stime);
211 err |= __put_user(from->si_status, &to->si_status);
212
213 default:
214 case __SI_KILL >> 16:
215 err |= __put_user(from->si_uid, &to->si_uid);
216 break;
217 case __SI_POLL >> 16:
218 err |= __put_user(from->si_fd, &to->si_fd);
219 break;
220 case __SI_TIMER >> 16:
221 err |= __put_user(from->si_overrun, &to->si_overrun);
222 err |= __put_user(ptr_to_compat(from->si_ptr),
223 &to->si_ptr);
224 break;
225
226 case __SI_RT >> 16:
227 case __SI_MESGQ >> 16:
228 err |= __put_user(from->si_uid, &to->si_uid);
229 err |= __put_user(from->si_int, &to->si_int);
230 break;
231 }
232 }
233 return err;
234}
235
236int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
237{
238 int err;
239 u32 ptr32;
240
241 if (!access_ok(VERIFY_READ, from, sizeof(struct compat_siginfo)))
242 return -EFAULT;
243
244 err = __get_user(to->si_signo, &from->si_signo);
245 err |= __get_user(to->si_errno, &from->si_errno);
246 err |= __get_user(to->si_code, &from->si_code);
247
248 err |= __get_user(to->si_pid, &from->si_pid);
249 err |= __get_user(to->si_uid, &from->si_uid);
250 err |= __get_user(ptr32, &from->si_ptr);
251 to->si_ptr = compat_ptr(ptr32);
252
253 return err;
254}
255
256long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
257 struct compat_sigaltstack __user *uoss_ptr,
258 struct pt_regs *regs)
259{
260 stack_t uss, uoss;
261 int ret;
262 mm_segment_t seg;
263
264 if (uss_ptr) {
265 u32 ptr;
266
267 memset(&uss, 0, sizeof(stack_t));
268 if (!access_ok(VERIFY_READ, uss_ptr, sizeof(*uss_ptr)) ||
269 __get_user(ptr, &uss_ptr->ss_sp) ||
270 __get_user(uss.ss_flags, &uss_ptr->ss_flags) ||
271 __get_user(uss.ss_size, &uss_ptr->ss_size))
272 return -EFAULT;
273 uss.ss_sp = compat_ptr(ptr);
274 }
275 seg = get_fs();
276 set_fs(KERNEL_DS);
277 ret = do_sigaltstack(uss_ptr ? (stack_t __user __force *)&uss : NULL,
278 (stack_t __user __force *)&uoss,
279 (unsigned long)compat_ptr(regs->sp));
280 set_fs(seg);
281 if (ret >= 0 && uoss_ptr) {
282 if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(*uoss_ptr)) ||
283 __put_user(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp) ||
284 __put_user(uoss.ss_flags, &uoss_ptr->ss_flags) ||
285 __put_user(uoss.ss_size, &uoss_ptr->ss_size))
286 ret = -EFAULT;
287 }
288 return ret;
289}
290
291
292long compat_sys_rt_sigreturn(struct pt_regs *regs)
293{
294 struct compat_rt_sigframe __user *frame =
295 (struct compat_rt_sigframe __user *) compat_ptr(regs->sp);
296 sigset_t set;
297
298 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
299 goto badframe;
300 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
301 goto badframe;
302
303 set_current_blocked(&set);
304
305 if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
306 goto badframe;
307
308 if (compat_sys_sigaltstack(&frame->uc.uc_stack, NULL, regs) != 0)
309 goto badframe;
310
311 return 0;
312
313badframe:
314 signal_fault("bad sigreturn frame", regs, frame, 0);
315 return 0;
316}
317
318
319
320
321static inline void __user *compat_get_sigframe(struct k_sigaction *ka,
322 struct pt_regs *regs,
323 size_t frame_size)
324{
325 unsigned long sp;
326
327
328 sp = (unsigned long)compat_ptr(regs->sp);
329
330
331
332
333
334
335 if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size)))
336 return (void __user __force *)-1UL;
337
338
339 if (ka->sa.sa_flags & SA_ONSTACK) {
340 if (sas_ss_flags(sp) == 0)
341 sp = current->sas_ss_sp + current->sas_ss_size;
342 }
343
344 sp -= frame_size;
345
346
347
348
349 sp &= -16UL;
350 return (void __user *) sp;
351}
352
353int compat_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
354 sigset_t *set, struct pt_regs *regs)
355{
356 unsigned long restorer;
357 struct compat_rt_sigframe __user *frame;
358 int err = 0;
359 int usig;
360
361 frame = compat_get_sigframe(ka, regs, sizeof(*frame));
362
363 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
364 goto give_sigsegv;
365
366 usig = current_thread_info()->exec_domain
367 && current_thread_info()->exec_domain->signal_invmap
368 && sig < 32
369 ? current_thread_info()->exec_domain->signal_invmap[sig]
370 : sig;
371
372
373 if (ka->sa.sa_flags & SA_SIGINFO) {
374
375 err |= copy_siginfo_to_user32(&frame->info, info);
376 regs->flags |= PT_FLAGS_RESTORE_REGS;
377 } else {
378 err |= __put_user(info->si_signo, &frame->info.si_signo);
379 }
380
381
382 err |= __clear_user(&frame->save_area, sizeof(frame->save_area));
383 err |= __put_user(0, &frame->uc.uc_flags);
384 err |= __put_user(0, &frame->uc.uc_link);
385 err |= __put_user(ptr_to_compat((void *)(current->sas_ss_sp)),
386 &frame->uc.uc_stack.ss_sp);
387 err |= __put_user(sas_ss_flags(regs->sp),
388 &frame->uc.uc_stack.ss_flags);
389 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
390 err |= setup_sigcontext(&frame->uc.uc_mcontext, regs);
391 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
392 if (err)
393 goto give_sigsegv;
394
395 restorer = VDSO_BASE;
396 if (ka->sa.sa_flags & SA_RESTORER)
397 restorer = ptr_to_compat_reg(ka->sa.sa_restorer);
398
399
400
401
402
403
404
405
406 regs->pc = ptr_to_compat_reg(ka->sa.sa_handler);
407 regs->ex1 = PL_ICS_EX1(USER_PL, 1);
408 regs->sp = ptr_to_compat_reg(frame);
409 regs->lr = restorer;
410 regs->regs[0] = (unsigned long) usig;
411 regs->regs[1] = ptr_to_compat_reg(&frame->info);
412 regs->regs[2] = ptr_to_compat_reg(&frame->uc);
413 regs->flags |= PT_FLAGS_CALLER_SAVES;
414
415
416
417
418
419
420 if (test_thread_flag(TIF_SINGLESTEP))
421 ptrace_notify(SIGTRAP);
422
423 return 0;
424
425give_sigsegv:
426 signal_fault("bad setup frame", regs, frame, sig);
427 return -EFAULT;
428}
429