bpf: use kvmalloc for map values in syscall
Subsystems (4)
PATCH v3 1/2 bpf: use kvmalloc for map values in syscall
Use kvmalloc/kvfree for temporary value when manipulating a map via syscall. kmalloc might not be sufficient for percpu maps where the value is big (and further multiplied by hundreds of CPUs).
Can be reproduced with netcnt test on qemu with "-smp 255".
--- kernel/bpf/syscall.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-)
kernel/bpf/syscall.c +11 -17
@@ -1076,7 +1076,7 @@ static int map_lookup_elem(union bpf_attr *attr) value_size =bpf_map_value_size (map); err = -ENOMEM ; - value =kmalloc (value_size,GFP_USER | __GFP_NOWARN); + value =kvmalloc (value_size,GFP_USER | __GFP_NOWARN);if (!value) goto free_key;
@@ -1091,7 +1091,7 @@ static int map_lookup_elem(union bpf_attr *attr) err =0 ; free_value: -kfree (value); +kvfree (value); free_key:kfree (key); err_put:
@@ -1137,16 +1137,10 @@ static int map_update_elem(union bpf_attr *attr, bpfptr_t uattr) goto err_put; } -if (map->map_type ==BPF_MAP_TYPE_PERCPU_HASH || - map->map_type ==BPF_MAP_TYPE_LRU_PERCPU_HASH || - map->map_type ==BPF_MAP_TYPE_PERCPU_ARRAY || - map->map_type ==BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE ) - value_size =round_up (map->value_size,8 ) *num_possible_cpus (); -else - value_size = map->value_size; + value_size =bpf_map_value_size (map); err = -ENOMEM ; - value =kmalloc (value_size,GFP_USER | __GFP_NOWARN); + value =kvmalloc (value_size,GFP_USER | __GFP_NOWARN);if (!value) goto free_key;
@@ -1157,7 +1151,7 @@ static int map_update_elem(union bpf_attr *attr, bpfptr_t uattr) err =bpf_map_update_value (map, f, key, value, attr->flags); free_value: -kfree (value); +kvfree (value); free_key:kfree (key); err_put:
@@ -1367,7 +1361,7 @@ int generic_map_update_batch(struct bpf_map *map,if (!key)return -ENOMEM ; - value =kmalloc (value_size,GFP_USER | __GFP_NOWARN); + value =kvmalloc (value_size,GFP_USER | __GFP_NOWARN);if (!value) {kfree (key);return -ENOMEM ;
@@ -1390,7 +1384,7 @@ int generic_map_update_batch(struct bpf_map *map,if (copy_to_user (&uattr->batch.count, &cp,sizeof (cp))) err = -EFAULT ; -kfree (value); +kvfree (value);kfree (key);return err; }
@@ -1429,7 +1423,7 @@ int generic_map_lookup_batch(struct bpf_map *map,if (!buf_prevkey)return -ENOMEM ; - buf =kmalloc (map->key_size + value_size,GFP_USER | __GFP_NOWARN); + buf =kvmalloc (map->key_size + value_size,GFP_USER | __GFP_NOWARN);if (!buf) {kfree (buf_prevkey);return -ENOMEM ;
@@ -1492,7 +1486,7 @@ int generic_map_lookup_batch(struct bpf_map *map, free_buf:kfree (buf_prevkey); -kfree (buf); +kvfree (buf);return err; }
@@ -1547,7 +1541,7 @@ static int map_lookup_and_delete_elem(union bpf_attr *attr) value_size =bpf_map_value_size (map); err = -ENOMEM ; - value =kmalloc (value_size,GFP_USER | __GFP_NOWARN); + value =kvmalloc (value_size,GFP_USER | __GFP_NOWARN);if (!value) goto free_key;
@@ -1579,7 +1573,7 @@ static int map_lookup_and_delete_elem(union bpf_attr *attr) err =0 ; free_value: -kfree (value); +kvfree (value); free_key:kfree (key); err_put:
Signature · 1 line
2.33.0.rc2.250.ged5fa647cd-goog
PATCH v3 2/2 bpf: use kvmalloc for map keys in syscalls
Same as previous patch but for the keys. memdup_bpfptr is renamed to kvmemdup_bpfptr (and converted to kvmalloc).
v3:
* kvmemdup_bpfptr and copy_from_bpfptr (Daniel Borkmann)
--- include/linux/bpfptr.h | 12 ++++++++++-- kernel/bpf/syscall.c | 34 +++++++++++++++++----------------- 2 files changed, 27 insertions(+), 19 deletions(-)
include/linux/bpfptr.h +10 -2
@@ -62,9 +62,17 @@ static inline int copy_to_bpfptr_offset(bpfptr_t dst, size_t offset,return copy_to_sockptr_offset ((sockptr_t ) dst, offset, src, size); } -static inline void *memdup_bpfptr (bpfptr_t src,size_t len) +static inline void *kvmemdup_bpfptr (bpfptr_t src,size_t len) { -return memdup_sockptr ((sockptr_t ) src, len); +void *p =kvmalloc (len,GFP_USER | __GFP_NOWARN); + +if (!p) +return ERR_PTR (-ENOMEM ); +if (copy_from_bpfptr (p, src, len)) { +kvfree (p); +return ERR_PTR (-EFAULT ); + } +return p; }static inline long strncpy_from_bpfptr (char *dst,bpfptr_t src,size_t count)
kernel/bpf/syscall.c +17 -17
@@ -1013,7 +1013,7 @@ int __weak bpf_stackmap_copy(struct bpf_map *map, void *key, void *value)static void *__bpf_copy_key (void __user *ukey,u64 key_size) {if (key_size) -return memdup_user (ukey, key_size); +return vmemdup_user (ukey, key_size);if (ukey)return ERR_PTR (-EINVAL );
@@ -1024,7 +1024,7 @@ static void *__bpf_copy_key(void __user *ukey, u64 key_size)static void *___bpf_copy_key (bpfptr_t ukey,u64 key_size) {if (key_size) -return memdup_bpfptr (ukey, key_size); +return kvmemdup_bpfptr (ukey, key_size);if (!bpfptr_is_null (ukey))return ERR_PTR (-EINVAL );
@@ -1093,7 +1093,7 @@ static int map_lookup_elem(union bpf_attr *attr) free_value:kvfree (value); free_key: -kfree (key); +kvfree (key); err_put:fdput (f);return err;
@@ -1153,7 +1153,7 @@ static int map_update_elem(union bpf_attr *attr, bpfptr_t uattr) free_value:kvfree (value); free_key: -kfree (key); +kvfree (key); err_put:fdput (f);return err;
@@ -1205,7 +1205,7 @@ static int map_delete_elem(union bpf_attr *attr)bpf_enable_instrumentation ();maybe_wait_bpf_programs (map); out: -kfree (key); +kvfree (key); err_put:fdput (f);return err;
@@ -1247,7 +1247,7 @@ static int map_get_next_key(union bpf_attr *attr) } err = -ENOMEM ; - next_key =kmalloc (map->key_size,GFP_USER ); + next_key =kvmalloc (map->key_size,GFP_USER );if (!next_key) goto free_key;
@@ -1270,9 +1270,9 @@ static int map_get_next_key(union bpf_attr *attr) err =0 ; free_next_key: -kfree (next_key); +kvfree (next_key); free_key: -kfree (key); +kvfree (key); err_put:fdput (f);return err;
@@ -1299,7 +1299,7 @@ int generic_map_delete_batch(struct bpf_map *map,if (!max_count)return 0 ; - key =kmalloc (map->key_size,GFP_USER | __GFP_NOWARN); + key =kvmalloc (map->key_size,GFP_USER | __GFP_NOWARN);if (!key)return -ENOMEM ;
@@ -1326,7 +1326,7 @@ int generic_map_delete_batch(struct bpf_map *map,if (copy_to_user (&uattr->batch.count, &cp,sizeof (cp))) err = -EFAULT ; -kfree (key); +kvfree (key);return err; }
@@ -1357,13 +1357,13 @@ int generic_map_update_batch(struct bpf_map *map,if (!max_count)return 0 ; - key =kmalloc (map->key_size,GFP_USER | __GFP_NOWARN); + key =kvmalloc (map->key_size,GFP_USER | __GFP_NOWARN);if (!key)return -ENOMEM ; value =kvmalloc (value_size,GFP_USER | __GFP_NOWARN);if (!value) { -kfree (key); +kvfree (key);return -ENOMEM ; }
@@ -1385,7 +1385,7 @@ int generic_map_update_batch(struct bpf_map *map, err = -EFAULT ;kvfree (value); -kfree (key); +kvfree (key);return err; }
@@ -1419,13 +1419,13 @@ int generic_map_lookup_batch(struct bpf_map *map,if (put_user (0 , &uattr->batch.count))return -EFAULT ; - buf_prevkey =kmalloc (map->key_size,GFP_USER | __GFP_NOWARN); + buf_prevkey =kvmalloc (map->key_size,GFP_USER | __GFP_NOWARN);if (!buf_prevkey)return -ENOMEM ; buf =kvmalloc (map->key_size + value_size,GFP_USER | __GFP_NOWARN);if (!buf) { -kfree (buf_prevkey); +kvfree (buf_prevkey);return -ENOMEM ; }
@@ -1485,7 +1485,7 @@ int generic_map_lookup_batch(struct bpf_map *map, err = -EFAULT ; free_buf: -kfree (buf_prevkey); +kvfree (buf_prevkey);kvfree (buf);return err; }
@@ -1575,7 +1575,7 @@ static int map_lookup_and_delete_elem(union bpf_attr *attr) free_value:kvfree (value); free_key: -kfree (key); +kvfree (key); err_put:fdput (f);return err;
Signature · 1 line
2.33.0.rc2.250.ged5fa647cd-goog
This series was applied to bpf/bpf-next.git (refs/heads/master):
Hello:
This series was applied to bpf/bpf-next.git (refs/heads/master):
Quoted 10 lines · On Wed, 18 Aug 2021 16:52:15 -0700 you wrote:
Use kvmalloc/kvfree for temporary value when manipulating a map via syscall. kmalloc might not be sufficient for percpu maps where the value is big (and further multiplied by hundreds of CPUs).
Can be reproduced with netcnt test on qemu with "-smp 255".
Signed-off-by Stanislav Fomichev <[email protected]>Acked-by Song Liu <[email protected]>[...]
Here is the summary with links:
- [bpf-next,v3,1/2] bpf: use kvmalloc for map values in syscall
https://git.kernel.org/bpf/bpf-next/c/f0dce1d9b7c8 - [bpf-next,v3,2/2] bpf: use kvmalloc for map keys in syscalls https://git.kernel.org/bpf/bpf-next/c/44779a4b85ab
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html