Skip to content

Commit 0fb6c9e

Browse files
sinkapAlexei Starovoitov
authored andcommitted
libbpf: Reject non-exclusive metadata maps in the signed loader
The loader verifies map->sha against the metadata hash in its instructions. map->sha is calculated when BPF_OBJ_GET_INFO_BY_FD is called on the frozen map. While the map is frozen, the /signed loader/ must also ensure the map is exclusive, as, without exclusivity (which a hostile host could just omit when loading the loader), another BPF program with map access can mutate the contents afterwards, so the check passes on stale data. With the extra check as part of the signed loader, it now refuses to move on with map->sha validation if the host set it up wrongly. Fixes: fb2b0e2 ("libbpf: Update light skeleton for signing") Signed-off-by: KP Singh <kpsingh@kernel.org> Co-developed-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Link: https://lore.kernel.org/r/20260601150248.394863-4-daniel@iogearbox.net Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent c48c3a7 commit 0fb6c9e

3 files changed

Lines changed: 25 additions & 0 deletions

File tree

include/linux/bpf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ struct bpf_map_owner {
296296

297297
struct bpf_map {
298298
u8 sha[SHA256_DIGEST_SIZE];
299+
u32 excl;
299300
const struct bpf_map_ops *ops;
300301
struct bpf_map *inner_map_meta;
301302
#ifdef CONFIG_SECURITY

kernel/bpf/syscall.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1588,6 +1588,13 @@ static int map_create_alloc(union bpf_attr *attr, bpfptr_t uattr, struct bpf_ver
15881588
err = -EFAULT;
15891589
goto free_map;
15901590
}
1591+
1592+
/* See libbpf: emit_signature_match() */
1593+
BUILD_BUG_ON(offsetof(struct bpf_map, excl) != SHA256_DIGEST_SIZE);
1594+
BUILD_BUG_ON(!__same_type(map->excl, u32));
1595+
BUILD_BUG_ON(offsetof(struct bpf_map, sha) != 0);
1596+
BUILD_BUG_ON(!__same_type(map->sha, u8[SHA256_DIGEST_SIZE]));
1597+
map->excl = 1;
15911598
} else if (attr->excl_prog_hash_size) {
15921599
bpf_log(log, "Invalid excl_prog_hash_size.\n");
15931600
err = -EINVAL;

tools/lib/bpf/gen_loader.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,23 @@ static void emit_signature_match(struct bpf_gen *gen)
586586
__s64 off;
587587
int i;
588588

589+
/*
590+
* Reject if the metadata map is not exclusive. Without exclusivity
591+
* the cached map->sha[] verified above can be stale: another BPF
592+
* program with map access could have mutated the contents between
593+
* BPF_OBJ_GET_INFO_BY_FD and loader execution.
594+
*/
595+
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX,
596+
0, 0, 0, 0));
597+
emit(gen, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, SHA256_DIGEST_LENGTH));
598+
off = -(gen->insn_cur - gen->insn_start - gen->cleanup_label) / 8 - 2;
599+
if (is_simm16(off)) {
600+
emit(gen, BPF_MOV64_IMM(BPF_REG_7, -EINVAL));
601+
emit(gen, BPF_JMP_IMM(BPF_JNE, BPF_REG_2, 1, off));
602+
} else {
603+
gen->error = -ERANGE;
604+
}
605+
589606
for (i = 0; i < SHA256_DWORD_SIZE; i++) {
590607
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX,
591608
0, 0, 0, 0));

0 commit comments

Comments
 (0)