Skip to content

Commit 11ba7ce

Browse files
Yonghong SongAlexei Starovoitov
authored andcommitted
bpf: Fix kmemleak warning for percpu hashmap
Vlad Poenaru reported the following kmemleak issue: unreferenced object 0x606fd7c44ac8 (size 32): backtrace (crc 0): pcpu_alloc_noprof+0x730/0xeb0 bpf_map_alloc_percpu+0x69/0xc0 prealloc_init+0x9d/0x1b0 htab_map_alloc+0x363/0x510 map_create+0x215/0x3a0 __sys_bpf+0x16b/0x3e0 __x64_sys_bpf+0x18/0x20 do_syscall_64+0x7b/0x150 entry_SYSCALL_64_after_hwframe+0x4b/0x53 Further investigation shows the reason is due to not 8-byte aligned store of percpu pointer in htab_elem_set_ptr(): *(void __percpu **)(l->key + key_size) = pptr; Note that the whole htab_elem alignment is 8 (for x86_64). If the key_size is 4, that means pptr is stored in a location which is 4 byte aligned but not 8 byte aligned. In mm/kmemleak.c, scan_block() scans the memory based on 8 byte stride, so it won't detect above pptr, hence reporting the memory leak. In htab_map_alloc(), we already have htab->elem_size = sizeof(struct htab_elem) + round_up(htab->map.key_size, 8); if (percpu) htab->elem_size += sizeof(void *); else htab->elem_size += round_up(htab->map.value_size, 8); So storing pptr with 8-byte alignment won't cause any problem and can fix kmemleak too. The issue can be reproduced with bpf selftest as well: 1. Enable CONFIG_DEBUG_KMEMLEAK config 2. Add a getchar() before skel destroy in test_hash_map() in prog_tests/for_each.c. The purpose is to keep map available so kmemleak can be detected. 3. run './test_progs -t for_each/hash_map &' and a kmemleak should be reported. Reported-by: Vlad Poenaru <[email protected]> Signed-off-by: Yonghong Song <[email protected]> Acked-by: Martin KaFai Lau <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 2398608 commit 11ba7ce

File tree

1 file changed

+3
-3
lines changed

1 file changed

+3
-3
lines changed

kernel/bpf/hashtab.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,12 +198,12 @@ static bool htab_is_percpu(const struct bpf_htab *htab)
198198
static inline void htab_elem_set_ptr(struct htab_elem *l, u32 key_size,
199199
void __percpu *pptr)
200200
{
201-
*(void __percpu **)(l->key + key_size) = pptr;
201+
*(void __percpu **)(l->key + roundup(key_size, 8)) = pptr;
202202
}
203203

204204
static inline void __percpu *htab_elem_get_ptr(struct htab_elem *l, u32 key_size)
205205
{
206-
return *(void __percpu **)(l->key + key_size);
206+
return *(void __percpu **)(l->key + roundup(key_size, 8));
207207
}
208208

209209
static void *fd_htab_map_get_ptr(const struct bpf_map *map, struct htab_elem *l)
@@ -2354,7 +2354,7 @@ static int htab_percpu_map_gen_lookup(struct bpf_map *map, struct bpf_insn *insn
23542354
*insn++ = BPF_EMIT_CALL(__htab_map_lookup_elem);
23552355
*insn++ = BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3);
23562356
*insn++ = BPF_ALU64_IMM(BPF_ADD, BPF_REG_0,
2357-
offsetof(struct htab_elem, key) + map->key_size);
2357+
offsetof(struct htab_elem, key) + roundup(map->key_size, 8));
23582358
*insn++ = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0);
23592359
*insn++ = BPF_MOV64_PERCPU_REG(BPF_REG_0, BPF_REG_0);
23602360

0 commit comments

Comments
 (0)