Skip to content

Commit

Permalink
libbpf: Add enum64 sanitization
Browse files Browse the repository at this point in the history
When old kernel does not support enum64 but user space btf
contains non-zero enum kflag or enum64, libbpf needs to
do proper sanitization so modified btf can be accepted
by the kernel.

Sanitization for enum kflag can be achieved by clearing
the kflag bit. For enum64, the type is replaced with an
union of integer member types and the integer member size
must be smaller than enum64 size. If such an integer
type cannot be found, a new type is created and used
for union members.

Acked-by: Andrii Nakryiko <[email protected]>
Signed-off-by: Yonghong Song <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Alexei Starovoitov <[email protected]>
  • Loading branch information
yonghong-song authored and Alexei Starovoitov committed Jun 7, 2022
1 parent d90ec26 commit f2a6258
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 5 deletions.
3 changes: 2 additions & 1 deletion tools/lib/bpf/btf.h
Original file line number Diff line number Diff line change
Expand Up @@ -395,9 +395,10 @@ btf_dump__dump_type_data(struct btf_dump *d, __u32 id,
#ifndef BTF_KIND_FLOAT
#define BTF_KIND_FLOAT 16 /* Floating point */
#endif
/* The kernel header switched to enums, so these two were never #defined */
/* The kernel header switched to enums, so the following were never #defined */
#define BTF_KIND_DECL_TAG 17 /* Decl Tag */
#define BTF_KIND_TYPE_TAG 18 /* Type Tag */
#define BTF_KIND_ENUM64 19 /* Enum for up-to 64bit values */

static inline __u16 btf_kind(const struct btf_type *t)
{
Expand Down
56 changes: 52 additions & 4 deletions tools/lib/bpf/libbpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -2242,6 +2242,7 @@ static const char *__btf_kind_str(__u16 kind)
case BTF_KIND_FLOAT: return "float";
case BTF_KIND_DECL_TAG: return "decl_tag";
case BTF_KIND_TYPE_TAG: return "type_tag";
case BTF_KIND_ENUM64: return "enum64";
default: return "unknown";
}
}
Expand Down Expand Up @@ -2770,19 +2771,22 @@ static bool btf_needs_sanitization(struct bpf_object *obj)
bool has_func = kernel_supports(obj, FEAT_BTF_FUNC);
bool has_decl_tag = kernel_supports(obj, FEAT_BTF_DECL_TAG);
bool has_type_tag = kernel_supports(obj, FEAT_BTF_TYPE_TAG);
bool has_enum64 = kernel_supports(obj, FEAT_BTF_ENUM64);

return !has_func || !has_datasec || !has_func_global || !has_float ||
!has_decl_tag || !has_type_tag;
!has_decl_tag || !has_type_tag || !has_enum64;
}

static void bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *btf)
static int bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *btf)
{
bool has_func_global = kernel_supports(obj, FEAT_BTF_GLOBAL_FUNC);
bool has_datasec = kernel_supports(obj, FEAT_BTF_DATASEC);
bool has_float = kernel_supports(obj, FEAT_BTF_FLOAT);
bool has_func = kernel_supports(obj, FEAT_BTF_FUNC);
bool has_decl_tag = kernel_supports(obj, FEAT_BTF_DECL_TAG);
bool has_type_tag = kernel_supports(obj, FEAT_BTF_TYPE_TAG);
bool has_enum64 = kernel_supports(obj, FEAT_BTF_ENUM64);
__u32 enum64_placeholder_id = 0;
struct btf_type *t;
int i, j, vlen;

Expand Down Expand Up @@ -2845,8 +2849,32 @@ static void bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *btf)
/* replace TYPE_TAG with a CONST */
t->name_off = 0;
t->info = BTF_INFO_ENC(BTF_KIND_CONST, 0, 0);
}
} else if (!has_enum64 && btf_is_enum(t)) {
/* clear the kflag */
t->info = btf_type_info(btf_kind(t), btf_vlen(t), false);
} else if (!has_enum64 && btf_is_enum64(t)) {
/* replace ENUM64 with a union */
struct btf_member *m;

if (enum64_placeholder_id == 0) {
enum64_placeholder_id = btf__add_int(btf, "enum64_placeholder", 1, 0);
if (enum64_placeholder_id < 0)
return enum64_placeholder_id;

t = (struct btf_type *)btf__type_by_id(btf, i);
}

m = btf_members(t);
vlen = btf_vlen(t);
t->info = BTF_INFO_ENC(BTF_KIND_UNION, 0, vlen);
for (j = 0; j < vlen; j++, m++) {
m->type = enum64_placeholder_id;
m->offset = 0;
}
}
}

return 0;
}

static bool libbpf_needs_btf(const struct bpf_object *obj)
Expand Down Expand Up @@ -3184,7 +3212,9 @@ static int bpf_object__sanitize_and_load_btf(struct bpf_object *obj)

/* enforce 8-byte pointers for BPF-targeted BTFs */
btf__set_pointer_size(obj->btf, 8);
bpf_object__sanitize_btf(obj, kern_btf);
err = bpf_object__sanitize_btf(obj, kern_btf);
if (err)
return err;
}

if (obj->gen_loader) {
Expand Down Expand Up @@ -3691,6 +3721,10 @@ static enum kcfg_type find_kcfg_type(const struct btf *btf, int id,
if (strcmp(name, "libbpf_tristate"))
return KCFG_UNKNOWN;
return KCFG_TRISTATE;
case BTF_KIND_ENUM64:
if (strcmp(name, "libbpf_tristate"))
return KCFG_UNKNOWN;
return KCFG_TRISTATE;
case BTF_KIND_ARRAY:
if (btf_array(t)->nelems == 0)
return KCFG_UNKNOWN;
Expand Down Expand Up @@ -4874,6 +4908,17 @@ static int probe_kern_bpf_cookie(void)
return probe_fd(ret);
}

static int probe_kern_btf_enum64(void)
{
static const char strs[] = "\0enum64";
__u32 types[] = {
BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 0), 8),
};

return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
strs, sizeof(strs)));
}

enum kern_feature_result {
FEAT_UNKNOWN = 0,
FEAT_SUPPORTED = 1,
Expand Down Expand Up @@ -4939,6 +4984,9 @@ static struct kern_feature_desc {
[FEAT_BPF_COOKIE] = {
"BPF cookie support", probe_kern_bpf_cookie,
},
[FEAT_BTF_ENUM64] = {
"BTF_KIND_ENUM64 support", probe_kern_btf_enum64,
},
};

bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id)
Expand Down
2 changes: 2 additions & 0 deletions tools/lib/bpf/libbpf_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,8 @@ enum kern_feature_id {
FEAT_MEMCG_ACCOUNT,
/* BPF cookie (bpf_get_attach_cookie() BPF helper) support */
FEAT_BPF_COOKIE,
/* BTF_KIND_ENUM64 support and BTF_KIND_ENUM kflag support */
FEAT_BTF_ENUM64,
__FEAT_CNT,
};

Expand Down

0 comments on commit f2a6258

Please sign in to comment.