Skip to content

Commit 31bf1db

Browse files
viktormalikAlexei Starovoitov
authored andcommitted
bpf: Fix attaching fentry/fexit/fmod_ret/lsm to modules
This resolves two problems with attachment of fentry/fexit/fmod_ret/lsm to functions located in modules: 1. The verifier tries to find the address to attach to in kallsyms. This is always done by searching the entire kallsyms, not respecting the module in which the function is located. Such approach causes an incorrect attachment address to be computed if the function to attach to is shadowed by a function of the same name located earlier in kallsyms. 2. If the address to attach to is located in a module, the module reference is only acquired in register_fentry. If the module is unloaded between the place where the address is found (bpf_check_attach_target in the verifier) and register_fentry, it is possible that another module is loaded to the same address which may lead to potential errors. Since the attachment must contain the BTF of the program to attach to, we extract the module from it and search for the function address in the correct module (resolving problem no. 1). Then, the module reference is taken directly in bpf_check_attach_target and stored in the bpf program (in bpf_prog_aux). The reference is only released when the program is unloaded (resolving problem no. 2). Signed-off-by: Viktor Malik <[email protected]> Acked-by: Jiri Olsa <[email protected]> Reviewed-by: Luis Chamberlain <[email protected]> Link: https://lore.kernel.org/r/3f6a9d8ae850532b5ef864ef16327b0f7a669063.1678432753.git.vmalik@redhat.com Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent b8a2e3f commit 31bf1db

File tree

5 files changed

+30
-29
lines changed

5 files changed

+30
-29
lines changed

include/linux/bpf.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,7 @@ struct bpf_trampoline {
11031103
struct bpf_attach_target_info {
11041104
struct btf_func_model fmodel;
11051105
long tgt_addr;
1106+
struct module *tgt_mod;
11061107
const char *tgt_name;
11071108
const struct btf_type *tgt_type;
11081109
};
@@ -1406,6 +1407,7 @@ struct bpf_prog_aux {
14061407
* main prog always has linfo_idx == 0
14071408
*/
14081409
u32 linfo_idx;
1410+
struct module *mod;
14091411
u32 num_exentries;
14101412
struct exception_table_entry *extable;
14111413
union {

kernel/bpf/syscall.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2067,6 +2067,7 @@ static void __bpf_prog_put_noref(struct bpf_prog *prog, bool deferred)
20672067
{
20682068
bpf_prog_kallsyms_del_all(prog);
20692069
btf_put(prog->aux->btf);
2070+
module_put(prog->aux->mod);
20702071
kvfree(prog->aux->jited_linfo);
20712072
kvfree(prog->aux->linfo);
20722073
kfree(prog->aux->kfunc_tab);
@@ -3113,6 +3114,11 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,
31133114
if (err)
31143115
goto out_unlock;
31153116

3117+
if (tgt_info.tgt_mod) {
3118+
module_put(prog->aux->mod);
3119+
prog->aux->mod = tgt_info.tgt_mod;
3120+
}
3121+
31163122
tr = bpf_trampoline_get(key, &tgt_info);
31173123
if (!tr) {
31183124
err = -ENOMEM;

kernel/bpf/trampoline.c

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
#include <linux/btf.h>
1010
#include <linux/rcupdate_trace.h>
1111
#include <linux/rcupdate_wait.h>
12-
#include <linux/module.h>
1312
#include <linux/static_call.h>
1413
#include <linux/bpf_verifier.h>
1514
#include <linux/bpf_lsm.h>
@@ -172,26 +171,6 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
172171
return tr;
173172
}
174173

175-
static int bpf_trampoline_module_get(struct bpf_trampoline *tr)
176-
{
177-
struct module *mod;
178-
int err = 0;
179-
180-
preempt_disable();
181-
mod = __module_text_address((unsigned long) tr->func.addr);
182-
if (mod && !try_module_get(mod))
183-
err = -ENOENT;
184-
preempt_enable();
185-
tr->mod = mod;
186-
return err;
187-
}
188-
189-
static void bpf_trampoline_module_put(struct bpf_trampoline *tr)
190-
{
191-
module_put(tr->mod);
192-
tr->mod = NULL;
193-
}
194-
195174
static int unregister_fentry(struct bpf_trampoline *tr, void *old_addr)
196175
{
197176
void *ip = tr->func.addr;
@@ -202,8 +181,6 @@ static int unregister_fentry(struct bpf_trampoline *tr, void *old_addr)
202181
else
203182
ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, old_addr, NULL);
204183

205-
if (!ret)
206-
bpf_trampoline_module_put(tr);
207184
return ret;
208185
}
209186

@@ -238,18 +215,13 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
238215
tr->func.ftrace_managed = true;
239216
}
240217

241-
if (bpf_trampoline_module_get(tr))
242-
return -ENOENT;
243-
244218
if (tr->func.ftrace_managed) {
245219
ftrace_set_filter_ip(tr->fops, (unsigned long)ip, 0, 1);
246220
ret = register_ftrace_direct_multi(tr->fops, (long)new_addr);
247221
} else {
248222
ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, NULL, new_addr);
249223
}
250224

251-
if (ret)
252-
bpf_trampoline_module_put(tr);
253225
return ret;
254226
}
255227

