Skip to content

Commit 984fe94

Browse files
zhuyifei1999Alexei Starovoitov
authored andcommitted
bpf: Mutex protect used_maps array and count
To support modifying the used_maps array, we use a mutex to protect the use of the counter and the array. The mutex is initialized right after the prog aux is allocated, and destroyed right before prog aux is freed. This way we guarantee it's initialized for both cBPF and eBPF. Signed-off-by: YiFei Zhu <[email protected]> Signed-off-by: Stanislav Fomichev <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Acked-by: Andrii Nakryiko <[email protected]> Cc: YiFei Zhu <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent d317b0a commit 984fe94

File tree

5 files changed

+44
-17
lines changed

5 files changed

+44
-17
lines changed

drivers/net/ethernet/netronome/nfp/bpf/offload.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,34 +111,40 @@ static int
111111
nfp_map_ptrs_record(struct nfp_app_bpf *bpf, struct nfp_prog *nfp_prog,
112112
struct bpf_prog *prog)
113113
{
114-
int i, cnt, err;
114+
int i, cnt, err = 0;
115+
116+
mutex_lock(&prog->aux->used_maps_mutex);
115117

116118
/* Quickly count the maps we will have to remember */
117119
cnt = 0;
118120
for (i = 0; i < prog->aux->used_map_cnt; i++)
119121
if (bpf_map_offload_neutral(prog->aux->used_maps[i]))
120122
cnt++;
121123
if (!cnt)
122-
return 0;
124+
goto out;
123125

124126
nfp_prog->map_records = kmalloc_array(cnt,
125127
sizeof(nfp_prog->map_records[0]),
126128
GFP_KERNEL);
127-
if (!nfp_prog->map_records)
128-
return -ENOMEM;
129+
if (!nfp_prog->map_records) {
130+
err = -ENOMEM;
131+
goto out;
132+
}
129133

130134
for (i = 0; i < prog->aux->used_map_cnt; i++)
131135
if (bpf_map_offload_neutral(prog->aux->used_maps[i])) {
132136
err = nfp_map_ptr_record(bpf, nfp_prog,
133137
prog->aux->used_maps[i]);
134138
if (err) {
135139
nfp_map_ptrs_forget(bpf, nfp_prog);
136-
return err;
140+
goto out;
137141
}
138142
}
139143
WARN_ON(cnt != nfp_prog->map_records_cnt);
140144

141-
return 0;
145+
out:
146+
mutex_unlock(&prog->aux->used_maps_mutex);
147+
return err;
142148
}
143149

144150
static int

