Skip to content

Commit f45d5b6

Browse files
tohojoAlexei Starovoitov
authored andcommitted
bpf: generalise tail call map compatibility check
The check for tail call map compatibility ensures that tail calls only happen between maps of the same type. To ensure backwards compatibility for XDP frags we need a similar type of check for cpumap and devmap programs, so move the state from bpf_array_aux into bpf_map, add xdp_has_frags to the check, and apply the same check to cpumap and devmap. Acked-by: John Fastabend <[email protected]> Co-developed-by: Lorenzo Bianconi <[email protected]> Signed-off-by: Lorenzo Bianconi <[email protected]> Signed-off-by: Toke Hoiland-Jorgensen <[email protected]> Link: https://lore.kernel.org/r/f19fd97c0328a39927f3ad03e1ca6b43fd53cdfd.1642758637.git.lorenzo@kernel.org Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 082c4bf commit f45d5b6

File tree

6 files changed

+48
-40
lines changed

6 files changed

+48
-40
lines changed

include/linux/bpf.h

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,17 @@ struct bpf_map {
194194
struct work_struct work;
195195
struct mutex freeze_mutex;
196196
atomic64_t writecnt;
197+
/* 'Ownership' of program-containing map is claimed by the first program
198+
* that is going to use this map or by the first program which FD is
199+
* stored in the map to make sure that all callers and callees have the
200+
* same prog type, JITed flag and xdp_has_frags flag.
201+
*/
202+
struct {
203+
spinlock_t lock;
204+
enum bpf_prog_type type;
205+
bool jited;
206+
bool xdp_has_frags;
207+
} owner;
197208
};
198209

199210
static inline bool map_value_has_spin_lock(const struct bpf_map *map)
@@ -994,16 +1005,6 @@ struct bpf_prog_aux {
9941005
};
9951006

