arch/tile: implement arch_ptrace using user_regset on tile
[deliverable/linux.git] / arch / tile / kernel / compat_signal.c
CommitLineData
867e359b
CM
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>
867e359b
CM
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>
0707ad30 34#include <asm/syscalls.h>
867e359b
CM
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;
0707ad30 41 sigset_t sa_mask __packed;
867e359b
CM
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; /* mask last for extensibility */
56};
57
867e359b
CM
58struct compat_rt_sigframe {
59 unsigned char save_area[C_ABI_SAVE_AREA_SIZE]; /* caller save area */
60 struct compat_siginfo info;
61 struct compat_ucontext uc;
62};
63
867e359b
CM
64long compat_sys_rt_sigaction(int sig, struct compat_sigaction __user *act,
65 struct compat_sigaction __user *oact,
66 size_t sigsetsize)
67{
68 struct k_sigaction new_sa, old_sa;
69 int ret = -EINVAL;
70
71 /* XXX: Don't preclude handling different sized sigset_t's. */
72 if (sigsetsize != sizeof(sigset_t))
73 goto out;
74
75 if (act) {
76 compat_uptr_t handler, restorer;
77
78 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
79 __get_user(handler, &act->sa_handler) ||
80 __get_user(new_sa.sa.sa_flags, &act->sa_flags) ||
81 __get_user(restorer, &act->sa_restorer) ||
82 __copy_from_user(&new_sa.sa.sa_mask, &act->sa_mask,
83 sizeof(sigset_t)))
84 return -EFAULT;
85 new_sa.sa.sa_handler = compat_ptr(handler);
86 new_sa.sa.sa_restorer = compat_ptr(restorer);
87 }
88
89 ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
90
91 if (!ret && oact) {
92 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
93 __put_user(ptr_to_compat(old_sa.sa.sa_handler),
94 &oact->sa_handler) ||
95 __put_user(ptr_to_compat(old_sa.sa.sa_restorer),
96 &oact->sa_restorer) ||
97 __put_user(old_sa.sa.sa_flags, &oact->sa_flags) ||
98 __copy_to_user(&oact->sa_mask, &old_sa.sa.sa_mask,
99 sizeof(sigset_t)))
100 return -EFAULT;
101 }
102out:
103 return ret;
104}
105
106long compat_sys_rt_sigqueueinfo(int pid, int sig,
107 struct compat_siginfo __user *uinfo)
108{
109 siginfo_t info;
110 int ret;
111 mm_segment_t old_fs = get_fs();
112
113 if (copy_siginfo_from_user32(&info, uinfo))
114 return -EFAULT;
115 set_fs(KERNEL_DS);
0707ad30 116 ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __force __user *)&info);
867e359b
CM
117 set_fs(old_fs);
118 return ret;
119}
120
121int copy_siginfo_to_user32(struct compat_siginfo __user *to, siginfo_t *from)
122{
123 int err;
124
125 if (!access_ok(VERIFY_WRITE, to, sizeof(struct compat_siginfo)))
126 return -EFAULT;
127
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 err = __put_user(from->si_signo, &to->si_signo);
134 err |= __put_user(from->si_errno, &to->si_errno);
135 err |= __put_user((short)from->si_code, &to->si_code);
136
137 if (from->si_code < 0) {
138 err |= __put_user(from->si_pid, &to->si_pid);
139 err |= __put_user(from->si_uid, &to->si_uid);
140 err |= __put_user(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 err |= __put_user(from->_sifields._pad[0],
147 &to->_sifields._pad[0]);
148 switch (from->si_code >> 16) {
149 case __SI_FAULT >> 16:
150 break;
151 case __SI_CHLD >> 16:
152 err |= __put_user(from->si_utime, &to->si_utime);
153 err |= __put_user(from->si_stime, &to->si_stime);
154 err |= __put_user(from->si_status, &to->si_status);
155 /* FALL THROUGH */
156 default:
157 case __SI_KILL >> 16:
158 err |= __put_user(from->si_uid, &to->si_uid);
159 break;
160 case __SI_POLL >> 16:
161 err |= __put_user(from->si_fd, &to->si_fd);
162 break;
163 case __SI_TIMER >> 16:
164 err |= __put_user(from->si_overrun, &to->si_overrun);
165 err |= __put_user(ptr_to_compat(from->si_ptr),
166 &to->si_ptr);
167 break;
168 /* This is not generated by the kernel as of now. */
169 case __SI_RT >> 16:
170 case __SI_MESGQ >> 16:
171 err |= __put_user(from->si_uid, &to->si_uid);
172 err |= __put_user(from->si_int, &to->si_int);
173 break;
174 }
175 }
176 return err;
177}
178
179int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
180{
181 int err;
182 u32 ptr32;
183
184 if (!access_ok(VERIFY_READ, from, sizeof(struct compat_siginfo)))
185 return -EFAULT;
186
187 err = __get_user(to->si_signo, &from->si_signo);
188 err |= __get_user(to->si_errno, &from->si_errno);
189 err |= __get_user(to->si_code, &from->si_code);
190
191 err |= __get_user(to->si_pid, &from->si_pid);
192 err |= __get_user(to->si_uid, &from->si_uid);
193 err |= __get_user(ptr32, &from->si_ptr);
194 to->si_ptr = compat_ptr(ptr32);
195
196 return err;
197}
198
d929b6ae
CM
199long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
200 struct compat_sigaltstack __user *uoss_ptr,
201 struct pt_regs *regs)
867e359b
CM
202{
203 stack_t uss, uoss;
204 int ret;
205 mm_segment_t seg;
206
207 if (uss_ptr) {
208 u32 ptr;
209
210 memset(&uss, 0, sizeof(stack_t));
211 if (!access_ok(VERIFY_READ, uss_ptr, sizeof(*uss_ptr)) ||
212 __get_user(ptr, &uss_ptr->ss_sp) ||
213 __get_user(uss.ss_flags, &uss_ptr->ss_flags) ||
214 __get_user(uss.ss_size, &uss_ptr->ss_size))
215 return -EFAULT;
216 uss.ss_sp = compat_ptr(ptr);
217 }
218 seg = get_fs();
219 set_fs(KERNEL_DS);
0707ad30
CM
220 ret = do_sigaltstack(uss_ptr ? (stack_t __user __force *)&uss : NULL,
221 (stack_t __user __force *)&uoss,
867e359b
CM
222 (unsigned long)compat_ptr(regs->sp));
223 set_fs(seg);
224 if (ret >= 0 && uoss_ptr) {
225 if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(*uoss_ptr)) ||
226 __put_user(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp) ||
227 __put_user(uoss.ss_flags, &uoss_ptr->ss_flags) ||
228 __put_user(uoss.ss_size, &uoss_ptr->ss_size))
229 ret = -EFAULT;
230 }
231 return ret;
232}
233
81711cee 234/* The assembly shim for this function arranges to ignore the return value. */
d929b6ae 235long compat_sys_rt_sigreturn(struct pt_regs *regs)
867e359b
CM
236{
237 struct compat_rt_sigframe __user *frame =
238 (struct compat_rt_sigframe __user *) compat_ptr(regs->sp);
239 sigset_t set;
867e359b
CM
240
241 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
242 goto badframe;
243 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
244 goto badframe;
245
ad092338 246 set_current_blocked(&set);
867e359b 247
81711cee 248 if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
867e359b
CM
249 goto badframe;
250
d929b6ae 251 if (compat_sys_sigaltstack(&frame->uc.uc_stack, NULL, regs) != 0)
867e359b
CM
252 goto badframe;
253
81711cee 254 return 0;
867e359b
CM
255
256badframe:
571d76ac 257 signal_fault("bad sigreturn frame", regs, frame, 0);
867e359b
CM
258 return 0;
259}
260
261/*
262 * Determine which stack to use..
263 */
264static inline void __user *compat_get_sigframe(struct k_sigaction *ka,
265 struct pt_regs *regs,
266 size_t frame_size)
267{
268 unsigned long sp;
269
270 /* Default to using normal stack */
271 sp = (unsigned long)compat_ptr(regs->sp);
272
273 /*
274 * If we are on the alternate signal stack and would overflow
275 * it, don't. Return an always-bogus address instead so we
276 * will die with SIGSEGV.
277 */
278 if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size)))
0707ad30 279 return (void __user __force *)-1UL;
867e359b
CM
280
281 /* This is the X/Open sanctioned signal stack switching. */
282 if (ka->sa.sa_flags & SA_ONSTACK) {
283 if (sas_ss_flags(sp) == 0)
284 sp = current->sas_ss_sp + current->sas_ss_size;
285 }
286
287 sp -= frame_size;
288 /*
289 * Align the stack pointer according to the TILE ABI,
290 * i.e. so that on function entry (sp & 15) == 0.
291 */
292 sp &= -16UL;
293 return (void __user *) sp;
294}
295
296int compat_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
297 sigset_t *set, struct pt_regs *regs)
298{
299 unsigned long restorer;
300 struct compat_rt_sigframe __user *frame;
301 int err = 0;
302 int usig;
303
304 frame = compat_get_sigframe(ka, regs, sizeof(*frame));
305
306 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
307 goto give_sigsegv;
308
309 usig = current_thread_info()->exec_domain
310 && current_thread_info()->exec_domain->signal_invmap
311 && sig < 32
312 ? current_thread_info()->exec_domain->signal_invmap[sig]
313 : sig;
314
315 /* Always write at least the signal number for the stack backtracer. */
316 if (ka->sa.sa_flags & SA_SIGINFO) {
317 /* At sigreturn time, restore the callee-save registers too. */
318 err |= copy_siginfo_to_user32(&frame->info, info);
319 regs->flags |= PT_FLAGS_RESTORE_REGS;
320 } else {
321 err |= __put_user(info->si_signo, &frame->info.si_signo);
322 }
323
324 /* Create the ucontext. */
325 err |= __clear_user(&frame->save_area, sizeof(frame->save_area));
326 err |= __put_user(0, &frame->uc.uc_flags);
327 err |= __put_user(0, &frame->uc.uc_link);
328 err |= __put_user(ptr_to_compat((void *)(current->sas_ss_sp)),
329 &frame->uc.uc_stack.ss_sp);
330 err |= __put_user(sas_ss_flags(regs->sp),
331 &frame->uc.uc_stack.ss_flags);
332 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
333 err |= setup_sigcontext(&frame->uc.uc_mcontext, regs);
334 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
335 if (err)
336 goto give_sigsegv;
337
338 restorer = VDSO_BASE;
339 if (ka->sa.sa_flags & SA_RESTORER)
340 restorer = ptr_to_compat_reg(ka->sa.sa_restorer);
341
342 /*
343 * Set up registers for signal handler.
344 * Registers that we don't modify keep the value they had from
345 * user-space at the time we took the signal.
a134d228
CM
346 * We always pass siginfo and mcontext, regardless of SA_SIGINFO,
347 * since some things rely on this (e.g. glibc's debug/segfault.c).
867e359b
CM
348 */
349 regs->pc = ptr_to_compat_reg(ka->sa.sa_handler);
350 regs->ex1 = PL_ICS_EX1(USER_PL, 1); /* set crit sec in handler */
351 regs->sp = ptr_to_compat_reg(frame);
352 regs->lr = restorer;
353 regs->regs[0] = (unsigned long) usig;
a134d228
CM
354 regs->regs[1] = ptr_to_compat_reg(&frame->info);
355 regs->regs[2] = ptr_to_compat_reg(&frame->uc);
356 regs->flags |= PT_FLAGS_CALLER_SAVES;
867e359b
CM
357 return 0;
358
359give_sigsegv:
571d76ac 360 signal_fault("bad setup frame", regs, frame, sig);
867e359b
CM
361 return -EFAULT;
362}
This page took 0.203841 seconds and 5 git commands to generate.