Skip to content

Commit d370bbe

Browse files
haoluo1022Alexei Starovoitov
authored andcommitted
bpf/libbpf: BTF support for typed ksyms
If a ksym is defined with a type, libbpf will try to find the ksym's btf information from kernel btf. If a valid btf entry for the ksym is found, libbpf can pass in the found btf id to the verifier, which validates the ksym's type and value. Typeless ksyms (i.e. those defined as 'void') will not have such btf_id, but it has the symbol's address (read from kallsyms) and its value is treated as a raw pointer. Signed-off-by: Hao Luo <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Acked-by: Andrii Nakryiko <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 4976b71 commit d370bbe

File tree

1 file changed

+99
-13
lines changed

1 file changed

+99
-13
lines changed

tools/lib/bpf/libbpf.c

Lines changed: 99 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,12 @@ struct extern_desc {
390390
} kcfg;
391391
struct {
392392
unsigned long long addr;
393+
394+
/* target btf_id of the corresponding kernel var. */
395+
int vmlinux_btf_id;
396+
397+
/* local btf_id of the ksym extern's type. */
398+
__u32 type_id;
393399
} ksym;
394400
};
395401
};
@@ -2522,12 +2528,23 @@ static int bpf_object__load_vmlinux_btf(struct bpf_object *obj)
25222528
{
25232529
bool need_vmlinux_btf = false;
25242530
struct bpf_program *prog;
2525-
int err;
2531+
int i, err;
25262532

25272533
/* CO-RE relocations need kernel BTF */
25282534
if (obj->btf_ext && obj->btf_ext->core_relo_info.len)
25292535
need_vmlinux_btf = true;
25302536

2537+
/* Support for typed ksyms needs kernel BTF */
2538+
for (i = 0; i < obj->nr_extern; i++) {
2539+
const struct extern_desc *ext;
2540+
2541+
ext = &obj->externs[i];
2542+
if (ext->type == EXT_KSYM && ext->ksym.type_id) {
2543+
need_vmlinux_btf = true;
2544+
break;
2545+
}
2546+
}
2547+
25312548
bpf_object__for_each_program(prog, obj) {
25322549
if (!prog->load)
25332550
continue;
@@ -3156,16 +3173,10 @@ static int bpf_object__collect_externs(struct bpf_object *obj)
31563173
return -ENOTSUP;
31573174
}
31583175
} else if (strcmp(sec_name, KSYMS_SEC) == 0) {
3159-
const struct btf_type *vt;
3160-
31613176
ksym_sec = sec;
31623177
ext->type = EXT_KSYM;
3163-
3164-
vt = skip_mods_and_typedefs(obj->btf, t->type, NULL);
3165-
if (!btf_is_void(vt)) {
3166-
pr_warn("extern (ksym) '%s' is not typeless (void)\n", ext_name);
3167-
return -ENOTSUP;
3168-
}
3178+
skip_mods_and_typedefs(obj->btf, t->type,
3179+
&ext->ksym.type_id);
31693180
} else {
31703181
pr_warn("unrecognized extern section '%s'\n", sec_name);
31713182
return -ENOTSUP;
@@ -5800,8 +5811,13 @@ bpf_object__relocate_data(struct bpf_object *obj, struct bpf_program *prog)
58005811
insn[0].imm = obj->maps[obj->kconfig_map_idx].fd;
58015812
insn[1].imm = ext->kcfg.data_off;
58025813
} else /* EXT_KSYM */ {
5803-
insn[0].imm = (__u32)ext->ksym.addr;
5804-
insn[1].imm = ext->ksym.addr >> 32;
5814+
if (ext->ksym.type_id) { /* typed ksyms */
5815+
insn[0].src_reg = BPF_PSEUDO_BTF_ID;
5816+
insn[0].imm = ext->ksym.vmlinux_btf_id;
5817+
} else { /* typeless ksyms */
5818+
insn[0].imm = (__u32)ext->ksym.addr;
5819+
insn[1].imm = ext->ksym.addr >> 32;
5820+
}
58055821
}
58065822
relo->processed = true;
58075823
break;
@@ -6933,10 +6949,72 @@ static int bpf_object__read_kallsyms_file(struct bpf_object *obj)
69336949
return err;
69346950
}
69356951

