tracing/probes: Reject symbol/symstr type for uprobe
authorMasami Hiramatsu (Google) <mhiramat@kernel.org>
Mon, 14 Nov 2022 04:47:56 +0000 (13:47 +0900)
committerMasami Hiramatsu (Google) <mhiramat@kernel.org>
Thu, 15 Dec 2022 00:00:20 +0000 (09:00 +0900)
Since uprobe's argument must contain the user-space data, that
should not be converted to kernel symbols. Reject if user
specifies these types on uprobe events. e.g.

 /sys/kernel/debug/tracing # echo 'p /bin/sh:10 %ax:symbol' >> uprobe_events
 sh: write error: Invalid argument
 /sys/kernel/debug/tracing # echo 'p /bin/sh:10 %ax:symstr' >> uprobe_events
 sh: write error: Invalid argument
 /sys/kernel/debug/tracing # cat error_log
 [ 1783.134883] trace_uprobe: error: Unknown type is specified
   Command: p /bin/sh:10 %ax:symbol
                             ^
 [ 1792.201120] trace_uprobe: error: Unknown type is specified
   Command: p /bin/sh:10 %ax:symstr
                             ^
Link: https://lore.kernel.org/all/166679931679.1528100.15540755370726009882.stgit@devnote3/
Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
kernel/trace/trace_probe.c
kernel/trace/trace_probe.h
kernel/trace/trace_uprobe.c
tools/testing/selftests/ftrace/test.d/kprobe/uprobe_syntax_errors.tc

index dfec4af857b40113fc332754346f8d53a4661cae..960bb7693a843648c9387be6acc4057ce61d657f 100644 (file)
@@ -100,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;
 
@@ -121,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;
                }
@@ -480,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);
@@ -632,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;
index 0838b74f403b688523f2b6b9448a263034c93c7b..23acfd1c381221001d1739a5f2e29ea0ac3004e9 100644 (file)
@@ -358,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);
index fb58e86dd1178ffca0cdd3244b61bc8622dcc1c8..8d64b6553aedf7244431caab9f7f6e7b07eaa4d8 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 f5e3f9e4a01fe334f26a2d95dc4a1bb37528ac9a..c817158b99db6c1046f9ab9232645e5335a19641 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