kernel/bpf/verifier.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <linux/bpf_lsm.h>
2525
#include <linux/btf_ids.h>
2626
#include <linux/poison.h>
27+
#include "../module/internal.h"
2728

2829
#include "disasm.h"
2930

@@ -18307,6 +18308,7 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
1830718308
const char *tname;
1830818309
struct btf *btf;
1830918310
long addr = 0;
18311+
struct module *mod = NULL;
1831018312

1831118313
if (!btf_id) {
1831218314
bpf_log(log, "Tracing programs must provide btf_id\n");
@@ -18480,8 +18482,17 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
1848018482
else
1848118483
addr = (long) tgt_prog->aux->func[subprog]->bpf_func;
1848218484
} else {
18483-
addr = kallsyms_lookup_name(tname);
18485+
if (btf_is_module(btf)) {
18486+
mod = btf_try_get_module(btf);
18487+
if (mod)
18488+
addr = find_kallsyms_symbol_value(mod, tname);
18489+
else
18490+
addr = 0;
18491+
} else {
18492+
addr = kallsyms_lookup_name(tname);
18493+
}
1848418494
if (!addr) {
18495+
module_put(mod);
1848518496
bpf_log(log,
1848618497
"The address of function %s cannot be found\n",
1848718498
tname);
@@ -18521,11 +18532,13 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
1852118532
break;
1852218533
}
1852318534
if (ret) {
18535+
module_put(mod);
1852418536
bpf_log(log, "%s is not sleepable\n", tname);
1852518537
return ret;
1852618538
}
1852718539
} else if (prog->expected_attach_type == BPF_MODIFY_RETURN) {
1852818540
if (tgt_prog) {
18541+
module_put(mod);
1852918542
bpf_log(log, "can't modify return codes of BPF programs\n");
1853018543
return -EINVAL;
1853118544
}
@@ -18534,6 +18547,7 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
1853418547
!check_attach_modify_return(addr, tname))
1853518548
ret = 0;
1853618549
if (ret) {
18550+
module_put(mod);
1853718551
bpf_log(log, "%s() is not modifiable\n", tname);
1853818552
return ret;
1853918553
}
@@ -18544,6 +18558,7 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
1854418558
tgt_info->tgt_addr = addr;
1854518559
tgt_info->tgt_name = tname;
1854618560
tgt_info->tgt_type = t;
18561+
tgt_info->tgt_mod = mod;
1854718562
return 0;
1854818563
}
1854918564

@@ -18623,6 +18638,7 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
1862318638
/* store info about the attachment target that will be used later */
1862418639
prog->aux->attach_func_proto = tgt_info.tgt_type;
1862518640
prog->aux->attach_func_name = tgt_info.tgt_name;
18641+
prog->aux->mod = tgt_info.tgt_mod;
1862618642

1862718643
if (tgt_prog) {
1862818644
prog->aux->saved_dst_prog_type = tgt_prog->type;

kernel/module/internal.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,11 @@ static inline bool sect_empty(const Elf_Shdr *sect)
256256
static inline void init_build_id(struct module *mod, const struct load_info *info) { }
257257
static inline void layout_symtab(struct module *mod, struct load_info *info) { }
258258
static inline void add_kallsyms(struct module *mod, const struct load_info *info) { }
259+
static inline unsigned long find_kallsyms_symbol_value(struct module *mod,
260+
const char *name)
261+
{
262+
return 0;
263+
}
259264
#endif /* CONFIG_KALLSYMS */
260265

261266
#ifdef CONFIG_SYSFS

0 commit comments

Comments
 (0)