aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2011-06-17 10:50:35 -0400
committerOleg Nesterov <oleg@redhat.com>2011-06-22 13:26:28 -0400
commit643ad8388e189dfd14ef76972cf7dc394b3cbebd (patch)
tree82d4787ddc09cf5a6fc9fc1345839973ab7763f5 /include/linux
parentd21142ece414ce1088cfcae760689aa60d6fee80 (diff)
ptrace: introduce ptrace_event_enabled() and simplify ptrace_event() and tracehook_prepare_clone()
This patch implements ptrace_event_enabled() which tests whether a given PTRACE_EVENT_* is enabled and use it to simplify ptrace_event() and tracehook_prepare_clone(). PT_EVENT_FLAG() macro is added which calculates PT_TRACE_* flag from PTRACE_EVENT_*. This is used to define PT_TRACE_* flags and by ptrace_event_enabled() to find the matching flag. This is used to make ptrace_event() and tracehook_prepare_clone() simpler. * ptrace_event() callers were responsible for providing mask to test whether the event was enabled. This patch implements ptrace_event_enabled() and make ptrace_event() drop @mask and determine whether the event is enabled from @event. Note that @event is constant and this conversion doesn't add runtime overhead. All conversions except tracehook_report_clone_complete() are trivial. tracehook_report_clone_complete() used to use 0 for @mask (always enabled) but now tests whether the specified event is enabled. This doesn't cause any behavior difference as it's guaranteed that the event specified by @trace is enabled. * tracehook_prepare_clone() now only determines which event is applicable and use ptrace_event_enabled() for enable test. This doesn't introduce any behavior change. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/ptrace.h46
-rw-r--r--include/linux/tracehook.h26
2 files changed, 45 insertions, 27 deletions
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index 3ff20b322598..18feac6f441e 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -90,12 +90,17 @@
90#define PT_DTRACE 0x00000002 /* delayed trace (used on m68k, i386) */ 90#define PT_DTRACE 0x00000002 /* delayed trace (used on m68k, i386) */
91#define PT_TRACESYSGOOD 0x00000004 91#define PT_TRACESYSGOOD 0x00000004
92#define PT_PTRACE_CAP 0x00000008 /* ptracer can follow suid-exec */ 92#define PT_PTRACE_CAP 0x00000008 /* ptracer can follow suid-exec */
93#define PT_TRACE_FORK 0x00000010 93
94#define PT_TRACE_VFORK 0x00000020 94/* PT_TRACE_* event enable flags */
95#define PT_TRACE_CLONE 0x00000040 95#define PT_EVENT_FLAG_SHIFT 4
96#define PT_TRACE_EXEC 0x00000080 96#define PT_EVENT_FLAG(event) (1 << (PT_EVENT_FLAG_SHIFT + (event) - 1))
97#define PT_TRACE_VFORK_DONE 0x00000100 97
98#define PT_TRACE_EXIT 0x00000200 98#define PT_TRACE_FORK PT_EVENT_FLAG(PTRACE_EVENT_FORK)
99#define PT_TRACE_VFORK PT_EVENT_FLAG(PTRACE_EVENT_VFORK)
100#define PT_TRACE_CLONE PT_EVENT_FLAG(PTRACE_EVENT_CLONE)
101#define PT_TRACE_EXEC PT_EVENT_FLAG(PTRACE_EVENT_EXEC)
102#define PT_TRACE_VFORK_DONE PT_EVENT_FLAG(PTRACE_EVENT_VFORK_DONE)
103#define PT_TRACE_EXIT PT_EVENT_FLAG(PTRACE_EVENT_EXIT)
99 104
100#define PT_TRACE_MASK 0x000003f4 105#define PT_TRACE_MASK 0x000003f4
101 106
@@ -146,25 +151,38 @@ int generic_ptrace_pokedata(struct task_struct *tsk, unsigned long addr,
146 unsigned long data); 151 unsigned long data);
147 152
148/** 153/**
154 * ptrace_event_enabled - test whether a ptrace event is enabled
155 * @task: ptracee of interest
156 * @event: %PTRACE_EVENT_* to test
157 *
158 * Test whether @event is enabled for ptracee @task.
159 *
160 * Returns %true if @event is enabled, %false otherwise.
161 */
162static inline bool ptrace_event_enabled(struct task_struct *task, int event)
163{
164 return task->ptrace & PT_EVENT_FLAG(event);
165}
166
167/**
149 * ptrace_event - possibly stop for a ptrace event notification 168 * ptrace_event - possibly stop for a ptrace event notification
150 * @mask: %PT_* bit to check in @current->ptrace 169 * @event: %PTRACE_EVENT_* value to report
151 * @event: %PTRACE_EVENT_* value to report if @mask is set
152 * @message: value for %PTRACE_GETEVENTMSG to return 170 * @message: value for %PTRACE_GETEVENTMSG to return
153 * 171 *
154 * This checks the @mask bit to see if ptrace wants stops for this event. 172 * Check whether @event is enabled and, if so, report @event and @message
155 * If so we stop, reporting @event and @message to the ptrace parent. 173 * to the ptrace parent.
156 * 174 *
157 * Returns nonzero if we did a ptrace notification, zero if not. 175 * Returns nonzero if we did a ptrace notification, zero if not.
158 * 176 *
159 * Called without locks. 177 * Called without locks.
160 */ 178 */
161static inline int ptrace_event(int mask, int event, unsigned long message) 179static inline int ptrace_event(int event, unsigned long message)
162{ 180{
163 if (mask && likely(!(current->ptrace & mask))) 181 if (likely(!ptrace_event_enabled(current, event)))
164 return 0; 182 return false;
165 current->ptrace_message = message; 183 current->ptrace_message = message;
166 ptrace_notify((event << 8) | SIGTRAP); 184 ptrace_notify((event << 8) | SIGTRAP);
167 return 1; 185 return true;
168} 186}
169 187
170/** 188/**
diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h
index a3e838784f43..7d38571b0c05 100644
--- a/include/linux/tracehook.h
+++ b/include/linux/tracehook.h
@@ -201,7 +201,7 @@ static inline void tracehook_report_exec(struct linux_binfmt *fmt,
201 struct linux_binprm *bprm, 201 struct linux_binprm *bprm,
202 struct pt_regs *regs) 202 struct pt_regs *regs)
203{ 203{
204 if (!ptrace_event(PT_TRACE_EXEC, PTRACE_EVENT_EXEC, 0) && 204 if (!ptrace_event(PTRACE_EVENT_EXEC, 0) &&
205 unlikely(current->ptrace & PT_PTRACED)) 205 unlikely(current->ptrace & PT_PTRACED))
206 send_sig(SIGTRAP, current, 0); 206 send_sig(SIGTRAP, current, 0);
207} 207}
@@ -218,7 +218,7 @@ static inline void tracehook_report_exec(struct linux_binfmt *fmt,
218 */ 218 */
219static inline void tracehook_report_exit(long *exit_code) 219static inline void tracehook_report_exit(long *exit_code)
220{ 220{
221 ptrace_event(PT_TRACE_EXIT, PTRACE_EVENT_EXIT, *exit_code); 221 ptrace_event(PTRACE_EVENT_EXIT, *exit_code);
222} 222}
223 223
224/** 224/**
@@ -232,19 +232,19 @@ static inline void tracehook_report_exit(long *exit_code)
232 */ 232 */
233static inline int tracehook_prepare_clone(unsigned clone_flags) 233static inline int tracehook_prepare_clone(unsigned clone_flags)
234{ 234{
235 int event = 0;
236
235 if (clone_flags & CLONE_UNTRACED) 237 if (clone_flags & CLONE_UNTRACED)
236 return 0; 238 return 0;
237 239
238 if (clone_flags & CLONE_VFORK) { 240 if (clone_flags & CLONE_VFORK)
239 if (current->ptrace & PT_TRACE_VFORK) 241 event = PTRACE_EVENT_VFORK;
240 return PTRACE_EVENT_VFORK; 242 else if ((clone_flags & CSIGNAL) != SIGCHLD)
241 } else if ((clone_flags & CSIGNAL) != SIGCHLD) { 243 event = PTRACE_EVENT_CLONE;
242 if (current->ptrace & PT_TRACE_CLONE) 244 else
243 return PTRACE_EVENT_CLONE; 245 event = PTRACE_EVENT_FORK;
244 } else if (current->ptrace & PT_TRACE_FORK)
245 return PTRACE_EVENT_FORK;
246 246
247 return 0; 247 return ptrace_event_enabled(current, event) ? event : 0;
248} 248}
249 249
250/** 250/**
@@ -318,7 +318,7 @@ static inline void tracehook_report_clone_complete(int trace,
318 struct task_struct *child) 318 struct task_struct *child)
319{ 319{
320 if (unlikely(trace)) 320 if (unlikely(trace))
321 ptrace_event(0, trace, pid); 321 ptrace_event(trace, pid);
322} 322}
323 323
324/** 324/**
@@ -336,7 +336,7 @@ static inline void tracehook_report_clone_complete(int trace,
336static inline void tracehook_report_vfork_done(struct task_struct *child, 336static inline void tracehook_report_vfork_done(struct task_struct *child,
337 pid_t pid) 337 pid_t pid)
338{ 338{
339 ptrace_event(PT_TRACE_VFORK_DONE, PTRACE_EVENT_VFORK_DONE, pid); 339 ptrace_event(PTRACE_EVENT_VFORK_DONE, pid);
340} 340}
341 341
342/** 342/**