Skip to content

Commit 80bb66d

Browse files
theihorKernel Patches Daemon
authored andcommitted
bpf: Support for kfuncs with KF_MAGIC_ARGS
A kernel function bpf_foo with KF_MAGIC_ARGS flag is expected to have two types in BTF: * `bpf_foo` with a function prototype that omits __magic arguments * `bpf_foo_impl` with a function prototype that matches kernel declaration, but doesn't have a ksym associated with its name In order to support magic kfuncs the verifier has to know how to resolve calls both of `bpf_foo` and `bpf_foo_impl` to the correct BTF function prototype and address. In add_kfunc_call() kfunc flags are inspected to detect a magic kfunc or its _impl, and then the address and func_proto are adjusted for the kfunc descriptor. In fetch_kfunc_meta() similar logic is used to fixup the contents of struct bpf_kfunc_call_arg_meta. In check_kfunc_call() reset the subreg_def of registers holding magic arguments to correctly track zero extensions. Signed-off-by: Ihor Solodrai <[email protected]>
1 parent aa32c9e commit 80bb66d

File tree

2 files changed

+120
-4
lines changed

2 files changed

+120
-4
lines changed

include/linux/btf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
#define KF_ARENA_RET (1 << 13) /* kfunc returns an arena pointer */
8080
#define KF_ARENA_ARG1 (1 << 14) /* kfunc takes an arena pointer as its first argument */
8181
#define KF_ARENA_ARG2 (1 << 15) /* kfunc takes an arena pointer as its second argument */
82+
#define KF_MAGIC_ARGS (1 << 16) /* kfunc signature is different from its BPF signature */
8283

8384
/*
8485
* Tag marking a kernel function as a kfunc. This is meant to minimize the

kernel/bpf/verifier.c

Lines changed: 119 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3263,17 +3263,68 @@ static struct btf *find_kfunc_desc_btf(struct bpf_verifier_env *env, s16 offset)
32633263
return btf_vmlinux ?: ERR_PTR(-ENOENT);
32643264
}
32653265

3266+
/*
3267+
* magic_kfuncs is used as a list of (foo, foo_impl) pairs
3268+
*/
3269+
BTF_ID_LIST(magic_kfuncs)
3270+
BTF_ID_UNUSED
3271+
BTF_ID_LIST_END(magic_kfuncs)
3272+
3273+
static s32 magic_kfunc_by_impl(s32 impl_func_id)
3274+
{
3275+
int i;
3276+
3277+
for (i = 1; i < BTF_ID_LIST_SIZE(magic_kfuncs); i += 2) {
3278+
if (magic_kfuncs[i] == impl_func_id)
3279+
return magic_kfuncs[i - 1];
3280+
}
3281+
return -ENOENT;
3282+
}
3283+
3284+
static s32 impl_by_magic_kfunc(s32 func_id)
3285+
{
3286+
int i;
3287+
3288+
for (i = 0; i < BTF_ID_LIST_SIZE(magic_kfuncs); i += 2) {
3289+
if (magic_kfuncs[i] == func_id)
3290+
return magic_kfuncs[i + 1];
3291+
}
3292+
return -ENOENT;
3293+
}
3294+
3295+
static const struct btf_type *find_magic_kfunc_proto(struct btf *desc_btf, s32 func_id)
3296+
{
3297+
const struct btf_type *impl_func, *func_proto;
3298+
u32 impl_func_id;
3299+
3300+
impl_func_id = impl_by_magic_kfunc(func_id);
3301+
if (impl_func_id < 0)
3302+
return NULL;
3303+
3304+
impl_func = btf_type_by_id(desc_btf, impl_func_id);
3305+
if (!impl_func || !btf_type_is_func(impl_func))
3306+
return NULL;
3307+
3308+
func_proto = btf_type_by_id(desc_btf, impl_func->type);
3309+
if (!func_proto || !btf_type_is_func_proto(func_proto))
3310+
return NULL;
3311+
3312+
return func_proto;
3313+
}
3314+
32663315
static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 offset)
32673316
{
3268-
const struct btf_type *func, *func_proto;
3317+
const struct btf_type *func, *func_proto, *tmp_func;
32693318
struct bpf_kfunc_btf_tab *btf_tab;
3319+
const char *func_name, *tmp_name;
32703320
struct btf_func_model func_model;
32713321
struct bpf_kfunc_desc_tab *tab;
32723322
struct bpf_prog_aux *prog_aux;
32733323
struct bpf_kfunc_desc *desc;
3274-
const char *func_name;
32753324
struct btf *desc_btf;
32763325
unsigned long addr;
3326+
u32 *kfunc_flags;
3327+
s32 tmp_func_id;
32773328
int err;
32783329

32793330
prog_aux = env->prog->aux;
@@ -3349,8 +3400,37 @@ static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 offset)
33493400
return -EINVAL;
33503401
}
33513402

