diff options
Diffstat (limited to 'arch/x86/kernel/signal_64.c')
-rw-r--r-- | arch/x86/kernel/signal_64.c | 112 |
1 files changed, 45 insertions, 67 deletions
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c index ca316b5b742c..694aa888bb19 100644 --- a/arch/x86/kernel/signal_64.c +++ b/arch/x86/kernel/signal_64.c | |||
@@ -15,17 +15,21 @@ | |||
15 | #include <linux/errno.h> | 15 | #include <linux/errno.h> |
16 | #include <linux/wait.h> | 16 | #include <linux/wait.h> |
17 | #include <linux/ptrace.h> | 17 | #include <linux/ptrace.h> |
18 | #include <linux/tracehook.h> | ||
18 | #include <linux/unistd.h> | 19 | #include <linux/unistd.h> |
19 | #include <linux/stddef.h> | 20 | #include <linux/stddef.h> |
20 | #include <linux/personality.h> | 21 | #include <linux/personality.h> |
21 | #include <linux/compiler.h> | 22 | #include <linux/compiler.h> |
23 | #include <linux/uaccess.h> | ||
24 | |||
22 | #include <asm/processor.h> | 25 | #include <asm/processor.h> |
23 | #include <asm/ucontext.h> | 26 | #include <asm/ucontext.h> |
24 | #include <asm/uaccess.h> | ||
25 | #include <asm/i387.h> | 27 | #include <asm/i387.h> |
26 | #include <asm/proto.h> | 28 | #include <asm/proto.h> |
27 | #include <asm/ia32_unistd.h> | 29 | #include <asm/ia32_unistd.h> |
28 | #include <asm/mce.h> | 30 | #include <asm/mce.h> |
31 | #include <asm/syscall.h> | ||
32 | #include <asm/syscalls.h> | ||
29 | #include "sigframe.h" | 33 | #include "sigframe.h" |
30 | 34 | ||
31 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 35 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
@@ -41,11 +45,6 @@ | |||
41 | # define FIX_EFLAGS __FIX_EFLAGS | 45 | # define FIX_EFLAGS __FIX_EFLAGS |
42 | #endif | 46 | #endif |
43 | 47 | ||
44 | int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | ||
45 | sigset_t *set, struct pt_regs * regs); | ||
46 | int ia32_setup_frame(int sig, struct k_sigaction *ka, | ||
47 | sigset_t *set, struct pt_regs * regs); | ||
48 | |||
49 | asmlinkage long | 48 | asmlinkage long |
50 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | 49 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, |
51 | struct pt_regs *regs) | 50 | struct pt_regs *regs) |
@@ -128,7 +127,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | |||
128 | /* Always make any pending restarted system calls return -EINTR */ | 127 | /* Always make any pending restarted system calls return -EINTR */ |
129 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | 128 | current_thread_info()->restart_block.fn = do_no_restart_syscall; |
130 | 129 | ||
131 | #define COPY(x) err |= __get_user(regs->x, &sc->x) | 130 | #define COPY(x) (err |= __get_user(regs->x, &sc->x)) |
132 | 131 | ||
133 | COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); | 132 | COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); |
134 | COPY(dx); COPY(cx); COPY(ip); | 133 | COPY(dx); COPY(cx); COPY(ip); |
@@ -158,7 +157,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | |||
158 | } | 157 | } |
159 | 158 | ||
160 | { | 159 | { |
161 | struct _fpstate __user * buf; | 160 | struct _fpstate __user *buf; |
162 | err |= __get_user(buf, &sc->fpstate); | 161 | err |= __get_user(buf, &sc->fpstate); |
163 | 162 | ||
164 | if (buf) { | 163 | if (buf) { |
@@ -198,7 +197,7 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | |||
198 | current->blocked = set; | 197 | current->blocked = set; |
199 | recalc_sigpending(); | 198 | recalc_sigpending(); |
200 | spin_unlock_irq(¤t->sighand->siglock); | 199 | spin_unlock_irq(¤t->sighand->siglock); |
201 | 200 | ||
202 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) | 201 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) |
203 | goto badframe; | 202 | goto badframe; |
204 | 203 | ||
@@ -208,16 +207,17 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | |||
208 | return ax; | 207 | return ax; |
209 | 208 | ||
210 | badframe: | 209 | badframe: |
211 | signal_fault(regs,frame,"sigreturn"); | 210 | signal_fault(regs, frame, "sigreturn"); |
212 | return 0; | 211 | return 0; |
213 | } | 212 | } |
214 | 213 | ||
215 | /* | 214 | /* |
216 | * Set up a signal frame. | 215 | * Set up a signal frame. |
217 | */ | 216 | */ |
218 | 217 | ||
219 | static inline int | 218 | static inline int |
220 | setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned long mask, struct task_struct *me) | 219 | setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, |
220 | unsigned long mask, struct task_struct *me) | ||
221 | { | 221 | { |
222 | int err = 0; | 222 | int err = 0; |
223 | 223 | ||
@@ -273,35 +273,35 @@ get_stack(struct k_sigaction *ka, struct pt_regs *regs, unsigned long size) | |||
273 | } | 273 | } |
274 | 274 | ||
275 | static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 275 | static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
276 | sigset_t *set, struct pt_regs * regs) | 276 | sigset_t *set, struct pt_regs *regs) |
277 | { | 277 | { |
278 | struct rt_sigframe __user *frame; | 278 | struct rt_sigframe __user *frame; |
279 | struct _fpstate __user *fp = NULL; | 279 | struct _fpstate __user *fp = NULL; |
280 | int err = 0; | 280 | int err = 0; |
281 | struct task_struct *me = current; | 281 | struct task_struct *me = current; |
282 | 282 | ||
283 | if (used_math()) { | 283 | if (used_math()) { |
284 | fp = get_stack(ka, regs, sizeof(struct _fpstate)); | 284 | fp = get_stack(ka, regs, sizeof(struct _fpstate)); |
285 | frame = (void __user *)round_down( | 285 | frame = (void __user *)round_down( |
286 | (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8; | 286 | (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8; |
287 | 287 | ||
288 | if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) | 288 | if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) |
289 | goto give_sigsegv; | 289 | goto give_sigsegv; |
290 | 290 | ||
291 | if (save_i387(fp) < 0) | 291 | if (save_i387(fp) < 0) |
292 | err |= -1; | 292 | err |= -1; |
293 | } else | 293 | } else |
294 | frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8; | 294 | frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8; |
295 | 295 | ||
296 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 296 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
297 | goto give_sigsegv; | 297 | goto give_sigsegv; |
298 | 298 | ||
299 | if (ka->sa.sa_flags & SA_SIGINFO) { | 299 | if (ka->sa.sa_flags & SA_SIGINFO) { |
300 | err |= copy_siginfo_to_user(&frame->info, info); | 300 | err |= copy_siginfo_to_user(&frame->info, info); |
301 | if (err) | 301 | if (err) |
302 | goto give_sigsegv; | 302 | goto give_sigsegv; |
303 | } | 303 | } |
304 | 304 | ||
305 | /* Create the ucontext. */ | 305 | /* Create the ucontext. */ |
306 | err |= __put_user(0, &frame->uc.uc_flags); | 306 | err |= __put_user(0, &frame->uc.uc_flags); |
307 | err |= __put_user(0, &frame->uc.uc_link); | 307 | err |= __put_user(0, &frame->uc.uc_link); |
@@ -311,9 +311,9 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
311 | err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); | 311 | err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); |
312 | err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0], me); | 312 | err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0], me); |
313 | err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate); | 313 | err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate); |
314 | if (sizeof(*set) == 16) { | 314 | if (sizeof(*set) == 16) { |
315 | __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); | 315 | __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); |
316 | __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]); | 316 | __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]); |
317 | } else | 317 | } else |
318 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 318 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
319 | 319 | ||
@@ -324,7 +324,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
324 | err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); | 324 | err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); |
325 | } else { | 325 | } else { |
326 | /* could use a vstub here */ | 326 | /* could use a vstub here */ |
327 | goto give_sigsegv; | 327 | goto give_sigsegv; |
328 | } | 328 | } |
329 | 329 | ||
330 | if (err) | 330 | if (err) |
@@ -332,7 +332,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
332 | 332 | ||
333 | /* Set up registers for signal handler */ | 333 | /* Set up registers for signal handler */ |
334 | regs->di = sig; | 334 | regs->di = sig; |
335 | /* In case the signal handler was declared without prototypes */ | 335 | /* In case the signal handler was declared without prototypes */ |
336 | regs->ax = 0; | 336 | regs->ax = 0; |
337 | 337 | ||
338 | /* This also works for non SA_SIGINFO handlers because they expect the | 338 | /* This also works for non SA_SIGINFO handlers because they expect the |
@@ -355,37 +355,8 @@ give_sigsegv: | |||
355 | } | 355 | } |
356 | 356 | ||
357 | /* | 357 | /* |
358 | * Return -1L or the syscall number that @regs is executing. | ||
359 | */ | ||
360 | static long current_syscall(struct pt_regs *regs) | ||
361 | { | ||
362 | /* | ||
363 | * We always sign-extend a -1 value being set here, | ||
364 | * so this is always either -1L or a syscall number. | ||
365 | */ | ||
366 | return regs->orig_ax; | ||
367 | } | ||
368 | |||
369 | /* | ||
370 | * Return a value that is -EFOO if the system call in @regs->orig_ax | ||
371 | * returned an error. This only works for @regs from @current. | ||
372 | */ | ||
373 | static long current_syscall_ret(struct pt_regs *regs) | ||
374 | { | ||
375 | #ifdef CONFIG_IA32_EMULATION | ||
376 | if (test_thread_flag(TIF_IA32)) | ||
377 | /* | ||
378 | * Sign-extend the value so (int)-EFOO becomes (long)-EFOO | ||
379 | * and will match correctly in comparisons. | ||
380 | */ | ||
381 | return (int) regs->ax; | ||
382 | #endif | ||
383 | return regs->ax; | ||
384 | } | ||
385 | |||
386 | /* | ||
387 | * OK, we're invoking a handler | 358 | * OK, we're invoking a handler |
388 | */ | 359 | */ |
389 | 360 | ||
390 | static int | 361 | static int |
391 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | 362 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, |
@@ -394,9 +365,9 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
394 | int ret; | 365 | int ret; |
395 | 366 | ||
396 | /* Are we from a system call? */ | 367 | /* Are we from a system call? */ |
397 | if (current_syscall(regs) >= 0) { | 368 | if (syscall_get_nr(current, regs) >= 0) { |
398 | /* If so, check system call restarting.. */ | 369 | /* If so, check system call restarting.. */ |
399 | switch (current_syscall_ret(regs)) { | 370 | switch (syscall_get_error(current, regs)) { |
400 | case -ERESTART_RESTARTBLOCK: | 371 | case -ERESTART_RESTARTBLOCK: |
401 | case -ERESTARTNOHAND: | 372 | case -ERESTARTNOHAND: |
402 | regs->ax = -EINTR; | 373 | regs->ax = -EINTR; |
@@ -429,7 +400,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
429 | ret = ia32_setup_rt_frame(sig, ka, info, oldset, regs); | 400 | ret = ia32_setup_rt_frame(sig, ka, info, oldset, regs); |
430 | else | 401 | else |
431 | ret = ia32_setup_frame(sig, ka, oldset, regs); | 402 | ret = ia32_setup_frame(sig, ka, oldset, regs); |
432 | } else | 403 | } else |
433 | #endif | 404 | #endif |
434 | ret = setup_rt_frame(sig, ka, info, oldset, regs); | 405 | ret = setup_rt_frame(sig, ka, info, oldset, regs); |
435 | 406 | ||
@@ -453,15 +424,16 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
453 | * handler too. | 424 | * handler too. |
454 | */ | 425 | */ |
455 | regs->flags &= ~X86_EFLAGS_TF; | 426 | regs->flags &= ~X86_EFLAGS_TF; |
456 | if (test_thread_flag(TIF_SINGLESTEP)) | ||
457 | ptrace_notify(SIGTRAP); | ||
458 | 427 | ||
459 | spin_lock_irq(¤t->sighand->siglock); | 428 | spin_lock_irq(¤t->sighand->siglock); |
460 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 429 | sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); |
461 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 430 | if (!(ka->sa.sa_flags & SA_NODEFER)) |
462 | sigaddset(¤t->blocked,sig); | 431 | sigaddset(¤t->blocked, sig); |
463 | recalc_sigpending(); | 432 | recalc_sigpending(); |
464 | spin_unlock_irq(¤t->sighand->siglock); | 433 | spin_unlock_irq(¤t->sighand->siglock); |
434 | |||
435 | tracehook_signal_handler(sig, info, ka, regs, | ||
436 | test_thread_flag(TIF_SINGLESTEP)); | ||
465 | } | 437 | } |
466 | 438 | ||
467 | return ret; | 439 | return ret; |
@@ -518,9 +490,9 @@ static void do_signal(struct pt_regs *regs) | |||
518 | } | 490 | } |
519 | 491 | ||
520 | /* Did we come from a system call? */ | 492 | /* Did we come from a system call? */ |
521 | if (current_syscall(regs) >= 0) { | 493 | if (syscall_get_nr(current, regs) >= 0) { |
522 | /* Restart the system call - no handlers present */ | 494 | /* Restart the system call - no handlers present */ |
523 | switch (current_syscall_ret(regs)) { | 495 | switch (syscall_get_error(current, regs)) { |
524 | case -ERESTARTNOHAND: | 496 | case -ERESTARTNOHAND: |
525 | case -ERESTARTSYS: | 497 | case -ERESTARTSYS: |
526 | case -ERESTARTNOINTR: | 498 | case -ERESTARTNOINTR: |
@@ -558,17 +530,23 @@ void do_notify_resume(struct pt_regs *regs, void *unused, | |||
558 | /* deal with pending signal delivery */ | 530 | /* deal with pending signal delivery */ |
559 | if (thread_info_flags & _TIF_SIGPENDING) | 531 | if (thread_info_flags & _TIF_SIGPENDING) |
560 | do_signal(regs); | 532 | do_signal(regs); |
533 | |||
534 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | ||
535 | clear_thread_flag(TIF_NOTIFY_RESUME); | ||
536 | tracehook_notify_resume(regs); | ||
537 | } | ||
561 | } | 538 | } |
562 | 539 | ||
563 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where) | 540 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where) |
564 | { | 541 | { |
565 | struct task_struct *me = current; | 542 | struct task_struct *me = current; |
566 | if (show_unhandled_signals && printk_ratelimit()) { | 543 | if (show_unhandled_signals && printk_ratelimit()) { |
567 | printk("%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx", | 544 | printk("%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx", |
568 | me->comm,me->pid,where,frame,regs->ip,regs->sp,regs->orig_ax); | 545 | me->comm, me->pid, where, frame, regs->ip, |
546 | regs->sp, regs->orig_ax); | ||
569 | print_vma_addr(" in ", regs->ip); | 547 | print_vma_addr(" in ", regs->ip); |
570 | printk("\n"); | 548 | printk("\n"); |
571 | } | 549 | } |
572 | 550 | ||
573 | force_sig(SIGSEGV, me); | 551 | force_sig(SIGSEGV, me); |
574 | } | 552 | } |