tracing/probe: Reject exactly same probe event
authorMasami Hiramatsu <mhiramat@kernel.org>
Wed, 18 Sep 2019 08:55:46 +0000 (17:55 +0900)
committerSteven Rostedt (VMware) <rostedt@goodmis.org>
Thu, 19 Sep 2019 15:09:16 +0000 (11:09 -0400)
Reject exactly same probe events as existing probes.

Multiprobe allows user to define multiple probes on same
event. If user appends a probe which exactly same definition
(same probe address and same arguments) on existing event,
the event will record same probe information twice.
That can be confusing users, so reject it.

Link: http://lkml.kernel.org/r/156879694602.31056.5533024778165036763.stgit@devnote2
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
kernel/trace/trace_kprobe.c
kernel/trace/trace_probe.h
kernel/trace/trace_uprobe.c

index 0ba3239c0270de7382540f4e2a7d9aae6ff7c592..a6697e28ddda00533e734406fb8c2ee02f1fa225 100644 (file)
@@ -528,10 +528,53 @@ unreg:
        return 0;
 }
 
+static bool trace_kprobe_has_same_kprobe(struct trace_kprobe *orig,
+                                        struct trace_kprobe *comp)
+{
+       struct trace_probe_event *tpe = orig->tp.event;
+       struct trace_probe *pos;
+       int i;
+
+       list_for_each_entry(pos, &tpe->probes, list) {
+               orig = container_of(pos, struct trace_kprobe, tp);
+               if (strcmp(trace_kprobe_symbol(orig),
+                          trace_kprobe_symbol(comp)) ||
+                   trace_kprobe_offset(orig) != trace_kprobe_offset(comp))
+                       continue;
+
+               /*
+                * trace_probe_compare_arg_type() ensured that nr_args and
+                * each argument name and type are same. Let's compare comm.
+                */
+               for (i = 0; i < orig->tp.nr_args; i++) {
+                       if (strcmp(orig->tp.args[i].comm,
+                                  comp->tp.args[i].comm))
+                               continue;
+               }
+
+               return true;
+       }
+
+       return false;
+}
+
 static int append_trace_kprobe(struct trace_kprobe *tk, struct trace_kprobe *to)
 {
        int ret;
 
+       ret = trace_probe_compare_arg_type(&tk->tp, &to->tp);
+       if (ret) {
+               /* Note that argument starts index = 2 */
+               trace_probe_log_set_index(ret + 1);
+               trace_probe_log_err(0, DIFF_ARG_TYPE);
+               return -EEXIST;
+       }
+       if (trace_kprobe_has_same_kprobe(to, tk)) {
+               trace_probe_log_set_index(0);
+               trace_probe_log_err(0, SAME_PROBE);
+               return -EEXIST;
+       }
+
        /* Append to existing event */
        ret = trace_probe_append(&tk->tp, &to->tp);
        if (ret)
@@ -568,14 +611,7 @@ static int register_trace_kprobe(struct trace_kprobe *tk)
                        trace_probe_log_err(0, DIFF_PROBE_TYPE);
                        ret = -EEXIST;
                } else {
-                       ret = trace_probe_compare_arg_type(&tk->tp, &old_tk->tp);
-                       if (ret) {
-                               /* Note that argument starts index = 2 */
-                               trace_probe_log_set_index(ret + 1);
-                               trace_probe_log_err(0, DIFF_ARG_TYPE);
-                               ret = -EEXIST;
-                       } else
-                               ret = append_trace_kprobe(tk, old_tk);
+                       ret = append_trace_kprobe(tk, old_tk);
                }
                goto end;
        }
index f805cc4cbe7c9d72c7f2a0496f0940728d799e95..4ee703728aeca5c46712fea9d139d78f2dfcf1ff 100644 (file)
@@ -436,7 +436,8 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
        C(BAD_INSN_BNDRY,       "Probe point is not an instruction boundary"),\
        C(FAIL_REG_PROBE,       "Failed to register probe event"),\
        C(DIFF_PROBE_TYPE,      "Probe type is different from existing probe"),\
-       C(DIFF_ARG_TYPE,        "Argument type or name is different from existing probe"),
+       C(DIFF_ARG_TYPE,        "Argument type or name is different from existing probe"),\
+       C(SAME_PROBE,           "There is already the exact same probe event"),
 
 #undef C
 #define C(a, b)                TP_ERR_##a
index cbf4da4bf3675003454f6765fb672263045afb33..34dd6d0016a3b73080617bdcacb08e2451c6b67b 100644 (file)
@@ -410,10 +410,53 @@ unreg:
        return 0;
 }
 
+static bool trace_uprobe_has_same_uprobe(struct trace_uprobe *orig,
+                                        struct trace_uprobe *comp)
+{
+       struct trace_probe_event *tpe = orig->tp.event;
+       struct trace_probe *pos;
+       struct inode *comp_inode = d_real_inode(comp->path.dentry);
+       int i;
+
+       list_for_each_entry(pos, &tpe->probes, list) {
+               orig = container_of(pos, struct trace_uprobe, tp);
+               if (comp_inode != d_real_inode(orig->path.dentry) ||
+                   comp->offset != orig->offset)
+                       continue;
+
+               /*
+                * trace_probe_compare_arg_type() ensured that nr_args and
+                * each argument name and type are same. Let's compare comm.
+                */
+               for (i = 0; i < orig->tp.nr_args; i++) {
+                       if (strcmp(orig->tp.args[i].comm,
+                                  comp->tp.args[i].comm))
+                               continue;
+               }
+
+               return true;
+       }
+
+       return false;
+}
+
 static int append_trace_uprobe(struct trace_uprobe *tu, struct trace_uprobe *to)
 {
        int ret;
 
+       ret = trace_probe_compare_arg_type(&tu->tp, &to->tp);
+       if (ret) {
+               /* Note that argument starts index = 2 */
+               trace_probe_log_set_index(ret + 1);
+               trace_probe_log_err(0, DIFF_ARG_TYPE);
+               return -EEXIST;
+       }
+       if (trace_uprobe_has_same_uprobe(to, tu)) {
+               trace_probe_log_set_index(0);
+               trace_probe_log_err(0, SAME_PROBE);
+               return -EEXIST;
+       }
+
        /* Append to existing event */
        ret = trace_probe_append(&tu->tp, &to->tp);
        if (!ret)
@@ -469,14 +512,7 @@ static int register_trace_uprobe(struct trace_uprobe *tu)
                        trace_probe_log_err(0, DIFF_PROBE_TYPE);
                        ret = -EEXIST;
                } else {
-                       ret = trace_probe_compare_arg_type(&tu->tp, &old_tu->tp);
-                       if (ret) {
-                               /* Note that argument starts index = 2 */
-                               trace_probe_log_set_index(ret + 1);
-                               trace_probe_log_err(0, DIFF_ARG_TYPE);
-                               ret = -EEXIST;
-                       } else
-                               ret = append_trace_uprobe(tu, old_tu);
+                       ret = append_trace_uprobe(tu, old_tu);
                }
                goto end;
        }