3403+
kfunc_flags = btf_kfunc_flags(desc_btf, func_id, env->prog);
33523404
func_name = btf_name_by_offset(desc_btf, func->name_off);
33533405
addr = kallsyms_lookup_name(func_name);
3406+
3407+
/* This may be an _impl kfunc with KF_MAGIC_ARGS counterpart */
3408+
if (unlikely(!addr && !kfunc_flags)) {
3409+
tmp_func_id = magic_kfunc_by_impl(func_id);
3410+
if (tmp_func_id < 0)
3411+
return -EACCES;
3412+
tmp_func = btf_type_by_id(desc_btf, tmp_func_id);
3413+
if (!tmp_func || !btf_type_is_func(tmp_func))
3414+
return -EACCES;
3415+
tmp_name = btf_name_by_offset(desc_btf, tmp_func->name_off);
3416+
addr = kallsyms_lookup_name(tmp_name);
3417+
}
3418+
3419+
/*
3420+
* Note that kfunc_flags may be NULL at this point, which means that we couldn't find
3421+
* func_id in any relevant kfunc_id_set. This most likely indicates an invalid kfunc call.
3422+
* However we don't want to fail the verification here, because invalid calls may be
3423+
* eliminated as dead code later.
3424+
*/
3425+
if (unlikely(kfunc_flags && KF_MAGIC_ARGS & *kfunc_flags)) {
3426+
func_proto = find_magic_kfunc_proto(desc_btf, func_id);
3427+
if (!func_proto) {
3428+
verbose(env, "cannot find _impl proto for kernel function %s\n",
3429+
func_name);
3430+
return -EINVAL;
3431+
}
3432+
}
3433+
33543434
if (!addr) {
33553435
verbose(env, "cannot find address for kernel function %s\n",
33563436
func_name);
@@ -12051,6 +12131,11 @@ static bool is_kfunc_arg_irq_flag(const struct btf *btf, const struct btf_param
1205112131
return btf_param_match_suffix(btf, arg, "__irq_flag");
1205212132
}
1205312133

12134+
static bool is_kfunc_arg_magic(const struct btf *btf, const struct btf_param *arg)
12135+
{
12136+
return btf_param_match_suffix(btf, arg, "__magic");
12137+
}
12138+
1205412139
static bool is_kfunc_arg_prog(const struct btf *btf, const struct btf_param *arg)
1205512140
{
1205612141
return btf_param_match_suffix(btf, arg, "__prog");
@@ -13613,6 +13698,7 @@ static int fetch_kfunc_meta(struct bpf_verifier_env *env,
1361313698
u32 func_id, *kfunc_flags;
1361413699
const char *func_name;
1361513700
struct btf *desc_btf;
13701+
s32 tmp_func_id;
1361613702

1361713703
if (kfunc_name)
1361813704
*kfunc_name = NULL;
@@ -13632,10 +13718,28 @@ static int fetch_kfunc_meta(struct bpf_verifier_env *env,
1363213718
func_proto = btf_type_by_id(desc_btf, func->type);
1363313719

1363413720
kfunc_flags = btf_kfunc_flags_if_allowed(desc_btf, func_id, env->prog);
13635-
if (!kfunc_flags) {
13636-
return -EACCES;
13721+
if (unlikely(!kfunc_flags)) {
13722+
/*
13723+
* An _impl kfunc with KF_MAGIC_ARGS counterpart
13724+
* does not have its own kfunc flags.
13725+
*/
13726+
tmp_func_id = magic_kfunc_by_impl(func_id);
13727+
if (tmp_func_id < 0)
13728+
return -EACCES;
13729+
kfunc_flags = btf_kfunc_flags_if_allowed(desc_btf, tmp_func_id, env->prog);
13730+
if (!kfunc_flags)
13731+
return -EACCES;
13732+
} else if (unlikely(KF_MAGIC_ARGS & *kfunc_flags)) {
13733+
/*
13734+
* An actual func_proto of a kfunc with KF_MAGIC_ARGS flag
13735+
* can be found through the corresponding _impl kfunc.
13736+
*/
13737+
func_proto = find_magic_kfunc_proto(desc_btf, func_id);
1363713738
}
1363813739

13740+
if (!func_proto)
13741+
return -EACCES;
13742+
1363913743
memset(meta, 0, sizeof(*meta));
1364013744
meta->btf = desc_btf;
1364113745
meta->func_id = func_id;
@@ -14189,6 +14293,17 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
1418914293
for (i = 0; i < nargs; i++) {
1419014294
u32 regno = i + 1;
1419114295

14296+
/*
14297+
* Magic arguments are set after main verification pass.
14298+
* For correct tracking of zero-extensions we have to reset subreg_def for such
14299+
* args. Otherwise mark_btf_func_reg_size() will be inspecting subreg_def of regs
14300+
* from an earlier (irrelevant) point in the program, which may lead to an error
14301+
* in opt_subreg_zext_lo32_rnd_hi32().
14302+
*/
14303+
if (unlikely(KF_MAGIC_ARGS & meta.kfunc_flags
14304+
&& is_kfunc_arg_magic(desc_btf, &args[i])))
14305+
regs[regno].subreg_def = DEF_NOT_SUBREG;
14306+
1419214307
t = btf_type_skip_modifiers(desc_btf, args[i].type, NULL);
1419314308
if (btf_type_is_ptr(t))
1419414309
mark_btf_func_reg_size(env, regno, sizeof(void *));

0 commit comments

Comments
 (0)