diff options
Diffstat (limited to 'arch/s390/kernel/ptrace.c')
-rw-r--r-- | arch/s390/kernel/ptrace.c | 89 |
1 files changed, 61 insertions, 28 deletions
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 2815bfe348a6..1f31be1ecc4b 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/signal.h> | 35 | #include <linux/signal.h> |
36 | #include <linux/elf.h> | 36 | #include <linux/elf.h> |
37 | #include <linux/regset.h> | 37 | #include <linux/regset.h> |
38 | #include <linux/tracehook.h> | ||
38 | 39 | ||
39 | #include <asm/segment.h> | 40 | #include <asm/segment.h> |
40 | #include <asm/page.h> | 41 | #include <asm/page.h> |
@@ -170,6 +171,13 @@ static unsigned long __peek_user(struct task_struct *child, addr_t addr) | |||
170 | */ | 171 | */ |
171 | tmp = (addr_t) task_pt_regs(child)->orig_gpr2; | 172 | tmp = (addr_t) task_pt_regs(child)->orig_gpr2; |
172 | 173 | ||
174 | } else if (addr < (addr_t) &dummy->regs.fp_regs) { | ||
175 | /* | ||
176 | * prevent reads of padding hole between | ||
177 | * orig_gpr2 and fp_regs on s390. | ||
178 | */ | ||
179 | tmp = 0; | ||
180 | |||
173 | } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { | 181 | } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { |
174 | /* | 182 | /* |
175 | * floating point regs. are stored in the thread structure | 183 | * floating point regs. are stored in the thread structure |
@@ -270,6 +278,13 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) | |||
270 | */ | 278 | */ |
271 | task_pt_regs(child)->orig_gpr2 = data; | 279 | task_pt_regs(child)->orig_gpr2 = data; |
272 | 280 | ||
281 | } else if (addr < (addr_t) &dummy->regs.fp_regs) { | ||
282 | /* | ||
283 | * prevent writes of padding hole between | ||
284 | * orig_gpr2 and fp_regs on s390. | ||
285 | */ | ||
286 | return 0; | ||
287 | |||
273 | } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { | 288 | } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { |
274 | /* | 289 | /* |
275 | * floating point regs. are stored in the thread structure | 290 | * floating point regs. are stored in the thread structure |
@@ -428,6 +443,13 @@ static u32 __peek_user_compat(struct task_struct *child, addr_t addr) | |||
428 | */ | 443 | */ |
429 | tmp = *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4); | 444 | tmp = *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4); |
430 | 445 | ||
446 | } else if (addr < (addr_t) &dummy32->regs.fp_regs) { | ||
447 | /* | ||
448 | * prevent reads of padding hole between | ||
449 | * orig_gpr2 and fp_regs on s390. | ||
450 | */ | ||
451 | tmp = 0; | ||
452 | |||
431 | } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { | 453 | } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { |
432 | /* | 454 | /* |
433 | * floating point regs. are stored in the thread structure | 455 | * floating point regs. are stored in the thread structure |
@@ -514,6 +536,13 @@ static int __poke_user_compat(struct task_struct *child, | |||
514 | */ | 536 | */ |
515 | *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4) = tmp; | 537 | *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4) = tmp; |
516 | 538 | ||
539 | } else if (addr < (addr_t) &dummy32->regs.fp_regs) { | ||
540 | /* | ||
541 | * prevent writess of padding hole between | ||
542 | * orig_gpr2 and fp_regs on s390. | ||
543 | */ | ||
544 | return 0; | ||
545 | |||
517 | } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { | 546 | } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { |
518 | /* | 547 | /* |
519 | * floating point regs. are stored in the thread structure | 548 | * floating point regs. are stored in the thread structure |
@@ -611,40 +640,44 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
611 | } | 640 | } |
612 | #endif | 641 | #endif |
613 | 642 | ||
614 | asmlinkage void | 643 | asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) |
615 | syscall_trace(struct pt_regs *regs, int entryexit) | ||
616 | { | 644 | { |
617 | if (unlikely(current->audit_context) && entryexit) | 645 | long ret; |
618 | audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]), regs->gprs[2]); | ||
619 | |||
620 | if (!test_thread_flag(TIF_SYSCALL_TRACE)) | ||
621 | goto out; | ||
622 | if (!(current->ptrace & PT_PTRACED)) | ||
623 | goto out; | ||
624 | ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) | ||
625 | ? 0x80 : 0)); | ||
626 | 646 | ||
627 | /* | 647 | /* |
628 | * If the debuffer has set an invalid system call number, | 648 | * The sysc_tracesys code in entry.S stored the system |
629 | * we prepare to skip the system call restart handling. | 649 | * call number to gprs[2]. |
630 | */ | 650 | */ |
631 | if (!entryexit && regs->gprs[2] >= NR_syscalls) | 651 | ret = regs->gprs[2]; |
652 | if (test_thread_flag(TIF_SYSCALL_TRACE) && | ||
653 | (tracehook_report_syscall_entry(regs) || | ||
654 | regs->gprs[2] >= NR_syscalls)) { | ||
655 | /* | ||
656 | * Tracing decided this syscall should not happen or the | ||
657 | * debugger stored an invalid system call number. Skip | ||
658 | * the system call and the system call restart handling. | ||
659 | */ | ||
632 | regs->trap = -1; | 660 | regs->trap = -1; |
633 | 661 | ret = -1; | |
634 | /* | ||
635 | * this isn't the same as continuing with a signal, but it will do | ||
636 | * for normal use. strace only continues with a signal if the | ||
637 | * stopping signal is not SIGTRAP. -brl | ||
638 | */ | ||
639 | if (current->exit_code) { | ||
640 | send_sig(current->exit_code, current, 1); | ||
641 | current->exit_code = 0; | ||
642 | } | 662 | } |
643 | out: | 663 | |
644 | if (unlikely(current->audit_context) && !entryexit) | 664 | if (unlikely(current->audit_context)) |
645 | audit_syscall_entry(test_thread_flag(TIF_31BIT)?AUDIT_ARCH_S390:AUDIT_ARCH_S390X, | 665 | audit_syscall_entry(test_thread_flag(TIF_31BIT) ? |
646 | regs->gprs[2], regs->orig_gpr2, regs->gprs[3], | 666 | AUDIT_ARCH_S390 : AUDIT_ARCH_S390X, |
647 | regs->gprs[4], regs->gprs[5]); | 667 | regs->gprs[2], regs->orig_gpr2, |
668 | regs->gprs[3], regs->gprs[4], | ||
669 | regs->gprs[5]); | ||
670 | return ret; | ||
671 | } | ||
672 | |||
673 | asmlinkage void do_syscall_trace_exit(struct pt_regs *regs) | ||
674 | { | ||
675 | if (unlikely(current->audit_context)) | ||
676 | audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]), | ||
677 | regs->gprs[2]); | ||
678 | |||
679 | if (test_thread_flag(TIF_SYSCALL_TRACE)) | ||
680 | tracehook_report_syscall_exit(regs, 0); | ||
648 | } | 681 | } |
649 | 682 | ||
650 | /* | 683 | /* |