diff options
Diffstat (limited to 'arch/x86/kernel/signal_64.c')
| -rw-r--r-- | arch/x86/kernel/signal_64.c | 62 |
1 files changed, 30 insertions, 32 deletions
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c index 4d32487805ef..694aa888bb19 100644 --- a/arch/x86/kernel/signal_64.c +++ b/arch/x86/kernel/signal_64.c | |||
| @@ -20,9 +20,10 @@ | |||
| 20 | #include <linux/stddef.h> | 20 | #include <linux/stddef.h> |
| 21 | #include <linux/personality.h> | 21 | #include <linux/personality.h> |
| 22 | #include <linux/compiler.h> | 22 | #include <linux/compiler.h> |
| 23 | #include <linux/uaccess.h> | ||
| 24 | |||
| 23 | #include <asm/processor.h> | 25 | #include <asm/processor.h> |
| 24 | #include <asm/ucontext.h> | 26 | #include <asm/ucontext.h> |
| 25 | #include <asm/uaccess.h> | ||
| 26 | #include <asm/i387.h> | 27 | #include <asm/i387.h> |
| 27 | #include <asm/proto.h> | 28 | #include <asm/proto.h> |
| 28 | #include <asm/ia32_unistd.h> | 29 | #include <asm/ia32_unistd.h> |
| @@ -44,11 +45,6 @@ | |||
| 44 | # define FIX_EFLAGS __FIX_EFLAGS | 45 | # define FIX_EFLAGS __FIX_EFLAGS |
| 45 | #endif | 46 | #endif |
| 46 | 47 | ||
| 47 | int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | ||
| 48 | sigset_t *set, struct pt_regs * regs); | ||
| 49 | int ia32_setup_frame(int sig, struct k_sigaction *ka, | ||
| 50 | sigset_t *set, struct pt_regs * regs); | ||
| 51 | |||
| 52 | asmlinkage long | 48 | asmlinkage long |
| 53 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | 49 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, |
| 54 | struct pt_regs *regs) | 50 | struct pt_regs *regs) |
| @@ -131,7 +127,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | |||
| 131 | /* Always make any pending restarted system calls return -EINTR */ | 127 | /* Always make any pending restarted system calls return -EINTR */ |
| 132 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | 128 | current_thread_info()->restart_block.fn = do_no_restart_syscall; |
| 133 | 129 | ||
| 134 | #define COPY(x) err |= __get_user(regs->x, &sc->x) | 130 | #define COPY(x) (err |= __get_user(regs->x, &sc->x)) |
| 135 | 131 | ||
| 136 | COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); | 132 | COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); |
| 137 | COPY(dx); COPY(cx); COPY(ip); | 133 | COPY(dx); COPY(cx); COPY(ip); |
| @@ -161,7 +157,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | |||
| 161 | } | 157 | } |
| 162 | 158 | ||
| 163 | { | 159 | { |
| 164 | struct _fpstate __user * buf; | 160 | struct _fpstate __user *buf; |
| 165 | err |= __get_user(buf, &sc->fpstate); | 161 | err |= __get_user(buf, &sc->fpstate); |
| 166 | 162 | ||
| 167 | if (buf) { | 163 | if (buf) { |
| @@ -201,7 +197,7 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | |||
| 201 | current->blocked = set; | 197 | current->blocked = set; |
| 202 | recalc_sigpending(); | 198 | recalc_sigpending(); |
| 203 | spin_unlock_irq(¤t->sighand->siglock); | 199 | spin_unlock_irq(¤t->sighand->siglock); |
| 204 | 200 | ||
| 205 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) | 201 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) |
| 206 | goto badframe; | 202 | goto badframe; |
| 207 | 203 | ||
| @@ -211,16 +207,17 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | |||
| 211 | return ax; | 207 | return ax; |
| 212 | 208 | ||
| 213 | badframe: | 209 | badframe: |
| 214 | signal_fault(regs,frame,"sigreturn"); | 210 | signal_fault(regs, frame, "sigreturn"); |
| 215 | return 0; | 211 | return 0; |
| 216 | } | 212 | } |
| 217 | 213 | ||
| 218 | /* | 214 | /* |
| 219 | * Set up a signal frame. | 215 | * Set up a signal frame. |
| 220 | */ | 216 | */ |
| 221 | 217 | ||
| 222 | static inline int | 218 | static inline int |
| 223 | 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) | ||
| 224 | { | 221 | { |
| 225 | int err = 0; | 222 | int err = 0; |
| 226 | 223 | ||
| @@ -276,35 +273,35 @@ get_stack(struct k_sigaction *ka, struct pt_regs *regs, unsigned long size) | |||
| 276 | } | 273 | } |
| 277 | 274 | ||
| 278 | 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, |
| 279 | sigset_t *set, struct pt_regs * regs) | 276 | sigset_t *set, struct pt_regs *regs) |
| 280 | { | 277 | { |
| 281 | struct rt_sigframe __user *frame; | 278 | struct rt_sigframe __user *frame; |
| 282 | struct _fpstate __user *fp = NULL; | 279 | struct _fpstate __user *fp = NULL; |
| 283 | int err = 0; | 280 | int err = 0; |
| 284 | struct task_struct *me = current; | 281 | struct task_struct *me = current; |
| 285 | 282 | ||
| 286 | if (used_math()) { | 283 | if (used_math()) { |
| 287 | fp = get_stack(ka, regs, sizeof(struct _fpstate)); | 284 | fp = get_stack(ka, regs, sizeof(struct _fpstate)); |
| 288 | frame = (void __user *)round_down( | 285 | frame = (void __user *)round_down( |
| 289 | (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8; | 286 | (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8; |
| 290 | 287 | ||
| 291 | if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) | 288 | if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) |
| 292 | goto give_sigsegv; | 289 | goto give_sigsegv; |
| 293 | 290 | ||
| 294 | if (save_i387(fp) < 0) | 291 | if (save_i387(fp) < 0) |
| 295 | err |= -1; | 292 | err |= -1; |
| 296 | } else | 293 | } else |
| 297 | frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8; | 294 | frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8; |
| 298 | 295 | ||
| 299 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 296 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
| 300 | goto give_sigsegv; | 297 | goto give_sigsegv; |
| 301 | 298 | ||
| 302 | if (ka->sa.sa_flags & SA_SIGINFO) { | 299 | if (ka->sa.sa_flags & SA_SIGINFO) { |
| 303 | err |= copy_siginfo_to_user(&frame->info, info); | 300 | err |= copy_siginfo_to_user(&frame->info, info); |
| 304 | if (err) | 301 | if (err) |
| 305 | goto give_sigsegv; | 302 | goto give_sigsegv; |
| 306 | } | 303 | } |
| 307 | 304 | ||
| 308 | /* Create the ucontext. */ | 305 | /* Create the ucontext. */ |
| 309 | err |= __put_user(0, &frame->uc.uc_flags); | 306 | err |= __put_user(0, &frame->uc.uc_flags); |
| 310 | err |= __put_user(0, &frame->uc.uc_link); | 307 | err |= __put_user(0, &frame->uc.uc_link); |
| @@ -314,9 +311,9 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
| 314 | 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); |
| 315 | 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); |
| 316 | err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate); | 313 | err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate); |
| 317 | if (sizeof(*set) == 16) { | 314 | if (sizeof(*set) == 16) { |
| 318 | __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); | 315 | __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); |
| 319 | __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]); | 316 | __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]); |
| 320 | } else | 317 | } else |
| 321 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 318 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
| 322 | 319 | ||
| @@ -327,7 +324,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
| 327 | err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); | 324 | err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); |
| 328 | } else { | 325 | } else { |
| 329 | /* could use a vstub here */ | 326 | /* could use a vstub here */ |
| 330 | goto give_sigsegv; | 327 | goto give_sigsegv; |
| 331 | } | 328 | } |
| 332 | 329 | ||
| 333 | if (err) | 330 | if (err) |
| @@ -335,7 +332,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
| 335 | 332 | ||
| 336 | /* Set up registers for signal handler */ | 333 | /* Set up registers for signal handler */ |
| 337 | regs->di = sig; | 334 | regs->di = sig; |
| 338 | /* In case the signal handler was declared without prototypes */ | 335 | /* In case the signal handler was declared without prototypes */ |
| 339 | regs->ax = 0; | 336 | regs->ax = 0; |
| 340 | 337 | ||
| 341 | /* 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 |
| @@ -359,7 +356,7 @@ give_sigsegv: | |||
| 359 | 356 | ||
| 360 | /* | 357 | /* |
| 361 | * OK, we're invoking a handler | 358 | * OK, we're invoking a handler |
| 362 | */ | 359 | */ |
| 363 | 360 | ||
| 364 | static int | 361 | static int |
| 365 | 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, |
| @@ -403,7 +400,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
| 403 | ret = ia32_setup_rt_frame(sig, ka, info, oldset, regs); | 400 | ret = ia32_setup_rt_frame(sig, ka, info, oldset, regs); |
| 404 | else | 401 | else |
| 405 | ret = ia32_setup_frame(sig, ka, oldset, regs); | 402 | ret = ia32_setup_frame(sig, ka, oldset, regs); |
| 406 | } else | 403 | } else |
| 407 | #endif | 404 | #endif |
| 408 | ret = setup_rt_frame(sig, ka, info, oldset, regs); | 405 | ret = setup_rt_frame(sig, ka, info, oldset, regs); |
| 409 | 406 | ||
| @@ -429,9 +426,9 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
| 429 | regs->flags &= ~X86_EFLAGS_TF; | 426 | regs->flags &= ~X86_EFLAGS_TF; |
| 430 | 427 | ||
| 431 | spin_lock_irq(¤t->sighand->siglock); | 428 | spin_lock_irq(¤t->sighand->siglock); |
| 432 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 429 | sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); |
| 433 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 430 | if (!(ka->sa.sa_flags & SA_NODEFER)) |
| 434 | sigaddset(¤t->blocked,sig); | 431 | sigaddset(¤t->blocked, sig); |
| 435 | recalc_sigpending(); | 432 | recalc_sigpending(); |
| 436 | spin_unlock_irq(¤t->sighand->siglock); | 433 | spin_unlock_irq(¤t->sighand->siglock); |
| 437 | 434 | ||
| @@ -541,14 +538,15 @@ void do_notify_resume(struct pt_regs *regs, void *unused, | |||
| 541 | } | 538 | } |
| 542 | 539 | ||
| 543 | 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) |
| 544 | { | 541 | { |
| 545 | struct task_struct *me = current; | 542 | struct task_struct *me = current; |
| 546 | if (show_unhandled_signals && printk_ratelimit()) { | 543 | if (show_unhandled_signals && printk_ratelimit()) { |
| 547 | 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", |
| 548 | 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); | ||
| 549 | print_vma_addr(" in ", regs->ip); | 547 | print_vma_addr(" in ", regs->ip); |
| 550 | printk("\n"); | 548 | printk("\n"); |
| 551 | } | 549 | } |
| 552 | 550 | ||
| 553 | force_sig(SIGSEGV, me); | 551 | force_sig(SIGSEGV, me); |
| 554 | } | 552 | } |