6952+
static int bpf_object__resolve_ksyms_btf_id(struct bpf_object *obj)
6953+
{
6954+
struct extern_desc *ext;
6955+
int i, id;
6956+
6957+
for (i = 0; i < obj->nr_extern; i++) {
6958+
const struct btf_type *targ_var, *targ_type;
6959+
__u32 targ_type_id, local_type_id;
6960+
const char *targ_var_name;
6961+
int ret;
6962+
6963+
ext = &obj->externs[i];
6964+
if (ext->type != EXT_KSYM || !ext->ksym.type_id)
6965+
continue;
6966+
6967+
id = btf__find_by_name_kind(obj->btf_vmlinux, ext->name,
6968+
BTF_KIND_VAR);
6969+
if (id <= 0) {
6970+
pr_warn("extern (ksym) '%s': failed to find BTF ID in vmlinux BTF.\n",
6971+
ext->name);
6972+
return -ESRCH;
6973+
}
6974+
6975+
/* find local type_id */
6976+
local_type_id = ext->ksym.type_id;
6977+
6978+
/* find target type_id */
6979+
targ_var = btf__type_by_id(obj->btf_vmlinux, id);
6980+
targ_var_name = btf__name_by_offset(obj->btf_vmlinux,
6981+
targ_var->name_off);
6982+
targ_type = skip_mods_and_typedefs(obj->btf_vmlinux,
6983+
targ_var->type,
6984+
&targ_type_id);
6985+
6986+
ret = bpf_core_types_are_compat(obj->btf, local_type_id,
6987+
obj->btf_vmlinux, targ_type_id);
6988+
if (ret <= 0) {
6989+
const struct btf_type *local_type;
6990+
const char *targ_name, *local_name;
6991+
6992+
local_type = btf__type_by_id(obj->btf, local_type_id);
6993+
local_name = btf__name_by_offset(obj->btf,
6994+
local_type->name_off);
6995+
targ_name = btf__name_by_offset(obj->btf_vmlinux,
6996+
targ_type->name_off);
6997+
6998+
pr_warn("extern (ksym) '%s': incompatible types, expected [%d] %s %s, but kernel has [%d] %s %s\n",
6999+
ext->name, local_type_id,
7000+
btf_kind_str(local_type), local_name, targ_type_id,
7001+
btf_kind_str(targ_type), targ_name);
7002+
return -EINVAL;
7003+
}
7004+
7005+
ext->is_set = true;
7006+
ext->ksym.vmlinux_btf_id = id;
7007+
pr_debug("extern (ksym) '%s': resolved to [%d] %s %s\n",
7008+
ext->name, id, btf_kind_str(targ_var), targ_var_name);
7009+
}
7010+
return 0;
7011+
}
7012+
69367013
static int bpf_object__resolve_externs(struct bpf_object *obj,
69377014
const char *extra_kconfig)
69387015
{
69397016
bool need_config = false, need_kallsyms = false;
7017+
bool need_vmlinux_btf = false;
69407018
struct extern_desc *ext;
69417019
void *kcfg_data = NULL;
69427020
int err, i;
@@ -6967,7 +7045,10 @@ static int bpf_object__resolve_externs(struct bpf_object *obj,
69677045
strncmp(ext->name, "CONFIG_", 7) == 0) {
69687046
need_config = true;
69697047
} else if (ext->type == EXT_KSYM) {
6970-
need_kallsyms = true;
7048+
if (ext->ksym.type_id)
7049+
need_vmlinux_btf = true;
7050+
else
7051+
need_kallsyms = true;
69717052
} else {
69727053
pr_warn("unrecognized extern '%s'\n", ext->name);
69737054
return -EINVAL;
@@ -6996,6 +7077,11 @@ static int bpf_object__resolve_externs(struct bpf_object *obj,
69967077
if (err)
69977078
return -EINVAL;
69987079
}
7080+
if (need_vmlinux_btf) {
7081+
err = bpf_object__resolve_ksyms_btf_id(obj);
7082+
if (err)
7083+
return -EINVAL;
7084+
}
69997085
for (i = 0; i < obj->nr_extern; i++) {
70007086
ext = &obj->externs[i];
70017087

@@ -7028,10 +7114,10 @@ int bpf_object__load_xattr(struct bpf_object_load_attr *attr)
70287114
}
70297115

70307116
err = bpf_object__probe_loading(obj);
7117+
err = err ? : bpf_object__load_vmlinux_btf(obj);
70317118
err = err ? : bpf_object__resolve_externs(obj, obj->kconfig);
70327119
err = err ? : bpf_object__sanitize_and_load_btf(obj);
70337120
err = err ? : bpf_object__sanitize_maps(obj);
7034-
err = err ? : bpf_object__load_vmlinux_btf(obj);
70357121
err = err ? : bpf_object__init_kern_struct_ops_maps(obj);
70367122
err = err ? : bpf_object__create_maps(obj);
70377123
err = err ? : bpf_object__relocate(obj, attr->target_btf_path);

0 commit comments

Comments
 (0)