lkml.org 
[lkml]   [2022]   [Aug]   [23]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.15 022/244] tracing/eprobes: Have event probes be consistent with kprobes and uprobes
    Date
    From: Steven Rostedt (Google) <rostedt@goodmis.org>

    commit 6a832ec3d680b3a4f4fad5752672827d71bae501 upstream.

    Currently, if a symbol "@" is attempted to be used with an event probe
    (eprobes), it will cause a NULL pointer dereference crash.

    Both kprobes and uprobes can reference data other than the main registers.
    Such as immediate address, symbols and the current task name. Have eprobes
    do the same thing.

    For "comm", if "comm" is used and the event being attached to does not
    have the "comm" field, then make it the "$comm" that kprobes has. This is
    consistent to the way histograms and filters work.

    Link: https://lkml.kernel.org/r/20220820134401.136924220@goodmis.org

    Cc: stable@vger.kernel.org
    Cc: Ingo Molnar <mingo@kernel.org>
    Cc: Andrew Morton <akpm@linux-foundation.org>
    Cc: Masami Hiramatsu <mhiramat@kernel.org>
    Cc: Tzvetomir Stoyanov <tz.stoyanov@gmail.com>
    Cc: Tom Zanussi <zanussi@kernel.org>
    Fixes: 7491e2c44278 ("tracing: Add a probe that attaches to trace events")
    Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    kernel/trace/trace_eprobe.c | 70 ++++++++++++++++++++++++++++++++++++++++----
    1 file changed, 64 insertions(+), 6 deletions(-)

    --- a/kernel/trace/trace_eprobe.c
    +++ b/kernel/trace/trace_eprobe.c
    @@ -226,6 +226,7 @@ static int trace_eprobe_tp_arg_update(st
    struct probe_arg *parg = &ep->tp.args[i];
    struct ftrace_event_field *field;
    struct list_head *head;
    + int ret = -ENOENT;

    head = trace_get_fields(ep->event);
    list_for_each_entry(field, head, link) {
    @@ -235,9 +236,20 @@ static int trace_eprobe_tp_arg_update(st
    return 0;
    }
    }
    +
    + /*
    + * Argument not found on event. But allow for comm and COMM
    + * to be used to get the current->comm.
    + */
    + if (strcmp(parg->code->data, "COMM") == 0 ||
    + strcmp(parg->code->data, "comm") == 0) {
    + parg->code->op = FETCH_OP_COMM;
    + ret = 0;
    + }
    +
    kfree(parg->code->data);
    parg->code->data = NULL;
    - return -ENOENT;
    + return ret;
    }

    static int eprobe_event_define_fields(struct trace_event_call *event_call)
    @@ -339,16 +351,38 @@ static unsigned long get_event_field(str

    static int get_eprobe_size(struct trace_probe *tp, void *rec)
    {
    + struct fetch_insn *code;
    struct probe_arg *arg;
    int i, len, ret = 0;

    for (i = 0; i < tp->nr_args; i++) {
    arg = tp->args + i;
    - if (unlikely(arg->dynamic)) {
    + if (arg->dynamic) {
    unsigned long val;

    - val = get_event_field(arg->code, rec);
    - len = process_fetch_insn_bottom(arg->code + 1, val, NULL, NULL);
    + code = arg->code;
    + retry:
    + switch (code->op) {
    + case FETCH_OP_TP_ARG:
    + val = get_event_field(code, rec);
    + break;
    + case FETCH_OP_IMM:
    + val = code->immediate;
    + break;
    + case FETCH_OP_COMM:
    + val = (unsigned long)current->comm;
    + break;
    + case FETCH_OP_DATA:
    + val = (unsigned long)code->data;
    + break;
    + case FETCH_NOP_SYMBOL: /* Ignore a place holder */
    + code++;
    + goto retry;
    + default:
    + continue;
    + }
    + code++;
    + len = process_fetch_insn_bottom(code, val, NULL, NULL);
    if (len > 0)
    ret += len;
    }
    @@ -366,8 +400,28 @@ process_fetch_insn(struct fetch_insn *co
    {
    unsigned long val;

    - val = get_event_field(code, rec);
    - return process_fetch_insn_bottom(code + 1, val, dest, base);
    + retry:
    + switch (code->op) {
    + case FETCH_OP_TP_ARG:
    + val = get_event_field(code, rec);
    + break;
    + case FETCH_OP_IMM:
    + val = code->immediate;
    + break;
    + case FETCH_OP_COMM:
    + val = (unsigned long)current->comm;
    + break;
    + case FETCH_OP_DATA:
    + val = (unsigned long)code->data;
    + break;
    + case FETCH_NOP_SYMBOL: /* Ignore a place holder */
    + code++;
    + goto retry;
    + default:
    + return -EILSEQ;
    + }
    + code++;
    + return process_fetch_insn_bottom(code, val, dest, base);
    }
    NOKPROBE_SYMBOL(process_fetch_insn)

    @@ -849,6 +903,10 @@ static int trace_eprobe_tp_update_arg(st
    if (ep->tp.args[i].code->op == FETCH_OP_TP_ARG)
    ret = trace_eprobe_tp_arg_update(ep, i);

    + /* Handle symbols "@" */
    + if (!ret)
    + ret = traceprobe_update_arg(&ep->tp.args[i]);
    +
    return ret;
    }


    \
     
     \ /
      Last update: 2022-08-23 11:42    [W:2.180 / U:0.816 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site