]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: Gerald Schaefer <geraldsc@de.ibm.com> |
2 | Subject: [PATCH] system call notification with self_ptrace | |
3 | References: bnc#417299 | |
4 | ||
5 | PTRACE SELF | |
6 | ||
7 | This patch adds a new functionality to ptrace: system call notification to | |
8 | the current process. | |
9 | When a process requests self ptrace, with the new request PTRACE_SELF_ON: | |
10 | ||
11 | 1. the next system call performed by the process will not be executed | |
12 | 2. self ptrace will be disabled for the process | |
13 | 3. a SIGSYS signal will be sent to the process. | |
14 | ||
15 | With an appropriate SIGSYS signal handler, the process can access its own | |
16 | data structures to | |
17 | ||
18 | 1. get the system call number from the siginfo structure | |
19 | 2. get the system call arguments from the stack | |
20 | 3. instrument the system call with other system calls | |
21 | 4. emulate the system call with other system calls | |
22 | 5. change the arguments of the system call | |
23 | 6. perform the system call for good | |
24 | 7. change the return value of the system call | |
25 | 8. request self ptrace again before returning. | |
26 | ||
27 | The new request PTRACE_SELF_OFF disables self ptrace. | |
28 | ||
29 | ||
30 | Signed-off-by: Pierre Morel <pmorel@fr.ibm.com> | |
31 | Signed-off-by: Volker Sameske <sameske@de.ibm.com> | |
32 | ||
33 | Acked-by: John Jolly <jjolly@suse.de> | |
34 | --- | |
35 | ||
36 | include/asm-generic/siginfo.h | 6 ++++++ | |
37 | include/linux/ptrace.h | 18 ++++++++++++++++++ | |
38 | include/linux/sched.h | 1 + | |
39 | kernel/ptrace.c | 32 ++++++++++++++++++++++++++++++++ | |
40 | 4 files changed, 57 insertions(+) | |
41 | ||
42 | --- a/include/asm-generic/siginfo.h | |
43 | +++ b/include/asm-generic/siginfo.h | |
44 | @@ -224,6 +224,12 @@ typedef struct siginfo { | |
45 | #define NSIGPOLL 6 | |
46 | ||
47 | /* | |
48 | + * SIGSYS si_codes | |
49 | + */ | |
50 | +#define SYS_SYSCALL (__SI_FAULT|1) /* system call notification */ | |
51 | +#define NSIGSYS 1 | |
52 | + | |
53 | +/* | |
54 | * sigevent definitions | |
55 | * | |
56 | * It seems likely that SIGEV_THREAD will have to be handled from | |
57 | --- a/include/linux/ptrace.h | |
58 | +++ b/include/linux/ptrace.h | |
59 | @@ -27,6 +27,10 @@ | |
60 | #define PTRACE_GETSIGINFO 0x4202 | |
61 | #define PTRACE_SETSIGINFO 0x4203 | |
62 | ||
63 | +/* PTRACE SELF requests */ | |
64 | +#define PTRACE_SELF_ON 0x4281 | |
65 | +#define PTRACE_SELF_OFF 0x4282 | |
66 | + | |
67 | /* options set using PTRACE_SETOPTIONS */ | |
68 | #define PTRACE_O_TRACESYSGOOD 0x00000001 | |
69 | #define PTRACE_O_TRACEFORK 0x00000002 | |
70 | @@ -78,7 +82,21 @@ | |
71 | ||
72 | #include <linux/compiler.h> /* For unlikely. */ | |
73 | #include <linux/sched.h> /* For struct task_struct. */ | |
74 | +#include <linux/unistd.h> /* For syscall definitions */ | |
75 | + | |
76 | +#define PTS_INSTRUMENTED 0x00000001 | |
77 | +#define PTS_SELF 0x00000002 | |
78 | ||
79 | +static inline int is_self_ptracing(unsigned long syscall) | |
80 | +{ | |
81 | + if (!(current->instrumentation & PTS_SELF)) | |
82 | + return 0; | |
83 | + if (syscall == __NR_rt_sigreturn) | |
84 | + return 0; | |
85 | + if (syscall == __NR_ptrace) | |
86 | + return 0; | |
87 | + return 1; | |
88 | +} | |
89 | ||
90 | extern long arch_ptrace(struct task_struct *child, long request, long addr, long data); | |
91 | extern struct task_struct *ptrace_get_task_struct(pid_t pid); | |
92 | --- a/include/linux/sched.h | |
93 | +++ b/include/linux/sched.h | |
94 | @@ -1308,6 +1308,7 @@ struct task_struct { | |
95 | int latency_record_count; | |
96 | struct latency_record latency_record[LT_SAVECOUNT]; | |
97 | #endif | |
98 | + u64 instrumentation; | |
99 | }; | |
100 | ||
101 | /* | |
102 | --- a/kernel/ptrace.c | |
103 | +++ b/kernel/ptrace.c | |
104 | @@ -554,6 +554,38 @@ SYSCALL_DEFINE4(ptrace, long, request, l | |
105 | * This lock_kernel fixes a subtle race with suid exec | |
106 | */ | |
107 | lock_kernel(); | |
108 | + if (request == PTRACE_SELF_ON) { | |
109 | + task_lock(current); | |
110 | + if (current->ptrace) { | |
111 | + task_unlock(current); | |
112 | + ret = -EPERM; | |
113 | + goto out; | |
114 | + } | |
115 | + set_thread_flag(TIF_SYSCALL_TRACE); | |
116 | + current->instrumentation |= PTS_INSTRUMENTED|PTS_SELF; | |
117 | + task_unlock(current); | |
118 | + ret = 0; | |
119 | + goto out; | |
120 | + } | |
121 | + if (request == PTRACE_SELF_OFF) { | |
122 | + task_lock(current); | |
123 | + if (current->ptrace) { | |
124 | + task_unlock(current); | |
125 | + ret = -EPERM; | |
126 | + goto out; | |
127 | + } | |
128 | + clear_thread_flag(TIF_SYSCALL_TRACE); | |
129 | + current->instrumentation &= ~PTS_SELF; | |
130 | + task_unlock(current); | |
131 | + ret = 0; | |
132 | + goto out; | |
133 | + } | |
134 | + | |
135 | + if (current->instrumentation) { | |
136 | + ret = -EPERM; | |
137 | + goto out; | |
138 | + } | |
139 | + | |
140 | if (request == PTRACE_TRACEME) { | |
141 | ret = ptrace_traceme(); | |
142 | if (!ret) |