mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
libbpf: Support sanitization of BTF layout for older kernels
Add a FEAT_BTF_LAYOUT feature check which checks if the kernel supports BTF layout information. Also sanitize BTF if it contains layout data but the kernel does not support it. The sanitization requires rewriting raw BTF data to update the header and eliminate the layout section (since it lies between the types and strings), so refactor sanitization to do the raw BTF retrieval and creation of updated BTF, returning that new BTF on success. Signed-off-by: Alan Maguire <alan.maguire@oracle.com> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Link: https://lore.kernel.org/bpf/20260326145444.2076244-7-alan.maguire@oracle.com
This commit is contained in:
committed by
Andrii Nakryiko
parent
6ad8928599
commit
081677d03d
@@ -3138,12 +3138,14 @@ static bool btf_needs_sanitization(struct bpf_object *obj)
|
||||
bool has_type_tag = kernel_supports(obj, FEAT_BTF_TYPE_TAG);
|
||||
bool has_enum64 = kernel_supports(obj, FEAT_BTF_ENUM64);
|
||||
bool has_qmark_datasec = kernel_supports(obj, FEAT_BTF_QMARK_DATASEC);
|
||||
bool has_layout = kernel_supports(obj, FEAT_BTF_LAYOUT);
|
||||
|
||||
return !has_func || !has_datasec || !has_func_global || !has_float ||
|
||||
!has_decl_tag || !has_type_tag || !has_enum64 || !has_qmark_datasec;
|
||||
!has_decl_tag || !has_type_tag || !has_enum64 || !has_qmark_datasec ||
|
||||
!has_layout;
|
||||
}
|
||||
|
||||
static int bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *btf)
|
||||
static struct btf *bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *orig_btf)
|
||||
{
|
||||
bool has_func_global = kernel_supports(obj, FEAT_BTF_GLOBAL_FUNC);
|
||||
bool has_datasec = kernel_supports(obj, FEAT_BTF_DATASEC);
|
||||
@@ -3153,9 +3155,64 @@ static int bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *btf)
|
||||
bool has_type_tag = kernel_supports(obj, FEAT_BTF_TYPE_TAG);
|
||||
bool has_enum64 = kernel_supports(obj, FEAT_BTF_ENUM64);
|
||||
bool has_qmark_datasec = kernel_supports(obj, FEAT_BTF_QMARK_DATASEC);
|
||||
bool has_layout = kernel_supports(obj, FEAT_BTF_LAYOUT);
|
||||
int enum64_placeholder_id = 0;
|
||||
const struct btf_header *hdr;
|
||||
struct btf *btf = NULL;
|
||||
const void *raw_data;
|
||||
struct btf_type *t;
|
||||
int i, j, vlen;
|
||||
__u32 sz;
|
||||
int err;
|
||||
|
||||
/* clone BTF to sanitize a copy and leave the original intact */
|
||||
raw_data = btf__raw_data(orig_btf, &sz);
|
||||
if (!raw_data)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
/* btf_header() gives us endian-safe header info */
|
||||
hdr = btf_header(orig_btf);
|
||||
|
||||
if (!has_layout && hdr->hdr_len >= sizeof(struct btf_header) &&
|
||||
(hdr->layout_len != 0 || hdr->layout_off != 0)) {
|
||||
const struct btf_header *old_hdr = raw_data;
|
||||
struct btf_header *new_hdr;
|
||||
void *new_raw_data;
|
||||
__u32 new_str_off;
|
||||
|
||||
/*
|
||||
* Need to rewrite BTF to exclude layout information and
|
||||
* move string section to immediately after types.
|
||||
*/
|
||||
new_raw_data = malloc(sz);
|
||||
if (!new_raw_data)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
memcpy(new_raw_data, raw_data, sz);
|
||||
new_hdr = new_raw_data;
|
||||
new_hdr->layout_off = 0;
|
||||
new_hdr->layout_len = 0;
|
||||
new_str_off = hdr->type_off + hdr->type_len;
|
||||
/* Handle swapped endian case */
|
||||
if (old_hdr->magic != hdr->magic)
|
||||
new_hdr->str_off = bswap_32(new_str_off);
|
||||
else
|
||||
new_hdr->str_off = new_str_off;
|
||||
|
||||
memmove(new_raw_data + hdr->hdr_len + new_str_off,
|
||||
new_raw_data + hdr->hdr_len + hdr->str_off,
|
||||
hdr->str_len);
|
||||
sz = hdr->hdr_len + hdr->type_off + hdr->type_len + hdr->str_len;
|
||||
btf = btf__new(new_raw_data, sz);
|
||||
free(new_raw_data);
|
||||
} else {
|
||||
btf = btf__new(raw_data, sz);
|
||||
}
|
||||
err = libbpf_get_error(btf);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
/* enforce 8-byte pointers for BPF-targeted BTFs */
|
||||
btf__set_pointer_size(btf, 8);
|
||||
|
||||
for (i = 1; i < btf__type_cnt(btf); i++) {
|
||||
t = (struct btf_type *)btf__type_by_id(btf, i);
|
||||
@@ -3233,9 +3290,10 @@ static int bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *btf)
|
||||
|
||||
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;
|
||||
|
||||
if (enum64_placeholder_id < 0) {
|
||||
btf__free(btf);
|
||||
return ERR_PTR(enum64_placeholder_id);
|
||||
}
|
||||
t = (struct btf_type *)btf__type_by_id(btf, i);
|
||||
}
|
||||
|
||||
@@ -3249,7 +3307,7 @@ static int bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *btf)
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return btf;
|
||||
}
|
||||
|
||||
static bool libbpf_needs_btf(const struct bpf_object *obj)
|
||||
@@ -3600,21 +3658,9 @@ static int bpf_object__sanitize_and_load_btf(struct bpf_object *obj)
|
||||
|
||||
sanitize = btf_needs_sanitization(obj);
|
||||
if (sanitize) {
|
||||
const void *raw_data;
|
||||
__u32 sz;
|
||||
|
||||
/* clone BTF to sanitize a copy and leave the original intact */
|
||||
raw_data = btf__raw_data(obj->btf, &sz);
|
||||
kern_btf = btf__new(raw_data, sz);
|
||||
err = libbpf_get_error(kern_btf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* enforce 8-byte pointers for BPF-targeted BTFs */
|
||||
btf__set_pointer_size(obj->btf, 8);
|
||||
err = bpf_object__sanitize_btf(obj, kern_btf);
|
||||
if (err)
|
||||
return err;
|
||||
kern_btf = bpf_object__sanitize_btf(obj, obj->btf);
|
||||
if (IS_ERR(kern_btf))
|
||||
return PTR_ERR(kern_btf);
|
||||
}
|
||||
|
||||
if (obj->gen_loader) {
|
||||
|
||||
Reference in New Issue
Block a user