Skip to content

Commit 5b481ac

Browse files
committed
bpf: do not rely on ALLOW_ERROR_INJECTION for fmod_ret
The current way of expressing that a non-bpf kernel component is willing to accept that bpf programs can be attached to it and that they can change the return value is to abuse ALLOW_ERROR_INJECTION. This is debated in the link below, and the result is that it is not a reasonable thing to do. Reuse the kfunc declaration structure to also tag the kernel functions we want to be fmodret. This way we can control from any subsystem which functions are being modified by bpf without touching the verifier. Link: https://lore.kernel.org/all/[email protected]/ Suggested-by: Alexei Starovoitov <[email protected]> Signed-off-by: Benjamin Tissoires <[email protected]> Acked-by: Alexei Starovoitov <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 9c730fe commit 5b481ac

File tree

4 files changed

+53
-10
lines changed

4 files changed

+53
-10
lines changed

include/linux/btf.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,8 +412,10 @@ struct btf *bpf_prog_get_target_btf(const struct bpf_prog *prog);
412412
u32 *btf_kfunc_id_set_contains(const struct btf *btf,
413413
enum bpf_prog_type prog_type,
414414
u32 kfunc_btf_id);
415+
u32 *btf_kfunc_is_modify_return(const struct btf *btf, u32 kfunc_btf_id);
415416
int register_btf_kfunc_id_set(enum bpf_prog_type prog_type,
416417
const struct btf_kfunc_id_set *s);
418+
int register_btf_fmodret_id_set(const struct btf_kfunc_id_set *kset);
417419
s32 btf_find_dtor_kfunc(struct btf *btf, u32 btf_id);
418420
int register_btf_id_dtor_kfuncs(const struct btf_id_dtor_kfunc *dtors, u32 add_cnt,
419421
struct module *owner);

kernel/bpf/btf.c

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ enum btf_kfunc_hook {
204204
BTF_KFUNC_HOOK_STRUCT_OPS,
205205
BTF_KFUNC_HOOK_TRACING,
206206
BTF_KFUNC_HOOK_SYSCALL,
207+
BTF_KFUNC_HOOK_FMODRET,
207208
BTF_KFUNC_HOOK_MAX,
208209
};
209210

@@ -7448,11 +7449,14 @@ u32 *btf_kfunc_id_set_contains(const struct btf *btf,
74487449
return __btf_kfunc_id_set_contains(btf, hook, kfunc_btf_id);
74497450
}
74507451

