Unified · Split
| @@ -113,11 +113,6 @@ typedef struct siginfo { · 112 unmodified lines | ||
| 113 | 113 | #undef NSIGSEGV |
| 114 | 114 | #define NSIGSEGV 3 |
| 115 | 115 | |
| 116 | −/* | |
| 117 | − * SIGTRAP si_codes | |
| 118 | − */ | |
| 119 | −#define TRAP_BRANCH (__SI_FAULT|3) /* process taken branch trap */ | |
| 120 | −#define TRAP_HWBKPT (__SI_FAULT|4) /* hardware breakpoint or watchpoint */ | |
| 121 | 116 | #undef NSIGTRAP |
| 122 | 117 | #define NSIGTRAP 4 |
| 123 | 118 | |
| @@ -15,11 +15,6 @@ · 14 unmodified lines | ||
| 15 | 15 | |
| 16 | 16 | #include <asm-generic/siginfo.h> |
| 17 | 17 | |
| 18 | −/* | |
| 19 | − * SIGTRAP si_codes | |
| 20 | − */ | |
| 21 | −#define TRAP_BRANCH (__SI_FAULT|3) /* process taken branch trap */ | |
| 22 | −#define TRAP_HWBKPT (__SI_FAULT|4) /* hardware breakpoint or watchpoint */ | |
| 23 | 18 | #undef NSIGTRAP |
| 24 | 19 | #define NSIGTRAP 4 |
| 25 | 20 | |
| @@ -351,31 +351,28 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, · 350 unmodified lines | ||
| 351 | 351 | savesegment(es, tmp); |
| 352 | 352 | err |= __put_user(tmp, (unsigned int __user *)&sc->es); |
| 353 | 353 | |
| 354 | − err |= __put_user((u32)regs->di, &sc->di); | |
| 355 | − err |= __put_user((u32)regs->si, &sc->si); | |
| 356 | − err |= __put_user((u32)regs->bp, &sc->bp); | |
| 357 | − err |= __put_user((u32)regs->sp, &sc->sp); | |
| 358 | − err |= __put_user((u32)regs->bx, &sc->bx); | |
| 359 | − err |= __put_user((u32)regs->dx, &sc->dx); | |
| 360 | − err |= __put_user((u32)regs->cx, &sc->cx); | |
| 361 | − err |= __put_user((u32)regs->ax, &sc->ax); | |
| 362 | − err |= __put_user((u32)regs->cs, &sc->cs); | |
| 363 | − err |= __put_user((u32)regs->ss, &sc->ss); | |
| 354 | + err |= __put_user(regs->di, &sc->di); | |
| 355 | + err |= __put_user(regs->si, &sc->si); | |
| 356 | + err |= __put_user(regs->bp, &sc->bp); | |
| 357 | + err |= __put_user(regs->sp, &sc->sp); | |
| 358 | + err |= __put_user(regs->bx, &sc->bx); | |
| 359 | + err |= __put_user(regs->dx, &sc->dx); | |
| 360 | + err |= __put_user(regs->cx, &sc->cx); | |
| 361 | + err |= __put_user(regs->ax, &sc->ax); | |
| 362 | + err |= __put_user(regs->cs, &sc->cs); | |
| 363 | + err |= __put_user(regs->ss, &sc->ss); | |
| 364 | 364 | err |= __put_user(current->thread.trap_no, &sc->trapno); |
| 365 | 365 | err |= __put_user(current->thread.error_code, &sc->err); |
| 366 | − err |= __put_user((u32)regs->ip, &sc->ip); | |
| 367 | − err |= __put_user((u32)regs->flags, &sc->flags); | |
| 368 | − err |= __put_user((u32)regs->sp, &sc->sp_at_signal); | |
| 366 | + err |= __put_user(regs->ip, &sc->ip); | |
| 367 | + err |= __put_user(regs->flags, &sc->flags); | |
| 368 | + err |= __put_user(regs->sp, &sc->sp_at_signal); | |
| 369 | 369 | |
| 370 | 370 | tmp = save_i387_xstate_ia32(fpstate); |
| 371 | 371 | if (tmp < 0) |
| 372 | 372 | err = -EFAULT; |
| 373 | − else { | |
| 374 | − clear_used_math(); | |
| 375 | − stts(); | |
| 373 | + else | |
| 376 | 374 | err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL), |
| 377 | 375 | &sc->fpstate); |
| 378 | − } | |
| 379 | 376 | |
| 380 | 377 | /* non-iBCS2 extensions.. */ |
| 381 | 378 | err |= __put_user(mask, &sc->oldmask); |
| @@ -444,21 +441,18 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, · 62 unmodified lines | ||
| 444 | 441 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
| 445 | 442 | |
| 446 | 443 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
| 447 | − goto give_sigsegv; | |
| 444 | + return -EFAULT; | |
| 448 | 445 | |
| 449 | − err |= __put_user(sig, &frame->sig); | |
| 450 | − if (err) | |
| 451 | − goto give_sigsegv; | |
| 446 | + if (__put_user(sig, &frame->sig)) | |
| 447 | + return -EFAULT; | |
| 452 | 448 | |
| 453 | − err |= ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]); | |
| 454 | − if (err) | |
| 455 | − goto give_sigsegv; | |
| 449 | + if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0])) | |
| 450 | + return -EFAULT; | |
| 456 | 451 | |
| 457 | 452 | if (_COMPAT_NSIG_WORDS > 1) { |
| 458 | − err |= __copy_to_user(frame->extramask, &set->sig[1], | |
| 459 | − sizeof(frame->extramask)); | |
| 460 | − if (err) | |
| 461 | − goto give_sigsegv; | |
| 453 | + if (__copy_to_user(frame->extramask, &set->sig[1], | |
| 454 | + sizeof(frame->extramask))) | |
| 455 | + return -EFAULT; | |
| 462 | 456 | } |
| 463 | 457 | |
| 464 | 458 | if (ka->sa.sa_flags & SA_RESTORER) { |
| @@ -479,7 +473,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, · 14 unmodified lines | ||
| 479 | 473 | */ |
| 480 | 474 | err |= __copy_to_user(frame->retcode, &code, 8); |
| 481 | 475 | if (err) |
| 482 | − goto give_sigsegv; | |
| 476 | + return -EFAULT; | |
| 483 | 477 | |
| 484 | 478 | /* Set up registers for signal handler */ |
| 485 | 479 | regs->sp = (unsigned long) frame; |
| @@ -502,10 +496,6 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, · 16 unmodified lines | ||
| 502 | 496 | #endif |
| 503 | 497 | |
| 504 | 498 | return 0; |
| 505 | − | |
| 506 | −give_sigsegv: | |
| 507 | − force_sigsegv(sig, current); | |
| 508 | − return -EFAULT; | |
| 509 | 499 | } |
| 510 | 500 | |
| 511 | 501 | int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
| @@ -533,14 +523,14 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, · 21 unmodified lines | ||
| 533 | 523 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
| 534 | 524 | |
| 535 | 525 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
| 536 | − goto give_sigsegv; | |
| 526 | + return -EFAULT; | |
| 537 | 527 | |
| 538 | 528 | err |= __put_user(sig, &frame->sig); |
| 539 | 529 | err |= __put_user(ptr_to_compat(&frame->info), &frame->pinfo); |
| 540 | 530 | err |= __put_user(ptr_to_compat(&frame->uc), &frame->puc); |
| 541 | 531 | err |= copy_siginfo_to_user32(&frame->info, info); |
| 542 | 532 | if (err) |
| 543 | − goto give_sigsegv; | |
| 533 | + return -EFAULT; | |
| 544 | 534 | |
| 545 | 535 | /* Create the ucontext. */ |
| 546 | 536 | if (cpu_has_xsave) |
| @@ -556,7 +546,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, · 9 unmodified lines | ||
| 556 | 546 | regs, set->sig[0]); |
| 557 | 547 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
| 558 | 548 | if (err) |
| 559 | − goto give_sigsegv; | |
| 549 | + return -EFAULT; | |
| 560 | 550 | |
| 561 | 551 | if (ka->sa.sa_flags & SA_RESTORER) |
| 562 | 552 | restorer = ka->sa.sa_restorer; |
| @@ -571,7 +561,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, · 8 unmodified lines | ||
| 571 | 561 | */ |
| 572 | 562 | err |= __copy_to_user(frame->retcode, &code, 8); |
| 573 | 563 | if (err) |
| 574 | − goto give_sigsegv; | |
| 564 | + return -EFAULT; | |
| 575 | 565 | |
| 576 | 566 | /* Set up registers for signal handler */ |
| 577 | 567 | regs->sp = (unsigned long) frame; |
| @@ -599,8 +589,4 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, · 21 unmodified lines | ||
| 599 | 589 | #endif |
| 600 | 590 | |
| 601 | 591 | return 0; |
| 602 | − | |
| 603 | −give_sigsegv: | |
| 604 | − force_sigsegv(sig, current); | |
| 605 | − return -EFAULT; | |
| 606 | 592 | } |
| @@ -736,12 +736,12 @@ unsigned long get_wchan(struct task_struct *p) · 735 unmodified lines | ||
| 736 | 736 | if (!p || p == current || p->state == TASK_RUNNING) |
| 737 | 737 | return 0; |
| 738 | 738 | stack = (unsigned long)task_stack_page(p); |
| 739 | − if (p->thread.sp < stack || p->thread.sp > stack+THREAD_SIZE) | |
| 739 | + if (p->thread.sp < stack || p->thread.sp >= stack+THREAD_SIZE) | |
| 740 | 740 | return 0; |
| 741 | 741 | fp = *(u64 *)(p->thread.sp); |
| 742 | 742 | do { |
| 743 | 743 | if (fp < (unsigned long)stack || |
| 744 | − fp > (unsigned long)stack+THREAD_SIZE) | |
| 744 | + fp >= (unsigned long)stack+THREAD_SIZE) | |
| 745 | 745 | return 0; |
| 746 | 746 | ip = *(u64 *)(fp+8); |
| 747 | 747 | if (!in_sched_functions(ip)) |
| @@ -1452,7 +1452,8 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) · 1451 unmodified lines | ||
| 1452 | 1452 | #endif |
| 1453 | 1453 | } |
| 1454 | 1454 | |
| 1455 | −void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code) | |
| 1455 | +void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, | |
| 1456 | + int error_code, int si_code) | |
| 1456 | 1457 | { |
| 1457 | 1458 | struct siginfo info; |
| 1458 | 1459 | |
| @@ -1461,7 +1462,7 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code) · 2 unmodified lines | ||
| 1461 | 1462 | |
| 1462 | 1463 | memset(&info, 0, sizeof(info)); |
| 1463 | 1464 | info.si_signo = SIGTRAP; |
| 1464 | − info.si_code = TRAP_BRKPT; | |
| 1465 | + info.si_code = si_code; | |
| 1465 | 1466 | |
| 1466 | 1467 | /* User-mode ip? */ |
| 1467 | 1468 | info.si_addr = user_mode_vm(regs) ? (void __user *) regs->ip : NULL; |
| @@ -1548,5 +1549,5 @@ asmregparm void syscall_trace_leave(struct pt_regs *regs) · 80 unmodified lines | ||
| 1548 | 1549 | */ |
| 1549 | 1550 | if (test_thread_flag(TIF_SINGLESTEP) && |
| 1550 | 1551 | tracehook_consider_fatal_signal(current, SIGTRAP, SIG_DFL)) |
| 1551 | − send_sigtrap(current, regs, 0); | |
| 1552 | + send_sigtrap(current, regs, 0, TRAP_BRKPT); | |
| 1552 | 1553 | } |
| @@ -27,6 +27,7 @@ · 26 unmodified lines | ||
| 27 | 27 | #include <asm/uaccess.h> |
| 28 | 28 | #include <asm/i387.h> |
| 29 | 29 | #include <asm/vdso.h> |
| 30 | +#include <asm/syscall.h> | |
| 30 | 31 | #include <asm/syscalls.h> |
| 31 | 32 | |
| 32 | 33 | #include "sigframe.h" |
| @@ -112,6 +113,27 @@ asmlinkage int sys_sigaltstack(unsigned long bx) · 79 unmodified lines | ||
| 112 | 113 | return do_sigaltstack(uss, uoss, regs->sp); |
| 113 | 114 | } |
| 114 | 115 | |
| 116 | +#define COPY(x) { \ | |
| 117 | + err |= __get_user(regs->x, &sc->x); \ | |
| 118 | +} | |
| 119 | + | |
| 120 | +#define COPY_SEG(seg) { \ | |
| 121 | + unsigned short tmp; \ | |
| 122 | + err |= __get_user(tmp, &sc->seg); \ | |
| 123 | + regs->seg = tmp; \ | |
| 124 | +} | |
| 125 | + | |
| 126 | +#define COPY_SEG_STRICT(seg) { \ | |
| 127 | + unsigned short tmp; \ | |
| 128 | + err |= __get_user(tmp, &sc->seg); \ | |
| 129 | + regs->seg = tmp | 3; \ | |
| 130 | +} | |
| 131 | + | |
| 132 | +#define GET_SEG(seg) { \ | |
| 133 | + unsigned short tmp; \ | |
| 134 | + err |= __get_user(tmp, &sc->seg); \ | |
| 135 | + loadsegment(seg, tmp); \ | |
| 136 | +} | |
| 115 | 137 | |
| 116 | 138 | /* |
| 117 | 139 | * Do a signal return; undo the signal stack. |
| @@ -120,28 +142,13 @@ static int · 2 unmodified lines | ||
| 120 | 142 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, |
| 121 | 143 | unsigned long *pax) |
| 122 | 144 | { |
| 145 | + void __user *buf; | |
| 146 | + unsigned int tmpflags; | |
| 123 | 147 | unsigned int err = 0; |
| 124 | 148 | |
| 125 | 149 | /* Always make any pending restarted system calls return -EINTR */ |
| 126 | 150 | current_thread_info()->restart_block.fn = do_no_restart_syscall; |
| 127 | 151 | |
| 128 | −#define COPY(x) err |= __get_user(regs->x, &sc->x) | |
| 129 | − | |
| 130 | −#define COPY_SEG(seg) \ | |
| 131 | − { unsigned short tmp; \ | |
| 132 | − err |= __get_user(tmp, &sc->seg); \ | |
| 133 | − regs->seg = tmp; } | |
| 134 | − | |
| 135 | −#define COPY_SEG_STRICT(seg) \ | |
| 136 | − { unsigned short tmp; \ | |
| 137 | − err |= __get_user(tmp, &sc->seg); \ | |
| 138 | − regs->seg = tmp|3; } | |
| 139 | − | |
| 140 | −#define GET_SEG(seg) \ | |
| 141 | − { unsigned short tmp; \ | |
| 142 | − err |= __get_user(tmp, &sc->seg); \ | |
| 143 | − loadsegment(seg, tmp); } | |
| 144 | − | |
| 145 | 152 | GET_SEG(gs); |
| 146 | 153 | COPY_SEG(fs); |
| 147 | 154 | COPY_SEG(es); |
| @@ -151,21 +158,12 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, · 3 unmodified lines | ||
| 151 | 158 | COPY_SEG_STRICT(cs); |
| 152 | 159 | COPY_SEG_STRICT(ss); |
| 153 | 160 | |
| 154 | − { | |
| 155 | − unsigned int tmpflags; | |
| 156 | − | |
| 157 | − err |= __get_user(tmpflags, &sc->flags); | |
| 158 | − regs->flags = (regs->flags & ~FIX_EFLAGS) | | |
| 159 | − (tmpflags & FIX_EFLAGS); | |
| 160 | − regs->orig_ax = -1; /* disable syscall checks */ | |
| 161 | − } | |
| 162 | − | |
| 163 | − { | |
| 164 | − void __user *buf; | |
| 161 | + err |= __get_user(tmpflags, &sc->flags); | |
| 162 | + regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); | |
| 163 | + regs->orig_ax = -1; /* disable syscall checks */ | |
| 165 | 164 | |
| 166 | − err |= __get_user(buf, &sc->fpstate); | |
| 167 | − err |= restore_i387_xstate(buf); | |
| 168 | − } | |
| 165 | + err |= __get_user(buf, &sc->fpstate); | |
| 166 | + err |= restore_i387_xstate(buf); | |
| 169 | 167 | |
| 170 | 168 | err |= __get_user(*pax, &sc->ax); |
| 171 | 169 | return err; |
| @@ -214,9 +212,8 @@ badframe: · 42 unmodified lines | ||
| 214 | 212 | return 0; |
| 215 | 213 | } |
| 216 | 214 | |
| 217 | −asmlinkage int sys_rt_sigreturn(unsigned long __unused) | |
| 215 | +static long do_rt_sigreturn(struct pt_regs *regs) | |
| 218 | 216 | { |
| 219 | − struct pt_regs *regs = (struct pt_regs *)&__unused; | |
| 220 | 217 | struct rt_sigframe __user *frame; |
| 221 | 218 | unsigned long ax; |
| 222 | 219 | sigset_t set; |
| @@ -242,10 +239,17 @@ asmlinkage int sys_rt_sigreturn(unsigned long __unused) · 19 unmodified lines | ||
| 242 | 239 | return ax; |
| 243 | 240 | |
| 244 | 241 | badframe: |
| 245 | − force_sig(SIGSEGV, current); | |
| 242 | + signal_fault(regs, frame, "rt_sigreturn"); | |
| 246 | 243 | return 0; |
| 247 | 244 | } |
| 248 | 245 | |
| 246 | +asmlinkage int sys_rt_sigreturn(unsigned long __unused) | |
| 247 | +{ | |
| 248 | + struct pt_regs *regs = (struct pt_regs *)&__unused; | |
| 249 | + | |
| 250 | + return do_rt_sigreturn(regs); | |
| 251 | +} | |
| 252 | + | |
| 249 | 253 | /* |
| 250 | 254 | * Set up a signal frame. |
| 251 | 255 | */ |
| @@ -337,39 +341,29 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, · 85 unmodified lines | ||
| 337 | 341 | } |
| 338 | 342 | |
| 339 | 343 | static int |
| 340 | −setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |
| 341 | − struct pt_regs *regs) | |
| 344 | +__setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |
| 345 | + struct pt_regs *regs) | |
| 342 | 346 | { |
| 343 | 347 | struct sigframe __user *frame; |
| 344 | 348 | void __user *restorer; |
| 345 | 349 | int err = 0; |
| 346 | − int usig; | |
| 347 | 350 | void __user *fpstate = NULL; |
| 348 | 351 | |
| 349 | 352 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
| 350 | 353 | |
| 351 | 354 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
| 352 | − goto give_sigsegv; | |
| 355 | + return -EFAULT; | |
| 353 | 356 | |
| 354 | − usig = current_thread_info()->exec_domain | |
| 355 | − && current_thread_info()->exec_domain->signal_invmap | |
| 356 | − && sig < 32 | |
| 357 | − ? current_thread_info()->exec_domain->signal_invmap[sig] | |
| 358 | − : sig; | |
| 357 | + if (__put_user(sig, &frame->sig)) | |
| 358 | + return -EFAULT; | |
| 359 | 359 | |
| 360 | − err = __put_user(usig, &frame->sig); | |
| 361 | − if (err) | |
| 362 | − goto give_sigsegv; | |
| 363 | − | |
| 364 | − err = setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]); | |
| 365 | − if (err) | |
| 366 | − goto give_sigsegv; | |
| 360 | + if (setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0])) | |
| 361 | + return -EFAULT; | |
| 367 | 362 | |
| 368 | 363 | if (_NSIG_WORDS > 1) { |
| 369 | − err = __copy_to_user(&frame->extramask, &set->sig[1], | |
| 370 | − sizeof(frame->extramask)); | |
| 371 | − if (err) | |
| 372 | − goto give_sigsegv; | |
| 364 | + if (__copy_to_user(&frame->extramask, &set->sig[1], | |
| 365 | + sizeof(frame->extramask))) | |
| 366 | + return -EFAULT; | |
| 373 | 367 | } |
| 374 | 368 | |
| 375 | 369 | if (current->mm->context.vdso) |
| @@ -394,7 +388,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, · 18 unmodified lines | ||
| 394 | 388 | err |= __put_user(0x80cd, (short __user *)(frame->retcode+6)); |
| 395 | 389 | |
| 396 | 390 | if (err) |
| 397 | − goto give_sigsegv; | |
| 391 | + return -EFAULT; | |
| 398 | 392 | |
| 399 | 393 | /* Set up registers for signal handler */ |
| 400 | 394 | regs->sp = (unsigned long)frame; |
| @@ -409,38 +403,27 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, · 8 unmodified lines | ||
| 409 | 403 | regs->cs = __USER_CS; |
| 410 | 404 | |
| 411 | 405 | return 0; |
| 412 | − | |
| 413 | −give_sigsegv: | |
| 414 | − force_sigsegv(sig, current); | |
| 415 | − return -EFAULT; | |
| 416 | 406 | } |
| 417 | 407 | |
| 418 | −static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |
| 419 | − sigset_t *set, struct pt_regs *regs) | |
| 408 | +static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |
| 409 | + sigset_t *set, struct pt_regs *regs) | |
| 420 | 410 | { |
| 421 | 411 | struct rt_sigframe __user *frame; |
| 422 | 412 | void __user *restorer; |
| 423 | 413 | int err = 0; |
| 424 | − int usig; | |
| 425 | 414 | void __user *fpstate = NULL; |
| 426 | 415 | |
| 427 | 416 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
| 428 | 417 | |
| 429 | 418 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
| 430 | − goto give_sigsegv; | |
| 431 | − | |
| 432 | − usig = current_thread_info()->exec_domain | |
| 433 | − && current_thread_info()->exec_domain->signal_invmap | |
| 434 | − && sig < 32 | |
| 435 | − ? current_thread_info()->exec_domain->signal_invmap[sig] | |
| 436 | − : sig; | |
| 419 | + return -EFAULT; | |
| 437 | 420 | |
| 438 | − err |= __put_user(usig, &frame->sig); | |
| 421 | + err |= __put_user(sig, &frame->sig); | |
| 439 | 422 | err |= __put_user(&frame->info, &frame->pinfo); |
| 440 | 423 | err |= __put_user(&frame->uc, &frame->puc); |
| 441 | 424 | err |= copy_siginfo_to_user(&frame->info, info); |
| 442 | 425 | if (err) |
| 443 | − goto give_sigsegv; | |
| 426 | + return -EFAULT; | |
| 444 | 427 | |
| 445 | 428 | /* Create the ucontext. */ |
| 446 | 429 | if (cpu_has_xsave) |
| @@ -456,7 +439,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, · 9 unmodified lines | ||
| 456 | 439 | regs, set->sig[0]); |
| 457 | 440 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
| 458 | 441 | if (err) |
| 459 | − goto give_sigsegv; | |
| 442 | + return -EFAULT; | |
| 460 | 443 | |
| 461 | 444 | /* Set up to return from userspace. */ |
| 462 | 445 | restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn); |
| @@ -476,12 +459,12 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, · 13 unmodified lines | ||
| 476 | 459 | err |= __put_user(0x80cd, (short __user *)(frame->retcode+5)); |
| 477 | 460 | |
| 478 | 461 | if (err) |
| 479 | − goto give_sigsegv; | |
| 462 | + return -EFAULT; | |
| 480 | 463 | |
| 481 | 464 | /* Set up registers for signal handler */ |
| 482 | 465 | regs->sp = (unsigned long)frame; |
| 483 | 466 | regs->ip = (unsigned long)ka->sa.sa_handler; |
| 484 | − regs->ax = (unsigned long)usig; | |
| 467 | + regs->ax = (unsigned long)sig; | |
| 485 | 468 | regs->dx = (unsigned long)&frame->info; |
| 486 | 469 | regs->cx = (unsigned long)&frame->uc; |
| 487 | 470 | |
| @@ -491,15 +474,48 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, · 3 unmodified lines | ||
| 491 | 474 | regs->cs = __USER_CS; |
| 492 | 475 | |
| 493 | 476 | return 0; |
| 494 | − | |
| 495 | −give_sigsegv: | |
| 496 | − force_sigsegv(sig, current); | |
| 497 | − return -EFAULT; | |
| 498 | 477 | } |
| 499 | 478 | |
| 500 | 479 | /* |
| 501 | 480 | * OK, we're invoking a handler: |
| 502 | 481 | */ |
| 482 | +static int signr_convert(int sig) | |
| 483 | +{ | |
| 484 | + struct thread_info *info = current_thread_info(); | |
| 485 | + | |
| 486 | + if (info->exec_domain && info->exec_domain->signal_invmap && sig < 32) | |
| 487 | + return info->exec_domain->signal_invmap[sig]; | |
| 488 | + return sig; | |
| 489 | +} | |
| 490 | + | |
| 491 | +#define is_ia32 1 | |
| 492 | +#define ia32_setup_frame __setup_frame | |
| 493 | +#define ia32_setup_rt_frame __setup_rt_frame | |
| 494 | + | |
| 495 | +static int | |
| 496 | +setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |
| 497 | + sigset_t *set, struct pt_regs *regs) | |
| 498 | +{ | |
| 499 | + int usig = signr_convert(sig); | |
| 500 | + int ret; | |
| 501 | + | |
| 502 | + /* Set up the stack frame */ | |
| 503 | + if (is_ia32) { | |
| 504 | + if (ka->sa.sa_flags & SA_SIGINFO) | |
| 505 | + ret = ia32_setup_rt_frame(usig, ka, info, set, regs); | |
| 506 | + else | |
| 507 | + ret = ia32_setup_frame(usig, ka, set, regs); | |
| 508 | + } else | |
| 509 | + ret = __setup_rt_frame(sig, ka, info, set, regs); | |
| 510 | + | |
| 511 | + if (ret) { | |
| 512 | + force_sigsegv(sig, current); | |
| 513 | + return -EFAULT; | |
| 514 | + } | |
| 515 | + | |
| 516 | + return ret; | |
| 517 | +} | |
| 518 | + | |
| 503 | 519 | static int |
| 504 | 520 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, |
| 505 | 521 | sigset_t *oldset, struct pt_regs *regs) |
| @@ -507,9 +523,9 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, · 1 unmodified line | ||
| 507 | 523 | int ret; |
| 508 | 524 | |
| 509 | 525 | /* Are we from a system call? */ |
| 510 | − if ((long)regs->orig_ax >= 0) { | |
| 526 | + if (syscall_get_nr(current, regs) >= 0) { | |
| 511 | 527 | /* If so, check system call restarting.. */ |
| 512 | − switch (regs->ax) { | |
| 528 | + switch (syscall_get_error(current, regs)) { | |
| 513 | 529 | case -ERESTART_RESTARTBLOCK: |
| 514 | 530 | case -ERESTARTNOHAND: |
| 515 | 531 | regs->ax = -EINTR; |
| @@ -536,15 +552,20 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, · 20 unmodified lines | ||
| 536 | 552 | likely(test_and_clear_thread_flag(TIF_FORCED_TF))) |
| 537 | 553 | regs->flags &= ~X86_EFLAGS_TF; |
| 538 | 554 | |
| 539 | − /* Set up the stack frame */ | |
| 540 | − if (ka->sa.sa_flags & SA_SIGINFO) | |
| 541 | − ret = setup_rt_frame(sig, ka, info, oldset, regs); | |
| 542 | − else | |
| 543 | − ret = setup_frame(sig, ka, oldset, regs); | |
| 555 | + ret = setup_rt_frame(sig, ka, info, oldset, regs); | |
| 544 | 556 | |
| 545 | 557 | if (ret) |
| 546 | 558 | return ret; |
| 547 | 559 | |
| 560 | +#ifdef CONFIG_X86_64 | |
| 561 | + /* | |
| 562 | + * This has nothing to do with segment registers, | |
| 563 | + * despite the name. This magic affects uaccess.h | |
| 564 | + * macros' behavior. Reset it to the normal setting. | |
| 565 | + */ | |
| 566 | + set_fs(USER_DS); | |
| 567 | +#endif | |
| 568 | + | |
| 548 | 569 | /* |
| 549 | 570 | * Clear the direction flag as per the ABI for function entry. |
| 550 | 571 | */ |
| @@ -571,6 +592,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, · 20 unmodified lines | ||
| 571 | 592 | return 0; |
| 572 | 593 | } |
| 573 | 594 | |
| 595 | +#define NR_restart_syscall __NR_restart_syscall | |
| 574 | 596 | /* |
| 575 | 597 | * Note that 'init' is a special process: it doesn't get signals it doesn't |
| 576 | 598 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
| @@ -623,9 +645,9 @@ static void do_signal(struct pt_regs *regs) · 46 unmodified lines | ||
| 623 | 645 | } |
| 624 | 646 | |
| 625 | 647 | /* Did we come from a system call? */ |
| 626 | − if ((long)regs->orig_ax >= 0) { | |
| 648 | + if (syscall_get_nr(current, regs) >= 0) { | |
| 627 | 649 | /* Restart the system call - no handlers present */ |
| 628 | − switch (regs->ax) { | |
| 650 | + switch (syscall_get_error(current, regs)) { | |
| 629 | 651 | case -ERESTARTNOHAND: |
| 630 | 652 | case -ERESTARTSYS: |
| 631 | 653 | case -ERESTARTNOINTR: |
| @@ -634,7 +656,7 @@ static void do_signal(struct pt_regs *regs) · 2 unmodified lines | ||
| 634 | 656 | break; |
| 635 | 657 | |
| 636 | 658 | case -ERESTART_RESTARTBLOCK: |
| 637 | − regs->ax = __NR_restart_syscall; | |
| 659 | + regs->ax = NR_restart_syscall; | |
| 638 | 660 | regs->ip -= 2; |
| 639 | 661 | break; |
| 640 | 662 | } |
| @@ -657,6 +679,12 @@ static void do_signal(struct pt_regs *regs) · 16 unmodified lines | ||
| 657 | 679 | void |
| 658 | 680 | do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) |
| 659 | 681 | { |
| 682 | +#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE) | |
| 683 | + /* notify userspace of pending MCEs */ | |
| 684 | + if (thread_info_flags & _TIF_MCE_NOTIFY) | |
| 685 | + mce_notify_user(); | |
| 686 | +#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */ | |
| 687 | + | |
| 660 | 688 | /* deal with pending signal delivery */ |
| 661 | 689 | if (thread_info_flags & _TIF_SIGPENDING) |
| 662 | 690 | do_signal(regs); |
| @@ -666,5 +694,23 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) · 3 unmodified lines | ||
| 666 | 694 | tracehook_notify_resume(regs); |
| 667 | 695 | } |
| 668 | 696 | |
| 697 | +#ifdef CONFIG_X86_32 | |
| 669 | 698 | clear_thread_flag(TIF_IRET); |
| 699 | +#endif /* CONFIG_X86_32 */ | |
| 700 | +} | |
| 701 | + | |
| 702 | +void signal_fault(struct pt_regs *regs, void __user *frame, char *where) | |
| 703 | +{ | |
| 704 | + struct task_struct *me = current; | |
| 705 | + | |
| 706 | + if (show_unhandled_signals && printk_ratelimit()) { | |
| 707 | + printk(KERN_INFO | |
| 708 | + "%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx", | |
| 709 | + me->comm, me->pid, where, frame, | |
| 710 | + regs->ip, regs->sp, regs->orig_ax); | |
| 711 | + print_vma_addr(" in ", regs->ip); | |
| 712 | + printk(KERN_CONT "\n"); | |
| 713 | + } | |
| 714 | + | |
| 715 | + force_sig(SIGSEGV, me); | |
| 670 | 716 | } |
| @@ -52,6 +52,16 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, · 51 unmodified lines | ||
| 52 | 52 | return do_sigaltstack(uss, uoss, regs->sp); |
| 53 | 53 | } |
| 54 | 54 | |
| 55 | +#define COPY(x) { \ | |
| 56 | + err |= __get_user(regs->x, &sc->x); \ | |
| 57 | +} | |
| 58 | + | |
| 59 | +#define COPY_SEG_STRICT(seg) { \ | |
| 60 | + unsigned short tmp; \ | |
| 61 | + err |= __get_user(tmp, &sc->seg); \ | |
| 62 | + regs->seg = tmp | 3; \ | |
| 63 | +} | |
| 64 | + | |
| 55 | 65 | /* |
| 56 | 66 | * Do a signal return; undo the signal stack. |
| 57 | 67 | */ |
| @@ -59,13 +69,13 @@ static int · 1 unmodified line | ||
| 59 | 69 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, |
| 60 | 70 | unsigned long *pax) |
| 61 | 71 | { |
| 72 | + void __user *buf; | |
| 73 | + unsigned int tmpflags; | |
| 62 | 74 | unsigned int err = 0; |
| 63 | 75 | |
| 64 | 76 | /* Always make any pending restarted system calls return -EINTR */ |
| 65 | 77 | current_thread_info()->restart_block.fn = do_no_restart_syscall; |
| 66 | 78 | |
| 67 | −#define COPY(x) (err |= __get_user(regs->x, &sc->x)) | |
| 68 | − | |
| 69 | 79 | COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); |
| 70 | 80 | COPY(dx); COPY(cx); COPY(ip); |
| 71 | 81 | COPY(r8); |
| @@ -80,34 +90,24 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, · 8 unmodified lines | ||
| 80 | 90 | /* Kernel saves and restores only the CS segment register on signals, |
| 81 | 91 | * which is the bare minimum needed to allow mixed 32/64-bit code. |
| 82 | 92 | * App's signal handler can save/restore other segments if needed. */ |
| 83 | − { | |
| 84 | − unsigned cs; | |
| 85 | − err |= __get_user(cs, &sc->cs); | |
| 86 | − regs->cs = cs | 3; /* Force into user mode */ | |
| 87 | − } | |
| 93 | + COPY_SEG_STRICT(cs); | |
| 88 | 94 | |
| 89 | − { | |
| 90 | − unsigned int tmpflags; | |
| 91 | − err |= __get_user(tmpflags, &sc->flags); | |
| 92 | − regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); | |
| 93 | − regs->orig_ax = -1; /* disable syscall checks */ | |
| 94 | − } | |
| 95 | + err |= __get_user(tmpflags, &sc->flags); | |
| 96 | + regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); | |
| 97 | + regs->orig_ax = -1; /* disable syscall checks */ | |
| 95 | 98 | |
| 96 | − { | |
| 97 | − struct _fpstate __user *buf; | |
| 98 | − err |= __get_user(buf, &sc->fpstate); | |
| 99 | − err |= restore_i387_xstate(buf); | |
| 100 | − } | |
| 99 | + err |= __get_user(buf, &sc->fpstate); | |
| 100 | + err |= restore_i387_xstate(buf); | |
| 101 | 101 | |
| 102 | 102 | err |= __get_user(*pax, &sc->ax); |
| 103 | 103 | return err; |
| 104 | 104 | } |
| 105 | 105 | |
| 106 | −asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | |
| 106 | +static long do_rt_sigreturn(struct pt_regs *regs) | |
| 107 | 107 | { |
| 108 | 108 | struct rt_sigframe __user *frame; |
| 109 | − sigset_t set; | |
| 110 | 109 | unsigned long ax; |
| 110 | + sigset_t set; | |
| 111 | 111 | |
| 112 | 112 | frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long)); |
| 113 | 113 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
| @@ -130,10 +130,15 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) · 16 unmodified lines | ||
| 130 | 130 | return ax; |
| 131 | 131 | |
| 132 | 132 | badframe: |
| 133 | − signal_fault(regs, frame, "sigreturn"); | |
| 133 | + signal_fault(regs, frame, "rt_sigreturn"); | |
| 134 | 134 | return 0; |
| 135 | 135 | } |
| 136 | 136 | |
| 137 | +asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | |
| 138 | +{ | |
| 139 | + return do_rt_sigreturn(regs); | |
| 140 | +} | |
| 141 | + | |
| 137 | 142 | /* |
| 138 | 143 | * Set up a signal frame. |
| 139 | 144 | */ |
| @@ -195,8 +200,8 @@ get_stack(struct k_sigaction *ka, struct pt_regs *regs, unsigned long size) · 55 unmodified lines | ||
| 195 | 200 | return (void __user *)round_down(sp - size, 64); |
| 196 | 201 | } |
| 197 | 202 | |
| 198 | −static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |
| 199 | − sigset_t *set, struct pt_regs *regs) | |
| 203 | +static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |
| 204 | + sigset_t *set, struct pt_regs *regs) | |
| 200 | 205 | { |
| 201 | 206 | struct rt_sigframe __user *frame; |
| 202 | 207 | void __user *fp = NULL; |
| @@ -209,17 +214,16 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, · 6 unmodified lines | ||
| 209 | 214 | (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8; |
| 210 | 215 | |
| 211 | 216 | if (save_i387_xstate(fp) < 0) |
| 212 | − err |= -1; | |
| 217 | + return -EFAULT; | |
| 213 | 218 | } else |
| 214 | 219 | frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8; |
| 215 | 220 | |
| 216 | 221 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
| 217 | − goto give_sigsegv; | |
| 222 | + return -EFAULT; | |
| 218 | 223 | |
| 219 | 224 | if (ka->sa.sa_flags & SA_SIGINFO) { |
| 220 | − err |= copy_siginfo_to_user(&frame->info, info); | |
| 221 | − if (err) | |
| 222 | − goto give_sigsegv; | |
| 225 | + if (copy_siginfo_to_user(&frame->info, info)) | |
| 226 | + return -EFAULT; | |
| 223 | 227 | } |
| 224 | 228 | |
| 225 | 229 | /* Create the ucontext. */ |
| @@ -247,11 +251,11 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, · 21 unmodified lines | ||
| 247 | 251 | err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); |
| 248 | 252 | } else { |
| 249 | 253 | /* could use a vstub here */ |
| 250 | − goto give_sigsegv; | |
| 254 | + return -EFAULT; | |
| 251 | 255 | } |
| 252 | 256 | |
| 253 | 257 | if (err) |
| 254 | − goto give_sigsegv; | |
| 258 | + return -EFAULT; | |
| 255 | 259 | |
| 256 | 260 | /* Set up registers for signal handler */ |
| 257 | 261 | regs->di = sig; |
| @@ -271,15 +275,45 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, · 13 unmodified lines | ||
| 271 | 275 | regs->cs = __USER_CS; |
| 272 | 276 | |
| 273 | 277 | return 0; |
| 274 | − | |
| 275 | −give_sigsegv: | |
| 276 | − force_sigsegv(sig, current); | |
| 277 | − return -EFAULT; | |
| 278 | 278 | } |
| 279 | 279 | |
| 280 | 280 | /* |
| 281 | 281 | * OK, we're invoking a handler |
| 282 | 282 | */ |
| 283 | +static int signr_convert(int sig) | |
| 284 | +{ | |
| 285 | + return sig; | |
| 286 | +} | |
| 287 | + | |
| 288 | +#ifdef CONFIG_IA32_EMULATION | |
| 289 | +#define is_ia32 test_thread_flag(TIF_IA32) | |
| 290 | +#else | |
| 291 | +#define is_ia32 0 | |
| 292 | +#endif | |
| 293 | + | |
| 294 | +static int | |
| 295 | +setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |
| 296 | + sigset_t *set, struct pt_regs *regs) | |
| 297 | +{ | |
| 298 | + int usig = signr_convert(sig); | |
| 299 | + int ret; | |
| 300 | + | |
| 301 | + /* Set up the stack frame */ | |
| 302 | + if (is_ia32) { | |
| 303 | + if (ka->sa.sa_flags & SA_SIGINFO) | |
| 304 | + ret = ia32_setup_rt_frame(usig, ka, info, set, regs); | |
| 305 | + else | |
| 306 | + ret = ia32_setup_frame(usig, ka, set, regs); | |
| 307 | + } else | |
| 308 | + ret = __setup_rt_frame(sig, ka, info, set, regs); | |
| 309 | + | |
| 310 | + if (ret) { | |
| 311 | + force_sigsegv(sig, current); | |
| 312 | + return -EFAULT; | |
| 313 | + } | |
| 314 | + | |
| 315 | + return ret; | |
| 316 | +} | |
| 283 | 317 | |
| 284 | 318 | static int |
| 285 | 319 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, |
| @@ -317,51 +351,48 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, · 31 unmodified lines | ||
| 317 | 351 | likely(test_and_clear_thread_flag(TIF_FORCED_TF))) |
| 318 | 352 | regs->flags &= ~X86_EFLAGS_TF; |
| 319 | 353 | |
| 320 | −#ifdef CONFIG_IA32_EMULATION | |
| 321 | − if (test_thread_flag(TIF_IA32)) { | |
| 322 | − if (ka->sa.sa_flags & SA_SIGINFO) | |
| 323 | − ret = ia32_setup_rt_frame(sig, ka, info, oldset, regs); | |
| 324 | − else | |
| 325 | − ret = ia32_setup_frame(sig, ka, oldset, regs); | |
| 326 | − } else | |
| 327 | −#endif | |
| 328 | 354 | ret = setup_rt_frame(sig, ka, info, oldset, regs); |
| 329 | 355 | |
| 330 | − if (ret == 0) { | |
| 331 | − /* | |
| 332 | − * This has nothing to do with segment registers, | |
| 333 | − * despite the name. This magic affects uaccess.h | |
| 334 | − * macros' behavior. Reset it to the normal setting. | |
| 335 | − */ | |
| 336 | − set_fs(USER_DS); | |
| 356 | + if (ret) | |
| 357 | + return ret; | |
| 337 | 358 | |
| 338 | − /* | |
| 339 | − * Clear the direction flag as per the ABI for function entry. | |
| 340 | − */ | |
| 341 | − regs->flags &= ~X86_EFLAGS_DF; | |
| 359 | +#ifdef CONFIG_X86_64 | |
| 360 | + /* | |
| 361 | + * This has nothing to do with segment registers, | |
| 362 | + * despite the name. This magic affects uaccess.h | |
| 363 | + * macros' behavior. Reset it to the normal setting. | |
| 364 | + */ | |
| 365 | + set_fs(USER_DS); | |
| 366 | +#endif | |
| 342 | 367 | |
| 343 | − /* | |
| 344 | − * Clear TF when entering the signal handler, but | |
| 345 | − * notify any tracer that was single-stepping it. | |
| 346 | − * The tracer may want to single-step inside the | |
| 347 | − * handler too. | |
| 348 | − */ | |
| 349 | − regs->flags &= ~X86_EFLAGS_TF; | |
| 368 | + /* | |
| 369 | + * Clear the direction flag as per the ABI for function entry. | |
| 370 | + */ | |
| 371 | + regs->flags &= ~X86_EFLAGS_DF; | |
| 350 | 372 | |
| 351 | − spin_lock_irq(¤t->sighand->siglock); | |
| 352 | − sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); | |
| 353 | − if (!(ka->sa.sa_flags & SA_NODEFER)) | |
| 354 | − sigaddset(¤t->blocked, sig); | |
| 355 | − recalc_sigpending(); | |
| 356 | − spin_unlock_irq(¤t->sighand->siglock); | |
| 373 | + /* | |
| 374 | + * Clear TF when entering the signal handler, but | |
| 375 | + * notify any tracer that was single-stepping it. | |
| 376 | + * The tracer may want to single-step inside the | |
| 377 | + * handler too. | |
| 378 | + */ | |
| 379 | + regs->flags &= ~X86_EFLAGS_TF; | |
| 357 | 380 | |
| 358 | − tracehook_signal_handler(sig, info, ka, regs, | |
| 359 | − test_thread_flag(TIF_SINGLESTEP)); | |
| 360 | − } | |
| 381 | + spin_lock_irq(¤t->sighand->siglock); | |
| 382 | + sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); | |
| 383 | + if (!(ka->sa.sa_flags & SA_NODEFER)) | |
| 384 | + sigaddset(¤t->blocked, sig); | |
| 385 | + recalc_sigpending(); | |
| 386 | + spin_unlock_irq(¤t->sighand->siglock); | |
| 361 | 387 | |
| 362 | − return ret; | |
| 388 | + tracehook_signal_handler(sig, info, ka, regs, | |
| 389 | + test_thread_flag(TIF_SINGLESTEP)); | |
| 390 | + | |
| 391 | + return 0; | |
| 363 | 392 | } |
| 364 | 393 | |
| 394 | +#define NR_restart_syscall \ | |
| 395 | + test_thread_flag(TIF_IA32) ? __NR_ia32_restart_syscall : __NR_restart_syscall | |
| 365 | 396 | /* |
| 366 | 397 | * Note that 'init' is a special process: it doesn't get signals it doesn't |
| 367 | 398 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
| @@ -391,7 +422,8 @@ static void do_signal(struct pt_regs *regs) · 23 unmodified lines | ||
| 391 | 422 | |
| 392 | 423 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
| 393 | 424 | if (signr > 0) { |
| 394 | − /* Re-enable any watchpoints before delivering the | |
| 425 | + /* | |
| 426 | + * Re-enable any watchpoints before delivering the | |
| 395 | 427 | * signal to user space. The processor register will |
| 396 | 428 | * have been cleared if the watchpoint triggered |
| 397 | 429 | * inside the kernel. |
| @@ -399,7 +431,7 @@ static void do_signal(struct pt_regs *regs) · 1 unmodified line | ||
| 399 | 431 | if (current->thread.debugreg7) |
| 400 | 432 | set_debugreg(current->thread.debugreg7, 7); |
| 401 | 433 | |
| 402 | − /* Whee! Actually deliver the signal. */ | |
| 434 | + /* Whee! Actually deliver the signal. */ | |
| 403 | 435 | if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { |
| 404 | 436 | /* |
| 405 | 437 | * A signal was successfully delivered; the saved |
| @@ -422,10 +454,9 @@ static void do_signal(struct pt_regs *regs) · 16 unmodified lines | ||
| 422 | 454 | regs->ax = regs->orig_ax; |
| 423 | 455 | regs->ip -= 2; |
| 424 | 456 | break; |
| 457 | + | |
| 425 | 458 | case -ERESTART_RESTARTBLOCK: |
| 426 | − regs->ax = test_thread_flag(TIF_IA32) ? | |
| 427 | − __NR_ia32_restart_syscall : | |
| 428 | − __NR_restart_syscall; | |
| 459 | + regs->ax = NR_restart_syscall; | |
| 429 | 460 | regs->ip -= 2; |
| 430 | 461 | break; |
| 431 | 462 | } |
| @@ -441,14 +472,18 @@ static void do_signal(struct pt_regs *regs) · 9 unmodified lines | ||
| 441 | 472 | } |
| 442 | 473 | } |
| 443 | 474 | |
| 444 | −void do_notify_resume(struct pt_regs *regs, void *unused, | |
| 445 | − __u32 thread_info_flags) | |
| 475 | +/* | |
| 476 | + * notification of userspace execution resumption | |
| 477 | + * - triggered by the TIF_WORK_MASK flags | |
| 478 | + */ | |
| 479 | +void | |
| 480 | +do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) | |
| 446 | 481 | { |
| 447 | −#ifdef CONFIG_X86_MCE | |
| 482 | +#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE) | |
| 448 | 483 | /* notify userspace of pending MCEs */ |
| 449 | 484 | if (thread_info_flags & _TIF_MCE_NOTIFY) |
| 450 | 485 | mce_notify_user(); |
| 451 | −#endif /* CONFIG_X86_MCE */ | |
| 486 | +#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */ | |
| 452 | 487 | |
| 453 | 488 | /* deal with pending signal delivery */ |
| 454 | 489 | if (thread_info_flags & _TIF_SIGPENDING) |
| @@ -458,17 +493,23 @@ void do_notify_resume(struct pt_regs *regs, void *unused, · 3 unmodified lines | ||
| 458 | 493 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 459 | 494 | tracehook_notify_resume(regs); |
| 460 | 495 | } |
| 496 | + | |
| 497 | +#ifdef CONFIG_X86_32 | |
| 498 | + clear_thread_flag(TIF_IRET); | |
| 499 | +#endif /* CONFIG_X86_32 */ | |
| 461 | 500 | } |
| 462 | 501 | |
| 463 | 502 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where) |
| 464 | 503 | { |
| 465 | 504 | struct task_struct *me = current; |
| 505 | + | |
| 466 | 506 | if (show_unhandled_signals && printk_ratelimit()) { |
| 467 | − printk("%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx", | |
| 468 | − me->comm, me->pid, where, frame, regs->ip, | |
| 469 | − regs->sp, regs->orig_ax); | |
| 507 | + printk(KERN_INFO | |
| 508 | + "%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx", | |
| 509 | + me->comm, me->pid, where, frame, | |
| 510 | + regs->ip, regs->sp, regs->orig_ax); | |
| 470 | 511 | print_vma_addr(" in ", regs->ip); |
| 471 | − printk("\n"); | |
| 512 | + printk(KERN_CONT "\n"); | |
| 472 | 513 | } |
| 473 | 514 | |
| 474 | 515 | force_sig(SIGSEGV, me); |
| @@ -891,6 +891,7 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code) · 890 unmodified lines | ||
| 891 | 891 | { |
| 892 | 892 | struct task_struct *tsk = current; |
| 893 | 893 | unsigned int condition; |
| 894 | + int si_code; | |
| 894 | 895 | |
| 895 | 896 | trace_hardirqs_fixup(); |
| 896 | 897 | |
| @@ -935,8 +936,9 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code) · 38 unmodified lines | ||
| 935 | 936 | goto clear_TF_reenable; |
| 936 | 937 | } |
| 937 | 938 | |
| 939 | + si_code = get_si_code((unsigned long)condition); | |
| 938 | 940 | /* Ok, finally something we can handle */ |
| 939 | − send_sigtrap(tsk, regs, error_code); | |
| 941 | + send_sigtrap(tsk, regs, error_code, si_code); | |
| 940 | 942 | |
| 941 | 943 | /* |
| 942 | 944 | * Disable additional traps. They'll be re-enabled when |
| @@ -940,7 +940,7 @@ asmlinkage void __kprobes do_debug(struct pt_regs *regs, · 939 unmodified lines | ||
| 940 | 940 | tsk->thread.error_code = error_code; |
| 941 | 941 | info.si_signo = SIGTRAP; |
| 942 | 942 | info.si_errno = 0; |
| 943 | − info.si_code = TRAP_BRKPT; | |
| 943 | + info.si_code = get_si_code(condition); | |
| 944 | 944 | info.si_addr = user_mode(regs) ? (void __user *)regs->ip : NULL; |
| 945 | 945 | force_sig_info(SIGTRAP, &info, tsk); |
| 946 | 946 | |
| @@ -172,8 +172,8 @@ SECTIONS · 171 unmodified lines | ||
| 172 | 172 | .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) { |
| 173 | 173 | *(.x86_cpu_dev.init) |
| 174 | 174 | } |
| 175 | − SECURITY_INIT | |
| 176 | 175 | __x86_cpu_dev_end = .; |
| 176 | + SECURITY_INIT | |
| 177 | 177 | |
| 178 | 178 | . = ALIGN(8); |
| 179 | 179 | .parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) { |
| @@ -614,7 +614,7 @@ void __init *early_ioremap(unsigned long phys_addr, unsigned long size) · 613 unmodified lines | ||
| 614 | 614 | */ |
| 615 | 615 | offset = phys_addr & ~PAGE_MASK; |
| 616 | 616 | phys_addr &= PAGE_MASK; |
| 617 | − size = PAGE_ALIGN(last_addr) - phys_addr; | |
| 617 | + size = PAGE_ALIGN(last_addr + 1) - phys_addr; | |
| 618 | 618 | |
| 619 | 619 | /* |
| 620 | 620 | * Mappings have to fit in the FIX_BTMAP area. |
| @@ -199,6 +199,8 @@ typedef struct siginfo { · 198 unmodified lines | ||
| 199 | 199 | */ |
| 200 | 200 | #define TRAP_BRKPT (__SI_FAULT|1) /* process breakpoint */ |
| 201 | 201 | #define TRAP_TRACE (__SI_FAULT|2) /* process trace trap */ |
| 202 | +#define TRAP_BRANCH (__SI_FAULT|3) /* process taken branch trap */ | |
| 203 | +#define TRAP_HWBKPT (__SI_FAULT|4) /* hardware breakpoint/watchpoint */ | |
| 202 | 204 | #define NSIGTRAP 2 |
| 203 | 205 | |
| 204 | 206 | /* |
| @@ -3,11 +3,6 @@ · 2 unmodified lines | ||
| 3 | 3 | |
| 4 | 4 | #include <asm-generic/siginfo.h> |
| 5 | 5 | |
| 6 | −/* | |
| 7 | − * SIGTRAP si_codes | |
| 8 | − */ | |
| 9 | −#define TRAP_BRANCH (__SI_FAULT|3) /* process taken branch trap */ | |
| 10 | −#define TRAP_HWBKPT (__SI_FAULT|4) /* hardware breakpoint or watchpoint */ | |
| 11 | 6 | #undef NSIGTRAP |
| 12 | 7 | #define NSIGTRAP 4 |
| 13 | 8 | |
| @@ -177,11 +177,11 @@ convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs); · 176 unmodified lines | ||
| 177 | 177 | |
| 178 | 178 | #ifdef CONFIG_X86_32 |
| 179 | 179 | extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, |
| 180 | − int error_code); | |
| 181 | −#else | |
| 182 | −void signal_fault(struct pt_regs *regs, void __user *frame, char *where); | |
| 180 | + int error_code, int si_code); | |
| 183 | 181 | #endif |
| 184 | 182 | |
| 183 | +void signal_fault(struct pt_regs *regs, void __user *frame, char *where); | |
| 184 | + | |
| 185 | 185 | extern long syscall_trace_enter(struct pt_regs *); |
| 186 | 186 | extern void syscall_trace_leave(struct pt_regs *); |
| 187 | 187 | |
| @@ -21,8 +21,10 @@ · 20 unmodified lines | ||
| 21 | 21 | |
| 22 | 22 | #ifdef CONFIG_X86_32 |
| 23 | 23 | # define LOCK_PTR_REG "a" |
| 24 | +# define REG_PTR_MODE "k" | |
| 24 | 25 | #else |
| 25 | 26 | # define LOCK_PTR_REG "D" |
| 27 | +# define REG_PTR_MODE "q" | |
| 26 | 28 | #endif |
| 27 | 29 | |
| 28 | 30 | #if defined(CONFIG_X86_32) && \ |
| @@ -54,19 +56,7 @@ · 25 unmodified lines | ||
| 54 | 56 | * much between them in performance though, especially as locks are out of line. |
| 55 | 57 | */ |
| 56 | 58 | #if (NR_CPUS < 256) |
| 57 | −static inline int __ticket_spin_is_locked(raw_spinlock_t *lock) | |
| 58 | −{ | |
| 59 | − int tmp = ACCESS_ONCE(lock->slock); | |
| 60 | − | |
| 61 | − return (((tmp >> 8) & 0xff) != (tmp & 0xff)); | |
| 62 | −} | |
| 63 | − | |
| 64 | −static inline int __ticket_spin_is_contended(raw_spinlock_t *lock) | |
| 65 | −{ | |
| 66 | − int tmp = ACCESS_ONCE(lock->slock); | |
| 67 | − | |
| 68 | − return (((tmp >> 8) - tmp) & 0xff) > 1; | |
| 69 | −} | |
| 59 | +#define TICKET_SHIFT 8 | |
| 70 | 60 | |
| 71 | 61 | static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock) |
| 72 | 62 | { |
| @@ -89,19 +79,17 @@ static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock) · 16 unmodified lines | ||
| 89 | 79 | |
| 90 | 80 | static __always_inline int __ticket_spin_trylock(raw_spinlock_t *lock) |
| 91 | 81 | { |
| 92 | − int tmp; | |
| 93 | − short new; | |
| 82 | + int tmp, new; | |
| 94 | 83 | |
| 95 | − asm volatile("movw %2,%w0\n\t" | |
| 84 | + asm volatile("movzwl %2, %0\n\t" | |
| 96 | 85 | "cmpb %h0,%b0\n\t" |
| 86 | + "leal 0x100(%" REG_PTR_MODE "0), %1\n\t" | |
| 97 | 87 | "jne 1f\n\t" |
| 98 | − "movw %w0,%w1\n\t" | |
| 99 | − "incb %h1\n\t" | |
| 100 | 88 | LOCK_PREFIX "cmpxchgw %w1,%2\n\t" |
| 101 | 89 | "1:" |
| 102 | 90 | "sete %b1\n\t" |
| 103 | 91 | "movzbl %b1,%0\n\t" |
| 104 | − : "=&a" (tmp), "=Q" (new), "+m" (lock->slock) | |
| 92 | + : "=&a" (tmp), "=&q" (new), "+m" (lock->slock) | |
| 105 | 93 | : |
| 106 | 94 | : "memory", "cc"); |
| 107 | 95 | |
| @@ -116,19 +104,7 @@ static __always_inline void __ticket_spin_unlock(raw_spinlock_t *lock) · 8 unmodified lines | ||
| 116 | 104 | : "memory", "cc"); |
| 117 | 105 | } |
| 118 | 106 | #else |
| 119 | −static inline int __ticket_spin_is_locked(raw_spinlock_t *lock) | |
| 120 | −{ | |
| 121 | − int tmp = ACCESS_ONCE(lock->slock); | |
| 122 | − | |
| 123 | − return (((tmp >> 16) & 0xffff) != (tmp & 0xffff)); | |
| 124 | −} | |
| 125 | − | |
| 126 | −static inline int __ticket_spin_is_contended(raw_spinlock_t *lock) | |
| 127 | −{ | |
| 128 | − int tmp = ACCESS_ONCE(lock->slock); | |
| 129 | − | |
| 130 | − return (((tmp >> 16) - tmp) & 0xffff) > 1; | |
| 131 | −} | |
| 107 | +#define TICKET_SHIFT 16 | |
| 132 | 108 | |
| 133 | 109 | static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock) |
| 134 | 110 | { |
| @@ -146,7 +122,7 @@ static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock) · 11 unmodified lines | ||
| 146 | 122 | /* don't need lfence here, because loads are in-order */ |
| 147 | 123 | "jmp 1b\n" |
| 148 | 124 | "2:" |
| 149 | − : "+Q" (inc), "+m" (lock->slock), "=r" (tmp) | |
| 125 | + : "+r" (inc), "+m" (lock->slock), "=&r" (tmp) | |
| 150 | 126 | : |
| 151 | 127 | : "memory", "cc"); |
| 152 | 128 | } |
| @@ -160,13 +136,13 @@ static __always_inline int __ticket_spin_trylock(raw_spinlock_t *lock) · 7 unmodified lines | ||
| 160 | 136 | "movl %0,%1\n\t" |
| 161 | 137 | "roll $16, %0\n\t" |
| 162 | 138 | "cmpl %0,%1\n\t" |
| 139 | + "leal 0x00010000(%" REG_PTR_MODE "0), %1\n\t" | |
| 163 | 140 | "jne 1f\n\t" |
| 164 | − "addl $0x00010000, %1\n\t" | |
| 165 | 141 | LOCK_PREFIX "cmpxchgl %1,%2\n\t" |
| 166 | 142 | "1:" |
| 167 | 143 | "sete %b1\n\t" |
| 168 | 144 | "movzbl %b1,%0\n\t" |
| 169 | − : "=&a" (tmp), "=r" (new), "+m" (lock->slock) | |
| 145 | + : "=&a" (tmp), "=&q" (new), "+m" (lock->slock) | |
| 170 | 146 | : |
| 171 | 147 | : "memory", "cc"); |
| 172 | 148 | |
| @@ -182,6 +158,20 @@ static __always_inline void __ticket_spin_unlock(raw_spinlock_t *lock) · 9 unmodified lines | ||
| 182 | 158 | } |
| 183 | 159 | #endif |
| 184 | 160 | |
| 161 | +static inline int __ticket_spin_is_locked(raw_spinlock_t *lock) | |
| 162 | +{ | |
| 163 | + int tmp = ACCESS_ONCE(lock->slock); | |
| 164 | + | |
| 165 | + return !!(((tmp >> TICKET_SHIFT) ^ tmp) & ((1 << TICKET_SHIFT) - 1)); | |
| 166 | +} | |
| 167 | + | |
| 168 | +static inline int __ticket_spin_is_contended(raw_spinlock_t *lock) | |
| 169 | +{ | |
| 170 | + int tmp = ACCESS_ONCE(lock->slock); | |
| 171 | + | |
| 172 | + return (((tmp >> TICKET_SHIFT) - tmp) & ((1 << TICKET_SHIFT) - 1)) > 1; | |
| 173 | +} | |
| 174 | + | |
| 185 | 175 | #ifdef CONFIG_PARAVIRT |
| 186 | 176 | /* |
| 187 | 177 | * Define virtualization-friendly old-style lock byte lock, for use in |
| @@ -1,6 +1,8 @@ | ||
| 1 | 1 | #ifndef ASM_X86__TRAPS_H |
| 2 | 2 | #define ASM_X86__TRAPS_H |
| 3 | 3 | |
| 4 | +#include <asm/debugreg.h> | |
| 5 | + | |
| 4 | 6 | /* Common in X86_32 and X86_64 */ |
| 5 | 7 | asmlinkage void divide_error(void); |
| 6 | 8 | asmlinkage void debug(void); |
| @@ -36,6 +38,16 @@ void do_invalid_op(struct pt_regs *, long); · 29 unmodified lines | ||
| 36 | 38 | void do_general_protection(struct pt_regs *, long); |
| 37 | 39 | void do_nmi(struct pt_regs *, long); |
| 38 | 40 | |
| 41 | +static inline int get_si_code(unsigned long condition) | |
| 42 | +{ | |
| 43 | + if (condition & DR_STEP) | |
| 44 | + return TRAP_TRACE; | |
| 45 | + else if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) | |
| 46 | + return TRAP_HWBKPT; | |
| 47 | + else | |
| 48 | + return TRAP_BRKPT; | |
| 49 | +} | |
| 50 | + | |
| 39 | 51 | extern int panic_on_unrecovered_nmi; |
| 40 | 52 | extern int kstack_depth_to_print; |
| 41 | 53 | |