Commit 643ad838 authored by Tejun Heo's avatar Tejun Heo Committed by Oleg Nesterov

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: default avatarTejun Heo <tj@kernel.org>
Signed-off-by: default avatarOleg Nesterov <oleg@redhat.com>
parent d21142ec
...@@ -90,12 +90,17 @@ ...@@ -90,12 +90,17 @@
#define PT_DTRACE 0x00000002 /* delayed trace (used on m68k, i386) */ #define PT_DTRACE 0x00000002 /* delayed trace (used on m68k, i386) */
#define PT_TRACESYSGOOD 0x00000004 #define PT_TRACESYSGOOD 0x00000004
#define PT_PTRACE_CAP 0x00000008 /* ptracer can follow suid-exec */ #define PT_PTRACE_CAP 0x00000008 /* ptracer can follow suid-exec */
#define PT_TRACE_FORK 0x00000010
#define PT_TRACE_VFORK 0x00000020 /* PT_TRACE_* event enable flags */
#define PT_TRACE_CLONE 0x00000040 #define PT_EVENT_FLAG_SHIFT 4
#define PT_TRACE_EXEC 0x00000080 #define PT_EVENT_FLAG(event) (1 << (PT_EVENT_FLAG_SHIFT + (event) - 1))
#define PT_TRACE_VFORK_DONE 0x00000100
#define PT_TRACE_EXIT 0x00000200 #define PT_TRACE_FORK PT_EVENT_FLAG(PTRACE_EVENT_FORK)
#define PT_TRACE_VFORK PT_EVENT_FLAG(PTRACE_EVENT_VFORK)
#define PT_TRACE_CLONE PT_EVENT_FLAG(PTRACE_EVENT_CLONE)
#define PT_TRACE_EXEC PT_EVENT_FLAG(PTRACE_EVENT_EXEC)
#define PT_TRACE_VFORK_DONE PT_EVENT_FLAG(PTRACE_EVENT_VFORK_DONE)
#define PT_TRACE_EXIT PT_EVENT_FLAG(PTRACE_EVENT_EXIT)
#define PT_TRACE_MASK 0x000003f4 #define PT_TRACE_MASK 0x000003f4
...@@ -145,26 +150,39 @@ int generic_ptrace_peekdata(struct task_struct *tsk, unsigned long addr, ...@@ -145,26 +150,39 @@ int generic_ptrace_peekdata(struct task_struct *tsk, unsigned long addr,
int generic_ptrace_pokedata(struct task_struct *tsk, unsigned long addr, int generic_ptrace_pokedata(struct task_struct *tsk, unsigned long addr,
unsigned long data); unsigned long data);
/**
* ptrace_event_enabled - test whether a ptrace event is enabled
* @task: ptracee of interest
* @event: %PTRACE_EVENT_* to test
*
* Test whether @event is enabled for ptracee @task.
*
* Returns %true if @event is enabled, %false otherwise.
*/
static inline bool ptrace_event_enabled(struct task_struct *task, int event)
{
return task->ptrace & PT_EVENT_FLAG(event);
}
/** /**
* ptrace_event - possibly stop for a ptrace event notification * ptrace_event - possibly stop for a ptrace event notification
* @mask: %PT_* bit to check in @current->ptrace * @event: %PTRACE_EVENT_* value to report
* @event: %PTRACE_EVENT_* value to report if @mask is set
* @message: value for %PTRACE_GETEVENTMSG to return * @message: value for %PTRACE_GETEVENTMSG to return
* *
* This checks the @mask bit to see if ptrace wants stops for this event. * Check whether @event is enabled and, if so, report @event and @message
* If so we stop, reporting @event and @message to the ptrace parent. * to the ptrace parent.
* *
* Returns nonzero if we did a ptrace notification, zero if not. * Returns nonzero if we did a ptrace notification, zero if not.
* *
* Called without locks. * Called without locks.
*/ */
static inline int ptrace_event(int mask, int event, unsigned long message) static inline int ptrace_event(int event, unsigned long message)
{ {
if (mask && likely(!(current->ptrace & mask))) if (likely(!ptrace_event_enabled(current, event)))
return 0; return false;
current->ptrace_message = message; current->ptrace_message = message;
ptrace_notify((event << 8) | SIGTRAP); ptrace_notify((event << 8) | SIGTRAP);
return 1; return true;
} }
/** /**
......
...@@ -201,7 +201,7 @@ static inline void tracehook_report_exec(struct linux_binfmt *fmt, ...@@ -201,7 +201,7 @@ static inline void tracehook_report_exec(struct linux_binfmt *fmt,
struct linux_binprm *bprm, struct linux_binprm *bprm,
struct pt_regs *regs) struct pt_regs *regs)
{ {
if (!ptrace_event(PT_TRACE_EXEC, PTRACE_EVENT_EXEC, 0) && if (!ptrace_event(PTRACE_EVENT_EXEC, 0) &&
unlikely(current->ptrace & PT_PTRACED)) unlikely(current->ptrace & PT_PTRACED))
send_sig(SIGTRAP, current, 0); send_sig(SIGTRAP, current, 0);
} }
...@@ -218,7 +218,7 @@ static inline void tracehook_report_exec(struct linux_binfmt *fmt, ...@@ -218,7 +218,7 @@ static inline void tracehook_report_exec(struct linux_binfmt *fmt,
*/ */
static inline void tracehook_report_exit(long *exit_code) static inline void tracehook_report_exit(long *exit_code)
{ {
ptrace_event(PT_TRACE_EXIT, PTRACE_EVENT_EXIT, *exit_code); ptrace_event(PTRACE_EVENT_EXIT, *exit_code);
} }
/** /**
...@@ -232,19 +232,19 @@ static inline void tracehook_report_exit(long *exit_code) ...@@ -232,19 +232,19 @@ static inline void tracehook_report_exit(long *exit_code)
*/ */
static inline int tracehook_prepare_clone(unsigned clone_flags) static inline int tracehook_prepare_clone(unsigned clone_flags)
{ {
int event = 0;
if (clone_flags & CLONE_UNTRACED) if (clone_flags & CLONE_UNTRACED)
return 0; return 0;
if (clone_flags & CLONE_VFORK) { if (clone_flags & CLONE_VFORK)
if (current->ptrace & PT_TRACE_VFORK) event = PTRACE_EVENT_VFORK;
return PTRACE_EVENT_VFORK; else if ((clone_flags & CSIGNAL) != SIGCHLD)
} else if ((clone_flags & CSIGNAL) != SIGCHLD) { event = PTRACE_EVENT_CLONE;
if (current->ptrace & PT_TRACE_CLONE) else
return PTRACE_EVENT_CLONE; event = PTRACE_EVENT_FORK;
} else if (current->ptrace & PT_TRACE_FORK)
return PTRACE_EVENT_FORK;
return 0; return ptrace_event_enabled(current, event) ? event : 0;
} }
/** /**
...@@ -318,7 +318,7 @@ static inline void tracehook_report_clone_complete(int trace, ...@@ -318,7 +318,7 @@ static inline void tracehook_report_clone_complete(int trace,
struct task_struct *child) struct task_struct *child)
{ {
if (unlikely(trace)) if (unlikely(trace))
ptrace_event(0, trace, pid); ptrace_event(trace, pid);
} }
/** /**
...@@ -336,7 +336,7 @@ static inline void tracehook_report_clone_complete(int trace, ...@@ -336,7 +336,7 @@ static inline void tracehook_report_clone_complete(int trace,
static inline void tracehook_report_vfork_done(struct task_struct *child, static inline void tracehook_report_vfork_done(struct task_struct *child,
pid_t pid) pid_t pid)
{ {
ptrace_event(PT_TRACE_VFORK_DONE, PTRACE_EVENT_VFORK_DONE, pid); ptrace_event(PTRACE_EVENT_VFORK_DONE, pid);
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment