diff options
| -rw-r--r-- | arch/x86/kernel/signal.c | 291 |
1 files changed, 154 insertions, 137 deletions
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 89bb7668041d..cf34eb37fbee 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c | |||
| @@ -51,24 +51,24 @@ | |||
| 51 | #endif | 51 | #endif |
| 52 | 52 | ||
| 53 | #define COPY(x) { \ | 53 | #define COPY(x) { \ |
| 54 | err |= __get_user(regs->x, &sc->x); \ | 54 | get_user_ex(regs->x, &sc->x); \ |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | #define COPY_SEG(seg) { \ | 57 | #define COPY_SEG(seg) { \ |
| 58 | unsigned short tmp; \ | 58 | unsigned short tmp; \ |
| 59 | err |= __get_user(tmp, &sc->seg); \ | 59 | get_user_ex(tmp, &sc->seg); \ |
| 60 | regs->seg = tmp; \ | 60 | regs->seg = tmp; \ |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | #define COPY_SEG_CPL3(seg) { \ | 63 | #define COPY_SEG_CPL3(seg) { \ |
| 64 | unsigned short tmp; \ | 64 | unsigned short tmp; \ |
| 65 | err |= __get_user(tmp, &sc->seg); \ | 65 | get_user_ex(tmp, &sc->seg); \ |
| 66 | regs->seg = tmp | 3; \ | 66 | regs->seg = tmp | 3; \ |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | #define GET_SEG(seg) { \ | 69 | #define GET_SEG(seg) { \ |
| 70 | unsigned short tmp; \ | 70 | unsigned short tmp; \ |
| 71 | err |= __get_user(tmp, &sc->seg); \ | 71 | get_user_ex(tmp, &sc->seg); \ |
| 72 | loadsegment(seg, tmp); \ | 72 | loadsegment(seg, tmp); \ |
| 73 | } | 73 | } |
| 74 | 74 | ||
| @@ -83,45 +83,49 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | |||
| 83 | /* Always make any pending restarted system calls return -EINTR */ | 83 | /* Always make any pending restarted system calls return -EINTR */ |
| 84 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | 84 | current_thread_info()->restart_block.fn = do_no_restart_syscall; |
| 85 | 85 | ||
| 86 | get_user_try { | ||
| 87 | |||
| 86 | #ifdef CONFIG_X86_32 | 88 | #ifdef CONFIG_X86_32 |
| 87 | GET_SEG(gs); | 89 | GET_SEG(gs); |
| 88 | COPY_SEG(fs); | 90 | COPY_SEG(fs); |
| 89 | COPY_SEG(es); | 91 | COPY_SEG(es); |
| 90 | COPY_SEG(ds); | 92 | COPY_SEG(ds); |
| 91 | #endif /* CONFIG_X86_32 */ | 93 | #endif /* CONFIG_X86_32 */ |
| 92 | 94 | ||
| 93 | COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); | 95 | COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); |
| 94 | COPY(dx); COPY(cx); COPY(ip); | 96 | COPY(dx); COPY(cx); COPY(ip); |
| 95 | 97 | ||
| 96 | #ifdef CONFIG_X86_64 | 98 | #ifdef CONFIG_X86_64 |
| 97 | COPY(r8); | 99 | COPY(r8); |
| 98 | COPY(r9); | 100 | COPY(r9); |
| 99 | COPY(r10); | 101 | COPY(r10); |
| 100 | COPY(r11); | 102 | COPY(r11); |
| 101 | COPY(r12); | 103 | COPY(r12); |
| 102 | COPY(r13); | 104 | COPY(r13); |
| 103 | COPY(r14); | 105 | COPY(r14); |
| 104 | COPY(r15); | 106 | COPY(r15); |
| 105 | #endif /* CONFIG_X86_64 */ | 107 | #endif /* CONFIG_X86_64 */ |
| 106 | 108 | ||
| 107 | #ifdef CONFIG_X86_32 | 109 | #ifdef CONFIG_X86_32 |
| 108 | COPY_SEG_CPL3(cs); | 110 | COPY_SEG_CPL3(cs); |
| 109 | COPY_SEG_CPL3(ss); | 111 | COPY_SEG_CPL3(ss); |
| 110 | #else /* !CONFIG_X86_32 */ | 112 | #else /* !CONFIG_X86_32 */ |
| 111 | /* Kernel saves and restores only the CS segment register on signals, | 113 | /* Kernel saves and restores only the CS segment register on signals, |
| 112 | * which is the bare minimum needed to allow mixed 32/64-bit code. | 114 | * which is the bare minimum needed to allow mixed 32/64-bit code. |
| 113 | * App's signal handler can save/restore other segments if needed. */ | 115 | * App's signal handler can save/restore other segments if needed. */ |
| 114 | COPY_SEG_CPL3(cs); | 116 | COPY_SEG_CPL3(cs); |
| 115 | #endif /* CONFIG_X86_32 */ | 117 | #endif /* CONFIG_X86_32 */ |
| 116 | 118 | ||
| 117 | err |= __get_user(tmpflags, &sc->flags); | 119 | get_user_ex(tmpflags, &sc->flags); |
| 118 | regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); | 120 | regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); |
| 119 | regs->orig_ax = -1; /* disable syscall checks */ | 121 | regs->orig_ax = -1; /* disable syscall checks */ |
| 122 | |||
| 123 | get_user_ex(buf, &sc->fpstate); | ||
| 124 | err |= restore_i387_xstate(buf); | ||
| 120 | 125 | ||
| 121 | err |= __get_user(buf, &sc->fpstate); | 126 | get_user_ex(*pax, &sc->ax); |
| 122 | err |= restore_i387_xstate(buf); | 127 | } get_user_catch(err); |
| 123 | 128 | ||
| 124 | err |= __get_user(*pax, &sc->ax); | ||
| 125 | return err; | 129 | return err; |
| 126 | } | 130 | } |
| 127 | 131 | ||
| @@ -131,57 +135,60 @@ setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, | |||
| 131 | { | 135 | { |
| 132 | int err = 0; | 136 | int err = 0; |
| 133 | 137 | ||
| 138 | put_user_try { | ||
| 139 | |||
| 134 | #ifdef CONFIG_X86_32 | 140 | #ifdef CONFIG_X86_32 |
| 135 | { | 141 | { |
| 136 | unsigned int tmp; | 142 | unsigned int tmp; |
| 137 | 143 | ||
| 138 | savesegment(gs, tmp); | 144 | savesegment(gs, tmp); |
| 139 | err |= __put_user(tmp, (unsigned int __user *)&sc->gs); | 145 | put_user_ex(tmp, (unsigned int __user *)&sc->gs); |
| 140 | } | 146 | } |
| 141 | err |= __put_user(regs->fs, (unsigned int __user *)&sc->fs); | 147 | put_user_ex(regs->fs, (unsigned int __user *)&sc->fs); |
| 142 | err |= __put_user(regs->es, (unsigned int __user *)&sc->es); | 148 | put_user_ex(regs->es, (unsigned int __user *)&sc->es); |
| 143 | err |= __put_user(regs->ds, (unsigned int __user *)&sc->ds); | 149 | put_user_ex(regs->ds, (unsigned int __user *)&sc->ds); |
| 144 | #endif /* CONFIG_X86_32 */ | 150 | #endif /* CONFIG_X86_32 */ |
| 145 | 151 | ||
| 146 | err |= __put_user(regs->di, &sc->di); | 152 | put_user_ex(regs->di, &sc->di); |
| 147 | err |= __put_user(regs->si, &sc->si); | 153 | put_user_ex(regs->si, &sc->si); |
| 148 | err |= __put_user(regs->bp, &sc->bp); | 154 | put_user_ex(regs->bp, &sc->bp); |
| 149 | err |= __put_user(regs->sp, &sc->sp); | 155 | put_user_ex(regs->sp, &sc->sp); |
| 150 | err |= __put_user(regs->bx, &sc->bx); | 156 | put_user_ex(regs->bx, &sc->bx); |
| 151 | err |= __put_user(regs->dx, &sc->dx); | 157 | put_user_ex(regs->dx, &sc->dx); |
| 152 | err |= __put_user(regs->cx, &sc->cx); | 158 | put_user_ex(regs->cx, &sc->cx); |
| 153 | err |= __put_user(regs->ax, &sc->ax); | 159 | put_user_ex(regs->ax, &sc->ax); |
| 154 | #ifdef CONFIG_X86_64 | 160 | #ifdef CONFIG_X86_64 |
| 155 | err |= __put_user(regs->r8, &sc->r8); | 161 | put_user_ex(regs->r8, &sc->r8); |
| 156 | err |= __put_user(regs->r9, &sc->r9); | 162 | put_user_ex(regs->r9, &sc->r9); |
| 157 | err |= __put_user(regs->r10, &sc->r10); | 163 | put_user_ex(regs->r10, &sc->r10); |
| 158 | err |= __put_user(regs->r11, &sc->r11); | 164 | put_user_ex(regs->r11, &sc->r11); |
| 159 | err |= __put_user(regs->r12, &sc->r12); | 165 | put_user_ex(regs->r12, &sc->r12); |
| 160 | err |= __put_user(regs->r13, &sc->r13); | 166 | put_user_ex(regs->r13, &sc->r13); |
| 161 | err |= __put_user(regs->r14, &sc->r14); | 167 | put_user_ex(regs->r14, &sc->r14); |
| 162 | err |= __put_user(regs->r15, &sc->r15); | 168 | put_user_ex(regs->r15, &sc->r15); |
| 163 | #endif /* CONFIG_X86_64 */ | 169 | #endif /* CONFIG_X86_64 */ |
| 164 | 170 | ||
| 165 | err |= __put_user(current->thread.trap_no, &sc->trapno); | 171 | put_user_ex(current->thread.trap_no, &sc->trapno); |
| 166 | err |= __put_user(current->thread.error_code, &sc->err); | 172 | put_user_ex(current->thread.error_code, &sc->err); |
| 167 | err |= __put_user(regs->ip, &sc->ip); | 173 | put_user_ex(regs->ip, &sc->ip); |
| 168 | #ifdef CONFIG_X86_32 | 174 | #ifdef CONFIG_X86_32 |
| 169 | err |= __put_user(regs->cs, (unsigned int __user *)&sc->cs); | 175 | put_user_ex(regs->cs, (unsigned int __user *)&sc->cs); |
| 170 | err |= __put_user(regs->flags, &sc->flags); | 176 | put_user_ex(regs->flags, &sc->flags); |
| 171 | err |= __put_user(regs->sp, &sc->sp_at_signal); | 177 | put_user_ex(regs->sp, &sc->sp_at_signal); |
| 172 | err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss); | 178 | put_user_ex(regs->ss, (unsigned int __user *)&sc->ss); |
| 173 | #else /* !CONFIG_X86_32 */ | 179 | #else /* !CONFIG_X86_32 */ |
| 174 | err |= __put_user(regs->flags, &sc->flags); | 180 | put_user_ex(regs->flags, &sc->flags); |
| 175 | err |= __put_user(regs->cs, &sc->cs); | 181 | put_user_ex(regs->cs, &sc->cs); |
| 176 | err |= __put_user(0, &sc->gs); | 182 | put_user_ex(0, &sc->gs); |
| 177 | err |= __put_user(0, &sc->fs); | 183 | put_user_ex(0, &sc->fs); |
| 178 | #endif /* CONFIG_X86_32 */ | 184 | #endif /* CONFIG_X86_32 */ |
| 179 | 185 | ||
| 180 | err |= __put_user(fpstate, &sc->fpstate); | 186 | put_user_ex(fpstate, &sc->fpstate); |
| 181 | 187 | ||
| 182 | /* non-iBCS2 extensions.. */ | 188 | /* non-iBCS2 extensions.. */ |
| 183 | err |= __put_user(mask, &sc->oldmask); | 189 | put_user_ex(mask, &sc->oldmask); |
| 184 | err |= __put_user(current->thread.cr2, &sc->cr2); | 190 | put_user_ex(current->thread.cr2, &sc->cr2); |
| 191 | } put_user_catch(err); | ||
| 185 | 192 | ||
| 186 | return err; | 193 | return err; |
| 187 | } | 194 | } |
| @@ -336,43 +343,41 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
| 336 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 343 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
| 337 | return -EFAULT; | 344 | return -EFAULT; |
| 338 | 345 | ||
| 339 | err |= __put_user(sig, &frame->sig); | 346 | put_user_try { |
| 340 | err |= __put_user(&frame->info, &frame->pinfo); | 347 | put_user_ex(sig, &frame->sig); |
| 341 | err |= __put_user(&frame->uc, &frame->puc); | 348 | put_user_ex(&frame->info, &frame->pinfo); |
| 342 | err |= copy_siginfo_to_user(&frame->info, info); | 349 | put_user_ex(&frame->uc, &frame->puc); |
| 343 | if (err) | 350 | err |= copy_siginfo_to_user(&frame->info, info); |
| 344 | return -EFAULT; | ||
| 345 | |||
| 346 | /* Create the ucontext. */ | ||
| 347 | if (cpu_has_xsave) | ||
| 348 | err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags); | ||
| 349 | else | ||
| 350 | err |= __put_user(0, &frame->uc.uc_flags); | ||
| 351 | err |= __put_user(0, &frame->uc.uc_link); | ||
| 352 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | ||
| 353 | err |= __put_user(sas_ss_flags(regs->sp), | ||
| 354 | &frame->uc.uc_stack.ss_flags); | ||
| 355 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | ||
| 356 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, | ||
| 357 | regs, set->sig[0]); | ||
| 358 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | ||
| 359 | if (err) | ||
| 360 | return -EFAULT; | ||
| 361 | 351 | ||
| 362 | /* Set up to return from userspace. */ | 352 | /* Create the ucontext. */ |
| 363 | restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn); | 353 | if (cpu_has_xsave) |
| 364 | if (ka->sa.sa_flags & SA_RESTORER) | 354 | put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags); |
| 365 | restorer = ka->sa.sa_restorer; | 355 | else |
| 366 | err |= __put_user(restorer, &frame->pretcode); | 356 | put_user_ex(0, &frame->uc.uc_flags); |
| 357 | put_user_ex(0, &frame->uc.uc_link); | ||
| 358 | put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | ||
| 359 | put_user_ex(sas_ss_flags(regs->sp), | ||
| 360 | &frame->uc.uc_stack.ss_flags); | ||
| 361 | put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | ||
| 362 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, | ||
| 363 | regs, set->sig[0]); | ||
| 364 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | ||
| 365 | |||
| 366 | /* Set up to return from userspace. */ | ||
| 367 | restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn); | ||
| 368 | if (ka->sa.sa_flags & SA_RESTORER) | ||
| 369 | restorer = ka->sa.sa_restorer; | ||
| 370 | put_user_ex(restorer, &frame->pretcode); | ||
| 367 | 371 | ||
| 368 | /* | 372 | /* |
| 369 | * This is movl $__NR_rt_sigreturn, %ax ; int $0x80 | 373 | * This is movl $__NR_rt_sigreturn, %ax ; int $0x80 |
| 370 | * | 374 | * |
| 371 | * WE DO NOT USE IT ANY MORE! It's only left here for historical | 375 | * WE DO NOT USE IT ANY MORE! It's only left here for historical |
| 372 | * reasons and because gdb uses it as a signature to notice | 376 | * reasons and because gdb uses it as a signature to notice |
| 373 | * signal handler stack frames. | 377 | * signal handler stack frames. |
| 374 | */ | 378 | */ |
| 375 | err |= __put_user(*((u64 *)&rt_retcode), (u64 *)frame->retcode); | 379 | put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode); |
| 380 | } put_user_catch(err); | ||
| 376 | 381 | ||
| 377 | if (err) | 382 | if (err) |
| 378 | return -EFAULT; | 383 | return -EFAULT; |
| @@ -436,28 +441,30 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
| 436 | return -EFAULT; | 441 | return -EFAULT; |
| 437 | } | 442 | } |
| 438 | 443 | ||
| 439 | /* Create the ucontext. */ | 444 | put_user_try { |
| 440 | if (cpu_has_xsave) | 445 | /* Create the ucontext. */ |
| 441 | err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags); | 446 | if (cpu_has_xsave) |
| 442 | else | 447 | put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags); |
| 443 | err |= __put_user(0, &frame->uc.uc_flags); | 448 | else |
| 444 | err |= __put_user(0, &frame->uc.uc_link); | 449 | put_user_ex(0, &frame->uc.uc_flags); |
| 445 | err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | 450 | put_user_ex(0, &frame->uc.uc_link); |
| 446 | err |= __put_user(sas_ss_flags(regs->sp), | 451 | put_user_ex(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); |
| 447 | &frame->uc.uc_stack.ss_flags); | 452 | put_user_ex(sas_ss_flags(regs->sp), |
| 448 | err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); | 453 | &frame->uc.uc_stack.ss_flags); |
| 449 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]); | 454 | put_user_ex(me->sas_ss_size, &frame->uc.uc_stack.ss_size); |
| 450 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 455 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]); |
| 451 | 456 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | |
| 452 | /* Set up to return from userspace. If provided, use a stub | 457 | |
| 453 | already in userspace. */ | 458 | /* Set up to return from userspace. If provided, use a stub |
| 454 | /* x86-64 should always use SA_RESTORER. */ | 459 | already in userspace. */ |
| 455 | if (ka->sa.sa_flags & SA_RESTORER) { | 460 | /* x86-64 should always use SA_RESTORER. */ |
| 456 | err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); | 461 | if (ka->sa.sa_flags & SA_RESTORER) { |
| 457 | } else { | 462 | put_user_ex(ka->sa.sa_restorer, &frame->pretcode); |
| 458 | /* could use a vstub here */ | 463 | } else { |
| 459 | return -EFAULT; | 464 | /* could use a vstub here */ |
| 460 | } | 465 | err |= -EFAULT; |
| 466 | } | ||
| 467 | } put_user_catch(err); | ||
| 461 | 468 | ||
| 462 | if (err) | 469 | if (err) |
| 463 | return -EFAULT; | 470 | return -EFAULT; |
| @@ -509,31 +516,41 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, | |||
| 509 | struct old_sigaction __user *oact) | 516 | struct old_sigaction __user *oact) |
| 510 | { | 517 | { |
| 511 | struct k_sigaction new_ka, old_ka; | 518 | struct k_sigaction new_ka, old_ka; |
| 512 | int ret; | 519 | int ret = 0; |
| 513 | 520 | ||
| 514 | if (act) { | 521 | if (act) { |
| 515 | old_sigset_t mask; | 522 | old_sigset_t mask; |
| 516 | 523 | ||
| 517 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | 524 | if (!access_ok(VERIFY_READ, act, sizeof(*act))) |
| 518 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | ||
| 519 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) | ||
| 520 | return -EFAULT; | 525 | return -EFAULT; |
| 521 | 526 | ||
| 522 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); | 527 | get_user_try { |
| 523 | __get_user(mask, &act->sa_mask); | 528 | get_user_ex(new_ka.sa.sa_handler, &act->sa_handler); |
| 529 | get_user_ex(new_ka.sa.sa_flags, &act->sa_flags); | ||
| 530 | get_user_ex(mask, &act->sa_mask); | ||
| 531 | get_user_ex(new_ka.sa.sa_restorer, &act->sa_restorer); | ||
| 532 | } get_user_catch(ret); | ||
| 533 | |||
| 534 | if (ret) | ||
| 535 | return -EFAULT; | ||
| 524 | siginitset(&new_ka.sa.sa_mask, mask); | 536 | siginitset(&new_ka.sa.sa_mask, mask); |
| 525 | } | 537 | } |
| 526 | 538 | ||
| 527 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | 539 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); |
| 528 | 540 | ||
| 529 | if (!ret && oact) { | 541 | if (!ret && oact) { |
| 530 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | 542 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) |
| 531 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | ||
| 532 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) | ||
| 533 | return -EFAULT; | 543 | return -EFAULT; |
| 534 | 544 | ||
| 535 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | 545 | put_user_try { |
| 536 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | 546 | put_user_ex(old_ka.sa.sa_handler, &oact->sa_handler); |
| 547 | put_user_ex(old_ka.sa.sa_flags, &oact->sa_flags); | ||
| 548 | put_user_ex(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | ||
| 549 | put_user_ex(old_ka.sa.sa_restorer, &oact->sa_restorer); | ||
| 550 | } put_user_catch(ret); | ||
| 551 | |||
| 552 | if (ret) | ||
| 553 | return -EFAULT; | ||
| 537 | } | 554 | } |
| 538 | 555 | ||
| 539 | return ret; | 556 | return ret; |
