mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-12 08:09:56 +00:00
bpf: rcu lock must not be held when calling copy_to_user()
BUG: sleeping function called from invalid context at mm/memory.c:3732 in_atomic(): 0, irqs_disabled(): 0, pid: 671, name: test_maps 1 lock held by test_maps/671: #0: (rcu_read_lock){......}, at: [<0000000000264190>] map_lookup_elem+0xe8/0x260 Call Trace: ([<0000000000115b7e>] show_trace+0x12e/0x150) [<0000000000115c40>] show_stack+0xa0/0x100 [<00000000009b163c>] dump_stack+0x74/0xc8 [<000000000017424a>] ___might_sleep+0x23a/0x248 [<00000000002b58e8>] might_fault+0x70/0xe8 [<0000000000264230>] map_lookup_elem+0x188/0x260 [<0000000000264716>] SyS_bpf+0x20e/0x840 Fix it by allocating temporary buffer to store map element value. Fixes: db20fd2b0108 ("bpf: add lookup/update/delete/iterate methods to BPF maps") Reported-by: Michael Holzheu <holzheu@linux.vnet.ibm.com> Signed-off-by: Alexei Starovoitov <ast@plumgrid.com> Acked-by: Daniel Borkmann <dborkman@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
600ddd6825
commit
8ebe667c41
@ -150,7 +150,7 @@ static int map_lookup_elem(union bpf_attr *attr)
|
|||||||
int ufd = attr->map_fd;
|
int ufd = attr->map_fd;
|
||||||
struct fd f = fdget(ufd);
|
struct fd f = fdget(ufd);
|
||||||
struct bpf_map *map;
|
struct bpf_map *map;
|
||||||
void *key, *value;
|
void *key, *value, *ptr;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM))
|
if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM))
|
||||||
@ -169,20 +169,29 @@ static int map_lookup_elem(union bpf_attr *attr)
|
|||||||
if (copy_from_user(key, ukey, map->key_size) != 0)
|
if (copy_from_user(key, ukey, map->key_size) != 0)
|
||||||
goto free_key;
|
goto free_key;
|
||||||
|
|
||||||
err = -ENOENT;
|
err = -ENOMEM;
|
||||||
rcu_read_lock();
|
value = kmalloc(map->value_size, GFP_USER);
|
||||||
value = map->ops->map_lookup_elem(map, key);
|
|
||||||
if (!value)
|
if (!value)
|
||||||
goto err_unlock;
|
goto free_key;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
ptr = map->ops->map_lookup_elem(map, key);
|
||||||
|
if (ptr)
|
||||||
|
memcpy(value, ptr, map->value_size);
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
err = -ENOENT;
|
||||||
|
if (!ptr)
|
||||||
|
goto free_value;
|
||||||
|
|
||||||
err = -EFAULT;
|
err = -EFAULT;
|
||||||
if (copy_to_user(uvalue, value, map->value_size) != 0)
|
if (copy_to_user(uvalue, value, map->value_size) != 0)
|
||||||
goto err_unlock;
|
goto free_value;
|
||||||
|
|
||||||
err = 0;
|
err = 0;
|
||||||
|
|
||||||
err_unlock:
|
free_value:
|
||||||
rcu_read_unlock();
|
kfree(value);
|
||||||
free_key:
|
free_key:
|
||||||
kfree(key);
|
kfree(key);
|
||||||
err_put:
|
err_put:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user