Commit 593fffb8 authored by Andrii Nakryiko's avatar Andrii Nakryiko
Browse files

Merge branch 'libbpf-fix-perm-errors-for-ldimm_64_full_range_off'



Emil Tsalapatis says:

====================
libbpf: Fix perm errors for LDIMM_64_FULL_RANGE_OFF

Commit 728ff167 ("libbpf: Add gating for arena globals relocation feature")
adds a feature flag for testing whether the running kernel supports LDIMM64
instructions with large direct offsets. Fix two edge cases that can
cause unexpected -EPERM errors in two ways:

1) The probe program used for the feature has type TRACEPOINT, but it's
possible the caller does not have permission to load it, even if it is
able to do so for generic BPF programs. Use the SOCKET_FILTER type
instead that requires fewer permissions. This does not affect the check
itself, which will always fail verification anyway.

2) The probe is triggered during bpf_object__collect_relos(), itself
called in bpf_object_open(), to compute the arena relocation offsets of
arena variables. However, the caller may not have permissions to load
BPF programs. This is the case in some systems with the bpftool calls made
by the BPF selftests during compilation, e.g., for skeleton generation.
Move all uses of the feature check to bpf_object_prepare() time instead.

Fixes: 728ff167 ("libbpf: Add gating for arena globals relocation feature")
Signed-off-by: default avatarEmil Tsalapatis <emil@etsalapatis.com>

v2 -> v3: https://lore.kernel.org/bpf/20260214021014.15670-1-emil@etsalapatis.com/

- Only zero out the first byte of the log buffer (Andrii)
- Minimize invocations of the feature gate (Andrii)

v1 -> v2: https://lore.kernel.org/bpf/20260213181752.505318-1-emil@etsalapatis.com/

- Adjust the hash of the original commit post-tree rebase
- Ensure close() is not called on invalid prog_fd in feature probe (Coverity)
====================

Link: https://patch.msgid.link/20260217204345.548648-1-emil@etsalapatis.com


Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
parents b0b1a858 d7988720
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -536,14 +536,15 @@ static int probe_ldimm64_full_range_off(int token_fd)
	}
	insns[0].imm = map_fd;

	prog_fd = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, "global_reloc", "GPL", insns, insn_cnt, &prog_opts);
	log_buf[0] = '\0';
	prog_fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, "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__);
		close(prog_fd);
		return -EINVAL;
	}

+13 −7
Original line number Diff line number Diff line
@@ -3009,12 +3009,6 @@ static int init_arena_map_data(struct bpf_object *obj, struct bpf_map *map,
	memcpy(obj->arena_data, data, data_sz);
	obj->arena_data_sz = data_sz;

	/* place globals at the end of the arena (if supported) */
	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 */
	map->mmaped = obj->arena_data;

@@ -4672,7 +4666,7 @@ static int bpf_program__record_reloc(struct bpf_program *prog,
		reloc_desc->type = RELO_DATA;
		reloc_desc->insn_idx = insn_idx;
		reloc_desc->map_idx = obj->arena_map_idx;
		reloc_desc->sym_off = sym->st_value + obj->arena_data_off;
		reloc_desc->sym_off = sym->st_value;

		map = &obj->maps[obj->arena_map_idx];
		pr_debug("prog '%s': found arena map %d (%s, sec %d, off %zu) for insn %u\n",
@@ -6386,6 +6380,10 @@ bpf_object__relocate_data(struct bpf_object *obj, struct bpf_program *prog)
		case RELO_DATA:
			map = &obj->maps[relo->map_idx];
			insn[1].imm = insn[0].imm + relo->sym_off;

			if (relo->map_idx == obj->arena_map_idx)
				insn[1].imm += obj->arena_data_off;

			if (obj->gen_loader) {
				insn[0].src_reg = BPF_PSEUDO_MAP_IDX_VALUE;
				insn[0].imm = relo->map_idx;
@@ -7387,6 +7385,14 @@ static int bpf_object__relocate(struct bpf_object *obj, const char *targ_btf_pat
		bpf_object__sort_relos(obj);
	}

	/* place globals at the end of the arena (if supported) */
	if (obj->arena_map_idx >= 0 && kernel_supports(obj, FEAT_LDIMM64_FULL_RANGE_OFF)) {
		struct bpf_map *arena_map = &obj->maps[obj->arena_map_idx];

		obj->arena_data_off = bpf_map_mmap_sz(arena_map) -
				      roundup(obj->arena_data_sz, sysconf(_SC_PAGE_SIZE));
	}

	/* Before relocating calls pre-process relocations and mark
	 * few ld_imm64 instructions that points to subprogs.
	 * Otherwise bpf_object__reloc_code() later would have to consider