include/linux/bpf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,7 @@ struct bpf_prog_aux {
751751
struct bpf_ksym ksym;
752752
const struct bpf_prog_ops *ops;
753753
struct bpf_map **used_maps;
754+
struct mutex used_maps_mutex; /* mutex for used_maps and used_map_cnt */
754755
struct bpf_prog *prog;
755756
struct user_struct *user;
756757
u64 load_time; /* ns since boottime */

kernel/bpf/core.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ struct bpf_prog *bpf_prog_alloc_no_stats(unsigned int size, gfp_t gfp_extra_flag
9898
fp->jit_requested = ebpf_jit_enabled();
9999

100100
INIT_LIST_HEAD_RCU(&fp->aux->ksym.lnode);
101+
mutex_init(&fp->aux->used_maps_mutex);
101102

102103
return fp;
103104
}
@@ -253,6 +254,7 @@ struct bpf_prog *bpf_prog_realloc(struct bpf_prog *fp_old, unsigned int size,
253254
void __bpf_prog_free(struct bpf_prog *fp)
254255
{
255256
if (fp->aux) {
257+
mutex_destroy(&fp->aux->used_maps_mutex);
256258
free_percpu(fp->aux->stats);
257259
kfree(fp->aux->poke_tab);
258260
kfree(fp->aux);
@@ -1747,8 +1749,9 @@ bool bpf_prog_array_compatible(struct bpf_array *array,
17471749
static int bpf_check_tail_call(const struct bpf_prog *fp)
17481750
{
17491751
struct bpf_prog_aux *aux = fp->aux;
1750-
int i;
1752+
int i, ret = 0;
17511753

1754+
mutex_lock(&aux->used_maps_mutex);
17521755
for (i = 0; i < aux->used_map_cnt; i++) {
17531756
struct bpf_map *map = aux->used_maps[i];
17541757
struct bpf_array *array;
@@ -1757,11 +1760,15 @@ static int bpf_check_tail_call(const struct bpf_prog *fp)
17571760
continue;
17581761

17591762
array = container_of(map, struct bpf_array, map);
1760-
if (!bpf_prog_array_compatible(array, fp))
1761-
return -EINVAL;
1763+
if (!bpf_prog_array_compatible(array, fp)) {
1764+
ret = -EINVAL;
1765+
goto out;
1766+
}
17621767
}
17631768

1764-
return 0;
1769+
out:
1770+
mutex_unlock(&aux->used_maps_mutex);
1771+
return ret;
17651772
}
17661773

17671774
static void bpf_prog_select_func(struct bpf_prog *fp)

kernel/bpf/syscall.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3162,21 +3162,25 @@ static const struct bpf_map *bpf_map_from_imm(const struct bpf_prog *prog,
31623162
const struct bpf_map *map;
31633163
int i;
31643164

3165+
mutex_lock(&prog->aux->used_maps_mutex);
31653166
for (i = 0, *off = 0; i < prog->aux->used_map_cnt; i++) {
31663167
map = prog->aux->used_maps[i];
31673168
if (map == (void *)addr) {
31683169
*type = BPF_PSEUDO_MAP_FD;
3169-
return map;
3170+
goto out;
31703171
}
31713172
if (!map->ops->map_direct_value_meta)
31723173
continue;
31733174
if (!map->ops->map_direct_value_meta(map, addr, off)) {
31743175
*type = BPF_PSEUDO_MAP_VALUE;
3175-
return map;
3176+
goto out;
31763177
}
31773178
}
3179+
map = NULL;
31783180

3179-
return NULL;
3181+
out:
3182+
mutex_unlock(&prog->aux->used_maps_mutex);
3183+
return map;
31803184
}
31813185

31823186
static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog,
@@ -3294,6 +3298,7 @@ static int bpf_prog_get_info_by_fd(struct file *file,
32943298
memcpy(info.tag, prog->tag, sizeof(prog->tag));
32953299
memcpy(info.name, prog->aux->name, sizeof(prog->aux->name));
32963300

3301+
mutex_lock(&prog->aux->used_maps_mutex);
32973302
ulen = info.nr_map_ids;
32983303
info.nr_map_ids = prog->aux->used_map_cnt;
32993304
ulen = min_t(u32, info.nr_map_ids, ulen);
@@ -3303,9 +3308,12 @@ static int bpf_prog_get_info_by_fd(struct file *file,
33033308

33043309
for (i = 0; i < ulen; i++)
33053310
if (put_user(prog->aux->used_maps[i]->id,
3306-
&user_map_ids[i]))
3311+
&user_map_ids[i])) {
3312+
mutex_unlock(&prog->aux->used_maps_mutex);
33073313
return -EFAULT;
3314+
}
33083315
}
3316+
mutex_unlock(&prog->aux->used_maps_mutex);
33093317

33103318
err = set_info_rec_size(&info);
33113319
if (err)

net/core/dev.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5441,15 +5441,20 @@ static int generic_xdp_install(struct net_device *dev, struct netdev_bpf *xdp)
54415441
if (new) {
54425442
u32 i;
54435443

5444+
mutex_lock(&new->aux->used_maps_mutex);
5445+
54445446
/* generic XDP does not work with DEVMAPs that can
54455447
* have a bpf_prog installed on an entry
54465448
*/
54475449
for (i = 0; i < new->aux->used_map_cnt; i++) {
5448-
if (dev_map_can_have_prog(new->aux->used_maps[i]))
5449-
return -EINVAL;
5450-
if (cpu_map_prog_allowed(new->aux->used_maps[i]))
5450+
if (dev_map_can_have_prog(new->aux->used_maps[i]) ||
5451+
cpu_map_prog_allowed(new->aux->used_maps[i])) {
5452+
mutex_unlock(&new->aux->used_maps_mutex);
54515453
return -EINVAL;
5454+
}
54525455
}
5456+
5457+
mutex_unlock(&new->aux->used_maps_mutex);
54535458
}
54545459

54555460
switch (xdp->command) {

0 commit comments

Comments
 (0)