Skip to content

Commit 0345a72

Browse files
Hou TaoKernel Patches Daemon
authored andcommitted
bpf: Add bpf_map_of_map_fd_{get,put}_ptr() helpers
bpf_map_of_map_fd_get_ptr() will convert the map fd to the pointer saved in map-in-map. bpf_map_of_map_fd_put_ptr() will release the pointer saved in map-in-map. These two helpers will be used by the following patches to fix the use-after-free problems for map-in-map. Signed-off-by: Hou Tao <[email protected]>
1 parent 9759fcd commit 0345a72

File tree

2 files changed

+60
-2
lines changed

2 files changed

+60
-2
lines changed

kernel/bpf/map_in_map.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <linux/slab.h>
55
#include <linux/bpf.h>
66
#include <linux/btf.h>
7+
#include <linux/rcupdate.h>
78

89
#include "map_in_map.h"
910

@@ -139,3 +140,53 @@ u32 bpf_map_fd_sys_lookup_elem(void *ptr)
139140
{
140141
return ((struct bpf_map *)ptr)->id;
141142
}
143+
144+
void *bpf_map_of_map_fd_get_ptr(struct bpf_map *map, struct file *map_file,
145+
int ufd)
146+
{
147+
struct bpf_inner_map_element *element;
148+
struct bpf_map *inner_map;
149+
150+
element = kmalloc(sizeof(*element), GFP_KERNEL);
151+
if (!element)
152+
return ERR_PTR(-ENOMEM);
153+
154+
inner_map = bpf_map_fd_get_ptr(map, map_file, ufd);
155+
if (IS_ERR(inner_map)) {
156+
kfree(element);
157+
return inner_map;
158+
}
159+
160+
element->map = inner_map;
161+
return element;
162+
}
163+
164+
static void bpf_inner_map_element_free_rcu(struct rcu_head *rcu)
165+
{
166+
struct bpf_inner_map_element *elem = container_of(rcu, struct bpf_inner_map_element, rcu);
167+
168+
bpf_map_put(elem->map);
169+
kfree(elem);
170+
}
171+
172+
static void bpf_inner_map_element_free_tt_rcu(struct rcu_head *rcu)
173+
{
174+
if (rcu_trace_implies_rcu_gp())
175+
bpf_inner_map_element_free_rcu(rcu);
176+
else
177+
call_rcu(rcu, bpf_inner_map_element_free_rcu);
178+
}
179+
180+
void bpf_map_of_map_fd_put_ptr(void *ptr, bool need_defer)
181+
{
182+
struct bpf_inner_map_element *element = ptr;
183+
184+
/* Do bpf_map_put() after a RCU grace period and a tasks trace
185+
* RCU grace period, so it is certain that the bpf program which is
186+
* manipulating the map now has exited when bpf_map_put() is called.
187+
*/
188+
if (need_defer)
189+
call_rcu_tasks_trace(&element->rcu, bpf_inner_map_element_free_tt_rcu);
190+
else
191+
bpf_inner_map_element_free_rcu(&element->rcu);
192+
}

kernel/bpf/map_in_map.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,18 @@
99
struct file;
1010
struct bpf_map;
1111

12+
struct bpf_inner_map_element {
13+
struct bpf_map *map;
14+
struct rcu_head rcu;
15+
};
16+
1217
struct bpf_map *bpf_map_meta_alloc(int inner_map_ufd);
1318
void bpf_map_meta_free(struct bpf_map *map_meta);
14-
void *bpf_map_fd_get_ptr(struct bpf_map *map, struct file *map_file,
15-
int ufd);
19+
void *bpf_map_fd_get_ptr(struct bpf_map *map, struct file *map_file, int ufd);
1620
void bpf_map_fd_put_ptr(void *ptr, bool need_defer);
1721
u32 bpf_map_fd_sys_lookup_elem(void *ptr);
1822

23+
void *bpf_map_of_map_fd_get_ptr(struct bpf_map *map, struct file *map_file, int ufd);
24+
void bpf_map_of_map_fd_put_ptr(void *ptr, bool need_defer);
25+
1926
#endif

0 commit comments

Comments
 (0)