Merge tag 'trace-probes-v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 22 Dec 2022 02:57:24 +0000 (18:57 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 22 Dec 2022 02:57:24 +0000 (18:57 -0800)
Pull trace probes updates from Steven Rostedt:

 - New "symstr" type for dynamic events that writes the name of the
   function+offset into the ring buffer and not just the address

 - Prevent kernel symbol processing on addresses in user space probes
   (uprobes).

 - And minor fixes and clean ups

* tag 'trace-probes-v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
  tracing/probes: Reject symbol/symstr type for uprobe
  tracing/probes: Add symstr type for dynamic events
  kprobes: kretprobe events missing on 2-core KVM guest
  kprobes: Fix check for probe enabled in kill_kprobe()
  test_kprobes: Fix implicit declaration error of test_kprobes
  tracing: Fix race where eprobes can be called before the event

Documentation/trace/kprobes.rst
Documentation/trace/kprobetrace.rst
kernel/kprobes.c
kernel/trace/trace.c
kernel/trace/trace_probe.c
kernel/trace/trace_probe.h
kernel/trace/trace_probe_tmpl.h
kernel/trace/trace_uprobe.c
tools/testing/selftests/ftrace/test.d/kprobe/uprobe_syntax_errors.tc

index 48cf778..fc7ce76 100644 (file)
@@ -131,8 +131,7 @@ For example, if the function is non-recursive and is called with a
 spinlock held, maxactive = 1 should be enough.  If the function is
 non-recursive and can never relinquish the CPU (e.g., via a semaphore
 or preemption), NR_CPUS should be enough.  If maxactive <= 0, it is
-set to a default value.  If CONFIG_PREEMPT is enabled, the default
-is max(10, 2*NR_CPUS).  Otherwise, the default is NR_CPUS.
+set to a default value: max(10, 2*NR_CPUS).
 
 It's not a disaster if you set maxactive too low; you'll just miss
 some probes.  In the kretprobe struct, the nmissed field is set to
