Root/
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/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 | |
37 | struct 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 | |
44 | struct compat_sigaltstack { |
45 | compat_uptr_t ss_sp; |
46 | int ss_flags; |
47 | compat_size_t ss_size; |
48 | }; |
49 | |
50 | struct 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 | |
58 | #define COMPAT_SI_PAD_SIZE ((SI_MAX_SIZE - 3 * sizeof(int)) / sizeof(int)) |
59 | |
60 | struct 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 | /* kill() */ |
69 | struct { |
70 | unsigned int _pid; /* sender's pid */ |
71 | unsigned int _uid; /* sender's uid */ |
72 | } _kill; |
73 | |
74 | /* POSIX.1b timers */ |
75 | struct { |
76 | compat_timer_t _tid; /* timer id */ |
77 | int _overrun; /* overrun count */ |
78 | compat_sigval_t _sigval; /* same as below */ |
79 | int _sys_private; /* not to be passed to user */ |
80 | int _overrun_incr; /* amount to add to overrun */ |
81 | } _timer; |
82 | |
83 | /* POSIX.1b signals */ |
84 | struct { |
85 | unsigned int _pid; /* sender's pid */ |
86 | unsigned int _uid; /* sender's uid */ |
87 | compat_sigval_t _sigval; |
88 | } _rt; |
89 | |
90 | /* SIGCHLD */ |
91 | struct { |
92 | unsigned int _pid; /* which child */ |
93 | unsigned int _uid; /* sender's uid */ |
94 | int _status; /* exit code */ |
95 | compat_clock_t _utime; |
96 | compat_clock_t _stime; |
97 | } _sigchld; |
98 | |
99 | /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ |
100 | struct { |
101 | unsigned int _addr; /* faulting insn/memory ref. */ |
102 | #ifdef __ARCH_SI_TRAPNO |
103 | int _trapno; /* TRAP # which caused the signal */ |
104 | #endif |
105 | } _sigfault; |
106 | |
107 | /* SIGPOLL */ |
108 | struct { |
109 | int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ |
110 | int _fd; |
111 | } _sigpoll; |
112 | } _sifields; |
113 | }; |
114 | |
115 | struct compat_rt_sigframe { |
116 | unsigned char save_area[C_ABI_SAVE_AREA_SIZE]; /* caller save area */ |
117 | struct compat_siginfo info; |
118 | struct compat_ucontext uc; |
119 | }; |
120 | |
121 | long 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 | /* XXX: Don't preclude handling different sized sigset_t's. */ |
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 | } |
159 | out: |
160 | return ret; |
161 | } |
162 | |
163 | long 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 | |
178 | int 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 | /* If you change siginfo_t structure, please make sure that |
186 | this code is fixed accordingly. |
187 | It should never copy any pad contained in the structure |
188 | to avoid security leaks, but must copy the generic |
189 | 3 ints plus the relevant union member. */ |
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 | * First 32bits of unions are always present: |
201 | * si_pid === si_band === si_tid === si_addr(LS half) |
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 | /* FALL THROUGH */ |
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 | /* This is not generated by the kernel as of now. */ |
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 | |
236 | int 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 | |
256 | long 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 | /* The assembly shim for this function arranges to ignore the return value. */ |
292 | long 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 | |
313 | badframe: |
314 | signal_fault("bad sigreturn frame", regs, frame, 0); |
315 | return 0; |
316 | } |
317 | |
318 | /* |
319 | * Determine which stack to use.. |
320 | */ |
321 | static 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 | /* Default to using normal stack */ |
328 | sp = (unsigned long)compat_ptr(regs->sp); |
329 | |
330 | /* |
331 | * If we are on the alternate signal stack and would overflow |
332 | * it, don't. Return an always-bogus address instead so we |
333 | * will die with SIGSEGV. |
334 | */ |
335 | if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size))) |
336 | return (void __user __force *)-1UL; |
337 | |
338 | /* This is the X/Open sanctioned signal stack switching. */ |
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 | * Align the stack pointer according to the TILE ABI, |
347 | * i.e. so that on function entry (sp & 15) == 0. |
348 | */ |
349 | sp &= -16UL; |
350 | return (void __user *) sp; |
351 | } |
352 | |
353 | int 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 | /* Always write at least the signal number for the stack backtracer. */ |
373 | if (ka->sa.sa_flags & SA_SIGINFO) { |
374 | /* At sigreturn time, restore the callee-save registers too. */ |
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 | /* Create the ucontext. */ |
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 | * Set up registers for signal handler. |
401 | * Registers that we don't modify keep the value they had from |
402 | * user-space at the time we took the signal. |
403 | * We always pass siginfo and mcontext, regardless of SA_SIGINFO, |
404 | * since some things rely on this (e.g. glibc's debug/segfault.c). |
405 | */ |
406 | regs->pc = ptr_to_compat_reg(ka->sa.sa_handler); |
407 | regs->ex1 = PL_ICS_EX1(USER_PL, 1); /* set crit sec in handler */ |
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 | * Notify any tracer that was single-stepping it. |
417 | * The tracer may want to single-step inside the |
418 | * handler too. |
419 | */ |
420 | if (test_thread_flag(TIF_SINGLESTEP)) |
421 | ptrace_notify(SIGTRAP); |
422 | |
423 | return 0; |
424 | |
425 | give_sigsegv: |
426 | signal_fault("bad setup frame", regs, frame, sig); |
427 | return -EFAULT; |
428 | } |
429 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9