mirror of
https://github.com/netdata/libbpf.git
synced 2026-04-11 02:59:07 +08:00
libbpf: Add gating for arena globals relocation feature
Add feature gating for the arena globals relocation introduced in
commit c1f61171d44b. The commit depends on a previous commit in the
same patchset that is absent from older kernels
(12a1fe6e12db "bpf/verifier: Do not limit maximum direct offset into arena map").
Without this commit, arena globals relocation with arenas >= 512MiB
fails to load and breaks libbpf's backwards compatibility.
Introduce a libbpf feature to check whether the running kernel allows for
full range ldimm64 offset, and only relocate arena globals if it does.
Fixes: c1f61171d44b ("libbpf: Move arena globals to the end of the arena")
Signed-off-by: Emil Tsalapatis <emil@etsalapatis.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20260210184532.255475-1-emil@etsalapatis.com
This commit is contained in:
committed by
Andrii Nakryiko
parent
ad0d0e5112
commit
429aaef6a3
@@ -506,6 +506,67 @@ static int probe_kern_arg_ctx_tag(int token_fd)
|
|||||||
return probe_fd(prog_fd);
|
return probe_fd(prog_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int probe_ldimm64_full_range_off(int token_fd)
|
||||||
|
{
|
||||||
|
char log_buf[1024];
|
||||||
|
int prog_fd, map_fd;
|
||||||
|
int ret;
|
||||||
|
LIBBPF_OPTS(bpf_map_create_opts, map_opts,
|
||||||
|
.token_fd = token_fd,
|
||||||
|
.map_flags = token_fd ? BPF_F_TOKEN_FD : 0,
|
||||||
|
);
|
||||||
|
LIBBPF_OPTS(bpf_prog_load_opts, prog_opts,
|
||||||
|
.token_fd = token_fd,
|
||||||
|
.prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
|
||||||
|
.log_buf = log_buf,
|
||||||
|
.log_size = sizeof(log_buf),
|
||||||
|
);
|
||||||
|
struct bpf_insn insns[] = {
|
||||||
|
BPF_LD_MAP_VALUE(BPF_REG_1, 0, 1UL << 30),
|
||||||
|
BPF_EXIT_INSN(),
|
||||||
|
};
|
||||||
|
int insn_cnt = ARRAY_SIZE(insns);
|
||||||
|
|
||||||
|
map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "arr", sizeof(int), 1, 1, &map_opts);
|
||||||
|
if (map_fd < 0) {
|
||||||
|
ret = -errno;
|
||||||
|
pr_warn("Error in %s(): %s. Couldn't create simple array map.\n",
|
||||||
|
__func__, errstr(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
insns[0].imm = map_fd;
|
||||||
|
|
||||||
|
prog_fd = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, "global_reloc", "GPL", insns, insn_cnt, &prog_opts);
|
||||||
|
ret = -errno;
|
||||||
|
|
||||||
|
close(map_fd);
|
||||||
|
close(prog_fd);
|
||||||
|
|
||||||
|
if (prog_fd >= 0) {
|
||||||
|
pr_warn("Error in %s(): Program loading unexpectedly succeeded.\n", __func__);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Feature is allowed if we're not failing with the error message
|
||||||
|
* "direct value offset of %u is not allowed" removed in
|
||||||
|
* 12a1fe6e12db ("bpf/verifier: Do not limit maximum direct offset into arena map").
|
||||||
|
* We should instead fail with "invalid access to map value pointer".
|
||||||
|
* Ensure we match with one of the two and we're not failing with a
|
||||||
|
* different, unexpected message.
|
||||||
|
*/
|
||||||
|
if (strstr(log_buf, "direct value offset of"))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!strstr(log_buf, "invalid access to map value pointer")) {
|
||||||
|
pr_warn("Error in %s(): Program unexpectedly failed with message: %s.\n",
|
||||||
|
__func__, log_buf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
typedef int (*feature_probe_fn)(int /* token_fd */);
|
typedef int (*feature_probe_fn)(int /* token_fd */);
|
||||||
|
|
||||||
static struct kern_feature_cache feature_cache;
|
static struct kern_feature_cache feature_cache;
|
||||||
@@ -581,6 +642,9 @@ static struct kern_feature_desc {
|
|||||||
[FEAT_BTF_QMARK_DATASEC] = {
|
[FEAT_BTF_QMARK_DATASEC] = {
|
||||||
"BTF DATASEC names starting from '?'", probe_kern_btf_qmark_datasec,
|
"BTF DATASEC names starting from '?'", probe_kern_btf_qmark_datasec,
|
||||||
},
|
},
|
||||||
|
[FEAT_LDIMM64_FULL_RANGE_OFF] = {
|
||||||
|
"full range LDIMM64 support", probe_ldimm64_full_range_off,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id)
|
bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id)
|
||||||
|
|||||||
@@ -3009,8 +3009,11 @@ static int init_arena_map_data(struct bpf_object *obj, struct bpf_map *map,
|
|||||||
memcpy(obj->arena_data, data, data_sz);
|
memcpy(obj->arena_data, data, data_sz);
|
||||||
obj->arena_data_sz = data_sz;
|
obj->arena_data_sz = data_sz;
|
||||||
|
|
||||||
/* place globals at the end of the arena */
|
/* place globals at the end of the arena (if supported) */
|
||||||
obj->arena_data_off = mmap_sz - data_alloc_sz;
|
if (kernel_supports(obj, FEAT_LDIMM64_FULL_RANGE_OFF))
|
||||||
|
obj->arena_data_off = mmap_sz - data_alloc_sz;
|
||||||
|
else
|
||||||
|
obj->arena_data_off = 0;
|
||||||
|
|
||||||
/* make bpf_map__init_value() work for ARENA maps */
|
/* make bpf_map__init_value() work for ARENA maps */
|
||||||
map->mmaped = obj->arena_data;
|
map->mmaped = obj->arena_data;
|
||||||
|
|||||||
@@ -392,6 +392,8 @@ enum kern_feature_id {
|
|||||||
FEAT_ARG_CTX_TAG,
|
FEAT_ARG_CTX_TAG,
|
||||||
/* Kernel supports '?' at the front of datasec names */
|
/* Kernel supports '?' at the front of datasec names */
|
||||||
FEAT_BTF_QMARK_DATASEC,
|
FEAT_BTF_QMARK_DATASEC,
|
||||||
|
/* Kernel supports LDIMM64 imm offsets past 512 MiB. */
|
||||||
|
FEAT_LDIMM64_FULL_RANGE_OFF,
|
||||||
__FEAT_CNT,
|
__FEAT_CNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user