Skip to content

Commit 67dfb25

Browse files
Hou TaoKernel Patches Daemon
authored andcommitted
bpf: Defer bpf_map_put() for inner map in map htab
When updating or deleting a map in map htab, the map may still be accessed by non-sleepable program or sleepable program. However bpf_fd_htab_map_update_elem() decreases the ref-count of the inner map directly through bpf_map_put(), if the ref-count is the last ref-count which is true for most cases, the inner map will be free by ops->map_free() in a kworker. But for now, most .map_free() callbacks don't use synchronize_rcu() or its variants to wait for the elapse of a RCU grace period, so bpf program which is accessing the inner map may incur use-after-free problem. Fix it by deferring the invocation of bpf_map_put() after the elapse of both one RCU grace period and one tasks trace RCU grace period. Fixes: bba1dc0 ("bpf: Remove redundant synchronize_rcu.") Fixes: 638e4b8 ("bpf: Allows per-cpu maps and map-in-map in sleepable programs") Signed-off-by: Hou Tao <[email protected]>
1 parent 4c416c1 commit 67dfb25

File tree

2 files changed

+17
-12
lines changed

2 files changed

+17
-12
lines changed

kernel/bpf/hashtab.c

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1813,10 +1813,10 @@ __htab_map_lookup_and_delete_batch(struct bpf_map *map,
18131813
} else {
18141814
value = l->key + roundup_key_size;
18151815
if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) {
1816-
struct bpf_map **inner_map = value;
1816+
void *inner = READ_ONCE(*(void **)value);
18171817

1818-
/* Actual value is the id of the inner map */
1819-
map_id = map->ops->map_fd_sys_lookup_elem(*inner_map);
1818+
/* Actual value is the id of the inner map */
1819+
map_id = map->ops->map_fd_sys_lookup_elem(inner);
18201820
value = &map_id;
18211821
}
18221822

@@ -2553,12 +2553,16 @@ static struct bpf_map *htab_of_map_alloc(union bpf_attr *attr)
25532553

25542554
static void *htab_of_map_lookup_elem(struct bpf_map *map, void *key)
25552555
{
2556-
struct bpf_map **inner_map = htab_map_lookup_elem(map, key);
2556+
struct bpf_inner_map_element *element;
2557+
void **ptr;
25572558

2558-
if (!inner_map)
2559+
ptr = htab_map_lookup_elem(map, key);
2560+
if (!ptr)
25592561
return NULL;
25602562

2561-
return READ_ONCE(*inner_map);
2563+
/* element must be no-NULL */
2564+
element = READ_ONCE(*ptr);
2565+
return element->map;
25622566
}
25632567

25642568
static int htab_of_map_gen_lookup(struct bpf_map *map,
@@ -2570,11 +2574,12 @@ static int htab_of_map_gen_lookup(struct bpf_map *map,
25702574
BUILD_BUG_ON(!__same_type(&__htab_map_lookup_elem,
25712575
(void *(*)(struct bpf_map *map, void *key))NULL));
25722576
*insn++ = BPF_EMIT_CALL(__htab_map_lookup_elem);
2573-
*insn++ = BPF_JMP_IMM(BPF_JEQ, ret, 0, 2);
2577+
*insn++ = BPF_JMP_IMM(BPF_JEQ, ret, 0, 3);
25742578
*insn++ = BPF_ALU64_IMM(BPF_ADD, ret,
25752579
offsetof(struct htab_elem, key) +
25762580
round_up(map->key_size, 8));
25772581
*insn++ = BPF_LDX_MEM(BPF_DW, ret, ret, 0);
2582+
*insn++ = BPF_LDX_MEM(BPF_DW, ret, ret, 0);
25782583

25792584
return insn - insn_buf;
25802585
}
@@ -2592,9 +2597,9 @@ const struct bpf_map_ops htab_of_maps_map_ops = {
25922597
.map_get_next_key = htab_map_get_next_key,
25932598
.map_lookup_elem = htab_of_map_lookup_elem,
25942599
.map_delete_elem = htab_map_delete_elem,
2595-
.map_fd_get_ptr = bpf_map_fd_get_ptr,
2596-
.map_fd_put_ptr = bpf_map_fd_put_ptr,
2597-
.map_fd_sys_lookup_elem = bpf_map_fd_sys_lookup_elem,
2600+
.map_fd_get_ptr = bpf_map_of_map_fd_get_ptr,
2601+
.map_fd_put_ptr = bpf_map_of_map_fd_put_ptr,
2602+
.map_fd_sys_lookup_elem = bpf_map_of_map_fd_sys_lookup_elem,
25982603
.map_gen_lookup = htab_of_map_gen_lookup,
25992604
.map_check_btf = map_check_no_btf,
26002605
.map_mem_usage = htab_map_mem_usage,

kernel/bpf/map_in_map.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ struct file;
1010
struct bpf_map;
1111

1212
struct bpf_inner_map_element {
13-
/* map must be the first member, array_of_map_gen_lookup() depends on it
14-
* to dereference map correctly.
13+
/* map must be the first member, array_of_map_gen_lookup() and
14+
* htab_of_map_lookup_elem() depend on it to dereference map correctly.
1515
*/
1616
struct bpf_map *map;
1717
struct rcu_head rcu;

0 commit comments

Comments
 (0)