mirror of
https://github.com/raspberrypi/linux.git
synced 2026-01-04 18:27:36 +00:00
libbpf: Support opening bpf objects of either endianness
Allow bpf_object__open() to access files of either endianness, and convert included BPF programs to native byte-order in-memory for introspection. Loading BPF objects of non-native byte-order is still disallowed however. Signed-off-by: Tony Ambardar <tony.ambardar@gmail.com> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Link: https://lore.kernel.org/bpf/26353c1a1887a54400e1acd6c138fa90c99cdd40.1726475448.git.tony.ambardar@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
committed by
Alexei Starovoitov
parent
cf579164e9
commit
bcc60abd67
@@ -694,6 +694,8 @@ struct bpf_object {
|
||||
/* Information when doing ELF related work. Only valid if efile.elf is not NULL */
|
||||
struct elf_state efile;
|
||||
|
||||
unsigned char byteorder;
|
||||
|
||||
struct btf *btf;
|
||||
struct btf_ext *btf_ext;
|
||||
|
||||
@@ -940,6 +942,20 @@ bpf_object__add_programs(struct bpf_object *obj, Elf_Data *sec_data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bpf_object_bswap_progs(struct bpf_object *obj)
|
||||
{
|
||||
struct bpf_program *prog = obj->programs;
|
||||
struct bpf_insn *insn;
|
||||
int p, i;
|
||||
|
||||
for (p = 0; p < obj->nr_programs; p++, prog++) {
|
||||
insn = prog->insns;
|
||||
for (i = 0; i < prog->insns_cnt; i++, insn++)
|
||||
bpf_insn_bswap(insn);
|
||||
}
|
||||
pr_debug("converted %zu BPF programs to native byte order\n", obj->nr_programs);
|
||||
}
|
||||
|
||||
static const struct btf_member *
|
||||
find_member_by_offset(const struct btf_type *t, __u32 bit_offset)
|
||||
{
|
||||
@@ -1506,6 +1522,7 @@ static void bpf_object__elf_finish(struct bpf_object *obj)
|
||||
|
||||
elf_end(obj->efile.elf);
|
||||
obj->efile.elf = NULL;
|
||||
obj->efile.ehdr = NULL;
|
||||
obj->efile.symbols = NULL;
|
||||
obj->efile.arena_data = NULL;
|
||||
|
||||
@@ -1571,6 +1588,16 @@ static int bpf_object__elf_init(struct bpf_object *obj)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Validate ELF object endianness... */
|
||||
if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB &&
|
||||
ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
|
||||
err = -LIBBPF_ERRNO__ENDIAN;
|
||||
pr_warn("elf: '%s' has unknown byte order\n", obj->path);
|
||||
goto errout;
|
||||
}
|
||||
/* and save after bpf_object_open() frees ELF data */
|
||||
obj->byteorder = ehdr->e_ident[EI_DATA];
|
||||
|
||||
if (elf_getshdrstrndx(elf, &obj->efile.shstrndx)) {
|
||||
pr_warn("elf: failed to get section names section index for %s: %s\n",
|
||||
obj->path, elf_errmsg(-1));
|
||||
@@ -1599,19 +1626,15 @@ errout:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int bpf_object__check_endianness(struct bpf_object *obj)
|
||||
static bool is_native_endianness(struct bpf_object *obj)
|
||||
{
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
if (obj->efile.ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
|
||||
return 0;
|
||||
return obj->byteorder == ELFDATA2LSB;
|
||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
if (obj->efile.ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
|
||||
return 0;
|
||||
return obj->byteorder == ELFDATA2MSB;
|
||||
#else
|
||||
# error "Unrecognized __BYTE_ORDER__"
|
||||
#endif
|
||||
pr_warn("elf: endianness mismatch in %s.\n", obj->path);
|
||||
return -LIBBPF_ERRNO__ENDIAN;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -3954,6 +3977,10 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
|
||||
return -LIBBPF_ERRNO__FORMAT;
|
||||
}
|
||||
|
||||
/* change BPF program insns to native endianness for introspection */
|
||||
if (!is_native_endianness(obj))
|
||||
bpf_object_bswap_progs(obj);
|
||||
|
||||
/* sort BPF programs by section name and in-section instruction offset
|
||||
* for faster search
|
||||
*/
|
||||
@@ -7997,7 +8024,6 @@ static struct bpf_object *bpf_object_open(const char *path, const void *obj_buf,
|
||||
}
|
||||
|
||||
err = bpf_object__elf_init(obj);
|
||||
err = err ? : bpf_object__check_endianness(obj);
|
||||
err = err ? : bpf_object__elf_collect(obj);
|
||||
err = err ? : bpf_object__collect_externs(obj);
|
||||
err = err ? : bpf_object_fixup_btf(obj);
|
||||
@@ -8503,8 +8529,15 @@ static int bpf_object_load(struct bpf_object *obj, int extra_log_level, const ch
|
||||
return libbpf_err(-EINVAL);
|
||||
}
|
||||
|
||||
if (obj->gen_loader)
|
||||
/* Disallow kernel loading programs of non-native endianness but
|
||||
* permit cross-endian creation of "light skeleton".
|
||||
*/
|
||||
if (obj->gen_loader) {
|
||||
bpf_gen__init(obj->gen_loader, extra_log_level, obj->nr_programs, obj->nr_maps);
|
||||
} else if (!is_native_endianness(obj)) {
|
||||
pr_warn("object '%s': loading non-native endianness is unsupported\n", obj->name);
|
||||
return libbpf_err(-LIBBPF_ERRNO__ENDIAN);
|
||||
}
|
||||
|
||||
err = bpf_object_prepare_token(obj);
|
||||
err = err ? : bpf_object__probe_loading(obj);
|
||||
|
||||
Reference in New Issue
Block a user