aboutsummaryrefslogtreecommitdiffstats
path: root/arch/tile/kernel/compat_signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/tile/kernel/compat_signal.c')
-rw-r--r--arch/tile/kernel/compat_signal.c435
1 files changed, 435 insertions, 0 deletions
diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c
new file mode 100644
index 00000000000..d5efb215dd5
--- /dev/null
+++ b/arch/tile/kernel/compat_signal.c
@@ -0,0 +1,435 @@
1/*
2 * Copyright 2010 Tilera Corporation. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation, version 2.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
11 * NON INFRINGEMENT. See the GNU General Public License for
12 * more details.
13 */
14
15#include <linux/sched.h>
16#include <linux/mm.h>
17#include <linux/smp.h>
18#include <linux/smp_lock.h>
19#include <linux/kernel.h>
20#include <linux/signal.h>
21#include <linux/errno.h>
22#include <linux/wait.h>
23#include <linux/unistd.h>
24#include <linux/stddef.h>
25#include <linux/personality.h>
26#include <linux/suspend.h>
27#include <linux/ptrace.h>
28#include <linux/elf.h>
29#include <linux/compat.h>
30#include <linux/syscalls.h>
31#include <linux/uaccess.h>
32#include <asm/processor.h>
33#include <asm/ucontext.h>
34#include <asm/sigframe.h>
35#include <asm/syscalls.h>
36#include <arch/interrupts.h>
37
38struct compat_sigaction {
39 compat_uptr_t sa_handler;
40 compat_ulong_t sa_flags;
41 compat_uptr_t sa_restorer;
42 sigset_t sa_mask __packed;
43};
44
45struct compat_sigaltstack {
46 compat_uptr_t ss_sp;
47 int ss_flags;
48 compat_size_t ss_size;
49};
50
51struct compat_ucontext {
52 compat_ulong_t uc_flags;
53 compat_uptr_t uc_link;
54 struct compat_sigaltstack uc_stack;
55 struct sigcontext uc_mcontext;
56 sigset_t uc_sigmask; /* mask last for extensibility */
57};
58
59struct compat_siginfo {
60 int si_signo;
61 int si_errno;
62 int si_code;
63
64 union {
65 int _pad[SI_PAD_SIZE];
66
67 /* kill() */
68 struct {
69 unsigned int _pid; /* sender's pid */
70 unsigned int _uid; /* sender's uid */
71 } _kill;
72
73 /* POSIX.1b timers */
74 struct {
75 compat_timer_t _tid; /* timer id */
76 int _overrun; /* overrun count */
77 compat_sigval_t _sigval; /* same as below */
78 int _sys_private; /* not to be passed to user */
79 int _overrun_incr; /* amount to add to overrun */
80 } _timer;
81
82 /* POSIX.1b signals */
83 struct {
84 unsigned int _pid; /* sender's pid */
85 unsigned int _uid; /* sender's uid */
86 compat_sigval_t _sigval;
87 } _rt;
88
89 /* SIGCHLD */
90 struct {
91 unsigned int _pid; /* which child */
92 unsigned int _uid; /* sender's uid */
93 int _status; /* exit code */
94 compat_clock_t _utime;
95 compat_clock_t _stime;
96 } _sigchld;
97
98 /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
99 struct {
100 unsigned int _addr; /* faulting insn/memory ref. */
101#ifdef __ARCH_SI_TRAPNO
102 int _trapno; /* TRAP # which caused the signal */
103#endif
104 } _sigfault;
105
106 /* SIGPOLL */
107 struct {
108 int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
109 int _fd;
110 } _sigpoll;
111 } _sifields;
112};
113
114struct compat_rt_sigframe {
115 unsigned char save_area[C_ABI_SAVE_AREA_SIZE]; /* caller save area */
116 struct compat_siginfo info;
117 struct compat_ucontext uc;
118};
119
120#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
121
122long compat_sys_rt_sigaction(int sig, struct compat_sigaction __user *act,
123 struct compat_sigaction __user *oact,
124 size_t sigsetsize)
125{
126 struct k_sigaction new_sa, old_sa;
127 int ret = -EINVAL;
128
129 /* XXX: Don't preclude handling different sized sigset_t's. */
130 if (sigsetsize != sizeof(sigset_t))
131 goto out;
132
133 if (act) {
134 compat_uptr_t handler, restorer;
135
136 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
137 __get_user(handler, &act->sa_handler) ||
138 __get_user(new_sa.sa.sa_flags, &act->sa_flags) ||
139 __get_user(restorer, &act->sa_restorer) ||
140 __copy_from_user(&new_sa.sa.sa_mask, &act->sa_mask,
141 sizeof(sigset_t)))
142 return -EFAULT;
143 new_sa.sa.sa_handler = compat_ptr(handler);
144 new_sa.sa.sa_restorer = compat_ptr(restorer);
145 }
146
147 ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
148
149 if (!ret && oact) {
150 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
151 __put_user(ptr_to_compat(old_sa.sa.sa_handler),
152 &oact->sa_handler) ||
153 __put_user(ptr_to_compat(old_sa.sa.sa_restorer),
154 &oact->sa_restorer) ||
155 __put_user(old_sa.sa.sa_flags, &oact->sa_flags) ||
156 __copy_to_user(&oact->sa_mask, &old_sa.sa.sa_mask,
157 sizeof(sigset_t)))
158 return -EFAULT;
159 }
160out:
161 return ret;
162}
163
164long compat_sys_rt_sigqueueinfo(int pid, int sig,
165 struct compat_siginfo __user *uinfo)
166{
167 siginfo_t info;
168 int ret;
169 mm_segment_t old_fs = get_fs();
170
171 if (copy_siginfo_from_user32(&info, uinfo))
172 return -EFAULT;
173 set_fs(KERNEL_DS);
174 ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __force __user *)&info);
175 set_fs(old_fs);
176 return ret;
177}
178
179int copy_siginfo_to_user32(struct compat_siginfo __user *to, siginfo_t *from)
180{
181 int err;
182
183 if (!access_ok(VERIFY_WRITE, to, sizeof(struct compat_siginfo)))
184 return -EFAULT;
185
186 /* If you change siginfo_t structure, please make sure that
187 this code is fixed accordingly.
188 It should never copy any pad contained in the structure
189 to avoid security leaks, but must copy the generic
190 3 ints plus the relevant union member. */
191 err = __put_user(from->si_signo, &to->si_signo);
192 err |= __put_user(from->si_errno, &to->si_errno);
193 err |= __put_user((short)from->si_code, &to->si_code);
194
195 if (from->si_code < 0) {
196 err |= __put_user(from->si_pid, &to->si_pid);
197 err |= __put_user(from->si_uid, &to->si_uid);
198 err |= __put_user(ptr_to_compat(from->si_ptr), &to->si_ptr);
199 } else {
200 /*
201 * First 32bits of unions are always present:
202 * si_pid === si_band === si_tid === si_addr(LS half)
203 */
204 err |= __put_user(from->_sifields._pad[0],
205 &to->_sifields._pad[0]);
206 switch (from->si_code >> 16) {
207 case __SI_FAULT >> 16:
208 break;
209 case __SI_CHLD >> 16:
210 err |= __put_user(from->si_utime, &to->si_utime);
211 err |= __put_user(from->si_stime, &to->si_stime);
212 err |= __put_user(from->si_status, &to->si_status);
213 /* FALL THROUGH */
214 default:
215 case __SI_KILL >> 16:
216 err |= __put_user(from->si_uid, &to->si_uid);
217 break;
218 case __SI_POLL >> 16:
219 err |= __put_user(from->si_fd, &to->si_fd);
220 break;
221 case __SI_TIMER >> 16:
222 err |= __put_user(from->si_overrun, &to->si_overrun);
223 err |= __put_user(ptr_to_compat(from->si_ptr),
224 &to->si_ptr);
225 break;
226 /* This is not generated by the kernel as of now. */
227 case __SI_RT >> 16:
228 case __SI_MESGQ >> 16:
229 err |= __put_user(from->si_uid, &to->si_uid);
230 err |= __put_user(from->si_int, &to->si_int);
231 break;
232 }
233 }
234 return err;
235}
236
237int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
238{
239 int err;
240 u32 ptr32;
241
242 if (!access_ok(VERIFY_READ, from, sizeof(struct compat_siginfo)))
243 return -EFAULT;
244
245 err = __get_user(to->si_signo, &from->si_signo);
246 err |= __get_user(to->si_errno, &from->si_errno);
247 err |= __get_user(to->si_code, &from->si_code);
248
249 err |= __get_user(to->si_pid, &from->si_pid);
250 err |= __get_user(to->si_uid, &from->si_uid);
251 err |= __get_user(ptr32, &from->si_ptr);
252 to->si_ptr = compat_ptr(ptr32);
253
254 return err;
255}
256
257long _compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
258 struct compat_sigaltstack __user *uoss_ptr,
259 struct pt_regs *regs)
260{
261 stack_t uss, uoss;
262 int ret;
263 mm_segment_t seg;
264
265 if (uss_ptr) {
266 u32 ptr;
267
268 memset(&uss, 0, sizeof(stack_t));
269 if (!access_ok(VERIFY_READ, uss_ptr, sizeof(*uss_ptr)) ||
270 __get_user(ptr, &uss_ptr->ss_sp) ||
271 __get_user(uss.ss_flags, &uss_ptr->ss_flags) ||
272 __get_user(uss.ss_size, &uss_ptr->ss_size))
273 return -EFAULT;
274 uss.ss_sp = compat_ptr(ptr);
275 }
276 seg = get_fs();
277 set_fs(KERNEL_DS);
278 ret = do_sigaltstack(uss_ptr ? (stack_t __user __force *)&uss : NULL,
279 (stack_t __user __force *)&uoss,
280 (unsigned long)compat_ptr(regs->sp));
281 set_fs(seg);
282 if (ret >= 0 && uoss_ptr) {
283 if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(*uoss_ptr)) ||
284 __put_user(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp) ||
285 __put_user(uoss.ss_flags, &uoss_ptr->ss_flags) ||
286 __put_user(uoss.ss_size, &uoss_ptr->ss_size))
287 ret = -EFAULT;
288 }
289 return ret;
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 long r0;
298
299 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
300 goto badframe;
301 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
302 goto badframe;
303
304 sigdelsetmask(&set, ~_BLOCKABLE);
305 spin_lock_irq(&current->sighand->siglock);
306 current->blocked = set;
307 recalc_sigpending();
308 spin_unlock_irq(&current->sighand->siglock);
309
310 if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
311 goto badframe;
312
313 if (_compat_sys_sigaltstack(&frame->uc.uc_stack, NULL, regs) != 0)
314 goto badframe;
315
316 return r0;
317
318badframe:
319 force_sig(SIGSEGV, current);
320 return 0;
321}
322
323/*
324 * Determine which stack to use..
325 */
326static inline void __user *compat_get_sigframe(struct k_sigaction *ka,
327 struct pt_regs *regs,
328 size_t frame_size)
329{
330 unsigned long sp;
331
332 /* Default to using normal stack */
333 sp = (unsigned long)compat_ptr(regs->sp);
334
335 /*
336 * If we are on the alternate signal stack and would overflow
337 * it, don't. Return an always-bogus address instead so we
338 * will die with SIGSEGV.
339 */
340 if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size)))
341 return (void __user __force *)-1UL;
342
343 /* This is the X/Open sanctioned signal stack switching. */
344 if (ka->sa.sa_flags & SA_ONSTACK) {
345 if (sas_ss_flags(sp) == 0)
346 sp = current->sas_ss_sp + current->sas_ss_size;
347 }
348
349 sp -= frame_size;
350 /*
351 * Align the stack pointer according to the TILE ABI,
352 * i.e. so that on function entry (sp & 15) == 0.
353 */
354 sp &= -16UL;
355 return (void __user *) sp;
356}
357
358int compat_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
359 sigset_t *set, struct pt_regs *regs)
360{
361 unsigned long restorer;
362 struct compat_rt_sigframe __user *frame;
363 int err = 0;
364 int usig;
365
366 frame = compat_get_sigframe(ka, regs, sizeof(*frame));
367
368 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
369 goto give_sigsegv;
370
371 usig = current_thread_info()->exec_domain
372 && current_thread_info()->exec_domain->signal_invmap
373 && sig < 32
374 ? current_thread_info()->exec_domain->signal_invmap[sig]
375 : sig;
376
377 /* Always write at least the signal number for the stack backtracer. */
378 if (ka->sa.sa_flags & SA_SIGINFO) {
379 /* At sigreturn time, restore the callee-save registers too. */
380 err |= copy_siginfo_to_user32(&frame->info, info);
381 regs->flags |= PT_FLAGS_RESTORE_REGS;
382 } else {
383 err |= __put_user(info->si_signo, &frame->info.si_signo);
384 }
385
386 /* Create the ucontext. */
387 err |= __clear_user(&frame->save_area, sizeof(frame->save_area));
388 err |= __put_user(0, &frame->uc.uc_flags);
389 err |= __put_user(0, &frame->uc.uc_link);
390 err |= __put_user(ptr_to_compat((void *)(current->sas_ss_sp)),
391 &frame->uc.uc_stack.ss_sp);
392 err |= __put_user(sas_ss_flags(regs->sp),
393 &frame->uc.uc_stack.ss_flags);
394 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
395 err |= setup_sigcontext(&frame->uc.uc_mcontext, regs);
396 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
397 if (err)
398 goto give_sigsegv;
399
400 restorer = VDSO_BASE;
401 if (ka->sa.sa_flags & SA_RESTORER)
402 restorer = ptr_to_compat_reg(ka->sa.sa_restorer);
403
404 /*
405 * Set up registers for signal handler.
406 * Registers that we don't modify keep the value they had from
407 * user-space at the time we took the signal.
408 */
409 regs->pc = ptr_to_compat_reg(ka->sa.sa_handler);
410 regs->ex1 = PL_ICS_EX1(USER_PL, 1); /* set crit sec in handler */
411 regs->sp = ptr_to_compat_reg(frame);
412 regs->lr = restorer;
413 regs->regs[0] = (unsigned long) usig;
414
415 if (ka->sa.sa_flags & SA_SIGINFO) {
416 /* Need extra arguments, so mark to restore caller-saves. */
417 regs->regs[1] = ptr_to_compat_reg(&frame->info);
418 regs->regs[2] = ptr_to_compat_reg(&frame->uc);
419 regs->flags |= PT_FLAGS_CALLER_SAVES;
420 }
421
422 /*
423 * Notify any tracer that was single-stepping it.
424 * The tracer may want to single-step inside the
425 * handler too.
426 */
427 if (test_thread_flag(TIF_SINGLESTEP))
428 ptrace_notify(SIGTRAP);
429
430 return 0;
431
432give_sigsegv:
433 force_sigsegv(sig, current);
434 return -EFAULT;
435}