index 4274cc6..08a2a6a 100644 (file)
@@ -58,8 +58,8 @@ Synopsis of kprobe_events
   NAME=FETCHARG : Set NAME as the argument name of FETCHARG.
   FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types
                  (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types
-                 (x8/x16/x32/x64), "string", "ustring" and bitfield
-                 are supported.
+                 (x8/x16/x32/x64), "string", "ustring", "symbol", "symstr"
+                  and bitfield are supported.
 
   (\*1) only for the probe on function entry (offs == 0).
   (\*2) only for return probe.
@@ -96,6 +96,10 @@ offset, and container-size (usually 32). The syntax is::
 
 Symbol type('symbol') is an alias of u32 or u64 type (depends on BITS_PER_LONG)
 which shows given pointer in "symbol+offset" style.
+On the other hand, symbol-string type ('symstr') converts the given address to
+"symbol+offset/symbolsize" style and stores it as a null-terminated string.
+With 'symstr' type, you can filter the event with wildcard pattern of the
+symbols, and you don't need to solve symbol name by yourself.
 For $comm, the default type is "string"; any other type is invalid.
 
 .. _user_mem_access:
index 3050631..1c18ecf 100644 (file)
@@ -2213,13 +2213,9 @@ int register_kretprobe(struct kretprobe *rp)
        rp->kp.post_handler = NULL;
 
        /* Pre-allocate memory for max kretprobe instances */
-       if (rp->maxactive <= 0) {
-#ifdef CONFIG_PREEMPTION
+       if (rp->maxactive <= 0)
                rp->maxactive = max_t(unsigned int, 10, 2*num_possible_cpus());
-#else
-               rp->maxactive = num_possible_cpus();
-#endif
-       }
+
 #ifdef CONFIG_KRETPROBE_ON_RETHOOK
        rp->rh = rethook_alloc((void *)rp, kretprobe_rethook_handler);
        if (!rp->rh)
@@ -2364,6 +2360,14 @@ static void kill_kprobe(struct kprobe *p)
 
        lockdep_assert_held(&kprobe_mutex);
 
+       /*
+        * The module is going away. We should disarm the kprobe which
+        * is using ftrace, because ftrace framework is still available at
+        * 'MODULE_STATE_GOING' notification.
+        */
+       if (kprobe_ftrace(p) && !kprobe_disabled(p) && !kprobes_all_disarmed)
+               disarm_kprobe_ftrace(p);
+
        p->flags |= KPROBE_FLAG_GONE;
        if (kprobe_aggrprobe(p)) {
                /*
@@ -2380,14 +2384,6 @@ static void kill_kprobe(struct kprobe *p)
         * the original probed function (which will be freed soon) any more.
         */
        arch_remove_kprobe(p);
-
-       /*
-        * The module is going away. We should disarm the kprobe which
-        * is using ftrace, because ftrace framework is still available at
-        * 'MODULE_STATE_GOING' notification.
-        */
-       if (kprobe_ftrace(p) && !kprobe_disabled(p) && !kprobes_all_disarmed)
-               disarm_kprobe_ftrace(p);
 }
 
 /* Disable one kprobe */
index 6d7ef13..a555a86 100644 (file)
@@ -5617,7 +5617,7 @@ static const char readme_msg[] =
        "\t           +|-[u]<offset>(<fetcharg>), \\imm-value, \\\"imm-string\"\n"
        "\t     type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n"
        "\t           b<bit-width>@<bit-offset>/<container-size>, ustring,\n"
-       "\t           <type>\\[<array-size>\\]\n"
+       "\t           symstr, <type>\\[<array-size>\\]\n"
 #ifdef CONFIG_HIST_TRIGGERS
        "\t    field: <stype> <name>;\n"
        "\t    stype: u8/u16/u32/u64, s8/s16/s32/s64, pid_t,\n"
index bb2f95d..01ebabb 100644 (file)
@@ -76,9 +76,11 @@ const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\"";
 /* Fetch type information table */
 static const struct fetch_type probe_fetch_types[] = {
        /* Special types */
-       __ASSIGN_FETCH_TYPE("string", string, string, sizeof(u32), 1,
+       __ASSIGN_FETCH_TYPE("string", string, string, sizeof(u32), 1, 1,
                            "__data_loc char[]"),
-       __ASSIGN_FETCH_TYPE("ustring", string, string, sizeof(u32), 1,
+       __ASSIGN_FETCH_TYPE("ustring", string, string, sizeof(u32), 1, 1,
+                           "__data_loc char[]"),
+       __ASSIGN_FETCH_TYPE("symstr", string, string, sizeof(u32), 1, 1,
                            "__data_loc char[]"),
        /* Basic types */
        ASSIGN_FETCH_TYPE(u8,  u8,  0),
@@ -98,10 +100,15 @@ static const struct fetch_type probe_fetch_types[] = {
        ASSIGN_FETCH_TYPE_END
 };
 
-static const struct fetch_type *find_fetch_type(const char *type)
+static const struct fetch_type *find_fetch_type(const char *type, unsigned long flags)
 {
        int i;
 
+       /* Reject the symbol/symstr for uprobes */
+       if (type && (flags & TPARG_FL_USER) &&
+           (!strcmp(type, "symbol") || !strcmp(type, "symstr")))
+               return NULL;
+
        if (!type)
                type = DEFAULT_FETCH_TYPE_STR;
 
@@ -119,13 +126,13 @@ static const struct fetch_type *find_fetch_type(const char *type)
 
                switch (bs) {
                case 8:
-                       return find_fetch_type("u8");
+                       return find_fetch_type("u8", flags);
                case 16:
-                       return find_fetch_type("u16");
+                       return find_fetch_type("u16", flags);
                case 32:
-                       return find_fetch_type("u32");
+                       return find_fetch_type("u32", flags);
                case 64:
-                       return find_fetch_type("u64");
+                       return find_fetch_type("u64", flags);
                default:
                        goto fail;
                }
@@ -478,7 +485,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
                                            DEREF_OPEN_BRACE);
                        return -EINVAL;
                } else {
-                       const struct fetch_type *t2 = find_fetch_type(NULL);
+                       const struct fetch_type *t2 = find_fetch_type(NULL, flags);
 
                        *tmp = '\0';
                        ret = parse_probe_arg(arg, t2, &code, end, flags, offs);
@@ -630,9 +637,9 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
                /* The type of $comm must be "string", and not an array. */
                if (parg->count || (t && strcmp(t, "string")))
                        goto out;
-               parg->type = find_fetch_type("string");
+               parg->type = find_fetch_type("string", flags);
        } else
-               parg->type = find_fetch_type(t);
+               parg->type = find_fetch_type(t, flags);
        if (!parg->type) {
                trace_probe_log_err(offset + (t ? (t - arg) : 0), BAD_TYPE);
                goto out;
@@ -662,16 +669,26 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
 
        ret = -EINVAL;
        /* Store operation */
-       if (!strcmp(parg->type->name, "string") ||
-           !strcmp(parg->type->name, "ustring")) {
-               if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_UDEREF &&
-                   code->op != FETCH_OP_IMM && code->op != FETCH_OP_COMM &&
-                   code->op != FETCH_OP_DATA && code->op != FETCH_OP_TP_ARG) {
-                       trace_probe_log_err(offset + (t ? (t - arg) : 0),
-                                           BAD_STRING);
-                       goto fail;
+       if (parg->type->is_string) {
+               if (!strcmp(parg->type->name, "symstr")) {
+                       if (code->op != FETCH_OP_REG && code->op != FETCH_OP_STACK &&
+                           code->op != FETCH_OP_RETVAL && code->op != FETCH_OP_ARG &&
+                           code->op != FETCH_OP_DEREF && code->op != FETCH_OP_TP_ARG) {
+                               trace_probe_log_err(offset + (t ? (t - arg) : 0),
+                                                   BAD_SYMSTRING);
+                               goto fail;
+                       }
+               } else {
+                       if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_UDEREF &&
+                           code->op != FETCH_OP_IMM && code->op != FETCH_OP_COMM &&
+                           code->op != FETCH_OP_DATA && code->op != FETCH_OP_TP_ARG) {
+                               trace_probe_log_err(offset + (t ? (t - arg) : 0),
+                                                   BAD_STRING);
+                               goto fail;
+                       }
                }
-               if ((code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM ||
+               if (!strcmp(parg->type->name, "symstr") ||
+                   (code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM ||
                     code->op == FETCH_OP_DATA) || code->op == FETCH_OP_TP_ARG ||
                     parg->count) {
                        /*
@@ -679,6 +696,8 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
                         * must be kept, and if parg->count != 0, this is an
                         * array of string pointers instead of string address
                         * itself.
+                        * For the symstr, it doesn't need to dereference, thus
+                        * it just get the value.
                         */
                        code++;
                        if (code->op != FETCH_OP_NOP) {
@@ -690,6 +709,8 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
                if (!strcmp(parg->type->name, "ustring") ||
                    code->op == FETCH_OP_UDEREF)
                        code->op = FETCH_OP_ST_USTRING;
+               else if (!strcmp(parg->type->name, "symstr"))
+                       code->op = FETCH_OP_ST_SYMSTR;
                else
                        code->op = FETCH_OP_ST_STRING;
                code->size = parg->type->size;
@@ -919,8 +940,7 @@ static int __set_print_fmt(struct trace_probe *tp, char *buf, int len,
        for (i = 0; i < tp->nr_args; i++) {
                parg = tp->args + i;
                if (parg->count) {
-                       if ((strcmp(parg->type->name, "string") == 0) ||
-                           (strcmp(parg->type->name, "ustring") == 0))
+                       if (parg->type->is_string)
                                fmt = ", __get_str(%s[%d])";
                        else
                                fmt = ", REC->%s[%d]";
@@ -928,8 +948,7 @@ static int __set_print_fmt(struct trace_probe *tp, char *buf, int len,
                                pos += snprintf(buf + pos, LEN_OR_ZERO,
                                                fmt, parg->name, j);
                } else {
-                       if ((strcmp(parg->type->name, "string") == 0) ||
-                           (strcmp(parg->type->name, "ustring") == 0))
+                       if (parg->type->is_string)
                                fmt = ", __get_str(%s)";
                        else
                                fmt = ", REC->%s";
index de38f1c..23acfd1 100644 (file)
@@ -98,6 +98,7 @@ enum fetch_op {
        FETCH_OP_ST_UMEM,       /* Mem: .offset, .size */
        FETCH_OP_ST_STRING,     /* String: .offset, .size */
        FETCH_OP_ST_USTRING,    /* User String: .offset, .size */
+       FETCH_OP_ST_SYMSTR,     /* Kernel Symbol String: .offset, .size */
        // Stage 4 (modify) op
        FETCH_OP_MOD_BF,        /* Bitfield: .basesize, .lshift, .rshift */
        // Stage 5 (loop) op
@@ -133,7 +134,8 @@ struct fetch_insn {
 struct fetch_type {
        const char              *name;          /* Name of type */
        size_t                  size;           /* Byte size of type */
-       int                     is_signed;      /* Signed flag */
+       bool                    is_signed;      /* Signed flag */
+       bool                    is_string;      /* String flag */
        print_type_func_t       print;          /* Print functions */
        const char              *fmt;           /* Format string */
        const char              *fmttype;       /* Name in format file */
@@ -177,16 +179,19 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(symbol);
 #define _ADDR_FETCH_TYPE(t) __ADDR_FETCH_TYPE(t)
 #define ADDR_FETCH_TYPE _ADDR_FETCH_TYPE(BITS_PER_LONG)
 
-#define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype)        \
-       {.name = _name,                         \
+#define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, str, _fmttype)   \
+       {.name = _name,                                 \
         .size = _size,                                 \
-        .is_signed = sign,                             \
+        .is_signed = (bool)sign,                       \
+        .is_string = (bool)str,                        \
         .print = PRINT_TYPE_FUNC_NAME(ptype),          \
         .fmt = PRINT_TYPE_FMT_NAME(ptype),             \
         .fmttype = _fmttype,                           \
        }
+
+/* Non string types can use these macros */
 #define _ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype) \
-       __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, #_fmttype)
+       __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, 0, #_fmttype)
 #define ASSIGN_FETCH_TYPE(ptype, ftype, sign)                  \
        _ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, ptype)
 
@@ -353,7 +358,8 @@ int trace_probe_create(const char *raw_command, int (*createfn)(int, const char
 #define TPARG_FL_KERNEL BIT(1)
 #define TPARG_FL_FENTRY BIT(2)
 #define TPARG_FL_TPOINT BIT(3)
-#define TPARG_FL_MASK  GENMASK(3, 0)
+#define TPARG_FL_USER   BIT(4)
+#define TPARG_FL_MASK  GENMASK(4, 0)
 
 extern int traceprobe_parse_probe_arg(struct trace_probe *tp, int i,
                                const char *argv, unsigned int flags);
@@ -431,6 +437,7 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
        C(ARRAY_TOO_BIG,        "Array number is too big"),             \
        C(BAD_TYPE,             "Unknown type is specified"),           \
        C(BAD_STRING,           "String accepts only memory argument"), \
+       C(BAD_SYMSTRING,        "Symbol String doesn't accept data/userdata"),  \
        C(BAD_BITFIELD,         "Invalid bitfield"),                    \
        C(ARG_NAME_TOO_LONG,    "Argument name is too long"),           \
        C(NO_ARG_NAME,          "Argument name is not specified"),      \
index b3bdb8d..5cea672 100644 (file)
@@ -67,6 +67,37 @@ probe_mem_read(void *dest, void *src, size_t size);
 static nokprobe_inline int
 probe_mem_read_user(void *dest, void *src, size_t size);
 
+static nokprobe_inline int
+fetch_store_symstrlen(unsigned long addr)
+{
+       char namebuf[KSYM_SYMBOL_LEN];
+       int ret;
+
+       ret = sprint_symbol(namebuf, addr);
+       if (ret < 0)
+               return 0;
+
+       return ret + 1;
+}
+
+/*
+ * Fetch a null-terminated symbol string + offset. Caller MUST set *(u32 *)buf
+ * with max length and relative data location.
+ */
+static nokprobe_inline int
+fetch_store_symstring(unsigned long addr, void *dest, void *base)
+{
+       int maxlen = get_loc_len(*(u32 *)dest);
+       void *__dest;
+
+       if (unlikely(!maxlen))
+               return -ENOMEM;
+
+       __dest = get_loc_data(dest, base);
+
+       return sprint_symbol(__dest, addr);
+}
+
 /* From the 2nd stage, routine is same */
 static nokprobe_inline int
 process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
@@ -99,16 +130,22 @@ stage2:
 stage3:
        /* 3rd stage: store value to buffer */
        if (unlikely(!dest)) {
-               if (code->op == FETCH_OP_ST_STRING) {
+               switch (code->op) {
+               case FETCH_OP_ST_STRING:
                        ret = fetch_store_strlen(val + code->offset);
                        code++;
                        goto array;
-               } else if (code->op == FETCH_OP_ST_USTRING) {
+               case FETCH_OP_ST_USTRING:
                        ret += fetch_store_strlen_user(val + code->offset);
                        code++;
                        goto array;
-               } else
+               case FETCH_OP_ST_SYMSTR:
+                       ret += fetch_store_symstrlen(val + code->offset);
+                       code++;
+                       goto array;
+               default:
                        return -EILSEQ;
+               }
        }
 
        switch (code->op) {
@@ -129,6 +166,10 @@ stage3:
                loc = *(u32 *)dest;
                ret = fetch_store_string_user(val + code->offset, dest, base);
                break;
+       case FETCH_OP_ST_SYMSTR:
+               loc = *(u32 *)dest;
+               ret = fetch_store_symstring(val + code->offset, dest, base);
+               break;
        default:
                return -EILSEQ;
        }
index fb58e86..8d64b65 100644 (file)
@@ -691,7 +691,8 @@ static int __trace_uprobe_create(int argc, const char **argv)
        for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
                trace_probe_log_set_index(i + 2);
                ret = traceprobe_parse_probe_arg(&tu->tp, i, argv[i],
-                                       is_return ? TPARG_FL_RETURN : 0);
+                                       (is_return ? TPARG_FL_RETURN : 0) |
+                                       TPARG_FL_USER);
                if (ret)
                        goto error;
        }
index f5e3f9e..c817158 100644 (file)
@@ -23,4 +23,9 @@ check_error 'p /bin/sh:10^%hoge'      # BAD_ADDR_SUFFIX
 check_error 'p /bin/sh:10(10)^%return' # BAD_REFCNT_SUFFIX
 fi
 
+# symstr is not supported by uprobe
+if grep -q ".*symstr.*" README; then
+check_error 'p /bin/sh:10 $stack0:^symstr'     # BAD_TYPE
+fi
+
 exit 0