libbpf: Support selective kernel module BTF loading via bpf_object_open_opts

Add btf_module_allowlist and btf_module_allowlist_cnt fields to
bpf_object_open_opts to limit which kernel module BTFs libbpf is
allowed to load.

When the option is not specified, the existing behavior remains
unchanged. An explicitly specified empty allowlist prevents libbpf from
consulting any kernel module BTFs.

The allowlist limits which kernel module BTFs libbpf will consult
wherever module BTF might be needed.

Suggested-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Fuyu Zhao <zhaofuyu@vivo.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20260915124104.77287-2-zhaofuyu@vivo.com
This commit is contained in:
Fuyu Zhao authored and Andrii Nakryiko committed 2026-10-02 05:41:50 -07:00
1 parent ab48c6f1ba
commit acc90a4bb1
2 files changed
+85 -1

No files matched your search

+70
View File
@@ -751,6 +751,8 @@ struct bpf_object {
bool btf_modules_loaded;
size_t btf_module_cnt;
size_t btf_module_cap;
char **btf_module_allowlist;
ssize_t btf_module_allowlist_cnt;
/* optional log settings passed to BPF_BTF_LOAD and BPF_PROG_LOAD commands */
char *log_buf;
@@ -5843,6 +5845,21 @@ int bpf_core_add_cands(struct bpf_core_cand *local_cand,
return 0;
}
static bool is_btf_mod_allowed(const struct bpf_object *obj, const char *name)
{
ssize_t i;
if (obj->btf_module_allowlist_cnt < 0)
return true;
for (i = 0; i < obj->btf_module_allowlist_cnt; i++) {
if (strcmp(obj->btf_module_allowlist[i], name) == 0)
return true;
}
return false;
}
static int load_module_btfs(struct bpf_object *obj)
{
struct bpf_btf_info info;
@@ -5865,6 +5882,9 @@ static int load_module_btfs(struct bpf_object *obj)
if (!kernel_supports(obj, FEAT_MODULE_BTF))
return 0;
if (obj->btf_module_allowlist_cnt == 0)
return 0;
while (true) {
err = bpf_btf_get_next_id(id, &id);
if (err && errno == ENOENT)
@@ -5907,6 +5927,11 @@ static int load_module_btfs(struct bpf_object *obj)
continue;
}
if (!is_btf_mod_allowed(obj, name)) {
close(fd);
continue;
}
btf = btf_get_from_fd(fd, obj->btf_vmlinux);
err = libbpf_get_error(btf);
if (err) {
@@ -5931,6 +5956,9 @@ static int load_module_btfs(struct bpf_object *obj)
break;
}
obj->btf_module_cnt++;
if (obj->btf_module_allowlist_cnt == obj->btf_module_cnt)
break;
}
if (err) {
@@ -8481,6 +8509,8 @@ static struct bpf_object *bpf_object_open(const char *path, const void *obj_buf,
const struct bpf_object_open_opts *opts)
{
const char *kconfig, *btf_tmp_path, *token_path;
size_t mod_allow_cnt, i, j;
const char **mod_allow;
struct bpf_object *obj;
int err;
char *log_buf;
@@ -8525,6 +8555,22 @@ static struct bpf_object *bpf_object_open(const char *path, const void *obj_buf,
if (token_path && strlen(token_path) >= PATH_MAX)
return ERR_PTR(-ENAMETOOLONG);
mod_allow = OPTS_GET(opts, btf_module_allowlist, NULL);
mod_allow_cnt = OPTS_GET(opts, btf_module_allowlist_cnt, 0);
if (mod_allow_cnt > SSIZE_MAX || (!mod_allow && mod_allow_cnt > 0))
return ERR_PTR(-EINVAL);
for (i = 0; i < mod_allow_cnt; i++) {
if (!mod_allow[i] || !mod_allow[i][0])
return ERR_PTR(-EINVAL);
for (j = 0; j < i; j++) {
if (strcmp(mod_allow[i], mod_allow[j]) == 0)
return ERR_PTR(-EINVAL);
}
}
obj = bpf_object__new(path, obj_buf, obj_buf_sz, obj_name);
if (IS_ERR(obj))
return obj;
@@ -8563,6 +8609,24 @@ static struct bpf_object *bpf_object_open(const char *path, const void *obj_buf,
}
}
obj->btf_module_allowlist_cnt = mod_allow ? mod_allow_cnt : -1;
if (mod_allow_cnt > 0) {
obj->btf_module_allowlist =
calloc(mod_allow_cnt, sizeof(*obj->btf_module_allowlist));
if (!obj->btf_module_allowlist) {
err = -ENOMEM;
goto out;
}
for (i = 0; i < mod_allow_cnt; i++) {
obj->btf_module_allowlist[i] = strdup(mod_allow[i]);
if (!obj->btf_module_allowlist[i]) {
err = -ENOMEM;
goto out;
}
}
}
err = bpf_object__elf_init(obj);
err = err ? : bpf_object__elf_collect(obj);
err = err ? : bpf_object__collect_externs(obj);
@@ -9685,6 +9749,12 @@ void bpf_object__close(struct bpf_object *obj)
close(obj->jumptable_maps[i].fd);
zfree(&obj->jumptable_maps);
if (obj->btf_module_allowlist) {
for (i = 0; i < obj->btf_module_allowlist_cnt; i++)
zfree(&obj->btf_module_allowlist[i]);
zfree(&obj->btf_module_allowlist);
}
free(obj);
}
+15 -1
View File
@@ -224,10 +224,24 @@ struct bpf_object_open_opts {
* point (/sys/fs/bpf), in case this default behavior is undesirable.
*/
const char *bpf_token_path;
/*
* Optional allowlist of kernel module names whose BTFs libbpf is
* allowed to load. The allowlist limits which kernel module BTFs libbpf
* will consult wherever module BTF might be needed.
*
* When the option is not specified, the existing behavior remains
* unchanged. An explicitly specified empty list prevents libbpf from
* consulting any kernel module BTFs.
*
* The list must contain valid, non-empty module names and must not
* contain duplicate entries; otherwise -EINVAL is returned.
*/
const char **btf_module_allowlist;
size_t btf_module_allowlist_cnt;
size_t :0;
};
#define bpf_object_open_opts__last_field bpf_token_path
#define bpf_object_open_opts__last_field btf_module_allowlist_cnt
/**
* @brief **bpf_object__open()** creates a bpf_object by opening