9961007
struct bpf_array_aux {
997-
/* 'Ownership' of prog array is claimed by the first program that
998-
* is going to use this map or by the first program which FD is
999-
* stored in the map to make sure that all callers and callees have
1000-
* the same prog type and JITed flag.
1001-
*/
1002-
struct {
1003-
spinlock_t lock;
1004-
enum bpf_prog_type type;
1005-
bool jited;
1006-
} owner;
10071008
/* Programs with direct jumps into programs part of this array. */
10081009
struct list_head poke_progs;
10091010
struct bpf_map *map;
@@ -1178,7 +1179,14 @@ struct bpf_event_entry {
11781179
struct rcu_head rcu;
11791180
};
11801181

1181-
bool bpf_prog_array_compatible(struct bpf_array *array, const struct bpf_prog *fp);
1182+
static inline bool map_type_contains_progs(struct bpf_map *map)
1183+
{
1184+
return map->map_type == BPF_MAP_TYPE_PROG_ARRAY ||
1185+
map->map_type == BPF_MAP_TYPE_DEVMAP ||
1186+
map->map_type == BPF_MAP_TYPE_CPUMAP;
1187+
}
1188+
1189+
bool bpf_prog_map_compatible(struct bpf_map *map, const struct bpf_prog *fp);
11821190
int bpf_prog_calc_tag(struct bpf_prog *fp);
11831191

11841192
const struct bpf_func_proto *bpf_get_trace_printk_proto(void);

kernel/bpf/arraymap.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -837,13 +837,12 @@ static int fd_array_map_delete_elem(struct bpf_map *map, void *key)
837837
static void *prog_fd_array_get_ptr(struct bpf_map *map,
838838
struct file *map_file, int fd)
839839
{
840-
struct bpf_array *array = container_of(map, struct bpf_array, map);
841840
struct bpf_prog *prog = bpf_prog_get(fd);
842841

843842
if (IS_ERR(prog))
844843
return prog;
845844

846-
if (!bpf_prog_array_compatible(array, prog)) {
845+
if (!bpf_prog_map_compatible(map, prog)) {
847846
bpf_prog_put(prog);
848847
return ERR_PTR(-EINVAL);
849848
}
@@ -1071,7 +1070,6 @@ static struct bpf_map *prog_array_map_alloc(union bpf_attr *attr)
10711070
INIT_WORK(&aux->work, prog_array_map_clear_deferred);
10721071
INIT_LIST_HEAD(&aux->poke_progs);
10731072
mutex_init(&aux->poke_mutex);
1074-
spin_lock_init(&aux->owner.lock);
10751073

10761074
map = array_map_alloc(attr);
10771075
if (IS_ERR(map)) {

kernel/bpf/core.c

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1829,28 +1829,30 @@ static unsigned int __bpf_prog_ret0_warn(const void *ctx,
18291829
}
18301830
#endif
18311831

1832-
bool bpf_prog_array_compatible(struct bpf_array *array,
1833-
const struct bpf_prog *fp)
1832+
bool bpf_prog_map_compatible(struct bpf_map *map,
1833+
const struct bpf_prog *fp)
18341834
{
18351835
bool ret;
18361836

18371837
if (fp->kprobe_override)
18381838
return false;
18391839

1840-
spin_lock(&array->aux->owner.lock);
1841-
1842-
if (!array->aux->owner.type) {
1840+
spin_lock(&map->owner.lock);
1841+
if (!map->owner.type) {
18431842
/* There's no owner yet where we could check for
18441843
* compatibility.
18451844
*/
1846-
array->aux->owner.type = fp->type;
1847-
array->aux->owner.jited = fp->jited;
1845+
map->owner.type = fp->type;
1846+
map->owner.jited = fp->jited;
1847+
map->owner.xdp_has_frags = fp->aux->xdp_has_frags;
18481848
ret = true;
18491849
} else {
1850-
ret = array->aux->owner.type == fp->type &&
1851-
array->aux->owner.jited == fp->jited;
1850+
ret = map->owner.type == fp->type &&
1851+
map->owner.jited == fp->jited &&
1852+
map->owner.xdp_has_frags == fp->aux->xdp_has_frags;
18521853
}
1853-
spin_unlock(&array->aux->owner.lock);
1854+
spin_unlock(&map->owner.lock);
1855+
18541856
return ret;
18551857
}
18561858

@@ -1862,13 +1864,11 @@ static int bpf_check_tail_call(const struct bpf_prog *fp)
18621864
mutex_lock(&aux->used_maps_mutex);
18631865
for (i = 0; i < aux->used_map_cnt; i++) {
18641866
struct bpf_map *map = aux->used_maps[i];
1865-
struct bpf_array *array;
18661867

1867-
if (map->map_type != BPF_MAP_TYPE_PROG_ARRAY)
1868+
if (!map_type_contains_progs(map))
18681869
continue;
18691870

1870-
array = container_of(map, struct bpf_array, map);
1871-
if (!bpf_prog_array_compatible(array, fp)) {
1871+
if (!bpf_prog_map_compatible(map, fp)) {
18721872
ret = -EINVAL;
18731873
goto out;
18741874
}

kernel/bpf/cpumap.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -397,15 +397,17 @@ static int cpu_map_kthread_run(void *data)
397397
return 0;
398398
}
399399

400-
static int __cpu_map_load_bpf_program(struct bpf_cpu_map_entry *rcpu, int fd)
400+
static int __cpu_map_load_bpf_program(struct bpf_cpu_map_entry *rcpu,
401+
struct bpf_map *map, int fd)
401402
{
402403
struct bpf_prog *prog;
403404

404405
prog = bpf_prog_get_type(fd, BPF_PROG_TYPE_XDP);
405406
if (IS_ERR(prog))
406407
return PTR_ERR(prog);
407408

408-
if (prog->expected_attach_type != BPF_XDP_CPUMAP) {
409+
if (prog->expected_attach_type != BPF_XDP_CPUMAP ||
410+
!bpf_prog_map_compatible(map, prog)) {
409411
bpf_prog_put(prog);
410412
return -EINVAL;
411413
}
@@ -457,7 +459,7 @@ __cpu_map_entry_alloc(struct bpf_map *map, struct bpf_cpumap_val *value,
457459
rcpu->map_id = map->id;
458460
rcpu->value.qsize = value->qsize;
459461

460-
if (fd > 0 && __cpu_map_load_bpf_program(rcpu, fd))
462+
if (fd > 0 && __cpu_map_load_bpf_program(rcpu, map, fd))
461463
goto free_ptr_ring;
462464

463465
/* Setup kthread */

kernel/bpf/devmap.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -858,7 +858,8 @@ static struct bpf_dtab_netdev *__dev_map_alloc_node(struct net *net,
858858
BPF_PROG_TYPE_XDP, false);
859859
if (IS_ERR(prog))
860860
goto err_put_dev;
861-
if (prog->expected_attach_type != BPF_XDP_DEVMAP)
861+
if (prog->expected_attach_type != BPF_XDP_DEVMAP ||
862+
!bpf_prog_map_compatible(&dtab->map, prog))
862863
goto err_put_prog;
863864
}
864865

kernel/bpf/syscall.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -556,16 +556,14 @@ static unsigned long bpf_map_memory_footprint(const struct bpf_map *map)
556556

557557
static void bpf_map_show_fdinfo(struct seq_file *m, struct file *filp)
558558
{
559-
const struct bpf_map *map = filp->private_data;
560-
const struct bpf_array *array;
559+
struct bpf_map *map = filp->private_data;
561560
u32 type = 0, jited = 0;
562561

563-
if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY) {
564-
array = container_of(map, struct bpf_array, map);
565-
spin_lock(&array->aux->owner.lock);
566-
type = array->aux->owner.type;
567-
jited = array->aux->owner.jited;
568-
spin_unlock(&array->aux->owner.lock);
562+
if (map_type_contains_progs(map)) {
563+
spin_lock(&map->owner.lock);
564+
type = map->owner.type;
565+
jited = map->owner.jited;
566+
spin_unlock(&map->owner.lock);
569567
}
570568

571569
seq_printf(m,
@@ -874,6 +872,7 @@ static int map_create(union bpf_attr *attr)
874872
atomic64_set(&map->refcnt, 1);
875873
atomic64_set(&map->usercnt, 1);
876874
mutex_init(&map->freeze_mutex);
875+
spin_lock_init(&map->owner.lock);
877876

878877
map->spin_lock_off = -EINVAL;
879878
map->timer_off = -EINVAL;

0 commit comments

Comments
 (0)