diff options
-rw-r--r-- | arch/powerpc/kernel/entry_32.S | 7 | ||||
-rw-r--r-- | arch/powerpc/kernel/entry_64.S | 7 | ||||
-rw-r--r-- | arch/powerpc/kernel/ptrace.c | 47 |
3 files changed, 34 insertions, 27 deletions
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index da52269aec1e..e6fca6a9014d 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S | |||
@@ -343,7 +343,12 @@ syscall_dotrace: | |||
343 | stw r0,_TRAP(r1) | 343 | stw r0,_TRAP(r1) |
344 | addi r3,r1,STACK_FRAME_OVERHEAD | 344 | addi r3,r1,STACK_FRAME_OVERHEAD |
345 | bl do_syscall_trace_enter | 345 | bl do_syscall_trace_enter |
346 | lwz r0,GPR0(r1) /* Restore original registers */ | 346 | /* |
347 | * Restore argument registers possibly just changed. | ||
348 | * We use the return value of do_syscall_trace_enter | ||
349 | * for call number to look up in the table (r0). | ||
350 | */ | ||
351 | mr r0,r3 | ||
347 | lwz r3,GPR3(r1) | 352 | lwz r3,GPR3(r1) |
348 | lwz r4,GPR4(r1) | 353 | lwz r4,GPR4(r1) |
349 | lwz r5,GPR5(r1) | 354 | lwz r5,GPR5(r1) |
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index d7369243ae44..79c089e97ce4 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S | |||
@@ -214,7 +214,12 @@ syscall_dotrace: | |||
214 | bl .save_nvgprs | 214 | bl .save_nvgprs |
215 | addi r3,r1,STACK_FRAME_OVERHEAD | 215 | addi r3,r1,STACK_FRAME_OVERHEAD |
216 | bl .do_syscall_trace_enter | 216 | bl .do_syscall_trace_enter |
217 | ld r0,GPR0(r1) /* Restore original registers */ | 217 | /* |
218 | * Restore argument registers possibly just changed. | ||
219 | * We use the return value of do_syscall_trace_enter | ||
220 | * for the call number to look up in the table (r0). | ||
221 | */ | ||
222 | mr r0,r3 | ||
218 | ld r3,GPR3(r1) | 223 | ld r3,GPR3(r1) |
219 | ld r4,GPR4(r1) | 224 | ld r4,GPR4(r1) |
220 | ld r5,GPR5(r1) | 225 | ld r5,GPR5(r1) |
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 66204cb51a1a..6b66cd85b433 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/errno.h> | 22 | #include <linux/errno.h> |
23 | #include <linux/ptrace.h> | 23 | #include <linux/ptrace.h> |
24 | #include <linux/regset.h> | 24 | #include <linux/regset.h> |
25 | #include <linux/tracehook.h> | ||
25 | #include <linux/elf.h> | 26 | #include <linux/elf.h> |
26 | #include <linux/user.h> | 27 | #include <linux/user.h> |
27 | #include <linux/security.h> | 28 | #include <linux/security.h> |
@@ -1014,31 +1015,24 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
1014 | return ret; | 1015 | return ret; |
1015 | } | 1016 | } |
1016 | 1017 | ||
1017 | static void do_syscall_trace(void) | 1018 | /* |
1019 | * We must return the syscall number to actually look up in the table. | ||
1020 | * This can be -1L to skip running any syscall at all. | ||
1021 | */ | ||
1022 | long do_syscall_trace_enter(struct pt_regs *regs) | ||
1018 | { | 1023 | { |
1019 | /* the 0x80 provides a way for the tracing parent to distinguish | 1024 | long ret = 0; |
1020 | between a syscall stop and SIGTRAP delivery */ | ||
1021 | ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) | ||
1022 | ? 0x80 : 0)); | ||
1023 | |||
1024 | /* | ||
1025 | * this isn't the same as continuing with a signal, but it will do | ||
1026 | * for normal use. strace only continues with a signal if the | ||
1027 | * stopping signal is not SIGTRAP. -brl | ||
1028 | */ | ||
1029 | if (current->exit_code) { | ||
1030 | send_sig(current->exit_code, current, 1); | ||
1031 | current->exit_code = 0; | ||
1032 | } | ||
1033 | } | ||
1034 | 1025 | ||
1035 | void do_syscall_trace_enter(struct pt_regs *regs) | ||
1036 | { | ||
1037 | secure_computing(regs->gpr[0]); | 1026 | secure_computing(regs->gpr[0]); |
1038 | 1027 | ||
1039 | if (test_thread_flag(TIF_SYSCALL_TRACE) | 1028 | if (test_thread_flag(TIF_SYSCALL_TRACE) && |
1040 | && (current->ptrace & PT_PTRACED)) | 1029 | tracehook_report_syscall_entry(regs)) |
1041 | do_syscall_trace(); | 1030 | /* |
1031 | * Tracing decided this syscall should not happen. | ||
1032 | * We'll return a bogus call number to get an ENOSYS | ||
1033 | * error, but leave the original number in regs->gpr[0]. | ||
1034 | */ | ||
1035 | ret = -1L; | ||
1042 | 1036 | ||
1043 | if (unlikely(current->audit_context)) { | 1037 | if (unlikely(current->audit_context)) { |
1044 | #ifdef CONFIG_PPC64 | 1038 | #ifdef CONFIG_PPC64 |
@@ -1056,16 +1050,19 @@ void do_syscall_trace_enter(struct pt_regs *regs) | |||
1056 | regs->gpr[5] & 0xffffffff, | 1050 | regs->gpr[5] & 0xffffffff, |
1057 | regs->gpr[6] & 0xffffffff); | 1051 | regs->gpr[6] & 0xffffffff); |
1058 | } | 1052 | } |
1053 | |||
1054 | return ret ?: regs->gpr[0]; | ||
1059 | } | 1055 | } |
1060 | 1056 | ||
1061 | void do_syscall_trace_leave(struct pt_regs *regs) | 1057 | void do_syscall_trace_leave(struct pt_regs *regs) |
1062 | { | 1058 | { |
1059 | int step; | ||
1060 | |||
1063 | if (unlikely(current->audit_context)) | 1061 | if (unlikely(current->audit_context)) |
1064 | audit_syscall_exit((regs->ccr&0x10000000)?AUDITSC_FAILURE:AUDITSC_SUCCESS, | 1062 | audit_syscall_exit((regs->ccr&0x10000000)?AUDITSC_FAILURE:AUDITSC_SUCCESS, |
1065 | regs->result); | 1063 | regs->result); |
1066 | 1064 | ||
1067 | if ((test_thread_flag(TIF_SYSCALL_TRACE) | 1065 | step = test_thread_flag(TIF_SINGLESTEP); |
1068 | || test_thread_flag(TIF_SINGLESTEP)) | 1066 | if (step || test_thread_flag(TIF_SYSCALL_TRACE)) |
1069 | && (current->ptrace & PT_PTRACED)) | 1067 | tracehook_report_syscall_exit(regs, step); |
1070 | do_syscall_trace(); | ||
1071 | } | 1068 | } |