diff options
author | Hiroshi Shimamoto <h-shimamoto@ct.jp.nec.com> | 2008-11-24 21:23:12 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-11-25 23:11:53 -0500 |
commit | bfeb91a9435889ef4fe7bfbb4b673f625e69e790 (patch) | |
tree | 904f16d0eba56b7812b1462de6bc28df6c70371f /arch | |
parent | 2601657d223d82053d4e1fe1063091401e6b860a (diff) |
x86: signal: cosmetic unification of __setup_sigframe() and __setup_rt_sigframe()
Impact: cleanup
Add #ifdef directive to unify __setup_sigframe() and __setup_rt_sigframe().
Move them after {setup|restore}_sigcontext() declaration.
Signed-off-by: Hiroshi Shimamoto <h-shimamoto@ct.jp.nec.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kernel/signal_32.c | 469 | ||||
-rw-r--r-- | arch/x86/kernel/signal_64.c | 309 |
2 files changed, 536 insertions, 242 deletions
diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c index b3f30d2a2178..e9f71298e746 100644 --- a/arch/x86/kernel/signal_32.c +++ b/arch/x86/kernel/signal_32.c | |||
@@ -48,28 +48,6 @@ | |||
48 | # define FIX_EFLAGS __FIX_EFLAGS | 48 | # define FIX_EFLAGS __FIX_EFLAGS |
49 | #endif | 49 | #endif |
50 | 50 | ||
51 | static const struct { | ||
52 | u16 poplmovl; | ||
53 | u32 val; | ||
54 | u16 int80; | ||
55 | } __attribute__((packed)) retcode = { | ||
56 | 0xb858, /* popl %eax; movl $..., %eax */ | ||
57 | __NR_sigreturn, | ||
58 | 0x80cd, /* int $0x80 */ | ||
59 | }; | ||
60 | |||
61 | static const struct { | ||
62 | u8 movl; | ||
63 | u32 val; | ||
64 | u16 int80; | ||
65 | u8 pad; | ||
66 | } __attribute__((packed)) rt_retcode = { | ||
67 | 0xb8, /* movl $..., %eax */ | ||
68 | __NR_rt_sigreturn, | ||
69 | 0x80cd, /* int $0x80 */ | ||
70 | 0 | ||
71 | }; | ||
72 | |||
73 | #define COPY(x) { \ | 51 | #define COPY(x) { \ |
74 | err |= __get_user(regs->x, &sc->x); \ | 52 | err |= __get_user(regs->x, &sc->x); \ |
75 | } | 53 | } |
@@ -207,176 +185,30 @@ setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, | |||
207 | } | 185 | } |
208 | 186 | ||
209 | /* | 187 | /* |
210 | * Atomically swap in the new signal mask, and wait for a signal. | 188 | * Set up a signal frame. |
211 | */ | 189 | */ |
212 | asmlinkage int | ||
213 | sys_sigsuspend(int history0, int history1, old_sigset_t mask) | ||
214 | { | ||
215 | mask &= _BLOCKABLE; | ||
216 | spin_lock_irq(¤t->sighand->siglock); | ||
217 | current->saved_sigmask = current->blocked; | ||
218 | siginitset(¤t->blocked, mask); | ||
219 | recalc_sigpending(); | ||
220 | spin_unlock_irq(¤t->sighand->siglock); | ||
221 | |||
222 | current->state = TASK_INTERRUPTIBLE; | ||
223 | schedule(); | ||
224 | set_restore_sigmask(); | ||
225 | |||
226 | return -ERESTARTNOHAND; | ||
227 | } | ||
228 | |||
229 | asmlinkage int | ||
230 | sys_sigaction(int sig, const struct old_sigaction __user *act, | ||
231 | struct old_sigaction __user *oact) | ||
232 | { | ||
233 | struct k_sigaction new_ka, old_ka; | ||
234 | int ret; | ||
235 | |||
236 | if (act) { | ||
237 | old_sigset_t mask; | ||
238 | |||
239 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | ||
240 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | ||
241 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) | ||
242 | return -EFAULT; | ||
243 | |||
244 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); | ||
245 | __get_user(mask, &act->sa_mask); | ||
246 | siginitset(&new_ka.sa.sa_mask, mask); | ||
247 | } | ||
248 | |||
249 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | ||
250 | |||
251 | if (!ret && oact) { | ||
252 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | ||
253 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | ||
254 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) | ||
255 | return -EFAULT; | ||
256 | |||
257 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | ||
258 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | ||
259 | } | ||
260 | |||
261 | return ret; | ||
262 | } | ||
263 | |||
264 | #ifdef CONFIG_X86_32 | 190 | #ifdef CONFIG_X86_32 |
265 | asmlinkage int sys_sigaltstack(unsigned long bx) | 191 | static const struct { |
266 | { | 192 | u16 poplmovl; |
267 | /* | 193 | u32 val; |
268 | * This is needed to make gcc realize it doesn't own the | 194 | u16 int80; |
269 | * "struct pt_regs" | 195 | } __attribute__((packed)) retcode = { |
270 | */ | 196 | 0xb858, /* popl %eax; movl $..., %eax */ |
271 | struct pt_regs *regs = (struct pt_regs *)&bx; | 197 | __NR_sigreturn, |
272 | const stack_t __user *uss = (const stack_t __user *)bx; | 198 | 0x80cd, /* int $0x80 */ |
273 | stack_t __user *uoss = (stack_t __user *)regs->cx; | 199 | }; |
274 | |||
275 | return do_sigaltstack(uss, uoss, regs->sp); | ||
276 | } | ||
277 | #else /* !CONFIG_X86_32 */ | ||
278 | asmlinkage long | ||
279 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | ||
280 | struct pt_regs *regs) | ||
281 | { | ||
282 | return do_sigaltstack(uss, uoss, regs->sp); | ||
283 | } | ||
284 | #endif /* CONFIG_X86_32 */ | ||
285 | |||
286 | /* | ||
287 | * Do a signal return; undo the signal stack. | ||
288 | */ | ||
289 | asmlinkage unsigned long sys_sigreturn(unsigned long __unused) | ||
290 | { | ||
291 | struct sigframe __user *frame; | ||
292 | struct pt_regs *regs; | ||
293 | unsigned long ax; | ||
294 | sigset_t set; | ||
295 | |||
296 | regs = (struct pt_regs *) &__unused; | ||
297 | frame = (struct sigframe __user *)(regs->sp - 8); | ||
298 | |||
299 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
300 | goto badframe; | ||
301 | if (__get_user(set.sig[0], &frame->sc.oldmask) || (_NSIG_WORDS > 1 | ||
302 | && __copy_from_user(&set.sig[1], &frame->extramask, | ||
303 | sizeof(frame->extramask)))) | ||
304 | goto badframe; | ||
305 | |||
306 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
307 | spin_lock_irq(¤t->sighand->siglock); | ||
308 | current->blocked = set; | ||
309 | recalc_sigpending(); | ||
310 | spin_unlock_irq(¤t->sighand->siglock); | ||
311 | |||
312 | if (restore_sigcontext(regs, &frame->sc, &ax)) | ||
313 | goto badframe; | ||
314 | return ax; | ||
315 | |||
316 | badframe: | ||
317 | if (show_unhandled_signals && printk_ratelimit()) { | ||
318 | printk("%s%s[%d] bad frame in sigreturn frame:" | ||
319 | "%p ip:%lx sp:%lx oeax:%lx", | ||
320 | task_pid_nr(current) > 1 ? KERN_INFO : KERN_EMERG, | ||
321 | current->comm, task_pid_nr(current), frame, regs->ip, | ||
322 | regs->sp, regs->orig_ax); | ||
323 | print_vma_addr(" in ", regs->ip); | ||
324 | printk(KERN_CONT "\n"); | ||
325 | } | ||
326 | |||
327 | force_sig(SIGSEGV, current); | ||
328 | |||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static long do_rt_sigreturn(struct pt_regs *regs) | ||
333 | { | ||
334 | struct rt_sigframe __user *frame; | ||
335 | unsigned long ax; | ||
336 | sigset_t set; | ||
337 | |||
338 | frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long)); | ||
339 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
340 | goto badframe; | ||
341 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | ||
342 | goto badframe; | ||
343 | |||
344 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
345 | spin_lock_irq(¤t->sighand->siglock); | ||
346 | current->blocked = set; | ||
347 | recalc_sigpending(); | ||
348 | spin_unlock_irq(¤t->sighand->siglock); | ||
349 | |||
350 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) | ||
351 | goto badframe; | ||
352 | |||
353 | if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT) | ||
354 | goto badframe; | ||
355 | |||
356 | return ax; | ||
357 | |||
358 | badframe: | ||
359 | signal_fault(regs, frame, "rt_sigreturn"); | ||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | #ifdef CONFIG_X86_32 | ||
364 | asmlinkage int sys_rt_sigreturn(unsigned long __unused) | ||
365 | { | ||
366 | struct pt_regs *regs = (struct pt_regs *)&__unused; | ||
367 | |||
368 | return do_rt_sigreturn(regs); | ||
369 | } | ||
370 | #else /* !CONFIG_X86_32 */ | ||
371 | asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | ||
372 | { | ||
373 | return do_rt_sigreturn(regs); | ||
374 | } | ||
375 | #endif /* CONFIG_X86_32 */ | ||
376 | 200 | ||
377 | /* | 201 | static const struct { |
378 | * Set up a signal frame. | 202 | u8 movl; |
379 | */ | 203 | u32 val; |
204 | u16 int80; | ||
205 | u8 pad; | ||
206 | } __attribute__((packed)) rt_retcode = { | ||
207 | 0xb8, /* movl $..., %eax */ | ||
208 | __NR_rt_sigreturn, | ||
209 | 0x80cd, /* int $0x80 */ | ||
210 | 0 | ||
211 | }; | ||
380 | 212 | ||
381 | /* | 213 | /* |
382 | * Determine which stack to use.. | 214 | * Determine which stack to use.. |
@@ -557,6 +389,265 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
557 | 389 | ||
558 | return 0; | 390 | return 0; |
559 | } | 391 | } |
392 | #else /* !CONFIG_X86_32 */ | ||
393 | /* | ||
394 | * Determine which stack to use.. | ||
395 | */ | ||
396 | static void __user * | ||
397 | get_stack(struct k_sigaction *ka, unsigned long sp, unsigned long size) | ||
398 | { | ||
399 | /* Default to using normal stack - redzone*/ | ||
400 | sp -= 128; | ||
401 | |||
402 | /* This is the X/Open sanctioned signal stack switching. */ | ||
403 | if (ka->sa.sa_flags & SA_ONSTACK) { | ||
404 | if (sas_ss_flags(sp) == 0) | ||
405 | sp = current->sas_ss_sp + current->sas_ss_size; | ||
406 | } | ||
407 | |||
408 | return (void __user *)round_down(sp - size, 64); | ||
409 | } | ||
410 | |||
411 | static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | ||
412 | sigset_t *set, struct pt_regs *regs) | ||
413 | { | ||
414 | struct rt_sigframe __user *frame; | ||
415 | void __user *fp = NULL; | ||
416 | int err = 0; | ||
417 | struct task_struct *me = current; | ||
418 | |||
419 | if (used_math()) { | ||
420 | fp = get_stack(ka, regs->sp, sig_xstate_size); | ||
421 | frame = (void __user *)round_down( | ||
422 | (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8; | ||
423 | |||
424 | if (save_i387_xstate(fp) < 0) | ||
425 | return -EFAULT; | ||
426 | } else | ||
427 | frame = get_stack(ka, regs->sp, sizeof(struct rt_sigframe)) - 8; | ||
428 | |||
429 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | ||
430 | return -EFAULT; | ||
431 | |||
432 | if (ka->sa.sa_flags & SA_SIGINFO) { | ||
433 | if (copy_siginfo_to_user(&frame->info, info)) | ||
434 | return -EFAULT; | ||
435 | } | ||
436 | |||
437 | /* Create the ucontext. */ | ||
438 | if (cpu_has_xsave) | ||
439 | err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags); | ||
440 | else | ||
441 | err |= __put_user(0, &frame->uc.uc_flags); | ||
442 | err |= __put_user(0, &frame->uc.uc_link); | ||
443 | err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | ||
444 | err |= __put_user(sas_ss_flags(regs->sp), | ||
445 | &frame->uc.uc_stack.ss_flags); | ||
446 | err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); | ||
447 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]); | ||
448 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | ||
449 | |||
450 | /* Set up to return from userspace. If provided, use a stub | ||
451 | already in userspace. */ | ||
452 | /* x86-64 should always use SA_RESTORER. */ | ||
453 | if (ka->sa.sa_flags & SA_RESTORER) { | ||
454 | err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); | ||
455 | } else { | ||
456 | /* could use a vstub here */ | ||
457 | return -EFAULT; | ||
458 | } | ||
459 | |||
460 | if (err) | ||
461 | return -EFAULT; | ||
462 | |||
463 | /* Set up registers for signal handler */ | ||
464 | regs->di = sig; | ||
465 | /* In case the signal handler was declared without prototypes */ | ||
466 | regs->ax = 0; | ||
467 | |||
468 | /* This also works for non SA_SIGINFO handlers because they expect the | ||
469 | next argument after the signal number on the stack. */ | ||
470 | regs->si = (unsigned long)&frame->info; | ||
471 | regs->dx = (unsigned long)&frame->uc; | ||
472 | regs->ip = (unsigned long) ka->sa.sa_handler; | ||
473 | |||
474 | regs->sp = (unsigned long)frame; | ||
475 | |||
476 | /* Set up the CS register to run signal handlers in 64-bit mode, | ||
477 | even if the handler happens to be interrupting 32-bit code. */ | ||
478 | regs->cs = __USER_CS; | ||
479 | |||
480 | return 0; | ||
481 | } | ||
482 | #endif /* CONFIG_X86_32 */ | ||
483 | |||
484 | /* | ||
485 | * Atomically swap in the new signal mask, and wait for a signal. | ||
486 | */ | ||
487 | asmlinkage int | ||
488 | sys_sigsuspend(int history0, int history1, old_sigset_t mask) | ||
489 | { | ||
490 | mask &= _BLOCKABLE; | ||
491 | spin_lock_irq(¤t->sighand->siglock); | ||
492 | current->saved_sigmask = current->blocked; | ||
493 | siginitset(¤t->blocked, mask); | ||
494 | recalc_sigpending(); | ||
495 | spin_unlock_irq(¤t->sighand->siglock); | ||
496 | |||
497 | current->state = TASK_INTERRUPTIBLE; | ||
498 | schedule(); | ||
499 | set_restore_sigmask(); | ||
500 | |||
501 | return -ERESTARTNOHAND; | ||
502 | } | ||
503 | |||
504 | asmlinkage int | ||
505 | sys_sigaction(int sig, const struct old_sigaction __user *act, | ||
506 | struct old_sigaction __user *oact) | ||
507 | { | ||
508 | struct k_sigaction new_ka, old_ka; | ||
509 | int ret; | ||
510 | |||
511 | if (act) { | ||
512 | old_sigset_t mask; | ||
513 | |||
514 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | ||
515 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | ||
516 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) | ||
517 | return -EFAULT; | ||
518 | |||
519 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); | ||
520 | __get_user(mask, &act->sa_mask); | ||
521 | siginitset(&new_ka.sa.sa_mask, mask); | ||
522 | } | ||
523 | |||
524 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | ||
525 | |||
526 | if (!ret && oact) { | ||
527 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | ||
528 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | ||
529 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) | ||
530 | return -EFAULT; | ||
531 | |||
532 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | ||
533 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | ||
534 | } | ||
535 | |||
536 | return ret; | ||
537 | } | ||
538 | |||
539 | #ifdef CONFIG_X86_32 | ||
540 | asmlinkage int sys_sigaltstack(unsigned long bx) | ||
541 | { | ||
542 | /* | ||
543 | * This is needed to make gcc realize it doesn't own the | ||
544 | * "struct pt_regs" | ||
545 | */ | ||
546 | struct pt_regs *regs = (struct pt_regs *)&bx; | ||
547 | const stack_t __user *uss = (const stack_t __user *)bx; | ||
548 | stack_t __user *uoss = (stack_t __user *)regs->cx; | ||
549 | |||
550 | return do_sigaltstack(uss, uoss, regs->sp); | ||
551 | } | ||
552 | #else /* !CONFIG_X86_32 */ | ||
553 | asmlinkage long | ||
554 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | ||
555 | struct pt_regs *regs) | ||
556 | { | ||
557 | return do_sigaltstack(uss, uoss, regs->sp); | ||
558 | } | ||
559 | #endif /* CONFIG_X86_32 */ | ||
560 | |||
561 | /* | ||
562 | * Do a signal return; undo the signal stack. | ||
563 | */ | ||
564 | asmlinkage unsigned long sys_sigreturn(unsigned long __unused) | ||
565 | { | ||
566 | struct sigframe __user *frame; | ||
567 | struct pt_regs *regs; | ||
568 | unsigned long ax; | ||
569 | sigset_t set; | ||
570 | |||
571 | regs = (struct pt_regs *) &__unused; | ||
572 | frame = (struct sigframe __user *)(regs->sp - 8); | ||
573 | |||
574 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
575 | goto badframe; | ||
576 | if (__get_user(set.sig[0], &frame->sc.oldmask) || (_NSIG_WORDS > 1 | ||
577 | && __copy_from_user(&set.sig[1], &frame->extramask, | ||
578 | sizeof(frame->extramask)))) | ||
579 | goto badframe; | ||
580 | |||
581 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
582 | spin_lock_irq(¤t->sighand->siglock); | ||
583 | current->blocked = set; | ||
584 | recalc_sigpending(); | ||
585 | spin_unlock_irq(¤t->sighand->siglock); | ||
586 | |||
587 | if (restore_sigcontext(regs, &frame->sc, &ax)) | ||
588 | goto badframe; | ||
589 | return ax; | ||
590 | |||
591 | badframe: | ||
592 | if (show_unhandled_signals && printk_ratelimit()) { | ||
593 | printk("%s%s[%d] bad frame in sigreturn frame:" | ||
594 | "%p ip:%lx sp:%lx oeax:%lx", | ||
595 | task_pid_nr(current) > 1 ? KERN_INFO : KERN_EMERG, | ||
596 | current->comm, task_pid_nr(current), frame, regs->ip, | ||
597 | regs->sp, regs->orig_ax); | ||
598 | print_vma_addr(" in ", regs->ip); | ||
599 | printk(KERN_CONT "\n"); | ||
600 | } | ||
601 | |||
602 | force_sig(SIGSEGV, current); | ||
603 | |||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | static long do_rt_sigreturn(struct pt_regs *regs) | ||
608 | { | ||
609 | struct rt_sigframe __user *frame; | ||
610 | unsigned long ax; | ||
611 | sigset_t set; | ||
612 | |||
613 | frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long)); | ||
614 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
615 | goto badframe; | ||
616 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | ||
617 | goto badframe; | ||
618 | |||
619 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
620 | spin_lock_irq(¤t->sighand->siglock); | ||
621 | current->blocked = set; | ||
622 | recalc_sigpending(); | ||
623 | spin_unlock_irq(¤t->sighand->siglock); | ||
624 | |||
625 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) | ||
626 | goto badframe; | ||
627 | |||
628 | if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT) | ||
629 | goto badframe; | ||
630 | |||
631 | return ax; | ||
632 | |||
633 | badframe: | ||
634 | signal_fault(regs, frame, "rt_sigreturn"); | ||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | #ifdef CONFIG_X86_32 | ||
639 | asmlinkage int sys_rt_sigreturn(unsigned long __unused) | ||
640 | { | ||
641 | struct pt_regs *regs = (struct pt_regs *)&__unused; | ||
642 | |||
643 | return do_rt_sigreturn(regs); | ||
644 | } | ||
645 | #else /* !CONFIG_X86_32 */ | ||
646 | asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | ||
647 | { | ||
648 | return do_rt_sigreturn(regs); | ||
649 | } | ||
650 | #endif /* CONFIG_X86_32 */ | ||
560 | 651 | ||
561 | /* | 652 | /* |
562 | * OK, we're invoking a handler: | 653 | * OK, we're invoking a handler: |
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c index 771c8fcc8b0d..2da7e6e60807 100644 --- a/arch/x86/kernel/signal_64.c +++ b/arch/x86/kernel/signal_64.c | |||
@@ -174,80 +174,212 @@ setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, | |||
174 | return err; | 174 | return err; |
175 | } | 175 | } |
176 | 176 | ||
177 | /* | ||
178 | * Set up a signal frame. | ||
179 | */ | ||
177 | #ifdef CONFIG_X86_32 | 180 | #ifdef CONFIG_X86_32 |
178 | asmlinkage int sys_sigaltstack(unsigned long bx) | 181 | static const struct { |
182 | u16 poplmovl; | ||
183 | u32 val; | ||
184 | u16 int80; | ||
185 | } __attribute__((packed)) retcode = { | ||
186 | 0xb858, /* popl %eax; movl $..., %eax */ | ||
187 | __NR_sigreturn, | ||
188 | 0x80cd, /* int $0x80 */ | ||
189 | }; | ||
190 | |||
191 | static const struct { | ||
192 | u8 movl; | ||
193 | u32 val; | ||
194 | u16 int80; | ||
195 | u8 pad; | ||
196 | } __attribute__((packed)) rt_retcode = { | ||
197 | 0xb8, /* movl $..., %eax */ | ||
198 | __NR_rt_sigreturn, | ||
199 | 0x80cd, /* int $0x80 */ | ||
200 | 0 | ||
201 | }; | ||
202 | |||
203 | /* | ||
204 | * Determine which stack to use.. | ||
205 | */ | ||
206 | static inline void __user * | ||
207 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, | ||
208 | void **fpstate) | ||
179 | { | 209 | { |
210 | unsigned long sp; | ||
211 | |||
212 | /* Default to using normal stack */ | ||
213 | sp = regs->sp; | ||
214 | |||
180 | /* | 215 | /* |
181 | * This is needed to make gcc realize it doesn't own the | 216 | * If we are on the alternate signal stack and would overflow it, don't. |
182 | * "struct pt_regs" | 217 | * Return an always-bogus address instead so we will die with SIGSEGV. |
183 | */ | 218 | */ |
184 | struct pt_regs *regs = (struct pt_regs *)&bx; | 219 | if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size))) |
185 | const stack_t __user *uss = (const stack_t __user *)bx; | 220 | return (void __user *) -1L; |
186 | stack_t __user *uoss = (stack_t __user *)regs->cx; | ||
187 | 221 | ||
188 | return do_sigaltstack(uss, uoss, regs->sp); | 222 | /* This is the X/Open sanctioned signal stack switching. */ |
189 | } | 223 | if (ka->sa.sa_flags & SA_ONSTACK) { |
190 | #else /* !CONFIG_X86_32 */ | 224 | if (sas_ss_flags(sp) == 0) |
191 | asmlinkage long | 225 | sp = current->sas_ss_sp + current->sas_ss_size; |
192 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | 226 | } else { |
193 | struct pt_regs *regs) | 227 | /* This is the legacy signal stack switching. */ |
194 | { | 228 | if ((regs->ss & 0xffff) != __USER_DS && |
195 | return do_sigaltstack(uss, uoss, regs->sp); | 229 | !(ka->sa.sa_flags & SA_RESTORER) && |
230 | ka->sa.sa_restorer) | ||
231 | sp = (unsigned long) ka->sa.sa_restorer; | ||
232 | } | ||
233 | |||
234 | if (used_math()) { | ||
235 | sp = sp - sig_xstate_size; | ||
236 | *fpstate = (struct _fpstate *) sp; | ||
237 | if (save_i387_xstate(*fpstate) < 0) | ||
238 | return (void __user *)-1L; | ||
239 | } | ||
240 | |||
241 | sp -= frame_size; | ||
242 | /* | ||
243 | * Align the stack pointer according to the i386 ABI, | ||
244 | * i.e. so that on function entry ((sp + 4) & 15) == 0. | ||
245 | */ | ||
246 | sp = ((sp + 4) & -16ul) - 4; | ||
247 | |||
248 | return (void __user *) sp; | ||
196 | } | 249 | } |
197 | #endif /* CONFIG_X86_32 */ | ||
198 | 250 | ||
199 | /* | 251 | static int |
200 | * Do a signal return; undo the signal stack. | 252 | __setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, |
201 | */ | 253 | struct pt_regs *regs) |
202 | static long do_rt_sigreturn(struct pt_regs *regs) | ||
203 | { | 254 | { |
204 | struct rt_sigframe __user *frame; | 255 | struct sigframe __user *frame; |
205 | unsigned long ax; | 256 | void __user *restorer; |
206 | sigset_t set; | 257 | int err = 0; |
258 | void __user *fpstate = NULL; | ||
207 | 259 | ||
208 | frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long)); | 260 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
209 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
210 | goto badframe; | ||
211 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | ||
212 | goto badframe; | ||
213 | 261 | ||
214 | sigdelsetmask(&set, ~_BLOCKABLE); | 262 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
215 | spin_lock_irq(¤t->sighand->siglock); | 263 | return -EFAULT; |
216 | current->blocked = set; | ||
217 | recalc_sigpending(); | ||
218 | spin_unlock_irq(¤t->sighand->siglock); | ||
219 | 264 | ||
220 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) | 265 | if (__put_user(sig, &frame->sig)) |
221 | goto badframe; | 266 | return -EFAULT; |
222 | 267 | ||
223 | if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT) | 268 | if (setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0])) |
224 | goto badframe; | 269 | return -EFAULT; |
225 | 270 | ||
226 | return ax; | 271 | if (_NSIG_WORDS > 1) { |
272 | if (__copy_to_user(&frame->extramask, &set->sig[1], | ||
273 | sizeof(frame->extramask))) | ||
274 | return -EFAULT; | ||
275 | } | ||
276 | |||
277 | if (current->mm->context.vdso) | ||
278 | restorer = VDSO32_SYMBOL(current->mm->context.vdso, sigreturn); | ||
279 | else | ||
280 | restorer = &frame->retcode; | ||
281 | if (ka->sa.sa_flags & SA_RESTORER) | ||
282 | restorer = ka->sa.sa_restorer; | ||
283 | |||
284 | /* Set up to return from userspace. */ | ||
285 | err |= __put_user(restorer, &frame->pretcode); | ||
286 | |||
287 | /* | ||
288 | * This is popl %eax ; movl $__NR_sigreturn, %eax ; int $0x80 | ||
289 | * | ||
290 | * WE DO NOT USE IT ANY MORE! It's only left here for historical | ||
291 | * reasons and because gdb uses it as a signature to notice | ||
292 | * signal handler stack frames. | ||
293 | */ | ||
294 | err |= __put_user(*((u64 *)&retcode), (u64 *)frame->retcode); | ||
295 | |||
296 | if (err) | ||
297 | return -EFAULT; | ||
298 | |||
299 | /* Set up registers for signal handler */ | ||
300 | regs->sp = (unsigned long)frame; | ||
301 | regs->ip = (unsigned long)ka->sa.sa_handler; | ||
302 | regs->ax = (unsigned long)sig; | ||
303 | regs->dx = 0; | ||
304 | regs->cx = 0; | ||
305 | |||
306 | regs->ds = __USER_DS; | ||
307 | regs->es = __USER_DS; | ||
308 | regs->ss = __USER_DS; | ||
309 | regs->cs = __USER_CS; | ||
227 | 310 | ||
228 | badframe: | ||
229 | signal_fault(regs, frame, "rt_sigreturn"); | ||
230 | return 0; | 311 | return 0; |
231 | } | 312 | } |
232 | 313 | ||
233 | #ifdef CONFIG_X86_32 | 314 | static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
234 | asmlinkage int sys_rt_sigreturn(unsigned long __unused) | 315 | sigset_t *set, struct pt_regs *regs) |
235 | { | 316 | { |
236 | struct pt_regs *regs = (struct pt_regs *)&__unused; | 317 | struct rt_sigframe __user *frame; |
318 | void __user *restorer; | ||
319 | int err = 0; | ||
320 | void __user *fpstate = NULL; | ||
237 | 321 | ||
238 | return do_rt_sigreturn(regs); | 322 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
239 | } | ||
240 | #else /* !CONFIG_X86_32 */ | ||
241 | asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | ||
242 | { | ||
243 | return do_rt_sigreturn(regs); | ||
244 | } | ||
245 | #endif /* CONFIG_X86_32 */ | ||
246 | 323 | ||
247 | /* | 324 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
248 | * Set up a signal frame. | 325 | return -EFAULT; |
249 | */ | 326 | |
327 | err |= __put_user(sig, &frame->sig); | ||
328 | err |= __put_user(&frame->info, &frame->pinfo); | ||
329 | err |= __put_user(&frame->uc, &frame->puc); | ||
330 | err |= copy_siginfo_to_user(&frame->info, info); | ||
331 | if (err) | ||
332 | return -EFAULT; | ||
333 | |||
334 | /* Create the ucontext. */ | ||
335 | if (cpu_has_xsave) | ||
336 | err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags); | ||
337 | else | ||
338 | err |= __put_user(0, &frame->uc.uc_flags); | ||
339 | err |= __put_user(0, &frame->uc.uc_link); | ||
340 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | ||
341 | err |= __put_user(sas_ss_flags(regs->sp), | ||
342 | &frame->uc.uc_stack.ss_flags); | ||
343 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | ||
344 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, | ||
345 | regs, set->sig[0]); | ||
346 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | ||
347 | if (err) | ||
348 | return -EFAULT; | ||
349 | |||
350 | /* Set up to return from userspace. */ | ||
351 | restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn); | ||
352 | if (ka->sa.sa_flags & SA_RESTORER) | ||
353 | restorer = ka->sa.sa_restorer; | ||
354 | err |= __put_user(restorer, &frame->pretcode); | ||
355 | |||
356 | /* | ||
357 | * This is movl $__NR_rt_sigreturn, %ax ; int $0x80 | ||
358 | * | ||
359 | * WE DO NOT USE IT ANY MORE! It's only left here for historical | ||
360 | * reasons and because gdb uses it as a signature to notice | ||
361 | * signal handler stack frames. | ||
362 | */ | ||
363 | err |= __put_user(*((u64 *)&rt_retcode), (u64 *)frame->retcode); | ||
250 | 364 | ||
365 | if (err) | ||
366 | return -EFAULT; | ||
367 | |||
368 | /* Set up registers for signal handler */ | ||
369 | regs->sp = (unsigned long)frame; | ||
370 | regs->ip = (unsigned long)ka->sa.sa_handler; | ||
371 | regs->ax = (unsigned long)sig; | ||
372 | regs->dx = (unsigned long)&frame->info; | ||
373 | regs->cx = (unsigned long)&frame->uc; | ||
374 | |||
375 | regs->ds = __USER_DS; | ||
376 | regs->es = __USER_DS; | ||
377 | regs->ss = __USER_DS; | ||
378 | regs->cs = __USER_CS; | ||
379 | |||
380 | return 0; | ||
381 | } | ||
382 | #else /* !CONFIG_X86_32 */ | ||
251 | /* | 383 | /* |
252 | * Determine which stack to use.. | 384 | * Determine which stack to use.. |
253 | */ | 385 | */ |
@@ -337,6 +469,77 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
337 | 469 | ||
338 | return 0; | 470 | return 0; |
339 | } | 471 | } |
472 | #endif /* CONFIG_X86_32 */ | ||
473 | |||
474 | #ifdef CONFIG_X86_32 | ||
475 | asmlinkage int sys_sigaltstack(unsigned long bx) | ||
476 | { | ||
477 | /* | ||
478 | * This is needed to make gcc realize it doesn't own the | ||
479 | * "struct pt_regs" | ||
480 | */ | ||
481 | struct pt_regs *regs = (struct pt_regs *)&bx; | ||
482 | const stack_t __user *uss = (const stack_t __user *)bx; | ||
483 | stack_t __user *uoss = (stack_t __user *)regs->cx; | ||
484 | |||
485 | return do_sigaltstack(uss, uoss, regs->sp); | ||
486 | } | ||
487 | #else /* !CONFIG_X86_32 */ | ||
488 | asmlinkage long | ||
489 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | ||
490 | struct pt_regs *regs) | ||
491 | { | ||
492 | return do_sigaltstack(uss, uoss, regs->sp); | ||
493 | } | ||
494 | #endif /* CONFIG_X86_32 */ | ||
495 | |||
496 | /* | ||
497 | * Do a signal return; undo the signal stack. | ||
498 | */ | ||
499 | static long do_rt_sigreturn(struct pt_regs *regs) | ||
500 | { | ||
501 | struct rt_sigframe __user *frame; | ||
502 | unsigned long ax; | ||
503 | sigset_t set; | ||
504 | |||
505 | frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long)); | ||
506 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
507 | goto badframe; | ||
508 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | ||
509 | goto badframe; | ||
510 | |||
511 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
512 | spin_lock_irq(¤t->sighand->siglock); | ||
513 | current->blocked = set; | ||
514 | recalc_sigpending(); | ||
515 | spin_unlock_irq(¤t->sighand->siglock); | ||
516 | |||
517 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) | ||
518 | goto badframe; | ||
519 | |||
520 | if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT) | ||
521 | goto badframe; | ||
522 | |||
523 | return ax; | ||
524 | |||
525 | badframe: | ||
526 | signal_fault(regs, frame, "rt_sigreturn"); | ||
527 | return 0; | ||
528 | } | ||
529 | |||
530 | #ifdef CONFIG_X86_32 | ||
531 | asmlinkage int sys_rt_sigreturn(unsigned long __unused) | ||
532 | { | ||
533 | struct pt_regs *regs = (struct pt_regs *)&__unused; | ||
534 | |||
535 | return do_rt_sigreturn(regs); | ||
536 | } | ||
537 | #else /* !CONFIG_X86_32 */ | ||
538 | asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | ||
539 | { | ||
540 | return do_rt_sigreturn(regs); | ||
541 | } | ||
542 | #endif /* CONFIG_X86_32 */ | ||
340 | 543 | ||
341 | /* | 544 | /* |
342 | * OK, we're invoking a handler | 545 | * OK, we're invoking a handler |