tracing/probes: Reject symbol/symstr type for uprobe

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: default avatarMasami Hiramatsu (Google) <mhiramat@kernel.org>
parent b26a124c
...@@ -100,10 +100,15 @@ static const struct fetch_type probe_fetch_types[] = { ...@@ -100,10 +100,15 @@ static const struct fetch_type probe_fetch_types[] = {
ASSIGN_FETCH_TYPE_END 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; int i;
/* Reject the symbol/symstr for uprobes */
if (type && (flags & TPARG_FL_USER) &&
(!strcmp(type, "symbol") || !strcmp(type, "symstr")))
return NULL;
if (!type) if (!type)
type = DEFAULT_FETCH_TYPE_STR; type = DEFAULT_FETCH_TYPE_STR;
...@@ -121,13 +126,13 @@ static const struct fetch_type *find_fetch_type(const char *type) ...@@ -121,13 +126,13 @@ static const struct fetch_type *find_fetch_type(const char *type)
switch (bs) { switch (bs) {
case 8: case 8:
return find_fetch_type("u8"); return find_fetch_type("u8", flags);
case 16: case 16:
return find_fetch_type("u16"); return find_fetch_type("u16", flags);
case 32: case 32:
return find_fetch_type("u32"); return find_fetch_type("u32", flags);
case 64: case 64:
return find_fetch_type("u64"); return find_fetch_type("u64", flags);
default: default:
goto fail; goto fail;
} }
...@@ -480,7 +485,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type, ...@@ -480,7 +485,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
DEREF_OPEN_BRACE); DEREF_OPEN_BRACE);
return -EINVAL; return -EINVAL;
} else { } else {
const struct fetch_type *t2 = find_fetch_type(NULL); const struct fetch_type *t2 = find_fetch_type(NULL, flags);
*tmp = '\0'; *tmp = '\0';
ret = parse_probe_arg(arg, t2, &code, end, flags, offs); 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, ...@@ -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. */ /* The type of $comm must be "string", and not an array. */
if (parg->count || (t && strcmp(t, "string"))) if (parg->count || (t && strcmp(t, "string")))
goto out; goto out;
parg->type = find_fetch_type("string"); parg->type = find_fetch_type("string", flags);
} else } else
parg->type = find_fetch_type(t); parg->type = find_fetch_type(t, flags);
if (!parg->type) { if (!parg->type) {
trace_probe_log_err(offset + (t ? (t - arg) : 0), BAD_TYPE); trace_probe_log_err(offset + (t ? (t - arg) : 0), BAD_TYPE);
goto out; goto out;
......
...@@ -358,7 +358,8 @@ int trace_probe_create(const char *raw_command, int (*createfn)(int, const char ...@@ -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_KERNEL BIT(1)
#define TPARG_FL_FENTRY BIT(2) #define TPARG_FL_FENTRY BIT(2)
#define TPARG_FL_TPOINT BIT(3) #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, extern int traceprobe_parse_probe_arg(struct trace_probe *tp, int i,
const char *argv, unsigned int flags); const char *argv, unsigned int flags);
......
...@@ -691,7 +691,8 @@ static int __trace_uprobe_create(int argc, const char **argv) ...@@ -691,7 +691,8 @@ static int __trace_uprobe_create(int argc, const char **argv)
for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) { for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
trace_probe_log_set_index(i + 2); trace_probe_log_set_index(i + 2);
ret = traceprobe_parse_probe_arg(&tu->tp, i, argv[i], 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) if (ret)
goto error; goto error;
} }
......
...@@ -23,4 +23,9 @@ check_error 'p /bin/sh:10^%hoge' # BAD_ADDR_SUFFIX ...@@ -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 check_error 'p /bin/sh:10(10)^%return' # BAD_REFCNT_SUFFIX
fi 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 exit 0
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment