Skip to content

Commit f4d0525

Browse files
iamkafaiborkmann
authored andcommitted
bpf: Add map_meta_equal map ops
Some properties of the inner map is used in the verification time. When an inner map is inserted to an outer map at runtime, bpf_map_meta_equal() is currently used to ensure those properties of the inserting inner map stays the same as the verification time. In particular, the current bpf_map_meta_equal() checks max_entries which turns out to be too restrictive for most of the maps which do not use max_entries during the verification time. It limits the use case that wants to replace a smaller inner map with a larger inner map. There are some maps do use max_entries during verification though. For example, the map_gen_lookup in array_map_ops uses the max_entries to generate the inline lookup code. To accommodate differences between maps, the map_meta_equal is added to bpf_map_ops. Each map-type can decide what to check when its map is used as an inner map during runtime. Also, some map types cannot be used as an inner map and they are currently black listed in bpf_map_meta_alloc() in map_in_map.c. It is not unusual that the new map types may not aware that such blacklist exists. This patch enforces an explicit opt-in and only allows a map to be used as an inner map if it has implemented the map_meta_equal ops. It is based on the discussion in [1]. All maps that support inner map has its map_meta_equal points to bpf_map_meta_equal in this patch. A later patch will relax the max_entries check for most maps. bpf_types.h counts 28 map types. This patch adds 23 ".map_meta_equal" by using coccinelle. -5 for BPF_MAP_TYPE_PROG_ARRAY BPF_MAP_TYPE_(PERCPU)_CGROUP_STORAGE BPF_MAP_TYPE_STRUCT_OPS BPF_MAP_TYPE_ARRAY_OF_MAPS BPF_MAP_TYPE_HASH_OF_MAPS The "if (inner_map->inner_map_meta)" check in bpf_map_meta_alloc() is moved such that the same error is returned. [1]: https://lore.kernel.org/bpf/[email protected]/ Signed-off-by: Martin KaFai Lau <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent b0c9eb3 commit f4d0525

17 files changed

+52
-15
lines changed

include/linux/bpf.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,19 @@ struct bpf_map_ops {
112112
void (*map_local_storage_uncharge)(struct bpf_local_storage_map *smap,
113113
void *owner, u32 size);
114114
struct bpf_local_storage __rcu ** (*map_owner_storage_ptr)(void *owner);
115+
116+
/* map_meta_equal must be implemented for maps that can be
117+
* used as an inner map. It is a runtime check to ensure
118+
* an inner map can be inserted to an outer map.
119+
*
120+
* Some properties of the inner map has been used during the
121+
* verification time. When inserting an inner map at the runtime,
122+
* map_meta_equal has to ensure the inserting map has the same
123+
* properties that the verifier has used earlier.
124+
*/
125+
bool (*map_meta_equal)(const struct bpf_map *meta0,
126+
const struct bpf_map *meta1);
127+
115128
/* BTF name and id of struct allocated by map_alloc */
116129
const char * const map_btf_name;
117130
int *map_btf_id;
@@ -235,6 +248,9 @@ int map_check_no_btf(const struct bpf_map *map,
235248
const struct btf_type *key_type,
236249
const struct btf_type *value_type);
237250

251+
bool bpf_map_meta_equal(const struct bpf_map *meta0,
252+
const struct bpf_map *meta1);
253+
238254
extern const struct bpf_map_ops bpf_map_offload_ops;
239255

240256
/* function argument constraints */

kernel/bpf/arraymap.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,7 @@ static const struct bpf_iter_seq_info iter_seq_info = {
625625

626626
static int array_map_btf_id;
627627
const struct bpf_map_ops array_map_ops = {
628+
.map_meta_equal = bpf_map_meta_equal,
628629
.map_alloc_check = array_map_alloc_check,
629630
.map_alloc = array_map_alloc,
630631
.map_free = array_map_free,
@@ -647,6 +648,7 @@ const struct bpf_map_ops array_map_ops = {
647648

648649
static int percpu_array_map_btf_id;
649650
const struct bpf_map_ops percpu_array_map_ops = {
651+
.map_meta_equal = bpf_map_meta_equal,
650652
.map_alloc_check = array_map_alloc_check,
651653
.map_alloc = array_map_alloc,
652654
.map_free = array_map_free,
@@ -1003,6 +1005,11 @@ static void prog_array_map_free(struct bpf_map *map)
10031005
fd_array_map_free(map);
10041006
}
10051007

1008+
/* prog_array->aux->{type,jited} is a runtime binding.
1009+
* Doing static check alone in the verifier is not enough.
1010+
* Thus, prog_array_map cannot be used as an inner_map
1011+
* and map_meta_equal is not implemented.
1012+
*/
10061013
static int prog_array_map_btf_id;
10071014
const struct bpf_map_ops prog_array_map_ops = {
10081015
.map_alloc_check = fd_array_map_alloc_check,
@@ -1101,6 +1108,7 @@ static void perf_event_fd_array_release(struct bpf_map *map,
11011108

11021109
static int perf_event_array_map_btf_id;
11031110
const struct bpf_map_ops perf_event_array_map_ops = {
1111+
.map_meta_equal = bpf_map_meta_equal,
11041112
.map_alloc_check = fd_array_map_alloc_check,
11051113
.map_alloc = array_map_alloc,
11061114
.map_free = fd_array_map_free,
@@ -1137,6 +1145,7 @@ static void cgroup_fd_array_free(struct bpf_map *map)
11371145

11381146
static int cgroup_array_map_btf_id;
11391147
const struct bpf_map_ops cgroup_array_map_ops = {
1148+
.map_meta_equal = bpf_map_meta_equal,
11401149
.map_alloc_check = fd_array_map_alloc_check,
11411150
.map_alloc = array_map_alloc,
11421151
.map_free = cgroup_fd_array_free,

kernel/bpf/bpf_inode_storage.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ static void inode_storage_map_free(struct bpf_map *map)
235235

236236
static int inode_storage_map_btf_id;
237237
const struct bpf_map_ops inode_storage_map_ops = {
238+
.map_meta_equal = bpf_map_meta_equal,
238239
.map_alloc_check = bpf_local_storage_map_alloc_check,
239240
.map_alloc = inode_storage_map_alloc,
240241
.map_free = inode_storage_map_free,

kernel/bpf/cpumap.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,7 @@ static int cpu_map_get_next_key(struct bpf_map *map, void *key, void *next_key)
658658

659659
static int cpu_map_btf_id;
660660
const struct bpf_map_ops cpu_map_ops = {
661+
.map_meta_equal = bpf_map_meta_equal,
661662
.map_alloc = cpu_map_alloc,
662663
.map_free = cpu_map_free,
663664
.map_delete_elem = cpu_map_delete_elem,

kernel/bpf/devmap.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,7 @@ static int dev_map_hash_update_elem(struct bpf_map *map, void *key, void *value,
751751

752752
static int dev_map_btf_id;
753753
const struct bpf_map_ops dev_map_ops = {
754+
.map_meta_equal = bpf_map_meta_equal,
754755
.map_alloc = dev_map_alloc,
755756
.map_free = dev_map_free,
756757
.map_get_next_key = dev_map_get_next_key,
@@ -764,6 +765,7 @@ const struct bpf_map_ops dev_map_ops = {
764765

765766
static int dev_map_hash_map_btf_id;
766767
const struct bpf_map_ops dev_map_hash_ops = {
768+
.map_meta_equal = bpf_map_meta_equal,
767769
.map_alloc = dev_map_alloc,
768770
.map_free = dev_map_free,
769771
.map_get_next_key = dev_map_hash_get_next_key,

kernel/bpf/hashtab.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1810,6 +1810,7 @@ static const struct bpf_iter_seq_info iter_seq_info = {
18101810

18111811
static int htab_map_btf_id;
18121812
const struct bpf_map_ops htab_map_ops = {
1813+
.map_meta_equal = bpf_map_meta_equal,
18131814
.map_alloc_check = htab_map_alloc_check,
18141815
.map_alloc = htab_map_alloc,
18151816
.map_free = htab_map_free,
@@ -1827,6 +1828,7 @@ const struct bpf_map_ops htab_map_ops = {
18271828

18281829
static int htab_lru_map_btf_id;
18291830
const struct bpf_map_ops htab_lru_map_ops = {
1831+
.map_meta_equal = bpf_map_meta_equal,
18301832
.map_alloc_check = htab_map_alloc_check,
18311833
.map_alloc = htab_map_alloc,
18321834
.map_free = htab_map_free,
@@ -1947,6 +1949,7 @@ static void htab_percpu_map_seq_show_elem(struct bpf_map *map, void *key,
19471949

19481950
static int htab_percpu_map_btf_id;
19491951
const struct bpf_map_ops htab_percpu_map_ops = {
1952+
.map_meta_equal = bpf_map_meta_equal,
19501953
.map_alloc_check = htab_map_alloc_check,
19511954
.map_alloc = htab_map_alloc,
19521955
.map_free = htab_map_free,
@@ -1963,6 +1966,7 @@ const struct bpf_map_ops htab_percpu_map_ops = {
19631966

19641967
static int htab_lru_percpu_map_btf_id;
19651968
const struct bpf_map_ops htab_lru_percpu_map_ops = {
1969+
.map_meta_equal = bpf_map_meta_equal,
19661970
.map_alloc_check = htab_map_alloc_check,
19671971
.map_alloc = htab_map_alloc,
19681972
.map_free = htab_map_free,

kernel/bpf/lpm_trie.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -732,6 +732,7 @@ static int trie_check_btf(const struct bpf_map *map,
732732

733733
static int trie_map_btf_id;
734734
const struct bpf_map_ops trie_map_ops = {
735+
.map_meta_equal = bpf_map_meta_equal,
735736
.map_alloc = trie_alloc,
736737
.map_free = trie_free,
737738
.map_get_next_key = trie_get_next_key,

kernel/bpf/map_in_map.c

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,17 @@ struct bpf_map *bpf_map_meta_alloc(int inner_map_ufd)
1717
if (IS_ERR(inner_map))
1818
return inner_map;
1919

20-
/* prog_array->aux->{type,jited} is a runtime binding.
21-
* Doing static check alone in the verifier is not enough.
22-
*/
23-
if (inner_map->map_type == BPF_MAP_TYPE_PROG_ARRAY ||
24-
inner_map->map_type == BPF_MAP_TYPE_CGROUP_STORAGE ||
25-
inner_map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE ||
26-
inner_map->map_type == BPF_MAP_TYPE_STRUCT_OPS) {
27-
fdput(f);
28-
return ERR_PTR(-ENOTSUPP);
29-
}
30-
3120
/* Does not support >1 level map-in-map */
3221
if (inner_map->inner_map_meta) {
3322
fdput(f);
3423
return ERR_PTR(-EINVAL);
3524
}
3625

26+
if (!inner_map->ops->map_meta_equal) {
27+
fdput(f);
28+
return ERR_PTR(-ENOTSUPP);
29+
}
30+
3731
if (map_value_has_spin_lock(inner_map)) {
3832
fdput(f);
3933
return ERR_PTR(-ENOTSUPP);
@@ -89,15 +83,16 @@ void *bpf_map_fd_get_ptr(struct bpf_map *map,
8983
struct file *map_file /* not used */,
9084
int ufd)
9185
{
92-
struct bpf_map *inner_map;
86+
struct bpf_map *inner_map, *inner_map_meta;
9387
struct fd f;
9488

9589
f = fdget(ufd);
9690
inner_map = __bpf_map_get(f);
9791
if (IS_ERR(inner_map))
9892
return inner_map;
9993

100-
if (bpf_map_meta_equal(map->inner_map_meta, inner_map))
94+
inner_map_meta = map->inner_map_meta;
95+
if (inner_map_meta->ops->map_meta_equal(inner_map_meta, inner_map))
10196
bpf_map_inc(inner_map);
10297
else
10398
inner_map = ERR_PTR(-EINVAL);

kernel/bpf/map_in_map.h

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

1212
struct bpf_map *bpf_map_meta_alloc(int inner_map_ufd);
1313
void bpf_map_meta_free(struct bpf_map *map_meta);
14-
bool bpf_map_meta_equal(const struct bpf_map *meta0,
15-
const struct bpf_map *meta1);
1614
void *bpf_map_fd_get_ptr(struct bpf_map *map, struct file *map_file,
1715
int ufd);
1816
void bpf_map_fd_put_ptr(void *ptr);

kernel/bpf/queue_stack_maps.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ static int queue_stack_map_get_next_key(struct bpf_map *map, void *key,
257257

258258
static int queue_map_btf_id;
259259
const struct bpf_map_ops queue_map_ops = {
260+
.map_meta_equal = bpf_map_meta_equal,
260261
.map_alloc_check = queue_stack_map_alloc_check,
261262
.map_alloc = queue_stack_map_alloc,
262263
.map_free = queue_stack_map_free,
@@ -273,6 +274,7 @@ const struct bpf_map_ops queue_map_ops = {
273274

274275
static int stack_map_btf_id;
275276
const struct bpf_map_ops stack_map_ops = {
277+
.map_meta_equal = bpf_map_meta_equal,
276278
.map_alloc_check = queue_stack_map_alloc_check,
277279
.map_alloc = queue_stack_map_alloc,
278280
.map_free = queue_stack_map_free,

kernel/bpf/reuseport_array.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,7 @@ static int reuseport_array_get_next_key(struct bpf_map *map, void *key,
351351

352352
static int reuseport_array_map_btf_id;
353353
const struct bpf_map_ops reuseport_array_ops = {
354+
.map_meta_equal = bpf_map_meta_equal,
354355
.map_alloc_check = reuseport_array_alloc_check,
355356
.map_alloc = reuseport_array_alloc,
356357
.map_free = reuseport_array_free,

kernel/bpf/ringbuf.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ static __poll_t ringbuf_map_poll(struct bpf_map *map, struct file *filp,
287287

288288
static int ringbuf_map_btf_id;
289289
const struct bpf_map_ops ringbuf_map_ops = {
290+
.map_meta_equal = bpf_map_meta_equal,
290291
.map_alloc = ringbuf_map_alloc,
291292
.map_free = ringbuf_map_free,
292293
.map_mmap = ringbuf_map_mmap,

kernel/bpf/stackmap.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,7 @@ static void stack_map_free(struct bpf_map *map)
839839

840840
static int stack_trace_map_btf_id;
841841
const struct bpf_map_ops stack_trace_map_ops = {
842+
.map_meta_equal = bpf_map_meta_equal,
842843
.map_alloc = stack_map_alloc,
843844
.map_free = stack_map_free,
844845
.map_get_next_key = stack_map_get_next_key,

kernel/bpf/syscall.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ int bpf_check_uarg_tail_zero(void __user *uaddr,
9090
}
9191

9292
const struct bpf_map_ops bpf_map_offload_ops = {
93+
.map_meta_equal = bpf_map_meta_equal,
9394
.map_alloc = bpf_map_offload_map_alloc,
9495
.map_free = bpf_map_offload_map_free,
9596
.map_check_btf = map_check_no_btf,

net/core/bpf_sk_storage.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ sk_storage_ptr(void *owner)
335335

336336
static int sk_storage_map_btf_id;
337337
const struct bpf_map_ops sk_storage_map_ops = {
338+
.map_meta_equal = bpf_map_meta_equal,
338339
.map_alloc_check = bpf_local_storage_map_alloc_check,
339340
.map_alloc = sk_storage_map_alloc,
340341
.map_free = sk_storage_map_free,

net/core/sock_map.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,7 @@ const struct bpf_func_proto bpf_msg_redirect_map_proto = {
705705

706706
static int sock_map_btf_id;
707707
const struct bpf_map_ops sock_map_ops = {
708+
.map_meta_equal = bpf_map_meta_equal,
708709
.map_alloc = sock_map_alloc,
709710
.map_free = sock_map_free,
710711
.map_get_next_key = sock_map_get_next_key,
@@ -1200,6 +1201,7 @@ const struct bpf_func_proto bpf_msg_redirect_hash_proto = {
12001201

12011202
static int sock_hash_map_btf_id;
12021203
const struct bpf_map_ops sock_hash_ops = {
1204+
.map_meta_equal = bpf_map_meta_equal,
12031205
.map_alloc = sock_hash_alloc,
12041206
.map_free = sock_hash_free,
12051207
.map_get_next_key = sock_hash_get_next_key,

net/xdp/xskmap.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ void xsk_map_try_sock_delete(struct xsk_map *map, struct xdp_sock *xs,
256256

257257
static int xsk_map_btf_id;
258258
const struct bpf_map_ops xsk_map_ops = {
259+
.map_meta_equal = bpf_map_meta_equal,
259260
.map_alloc = xsk_map_alloc,
260261
.map_free = xsk_map_free,
261262
.map_get_next_key = xsk_map_get_next_key,

0 commit comments

Comments
 (0)