diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index a8f1808a1ca5..4891904ee1fc 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -54,7 +54,7 @@ DEFINE_PER_CPU(int, bpf_prog_active); static DEFINE_IDR(prog_idr); static DEFINE_SPINLOCK(prog_idr_lock); static DEFINE_IDR(map_idr); -static DEFINE_SPINLOCK(map_idr_lock); +static DEFINE_RAW_SPINLOCK(map_idr_lock); static DEFINE_IDR(link_idr); static DEFINE_SPINLOCK(link_idr_lock); @@ -352,11 +352,11 @@ static int bpf_map_alloc_id(struct bpf_map *map) int id; idr_preload(GFP_KERNEL); - spin_lock_bh(&map_idr_lock); + raw_spin_lock_bh(&map_idr_lock); id = idr_alloc_cyclic(&map_idr, map, 1, INT_MAX, GFP_ATOMIC); if (id > 0) map->id = id; - spin_unlock_bh(&map_idr_lock); + raw_spin_unlock_bh(&map_idr_lock); idr_preload_end(); if (WARN_ON_ONCE(!id)) @@ -377,12 +377,12 @@ void bpf_map_free_id(struct bpf_map *map) if (!map->id) return; - spin_lock_irqsave(&map_idr_lock, flags); + raw_spin_lock_irqsave(&map_idr_lock, flags); idr_remove(&map_idr, map->id); map->id = 0; - spin_unlock_irqrestore(&map_idr_lock, flags); + raw_spin_unlock_irqrestore(&map_idr_lock, flags); } #ifdef CONFIG_MEMCG @@ -1479,9 +1479,9 @@ struct bpf_map *__bpf_map_inc_not_zero(struct bpf_map *map, bool uref) struct bpf_map *bpf_map_inc_not_zero(struct bpf_map *map) { - spin_lock_bh(&map_idr_lock); + raw_spin_lock_bh(&map_idr_lock); map = __bpf_map_inc_not_zero(map, false); - spin_unlock_bh(&map_idr_lock); + raw_spin_unlock_bh(&map_idr_lock); return map; } @@ -4278,11 +4278,37 @@ static int bpf_obj_get_next_id(const union bpf_attr *attr, return err; } +static int bpf_obj_get_next_id_raw(const union bpf_attr *attr, + union bpf_attr __user *uattr, + struct idr *idr, + raw_spinlock_t *lock) +{ + u32 next_id = attr->start_id; + int err = 0; + + if (CHECK_ATTR(BPF_OBJ_GET_NEXT_ID) || next_id >= INT_MAX) + return -EINVAL; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + next_id++; + raw_spin_lock_bh(lock); + if (!idr_get_next(idr, &next_id)) + err = -ENOENT; + raw_spin_unlock_bh(lock); + + if (!err) + err = put_user(next_id, &uattr->next_id); + + return err; +} + struct bpf_map *bpf_map_get_curr_or_next(u32 *id) { struct bpf_map *map; - spin_lock_bh(&map_idr_lock); + raw_spin_lock_bh(&map_idr_lock); again: map = idr_get_next(&map_idr, id); if (map) { @@ -4292,7 +4318,7 @@ struct bpf_map *bpf_map_get_curr_or_next(u32 *id) goto again; } } - spin_unlock_bh(&map_idr_lock); + raw_spin_unlock_bh(&map_idr_lock); return map; } @@ -4378,13 +4404,13 @@ static int bpf_map_get_fd_by_id(const union bpf_attr *attr) if (f_flags < 0) return f_flags; - spin_lock_bh(&map_idr_lock); + raw_spin_lock_bh(&map_idr_lock); map = idr_find(&map_idr, id); if (map) map = __bpf_map_inc_not_zero(map, true); else map = ERR_PTR(-ENOENT); - spin_unlock_bh(&map_idr_lock); + raw_spin_unlock_bh(&map_idr_lock); if (IS_ERR(map)) return PTR_ERR(map); @@ -5656,7 +5682,7 @@ static int __sys_bpf(enum bpf_cmd cmd, bpfptr_t uattr, unsigned int size) &prog_idr, &prog_idr_lock); break; case BPF_MAP_GET_NEXT_ID: - err = bpf_obj_get_next_id(&attr, uattr.user, + err = bpf_obj_get_next_id_raw(&attr, uattr.user, &map_idr, &map_idr_lock); break; case BPF_BTF_GET_NEXT_ID: