bpf: Take module reference for trampoline in module
Currently module can be unloaded even if there's a trampoline register in it. It's easily reproduced by running in parallel: # while :; do ./test_progs -t module_attach; done # while :; do rmmod bpf_testmod; sleep 0.5; done Taking the module reference in case the trampoline's ip is within the module code. Releasing it when the trampoline's ip is unregistered. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://lore.kernel.org/bpf/20210326105900.151466-1-jolsa@kernel.org
This commit is contained in:
Родитель
d6fe1cf890
Коммит
861de02e5f
|
@ -40,6 +40,7 @@ struct bpf_local_storage;
|
|||
struct bpf_local_storage_map;
|
||||
struct kobject;
|
||||
struct mem_cgroup;
|
||||
struct module;
|
||||
|
||||
extern struct idr btf_idr;
|
||||
extern spinlock_t btf_idr_lock;
|
||||
|
@ -623,6 +624,7 @@ struct bpf_trampoline {
|
|||
/* Executable image of trampoline */
|
||||
struct bpf_tramp_image *cur_image;
|
||||
u64 selector;
|
||||
struct module *mod;
|
||||
};
|
||||
|
||||
struct bpf_attach_target_info {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/btf.h>
|
||||
#include <linux/rcupdate_trace.h>
|
||||
#include <linux/rcupdate_wait.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
/* dummy _ops. The verifier will operate on target program's ops. */
|
||||
const struct bpf_verifier_ops bpf_extension_verifier_ops = {
|
||||
|
@ -87,6 +88,26 @@ out:
|
|||
return tr;
|
||||
}
|
||||
|
||||
static int bpf_trampoline_module_get(struct bpf_trampoline *tr)
|
||||
{
|
||||
struct module *mod;
|
||||
int err = 0;
|
||||
|
||||
preempt_disable();
|
||||
mod = __module_text_address((unsigned long) tr->func.addr);
|
||||
if (mod && !try_module_get(mod))
|
||||
err = -ENOENT;
|
||||
preempt_enable();
|
||||
tr->mod = mod;
|
||||
return err;
|
||||
}
|
||||
|
||||
static void bpf_trampoline_module_put(struct bpf_trampoline *tr)
|
||||
{
|
||||
module_put(tr->mod);
|
||||
tr->mod = NULL;
|
||||
}
|
||||
|
||||
static int is_ftrace_location(void *ip)
|
||||
{
|
||||
long addr;
|
||||
|
@ -108,6 +129,9 @@ static int unregister_fentry(struct bpf_trampoline *tr, void *old_addr)
|
|||
ret = unregister_ftrace_direct((long)ip, (long)old_addr);
|
||||
else
|
||||
ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, old_addr, NULL);
|
||||
|
||||
if (!ret)
|
||||
bpf_trampoline_module_put(tr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -134,10 +158,16 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
|
|||
return ret;
|
||||
tr->func.ftrace_managed = ret;
|
||||
|
||||
if (bpf_trampoline_module_get(tr))
|
||||
return -ENOENT;
|
||||
|
||||
if (tr->func.ftrace_managed)
|
||||
ret = register_ftrace_direct((long)ip, (long)new_addr);
|
||||
else
|
||||
ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, NULL, new_addr);
|
||||
|
||||
if (ret)
|
||||
bpf_trampoline_module_put(tr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче