Skip to content

Commit 4c416c1

Browse files
Hou TaoKernel Patches Daemon
authored andcommitted
bpf: Defer bpf_map_put() for inner map in map array
When updating or deleting a map in map array, the map may still be accessed by non-sleepable program or sleepable program. However bpf_fd_array_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 2920d44 commit 4c416c1

File tree

2 files changed

+20
-9
lines changed

2 files changed

+20
-9
lines changed

kernel/bpf/arraymap.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,12 +1355,18 @@ static void array_of_map_free(struct bpf_map *map)
13551355

13561356
static void *array_of_map_lookup_elem(struct bpf_map *map, void *key)
13571357
{
1358-
struct bpf_map **inner_map = array_map_lookup_elem(map, key);
1358+
struct bpf_inner_map_element *element;
1359+
void **ptr;
13591360

1360-
if (!inner_map)
1361+
ptr = array_map_lookup_elem(map, key);
1362+
if (!ptr)
13611363
return NULL;
13621364

1363-
return READ_ONCE(*inner_map);
1365+
element = READ_ONCE(*ptr);
1366+
/* Uninitialized element ? */
1367+
if (!element)
1368+
return NULL;
1369+
return element->map;
13641370
}
13651371

13661372
static int array_of_map_gen_lookup(struct bpf_map *map,
@@ -1376,18 +1382,20 @@ static int array_of_map_gen_lookup(struct bpf_map *map,
13761382
*insn++ = BPF_ALU64_IMM(BPF_ADD, map_ptr, offsetof(struct bpf_array, value));
13771383
*insn++ = BPF_LDX_MEM(BPF_W, ret, index, 0);
13781384
if (!map->bypass_spec_v1) {
1379-
*insn++ = BPF_JMP_IMM(BPF_JGE, ret, map->max_entries, 6);
1385+
*insn++ = BPF_JMP_IMM(BPF_JGE, ret, map->max_entries, 8);
13801386
*insn++ = BPF_ALU32_IMM(BPF_AND, ret, array->index_mask);
13811387
} else {
1382-
*insn++ = BPF_JMP_IMM(BPF_JGE, ret, map->max_entries, 5);
1388+
*insn++ = BPF_JMP_IMM(BPF_JGE, ret, map->max_entries, 7);
13831389
}
13841390
if (is_power_of_2(elem_size))
13851391
*insn++ = BPF_ALU64_IMM(BPF_LSH, ret, ilog2(elem_size));
13861392
else
13871393
*insn++ = BPF_ALU64_IMM(BPF_MUL, ret, elem_size);
13881394
*insn++ = BPF_ALU64_REG(BPF_ADD, ret, map_ptr);
13891395
*insn++ = BPF_LDX_MEM(BPF_DW, ret, ret, 0);
1390-
*insn++ = BPF_JMP_IMM(BPF_JEQ, ret, 0, 1);
1396+
*insn++ = BPF_JMP_IMM(BPF_JEQ, ret, 0, 4);
1397+
*insn++ = BPF_LDX_MEM(BPF_DW, ret, ret, 0);
1398+
*insn++ = BPF_JMP_IMM(BPF_JEQ, ret, 0, 2);
13911399
*insn++ = BPF_JMP_IMM(BPF_JA, 0, 0, 1);
13921400
*insn++ = BPF_MOV64_IMM(ret, 0);
13931401

@@ -1401,9 +1409,9 @@ const struct bpf_map_ops array_of_maps_map_ops = {
14011409
.map_get_next_key = array_map_get_next_key,
14021410
.map_lookup_elem = array_of_map_lookup_elem,
14031411
.map_delete_elem = fd_array_map_delete_elem,
1404-
.map_fd_get_ptr = bpf_map_fd_get_ptr,
1405-
.map_fd_put_ptr = bpf_map_fd_put_ptr,
1406-
.map_fd_sys_lookup_elem = bpf_map_fd_sys_lookup_elem,
1412+
.map_fd_get_ptr = bpf_map_of_map_fd_get_ptr,
1413+
.map_fd_put_ptr = bpf_map_of_map_fd_put_ptr,
1414+
.map_fd_sys_lookup_elem = bpf_map_of_map_fd_sys_lookup_elem,
14071415
.map_gen_lookup = array_of_map_gen_lookup,
14081416
.map_lookup_batch = generic_map_lookup_batch,
14091417
.map_update_batch = generic_map_update_batch,

kernel/bpf/map_in_map.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ 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.
15+
*/
1316
struct bpf_map *map;
1417
struct rcu_head rcu;
1518
};

0 commit comments

Comments
 (0)