ptrace: introduce ptrace_event_enabled() and simplify ptrace_event() and tracehook_pr...
authorTejun Heo <tj@kernel.org>
Fri, 17 Jun 2011 14:50:35 +0000 (16:50 +0200)
committerOleg Nesterov <oleg@redhat.com>
Wed, 22 Jun 2011 17:26:28 +0000 (19:26 +0200)
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>
include/linux/ptrace.h
include/linux/tracehook.h

index 3ff20b322598c1036a5eab97f1821ef5cb0d4678..18feac6f441ec27d1166bf4206b7abc83405def3 100644 (file)
 #define PT_DTRACE      0x00000002      /* delayed trace (used on m68k, i386) */
 #define PT_TRACESYSGOOD        0x00000004
 #define PT_PTRACE_CAP  0x00000008      /* ptracer can follow suid-exec */
-#define PT_TRACE_FORK  0x00000010
-#define PT_TRACE_VFORK 0x00000020
-#define PT_TRACE_CLONE 0x00000040
-#define PT_TRACE_EXEC  0x00000080
-#define PT_TRACE_VFORK_DONE    0x00000100
-#define PT_TRACE_EXIT  0x00000200
+
+/* PT_TRACE_* event enable flags */
+#define PT_EVENT_FLAG_SHIFT    4
+#define PT_EVENT_FLAG(event)   (1 << (PT_EVENT_FLAG_SHIFT + (event) - 1))
+
+#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
 
@@ -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,
                            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
- * @mask:      %PT_* bit to check in @current->ptrace
- * @event:     %PTRACE_EVENT_* value to report if @mask is set
+ * @event:     %PTRACE_EVENT_* value to report
  * @message:   value for %PTRACE_GETEVENTMSG to return
  *
- * This checks the @mask bit to see if ptrace wants stops for this event.
- * If so we stop, reporting @event and @message to the ptrace parent.
+ * Check whether @event is enabled and, if so, report @event and @message
+ * to the ptrace parent.
  *
  * Returns nonzero if we did a ptrace notification, zero if not.
  *
  * 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)))
-               return 0;
+       if (likely(!ptrace_event_enabled(current, event)))
+               return false;
        current->ptrace_message = message;
        ptrace_notify((event << 8) | SIGTRAP);
-       return 1;
+       return true;
 }
 
 /**
index a3e838784f43044ff45d46f6e3ef3bd7779e92bc..7d38571b0c0595e43634f6b2f0584bcd6a89a5f1 100644 (file)
@@ -201,7 +201,7 @@ static inline void tracehook_report_exec(struct linux_binfmt *fmt,
                                         struct linux_binprm *bprm,
                                         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))
                send_sig(SIGTRAP, current, 0);
 }
@@ -218,7 +218,7 @@ static inline void tracehook_report_exec(struct linux_binfmt *fmt,
  */
 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)
  */
 static inline int tracehook_prepare_clone(unsigned clone_flags)
 {
+       int event = 0;
+
        if (clone_flags & CLONE_UNTRACED)
                return 0;
 
-       if (clone_flags & CLONE_VFORK) {
-               if (current->ptrace & PT_TRACE_VFORK)
-                       return PTRACE_EVENT_VFORK;
-       } else if ((clone_flags & CSIGNAL) != SIGCHLD) {
-               if (current->ptrace & PT_TRACE_CLONE)
-                       return PTRACE_EVENT_CLONE;
-       } else if (current->ptrace & PT_TRACE_FORK)
-               return PTRACE_EVENT_FORK;
+       if (clone_flags & CLONE_VFORK)
+               event = PTRACE_EVENT_VFORK;
+       else if ((clone_flags & CSIGNAL) != SIGCHLD)
+               event = PTRACE_EVENT_CLONE;
+       else
+               event = 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,
                                                   struct task_struct *child)
 {
        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,
 static inline void tracehook_report_vfork_done(struct task_struct *child,
                                               pid_t pid)
 {
-       ptrace_event(PT_TRACE_VFORK_DONE, PTRACE_EVENT_VFORK_DONE, pid);
+       ptrace_event(PTRACE_EVENT_VFORK_DONE, pid);
 }
 
 /**