Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <haoluo@google.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Andrii Nakryiko <andriin@fb.com>
Link: https://lore.kernel.org/bpf/20200929235049.2533242-3-haoluo@google.com

authored by

Hao Luo and committed by
Alexei Starovoitov
d370bbe1 4976b718

+99 -13
+99 -13
tools/lib/bpf/libbpf.c
··· 390 390 } kcfg; 391 391 struct { 392 392 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; 393 399 } ksym; 394 400 }; 395 401 }; ··· 2528 2522 { 2529 2523 bool need_vmlinux_btf = false; 2530 2524 struct bpf_program *prog; 2531 - int err; 2525 + int i, err; 2532 2526 2533 2527 /* CO-RE relocations need kernel BTF */ 2534 2528 if (obj->btf_ext && obj->btf_ext->core_relo_info.len) 2535 2529 need_vmlinux_btf = true; 2530 + 2531 + /* Support for typed ksyms needs kernel BTF */ 2532 + for (i = 0; i < obj->nr_extern; i++) { 2533 + const struct extern_desc *ext; 2534 + 2535 + ext = &obj->externs[i]; 2536 + if (ext->type == EXT_KSYM && ext->ksym.type_id) { 2537 + need_vmlinux_btf = true; 2538 + break; 2539 + } 2540 + } 2536 2541 2537 2542 bpf_object__for_each_program(prog, obj) { 2538 2543 if (!prog->load) ··· 3173 3156 return -ENOTSUP; 3174 3157 } 3175 3158 } else if (strcmp(sec_name, KSYMS_SEC) == 0) { 3176 - const struct btf_type *vt; 3177 - 3178 3159 ksym_sec = sec; 3179 3160 ext->type = EXT_KSYM; 3180 - 3181 - vt = skip_mods_and_typedefs(obj->btf, t->type, NULL); 3182 - if (!btf_is_void(vt)) { 3183 - pr_warn("extern (ksym) '%s' is not typeless (void)\n", ext_name); 3184 - return -ENOTSUP; 3185 - } 3161 + skip_mods_and_typedefs(obj->btf, t->type, 3162 + &ext->ksym.type_id); 3186 3163 } else { 3187 3164 pr_warn("unrecognized extern section '%s'\n", sec_name); 3188 3165 return -ENOTSUP; ··· 5811 5800 insn[0].imm = obj->maps[obj->kconfig_map_idx].fd; 5812 5801 insn[1].imm = ext->kcfg.data_off; 5813 5802 } else /* EXT_KSYM */ { 5814 - insn[0].imm = (__u32)ext->ksym.addr; 5815 - insn[1].imm = ext->ksym.addr >> 32; 5803 + if (ext->ksym.type_id) { /* typed ksyms */ 5804 + insn[0].src_reg = BPF_PSEUDO_BTF_ID; 5805 + insn[0].imm = ext->ksym.vmlinux_btf_id; 5806 + } else { /* typeless ksyms */ 5807 + insn[0].imm = (__u32)ext->ksym.addr; 5808 + insn[1].imm = ext->ksym.addr >> 32; 5809 + } 5816 5810 } 5817 5811 relo->processed = true; 5818 5812 break; ··· 6949 6933 return err; 6950 6934 } 6951 6935 6936 + static int bpf_object__resolve_ksyms_btf_id(struct bpf_object *obj) 6937 + { 6938 + struct extern_desc *ext; 6939 + int i, id; 6940 + 6941 + for (i = 0; i < obj->nr_extern; i++) { 6942 + const struct btf_type *targ_var, *targ_type; 6943 + __u32 targ_type_id, local_type_id; 6944 + const char *targ_var_name; 6945 + int ret; 6946 + 6947 + ext = &obj->externs[i]; 6948 + if (ext->type != EXT_KSYM || !ext->ksym.type_id) 6949 + continue; 6950 + 6951 + id = btf__find_by_name_kind(obj->btf_vmlinux, ext->name, 6952 + BTF_KIND_VAR); 6953 + if (id <= 0) { 6954 + pr_warn("extern (ksym) '%s': failed to find BTF ID in vmlinux BTF.\n", 6955 + ext->name); 6956 + return -ESRCH; 6957 + } 6958 + 6959 + /* find local type_id */ 6960 + local_type_id = ext->ksym.type_id; 6961 + 6962 + /* find target type_id */ 6963 + targ_var = btf__type_by_id(obj->btf_vmlinux, id); 6964 + targ_var_name = btf__name_by_offset(obj->btf_vmlinux, 6965 + targ_var->name_off); 6966 + targ_type = skip_mods_and_typedefs(obj->btf_vmlinux, 6967 + targ_var->type, 6968 + &targ_type_id); 6969 + 6970 + ret = bpf_core_types_are_compat(obj->btf, local_type_id, 6971 + obj->btf_vmlinux, targ_type_id); 6972 + if (ret <= 0) { 6973 + const struct btf_type *local_type; 6974 + const char *targ_name, *local_name; 6975 + 6976 + local_type = btf__type_by_id(obj->btf, local_type_id); 6977 + local_name = btf__name_by_offset(obj->btf, 6978 + local_type->name_off); 6979 + targ_name = btf__name_by_offset(obj->btf_vmlinux, 6980 + targ_type->name_off); 6981 + 6982 + pr_warn("extern (ksym) '%s': incompatible types, expected [%d] %s %s, but kernel has [%d] %s %s\n", 6983 + ext->name, local_type_id, 6984 + btf_kind_str(local_type), local_name, targ_type_id, 6985 + btf_kind_str(targ_type), targ_name); 6986 + return -EINVAL; 6987 + } 6988 + 6989 + ext->is_set = true; 6990 + ext->ksym.vmlinux_btf_id = id; 6991 + pr_debug("extern (ksym) '%s': resolved to [%d] %s %s\n", 6992 + ext->name, id, btf_kind_str(targ_var), targ_var_name); 6993 + } 6994 + return 0; 6995 + } 6996 + 6952 6997 static int bpf_object__resolve_externs(struct bpf_object *obj, 6953 6998 const char *extra_kconfig) 6954 6999 { 6955 7000 bool need_config = false, need_kallsyms = false; 7001 + bool need_vmlinux_btf = false; 6956 7002 struct extern_desc *ext; 6957 7003 void *kcfg_data = NULL; 6958 7004 int err, i; ··· 7045 6967 strncmp(ext->name, "CONFIG_", 7) == 0) { 7046 6968 need_config = true; 7047 6969 } else if (ext->type == EXT_KSYM) { 7048 - need_kallsyms = true; 6970 + if (ext->ksym.type_id) 6971 + need_vmlinux_btf = true; 6972 + else 6973 + need_kallsyms = true; 7049 6974 } else { 7050 6975 pr_warn("unrecognized extern '%s'\n", ext->name); 7051 6976 return -EINVAL; ··· 7074 6993 } 7075 6994 if (need_kallsyms) { 7076 6995 err = bpf_object__read_kallsyms_file(obj); 6996 + if (err) 6997 + return -EINVAL; 6998 + } 6999 + if (need_vmlinux_btf) { 7000 + err = bpf_object__resolve_ksyms_btf_id(obj); 7077 7001 if (err) 7078 7002 return -EINVAL; 7079 7003 } ··· 7114 7028 } 7115 7029 7116 7030 err = bpf_object__probe_loading(obj); 7031 + err = err ? : bpf_object__load_vmlinux_btf(obj); 7117 7032 err = err ? : bpf_object__resolve_externs(obj, obj->kconfig); 7118 7033 err = err ? : bpf_object__sanitize_and_load_btf(obj); 7119 7034 err = err ? : bpf_object__sanitize_maps(obj); 7120 - err = err ? : bpf_object__load_vmlinux_btf(obj); 7121 7035 err = err ? : bpf_object__init_kern_struct_ops_maps(obj); 7122 7036 err = err ? : bpf_object__create_maps(obj); 7123 7037 err = err ? : bpf_object__relocate(obj, attr->target_btf_path);