diff options
Diffstat (limited to 'kernel/bpf/syscall.c')
| -rw-r--r-- | kernel/bpf/syscall.c | 25 | 
1 files changed, 17 insertions, 8 deletions
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 088ac0b1b106..536edc2be307 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -150,7 +150,7 @@ static int map_lookup_elem(union bpf_attr *attr)  	int ufd = attr->map_fd;  	struct fd f = fdget(ufd);  	struct bpf_map *map; -	void *key, *value; +	void *key, *value, *ptr;  	int err;  	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)  		goto free_key; -	err = -ENOENT; -	rcu_read_lock(); -	value = map->ops->map_lookup_elem(map, key); +	err = -ENOMEM; +	value = kmalloc(map->value_size, GFP_USER);  	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;  	if (copy_to_user(uvalue, value, map->value_size) != 0) -		goto err_unlock; +		goto free_value;  	err = 0; -err_unlock: -	rcu_read_unlock(); +free_value: +	kfree(value);  free_key:  	kfree(key);  err_put:  | 
