Skip to content

Commit 6cae5a7

Browse files
committed
Merge branch 'bpf: Add detection of kfuncs.'
Alexei Starovoitov says: ==================== From: Alexei Starovoitov <[email protected]> Allow BPF programs detect at load time whether particular kfunc exists. Patch 1: Allow ld_imm64 to point to kfunc in the kernel. Patch 2: Fix relocation of kfunc in ld_imm64 insn when kfunc is in kernel module. Patch 3: Introduce bpf_ksym_exists() macro. Patch 4: selftest. NOTE: detection of kfuncs from light skeleton is not supported yet. ==================== Signed-off-by: Andrii Nakryiko <[email protected]>
2 parents 0f10f64 + 95fdf6e commit 6cae5a7

File tree

4 files changed

+41
-7
lines changed

4 files changed

+41
-7
lines changed

kernel/bpf/verifier.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15952,8 +15952,8 @@ static int check_pseudo_btf_id(struct bpf_verifier_env *env,
1595215952
goto err_put;
1595315953
}
1595415954

15955-
if (!btf_type_is_var(t)) {
15956-
verbose(env, "pseudo btf_id %d in ldimm64 isn't KIND_VAR.\n", id);
15955+
if (!btf_type_is_var(t) && !btf_type_is_func(t)) {
15956+
verbose(env, "pseudo btf_id %d in ldimm64 isn't KIND_VAR or KIND_FUNC\n", id);
1595715957
err = -EINVAL;
1595815958
goto err_put;
1595915959
}
@@ -15966,6 +15966,14 @@ static int check_pseudo_btf_id(struct bpf_verifier_env *env,
1596615966
err = -ENOENT;
1596715967
goto err_put;
1596815968
}
15969+
insn[0].imm = (u32)addr;
15970+
insn[1].imm = addr >> 32;
15971+
15972+
if (btf_type_is_func(t)) {
15973+
aux->btf_var.reg_type = PTR_TO_MEM | MEM_RDONLY;
15974+
aux->btf_var.mem_size = 0;
15975+
goto check_btf;
15976+
}
1596915977

1597015978
datasec_id = find_btf_percpu_datasec(btf);
1597115979
if (datasec_id > 0) {
@@ -15978,9 +15986,6 @@ static int check_pseudo_btf_id(struct bpf_verifier_env *env,
1597815986
}
1597915987
}
1598015988

15981-
insn[0].imm = (u32)addr;
15982-
insn[1].imm = addr >> 32;
15983-
1598415989
type = t->type;
1598515990
t = btf_type_skip_modifiers(btf, type, NULL);
1598615991
if (percpu) {
@@ -16008,7 +16013,7 @@ static int check_pseudo_btf_id(struct bpf_verifier_env *env,
1600816013
aux->btf_var.btf = btf;
1600916014
aux->btf_var.btf_id = type;
1601016015
}
16011-
16016+
check_btf:
1601216017
/* check whether we recorded this BTF (and maybe module) already */
1601316018
for (i = 0; i < env->used_btf_cnt; i++) {
1601416019
if (env->used_btfs[i].btf == btf) {

tools/lib/bpf/bpf_helpers.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,11 @@ enum libbpf_tristate {
177177
#define __kptr_untrusted __attribute__((btf_type_tag("kptr_untrusted")))
178178
#define __kptr __attribute__((btf_type_tag("kptr")))
179179

180+
#define bpf_ksym_exists(sym) ({ \
181+
_Static_assert(!__builtin_constant_p(!!sym), #sym " should be marked as __weak"); \
182+
!!sym; \
183+
})
184+
180185
#ifndef ___bpf_concat
181186
#define ___bpf_concat(a, b) a ## b
182187
#endif

tools/lib/bpf/libbpf.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7533,6 +7533,12 @@ static int bpf_object__resolve_ksym_func_btf_id(struct bpf_object *obj,
75337533
ext->is_set = true;
75347534
ext->ksym.kernel_btf_id = kfunc_id;
75357535
ext->ksym.btf_fd_idx = mod_btf ? mod_btf->fd_array_idx : 0;
7536+
/* Also set kernel_btf_obj_fd to make sure that bpf_object__relocate_data()
7537+
* populates FD into ld_imm64 insn when it's used to point to kfunc.
7538+
* {kernel_btf_id, btf_fd_idx} -> fixup bpf_call.
7539+
* {kernel_btf_id, kernel_btf_obj_fd} -> fixup ld_imm64.
7540+
*/
7541+
ext->ksym.kernel_btf_obj_fd = mod_btf ? mod_btf->fd : 0;
75367542
pr_debug("extern (func ksym) '%s': resolved to kernel [%d]\n",
75377543
ext->name, kfunc_id);
75387544

tools/testing/selftests/bpf/progs/task_kfunc_success.c

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ int err, pid;
1717
* TP_PROTO(struct task_struct *p, u64 clone_flags)
1818
*/
1919

20+
struct task_struct *bpf_task_acquire(struct task_struct *p) __ksym __weak;
21+
void invalid_kfunc(void) __ksym __weak;
22+
void bpf_testmod_test_mod_kfunc(int i) __ksym __weak;
23+
2024
static bool is_test_kfunc_task(void)
2125
{
2226
int cur_pid = bpf_get_current_pid_tgid() >> 32;
@@ -26,7 +30,21 @@ static bool is_test_kfunc_task(void)
2630

2731
static int test_acquire_release(struct task_struct *task)
2832
{
29-
struct task_struct *acquired;
33+
struct task_struct *acquired = NULL;
34+
35+
if (!bpf_ksym_exists(bpf_task_acquire)) {
36+
err = 3;
37+
return 0;
38+
}
39+
if (!bpf_ksym_exists(bpf_testmod_test_mod_kfunc)) {
40+
err = 4;
41+
return 0;
42+
}
43+
if (bpf_ksym_exists(invalid_kfunc)) {
44+
/* the verifier's dead code elimination should remove this */
45+
err = 5;
46+
asm volatile ("goto -1"); /* for (;;); */
47+
}
3048

3149
acquired = bpf_task_acquire(task);
3250
bpf_task_release(acquired);

0 commit comments

Comments
 (0)