Merge tag 'probes-v6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace
Pull probes updates from Masami Hiramatsu:
"Uprobes:
- x86/shstk: Make return uprobe work with shadow stack
- Add uretprobe syscall which speeds up the uretprobe 10-30% faster.
This syscall is automatically used from user-space trampolines
which are generated by the uretprobe. If this syscall is used by
normal user program, it will cause SIGILL. Note that this is
currently only implemented on x86_64.
(This also has two fixes for adjusting the syscall number to avoid
conflict with new *attrat syscalls.)
- uprobes/perf: fix user stack traces in the presence of pending
uretprobe. This corrects the uretprobe's trampoline address in the
stacktrace with correct return address
- selftests/x86: Add a return uprobe with shadow stack test
- selftests/bpf: Add uretprobe syscall related tests.
- test case for register integrity check
- test case with register changing case
- test case for uretprobe syscall without uprobes (expected to fail)
- test case for uretprobe with shadow stack
- selftests/bpf: add test validating uprobe/uretprobe stack traces
- MAINTAINERS: Add uprobes entry. This does not specify the tree but
to clarify who maintains and reviews the uprobes
Kprobes:
- tracing/kprobes: Test case cleanups.
Replace redundant WARN_ON_ONCE() + pr_warn() with WARN_ONCE() and
remove unnecessary code from selftest
- tracing/kprobes: Add symbol counting check when module loads.
This checks the uniqueness of the probed symbol on modules. The
same check has already done for kernel symbols
(This also has a fix for build error with CONFIG_MODULES=n)
Cleanup:
- Add MODULE_DESCRIPTION() macros for fprobe and kprobe examples"
* tag 'probes-v6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
MAINTAINERS: Add uprobes entry
selftests/bpf: Change uretprobe syscall number in uprobe_syscall test
uprobe: Change uretprobe syscall scope and number
tracing/kprobes: Fix build error when find_module() is not available
tracing/kprobes: Add symbol counting check when module loads
selftests/bpf: add test validating uprobe/uretprobe stack traces
perf,uprobes: fix user stack traces in the presence of pending uretprobes
tracing/kprobe: Remove cleanup code unrelated to selftest
tracing/kprobe: Integrate test warnings into WARN_ONCE
selftests/bpf: Add uretprobe shadow stack test
selftests/bpf: Add uretprobe syscall call from user space test
selftests/bpf: Add uretprobe syscall test for regs changes
selftests/bpf: Add uretprobe syscall test for regs integrity
selftests/x86: Add return uprobe shadow stack test
uprobe: Add uretprobe syscall to speed up return probe
uprobe: Wire up uretprobe system call
x86/shstk: Make return uprobe work with shadow stack
samples: kprobes: add missing MODULE_DESCRIPTION() macros
fprobe: add missing MODULE_DESCRIPTION() macro
This commit is contained in:
+111
-81
@@ -678,6 +678,21 @@ end:
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MODULES
|
||||
static int validate_module_probe_symbol(const char *modname, const char *symbol);
|
||||
|
||||
static int register_module_trace_kprobe(struct module *mod, struct trace_kprobe *tk)
|
||||
{
|
||||
const char *p;
|
||||
int ret = 0;
|
||||
|
||||
p = strchr(trace_kprobe_symbol(tk), ':');
|
||||
if (p)
|
||||
ret = validate_module_probe_symbol(module_name(mod), p + 1);
|
||||
if (!ret)
|
||||
ret = __register_trace_kprobe(tk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Module notifier call back, checking event on the module */
|
||||
static int trace_kprobe_module_callback(struct notifier_block *nb,
|
||||
unsigned long val, void *data)
|
||||
@@ -696,7 +711,7 @@ static int trace_kprobe_module_callback(struct notifier_block *nb,
|
||||
if (trace_kprobe_within_module(tk, mod)) {
|
||||
/* Don't need to check busy - this should have gone. */
|
||||
__unregister_trace_kprobe(tk);
|
||||
ret = __register_trace_kprobe(tk);
|
||||
ret = register_module_trace_kprobe(mod, tk);
|
||||
if (ret)
|
||||
pr_warn("Failed to re-register probe %s on %s: %d\n",
|
||||
trace_probe_name(&tk->tp),
|
||||
@@ -747,17 +762,81 @@ static int count_mod_symbols(void *data, const char *name, unsigned long unused)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int number_of_same_symbols(char *func_name)
|
||||
static unsigned int number_of_same_symbols(const char *mod, const char *func_name)
|
||||
{
|
||||
struct sym_count_ctx ctx = { .count = 0, .name = func_name };
|
||||
|
||||
kallsyms_on_each_match_symbol(count_symbols, func_name, &ctx.count);
|
||||
if (!mod)
|
||||
kallsyms_on_each_match_symbol(count_symbols, func_name, &ctx.count);
|
||||
|
||||
module_kallsyms_on_each_symbol(NULL, count_mod_symbols, &ctx);
|
||||
module_kallsyms_on_each_symbol(mod, count_mod_symbols, &ctx);
|
||||
|
||||
return ctx.count;
|
||||
}
|
||||
|
||||
static int validate_module_probe_symbol(const char *modname, const char *symbol)
|
||||
{
|
||||
unsigned int count = number_of_same_symbols(modname, symbol);
|
||||
|
||||
if (count > 1) {
|
||||
/*
|
||||
* Users should use ADDR to remove the ambiguity of
|
||||
* using KSYM only.
|
||||
*/
|
||||
return -EADDRNOTAVAIL;
|
||||
} else if (count == 0) {
|
||||
/*
|
||||
* We can return ENOENT earlier than when register the
|
||||
* kprobe.
|
||||
*/
|
||||
return -ENOENT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MODULES
|
||||
/* Return NULL if the module is not loaded or under unloading. */
|
||||
static struct module *try_module_get_by_name(const char *name)
|
||||
{
|
||||
struct module *mod;
|
||||
|
||||
rcu_read_lock_sched();
|
||||
mod = find_module(name);
|
||||
if (mod && !try_module_get(mod))
|
||||
mod = NULL;
|
||||
rcu_read_unlock_sched();
|
||||
|
||||
return mod;
|
||||
}
|
||||
#else
|
||||
#define try_module_get_by_name(name) (NULL)
|
||||
#endif
|
||||
|
||||
static int validate_probe_symbol(char *symbol)
|
||||
{
|
||||
struct module *mod = NULL;
|
||||
char *modname = NULL, *p;
|
||||
int ret = 0;
|
||||
|
||||
p = strchr(symbol, ':');
|
||||
if (p) {
|
||||
modname = symbol;
|
||||
symbol = p + 1;
|
||||
*p = '\0';
|
||||
mod = try_module_get_by_name(modname);
|
||||
if (!mod)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = validate_module_probe_symbol(modname, symbol);
|
||||
out:
|
||||
if (p)
|
||||
*p = ':';
|
||||
if (mod)
|
||||
module_put(mod);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int trace_kprobe_entry_handler(struct kretprobe_instance *ri,
|
||||
struct pt_regs *regs);
|
||||
|
||||
@@ -881,6 +960,14 @@ static int __trace_kprobe_create(int argc, const char *argv[])
|
||||
trace_probe_log_err(0, BAD_PROBE_ADDR);
|
||||
goto parse_error;
|
||||
}
|
||||
ret = validate_probe_symbol(symbol);
|
||||
if (ret) {
|
||||
if (ret == -EADDRNOTAVAIL)
|
||||
trace_probe_log_err(0, NON_UNIQ_SYMBOL);
|
||||
else
|
||||
trace_probe_log_err(0, BAD_PROBE_ADDR);
|
||||
goto parse_error;
|
||||
}
|
||||
if (is_return)
|
||||
ctx.flags |= TPARG_FL_RETURN;
|
||||
ret = kprobe_on_func_entry(NULL, symbol, offset);
|
||||
@@ -893,31 +980,6 @@ static int __trace_kprobe_create(int argc, const char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (symbol && !strchr(symbol, ':')) {
|
||||
unsigned int count;
|
||||
|
||||
count = number_of_same_symbols(symbol);
|
||||
if (count > 1) {
|
||||
/*
|
||||
* Users should use ADDR to remove the ambiguity of
|
||||
* using KSYM only.
|
||||
*/
|
||||
trace_probe_log_err(0, NON_UNIQ_SYMBOL);
|
||||
ret = -EADDRNOTAVAIL;
|
||||
|
||||
goto error;
|
||||
} else if (count == 0) {
|
||||
/*
|
||||
* We can return ENOENT earlier than when register the
|
||||
* kprobe.
|
||||
*/
|
||||
trace_probe_log_err(0, BAD_PROBE_ADDR);
|
||||
ret = -ENOENT;
|
||||
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
trace_probe_log_set_index(0);
|
||||
if (event) {
|
||||
ret = traceprobe_parse_event_name(&event, &group, gbuf,
|
||||
@@ -1835,21 +1897,9 @@ create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
|
||||
char *event;
|
||||
|
||||
if (func) {
|
||||
unsigned int count;
|
||||
|
||||
count = number_of_same_symbols(func);
|
||||
if (count > 1)
|
||||
/*
|
||||
* Users should use addr to remove the ambiguity of
|
||||
* using func only.
|
||||
*/
|
||||
return ERR_PTR(-EADDRNOTAVAIL);
|
||||
else if (count == 0)
|
||||
/*
|
||||
* We can return ENOENT earlier than when register the
|
||||
* kprobe.
|
||||
*/
|
||||
return ERR_PTR(-ENOENT);
|
||||
ret = validate_probe_symbol(func);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2023,19 +2073,16 @@ static __init int kprobe_trace_self_tests_init(void)
|
||||
pr_info("Testing kprobe tracing: ");
|
||||
|
||||
ret = create_or_delete_trace_kprobe("p:testprobe kprobe_trace_selftest_target $stack $stack0 +0($stack)");
|
||||
if (WARN_ON_ONCE(ret)) {
|
||||
pr_warn("error on probing function entry.\n");
|
||||
if (WARN_ONCE(ret, "error on probing function entry.")) {
|
||||
warn++;
|
||||
} else {
|
||||
/* Enable trace point */
|
||||
tk = find_trace_kprobe("testprobe", KPROBE_EVENT_SYSTEM);
|
||||
if (WARN_ON_ONCE(tk == NULL)) {
|
||||
pr_warn("error on getting new probe.\n");
|
||||
if (WARN_ONCE(tk == NULL, "error on probing function entry.")) {
|
||||
warn++;
|
||||
} else {
|
||||
file = find_trace_probe_file(tk, top_trace_array());
|
||||
if (WARN_ON_ONCE(file == NULL)) {
|
||||
pr_warn("error on getting probe file.\n");
|
||||
if (WARN_ONCE(file == NULL, "error on getting probe file.")) {
|
||||
warn++;
|
||||
} else
|
||||
enable_trace_kprobe(
|
||||
@@ -2044,19 +2091,16 @@ static __init int kprobe_trace_self_tests_init(void)
|
||||
}
|
||||
|
||||
ret = create_or_delete_trace_kprobe("r:testprobe2 kprobe_trace_selftest_target $retval");
|
||||
if (WARN_ON_ONCE(ret)) {
|
||||
pr_warn("error on probing function return.\n");
|
||||
if (WARN_ONCE(ret, "error on probing function return.")) {
|
||||
warn++;
|
||||
} else {
|
||||
/* Enable trace point */
|
||||
tk = find_trace_kprobe("testprobe2", KPROBE_EVENT_SYSTEM);
|
||||
if (WARN_ON_ONCE(tk == NULL)) {
|
||||
pr_warn("error on getting 2nd new probe.\n");
|
||||
if (WARN_ONCE(tk == NULL, "error on getting 2nd new probe.")) {
|
||||
warn++;
|
||||
} else {
|
||||
file = find_trace_probe_file(tk, top_trace_array());
|
||||
if (WARN_ON_ONCE(file == NULL)) {
|
||||
pr_warn("error on getting probe file.\n");
|
||||
if (WARN_ONCE(file == NULL, "error on getting probe file.")) {
|
||||
warn++;
|
||||
} else
|
||||
enable_trace_kprobe(
|
||||
@@ -2079,18 +2123,15 @@ static __init int kprobe_trace_self_tests_init(void)
|
||||
|
||||
/* Disable trace points before removing it */
|
||||
tk = find_trace_kprobe("testprobe", KPROBE_EVENT_SYSTEM);
|
||||
if (WARN_ON_ONCE(tk == NULL)) {
|
||||
pr_warn("error on getting test probe.\n");
|
||||
if (WARN_ONCE(tk == NULL, "error on getting test probe.")) {
|
||||
warn++;
|
||||
} else {
|
||||
if (trace_kprobe_nhit(tk) != 1) {
|
||||
pr_warn("incorrect number of testprobe hits\n");
|
||||
if (WARN_ONCE(trace_kprobe_nhit(tk) != 1,
|
||||
"incorrect number of testprobe hits."))
|
||||
warn++;
|
||||
}
|
||||
|
||||
file = find_trace_probe_file(tk, top_trace_array());
|
||||
if (WARN_ON_ONCE(file == NULL)) {
|
||||
pr_warn("error on getting probe file.\n");
|
||||
if (WARN_ONCE(file == NULL, "error on getting probe file.")) {
|
||||
warn++;
|
||||
} else
|
||||
disable_trace_kprobe(
|
||||
@@ -2098,18 +2139,15 @@ static __init int kprobe_trace_self_tests_init(void)
|
||||
}
|
||||
|
||||
tk = find_trace_kprobe("testprobe2", KPROBE_EVENT_SYSTEM);
|
||||
if (WARN_ON_ONCE(tk == NULL)) {
|
||||
pr_warn("error on getting 2nd test probe.\n");
|
||||
if (WARN_ONCE(tk == NULL, "error on getting 2nd test probe.")) {
|
||||
warn++;
|
||||
} else {
|
||||
if (trace_kprobe_nhit(tk) != 1) {
|
||||
pr_warn("incorrect number of testprobe2 hits\n");
|
||||
if (WARN_ONCE(trace_kprobe_nhit(tk) != 1,
|
||||
"incorrect number of testprobe2 hits."))
|
||||
warn++;
|
||||
}
|
||||
|
||||
file = find_trace_probe_file(tk, top_trace_array());
|
||||
if (WARN_ON_ONCE(file == NULL)) {
|
||||
pr_warn("error on getting probe file.\n");
|
||||
if (WARN_ONCE(file == NULL, "error on getting probe file.")) {
|
||||
warn++;
|
||||
} else
|
||||
disable_trace_kprobe(
|
||||
@@ -2117,23 +2155,15 @@ static __init int kprobe_trace_self_tests_init(void)
|
||||
}
|
||||
|
||||
ret = create_or_delete_trace_kprobe("-:testprobe");
|
||||
if (WARN_ON_ONCE(ret)) {
|
||||
pr_warn("error on deleting a probe.\n");
|
||||
if (WARN_ONCE(ret, "error on deleting a probe."))
|
||||
warn++;
|
||||
}
|
||||
|
||||
ret = create_or_delete_trace_kprobe("-:testprobe2");
|
||||
if (WARN_ON_ONCE(ret)) {
|
||||
pr_warn("error on deleting a probe.\n");
|
||||
if (WARN_ONCE(ret, "error on deleting a probe."))
|
||||
warn++;
|
||||
}
|
||||
|
||||
|
||||
end:
|
||||
ret = dyn_events_release_all(&trace_kprobe_ops);
|
||||
if (WARN_ON_ONCE(ret)) {
|
||||
pr_warn("error on cleaning up probes.\n");
|
||||
warn++;
|
||||
}
|
||||
/*
|
||||
* Wait for the optimizer work to finish. Otherwise it might fiddle
|
||||
* with probes in already freed __init text.
|
||||
|
||||
Reference in New Issue
Block a user