7451-
/* This function must be invoked only from initcalls/module init functions */
7452-
int register_btf_kfunc_id_set(enum bpf_prog_type prog_type,
7453-
const struct btf_kfunc_id_set *kset)
7452+
u32 *btf_kfunc_is_modify_return(const struct btf *btf, u32 kfunc_btf_id)
7453+
{
7454+
return __btf_kfunc_id_set_contains(btf, BTF_KFUNC_HOOK_FMODRET, kfunc_btf_id);
7455+
}
7456+
7457+
static int __register_btf_kfunc_id_set(enum btf_kfunc_hook hook,
7458+
const struct btf_kfunc_id_set *kset)
74547459
{
7455-
enum btf_kfunc_hook hook;
74567460
struct btf *btf;
74577461
int ret;
74587462

@@ -7471,13 +7475,29 @@ int register_btf_kfunc_id_set(enum bpf_prog_type prog_type,
74717475
if (IS_ERR(btf))
74727476
return PTR_ERR(btf);
74737477

7474-
hook = bpf_prog_type_to_kfunc_hook(prog_type);
74757478
ret = btf_populate_kfunc_set(btf, hook, kset->set);
74767479
btf_put(btf);
74777480
return ret;
74787481
}
7482+
7483+
/* This function must be invoked only from initcalls/module init functions */
7484+
int register_btf_kfunc_id_set(enum bpf_prog_type prog_type,
7485+
const struct btf_kfunc_id_set *kset)
7486+
{
7487+
enum btf_kfunc_hook hook;
7488+
7489+
hook = bpf_prog_type_to_kfunc_hook(prog_type);
7490+
return __register_btf_kfunc_id_set(hook, kset);
7491+
}
74797492
EXPORT_SYMBOL_GPL(register_btf_kfunc_id_set);
74807493

7494+
/* This function must be invoked only from initcalls/module init functions */
7495+
int register_btf_fmodret_id_set(const struct btf_kfunc_id_set *kset)
7496+
{
7497+
return __register_btf_kfunc_id_set(BTF_KFUNC_HOOK_FMODRET, kset);
7498+
}
7499+
EXPORT_SYMBOL_GPL(register_btf_fmodret_id_set);
7500+
74817501
s32 btf_find_dtor_kfunc(struct btf *btf, u32 btf_id)
74827502
{
74837503
struct btf_id_dtor_kfunc_tab *tab = btf->dtor_kfunc_tab;

kernel/bpf/verifier.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15021,12 +15021,22 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
1502115021
ret = -EINVAL;
1502215022
switch (prog->type) {
1502315023
case BPF_PROG_TYPE_TRACING:
15024-
/* fentry/fexit/fmod_ret progs can be sleepable only if they are
15024+
15025+
/* fentry/fexit/fmod_ret progs can be sleepable if they are
1502515026
* attached to ALLOW_ERROR_INJECTION and are not in denylist.
1502615027
*/
1502715028
if (!check_non_sleepable_error_inject(btf_id) &&
1502815029
within_error_injection_list(addr))
1502915030
ret = 0;
15031+
/* fentry/fexit/fmod_ret progs can also be sleepable if they are
15032+
* in the fmodret id set with the KF_SLEEPABLE flag.
15033+
*/
15034+
else {
15035+
u32 *flags = btf_kfunc_is_modify_return(btf, btf_id);
15036+
15037+
if (flags && (*flags & KF_SLEEPABLE))
15038+
ret = 0;
15039+
}
1503015040
break;
1503115041
case BPF_PROG_TYPE_LSM:
1503215042
/* LSM progs check that they are attached to bpf_lsm_*() funcs.
@@ -15047,7 +15057,10 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
1504715057
bpf_log(log, "can't modify return codes of BPF programs\n");
1504815058
return -EINVAL;
1504915059
}
15050-
ret = check_attach_modify_return(addr, tname);
15060+
ret = -EINVAL;
15061+
if (btf_kfunc_is_modify_return(btf, btf_id) ||
15062+
!check_attach_modify_return(addr, tname))
15063+
ret = 0;
1505115064
if (ret) {
1505215065
bpf_log(log, "%s() is not modifiable\n", tname);
1505315066
return ret;

net/bpf/test_run.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,6 @@ int noinline bpf_fentry_test1(int a)
489489
return a + 1;
490490
}
491491
EXPORT_SYMBOL_GPL(bpf_fentry_test1);
492-
ALLOW_ERROR_INJECTION(bpf_fentry_test1, ERRNO);
493492

494493
int noinline bpf_fentry_test2(int a, u64 b)
495494
{
@@ -733,7 +732,15 @@ noinline void bpf_kfunc_call_test_destructive(void)
733732

734733
__diag_pop();
735734

736-
ALLOW_ERROR_INJECTION(bpf_modify_return_test, ERRNO);
735+
BTF_SET8_START(bpf_test_modify_return_ids)
736+
BTF_ID_FLAGS(func, bpf_modify_return_test)
737+
BTF_ID_FLAGS(func, bpf_fentry_test1, KF_SLEEPABLE)
738+
BTF_SET8_END(bpf_test_modify_return_ids)
739+
740+
static const struct btf_kfunc_id_set bpf_test_modify_return_set = {
741+
.owner = THIS_MODULE,
742+
.set = &bpf_test_modify_return_ids,
743+
};
737744

738745
BTF_SET8_START(test_sk_check_kfunc_ids)
739746
BTF_ID_FLAGS(func, bpf_kfunc_call_test1)
@@ -1668,7 +1675,8 @@ static int __init bpf_prog_test_run_init(void)
16681675
};
16691676
int ret;
16701677

1671-
ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS, &bpf_prog_test_kfunc_set);
1678+
ret = register_btf_fmodret_id_set(&bpf_test_modify_return_set);
1679+
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS, &bpf_prog_test_kfunc_set);
16721680
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &bpf_prog_test_kfunc_set);
16731681
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &bpf_prog_test_kfunc_set);
16741682
return ret ?: register_btf_id_dtor_kfuncs(bpf_prog_test_dtor_kfunc,

0 commit comments

Comments
 (0)