15b497af4SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 299c55f7dSAlexei Starovoitov /* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com 399c55f7dSAlexei Starovoitov */ 499c55f7dSAlexei Starovoitov #include <linux/bpf.h> 5a67edbf4SDaniel Borkmann #include <linux/bpf_trace.h> 6f4364dcfSSean Young #include <linux/bpf_lirc.h> 7f56a653cSMartin KaFai Lau #include <linux/btf.h> 899c55f7dSAlexei Starovoitov #include <linux/syscalls.h> 999c55f7dSAlexei Starovoitov #include <linux/slab.h> 103f07c014SIngo Molnar #include <linux/sched/signal.h> 11d407bd25SDaniel Borkmann #include <linux/vmalloc.h> 12d407bd25SDaniel Borkmann #include <linux/mmzone.h> 1399c55f7dSAlexei Starovoitov #include <linux/anon_inodes.h> 1441bdc4b4SYonghong Song #include <linux/fdtable.h> 15db20fd2bSAlexei Starovoitov #include <linux/file.h> 1641bdc4b4SYonghong Song #include <linux/fs.h> 1709756af4SAlexei Starovoitov #include <linux/license.h> 1809756af4SAlexei Starovoitov #include <linux/filter.h> 192541517cSAlexei Starovoitov #include <linux/version.h> 20535e7b4bSMickaël Salaün #include <linux/kernel.h> 21dc4bb0e2SMartin KaFai Lau #include <linux/idr.h> 22cb4d2b3fSMartin KaFai Lau #include <linux/cred.h> 23cb4d2b3fSMartin KaFai Lau #include <linux/timekeeping.h> 24cb4d2b3fSMartin KaFai Lau #include <linux/ctype.h> 259ef09e35SMark Rutland #include <linux/nospec.h> 26bae141f5SDaniel Borkmann #include <linux/audit.h> 27ccfe29ebSAlexei Starovoitov #include <uapi/linux/btf.h> 289e4e01dfSKP Singh #include <linux/bpf_lsm.h> 2999c55f7dSAlexei Starovoitov 30da765a2fSDaniel Borkmann #define IS_FD_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || \ 3114dc6f04SMartin KaFai Lau (map)->map_type == BPF_MAP_TYPE_CGROUP_ARRAY || \ 3214dc6f04SMartin KaFai Lau (map)->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS) 33da765a2fSDaniel Borkmann #define IS_FD_PROG_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PROG_ARRAY) 3414dc6f04SMartin KaFai Lau #define IS_FD_HASH(map) ((map)->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) 35da765a2fSDaniel Borkmann #define IS_FD_MAP(map) (IS_FD_ARRAY(map) || IS_FD_PROG_ARRAY(map) || \ 36da765a2fSDaniel Borkmann IS_FD_HASH(map)) 3714dc6f04SMartin KaFai Lau 386e71b04aSChenbo Feng #define BPF_OBJ_FLAG_MASK (BPF_F_RDONLY | BPF_F_WRONLY) 396e71b04aSChenbo Feng 40b121d1e7SAlexei Starovoitov DEFINE_PER_CPU(int, bpf_prog_active); 41dc4bb0e2SMartin KaFai Lau static DEFINE_IDR(prog_idr); 42dc4bb0e2SMartin KaFai Lau static DEFINE_SPINLOCK(prog_idr_lock); 43f3f1c054SMartin KaFai Lau static DEFINE_IDR(map_idr); 44f3f1c054SMartin KaFai Lau static DEFINE_SPINLOCK(map_idr_lock); 45b121d1e7SAlexei Starovoitov 461be7f75dSAlexei Starovoitov int sysctl_unprivileged_bpf_disabled __read_mostly; 471be7f75dSAlexei Starovoitov 4840077e0cSJohannes Berg static const struct bpf_map_ops * const bpf_map_types[] = { 4991cc1a99SAlexei Starovoitov #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) 5040077e0cSJohannes Berg #define BPF_MAP_TYPE(_id, _ops) \ 5140077e0cSJohannes Berg [_id] = &_ops, 5240077e0cSJohannes Berg #include <linux/bpf_types.h> 5340077e0cSJohannes Berg #undef BPF_PROG_TYPE 5440077e0cSJohannes Berg #undef BPF_MAP_TYPE 5540077e0cSJohannes Berg }; 5699c55f7dSAlexei Starovoitov 57752ba56fSMickaël Salaün /* 58752ba56fSMickaël Salaün * If we're handed a bigger struct than we know of, ensure all the unknown bits 59752ba56fSMickaël Salaün * are 0 - i.e. new user-space does not rely on any kernel feature extensions 60752ba56fSMickaël Salaün * we don't know about yet. 61752ba56fSMickaël Salaün * 62752ba56fSMickaël Salaün * There is a ToCToU between this function call and the following 63752ba56fSMickaël Salaün * copy_from_user() call. However, this is not a concern since this function is 64752ba56fSMickaël Salaün * meant to be a future-proofing of bits. 65752ba56fSMickaël Salaün */ 66dcab51f1SMartin KaFai Lau int bpf_check_uarg_tail_zero(void __user *uaddr, 6758291a74SMickaël Salaün size_t expected_size, 6858291a74SMickaël Salaün size_t actual_size) 6958291a74SMickaël Salaün { 7058291a74SMickaël Salaün unsigned char __user *addr; 7158291a74SMickaël Salaün unsigned char __user *end; 7258291a74SMickaël Salaün unsigned char val; 7358291a74SMickaël Salaün int err; 7458291a74SMickaël Salaün 75752ba56fSMickaël Salaün if (unlikely(actual_size > PAGE_SIZE)) /* silly large */ 76752ba56fSMickaël Salaün return -E2BIG; 77752ba56fSMickaël Salaün 7896d4f267SLinus Torvalds if (unlikely(!access_ok(uaddr, actual_size))) 79752ba56fSMickaël Salaün return -EFAULT; 80752ba56fSMickaël Salaün 8158291a74SMickaël Salaün if (actual_size <= expected_size) 8258291a74SMickaël Salaün return 0; 8358291a74SMickaël Salaün 8458291a74SMickaël Salaün addr = uaddr + expected_size; 8558291a74SMickaël Salaün end = uaddr + actual_size; 8658291a74SMickaël Salaün 8758291a74SMickaël Salaün for (; addr < end; addr++) { 8858291a74SMickaël Salaün err = get_user(val, addr); 8958291a74SMickaël Salaün if (err) 9058291a74SMickaël Salaün return err; 9158291a74SMickaël Salaün if (val) 9258291a74SMickaël Salaün return -E2BIG; 9358291a74SMickaël Salaün } 9458291a74SMickaël Salaün 9558291a74SMickaël Salaün return 0; 9658291a74SMickaël Salaün } 9758291a74SMickaël Salaün 98a3884572SJakub Kicinski const struct bpf_map_ops bpf_map_offload_ops = { 99a3884572SJakub Kicinski .map_alloc = bpf_map_offload_map_alloc, 100a3884572SJakub Kicinski .map_free = bpf_map_offload_map_free, 101e8d2bec0SDaniel Borkmann .map_check_btf = map_check_no_btf, 102a3884572SJakub Kicinski }; 103a3884572SJakub Kicinski 10499c55f7dSAlexei Starovoitov static struct bpf_map *find_and_alloc_map(union bpf_attr *attr) 10599c55f7dSAlexei Starovoitov { 1061110f3a9SJakub Kicinski const struct bpf_map_ops *ops; 1079ef09e35SMark Rutland u32 type = attr->map_type; 10899c55f7dSAlexei Starovoitov struct bpf_map *map; 1091110f3a9SJakub Kicinski int err; 11099c55f7dSAlexei Starovoitov 1119ef09e35SMark Rutland if (type >= ARRAY_SIZE(bpf_map_types)) 1121110f3a9SJakub Kicinski return ERR_PTR(-EINVAL); 1139ef09e35SMark Rutland type = array_index_nospec(type, ARRAY_SIZE(bpf_map_types)); 1149ef09e35SMark Rutland ops = bpf_map_types[type]; 1151110f3a9SJakub Kicinski if (!ops) 11640077e0cSJohannes Berg return ERR_PTR(-EINVAL); 11740077e0cSJohannes Berg 1181110f3a9SJakub Kicinski if (ops->map_alloc_check) { 1191110f3a9SJakub Kicinski err = ops->map_alloc_check(attr); 1201110f3a9SJakub Kicinski if (err) 1211110f3a9SJakub Kicinski return ERR_PTR(err); 1221110f3a9SJakub Kicinski } 123a3884572SJakub Kicinski if (attr->map_ifindex) 124a3884572SJakub Kicinski ops = &bpf_map_offload_ops; 1251110f3a9SJakub Kicinski map = ops->map_alloc(attr); 12699c55f7dSAlexei Starovoitov if (IS_ERR(map)) 12799c55f7dSAlexei Starovoitov return map; 1281110f3a9SJakub Kicinski map->ops = ops; 1299ef09e35SMark Rutland map->map_type = type; 13099c55f7dSAlexei Starovoitov return map; 13199c55f7dSAlexei Starovoitov } 13299c55f7dSAlexei Starovoitov 13315c14a3dSBrian Vazquez static u32 bpf_map_value_size(struct bpf_map *map) 13415c14a3dSBrian Vazquez { 13515c14a3dSBrian Vazquez if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 13615c14a3dSBrian Vazquez map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH || 13715c14a3dSBrian Vazquez map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY || 13815c14a3dSBrian Vazquez map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) 13915c14a3dSBrian Vazquez return round_up(map->value_size, 8) * num_possible_cpus(); 14015c14a3dSBrian Vazquez else if (IS_FD_MAP(map)) 14115c14a3dSBrian Vazquez return sizeof(u32); 14215c14a3dSBrian Vazquez else 14315c14a3dSBrian Vazquez return map->value_size; 14415c14a3dSBrian Vazquez } 14515c14a3dSBrian Vazquez 14615c14a3dSBrian Vazquez static void maybe_wait_bpf_programs(struct bpf_map *map) 14715c14a3dSBrian Vazquez { 14815c14a3dSBrian Vazquez /* Wait for any running BPF programs to complete so that 14915c14a3dSBrian Vazquez * userspace, when we return to it, knows that all programs 15015c14a3dSBrian Vazquez * that could be running use the new map value. 15115c14a3dSBrian Vazquez */ 15215c14a3dSBrian Vazquez if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS || 15315c14a3dSBrian Vazquez map->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS) 15415c14a3dSBrian Vazquez synchronize_rcu(); 15515c14a3dSBrian Vazquez } 15615c14a3dSBrian Vazquez 15715c14a3dSBrian Vazquez static int bpf_map_update_value(struct bpf_map *map, struct fd f, void *key, 15815c14a3dSBrian Vazquez void *value, __u64 flags) 15915c14a3dSBrian Vazquez { 16015c14a3dSBrian Vazquez int err; 16115c14a3dSBrian Vazquez 16215c14a3dSBrian Vazquez /* Need to create a kthread, thus must support schedule */ 16315c14a3dSBrian Vazquez if (bpf_map_is_dev_bound(map)) { 16415c14a3dSBrian Vazquez return bpf_map_offload_update_elem(map, key, value, flags); 16515c14a3dSBrian Vazquez } else if (map->map_type == BPF_MAP_TYPE_CPUMAP || 16615c14a3dSBrian Vazquez map->map_type == BPF_MAP_TYPE_SOCKHASH || 16715c14a3dSBrian Vazquez map->map_type == BPF_MAP_TYPE_SOCKMAP || 16815c14a3dSBrian Vazquez map->map_type == BPF_MAP_TYPE_STRUCT_OPS) { 16915c14a3dSBrian Vazquez return map->ops->map_update_elem(map, key, value, flags); 17015c14a3dSBrian Vazquez } else if (IS_FD_PROG_ARRAY(map)) { 17115c14a3dSBrian Vazquez return bpf_fd_array_map_update_elem(map, f.file, key, value, 17215c14a3dSBrian Vazquez flags); 17315c14a3dSBrian Vazquez } 17415c14a3dSBrian Vazquez 175b6e5dae1SThomas Gleixner bpf_disable_instrumentation(); 17615c14a3dSBrian Vazquez if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 17715c14a3dSBrian Vazquez map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) { 17815c14a3dSBrian Vazquez err = bpf_percpu_hash_update(map, key, value, flags); 17915c14a3dSBrian Vazquez } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) { 18015c14a3dSBrian Vazquez err = bpf_percpu_array_update(map, key, value, flags); 18115c14a3dSBrian Vazquez } else if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) { 18215c14a3dSBrian Vazquez err = bpf_percpu_cgroup_storage_update(map, key, value, 18315c14a3dSBrian Vazquez flags); 18415c14a3dSBrian Vazquez } else if (IS_FD_ARRAY(map)) { 18515c14a3dSBrian Vazquez rcu_read_lock(); 18615c14a3dSBrian Vazquez err = bpf_fd_array_map_update_elem(map, f.file, key, value, 18715c14a3dSBrian Vazquez flags); 18815c14a3dSBrian Vazquez rcu_read_unlock(); 18915c14a3dSBrian Vazquez } else if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) { 19015c14a3dSBrian Vazquez rcu_read_lock(); 19115c14a3dSBrian Vazquez err = bpf_fd_htab_map_update_elem(map, f.file, key, value, 19215c14a3dSBrian Vazquez flags); 19315c14a3dSBrian Vazquez rcu_read_unlock(); 19415c14a3dSBrian Vazquez } else if (map->map_type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY) { 19515c14a3dSBrian Vazquez /* rcu_read_lock() is not needed */ 19615c14a3dSBrian Vazquez err = bpf_fd_reuseport_array_update_elem(map, key, value, 19715c14a3dSBrian Vazquez flags); 19815c14a3dSBrian Vazquez } else if (map->map_type == BPF_MAP_TYPE_QUEUE || 19915c14a3dSBrian Vazquez map->map_type == BPF_MAP_TYPE_STACK) { 20015c14a3dSBrian Vazquez err = map->ops->map_push_elem(map, value, flags); 20115c14a3dSBrian Vazquez } else { 20215c14a3dSBrian Vazquez rcu_read_lock(); 20315c14a3dSBrian Vazquez err = map->ops->map_update_elem(map, key, value, flags); 20415c14a3dSBrian Vazquez rcu_read_unlock(); 20515c14a3dSBrian Vazquez } 206b6e5dae1SThomas Gleixner bpf_enable_instrumentation(); 20715c14a3dSBrian Vazquez maybe_wait_bpf_programs(map); 20815c14a3dSBrian Vazquez 20915c14a3dSBrian Vazquez return err; 21015c14a3dSBrian Vazquez } 21115c14a3dSBrian Vazquez 21215c14a3dSBrian Vazquez static int bpf_map_copy_value(struct bpf_map *map, void *key, void *value, 21315c14a3dSBrian Vazquez __u64 flags) 21415c14a3dSBrian Vazquez { 21515c14a3dSBrian Vazquez void *ptr; 21615c14a3dSBrian Vazquez int err; 21715c14a3dSBrian Vazquez 218cb4d03abSBrian Vazquez if (bpf_map_is_dev_bound(map)) 219cb4d03abSBrian Vazquez return bpf_map_offload_lookup_elem(map, key, value); 22015c14a3dSBrian Vazquez 221b6e5dae1SThomas Gleixner bpf_disable_instrumentation(); 22215c14a3dSBrian Vazquez if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 22315c14a3dSBrian Vazquez map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) { 22415c14a3dSBrian Vazquez err = bpf_percpu_hash_copy(map, key, value); 22515c14a3dSBrian Vazquez } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) { 22615c14a3dSBrian Vazquez err = bpf_percpu_array_copy(map, key, value); 22715c14a3dSBrian Vazquez } else if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) { 22815c14a3dSBrian Vazquez err = bpf_percpu_cgroup_storage_copy(map, key, value); 22915c14a3dSBrian Vazquez } else if (map->map_type == BPF_MAP_TYPE_STACK_TRACE) { 23015c14a3dSBrian Vazquez err = bpf_stackmap_copy(map, key, value); 23115c14a3dSBrian Vazquez } else if (IS_FD_ARRAY(map) || IS_FD_PROG_ARRAY(map)) { 23215c14a3dSBrian Vazquez err = bpf_fd_array_map_lookup_elem(map, key, value); 23315c14a3dSBrian Vazquez } else if (IS_FD_HASH(map)) { 23415c14a3dSBrian Vazquez err = bpf_fd_htab_map_lookup_elem(map, key, value); 23515c14a3dSBrian Vazquez } else if (map->map_type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY) { 23615c14a3dSBrian Vazquez err = bpf_fd_reuseport_array_lookup_elem(map, key, value); 23715c14a3dSBrian Vazquez } else if (map->map_type == BPF_MAP_TYPE_QUEUE || 23815c14a3dSBrian Vazquez map->map_type == BPF_MAP_TYPE_STACK) { 23915c14a3dSBrian Vazquez err = map->ops->map_peek_elem(map, value); 24015c14a3dSBrian Vazquez } else if (map->map_type == BPF_MAP_TYPE_STRUCT_OPS) { 24115c14a3dSBrian Vazquez /* struct_ops map requires directly updating "value" */ 24215c14a3dSBrian Vazquez err = bpf_struct_ops_map_sys_lookup_elem(map, key, value); 24315c14a3dSBrian Vazquez } else { 24415c14a3dSBrian Vazquez rcu_read_lock(); 24515c14a3dSBrian Vazquez if (map->ops->map_lookup_elem_sys_only) 24615c14a3dSBrian Vazquez ptr = map->ops->map_lookup_elem_sys_only(map, key); 24715c14a3dSBrian Vazquez else 24815c14a3dSBrian Vazquez ptr = map->ops->map_lookup_elem(map, key); 24915c14a3dSBrian Vazquez if (IS_ERR(ptr)) { 25015c14a3dSBrian Vazquez err = PTR_ERR(ptr); 25115c14a3dSBrian Vazquez } else if (!ptr) { 25215c14a3dSBrian Vazquez err = -ENOENT; 25315c14a3dSBrian Vazquez } else { 25415c14a3dSBrian Vazquez err = 0; 25515c14a3dSBrian Vazquez if (flags & BPF_F_LOCK) 25615c14a3dSBrian Vazquez /* lock 'ptr' and copy everything but lock */ 25715c14a3dSBrian Vazquez copy_map_value_locked(map, value, ptr, true); 25815c14a3dSBrian Vazquez else 25915c14a3dSBrian Vazquez copy_map_value(map, value, ptr); 26015c14a3dSBrian Vazquez /* mask lock, since value wasn't zero inited */ 26115c14a3dSBrian Vazquez check_and_init_map_lock(map, value); 26215c14a3dSBrian Vazquez } 26315c14a3dSBrian Vazquez rcu_read_unlock(); 26415c14a3dSBrian Vazquez } 26515c14a3dSBrian Vazquez 266b6e5dae1SThomas Gleixner bpf_enable_instrumentation(); 26715c14a3dSBrian Vazquez maybe_wait_bpf_programs(map); 26815c14a3dSBrian Vazquez 26915c14a3dSBrian Vazquez return err; 27015c14a3dSBrian Vazquez } 27115c14a3dSBrian Vazquez 272196e8ca7SDaniel Borkmann static void *__bpf_map_area_alloc(u64 size, int numa_node, bool mmapable) 273d407bd25SDaniel Borkmann { 274f01a7dbeSMartynas Pumputis /* We really just want to fail instead of triggering OOM killer 275f01a7dbeSMartynas Pumputis * under memory pressure, therefore we set __GFP_NORETRY to kmalloc, 276f01a7dbeSMartynas Pumputis * which is used for lower order allocation requests. 277f01a7dbeSMartynas Pumputis * 278f01a7dbeSMartynas Pumputis * It has been observed that higher order allocation requests done by 279f01a7dbeSMartynas Pumputis * vmalloc with __GFP_NORETRY being set might fail due to not trying 280f01a7dbeSMartynas Pumputis * to reclaim memory from the page cache, thus we set 281f01a7dbeSMartynas Pumputis * __GFP_RETRY_MAYFAIL to avoid such situations. 282d407bd25SDaniel Borkmann */ 283f01a7dbeSMartynas Pumputis 284f01a7dbeSMartynas Pumputis const gfp_t flags = __GFP_NOWARN | __GFP_ZERO; 285d407bd25SDaniel Borkmann void *area; 286d407bd25SDaniel Borkmann 287196e8ca7SDaniel Borkmann if (size >= SIZE_MAX) 288196e8ca7SDaniel Borkmann return NULL; 289196e8ca7SDaniel Borkmann 290fc970227SAndrii Nakryiko /* kmalloc()'ed memory can't be mmap()'ed */ 291fc970227SAndrii Nakryiko if (!mmapable && size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) { 292f01a7dbeSMartynas Pumputis area = kmalloc_node(size, GFP_USER | __GFP_NORETRY | flags, 293f01a7dbeSMartynas Pumputis numa_node); 294d407bd25SDaniel Borkmann if (area != NULL) 295d407bd25SDaniel Borkmann return area; 296d407bd25SDaniel Borkmann } 297fc970227SAndrii Nakryiko if (mmapable) { 298fc970227SAndrii Nakryiko BUG_ON(!PAGE_ALIGNED(size)); 299fc970227SAndrii Nakryiko return vmalloc_user_node_flags(size, numa_node, GFP_KERNEL | 300fc970227SAndrii Nakryiko __GFP_RETRY_MAYFAIL | flags); 301fc970227SAndrii Nakryiko } 302f01a7dbeSMartynas Pumputis return __vmalloc_node_flags_caller(size, numa_node, 303f01a7dbeSMartynas Pumputis GFP_KERNEL | __GFP_RETRY_MAYFAIL | 304f01a7dbeSMartynas Pumputis flags, __builtin_return_address(0)); 305d407bd25SDaniel Borkmann } 306d407bd25SDaniel Borkmann 307196e8ca7SDaniel Borkmann void *bpf_map_area_alloc(u64 size, int numa_node) 308fc970227SAndrii Nakryiko { 309fc970227SAndrii Nakryiko return __bpf_map_area_alloc(size, numa_node, false); 310fc970227SAndrii Nakryiko } 311fc970227SAndrii Nakryiko 312196e8ca7SDaniel Borkmann void *bpf_map_area_mmapable_alloc(u64 size, int numa_node) 313fc970227SAndrii Nakryiko { 314fc970227SAndrii Nakryiko return __bpf_map_area_alloc(size, numa_node, true); 315fc970227SAndrii Nakryiko } 316fc970227SAndrii Nakryiko 317d407bd25SDaniel Borkmann void bpf_map_area_free(void *area) 318d407bd25SDaniel Borkmann { 319d407bd25SDaniel Borkmann kvfree(area); 320d407bd25SDaniel Borkmann } 321d407bd25SDaniel Borkmann 322be70bcd5SDaniel Borkmann static u32 bpf_map_flags_retain_permanent(u32 flags) 323be70bcd5SDaniel Borkmann { 324be70bcd5SDaniel Borkmann /* Some map creation flags are not tied to the map object but 325be70bcd5SDaniel Borkmann * rather to the map fd instead, so they have no meaning upon 326be70bcd5SDaniel Borkmann * map object inspection since multiple file descriptors with 327be70bcd5SDaniel Borkmann * different (access) properties can exist here. Thus, given 328be70bcd5SDaniel Borkmann * this has zero meaning for the map itself, lets clear these 329be70bcd5SDaniel Borkmann * from here. 330be70bcd5SDaniel Borkmann */ 331be70bcd5SDaniel Borkmann return flags & ~(BPF_F_RDONLY | BPF_F_WRONLY); 332be70bcd5SDaniel Borkmann } 333be70bcd5SDaniel Borkmann 334bd475643SJakub Kicinski void bpf_map_init_from_attr(struct bpf_map *map, union bpf_attr *attr) 335bd475643SJakub Kicinski { 336bd475643SJakub Kicinski map->map_type = attr->map_type; 337bd475643SJakub Kicinski map->key_size = attr->key_size; 338bd475643SJakub Kicinski map->value_size = attr->value_size; 339bd475643SJakub Kicinski map->max_entries = attr->max_entries; 340be70bcd5SDaniel Borkmann map->map_flags = bpf_map_flags_retain_permanent(attr->map_flags); 341bd475643SJakub Kicinski map->numa_node = bpf_map_attr_numa_node(attr); 342bd475643SJakub Kicinski } 343bd475643SJakub Kicinski 3440a4c58f5SRoman Gushchin static int bpf_charge_memlock(struct user_struct *user, u32 pages) 345aaac3ba9SAlexei Starovoitov { 3460a4c58f5SRoman Gushchin unsigned long memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; 347aaac3ba9SAlexei Starovoitov 3480a4c58f5SRoman Gushchin if (atomic_long_add_return(pages, &user->locked_vm) > memlock_limit) { 3490a4c58f5SRoman Gushchin atomic_long_sub(pages, &user->locked_vm); 350aaac3ba9SAlexei Starovoitov return -EPERM; 351aaac3ba9SAlexei Starovoitov } 352aaac3ba9SAlexei Starovoitov return 0; 353aaac3ba9SAlexei Starovoitov } 354aaac3ba9SAlexei Starovoitov 3550a4c58f5SRoman Gushchin static void bpf_uncharge_memlock(struct user_struct *user, u32 pages) 3560a4c58f5SRoman Gushchin { 357b936ca64SRoman Gushchin if (user) 3580a4c58f5SRoman Gushchin atomic_long_sub(pages, &user->locked_vm); 3590a4c58f5SRoman Gushchin } 3600a4c58f5SRoman Gushchin 361196e8ca7SDaniel Borkmann int bpf_map_charge_init(struct bpf_map_memory *mem, u64 size) 3620a4c58f5SRoman Gushchin { 363c85d6913SRoman Gushchin u32 pages = round_up(size, PAGE_SIZE) >> PAGE_SHIFT; 364c85d6913SRoman Gushchin struct user_struct *user; 3650a4c58f5SRoman Gushchin int ret; 3660a4c58f5SRoman Gushchin 367c85d6913SRoman Gushchin if (size >= U32_MAX - PAGE_SIZE) 368c85d6913SRoman Gushchin return -E2BIG; 369c85d6913SRoman Gushchin 370c85d6913SRoman Gushchin user = get_current_user(); 371b936ca64SRoman Gushchin ret = bpf_charge_memlock(user, pages); 3720a4c58f5SRoman Gushchin if (ret) { 3730a4c58f5SRoman Gushchin free_uid(user); 3740a4c58f5SRoman Gushchin return ret; 3750a4c58f5SRoman Gushchin } 376b936ca64SRoman Gushchin 377b936ca64SRoman Gushchin mem->pages = pages; 378b936ca64SRoman Gushchin mem->user = user; 379b936ca64SRoman Gushchin 380b936ca64SRoman Gushchin return 0; 3810a4c58f5SRoman Gushchin } 3820a4c58f5SRoman Gushchin 383b936ca64SRoman Gushchin void bpf_map_charge_finish(struct bpf_map_memory *mem) 384aaac3ba9SAlexei Starovoitov { 385b936ca64SRoman Gushchin bpf_uncharge_memlock(mem->user, mem->pages); 386b936ca64SRoman Gushchin free_uid(mem->user); 387b936ca64SRoman Gushchin } 3883539b96eSRoman Gushchin 389b936ca64SRoman Gushchin void bpf_map_charge_move(struct bpf_map_memory *dst, 390b936ca64SRoman Gushchin struct bpf_map_memory *src) 391b936ca64SRoman Gushchin { 392b936ca64SRoman Gushchin *dst = *src; 393b936ca64SRoman Gushchin 394b936ca64SRoman Gushchin /* Make sure src will not be used for the redundant uncharging. */ 395b936ca64SRoman Gushchin memset(src, 0, sizeof(struct bpf_map_memory)); 396aaac3ba9SAlexei Starovoitov } 397aaac3ba9SAlexei Starovoitov 3980a4c58f5SRoman Gushchin int bpf_map_charge_memlock(struct bpf_map *map, u32 pages) 3990a4c58f5SRoman Gushchin { 4000a4c58f5SRoman Gushchin int ret; 4010a4c58f5SRoman Gushchin 4023539b96eSRoman Gushchin ret = bpf_charge_memlock(map->memory.user, pages); 4030a4c58f5SRoman Gushchin if (ret) 4040a4c58f5SRoman Gushchin return ret; 4053539b96eSRoman Gushchin map->memory.pages += pages; 4060a4c58f5SRoman Gushchin return ret; 4070a4c58f5SRoman Gushchin } 4080a4c58f5SRoman Gushchin 4090a4c58f5SRoman Gushchin void bpf_map_uncharge_memlock(struct bpf_map *map, u32 pages) 4100a4c58f5SRoman Gushchin { 4113539b96eSRoman Gushchin bpf_uncharge_memlock(map->memory.user, pages); 4123539b96eSRoman Gushchin map->memory.pages -= pages; 4130a4c58f5SRoman Gushchin } 4140a4c58f5SRoman Gushchin 415f3f1c054SMartin KaFai Lau static int bpf_map_alloc_id(struct bpf_map *map) 416f3f1c054SMartin KaFai Lau { 417f3f1c054SMartin KaFai Lau int id; 418f3f1c054SMartin KaFai Lau 419b76354cdSShaohua Li idr_preload(GFP_KERNEL); 420f3f1c054SMartin KaFai Lau spin_lock_bh(&map_idr_lock); 421f3f1c054SMartin KaFai Lau id = idr_alloc_cyclic(&map_idr, map, 1, INT_MAX, GFP_ATOMIC); 422f3f1c054SMartin KaFai Lau if (id > 0) 423f3f1c054SMartin KaFai Lau map->id = id; 424f3f1c054SMartin KaFai Lau spin_unlock_bh(&map_idr_lock); 425b76354cdSShaohua Li idr_preload_end(); 426f3f1c054SMartin KaFai Lau 427f3f1c054SMartin KaFai Lau if (WARN_ON_ONCE(!id)) 428f3f1c054SMartin KaFai Lau return -ENOSPC; 429f3f1c054SMartin KaFai Lau 430f3f1c054SMartin KaFai Lau return id > 0 ? 0 : id; 431f3f1c054SMartin KaFai Lau } 432f3f1c054SMartin KaFai Lau 433a3884572SJakub Kicinski void bpf_map_free_id(struct bpf_map *map, bool do_idr_lock) 434f3f1c054SMartin KaFai Lau { 435930651a7SEric Dumazet unsigned long flags; 436930651a7SEric Dumazet 437a3884572SJakub Kicinski /* Offloaded maps are removed from the IDR store when their device 438a3884572SJakub Kicinski * disappears - even if someone holds an fd to them they are unusable, 439a3884572SJakub Kicinski * the memory is gone, all ops will fail; they are simply waiting for 440a3884572SJakub Kicinski * refcnt to drop to be freed. 441a3884572SJakub Kicinski */ 442a3884572SJakub Kicinski if (!map->id) 443a3884572SJakub Kicinski return; 444a3884572SJakub Kicinski 445bd5f5f4eSMartin KaFai Lau if (do_idr_lock) 446930651a7SEric Dumazet spin_lock_irqsave(&map_idr_lock, flags); 447bd5f5f4eSMartin KaFai Lau else 448bd5f5f4eSMartin KaFai Lau __acquire(&map_idr_lock); 449bd5f5f4eSMartin KaFai Lau 450f3f1c054SMartin KaFai Lau idr_remove(&map_idr, map->id); 451a3884572SJakub Kicinski map->id = 0; 452bd5f5f4eSMartin KaFai Lau 453bd5f5f4eSMartin KaFai Lau if (do_idr_lock) 454930651a7SEric Dumazet spin_unlock_irqrestore(&map_idr_lock, flags); 455bd5f5f4eSMartin KaFai Lau else 456bd5f5f4eSMartin KaFai Lau __release(&map_idr_lock); 457f3f1c054SMartin KaFai Lau } 458f3f1c054SMartin KaFai Lau 45999c55f7dSAlexei Starovoitov /* called from workqueue */ 46099c55f7dSAlexei Starovoitov static void bpf_map_free_deferred(struct work_struct *work) 46199c55f7dSAlexei Starovoitov { 46299c55f7dSAlexei Starovoitov struct bpf_map *map = container_of(work, struct bpf_map, work); 463b936ca64SRoman Gushchin struct bpf_map_memory mem; 46499c55f7dSAlexei Starovoitov 465b936ca64SRoman Gushchin bpf_map_charge_move(&mem, &map->memory); 466afdb09c7SChenbo Feng security_bpf_map_free(map); 46799c55f7dSAlexei Starovoitov /* implementation dependent freeing */ 46899c55f7dSAlexei Starovoitov map->ops->map_free(map); 469b936ca64SRoman Gushchin bpf_map_charge_finish(&mem); 47099c55f7dSAlexei Starovoitov } 47199c55f7dSAlexei Starovoitov 472c9da161cSDaniel Borkmann static void bpf_map_put_uref(struct bpf_map *map) 473c9da161cSDaniel Borkmann { 4741e0bd5a0SAndrii Nakryiko if (atomic64_dec_and_test(&map->usercnt)) { 475ba6b8de4SJohn Fastabend if (map->ops->map_release_uref) 476ba6b8de4SJohn Fastabend map->ops->map_release_uref(map); 477c9da161cSDaniel Borkmann } 478c9da161cSDaniel Borkmann } 479c9da161cSDaniel Borkmann 48099c55f7dSAlexei Starovoitov /* decrement map refcnt and schedule it for freeing via workqueue 48199c55f7dSAlexei Starovoitov * (unrelying map implementation ops->map_free() might sleep) 48299c55f7dSAlexei Starovoitov */ 483bd5f5f4eSMartin KaFai Lau static void __bpf_map_put(struct bpf_map *map, bool do_idr_lock) 48499c55f7dSAlexei Starovoitov { 4851e0bd5a0SAndrii Nakryiko if (atomic64_dec_and_test(&map->refcnt)) { 48634ad5580SMartin KaFai Lau /* bpf_map_free_id() must be called first */ 487bd5f5f4eSMartin KaFai Lau bpf_map_free_id(map, do_idr_lock); 48878958fcaSMartin KaFai Lau btf_put(map->btf); 48999c55f7dSAlexei Starovoitov INIT_WORK(&map->work, bpf_map_free_deferred); 49099c55f7dSAlexei Starovoitov schedule_work(&map->work); 49199c55f7dSAlexei Starovoitov } 49299c55f7dSAlexei Starovoitov } 49399c55f7dSAlexei Starovoitov 494bd5f5f4eSMartin KaFai Lau void bpf_map_put(struct bpf_map *map) 495bd5f5f4eSMartin KaFai Lau { 496bd5f5f4eSMartin KaFai Lau __bpf_map_put(map, true); 497bd5f5f4eSMartin KaFai Lau } 498630a4d38SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_map_put); 499bd5f5f4eSMartin KaFai Lau 500c9da161cSDaniel Borkmann void bpf_map_put_with_uref(struct bpf_map *map) 501c9da161cSDaniel Borkmann { 502c9da161cSDaniel Borkmann bpf_map_put_uref(map); 503c9da161cSDaniel Borkmann bpf_map_put(map); 504c9da161cSDaniel Borkmann } 505c9da161cSDaniel Borkmann 50699c55f7dSAlexei Starovoitov static int bpf_map_release(struct inode *inode, struct file *filp) 50799c55f7dSAlexei Starovoitov { 50861d1b6a4SDaniel Borkmann struct bpf_map *map = filp->private_data; 50961d1b6a4SDaniel Borkmann 51061d1b6a4SDaniel Borkmann if (map->ops->map_release) 51161d1b6a4SDaniel Borkmann map->ops->map_release(map, filp); 51261d1b6a4SDaniel Borkmann 51361d1b6a4SDaniel Borkmann bpf_map_put_with_uref(map); 51499c55f7dSAlexei Starovoitov return 0; 51599c55f7dSAlexei Starovoitov } 51699c55f7dSAlexei Starovoitov 51787df15deSDaniel Borkmann static fmode_t map_get_sys_perms(struct bpf_map *map, struct fd f) 51887df15deSDaniel Borkmann { 51987df15deSDaniel Borkmann fmode_t mode = f.file->f_mode; 52087df15deSDaniel Borkmann 52187df15deSDaniel Borkmann /* Our file permissions may have been overridden by global 52287df15deSDaniel Borkmann * map permissions facing syscall side. 52387df15deSDaniel Borkmann */ 52487df15deSDaniel Borkmann if (READ_ONCE(map->frozen)) 52587df15deSDaniel Borkmann mode &= ~FMODE_CAN_WRITE; 52687df15deSDaniel Borkmann return mode; 52787df15deSDaniel Borkmann } 52887df15deSDaniel Borkmann 529f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS 530f99bf205SDaniel Borkmann static void bpf_map_show_fdinfo(struct seq_file *m, struct file *filp) 531f99bf205SDaniel Borkmann { 532f99bf205SDaniel Borkmann const struct bpf_map *map = filp->private_data; 53321116b70SDaniel Borkmann const struct bpf_array *array; 5342beee5f5SDaniel Borkmann u32 type = 0, jited = 0; 53521116b70SDaniel Borkmann 53621116b70SDaniel Borkmann if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY) { 53721116b70SDaniel Borkmann array = container_of(map, struct bpf_array, map); 5382beee5f5SDaniel Borkmann type = array->aux->type; 5392beee5f5SDaniel Borkmann jited = array->aux->jited; 54021116b70SDaniel Borkmann } 541f99bf205SDaniel Borkmann 542f99bf205SDaniel Borkmann seq_printf(m, 543f99bf205SDaniel Borkmann "map_type:\t%u\n" 544f99bf205SDaniel Borkmann "key_size:\t%u\n" 545f99bf205SDaniel Borkmann "value_size:\t%u\n" 546322cea2fSDaniel Borkmann "max_entries:\t%u\n" 54721116b70SDaniel Borkmann "map_flags:\t%#x\n" 5484316b409SDaniel Borkmann "memlock:\t%llu\n" 54987df15deSDaniel Borkmann "map_id:\t%u\n" 55087df15deSDaniel Borkmann "frozen:\t%u\n", 551f99bf205SDaniel Borkmann map->map_type, 552f99bf205SDaniel Borkmann map->key_size, 553f99bf205SDaniel Borkmann map->value_size, 554322cea2fSDaniel Borkmann map->max_entries, 55521116b70SDaniel Borkmann map->map_flags, 5563539b96eSRoman Gushchin map->memory.pages * 1ULL << PAGE_SHIFT, 55787df15deSDaniel Borkmann map->id, 55887df15deSDaniel Borkmann READ_ONCE(map->frozen)); 5592beee5f5SDaniel Borkmann if (type) { 5602beee5f5SDaniel Borkmann seq_printf(m, "owner_prog_type:\t%u\n", type); 5612beee5f5SDaniel Borkmann seq_printf(m, "owner_jited:\t%u\n", jited); 5629780c0abSDaniel Borkmann } 563f99bf205SDaniel Borkmann } 564f99bf205SDaniel Borkmann #endif 565f99bf205SDaniel Borkmann 5666e71b04aSChenbo Feng static ssize_t bpf_dummy_read(struct file *filp, char __user *buf, size_t siz, 5676e71b04aSChenbo Feng loff_t *ppos) 5686e71b04aSChenbo Feng { 5696e71b04aSChenbo Feng /* We need this handler such that alloc_file() enables 5706e71b04aSChenbo Feng * f_mode with FMODE_CAN_READ. 5716e71b04aSChenbo Feng */ 5726e71b04aSChenbo Feng return -EINVAL; 5736e71b04aSChenbo Feng } 5746e71b04aSChenbo Feng 5756e71b04aSChenbo Feng static ssize_t bpf_dummy_write(struct file *filp, const char __user *buf, 5766e71b04aSChenbo Feng size_t siz, loff_t *ppos) 5776e71b04aSChenbo Feng { 5786e71b04aSChenbo Feng /* We need this handler such that alloc_file() enables 5796e71b04aSChenbo Feng * f_mode with FMODE_CAN_WRITE. 5806e71b04aSChenbo Feng */ 5816e71b04aSChenbo Feng return -EINVAL; 5826e71b04aSChenbo Feng } 5836e71b04aSChenbo Feng 584fc970227SAndrii Nakryiko /* called for any extra memory-mapped regions (except initial) */ 585fc970227SAndrii Nakryiko static void bpf_map_mmap_open(struct vm_area_struct *vma) 586fc970227SAndrii Nakryiko { 587fc970227SAndrii Nakryiko struct bpf_map *map = vma->vm_file->private_data; 588fc970227SAndrii Nakryiko 5891f6cb19bSAndrii Nakryiko if (vma->vm_flags & VM_MAYWRITE) { 590fc970227SAndrii Nakryiko mutex_lock(&map->freeze_mutex); 591fc970227SAndrii Nakryiko map->writecnt++; 592fc970227SAndrii Nakryiko mutex_unlock(&map->freeze_mutex); 593fc970227SAndrii Nakryiko } 594fc970227SAndrii Nakryiko } 595fc970227SAndrii Nakryiko 596fc970227SAndrii Nakryiko /* called for all unmapped memory region (including initial) */ 597fc970227SAndrii Nakryiko static void bpf_map_mmap_close(struct vm_area_struct *vma) 598fc970227SAndrii Nakryiko { 599fc970227SAndrii Nakryiko struct bpf_map *map = vma->vm_file->private_data; 600fc970227SAndrii Nakryiko 6011f6cb19bSAndrii Nakryiko if (vma->vm_flags & VM_MAYWRITE) { 602fc970227SAndrii Nakryiko mutex_lock(&map->freeze_mutex); 603fc970227SAndrii Nakryiko map->writecnt--; 604fc970227SAndrii Nakryiko mutex_unlock(&map->freeze_mutex); 605fc970227SAndrii Nakryiko } 606fc970227SAndrii Nakryiko } 607fc970227SAndrii Nakryiko 608fc970227SAndrii Nakryiko static const struct vm_operations_struct bpf_map_default_vmops = { 609fc970227SAndrii Nakryiko .open = bpf_map_mmap_open, 610fc970227SAndrii Nakryiko .close = bpf_map_mmap_close, 611fc970227SAndrii Nakryiko }; 612fc970227SAndrii Nakryiko 613fc970227SAndrii Nakryiko static int bpf_map_mmap(struct file *filp, struct vm_area_struct *vma) 614fc970227SAndrii Nakryiko { 615fc970227SAndrii Nakryiko struct bpf_map *map = filp->private_data; 616fc970227SAndrii Nakryiko int err; 617fc970227SAndrii Nakryiko 618fc970227SAndrii Nakryiko if (!map->ops->map_mmap || map_value_has_spin_lock(map)) 619fc970227SAndrii Nakryiko return -ENOTSUPP; 620fc970227SAndrii Nakryiko 621fc970227SAndrii Nakryiko if (!(vma->vm_flags & VM_SHARED)) 622fc970227SAndrii Nakryiko return -EINVAL; 623fc970227SAndrii Nakryiko 624fc970227SAndrii Nakryiko mutex_lock(&map->freeze_mutex); 625fc970227SAndrii Nakryiko 626fc970227SAndrii Nakryiko if ((vma->vm_flags & VM_WRITE) && map->frozen) { 627fc970227SAndrii Nakryiko err = -EPERM; 628fc970227SAndrii Nakryiko goto out; 629fc970227SAndrii Nakryiko } 630fc970227SAndrii Nakryiko 631fc970227SAndrii Nakryiko /* set default open/close callbacks */ 632fc970227SAndrii Nakryiko vma->vm_ops = &bpf_map_default_vmops; 633fc970227SAndrii Nakryiko vma->vm_private_data = map; 6341f6cb19bSAndrii Nakryiko vma->vm_flags &= ~VM_MAYEXEC; 6351f6cb19bSAndrii Nakryiko if (!(vma->vm_flags & VM_WRITE)) 6361f6cb19bSAndrii Nakryiko /* disallow re-mapping with PROT_WRITE */ 6371f6cb19bSAndrii Nakryiko vma->vm_flags &= ~VM_MAYWRITE; 638fc970227SAndrii Nakryiko 639fc970227SAndrii Nakryiko err = map->ops->map_mmap(map, vma); 640fc970227SAndrii Nakryiko if (err) 641fc970227SAndrii Nakryiko goto out; 642fc970227SAndrii Nakryiko 6431f6cb19bSAndrii Nakryiko if (vma->vm_flags & VM_MAYWRITE) 644fc970227SAndrii Nakryiko map->writecnt++; 645fc970227SAndrii Nakryiko out: 646fc970227SAndrii Nakryiko mutex_unlock(&map->freeze_mutex); 647fc970227SAndrii Nakryiko return err; 648fc970227SAndrii Nakryiko } 649fc970227SAndrii Nakryiko 650f66e448cSChenbo Feng const struct file_operations bpf_map_fops = { 651f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS 652f99bf205SDaniel Borkmann .show_fdinfo = bpf_map_show_fdinfo, 653f99bf205SDaniel Borkmann #endif 65499c55f7dSAlexei Starovoitov .release = bpf_map_release, 6556e71b04aSChenbo Feng .read = bpf_dummy_read, 6566e71b04aSChenbo Feng .write = bpf_dummy_write, 657fc970227SAndrii Nakryiko .mmap = bpf_map_mmap, 65899c55f7dSAlexei Starovoitov }; 65999c55f7dSAlexei Starovoitov 6606e71b04aSChenbo Feng int bpf_map_new_fd(struct bpf_map *map, int flags) 661aa79781bSDaniel Borkmann { 662afdb09c7SChenbo Feng int ret; 663afdb09c7SChenbo Feng 664afdb09c7SChenbo Feng ret = security_bpf_map(map, OPEN_FMODE(flags)); 665afdb09c7SChenbo Feng if (ret < 0) 666afdb09c7SChenbo Feng return ret; 667afdb09c7SChenbo Feng 668aa79781bSDaniel Borkmann return anon_inode_getfd("bpf-map", &bpf_map_fops, map, 6696e71b04aSChenbo Feng flags | O_CLOEXEC); 6706e71b04aSChenbo Feng } 6716e71b04aSChenbo Feng 6726e71b04aSChenbo Feng int bpf_get_file_flag(int flags) 6736e71b04aSChenbo Feng { 6746e71b04aSChenbo Feng if ((flags & BPF_F_RDONLY) && (flags & BPF_F_WRONLY)) 6756e71b04aSChenbo Feng return -EINVAL; 6766e71b04aSChenbo Feng if (flags & BPF_F_RDONLY) 6776e71b04aSChenbo Feng return O_RDONLY; 6786e71b04aSChenbo Feng if (flags & BPF_F_WRONLY) 6796e71b04aSChenbo Feng return O_WRONLY; 6806e71b04aSChenbo Feng return O_RDWR; 681aa79781bSDaniel Borkmann } 682aa79781bSDaniel Borkmann 68399c55f7dSAlexei Starovoitov /* helper macro to check that unused fields 'union bpf_attr' are zero */ 68499c55f7dSAlexei Starovoitov #define CHECK_ATTR(CMD) \ 68599c55f7dSAlexei Starovoitov memchr_inv((void *) &attr->CMD##_LAST_FIELD + \ 68699c55f7dSAlexei Starovoitov sizeof(attr->CMD##_LAST_FIELD), 0, \ 68799c55f7dSAlexei Starovoitov sizeof(*attr) - \ 68899c55f7dSAlexei Starovoitov offsetof(union bpf_attr, CMD##_LAST_FIELD) - \ 68999c55f7dSAlexei Starovoitov sizeof(attr->CMD##_LAST_FIELD)) != NULL 69099c55f7dSAlexei Starovoitov 6918e7ae251SMartin KaFai Lau /* dst and src must have at least "size" number of bytes. 6928e7ae251SMartin KaFai Lau * Return strlen on success and < 0 on error. 693cb4d2b3fSMartin KaFai Lau */ 6948e7ae251SMartin KaFai Lau int bpf_obj_name_cpy(char *dst, const char *src, unsigned int size) 695cb4d2b3fSMartin KaFai Lau { 6968e7ae251SMartin KaFai Lau const char *end = src + size; 6978e7ae251SMartin KaFai Lau const char *orig_src = src; 698cb4d2b3fSMartin KaFai Lau 6998e7ae251SMartin KaFai Lau memset(dst, 0, size); 7003e0ddc4fSDaniel Borkmann /* Copy all isalnum(), '_' and '.' chars. */ 701cb4d2b3fSMartin KaFai Lau while (src < end && *src) { 7023e0ddc4fSDaniel Borkmann if (!isalnum(*src) && 7033e0ddc4fSDaniel Borkmann *src != '_' && *src != '.') 704cb4d2b3fSMartin KaFai Lau return -EINVAL; 705cb4d2b3fSMartin KaFai Lau *dst++ = *src++; 706cb4d2b3fSMartin KaFai Lau } 707cb4d2b3fSMartin KaFai Lau 7088e7ae251SMartin KaFai Lau /* No '\0' found in "size" number of bytes */ 709cb4d2b3fSMartin KaFai Lau if (src == end) 710cb4d2b3fSMartin KaFai Lau return -EINVAL; 711cb4d2b3fSMartin KaFai Lau 7128e7ae251SMartin KaFai Lau return src - orig_src; 713cb4d2b3fSMartin KaFai Lau } 714cb4d2b3fSMartin KaFai Lau 715e8d2bec0SDaniel Borkmann int map_check_no_btf(const struct bpf_map *map, 7161b2b234bSRoman Gushchin const struct btf *btf, 717e8d2bec0SDaniel Borkmann const struct btf_type *key_type, 718e8d2bec0SDaniel Borkmann const struct btf_type *value_type) 719e8d2bec0SDaniel Borkmann { 720e8d2bec0SDaniel Borkmann return -ENOTSUPP; 721e8d2bec0SDaniel Borkmann } 722e8d2bec0SDaniel Borkmann 723d83525caSAlexei Starovoitov static int map_check_btf(struct bpf_map *map, const struct btf *btf, 724e8d2bec0SDaniel Borkmann u32 btf_key_id, u32 btf_value_id) 725e8d2bec0SDaniel Borkmann { 726e8d2bec0SDaniel Borkmann const struct btf_type *key_type, *value_type; 727e8d2bec0SDaniel Borkmann u32 key_size, value_size; 728e8d2bec0SDaniel Borkmann int ret = 0; 729e8d2bec0SDaniel Borkmann 7302824ecb7SDaniel Borkmann /* Some maps allow key to be unspecified. */ 7312824ecb7SDaniel Borkmann if (btf_key_id) { 732e8d2bec0SDaniel Borkmann key_type = btf_type_id_size(btf, &btf_key_id, &key_size); 733e8d2bec0SDaniel Borkmann if (!key_type || key_size != map->key_size) 734e8d2bec0SDaniel Borkmann return -EINVAL; 7352824ecb7SDaniel Borkmann } else { 7362824ecb7SDaniel Borkmann key_type = btf_type_by_id(btf, 0); 7372824ecb7SDaniel Borkmann if (!map->ops->map_check_btf) 7382824ecb7SDaniel Borkmann return -EINVAL; 7392824ecb7SDaniel Borkmann } 740e8d2bec0SDaniel Borkmann 741e8d2bec0SDaniel Borkmann value_type = btf_type_id_size(btf, &btf_value_id, &value_size); 742e8d2bec0SDaniel Borkmann if (!value_type || value_size != map->value_size) 743e8d2bec0SDaniel Borkmann return -EINVAL; 744e8d2bec0SDaniel Borkmann 745d83525caSAlexei Starovoitov map->spin_lock_off = btf_find_spin_lock(btf, value_type); 746d83525caSAlexei Starovoitov 747d83525caSAlexei Starovoitov if (map_value_has_spin_lock(map)) { 748591fe988SDaniel Borkmann if (map->map_flags & BPF_F_RDONLY_PROG) 749591fe988SDaniel Borkmann return -EACCES; 750d83525caSAlexei Starovoitov if (map->map_type != BPF_MAP_TYPE_HASH && 751e16d2f1aSAlexei Starovoitov map->map_type != BPF_MAP_TYPE_ARRAY && 7526ac99e8fSMartin KaFai Lau map->map_type != BPF_MAP_TYPE_CGROUP_STORAGE && 7536ac99e8fSMartin KaFai Lau map->map_type != BPF_MAP_TYPE_SK_STORAGE) 754d83525caSAlexei Starovoitov return -ENOTSUPP; 755d83525caSAlexei Starovoitov if (map->spin_lock_off + sizeof(struct bpf_spin_lock) > 756d83525caSAlexei Starovoitov map->value_size) { 757d83525caSAlexei Starovoitov WARN_ONCE(1, 758d83525caSAlexei Starovoitov "verifier bug spin_lock_off %d value_size %d\n", 759d83525caSAlexei Starovoitov map->spin_lock_off, map->value_size); 760d83525caSAlexei Starovoitov return -EFAULT; 761d83525caSAlexei Starovoitov } 762d83525caSAlexei Starovoitov } 763d83525caSAlexei Starovoitov 764e8d2bec0SDaniel Borkmann if (map->ops->map_check_btf) 7651b2b234bSRoman Gushchin ret = map->ops->map_check_btf(map, btf, key_type, value_type); 766e8d2bec0SDaniel Borkmann 767e8d2bec0SDaniel Borkmann return ret; 768e8d2bec0SDaniel Borkmann } 769e8d2bec0SDaniel Borkmann 77085d33df3SMartin KaFai Lau #define BPF_MAP_CREATE_LAST_FIELD btf_vmlinux_value_type_id 77199c55f7dSAlexei Starovoitov /* called via syscall */ 77299c55f7dSAlexei Starovoitov static int map_create(union bpf_attr *attr) 77399c55f7dSAlexei Starovoitov { 77496eabe7aSMartin KaFai Lau int numa_node = bpf_map_attr_numa_node(attr); 775b936ca64SRoman Gushchin struct bpf_map_memory mem; 77699c55f7dSAlexei Starovoitov struct bpf_map *map; 7776e71b04aSChenbo Feng int f_flags; 77899c55f7dSAlexei Starovoitov int err; 77999c55f7dSAlexei Starovoitov 78099c55f7dSAlexei Starovoitov err = CHECK_ATTR(BPF_MAP_CREATE); 78199c55f7dSAlexei Starovoitov if (err) 78299c55f7dSAlexei Starovoitov return -EINVAL; 78399c55f7dSAlexei Starovoitov 78485d33df3SMartin KaFai Lau if (attr->btf_vmlinux_value_type_id) { 78585d33df3SMartin KaFai Lau if (attr->map_type != BPF_MAP_TYPE_STRUCT_OPS || 78685d33df3SMartin KaFai Lau attr->btf_key_type_id || attr->btf_value_type_id) 78785d33df3SMartin KaFai Lau return -EINVAL; 78885d33df3SMartin KaFai Lau } else if (attr->btf_key_type_id && !attr->btf_value_type_id) { 78985d33df3SMartin KaFai Lau return -EINVAL; 79085d33df3SMartin KaFai Lau } 79185d33df3SMartin KaFai Lau 7926e71b04aSChenbo Feng f_flags = bpf_get_file_flag(attr->map_flags); 7936e71b04aSChenbo Feng if (f_flags < 0) 7946e71b04aSChenbo Feng return f_flags; 7956e71b04aSChenbo Feng 79696eabe7aSMartin KaFai Lau if (numa_node != NUMA_NO_NODE && 79796e5ae4eSEric Dumazet ((unsigned int)numa_node >= nr_node_ids || 79896e5ae4eSEric Dumazet !node_online(numa_node))) 79996eabe7aSMartin KaFai Lau return -EINVAL; 80096eabe7aSMartin KaFai Lau 80199c55f7dSAlexei Starovoitov /* find map type and init map: hashtable vs rbtree vs bloom vs ... */ 80299c55f7dSAlexei Starovoitov map = find_and_alloc_map(attr); 80399c55f7dSAlexei Starovoitov if (IS_ERR(map)) 80499c55f7dSAlexei Starovoitov return PTR_ERR(map); 80599c55f7dSAlexei Starovoitov 8068e7ae251SMartin KaFai Lau err = bpf_obj_name_cpy(map->name, attr->map_name, 8078e7ae251SMartin KaFai Lau sizeof(attr->map_name)); 8088e7ae251SMartin KaFai Lau if (err < 0) 809b936ca64SRoman Gushchin goto free_map; 810ad5b177bSMartin KaFai Lau 8111e0bd5a0SAndrii Nakryiko atomic64_set(&map->refcnt, 1); 8121e0bd5a0SAndrii Nakryiko atomic64_set(&map->usercnt, 1); 813fc970227SAndrii Nakryiko mutex_init(&map->freeze_mutex); 81499c55f7dSAlexei Starovoitov 81585d33df3SMartin KaFai Lau map->spin_lock_off = -EINVAL; 81685d33df3SMartin KaFai Lau if (attr->btf_key_type_id || attr->btf_value_type_id || 81785d33df3SMartin KaFai Lau /* Even the map's value is a kernel's struct, 81885d33df3SMartin KaFai Lau * the bpf_prog.o must have BTF to begin with 81985d33df3SMartin KaFai Lau * to figure out the corresponding kernel's 82085d33df3SMartin KaFai Lau * counter part. Thus, attr->btf_fd has 82185d33df3SMartin KaFai Lau * to be valid also. 82285d33df3SMartin KaFai Lau */ 82385d33df3SMartin KaFai Lau attr->btf_vmlinux_value_type_id) { 824a26ca7c9SMartin KaFai Lau struct btf *btf; 825a26ca7c9SMartin KaFai Lau 826a26ca7c9SMartin KaFai Lau btf = btf_get_by_fd(attr->btf_fd); 827a26ca7c9SMartin KaFai Lau if (IS_ERR(btf)) { 828a26ca7c9SMartin KaFai Lau err = PTR_ERR(btf); 829b936ca64SRoman Gushchin goto free_map; 830a26ca7c9SMartin KaFai Lau } 83185d33df3SMartin KaFai Lau map->btf = btf; 832a26ca7c9SMartin KaFai Lau 83385d33df3SMartin KaFai Lau if (attr->btf_value_type_id) { 834e8d2bec0SDaniel Borkmann err = map_check_btf(map, btf, attr->btf_key_type_id, 8359b2cf328SMartin KaFai Lau attr->btf_value_type_id); 83685d33df3SMartin KaFai Lau if (err) 837b936ca64SRoman Gushchin goto free_map; 838a26ca7c9SMartin KaFai Lau } 839a26ca7c9SMartin KaFai Lau 8409b2cf328SMartin KaFai Lau map->btf_key_type_id = attr->btf_key_type_id; 8419b2cf328SMartin KaFai Lau map->btf_value_type_id = attr->btf_value_type_id; 84285d33df3SMartin KaFai Lau map->btf_vmlinux_value_type_id = 84385d33df3SMartin KaFai Lau attr->btf_vmlinux_value_type_id; 844a26ca7c9SMartin KaFai Lau } 845a26ca7c9SMartin KaFai Lau 846afdb09c7SChenbo Feng err = security_bpf_map_alloc(map); 847aaac3ba9SAlexei Starovoitov if (err) 848b936ca64SRoman Gushchin goto free_map; 849afdb09c7SChenbo Feng 850f3f1c054SMartin KaFai Lau err = bpf_map_alloc_id(map); 851f3f1c054SMartin KaFai Lau if (err) 852b936ca64SRoman Gushchin goto free_map_sec; 853f3f1c054SMartin KaFai Lau 8546e71b04aSChenbo Feng err = bpf_map_new_fd(map, f_flags); 855bd5f5f4eSMartin KaFai Lau if (err < 0) { 856bd5f5f4eSMartin KaFai Lau /* failed to allocate fd. 857352d20d6SPeng Sun * bpf_map_put_with_uref() is needed because the above 858bd5f5f4eSMartin KaFai Lau * bpf_map_alloc_id() has published the map 859bd5f5f4eSMartin KaFai Lau * to the userspace and the userspace may 860bd5f5f4eSMartin KaFai Lau * have refcnt-ed it through BPF_MAP_GET_FD_BY_ID. 861bd5f5f4eSMartin KaFai Lau */ 862352d20d6SPeng Sun bpf_map_put_with_uref(map); 863bd5f5f4eSMartin KaFai Lau return err; 864bd5f5f4eSMartin KaFai Lau } 86599c55f7dSAlexei Starovoitov 86699c55f7dSAlexei Starovoitov return err; 86799c55f7dSAlexei Starovoitov 868afdb09c7SChenbo Feng free_map_sec: 869afdb09c7SChenbo Feng security_bpf_map_free(map); 870b936ca64SRoman Gushchin free_map: 871a26ca7c9SMartin KaFai Lau btf_put(map->btf); 872b936ca64SRoman Gushchin bpf_map_charge_move(&mem, &map->memory); 87399c55f7dSAlexei Starovoitov map->ops->map_free(map); 874b936ca64SRoman Gushchin bpf_map_charge_finish(&mem); 87599c55f7dSAlexei Starovoitov return err; 87699c55f7dSAlexei Starovoitov } 87799c55f7dSAlexei Starovoitov 878db20fd2bSAlexei Starovoitov /* if error is returned, fd is released. 879db20fd2bSAlexei Starovoitov * On success caller should complete fd access with matching fdput() 880db20fd2bSAlexei Starovoitov */ 881c2101297SDaniel Borkmann struct bpf_map *__bpf_map_get(struct fd f) 882db20fd2bSAlexei Starovoitov { 883db20fd2bSAlexei Starovoitov if (!f.file) 884db20fd2bSAlexei Starovoitov return ERR_PTR(-EBADF); 885db20fd2bSAlexei Starovoitov if (f.file->f_op != &bpf_map_fops) { 886db20fd2bSAlexei Starovoitov fdput(f); 887db20fd2bSAlexei Starovoitov return ERR_PTR(-EINVAL); 888db20fd2bSAlexei Starovoitov } 889db20fd2bSAlexei Starovoitov 890c2101297SDaniel Borkmann return f.file->private_data; 891c2101297SDaniel Borkmann } 892c2101297SDaniel Borkmann 8931e0bd5a0SAndrii Nakryiko void bpf_map_inc(struct bpf_map *map) 894c9da161cSDaniel Borkmann { 8951e0bd5a0SAndrii Nakryiko atomic64_inc(&map->refcnt); 896c9da161cSDaniel Borkmann } 897630a4d38SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_map_inc); 898c9da161cSDaniel Borkmann 8991e0bd5a0SAndrii Nakryiko void bpf_map_inc_with_uref(struct bpf_map *map) 9001e0bd5a0SAndrii Nakryiko { 9011e0bd5a0SAndrii Nakryiko atomic64_inc(&map->refcnt); 9021e0bd5a0SAndrii Nakryiko atomic64_inc(&map->usercnt); 9031e0bd5a0SAndrii Nakryiko } 9041e0bd5a0SAndrii Nakryiko EXPORT_SYMBOL_GPL(bpf_map_inc_with_uref); 9051e0bd5a0SAndrii Nakryiko 9061ed4d924SMartin KaFai Lau struct bpf_map *bpf_map_get(u32 ufd) 9071ed4d924SMartin KaFai Lau { 9081ed4d924SMartin KaFai Lau struct fd f = fdget(ufd); 9091ed4d924SMartin KaFai Lau struct bpf_map *map; 9101ed4d924SMartin KaFai Lau 9111ed4d924SMartin KaFai Lau map = __bpf_map_get(f); 9121ed4d924SMartin KaFai Lau if (IS_ERR(map)) 9131ed4d924SMartin KaFai Lau return map; 9141ed4d924SMartin KaFai Lau 9151ed4d924SMartin KaFai Lau bpf_map_inc(map); 9161ed4d924SMartin KaFai Lau fdput(f); 9171ed4d924SMartin KaFai Lau 9181ed4d924SMartin KaFai Lau return map; 9191ed4d924SMartin KaFai Lau } 9201ed4d924SMartin KaFai Lau 921c9da161cSDaniel Borkmann struct bpf_map *bpf_map_get_with_uref(u32 ufd) 922c2101297SDaniel Borkmann { 923c2101297SDaniel Borkmann struct fd f = fdget(ufd); 924c2101297SDaniel Borkmann struct bpf_map *map; 925c2101297SDaniel Borkmann 926c2101297SDaniel Borkmann map = __bpf_map_get(f); 927c2101297SDaniel Borkmann if (IS_ERR(map)) 928c2101297SDaniel Borkmann return map; 929c2101297SDaniel Borkmann 9301e0bd5a0SAndrii Nakryiko bpf_map_inc_with_uref(map); 931c2101297SDaniel Borkmann fdput(f); 932db20fd2bSAlexei Starovoitov 933db20fd2bSAlexei Starovoitov return map; 934db20fd2bSAlexei Starovoitov } 935db20fd2bSAlexei Starovoitov 936bd5f5f4eSMartin KaFai Lau /* map_idr_lock should have been held */ 9371e0bd5a0SAndrii Nakryiko static struct bpf_map *__bpf_map_inc_not_zero(struct bpf_map *map, bool uref) 938bd5f5f4eSMartin KaFai Lau { 939bd5f5f4eSMartin KaFai Lau int refold; 940bd5f5f4eSMartin KaFai Lau 9411e0bd5a0SAndrii Nakryiko refold = atomic64_fetch_add_unless(&map->refcnt, 1, 0); 942bd5f5f4eSMartin KaFai Lau if (!refold) 943bd5f5f4eSMartin KaFai Lau return ERR_PTR(-ENOENT); 944bd5f5f4eSMartin KaFai Lau if (uref) 9451e0bd5a0SAndrii Nakryiko atomic64_inc(&map->usercnt); 946bd5f5f4eSMartin KaFai Lau 947bd5f5f4eSMartin KaFai Lau return map; 948bd5f5f4eSMartin KaFai Lau } 949bd5f5f4eSMartin KaFai Lau 9501e0bd5a0SAndrii Nakryiko struct bpf_map *bpf_map_inc_not_zero(struct bpf_map *map) 951b0e4701cSStanislav Fomichev { 952b0e4701cSStanislav Fomichev spin_lock_bh(&map_idr_lock); 9531e0bd5a0SAndrii Nakryiko map = __bpf_map_inc_not_zero(map, false); 954b0e4701cSStanislav Fomichev spin_unlock_bh(&map_idr_lock); 955b0e4701cSStanislav Fomichev 956b0e4701cSStanislav Fomichev return map; 957b0e4701cSStanislav Fomichev } 958b0e4701cSStanislav Fomichev EXPORT_SYMBOL_GPL(bpf_map_inc_not_zero); 959b0e4701cSStanislav Fomichev 960b8cdc051SAlexei Starovoitov int __weak bpf_stackmap_copy(struct bpf_map *map, void *key, void *value) 961b8cdc051SAlexei Starovoitov { 962b8cdc051SAlexei Starovoitov return -ENOTSUPP; 963b8cdc051SAlexei Starovoitov } 964b8cdc051SAlexei Starovoitov 965c9d29f46SMauricio Vasquez B static void *__bpf_copy_key(void __user *ukey, u64 key_size) 966c9d29f46SMauricio Vasquez B { 967c9d29f46SMauricio Vasquez B if (key_size) 968c9d29f46SMauricio Vasquez B return memdup_user(ukey, key_size); 969c9d29f46SMauricio Vasquez B 970c9d29f46SMauricio Vasquez B if (ukey) 971c9d29f46SMauricio Vasquez B return ERR_PTR(-EINVAL); 972c9d29f46SMauricio Vasquez B 973c9d29f46SMauricio Vasquez B return NULL; 974c9d29f46SMauricio Vasquez B } 975c9d29f46SMauricio Vasquez B 976db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */ 97796049f3aSAlexei Starovoitov #define BPF_MAP_LOOKUP_ELEM_LAST_FIELD flags 978db20fd2bSAlexei Starovoitov 979db20fd2bSAlexei Starovoitov static int map_lookup_elem(union bpf_attr *attr) 980db20fd2bSAlexei Starovoitov { 981535e7b4bSMickaël Salaün void __user *ukey = u64_to_user_ptr(attr->key); 982535e7b4bSMickaël Salaün void __user *uvalue = u64_to_user_ptr(attr->value); 983db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 984db20fd2bSAlexei Starovoitov struct bpf_map *map; 98515c14a3dSBrian Vazquez void *key, *value; 98615a07b33SAlexei Starovoitov u32 value_size; 987592867bfSDaniel Borkmann struct fd f; 988db20fd2bSAlexei Starovoitov int err; 989db20fd2bSAlexei Starovoitov 990db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM)) 991db20fd2bSAlexei Starovoitov return -EINVAL; 992db20fd2bSAlexei Starovoitov 99396049f3aSAlexei Starovoitov if (attr->flags & ~BPF_F_LOCK) 99496049f3aSAlexei Starovoitov return -EINVAL; 99596049f3aSAlexei Starovoitov 996592867bfSDaniel Borkmann f = fdget(ufd); 997c2101297SDaniel Borkmann map = __bpf_map_get(f); 998db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 999db20fd2bSAlexei Starovoitov return PTR_ERR(map); 100087df15deSDaniel Borkmann if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ)) { 10016e71b04aSChenbo Feng err = -EPERM; 10026e71b04aSChenbo Feng goto err_put; 10036e71b04aSChenbo Feng } 10046e71b04aSChenbo Feng 100596049f3aSAlexei Starovoitov if ((attr->flags & BPF_F_LOCK) && 100696049f3aSAlexei Starovoitov !map_value_has_spin_lock(map)) { 100796049f3aSAlexei Starovoitov err = -EINVAL; 100896049f3aSAlexei Starovoitov goto err_put; 100996049f3aSAlexei Starovoitov } 101096049f3aSAlexei Starovoitov 1011c9d29f46SMauricio Vasquez B key = __bpf_copy_key(ukey, map->key_size); 1012e4448ed8SAl Viro if (IS_ERR(key)) { 1013e4448ed8SAl Viro err = PTR_ERR(key); 1014db20fd2bSAlexei Starovoitov goto err_put; 1015e4448ed8SAl Viro } 1016db20fd2bSAlexei Starovoitov 101715c14a3dSBrian Vazquez value_size = bpf_map_value_size(map); 101815a07b33SAlexei Starovoitov 10198ebe667cSAlexei Starovoitov err = -ENOMEM; 102015a07b33SAlexei Starovoitov value = kmalloc(value_size, GFP_USER | __GFP_NOWARN); 1021db20fd2bSAlexei Starovoitov if (!value) 10228ebe667cSAlexei Starovoitov goto free_key; 10238ebe667cSAlexei Starovoitov 102415c14a3dSBrian Vazquez err = bpf_map_copy_value(map, key, value, attr->flags); 102515a07b33SAlexei Starovoitov if (err) 10268ebe667cSAlexei Starovoitov goto free_value; 1027db20fd2bSAlexei Starovoitov 1028db20fd2bSAlexei Starovoitov err = -EFAULT; 102915a07b33SAlexei Starovoitov if (copy_to_user(uvalue, value, value_size) != 0) 10308ebe667cSAlexei Starovoitov goto free_value; 1031db20fd2bSAlexei Starovoitov 1032db20fd2bSAlexei Starovoitov err = 0; 1033db20fd2bSAlexei Starovoitov 10348ebe667cSAlexei Starovoitov free_value: 10358ebe667cSAlexei Starovoitov kfree(value); 1036db20fd2bSAlexei Starovoitov free_key: 1037db20fd2bSAlexei Starovoitov kfree(key); 1038db20fd2bSAlexei Starovoitov err_put: 1039db20fd2bSAlexei Starovoitov fdput(f); 1040db20fd2bSAlexei Starovoitov return err; 1041db20fd2bSAlexei Starovoitov } 1042db20fd2bSAlexei Starovoitov 10431ae80cf3SDaniel Colascione 10443274f520SAlexei Starovoitov #define BPF_MAP_UPDATE_ELEM_LAST_FIELD flags 1045db20fd2bSAlexei Starovoitov 1046db20fd2bSAlexei Starovoitov static int map_update_elem(union bpf_attr *attr) 1047db20fd2bSAlexei Starovoitov { 1048535e7b4bSMickaël Salaün void __user *ukey = u64_to_user_ptr(attr->key); 1049535e7b4bSMickaël Salaün void __user *uvalue = u64_to_user_ptr(attr->value); 1050db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 1051db20fd2bSAlexei Starovoitov struct bpf_map *map; 1052db20fd2bSAlexei Starovoitov void *key, *value; 105315a07b33SAlexei Starovoitov u32 value_size; 1054592867bfSDaniel Borkmann struct fd f; 1055db20fd2bSAlexei Starovoitov int err; 1056db20fd2bSAlexei Starovoitov 1057db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_UPDATE_ELEM)) 1058db20fd2bSAlexei Starovoitov return -EINVAL; 1059db20fd2bSAlexei Starovoitov 1060592867bfSDaniel Borkmann f = fdget(ufd); 1061c2101297SDaniel Borkmann map = __bpf_map_get(f); 1062db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 1063db20fd2bSAlexei Starovoitov return PTR_ERR(map); 106487df15deSDaniel Borkmann if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) { 10656e71b04aSChenbo Feng err = -EPERM; 10666e71b04aSChenbo Feng goto err_put; 10676e71b04aSChenbo Feng } 10686e71b04aSChenbo Feng 106996049f3aSAlexei Starovoitov if ((attr->flags & BPF_F_LOCK) && 107096049f3aSAlexei Starovoitov !map_value_has_spin_lock(map)) { 107196049f3aSAlexei Starovoitov err = -EINVAL; 107296049f3aSAlexei Starovoitov goto err_put; 107396049f3aSAlexei Starovoitov } 107496049f3aSAlexei Starovoitov 1075c9d29f46SMauricio Vasquez B key = __bpf_copy_key(ukey, map->key_size); 1076e4448ed8SAl Viro if (IS_ERR(key)) { 1077e4448ed8SAl Viro err = PTR_ERR(key); 1078db20fd2bSAlexei Starovoitov goto err_put; 1079e4448ed8SAl Viro } 1080db20fd2bSAlexei Starovoitov 108115a07b33SAlexei Starovoitov if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 10828f844938SMartin KaFai Lau map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH || 1083b741f163SRoman Gushchin map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY || 1084b741f163SRoman Gushchin map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) 108515a07b33SAlexei Starovoitov value_size = round_up(map->value_size, 8) * num_possible_cpus(); 108615a07b33SAlexei Starovoitov else 108715a07b33SAlexei Starovoitov value_size = map->value_size; 108815a07b33SAlexei Starovoitov 1089db20fd2bSAlexei Starovoitov err = -ENOMEM; 109015a07b33SAlexei Starovoitov value = kmalloc(value_size, GFP_USER | __GFP_NOWARN); 1091db20fd2bSAlexei Starovoitov if (!value) 1092db20fd2bSAlexei Starovoitov goto free_key; 1093db20fd2bSAlexei Starovoitov 1094db20fd2bSAlexei Starovoitov err = -EFAULT; 109515a07b33SAlexei Starovoitov if (copy_from_user(value, uvalue, value_size) != 0) 1096db20fd2bSAlexei Starovoitov goto free_value; 1097db20fd2bSAlexei Starovoitov 109815c14a3dSBrian Vazquez err = bpf_map_update_value(map, f, key, value, attr->flags); 10996710e112SJesper Dangaard Brouer 1100db20fd2bSAlexei Starovoitov free_value: 1101db20fd2bSAlexei Starovoitov kfree(value); 1102db20fd2bSAlexei Starovoitov free_key: 1103db20fd2bSAlexei Starovoitov kfree(key); 1104db20fd2bSAlexei Starovoitov err_put: 1105db20fd2bSAlexei Starovoitov fdput(f); 1106db20fd2bSAlexei Starovoitov return err; 1107db20fd2bSAlexei Starovoitov } 1108db20fd2bSAlexei Starovoitov 1109db20fd2bSAlexei Starovoitov #define BPF_MAP_DELETE_ELEM_LAST_FIELD key 1110db20fd2bSAlexei Starovoitov 1111db20fd2bSAlexei Starovoitov static int map_delete_elem(union bpf_attr *attr) 1112db20fd2bSAlexei Starovoitov { 1113535e7b4bSMickaël Salaün void __user *ukey = u64_to_user_ptr(attr->key); 1114db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 1115db20fd2bSAlexei Starovoitov struct bpf_map *map; 1116592867bfSDaniel Borkmann struct fd f; 1117db20fd2bSAlexei Starovoitov void *key; 1118db20fd2bSAlexei Starovoitov int err; 1119db20fd2bSAlexei Starovoitov 1120db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_DELETE_ELEM)) 1121db20fd2bSAlexei Starovoitov return -EINVAL; 1122db20fd2bSAlexei Starovoitov 1123592867bfSDaniel Borkmann f = fdget(ufd); 1124c2101297SDaniel Borkmann map = __bpf_map_get(f); 1125db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 1126db20fd2bSAlexei Starovoitov return PTR_ERR(map); 112787df15deSDaniel Borkmann if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) { 11286e71b04aSChenbo Feng err = -EPERM; 11296e71b04aSChenbo Feng goto err_put; 11306e71b04aSChenbo Feng } 11316e71b04aSChenbo Feng 1132c9d29f46SMauricio Vasquez B key = __bpf_copy_key(ukey, map->key_size); 1133e4448ed8SAl Viro if (IS_ERR(key)) { 1134e4448ed8SAl Viro err = PTR_ERR(key); 1135db20fd2bSAlexei Starovoitov goto err_put; 1136e4448ed8SAl Viro } 1137db20fd2bSAlexei Starovoitov 1138a3884572SJakub Kicinski if (bpf_map_is_dev_bound(map)) { 1139a3884572SJakub Kicinski err = bpf_map_offload_delete_elem(map, key); 1140a3884572SJakub Kicinski goto out; 114185d33df3SMartin KaFai Lau } else if (IS_FD_PROG_ARRAY(map) || 114285d33df3SMartin KaFai Lau map->map_type == BPF_MAP_TYPE_STRUCT_OPS) { 114385d33df3SMartin KaFai Lau /* These maps require sleepable context */ 1144da765a2fSDaniel Borkmann err = map->ops->map_delete_elem(map, key); 1145da765a2fSDaniel Borkmann goto out; 1146a3884572SJakub Kicinski } 1147a3884572SJakub Kicinski 1148b6e5dae1SThomas Gleixner bpf_disable_instrumentation(); 1149db20fd2bSAlexei Starovoitov rcu_read_lock(); 1150db20fd2bSAlexei Starovoitov err = map->ops->map_delete_elem(map, key); 1151db20fd2bSAlexei Starovoitov rcu_read_unlock(); 1152b6e5dae1SThomas Gleixner bpf_enable_instrumentation(); 11531ae80cf3SDaniel Colascione maybe_wait_bpf_programs(map); 1154a3884572SJakub Kicinski out: 1155db20fd2bSAlexei Starovoitov kfree(key); 1156db20fd2bSAlexei Starovoitov err_put: 1157db20fd2bSAlexei Starovoitov fdput(f); 1158db20fd2bSAlexei Starovoitov return err; 1159db20fd2bSAlexei Starovoitov } 1160db20fd2bSAlexei Starovoitov 1161db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */ 1162db20fd2bSAlexei Starovoitov #define BPF_MAP_GET_NEXT_KEY_LAST_FIELD next_key 1163db20fd2bSAlexei Starovoitov 1164db20fd2bSAlexei Starovoitov static int map_get_next_key(union bpf_attr *attr) 1165db20fd2bSAlexei Starovoitov { 1166535e7b4bSMickaël Salaün void __user *ukey = u64_to_user_ptr(attr->key); 1167535e7b4bSMickaël Salaün void __user *unext_key = u64_to_user_ptr(attr->next_key); 1168db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 1169db20fd2bSAlexei Starovoitov struct bpf_map *map; 1170db20fd2bSAlexei Starovoitov void *key, *next_key; 1171592867bfSDaniel Borkmann struct fd f; 1172db20fd2bSAlexei Starovoitov int err; 1173db20fd2bSAlexei Starovoitov 1174db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_GET_NEXT_KEY)) 1175db20fd2bSAlexei Starovoitov return -EINVAL; 1176db20fd2bSAlexei Starovoitov 1177592867bfSDaniel Borkmann f = fdget(ufd); 1178c2101297SDaniel Borkmann map = __bpf_map_get(f); 1179db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 1180db20fd2bSAlexei Starovoitov return PTR_ERR(map); 118187df15deSDaniel Borkmann if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ)) { 11826e71b04aSChenbo Feng err = -EPERM; 11836e71b04aSChenbo Feng goto err_put; 11846e71b04aSChenbo Feng } 11856e71b04aSChenbo Feng 11868fe45924STeng Qin if (ukey) { 1187c9d29f46SMauricio Vasquez B key = __bpf_copy_key(ukey, map->key_size); 1188e4448ed8SAl Viro if (IS_ERR(key)) { 1189e4448ed8SAl Viro err = PTR_ERR(key); 1190db20fd2bSAlexei Starovoitov goto err_put; 1191e4448ed8SAl Viro } 11928fe45924STeng Qin } else { 11938fe45924STeng Qin key = NULL; 11948fe45924STeng Qin } 1195db20fd2bSAlexei Starovoitov 1196db20fd2bSAlexei Starovoitov err = -ENOMEM; 1197db20fd2bSAlexei Starovoitov next_key = kmalloc(map->key_size, GFP_USER); 1198db20fd2bSAlexei Starovoitov if (!next_key) 1199db20fd2bSAlexei Starovoitov goto free_key; 1200db20fd2bSAlexei Starovoitov 1201a3884572SJakub Kicinski if (bpf_map_is_dev_bound(map)) { 1202a3884572SJakub Kicinski err = bpf_map_offload_get_next_key(map, key, next_key); 1203a3884572SJakub Kicinski goto out; 1204a3884572SJakub Kicinski } 1205a3884572SJakub Kicinski 1206db20fd2bSAlexei Starovoitov rcu_read_lock(); 1207db20fd2bSAlexei Starovoitov err = map->ops->map_get_next_key(map, key, next_key); 1208db20fd2bSAlexei Starovoitov rcu_read_unlock(); 1209a3884572SJakub Kicinski out: 1210db20fd2bSAlexei Starovoitov if (err) 1211db20fd2bSAlexei Starovoitov goto free_next_key; 1212db20fd2bSAlexei Starovoitov 1213db20fd2bSAlexei Starovoitov err = -EFAULT; 1214db20fd2bSAlexei Starovoitov if (copy_to_user(unext_key, next_key, map->key_size) != 0) 1215db20fd2bSAlexei Starovoitov goto free_next_key; 1216db20fd2bSAlexei Starovoitov 1217db20fd2bSAlexei Starovoitov err = 0; 1218db20fd2bSAlexei Starovoitov 1219db20fd2bSAlexei Starovoitov free_next_key: 1220db20fd2bSAlexei Starovoitov kfree(next_key); 1221db20fd2bSAlexei Starovoitov free_key: 1222db20fd2bSAlexei Starovoitov kfree(key); 1223db20fd2bSAlexei Starovoitov err_put: 1224db20fd2bSAlexei Starovoitov fdput(f); 1225db20fd2bSAlexei Starovoitov return err; 1226db20fd2bSAlexei Starovoitov } 1227db20fd2bSAlexei Starovoitov 1228aa2e93b8SBrian Vazquez int generic_map_delete_batch(struct bpf_map *map, 1229aa2e93b8SBrian Vazquez const union bpf_attr *attr, 1230aa2e93b8SBrian Vazquez union bpf_attr __user *uattr) 1231aa2e93b8SBrian Vazquez { 1232aa2e93b8SBrian Vazquez void __user *keys = u64_to_user_ptr(attr->batch.keys); 1233aa2e93b8SBrian Vazquez u32 cp, max_count; 1234aa2e93b8SBrian Vazquez int err = 0; 1235aa2e93b8SBrian Vazquez void *key; 1236aa2e93b8SBrian Vazquez 1237aa2e93b8SBrian Vazquez if (attr->batch.elem_flags & ~BPF_F_LOCK) 1238aa2e93b8SBrian Vazquez return -EINVAL; 1239aa2e93b8SBrian Vazquez 1240aa2e93b8SBrian Vazquez if ((attr->batch.elem_flags & BPF_F_LOCK) && 1241aa2e93b8SBrian Vazquez !map_value_has_spin_lock(map)) { 1242aa2e93b8SBrian Vazquez return -EINVAL; 1243aa2e93b8SBrian Vazquez } 1244aa2e93b8SBrian Vazquez 1245aa2e93b8SBrian Vazquez max_count = attr->batch.count; 1246aa2e93b8SBrian Vazquez if (!max_count) 1247aa2e93b8SBrian Vazquez return 0; 1248aa2e93b8SBrian Vazquez 12492e3a94aaSBrian Vazquez key = kmalloc(map->key_size, GFP_USER | __GFP_NOWARN); 12502e3a94aaSBrian Vazquez if (!key) 12512e3a94aaSBrian Vazquez return -ENOMEM; 12522e3a94aaSBrian Vazquez 1253aa2e93b8SBrian Vazquez for (cp = 0; cp < max_count; cp++) { 12542e3a94aaSBrian Vazquez err = -EFAULT; 12552e3a94aaSBrian Vazquez if (copy_from_user(key, keys + cp * map->key_size, 12562e3a94aaSBrian Vazquez map->key_size)) 1257aa2e93b8SBrian Vazquez break; 1258aa2e93b8SBrian Vazquez 1259aa2e93b8SBrian Vazquez if (bpf_map_is_dev_bound(map)) { 1260aa2e93b8SBrian Vazquez err = bpf_map_offload_delete_elem(map, key); 1261aa2e93b8SBrian Vazquez break; 1262aa2e93b8SBrian Vazquez } 1263aa2e93b8SBrian Vazquez 1264b6e5dae1SThomas Gleixner bpf_disable_instrumentation(); 1265aa2e93b8SBrian Vazquez rcu_read_lock(); 1266aa2e93b8SBrian Vazquez err = map->ops->map_delete_elem(map, key); 1267aa2e93b8SBrian Vazquez rcu_read_unlock(); 1268b6e5dae1SThomas Gleixner bpf_enable_instrumentation(); 1269aa2e93b8SBrian Vazquez maybe_wait_bpf_programs(map); 1270aa2e93b8SBrian Vazquez if (err) 1271aa2e93b8SBrian Vazquez break; 1272aa2e93b8SBrian Vazquez } 1273aa2e93b8SBrian Vazquez if (copy_to_user(&uattr->batch.count, &cp, sizeof(cp))) 1274aa2e93b8SBrian Vazquez err = -EFAULT; 12752e3a94aaSBrian Vazquez 12762e3a94aaSBrian Vazquez kfree(key); 1277aa2e93b8SBrian Vazquez return err; 1278aa2e93b8SBrian Vazquez } 1279aa2e93b8SBrian Vazquez 1280aa2e93b8SBrian Vazquez int generic_map_update_batch(struct bpf_map *map, 1281aa2e93b8SBrian Vazquez const union bpf_attr *attr, 1282aa2e93b8SBrian Vazquez union bpf_attr __user *uattr) 1283aa2e93b8SBrian Vazquez { 1284aa2e93b8SBrian Vazquez void __user *values = u64_to_user_ptr(attr->batch.values); 1285aa2e93b8SBrian Vazquez void __user *keys = u64_to_user_ptr(attr->batch.keys); 1286aa2e93b8SBrian Vazquez u32 value_size, cp, max_count; 1287aa2e93b8SBrian Vazquez int ufd = attr->map_fd; 1288aa2e93b8SBrian Vazquez void *key, *value; 1289aa2e93b8SBrian Vazquez struct fd f; 1290aa2e93b8SBrian Vazquez int err = 0; 1291aa2e93b8SBrian Vazquez 1292aa2e93b8SBrian Vazquez f = fdget(ufd); 1293aa2e93b8SBrian Vazquez if (attr->batch.elem_flags & ~BPF_F_LOCK) 1294aa2e93b8SBrian Vazquez return -EINVAL; 1295aa2e93b8SBrian Vazquez 1296aa2e93b8SBrian Vazquez if ((attr->batch.elem_flags & BPF_F_LOCK) && 1297aa2e93b8SBrian Vazquez !map_value_has_spin_lock(map)) { 1298aa2e93b8SBrian Vazquez return -EINVAL; 1299aa2e93b8SBrian Vazquez } 1300aa2e93b8SBrian Vazquez 1301aa2e93b8SBrian Vazquez value_size = bpf_map_value_size(map); 1302aa2e93b8SBrian Vazquez 1303aa2e93b8SBrian Vazquez max_count = attr->batch.count; 1304aa2e93b8SBrian Vazquez if (!max_count) 1305aa2e93b8SBrian Vazquez return 0; 1306aa2e93b8SBrian Vazquez 13072e3a94aaSBrian Vazquez key = kmalloc(map->key_size, GFP_USER | __GFP_NOWARN); 13082e3a94aaSBrian Vazquez if (!key) 1309aa2e93b8SBrian Vazquez return -ENOMEM; 1310aa2e93b8SBrian Vazquez 13112e3a94aaSBrian Vazquez value = kmalloc(value_size, GFP_USER | __GFP_NOWARN); 13122e3a94aaSBrian Vazquez if (!value) { 13132e3a94aaSBrian Vazquez kfree(key); 13142e3a94aaSBrian Vazquez return -ENOMEM; 1315aa2e93b8SBrian Vazquez } 13162e3a94aaSBrian Vazquez 13172e3a94aaSBrian Vazquez for (cp = 0; cp < max_count; cp++) { 1318aa2e93b8SBrian Vazquez err = -EFAULT; 13192e3a94aaSBrian Vazquez if (copy_from_user(key, keys + cp * map->key_size, 13202e3a94aaSBrian Vazquez map->key_size) || 13212e3a94aaSBrian Vazquez copy_from_user(value, values + cp * value_size, value_size)) 1322aa2e93b8SBrian Vazquez break; 1323aa2e93b8SBrian Vazquez 1324aa2e93b8SBrian Vazquez err = bpf_map_update_value(map, f, key, value, 1325aa2e93b8SBrian Vazquez attr->batch.elem_flags); 1326aa2e93b8SBrian Vazquez 1327aa2e93b8SBrian Vazquez if (err) 1328aa2e93b8SBrian Vazquez break; 1329aa2e93b8SBrian Vazquez } 1330aa2e93b8SBrian Vazquez 1331aa2e93b8SBrian Vazquez if (copy_to_user(&uattr->batch.count, &cp, sizeof(cp))) 1332aa2e93b8SBrian Vazquez err = -EFAULT; 1333aa2e93b8SBrian Vazquez 1334aa2e93b8SBrian Vazquez kfree(value); 1335aa2e93b8SBrian Vazquez kfree(key); 1336aa2e93b8SBrian Vazquez return err; 1337aa2e93b8SBrian Vazquez } 1338aa2e93b8SBrian Vazquez 1339cb4d03abSBrian Vazquez #define MAP_LOOKUP_RETRIES 3 1340cb4d03abSBrian Vazquez 1341cb4d03abSBrian Vazquez int generic_map_lookup_batch(struct bpf_map *map, 1342cb4d03abSBrian Vazquez const union bpf_attr *attr, 1343cb4d03abSBrian Vazquez union bpf_attr __user *uattr) 1344cb4d03abSBrian Vazquez { 1345cb4d03abSBrian Vazquez void __user *uobatch = u64_to_user_ptr(attr->batch.out_batch); 1346cb4d03abSBrian Vazquez void __user *ubatch = u64_to_user_ptr(attr->batch.in_batch); 1347cb4d03abSBrian Vazquez void __user *values = u64_to_user_ptr(attr->batch.values); 1348cb4d03abSBrian Vazquez void __user *keys = u64_to_user_ptr(attr->batch.keys); 1349cb4d03abSBrian Vazquez void *buf, *buf_prevkey, *prev_key, *key, *value; 1350cb4d03abSBrian Vazquez int err, retry = MAP_LOOKUP_RETRIES; 1351cb4d03abSBrian Vazquez u32 value_size, cp, max_count; 1352cb4d03abSBrian Vazquez 1353cb4d03abSBrian Vazquez if (attr->batch.elem_flags & ~BPF_F_LOCK) 1354cb4d03abSBrian Vazquez return -EINVAL; 1355cb4d03abSBrian Vazquez 1356cb4d03abSBrian Vazquez if ((attr->batch.elem_flags & BPF_F_LOCK) && 1357cb4d03abSBrian Vazquez !map_value_has_spin_lock(map)) 1358cb4d03abSBrian Vazquez return -EINVAL; 1359cb4d03abSBrian Vazquez 1360cb4d03abSBrian Vazquez value_size = bpf_map_value_size(map); 1361cb4d03abSBrian Vazquez 1362cb4d03abSBrian Vazquez max_count = attr->batch.count; 1363cb4d03abSBrian Vazquez if (!max_count) 1364cb4d03abSBrian Vazquez return 0; 1365cb4d03abSBrian Vazquez 1366cb4d03abSBrian Vazquez if (put_user(0, &uattr->batch.count)) 1367cb4d03abSBrian Vazquez return -EFAULT; 1368cb4d03abSBrian Vazquez 1369cb4d03abSBrian Vazquez buf_prevkey = kmalloc(map->key_size, GFP_USER | __GFP_NOWARN); 1370cb4d03abSBrian Vazquez if (!buf_prevkey) 1371cb4d03abSBrian Vazquez return -ENOMEM; 1372cb4d03abSBrian Vazquez 1373cb4d03abSBrian Vazquez buf = kmalloc(map->key_size + value_size, GFP_USER | __GFP_NOWARN); 1374cb4d03abSBrian Vazquez if (!buf) { 1375cb4d03abSBrian Vazquez kvfree(buf_prevkey); 1376cb4d03abSBrian Vazquez return -ENOMEM; 1377cb4d03abSBrian Vazquez } 1378cb4d03abSBrian Vazquez 1379cb4d03abSBrian Vazquez err = -EFAULT; 1380cb4d03abSBrian Vazquez prev_key = NULL; 1381cb4d03abSBrian Vazquez if (ubatch && copy_from_user(buf_prevkey, ubatch, map->key_size)) 1382cb4d03abSBrian Vazquez goto free_buf; 1383cb4d03abSBrian Vazquez key = buf; 1384cb4d03abSBrian Vazquez value = key + map->key_size; 1385cb4d03abSBrian Vazquez if (ubatch) 1386cb4d03abSBrian Vazquez prev_key = buf_prevkey; 1387cb4d03abSBrian Vazquez 1388cb4d03abSBrian Vazquez for (cp = 0; cp < max_count;) { 1389cb4d03abSBrian Vazquez rcu_read_lock(); 1390cb4d03abSBrian Vazquez err = map->ops->map_get_next_key(map, prev_key, key); 1391cb4d03abSBrian Vazquez rcu_read_unlock(); 1392cb4d03abSBrian Vazquez if (err) 1393cb4d03abSBrian Vazquez break; 1394cb4d03abSBrian Vazquez err = bpf_map_copy_value(map, key, value, 1395cb4d03abSBrian Vazquez attr->batch.elem_flags); 1396cb4d03abSBrian Vazquez 1397cb4d03abSBrian Vazquez if (err == -ENOENT) { 1398cb4d03abSBrian Vazquez if (retry) { 1399cb4d03abSBrian Vazquez retry--; 1400cb4d03abSBrian Vazquez continue; 1401cb4d03abSBrian Vazquez } 1402cb4d03abSBrian Vazquez err = -EINTR; 1403cb4d03abSBrian Vazquez break; 1404cb4d03abSBrian Vazquez } 1405cb4d03abSBrian Vazquez 1406cb4d03abSBrian Vazquez if (err) 1407cb4d03abSBrian Vazquez goto free_buf; 1408cb4d03abSBrian Vazquez 1409cb4d03abSBrian Vazquez if (copy_to_user(keys + cp * map->key_size, key, 1410cb4d03abSBrian Vazquez map->key_size)) { 1411cb4d03abSBrian Vazquez err = -EFAULT; 1412cb4d03abSBrian Vazquez goto free_buf; 1413cb4d03abSBrian Vazquez } 1414cb4d03abSBrian Vazquez if (copy_to_user(values + cp * value_size, value, value_size)) { 1415cb4d03abSBrian Vazquez err = -EFAULT; 1416cb4d03abSBrian Vazquez goto free_buf; 1417cb4d03abSBrian Vazquez } 1418cb4d03abSBrian Vazquez 1419cb4d03abSBrian Vazquez if (!prev_key) 1420cb4d03abSBrian Vazquez prev_key = buf_prevkey; 1421cb4d03abSBrian Vazquez 1422cb4d03abSBrian Vazquez swap(prev_key, key); 1423cb4d03abSBrian Vazquez retry = MAP_LOOKUP_RETRIES; 1424cb4d03abSBrian Vazquez cp++; 1425cb4d03abSBrian Vazquez } 1426cb4d03abSBrian Vazquez 1427cb4d03abSBrian Vazquez if (err == -EFAULT) 1428cb4d03abSBrian Vazquez goto free_buf; 1429cb4d03abSBrian Vazquez 1430cb4d03abSBrian Vazquez if ((copy_to_user(&uattr->batch.count, &cp, sizeof(cp)) || 1431cb4d03abSBrian Vazquez (cp && copy_to_user(uobatch, prev_key, map->key_size)))) 1432cb4d03abSBrian Vazquez err = -EFAULT; 1433cb4d03abSBrian Vazquez 1434cb4d03abSBrian Vazquez free_buf: 1435cb4d03abSBrian Vazquez kfree(buf_prevkey); 1436cb4d03abSBrian Vazquez kfree(buf); 1437cb4d03abSBrian Vazquez return err; 1438cb4d03abSBrian Vazquez } 1439cb4d03abSBrian Vazquez 1440bd513cd0SMauricio Vasquez B #define BPF_MAP_LOOKUP_AND_DELETE_ELEM_LAST_FIELD value 1441bd513cd0SMauricio Vasquez B 1442bd513cd0SMauricio Vasquez B static int map_lookup_and_delete_elem(union bpf_attr *attr) 1443bd513cd0SMauricio Vasquez B { 1444bd513cd0SMauricio Vasquez B void __user *ukey = u64_to_user_ptr(attr->key); 1445bd513cd0SMauricio Vasquez B void __user *uvalue = u64_to_user_ptr(attr->value); 1446bd513cd0SMauricio Vasquez B int ufd = attr->map_fd; 1447bd513cd0SMauricio Vasquez B struct bpf_map *map; 1448540fefc0SAlexei Starovoitov void *key, *value; 1449bd513cd0SMauricio Vasquez B u32 value_size; 1450bd513cd0SMauricio Vasquez B struct fd f; 1451bd513cd0SMauricio Vasquez B int err; 1452bd513cd0SMauricio Vasquez B 1453bd513cd0SMauricio Vasquez B if (CHECK_ATTR(BPF_MAP_LOOKUP_AND_DELETE_ELEM)) 1454bd513cd0SMauricio Vasquez B return -EINVAL; 1455bd513cd0SMauricio Vasquez B 1456bd513cd0SMauricio Vasquez B f = fdget(ufd); 1457bd513cd0SMauricio Vasquez B map = __bpf_map_get(f); 1458bd513cd0SMauricio Vasquez B if (IS_ERR(map)) 1459bd513cd0SMauricio Vasquez B return PTR_ERR(map); 146087df15deSDaniel Borkmann if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) { 1461bd513cd0SMauricio Vasquez B err = -EPERM; 1462bd513cd0SMauricio Vasquez B goto err_put; 1463bd513cd0SMauricio Vasquez B } 1464bd513cd0SMauricio Vasquez B 1465bd513cd0SMauricio Vasquez B key = __bpf_copy_key(ukey, map->key_size); 1466bd513cd0SMauricio Vasquez B if (IS_ERR(key)) { 1467bd513cd0SMauricio Vasquez B err = PTR_ERR(key); 1468bd513cd0SMauricio Vasquez B goto err_put; 1469bd513cd0SMauricio Vasquez B } 1470bd513cd0SMauricio Vasquez B 1471bd513cd0SMauricio Vasquez B value_size = map->value_size; 1472bd513cd0SMauricio Vasquez B 1473bd513cd0SMauricio Vasquez B err = -ENOMEM; 1474bd513cd0SMauricio Vasquez B value = kmalloc(value_size, GFP_USER | __GFP_NOWARN); 1475bd513cd0SMauricio Vasquez B if (!value) 1476bd513cd0SMauricio Vasquez B goto free_key; 1477bd513cd0SMauricio Vasquez B 1478bd513cd0SMauricio Vasquez B if (map->map_type == BPF_MAP_TYPE_QUEUE || 1479bd513cd0SMauricio Vasquez B map->map_type == BPF_MAP_TYPE_STACK) { 1480bd513cd0SMauricio Vasquez B err = map->ops->map_pop_elem(map, value); 1481bd513cd0SMauricio Vasquez B } else { 1482bd513cd0SMauricio Vasquez B err = -ENOTSUPP; 1483bd513cd0SMauricio Vasquez B } 1484bd513cd0SMauricio Vasquez B 1485bd513cd0SMauricio Vasquez B if (err) 1486bd513cd0SMauricio Vasquez B goto free_value; 1487bd513cd0SMauricio Vasquez B 1488bd513cd0SMauricio Vasquez B if (copy_to_user(uvalue, value, value_size) != 0) 1489bd513cd0SMauricio Vasquez B goto free_value; 1490bd513cd0SMauricio Vasquez B 1491bd513cd0SMauricio Vasquez B err = 0; 1492bd513cd0SMauricio Vasquez B 1493bd513cd0SMauricio Vasquez B free_value: 1494bd513cd0SMauricio Vasquez B kfree(value); 1495bd513cd0SMauricio Vasquez B free_key: 1496bd513cd0SMauricio Vasquez B kfree(key); 1497bd513cd0SMauricio Vasquez B err_put: 1498bd513cd0SMauricio Vasquez B fdput(f); 1499bd513cd0SMauricio Vasquez B return err; 1500bd513cd0SMauricio Vasquez B } 1501bd513cd0SMauricio Vasquez B 150287df15deSDaniel Borkmann #define BPF_MAP_FREEZE_LAST_FIELD map_fd 150387df15deSDaniel Borkmann 150487df15deSDaniel Borkmann static int map_freeze(const union bpf_attr *attr) 150587df15deSDaniel Borkmann { 150687df15deSDaniel Borkmann int err = 0, ufd = attr->map_fd; 150787df15deSDaniel Borkmann struct bpf_map *map; 150887df15deSDaniel Borkmann struct fd f; 150987df15deSDaniel Borkmann 151087df15deSDaniel Borkmann if (CHECK_ATTR(BPF_MAP_FREEZE)) 151187df15deSDaniel Borkmann return -EINVAL; 151287df15deSDaniel Borkmann 151387df15deSDaniel Borkmann f = fdget(ufd); 151487df15deSDaniel Borkmann map = __bpf_map_get(f); 151587df15deSDaniel Borkmann if (IS_ERR(map)) 151687df15deSDaniel Borkmann return PTR_ERR(map); 1517fc970227SAndrii Nakryiko 1518849b4d94SMartin KaFai Lau if (map->map_type == BPF_MAP_TYPE_STRUCT_OPS) { 1519849b4d94SMartin KaFai Lau fdput(f); 1520849b4d94SMartin KaFai Lau return -ENOTSUPP; 1521849b4d94SMartin KaFai Lau } 1522849b4d94SMartin KaFai Lau 1523fc970227SAndrii Nakryiko mutex_lock(&map->freeze_mutex); 1524fc970227SAndrii Nakryiko 1525fc970227SAndrii Nakryiko if (map->writecnt) { 1526fc970227SAndrii Nakryiko err = -EBUSY; 1527fc970227SAndrii Nakryiko goto err_put; 1528fc970227SAndrii Nakryiko } 152987df15deSDaniel Borkmann if (READ_ONCE(map->frozen)) { 153087df15deSDaniel Borkmann err = -EBUSY; 153187df15deSDaniel Borkmann goto err_put; 153287df15deSDaniel Borkmann } 153387df15deSDaniel Borkmann if (!capable(CAP_SYS_ADMIN)) { 153487df15deSDaniel Borkmann err = -EPERM; 153587df15deSDaniel Borkmann goto err_put; 153687df15deSDaniel Borkmann } 153787df15deSDaniel Borkmann 153887df15deSDaniel Borkmann WRITE_ONCE(map->frozen, true); 153987df15deSDaniel Borkmann err_put: 1540fc970227SAndrii Nakryiko mutex_unlock(&map->freeze_mutex); 154187df15deSDaniel Borkmann fdput(f); 154287df15deSDaniel Borkmann return err; 154387df15deSDaniel Borkmann } 154487df15deSDaniel Borkmann 15457de16e3aSJakub Kicinski static const struct bpf_prog_ops * const bpf_prog_types[] = { 154691cc1a99SAlexei Starovoitov #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) \ 15477de16e3aSJakub Kicinski [_id] = & _name ## _prog_ops, 15487de16e3aSJakub Kicinski #define BPF_MAP_TYPE(_id, _ops) 15497de16e3aSJakub Kicinski #include <linux/bpf_types.h> 15507de16e3aSJakub Kicinski #undef BPF_PROG_TYPE 15517de16e3aSJakub Kicinski #undef BPF_MAP_TYPE 15527de16e3aSJakub Kicinski }; 15537de16e3aSJakub Kicinski 155409756af4SAlexei Starovoitov static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog) 155509756af4SAlexei Starovoitov { 1556d0f1a451SDaniel Borkmann const struct bpf_prog_ops *ops; 1557d0f1a451SDaniel Borkmann 1558d0f1a451SDaniel Borkmann if (type >= ARRAY_SIZE(bpf_prog_types)) 1559d0f1a451SDaniel Borkmann return -EINVAL; 1560d0f1a451SDaniel Borkmann type = array_index_nospec(type, ARRAY_SIZE(bpf_prog_types)); 1561d0f1a451SDaniel Borkmann ops = bpf_prog_types[type]; 1562d0f1a451SDaniel Borkmann if (!ops) 1563be9370a7SJohannes Berg return -EINVAL; 156409756af4SAlexei Starovoitov 1565ab3f0063SJakub Kicinski if (!bpf_prog_is_dev_bound(prog->aux)) 1566d0f1a451SDaniel Borkmann prog->aux->ops = ops; 1567ab3f0063SJakub Kicinski else 1568ab3f0063SJakub Kicinski prog->aux->ops = &bpf_offload_prog_ops; 156924701eceSDaniel Borkmann prog->type = type; 157009756af4SAlexei Starovoitov return 0; 157109756af4SAlexei Starovoitov } 157209756af4SAlexei Starovoitov 1573bae141f5SDaniel Borkmann enum bpf_audit { 1574bae141f5SDaniel Borkmann BPF_AUDIT_LOAD, 1575bae141f5SDaniel Borkmann BPF_AUDIT_UNLOAD, 1576bae141f5SDaniel Borkmann BPF_AUDIT_MAX, 1577bae141f5SDaniel Borkmann }; 1578bae141f5SDaniel Borkmann 1579bae141f5SDaniel Borkmann static const char * const bpf_audit_str[BPF_AUDIT_MAX] = { 1580bae141f5SDaniel Borkmann [BPF_AUDIT_LOAD] = "LOAD", 1581bae141f5SDaniel Borkmann [BPF_AUDIT_UNLOAD] = "UNLOAD", 1582bae141f5SDaniel Borkmann }; 1583bae141f5SDaniel Borkmann 1584bae141f5SDaniel Borkmann static void bpf_audit_prog(const struct bpf_prog *prog, unsigned int op) 1585bae141f5SDaniel Borkmann { 1586bae141f5SDaniel Borkmann struct audit_context *ctx = NULL; 1587bae141f5SDaniel Borkmann struct audit_buffer *ab; 1588bae141f5SDaniel Borkmann 1589bae141f5SDaniel Borkmann if (WARN_ON_ONCE(op >= BPF_AUDIT_MAX)) 1590bae141f5SDaniel Borkmann return; 1591bae141f5SDaniel Borkmann if (audit_enabled == AUDIT_OFF) 1592bae141f5SDaniel Borkmann return; 1593bae141f5SDaniel Borkmann if (op == BPF_AUDIT_LOAD) 1594bae141f5SDaniel Borkmann ctx = audit_context(); 1595bae141f5SDaniel Borkmann ab = audit_log_start(ctx, GFP_ATOMIC, AUDIT_BPF); 1596bae141f5SDaniel Borkmann if (unlikely(!ab)) 1597bae141f5SDaniel Borkmann return; 1598bae141f5SDaniel Borkmann audit_log_format(ab, "prog-id=%u op=%s", 1599bae141f5SDaniel Borkmann prog->aux->id, bpf_audit_str[op]); 1600bae141f5SDaniel Borkmann audit_log_end(ab); 1601bae141f5SDaniel Borkmann } 1602bae141f5SDaniel Borkmann 16035ccb071eSDaniel Borkmann int __bpf_prog_charge(struct user_struct *user, u32 pages) 16045ccb071eSDaniel Borkmann { 16055ccb071eSDaniel Borkmann unsigned long memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; 16065ccb071eSDaniel Borkmann unsigned long user_bufs; 16075ccb071eSDaniel Borkmann 16085ccb071eSDaniel Borkmann if (user) { 16095ccb071eSDaniel Borkmann user_bufs = atomic_long_add_return(pages, &user->locked_vm); 16105ccb071eSDaniel Borkmann if (user_bufs > memlock_limit) { 16115ccb071eSDaniel Borkmann atomic_long_sub(pages, &user->locked_vm); 16125ccb071eSDaniel Borkmann return -EPERM; 16135ccb071eSDaniel Borkmann } 16145ccb071eSDaniel Borkmann } 16155ccb071eSDaniel Borkmann 16165ccb071eSDaniel Borkmann return 0; 16175ccb071eSDaniel Borkmann } 16185ccb071eSDaniel Borkmann 16195ccb071eSDaniel Borkmann void __bpf_prog_uncharge(struct user_struct *user, u32 pages) 16205ccb071eSDaniel Borkmann { 16215ccb071eSDaniel Borkmann if (user) 16225ccb071eSDaniel Borkmann atomic_long_sub(pages, &user->locked_vm); 16235ccb071eSDaniel Borkmann } 16245ccb071eSDaniel Borkmann 1625aaac3ba9SAlexei Starovoitov static int bpf_prog_charge_memlock(struct bpf_prog *prog) 1626aaac3ba9SAlexei Starovoitov { 1627aaac3ba9SAlexei Starovoitov struct user_struct *user = get_current_user(); 16285ccb071eSDaniel Borkmann int ret; 1629aaac3ba9SAlexei Starovoitov 16305ccb071eSDaniel Borkmann ret = __bpf_prog_charge(user, prog->pages); 16315ccb071eSDaniel Borkmann if (ret) { 1632aaac3ba9SAlexei Starovoitov free_uid(user); 16335ccb071eSDaniel Borkmann return ret; 1634aaac3ba9SAlexei Starovoitov } 16355ccb071eSDaniel Borkmann 1636aaac3ba9SAlexei Starovoitov prog->aux->user = user; 1637aaac3ba9SAlexei Starovoitov return 0; 1638aaac3ba9SAlexei Starovoitov } 1639aaac3ba9SAlexei Starovoitov 1640aaac3ba9SAlexei Starovoitov static void bpf_prog_uncharge_memlock(struct bpf_prog *prog) 1641aaac3ba9SAlexei Starovoitov { 1642aaac3ba9SAlexei Starovoitov struct user_struct *user = prog->aux->user; 1643aaac3ba9SAlexei Starovoitov 16445ccb071eSDaniel Borkmann __bpf_prog_uncharge(user, prog->pages); 1645aaac3ba9SAlexei Starovoitov free_uid(user); 1646aaac3ba9SAlexei Starovoitov } 1647aaac3ba9SAlexei Starovoitov 1648dc4bb0e2SMartin KaFai Lau static int bpf_prog_alloc_id(struct bpf_prog *prog) 1649dc4bb0e2SMartin KaFai Lau { 1650dc4bb0e2SMartin KaFai Lau int id; 1651dc4bb0e2SMartin KaFai Lau 1652b76354cdSShaohua Li idr_preload(GFP_KERNEL); 1653dc4bb0e2SMartin KaFai Lau spin_lock_bh(&prog_idr_lock); 1654dc4bb0e2SMartin KaFai Lau id = idr_alloc_cyclic(&prog_idr, prog, 1, INT_MAX, GFP_ATOMIC); 1655dc4bb0e2SMartin KaFai Lau if (id > 0) 1656dc4bb0e2SMartin KaFai Lau prog->aux->id = id; 1657dc4bb0e2SMartin KaFai Lau spin_unlock_bh(&prog_idr_lock); 1658b76354cdSShaohua Li idr_preload_end(); 1659dc4bb0e2SMartin KaFai Lau 1660dc4bb0e2SMartin KaFai Lau /* id is in [1, INT_MAX) */ 1661dc4bb0e2SMartin KaFai Lau if (WARN_ON_ONCE(!id)) 1662dc4bb0e2SMartin KaFai Lau return -ENOSPC; 1663dc4bb0e2SMartin KaFai Lau 1664dc4bb0e2SMartin KaFai Lau return id > 0 ? 0 : id; 1665dc4bb0e2SMartin KaFai Lau } 1666dc4bb0e2SMartin KaFai Lau 1667ad8ad79fSJakub Kicinski void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock) 1668dc4bb0e2SMartin KaFai Lau { 1669ad8ad79fSJakub Kicinski /* cBPF to eBPF migrations are currently not in the idr store. 1670ad8ad79fSJakub Kicinski * Offloaded programs are removed from the store when their device 1671ad8ad79fSJakub Kicinski * disappears - even if someone grabs an fd to them they are unusable, 1672ad8ad79fSJakub Kicinski * simply waiting for refcnt to drop to be freed. 1673ad8ad79fSJakub Kicinski */ 1674dc4bb0e2SMartin KaFai Lau if (!prog->aux->id) 1675dc4bb0e2SMartin KaFai Lau return; 1676dc4bb0e2SMartin KaFai Lau 1677b16d9aa4SMartin KaFai Lau if (do_idr_lock) 1678dc4bb0e2SMartin KaFai Lau spin_lock_bh(&prog_idr_lock); 1679b16d9aa4SMartin KaFai Lau else 1680b16d9aa4SMartin KaFai Lau __acquire(&prog_idr_lock); 1681b16d9aa4SMartin KaFai Lau 1682dc4bb0e2SMartin KaFai Lau idr_remove(&prog_idr, prog->aux->id); 1683ad8ad79fSJakub Kicinski prog->aux->id = 0; 1684b16d9aa4SMartin KaFai Lau 1685b16d9aa4SMartin KaFai Lau if (do_idr_lock) 1686dc4bb0e2SMartin KaFai Lau spin_unlock_bh(&prog_idr_lock); 1687b16d9aa4SMartin KaFai Lau else 1688b16d9aa4SMartin KaFai Lau __release(&prog_idr_lock); 1689dc4bb0e2SMartin KaFai Lau } 1690dc4bb0e2SMartin KaFai Lau 16911aacde3dSDaniel Borkmann static void __bpf_prog_put_rcu(struct rcu_head *rcu) 1692abf2e7d6SAlexei Starovoitov { 1693abf2e7d6SAlexei Starovoitov struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu); 1694abf2e7d6SAlexei Starovoitov 16953b4d9eb2SDaniel Borkmann kvfree(aux->func_info); 16968c1b6e69SAlexei Starovoitov kfree(aux->func_info_aux); 1697aaac3ba9SAlexei Starovoitov bpf_prog_uncharge_memlock(aux->prog); 1698afdb09c7SChenbo Feng security_bpf_prog_free(aux); 1699abf2e7d6SAlexei Starovoitov bpf_prog_free(aux->prog); 1700abf2e7d6SAlexei Starovoitov } 1701abf2e7d6SAlexei Starovoitov 1702cd7455f1SDaniel Borkmann static void __bpf_prog_put_noref(struct bpf_prog *prog, bool deferred) 1703cd7455f1SDaniel Borkmann { 1704cd7455f1SDaniel Borkmann bpf_prog_kallsyms_del_all(prog); 1705cd7455f1SDaniel Borkmann btf_put(prog->aux->btf); 1706cd7455f1SDaniel Borkmann bpf_prog_free_linfo(prog); 1707cd7455f1SDaniel Borkmann 1708cd7455f1SDaniel Borkmann if (deferred) 1709cd7455f1SDaniel Borkmann call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu); 1710cd7455f1SDaniel Borkmann else 1711cd7455f1SDaniel Borkmann __bpf_prog_put_rcu(&prog->aux->rcu); 1712cd7455f1SDaniel Borkmann } 1713cd7455f1SDaniel Borkmann 1714b16d9aa4SMartin KaFai Lau static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock) 171509756af4SAlexei Starovoitov { 171685192dbfSAndrii Nakryiko if (atomic64_dec_and_test(&prog->aux->refcnt)) { 17176ee52e2aSSong Liu perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_UNLOAD, 0); 1718bae141f5SDaniel Borkmann bpf_audit_prog(prog, BPF_AUDIT_UNLOAD); 171934ad5580SMartin KaFai Lau /* bpf_prog_free_id() must be called first */ 1720b16d9aa4SMartin KaFai Lau bpf_prog_free_id(prog, do_idr_lock); 1721cd7455f1SDaniel Borkmann __bpf_prog_put_noref(prog, true); 172209756af4SAlexei Starovoitov } 1723a67edbf4SDaniel Borkmann } 1724b16d9aa4SMartin KaFai Lau 1725b16d9aa4SMartin KaFai Lau void bpf_prog_put(struct bpf_prog *prog) 1726b16d9aa4SMartin KaFai Lau { 1727b16d9aa4SMartin KaFai Lau __bpf_prog_put(prog, true); 1728b16d9aa4SMartin KaFai Lau } 1729e2e9b654SDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_put); 173009756af4SAlexei Starovoitov 173109756af4SAlexei Starovoitov static int bpf_prog_release(struct inode *inode, struct file *filp) 173209756af4SAlexei Starovoitov { 173309756af4SAlexei Starovoitov struct bpf_prog *prog = filp->private_data; 173409756af4SAlexei Starovoitov 17351aacde3dSDaniel Borkmann bpf_prog_put(prog); 173609756af4SAlexei Starovoitov return 0; 173709756af4SAlexei Starovoitov } 173809756af4SAlexei Starovoitov 1739492ecee8SAlexei Starovoitov static void bpf_prog_get_stats(const struct bpf_prog *prog, 1740492ecee8SAlexei Starovoitov struct bpf_prog_stats *stats) 1741492ecee8SAlexei Starovoitov { 1742492ecee8SAlexei Starovoitov u64 nsecs = 0, cnt = 0; 1743492ecee8SAlexei Starovoitov int cpu; 1744492ecee8SAlexei Starovoitov 1745492ecee8SAlexei Starovoitov for_each_possible_cpu(cpu) { 1746492ecee8SAlexei Starovoitov const struct bpf_prog_stats *st; 1747492ecee8SAlexei Starovoitov unsigned int start; 1748492ecee8SAlexei Starovoitov u64 tnsecs, tcnt; 1749492ecee8SAlexei Starovoitov 1750492ecee8SAlexei Starovoitov st = per_cpu_ptr(prog->aux->stats, cpu); 1751492ecee8SAlexei Starovoitov do { 1752492ecee8SAlexei Starovoitov start = u64_stats_fetch_begin_irq(&st->syncp); 1753492ecee8SAlexei Starovoitov tnsecs = st->nsecs; 1754492ecee8SAlexei Starovoitov tcnt = st->cnt; 1755492ecee8SAlexei Starovoitov } while (u64_stats_fetch_retry_irq(&st->syncp, start)); 1756492ecee8SAlexei Starovoitov nsecs += tnsecs; 1757492ecee8SAlexei Starovoitov cnt += tcnt; 1758492ecee8SAlexei Starovoitov } 1759492ecee8SAlexei Starovoitov stats->nsecs = nsecs; 1760492ecee8SAlexei Starovoitov stats->cnt = cnt; 1761492ecee8SAlexei Starovoitov } 1762492ecee8SAlexei Starovoitov 17637bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS 17647bd509e3SDaniel Borkmann static void bpf_prog_show_fdinfo(struct seq_file *m, struct file *filp) 17657bd509e3SDaniel Borkmann { 17667bd509e3SDaniel Borkmann const struct bpf_prog *prog = filp->private_data; 1767f1f7714eSDaniel Borkmann char prog_tag[sizeof(prog->tag) * 2 + 1] = { }; 1768492ecee8SAlexei Starovoitov struct bpf_prog_stats stats; 17697bd509e3SDaniel Borkmann 1770492ecee8SAlexei Starovoitov bpf_prog_get_stats(prog, &stats); 1771f1f7714eSDaniel Borkmann bin2hex(prog_tag, prog->tag, sizeof(prog->tag)); 17727bd509e3SDaniel Borkmann seq_printf(m, 17737bd509e3SDaniel Borkmann "prog_type:\t%u\n" 17747bd509e3SDaniel Borkmann "prog_jited:\t%u\n" 1775f1f7714eSDaniel Borkmann "prog_tag:\t%s\n" 17764316b409SDaniel Borkmann "memlock:\t%llu\n" 1777492ecee8SAlexei Starovoitov "prog_id:\t%u\n" 1778492ecee8SAlexei Starovoitov "run_time_ns:\t%llu\n" 1779492ecee8SAlexei Starovoitov "run_cnt:\t%llu\n", 17807bd509e3SDaniel Borkmann prog->type, 17817bd509e3SDaniel Borkmann prog->jited, 1782f1f7714eSDaniel Borkmann prog_tag, 17834316b409SDaniel Borkmann prog->pages * 1ULL << PAGE_SHIFT, 1784492ecee8SAlexei Starovoitov prog->aux->id, 1785492ecee8SAlexei Starovoitov stats.nsecs, 1786492ecee8SAlexei Starovoitov stats.cnt); 17877bd509e3SDaniel Borkmann } 17887bd509e3SDaniel Borkmann #endif 17897bd509e3SDaniel Borkmann 1790f66e448cSChenbo Feng const struct file_operations bpf_prog_fops = { 17917bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS 17927bd509e3SDaniel Borkmann .show_fdinfo = bpf_prog_show_fdinfo, 17937bd509e3SDaniel Borkmann #endif 179409756af4SAlexei Starovoitov .release = bpf_prog_release, 17956e71b04aSChenbo Feng .read = bpf_dummy_read, 17966e71b04aSChenbo Feng .write = bpf_dummy_write, 179709756af4SAlexei Starovoitov }; 179809756af4SAlexei Starovoitov 1799b2197755SDaniel Borkmann int bpf_prog_new_fd(struct bpf_prog *prog) 1800aa79781bSDaniel Borkmann { 1801afdb09c7SChenbo Feng int ret; 1802afdb09c7SChenbo Feng 1803afdb09c7SChenbo Feng ret = security_bpf_prog(prog); 1804afdb09c7SChenbo Feng if (ret < 0) 1805afdb09c7SChenbo Feng return ret; 1806afdb09c7SChenbo Feng 1807aa79781bSDaniel Borkmann return anon_inode_getfd("bpf-prog", &bpf_prog_fops, prog, 1808aa79781bSDaniel Borkmann O_RDWR | O_CLOEXEC); 1809aa79781bSDaniel Borkmann } 1810aa79781bSDaniel Borkmann 1811113214beSDaniel Borkmann static struct bpf_prog *____bpf_prog_get(struct fd f) 181209756af4SAlexei Starovoitov { 181309756af4SAlexei Starovoitov if (!f.file) 181409756af4SAlexei Starovoitov return ERR_PTR(-EBADF); 181509756af4SAlexei Starovoitov if (f.file->f_op != &bpf_prog_fops) { 181609756af4SAlexei Starovoitov fdput(f); 181709756af4SAlexei Starovoitov return ERR_PTR(-EINVAL); 181809756af4SAlexei Starovoitov } 181909756af4SAlexei Starovoitov 1820c2101297SDaniel Borkmann return f.file->private_data; 182109756af4SAlexei Starovoitov } 182209756af4SAlexei Starovoitov 182385192dbfSAndrii Nakryiko void bpf_prog_add(struct bpf_prog *prog, int i) 182492117d84SAlexei Starovoitov { 182585192dbfSAndrii Nakryiko atomic64_add(i, &prog->aux->refcnt); 182692117d84SAlexei Starovoitov } 182759d3656dSBrenden Blanco EXPORT_SYMBOL_GPL(bpf_prog_add); 182859d3656dSBrenden Blanco 1829c540594fSDaniel Borkmann void bpf_prog_sub(struct bpf_prog *prog, int i) 1830c540594fSDaniel Borkmann { 1831c540594fSDaniel Borkmann /* Only to be used for undoing previous bpf_prog_add() in some 1832c540594fSDaniel Borkmann * error path. We still know that another entity in our call 1833c540594fSDaniel Borkmann * path holds a reference to the program, thus atomic_sub() can 1834c540594fSDaniel Borkmann * be safely used in such cases! 1835c540594fSDaniel Borkmann */ 183685192dbfSAndrii Nakryiko WARN_ON(atomic64_sub_return(i, &prog->aux->refcnt) == 0); 1837c540594fSDaniel Borkmann } 1838c540594fSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_sub); 1839c540594fSDaniel Borkmann 184085192dbfSAndrii Nakryiko void bpf_prog_inc(struct bpf_prog *prog) 184159d3656dSBrenden Blanco { 184285192dbfSAndrii Nakryiko atomic64_inc(&prog->aux->refcnt); 184359d3656dSBrenden Blanco } 184497bc402dSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_inc); 184592117d84SAlexei Starovoitov 1846b16d9aa4SMartin KaFai Lau /* prog_idr_lock should have been held */ 1847a6f6df69SJohn Fastabend struct bpf_prog *bpf_prog_inc_not_zero(struct bpf_prog *prog) 1848b16d9aa4SMartin KaFai Lau { 1849b16d9aa4SMartin KaFai Lau int refold; 1850b16d9aa4SMartin KaFai Lau 185185192dbfSAndrii Nakryiko refold = atomic64_fetch_add_unless(&prog->aux->refcnt, 1, 0); 1852b16d9aa4SMartin KaFai Lau 1853b16d9aa4SMartin KaFai Lau if (!refold) 1854b16d9aa4SMartin KaFai Lau return ERR_PTR(-ENOENT); 1855b16d9aa4SMartin KaFai Lau 1856b16d9aa4SMartin KaFai Lau return prog; 1857b16d9aa4SMartin KaFai Lau } 1858a6f6df69SJohn Fastabend EXPORT_SYMBOL_GPL(bpf_prog_inc_not_zero); 1859b16d9aa4SMartin KaFai Lau 1860040ee692SAl Viro bool bpf_prog_get_ok(struct bpf_prog *prog, 1861288b3de5SJakub Kicinski enum bpf_prog_type *attach_type, bool attach_drv) 1862248f346fSJakub Kicinski { 1863288b3de5SJakub Kicinski /* not an attachment, just a refcount inc, always allow */ 1864288b3de5SJakub Kicinski if (!attach_type) 1865288b3de5SJakub Kicinski return true; 1866248f346fSJakub Kicinski 1867248f346fSJakub Kicinski if (prog->type != *attach_type) 1868248f346fSJakub Kicinski return false; 1869288b3de5SJakub Kicinski if (bpf_prog_is_dev_bound(prog->aux) && !attach_drv) 1870248f346fSJakub Kicinski return false; 1871248f346fSJakub Kicinski 1872248f346fSJakub Kicinski return true; 1873248f346fSJakub Kicinski } 1874248f346fSJakub Kicinski 1875248f346fSJakub Kicinski static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *attach_type, 1876288b3de5SJakub Kicinski bool attach_drv) 187709756af4SAlexei Starovoitov { 187809756af4SAlexei Starovoitov struct fd f = fdget(ufd); 187909756af4SAlexei Starovoitov struct bpf_prog *prog; 188009756af4SAlexei Starovoitov 1881113214beSDaniel Borkmann prog = ____bpf_prog_get(f); 188209756af4SAlexei Starovoitov if (IS_ERR(prog)) 188309756af4SAlexei Starovoitov return prog; 1884288b3de5SJakub Kicinski if (!bpf_prog_get_ok(prog, attach_type, attach_drv)) { 1885113214beSDaniel Borkmann prog = ERR_PTR(-EINVAL); 1886113214beSDaniel Borkmann goto out; 1887113214beSDaniel Borkmann } 188809756af4SAlexei Starovoitov 188985192dbfSAndrii Nakryiko bpf_prog_inc(prog); 1890113214beSDaniel Borkmann out: 189109756af4SAlexei Starovoitov fdput(f); 189209756af4SAlexei Starovoitov return prog; 189309756af4SAlexei Starovoitov } 1894113214beSDaniel Borkmann 1895113214beSDaniel Borkmann struct bpf_prog *bpf_prog_get(u32 ufd) 1896113214beSDaniel Borkmann { 1897288b3de5SJakub Kicinski return __bpf_prog_get(ufd, NULL, false); 1898113214beSDaniel Borkmann } 1899113214beSDaniel Borkmann 1900248f346fSJakub Kicinski struct bpf_prog *bpf_prog_get_type_dev(u32 ufd, enum bpf_prog_type type, 1901288b3de5SJakub Kicinski bool attach_drv) 1902248f346fSJakub Kicinski { 19034d220ed0SAlexei Starovoitov return __bpf_prog_get(ufd, &type, attach_drv); 1904248f346fSJakub Kicinski } 19056c8dfe21SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_prog_get_type_dev); 1906248f346fSJakub Kicinski 1907aac3fc32SAndrey Ignatov /* Initially all BPF programs could be loaded w/o specifying 1908aac3fc32SAndrey Ignatov * expected_attach_type. Later for some of them specifying expected_attach_type 1909aac3fc32SAndrey Ignatov * at load time became required so that program could be validated properly. 1910aac3fc32SAndrey Ignatov * Programs of types that are allowed to be loaded both w/ and w/o (for 1911aac3fc32SAndrey Ignatov * backward compatibility) expected_attach_type, should have the default attach 1912aac3fc32SAndrey Ignatov * type assigned to expected_attach_type for the latter case, so that it can be 1913aac3fc32SAndrey Ignatov * validated later at attach time. 1914aac3fc32SAndrey Ignatov * 1915aac3fc32SAndrey Ignatov * bpf_prog_load_fixup_attach_type() sets expected_attach_type in @attr if 1916aac3fc32SAndrey Ignatov * prog type requires it but has some attach types that have to be backward 1917aac3fc32SAndrey Ignatov * compatible. 1918aac3fc32SAndrey Ignatov */ 1919aac3fc32SAndrey Ignatov static void bpf_prog_load_fixup_attach_type(union bpf_attr *attr) 1920aac3fc32SAndrey Ignatov { 1921aac3fc32SAndrey Ignatov switch (attr->prog_type) { 1922aac3fc32SAndrey Ignatov case BPF_PROG_TYPE_CGROUP_SOCK: 1923aac3fc32SAndrey Ignatov /* Unfortunately BPF_ATTACH_TYPE_UNSPEC enumeration doesn't 1924aac3fc32SAndrey Ignatov * exist so checking for non-zero is the way to go here. 1925aac3fc32SAndrey Ignatov */ 1926aac3fc32SAndrey Ignatov if (!attr->expected_attach_type) 1927aac3fc32SAndrey Ignatov attr->expected_attach_type = 1928aac3fc32SAndrey Ignatov BPF_CGROUP_INET_SOCK_CREATE; 1929aac3fc32SAndrey Ignatov break; 1930aac3fc32SAndrey Ignatov } 1931aac3fc32SAndrey Ignatov } 1932aac3fc32SAndrey Ignatov 19335e43f899SAndrey Ignatov static int 1934ccfe29ebSAlexei Starovoitov bpf_prog_load_check_attach(enum bpf_prog_type prog_type, 1935ccfe29ebSAlexei Starovoitov enum bpf_attach_type expected_attach_type, 19365b92a28aSAlexei Starovoitov u32 btf_id, u32 prog_fd) 19375e43f899SAndrey Ignatov { 193827ae7997SMartin KaFai Lau if (btf_id) { 1939c108e3c1SAlexei Starovoitov if (btf_id > BTF_MAX_TYPE) 1940c108e3c1SAlexei Starovoitov return -EINVAL; 194127ae7997SMartin KaFai Lau 194227ae7997SMartin KaFai Lau switch (prog_type) { 194327ae7997SMartin KaFai Lau case BPF_PROG_TYPE_TRACING: 19449e4e01dfSKP Singh case BPF_PROG_TYPE_LSM: 194527ae7997SMartin KaFai Lau case BPF_PROG_TYPE_STRUCT_OPS: 1946be8704ffSAlexei Starovoitov case BPF_PROG_TYPE_EXT: 1947c108e3c1SAlexei Starovoitov break; 1948c108e3c1SAlexei Starovoitov default: 1949c108e3c1SAlexei Starovoitov return -EINVAL; 1950c108e3c1SAlexei Starovoitov } 195127ae7997SMartin KaFai Lau } 195227ae7997SMartin KaFai Lau 1953be8704ffSAlexei Starovoitov if (prog_fd && prog_type != BPF_PROG_TYPE_TRACING && 1954be8704ffSAlexei Starovoitov prog_type != BPF_PROG_TYPE_EXT) 195527ae7997SMartin KaFai Lau return -EINVAL; 1956c108e3c1SAlexei Starovoitov 1957c108e3c1SAlexei Starovoitov switch (prog_type) { 1958aac3fc32SAndrey Ignatov case BPF_PROG_TYPE_CGROUP_SOCK: 1959aac3fc32SAndrey Ignatov switch (expected_attach_type) { 1960aac3fc32SAndrey Ignatov case BPF_CGROUP_INET_SOCK_CREATE: 1961aac3fc32SAndrey Ignatov case BPF_CGROUP_INET4_POST_BIND: 1962aac3fc32SAndrey Ignatov case BPF_CGROUP_INET6_POST_BIND: 1963aac3fc32SAndrey Ignatov return 0; 1964aac3fc32SAndrey Ignatov default: 1965aac3fc32SAndrey Ignatov return -EINVAL; 1966aac3fc32SAndrey Ignatov } 19674fbac77dSAndrey Ignatov case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: 19684fbac77dSAndrey Ignatov switch (expected_attach_type) { 19694fbac77dSAndrey Ignatov case BPF_CGROUP_INET4_BIND: 19704fbac77dSAndrey Ignatov case BPF_CGROUP_INET6_BIND: 1971d74bad4eSAndrey Ignatov case BPF_CGROUP_INET4_CONNECT: 1972d74bad4eSAndrey Ignatov case BPF_CGROUP_INET6_CONNECT: 19731cedee13SAndrey Ignatov case BPF_CGROUP_UDP4_SENDMSG: 19741cedee13SAndrey Ignatov case BPF_CGROUP_UDP6_SENDMSG: 1975983695faSDaniel Borkmann case BPF_CGROUP_UDP4_RECVMSG: 1976983695faSDaniel Borkmann case BPF_CGROUP_UDP6_RECVMSG: 19775e43f899SAndrey Ignatov return 0; 19784fbac77dSAndrey Ignatov default: 19794fbac77dSAndrey Ignatov return -EINVAL; 19804fbac77dSAndrey Ignatov } 19815cf1e914Sbrakmo case BPF_PROG_TYPE_CGROUP_SKB: 19825cf1e914Sbrakmo switch (expected_attach_type) { 19835cf1e914Sbrakmo case BPF_CGROUP_INET_INGRESS: 19845cf1e914Sbrakmo case BPF_CGROUP_INET_EGRESS: 19855cf1e914Sbrakmo return 0; 19865cf1e914Sbrakmo default: 19875cf1e914Sbrakmo return -EINVAL; 19885cf1e914Sbrakmo } 19890d01da6aSStanislav Fomichev case BPF_PROG_TYPE_CGROUP_SOCKOPT: 19900d01da6aSStanislav Fomichev switch (expected_attach_type) { 19910d01da6aSStanislav Fomichev case BPF_CGROUP_SETSOCKOPT: 19920d01da6aSStanislav Fomichev case BPF_CGROUP_GETSOCKOPT: 19930d01da6aSStanislav Fomichev return 0; 19940d01da6aSStanislav Fomichev default: 19950d01da6aSStanislav Fomichev return -EINVAL; 19960d01da6aSStanislav Fomichev } 1997be8704ffSAlexei Starovoitov case BPF_PROG_TYPE_EXT: 1998be8704ffSAlexei Starovoitov if (expected_attach_type) 1999be8704ffSAlexei Starovoitov return -EINVAL; 2000be8704ffSAlexei Starovoitov /* fallthrough */ 20014fbac77dSAndrey Ignatov default: 20024fbac77dSAndrey Ignatov return 0; 20034fbac77dSAndrey Ignatov } 20045e43f899SAndrey Ignatov } 20055e43f899SAndrey Ignatov 200609756af4SAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */ 20075b92a28aSAlexei Starovoitov #define BPF_PROG_LOAD_LAST_FIELD attach_prog_fd 200809756af4SAlexei Starovoitov 2009838e9690SYonghong Song static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr) 201009756af4SAlexei Starovoitov { 201109756af4SAlexei Starovoitov enum bpf_prog_type type = attr->prog_type; 201209756af4SAlexei Starovoitov struct bpf_prog *prog; 201309756af4SAlexei Starovoitov int err; 201409756af4SAlexei Starovoitov char license[128]; 201509756af4SAlexei Starovoitov bool is_gpl; 201609756af4SAlexei Starovoitov 201709756af4SAlexei Starovoitov if (CHECK_ATTR(BPF_PROG_LOAD)) 201809756af4SAlexei Starovoitov return -EINVAL; 201909756af4SAlexei Starovoitov 2020c240eff6SJiong Wang if (attr->prog_flags & ~(BPF_F_STRICT_ALIGNMENT | 2021c240eff6SJiong Wang BPF_F_ANY_ALIGNMENT | 202210d274e8SAlexei Starovoitov BPF_F_TEST_STATE_FREQ | 2023c240eff6SJiong Wang BPF_F_TEST_RND_HI32)) 2024e07b98d9SDavid S. Miller return -EINVAL; 2025e07b98d9SDavid S. Miller 2026e9ee9efcSDavid Miller if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && 2027e9ee9efcSDavid Miller (attr->prog_flags & BPF_F_ANY_ALIGNMENT) && 2028e9ee9efcSDavid Miller !capable(CAP_SYS_ADMIN)) 2029e9ee9efcSDavid Miller return -EPERM; 2030e9ee9efcSDavid Miller 203109756af4SAlexei Starovoitov /* copy eBPF program license from user space */ 2032535e7b4bSMickaël Salaün if (strncpy_from_user(license, u64_to_user_ptr(attr->license), 203309756af4SAlexei Starovoitov sizeof(license) - 1) < 0) 203409756af4SAlexei Starovoitov return -EFAULT; 203509756af4SAlexei Starovoitov license[sizeof(license) - 1] = 0; 203609756af4SAlexei Starovoitov 203709756af4SAlexei Starovoitov /* eBPF programs must be GPL compatible to use GPL-ed functions */ 203809756af4SAlexei Starovoitov is_gpl = license_is_gpl_compatible(license); 203909756af4SAlexei Starovoitov 2040c04c0d2bSAlexei Starovoitov if (attr->insn_cnt == 0 || 2041c04c0d2bSAlexei Starovoitov attr->insn_cnt > (capable(CAP_SYS_ADMIN) ? BPF_COMPLEXITY_LIMIT_INSNS : BPF_MAXINSNS)) 2042ef0915caSDaniel Borkmann return -E2BIG; 204380b7d819SChenbo Feng if (type != BPF_PROG_TYPE_SOCKET_FILTER && 204480b7d819SChenbo Feng type != BPF_PROG_TYPE_CGROUP_SKB && 204580b7d819SChenbo Feng !capable(CAP_SYS_ADMIN)) 20461be7f75dSAlexei Starovoitov return -EPERM; 20471be7f75dSAlexei Starovoitov 2048aac3fc32SAndrey Ignatov bpf_prog_load_fixup_attach_type(attr); 2049ccfe29ebSAlexei Starovoitov if (bpf_prog_load_check_attach(type, attr->expected_attach_type, 20505b92a28aSAlexei Starovoitov attr->attach_btf_id, 20515b92a28aSAlexei Starovoitov attr->attach_prog_fd)) 20525e43f899SAndrey Ignatov return -EINVAL; 20535e43f899SAndrey Ignatov 205409756af4SAlexei Starovoitov /* plain bpf_prog allocation */ 205509756af4SAlexei Starovoitov prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER); 205609756af4SAlexei Starovoitov if (!prog) 205709756af4SAlexei Starovoitov return -ENOMEM; 205809756af4SAlexei Starovoitov 20595e43f899SAndrey Ignatov prog->expected_attach_type = attr->expected_attach_type; 2060ccfe29ebSAlexei Starovoitov prog->aux->attach_btf_id = attr->attach_btf_id; 20615b92a28aSAlexei Starovoitov if (attr->attach_prog_fd) { 20625b92a28aSAlexei Starovoitov struct bpf_prog *tgt_prog; 20635b92a28aSAlexei Starovoitov 20645b92a28aSAlexei Starovoitov tgt_prog = bpf_prog_get(attr->attach_prog_fd); 20655b92a28aSAlexei Starovoitov if (IS_ERR(tgt_prog)) { 20665b92a28aSAlexei Starovoitov err = PTR_ERR(tgt_prog); 20675b92a28aSAlexei Starovoitov goto free_prog_nouncharge; 20685b92a28aSAlexei Starovoitov } 20695b92a28aSAlexei Starovoitov prog->aux->linked_prog = tgt_prog; 20705b92a28aSAlexei Starovoitov } 20715e43f899SAndrey Ignatov 20729a18eedbSJakub Kicinski prog->aux->offload_requested = !!attr->prog_ifindex; 20739a18eedbSJakub Kicinski 2074afdb09c7SChenbo Feng err = security_bpf_prog_alloc(prog->aux); 2075aaac3ba9SAlexei Starovoitov if (err) 2076aaac3ba9SAlexei Starovoitov goto free_prog_nouncharge; 2077aaac3ba9SAlexei Starovoitov 2078afdb09c7SChenbo Feng err = bpf_prog_charge_memlock(prog); 2079afdb09c7SChenbo Feng if (err) 2080afdb09c7SChenbo Feng goto free_prog_sec; 2081afdb09c7SChenbo Feng 208209756af4SAlexei Starovoitov prog->len = attr->insn_cnt; 208309756af4SAlexei Starovoitov 208409756af4SAlexei Starovoitov err = -EFAULT; 2085535e7b4bSMickaël Salaün if (copy_from_user(prog->insns, u64_to_user_ptr(attr->insns), 2086aafe6ae9SDaniel Borkmann bpf_prog_insn_size(prog)) != 0) 208709756af4SAlexei Starovoitov goto free_prog; 208809756af4SAlexei Starovoitov 208909756af4SAlexei Starovoitov prog->orig_prog = NULL; 2090a91263d5SDaniel Borkmann prog->jited = 0; 209109756af4SAlexei Starovoitov 209285192dbfSAndrii Nakryiko atomic64_set(&prog->aux->refcnt, 1); 2093a91263d5SDaniel Borkmann prog->gpl_compatible = is_gpl ? 1 : 0; 209409756af4SAlexei Starovoitov 20959a18eedbSJakub Kicinski if (bpf_prog_is_dev_bound(prog->aux)) { 2096ab3f0063SJakub Kicinski err = bpf_prog_offload_init(prog, attr); 2097ab3f0063SJakub Kicinski if (err) 2098ab3f0063SJakub Kicinski goto free_prog; 2099ab3f0063SJakub Kicinski } 2100ab3f0063SJakub Kicinski 210109756af4SAlexei Starovoitov /* find program type: socket_filter vs tracing_filter */ 210209756af4SAlexei Starovoitov err = find_prog_type(type, prog); 210309756af4SAlexei Starovoitov if (err < 0) 210409756af4SAlexei Starovoitov goto free_prog; 210509756af4SAlexei Starovoitov 21069285ec4cSJason A. Donenfeld prog->aux->load_time = ktime_get_boottime_ns(); 21078e7ae251SMartin KaFai Lau err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name, 21088e7ae251SMartin KaFai Lau sizeof(attr->prog_name)); 21098e7ae251SMartin KaFai Lau if (err < 0) 2110cb4d2b3fSMartin KaFai Lau goto free_prog; 2111cb4d2b3fSMartin KaFai Lau 211209756af4SAlexei Starovoitov /* run eBPF verifier */ 2113838e9690SYonghong Song err = bpf_check(&prog, attr, uattr); 211409756af4SAlexei Starovoitov if (err < 0) 211509756af4SAlexei Starovoitov goto free_used_maps; 211609756af4SAlexei Starovoitov 2117d1c55ab5SDaniel Borkmann prog = bpf_prog_select_runtime(prog, &err); 211804fd61abSAlexei Starovoitov if (err < 0) 211904fd61abSAlexei Starovoitov goto free_used_maps; 212009756af4SAlexei Starovoitov 2121dc4bb0e2SMartin KaFai Lau err = bpf_prog_alloc_id(prog); 2122dc4bb0e2SMartin KaFai Lau if (err) 2123dc4bb0e2SMartin KaFai Lau goto free_used_maps; 2124dc4bb0e2SMartin KaFai Lau 2125c751798aSDaniel Borkmann /* Upon success of bpf_prog_alloc_id(), the BPF prog is 2126c751798aSDaniel Borkmann * effectively publicly exposed. However, retrieving via 2127c751798aSDaniel Borkmann * bpf_prog_get_fd_by_id() will take another reference, 2128c751798aSDaniel Borkmann * therefore it cannot be gone underneath us. 2129c751798aSDaniel Borkmann * 2130c751798aSDaniel Borkmann * Only for the time /after/ successful bpf_prog_new_fd() 2131c751798aSDaniel Borkmann * and before returning to userspace, we might just hold 2132c751798aSDaniel Borkmann * one reference and any parallel close on that fd could 2133c751798aSDaniel Borkmann * rip everything out. Hence, below notifications must 2134c751798aSDaniel Borkmann * happen before bpf_prog_new_fd(). 2135c751798aSDaniel Borkmann * 2136c751798aSDaniel Borkmann * Also, any failure handling from this point onwards must 2137c751798aSDaniel Borkmann * be using bpf_prog_put() given the program is exposed. 2138b16d9aa4SMartin KaFai Lau */ 213974451e66SDaniel Borkmann bpf_prog_kallsyms_add(prog); 21406ee52e2aSSong Liu perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_LOAD, 0); 2141bae141f5SDaniel Borkmann bpf_audit_prog(prog, BPF_AUDIT_LOAD); 2142c751798aSDaniel Borkmann 2143c751798aSDaniel Borkmann err = bpf_prog_new_fd(prog); 2144c751798aSDaniel Borkmann if (err < 0) 2145c751798aSDaniel Borkmann bpf_prog_put(prog); 214609756af4SAlexei Starovoitov return err; 214709756af4SAlexei Starovoitov 214809756af4SAlexei Starovoitov free_used_maps: 2149cd7455f1SDaniel Borkmann /* In case we have subprogs, we need to wait for a grace 2150cd7455f1SDaniel Borkmann * period before we can tear down JIT memory since symbols 2151cd7455f1SDaniel Borkmann * are already exposed under kallsyms. 2152cd7455f1SDaniel Borkmann */ 2153cd7455f1SDaniel Borkmann __bpf_prog_put_noref(prog, prog->aux->func_cnt); 2154cd7455f1SDaniel Borkmann return err; 215509756af4SAlexei Starovoitov free_prog: 2156aaac3ba9SAlexei Starovoitov bpf_prog_uncharge_memlock(prog); 2157afdb09c7SChenbo Feng free_prog_sec: 2158afdb09c7SChenbo Feng security_bpf_prog_free(prog->aux); 2159aaac3ba9SAlexei Starovoitov free_prog_nouncharge: 216009756af4SAlexei Starovoitov bpf_prog_free(prog); 216109756af4SAlexei Starovoitov return err; 216209756af4SAlexei Starovoitov } 216309756af4SAlexei Starovoitov 21646e71b04aSChenbo Feng #define BPF_OBJ_LAST_FIELD file_flags 2165b2197755SDaniel Borkmann 2166b2197755SDaniel Borkmann static int bpf_obj_pin(const union bpf_attr *attr) 2167b2197755SDaniel Borkmann { 21686e71b04aSChenbo Feng if (CHECK_ATTR(BPF_OBJ) || attr->file_flags != 0) 2169b2197755SDaniel Borkmann return -EINVAL; 2170b2197755SDaniel Borkmann 2171535e7b4bSMickaël Salaün return bpf_obj_pin_user(attr->bpf_fd, u64_to_user_ptr(attr->pathname)); 2172b2197755SDaniel Borkmann } 2173b2197755SDaniel Borkmann 2174b2197755SDaniel Borkmann static int bpf_obj_get(const union bpf_attr *attr) 2175b2197755SDaniel Borkmann { 21766e71b04aSChenbo Feng if (CHECK_ATTR(BPF_OBJ) || attr->bpf_fd != 0 || 21776e71b04aSChenbo Feng attr->file_flags & ~BPF_OBJ_FLAG_MASK) 2178b2197755SDaniel Borkmann return -EINVAL; 2179b2197755SDaniel Borkmann 21806e71b04aSChenbo Feng return bpf_obj_get_user(u64_to_user_ptr(attr->pathname), 21816e71b04aSChenbo Feng attr->file_flags); 2182b2197755SDaniel Borkmann } 2183b2197755SDaniel Borkmann 218470ed506cSAndrii Nakryiko void bpf_link_init(struct bpf_link *link, const struct bpf_link_ops *ops, 218570ed506cSAndrii Nakryiko struct bpf_prog *prog) 218670ed506cSAndrii Nakryiko { 218770ed506cSAndrii Nakryiko atomic64_set(&link->refcnt, 1); 218870ed506cSAndrii Nakryiko link->ops = ops; 218970ed506cSAndrii Nakryiko link->prog = prog; 219070ed506cSAndrii Nakryiko } 219170ed506cSAndrii Nakryiko 219298868668SAndrii Nakryiko /* Clean up bpf_link and corresponding anon_inode file and FD. After 219398868668SAndrii Nakryiko * anon_inode is created, bpf_link can't be just kfree()'d due to deferred 219498868668SAndrii Nakryiko * anon_inode's release() call. This helper manages marking bpf_link as 219598868668SAndrii Nakryiko * defunct, releases anon_inode file and puts reserved FD. 219698868668SAndrii Nakryiko */ 2197af6eea57SAndrii Nakryiko void bpf_link_cleanup(struct bpf_link *link, struct file *link_file, 219898868668SAndrii Nakryiko int link_fd) 2199babf3164SAndrii Nakryiko { 2200babf3164SAndrii Nakryiko link->prog = NULL; 220198868668SAndrii Nakryiko fput(link_file); 220298868668SAndrii Nakryiko put_unused_fd(link_fd); 2203babf3164SAndrii Nakryiko } 2204babf3164SAndrii Nakryiko 220570ed506cSAndrii Nakryiko void bpf_link_inc(struct bpf_link *link) 220670ed506cSAndrii Nakryiko { 220770ed506cSAndrii Nakryiko atomic64_inc(&link->refcnt); 220870ed506cSAndrii Nakryiko } 220970ed506cSAndrii Nakryiko 221070ed506cSAndrii Nakryiko /* bpf_link_free is guaranteed to be called from process context */ 221170ed506cSAndrii Nakryiko static void bpf_link_free(struct bpf_link *link) 221270ed506cSAndrii Nakryiko { 2213babf3164SAndrii Nakryiko if (link->prog) { 2214babf3164SAndrii Nakryiko /* detach BPF program, clean up used resources */ 221570ed506cSAndrii Nakryiko link->ops->release(link); 2216babf3164SAndrii Nakryiko bpf_prog_put(link->prog); 2217babf3164SAndrii Nakryiko } 2218babf3164SAndrii Nakryiko /* free bpf_link and its containing memory */ 2219babf3164SAndrii Nakryiko link->ops->dealloc(link); 222070ed506cSAndrii Nakryiko } 222170ed506cSAndrii Nakryiko 222270ed506cSAndrii Nakryiko static void bpf_link_put_deferred(struct work_struct *work) 222370ed506cSAndrii Nakryiko { 222470ed506cSAndrii Nakryiko struct bpf_link *link = container_of(work, struct bpf_link, work); 222570ed506cSAndrii Nakryiko 222670ed506cSAndrii Nakryiko bpf_link_free(link); 222770ed506cSAndrii Nakryiko } 222870ed506cSAndrii Nakryiko 222970ed506cSAndrii Nakryiko /* bpf_link_put can be called from atomic context, but ensures that resources 223070ed506cSAndrii Nakryiko * are freed from process context 223170ed506cSAndrii Nakryiko */ 223270ed506cSAndrii Nakryiko void bpf_link_put(struct bpf_link *link) 223370ed506cSAndrii Nakryiko { 223470ed506cSAndrii Nakryiko if (!atomic64_dec_and_test(&link->refcnt)) 223570ed506cSAndrii Nakryiko return; 223670ed506cSAndrii Nakryiko 223770ed506cSAndrii Nakryiko if (in_atomic()) { 223870ed506cSAndrii Nakryiko INIT_WORK(&link->work, bpf_link_put_deferred); 223970ed506cSAndrii Nakryiko schedule_work(&link->work); 224070ed506cSAndrii Nakryiko } else { 224170ed506cSAndrii Nakryiko bpf_link_free(link); 224270ed506cSAndrii Nakryiko } 224370ed506cSAndrii Nakryiko } 224470ed506cSAndrii Nakryiko 224570ed506cSAndrii Nakryiko static int bpf_link_release(struct inode *inode, struct file *filp) 224670ed506cSAndrii Nakryiko { 224770ed506cSAndrii Nakryiko struct bpf_link *link = filp->private_data; 224870ed506cSAndrii Nakryiko 224970ed506cSAndrii Nakryiko bpf_link_put(link); 2250fec56f58SAlexei Starovoitov return 0; 2251fec56f58SAlexei Starovoitov } 2252fec56f58SAlexei Starovoitov 225370ed506cSAndrii Nakryiko #ifdef CONFIG_PROC_FS 225470ed506cSAndrii Nakryiko static const struct bpf_link_ops bpf_raw_tp_lops; 225570ed506cSAndrii Nakryiko static const struct bpf_link_ops bpf_tracing_link_lops; 225670ed506cSAndrii Nakryiko 225770ed506cSAndrii Nakryiko static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp) 225870ed506cSAndrii Nakryiko { 225970ed506cSAndrii Nakryiko const struct bpf_link *link = filp->private_data; 226070ed506cSAndrii Nakryiko const struct bpf_prog *prog = link->prog; 226170ed506cSAndrii Nakryiko char prog_tag[sizeof(prog->tag) * 2 + 1] = { }; 226270ed506cSAndrii Nakryiko const char *link_type; 226370ed506cSAndrii Nakryiko 226470ed506cSAndrii Nakryiko if (link->ops == &bpf_raw_tp_lops) 226570ed506cSAndrii Nakryiko link_type = "raw_tracepoint"; 226670ed506cSAndrii Nakryiko else if (link->ops == &bpf_tracing_link_lops) 226770ed506cSAndrii Nakryiko link_type = "tracing"; 2268af6eea57SAndrii Nakryiko #ifdef CONFIG_CGROUP_BPF 2269af6eea57SAndrii Nakryiko else if (link->ops == &bpf_cgroup_link_lops) 2270af6eea57SAndrii Nakryiko link_type = "cgroup"; 2271af6eea57SAndrii Nakryiko #endif 227270ed506cSAndrii Nakryiko else 227370ed506cSAndrii Nakryiko link_type = "unknown"; 227470ed506cSAndrii Nakryiko 227570ed506cSAndrii Nakryiko bin2hex(prog_tag, prog->tag, sizeof(prog->tag)); 227670ed506cSAndrii Nakryiko seq_printf(m, 227770ed506cSAndrii Nakryiko "link_type:\t%s\n" 227870ed506cSAndrii Nakryiko "prog_tag:\t%s\n" 227970ed506cSAndrii Nakryiko "prog_id:\t%u\n", 228070ed506cSAndrii Nakryiko link_type, 228170ed506cSAndrii Nakryiko prog_tag, 228270ed506cSAndrii Nakryiko prog->aux->id); 228370ed506cSAndrii Nakryiko } 228470ed506cSAndrii Nakryiko #endif 228570ed506cSAndrii Nakryiko 2286*6f302bfbSZou Wei static const struct file_operations bpf_link_fops = { 228770ed506cSAndrii Nakryiko #ifdef CONFIG_PROC_FS 228870ed506cSAndrii Nakryiko .show_fdinfo = bpf_link_show_fdinfo, 228970ed506cSAndrii Nakryiko #endif 229070ed506cSAndrii Nakryiko .release = bpf_link_release, 2291fec56f58SAlexei Starovoitov .read = bpf_dummy_read, 2292fec56f58SAlexei Starovoitov .write = bpf_dummy_write, 2293fec56f58SAlexei Starovoitov }; 2294fec56f58SAlexei Starovoitov 229570ed506cSAndrii Nakryiko int bpf_link_new_fd(struct bpf_link *link) 229670ed506cSAndrii Nakryiko { 229770ed506cSAndrii Nakryiko return anon_inode_getfd("bpf-link", &bpf_link_fops, link, O_CLOEXEC); 229870ed506cSAndrii Nakryiko } 229970ed506cSAndrii Nakryiko 2300babf3164SAndrii Nakryiko /* Similar to bpf_link_new_fd, create anon_inode for given bpf_link, but 2301babf3164SAndrii Nakryiko * instead of immediately installing fd in fdtable, just reserve it and 2302babf3164SAndrii Nakryiko * return. Caller then need to either install it with fd_install(fd, file) or 2303babf3164SAndrii Nakryiko * release with put_unused_fd(fd). 2304babf3164SAndrii Nakryiko * This is useful for cases when bpf_link attachment/detachment are 2305babf3164SAndrii Nakryiko * complicated and expensive operations and should be delayed until all the fd 2306babf3164SAndrii Nakryiko * reservation and anon_inode creation succeeds. 2307babf3164SAndrii Nakryiko */ 2308babf3164SAndrii Nakryiko struct file *bpf_link_new_file(struct bpf_link *link, int *reserved_fd) 2309babf3164SAndrii Nakryiko { 2310babf3164SAndrii Nakryiko struct file *file; 2311babf3164SAndrii Nakryiko int fd; 2312babf3164SAndrii Nakryiko 2313babf3164SAndrii Nakryiko fd = get_unused_fd_flags(O_CLOEXEC); 2314babf3164SAndrii Nakryiko if (fd < 0) 2315babf3164SAndrii Nakryiko return ERR_PTR(fd); 2316babf3164SAndrii Nakryiko 2317babf3164SAndrii Nakryiko file = anon_inode_getfile("bpf_link", &bpf_link_fops, link, O_CLOEXEC); 2318babf3164SAndrii Nakryiko if (IS_ERR(file)) { 2319babf3164SAndrii Nakryiko put_unused_fd(fd); 2320babf3164SAndrii Nakryiko return file; 2321babf3164SAndrii Nakryiko } 2322babf3164SAndrii Nakryiko 2323babf3164SAndrii Nakryiko *reserved_fd = fd; 2324babf3164SAndrii Nakryiko return file; 2325babf3164SAndrii Nakryiko } 2326babf3164SAndrii Nakryiko 232770ed506cSAndrii Nakryiko struct bpf_link *bpf_link_get_from_fd(u32 ufd) 232870ed506cSAndrii Nakryiko { 232970ed506cSAndrii Nakryiko struct fd f = fdget(ufd); 233070ed506cSAndrii Nakryiko struct bpf_link *link; 233170ed506cSAndrii Nakryiko 233270ed506cSAndrii Nakryiko if (!f.file) 233370ed506cSAndrii Nakryiko return ERR_PTR(-EBADF); 233470ed506cSAndrii Nakryiko if (f.file->f_op != &bpf_link_fops) { 233570ed506cSAndrii Nakryiko fdput(f); 233670ed506cSAndrii Nakryiko return ERR_PTR(-EINVAL); 233770ed506cSAndrii Nakryiko } 233870ed506cSAndrii Nakryiko 233970ed506cSAndrii Nakryiko link = f.file->private_data; 234070ed506cSAndrii Nakryiko bpf_link_inc(link); 234170ed506cSAndrii Nakryiko fdput(f); 234270ed506cSAndrii Nakryiko 234370ed506cSAndrii Nakryiko return link; 234470ed506cSAndrii Nakryiko } 234570ed506cSAndrii Nakryiko 234670ed506cSAndrii Nakryiko struct bpf_tracing_link { 234770ed506cSAndrii Nakryiko struct bpf_link link; 234870ed506cSAndrii Nakryiko }; 234970ed506cSAndrii Nakryiko 235070ed506cSAndrii Nakryiko static void bpf_tracing_link_release(struct bpf_link *link) 235170ed506cSAndrii Nakryiko { 2352babf3164SAndrii Nakryiko WARN_ON_ONCE(bpf_trampoline_unlink_prog(link->prog)); 2353babf3164SAndrii Nakryiko } 2354babf3164SAndrii Nakryiko 2355babf3164SAndrii Nakryiko static void bpf_tracing_link_dealloc(struct bpf_link *link) 2356babf3164SAndrii Nakryiko { 235770ed506cSAndrii Nakryiko struct bpf_tracing_link *tr_link = 235870ed506cSAndrii Nakryiko container_of(link, struct bpf_tracing_link, link); 235970ed506cSAndrii Nakryiko 236070ed506cSAndrii Nakryiko kfree(tr_link); 236170ed506cSAndrii Nakryiko } 236270ed506cSAndrii Nakryiko 236370ed506cSAndrii Nakryiko static const struct bpf_link_ops bpf_tracing_link_lops = { 236470ed506cSAndrii Nakryiko .release = bpf_tracing_link_release, 2365babf3164SAndrii Nakryiko .dealloc = bpf_tracing_link_dealloc, 236670ed506cSAndrii Nakryiko }; 236770ed506cSAndrii Nakryiko 2368fec56f58SAlexei Starovoitov static int bpf_tracing_prog_attach(struct bpf_prog *prog) 2369fec56f58SAlexei Starovoitov { 237070ed506cSAndrii Nakryiko struct bpf_tracing_link *link; 2371babf3164SAndrii Nakryiko struct file *link_file; 237270ed506cSAndrii Nakryiko int link_fd, err; 2373fec56f58SAlexei Starovoitov 23749e4e01dfSKP Singh switch (prog->type) { 23759e4e01dfSKP Singh case BPF_PROG_TYPE_TRACING: 2376fec56f58SAlexei Starovoitov if (prog->expected_attach_type != BPF_TRACE_FENTRY && 2377be8704ffSAlexei Starovoitov prog->expected_attach_type != BPF_TRACE_FEXIT && 23789e4e01dfSKP Singh prog->expected_attach_type != BPF_MODIFY_RETURN) { 23799e4e01dfSKP Singh err = -EINVAL; 23809e4e01dfSKP Singh goto out_put_prog; 23819e4e01dfSKP Singh } 23829e4e01dfSKP Singh break; 23839e4e01dfSKP Singh case BPF_PROG_TYPE_EXT: 23849e4e01dfSKP Singh if (prog->expected_attach_type != 0) { 23859e4e01dfSKP Singh err = -EINVAL; 23869e4e01dfSKP Singh goto out_put_prog; 23879e4e01dfSKP Singh } 23889e4e01dfSKP Singh break; 23899e4e01dfSKP Singh case BPF_PROG_TYPE_LSM: 23909e4e01dfSKP Singh if (prog->expected_attach_type != BPF_LSM_MAC) { 23919e4e01dfSKP Singh err = -EINVAL; 23929e4e01dfSKP Singh goto out_put_prog; 23939e4e01dfSKP Singh } 23949e4e01dfSKP Singh break; 23959e4e01dfSKP Singh default: 2396fec56f58SAlexei Starovoitov err = -EINVAL; 2397fec56f58SAlexei Starovoitov goto out_put_prog; 2398fec56f58SAlexei Starovoitov } 2399fec56f58SAlexei Starovoitov 240070ed506cSAndrii Nakryiko link = kzalloc(sizeof(*link), GFP_USER); 240170ed506cSAndrii Nakryiko if (!link) { 240270ed506cSAndrii Nakryiko err = -ENOMEM; 2403fec56f58SAlexei Starovoitov goto out_put_prog; 2404fec56f58SAlexei Starovoitov } 240570ed506cSAndrii Nakryiko bpf_link_init(&link->link, &bpf_tracing_link_lops, prog); 2406fec56f58SAlexei Starovoitov 2407babf3164SAndrii Nakryiko link_file = bpf_link_new_file(&link->link, &link_fd); 2408babf3164SAndrii Nakryiko if (IS_ERR(link_file)) { 2409babf3164SAndrii Nakryiko kfree(link); 2410babf3164SAndrii Nakryiko err = PTR_ERR(link_file); 2411babf3164SAndrii Nakryiko goto out_put_prog; 241270ed506cSAndrii Nakryiko } 2413babf3164SAndrii Nakryiko 2414babf3164SAndrii Nakryiko err = bpf_trampoline_link_prog(prog); 2415babf3164SAndrii Nakryiko if (err) { 241698868668SAndrii Nakryiko bpf_link_cleanup(&link->link, link_file, link_fd); 2417babf3164SAndrii Nakryiko goto out_put_prog; 2418babf3164SAndrii Nakryiko } 2419babf3164SAndrii Nakryiko 2420babf3164SAndrii Nakryiko fd_install(link_fd, link_file); 242170ed506cSAndrii Nakryiko return link_fd; 242270ed506cSAndrii Nakryiko 2423fec56f58SAlexei Starovoitov out_put_prog: 2424fec56f58SAlexei Starovoitov bpf_prog_put(prog); 2425fec56f58SAlexei Starovoitov return err; 2426fec56f58SAlexei Starovoitov } 2427fec56f58SAlexei Starovoitov 242870ed506cSAndrii Nakryiko struct bpf_raw_tp_link { 242970ed506cSAndrii Nakryiko struct bpf_link link; 2430c4f6699dSAlexei Starovoitov struct bpf_raw_event_map *btp; 2431c4f6699dSAlexei Starovoitov }; 2432c4f6699dSAlexei Starovoitov 243370ed506cSAndrii Nakryiko static void bpf_raw_tp_link_release(struct bpf_link *link) 2434c4f6699dSAlexei Starovoitov { 243570ed506cSAndrii Nakryiko struct bpf_raw_tp_link *raw_tp = 243670ed506cSAndrii Nakryiko container_of(link, struct bpf_raw_tp_link, link); 2437c4f6699dSAlexei Starovoitov 243870ed506cSAndrii Nakryiko bpf_probe_unregister(raw_tp->btp, raw_tp->link.prog); 2439a38d1107SMatt Mullins bpf_put_raw_tracepoint(raw_tp->btp); 2440babf3164SAndrii Nakryiko } 2441babf3164SAndrii Nakryiko 2442babf3164SAndrii Nakryiko static void bpf_raw_tp_link_dealloc(struct bpf_link *link) 2443babf3164SAndrii Nakryiko { 2444babf3164SAndrii Nakryiko struct bpf_raw_tp_link *raw_tp = 2445babf3164SAndrii Nakryiko container_of(link, struct bpf_raw_tp_link, link); 2446babf3164SAndrii Nakryiko 2447c4f6699dSAlexei Starovoitov kfree(raw_tp); 2448c4f6699dSAlexei Starovoitov } 2449c4f6699dSAlexei Starovoitov 245070ed506cSAndrii Nakryiko static const struct bpf_link_ops bpf_raw_tp_lops = { 245170ed506cSAndrii Nakryiko .release = bpf_raw_tp_link_release, 2452babf3164SAndrii Nakryiko .dealloc = bpf_raw_tp_link_dealloc, 2453c4f6699dSAlexei Starovoitov }; 2454c4f6699dSAlexei Starovoitov 2455c4f6699dSAlexei Starovoitov #define BPF_RAW_TRACEPOINT_OPEN_LAST_FIELD raw_tracepoint.prog_fd 2456c4f6699dSAlexei Starovoitov 2457c4f6699dSAlexei Starovoitov static int bpf_raw_tracepoint_open(const union bpf_attr *attr) 2458c4f6699dSAlexei Starovoitov { 2459babf3164SAndrii Nakryiko struct bpf_raw_tp_link *link; 2460c4f6699dSAlexei Starovoitov struct bpf_raw_event_map *btp; 2461babf3164SAndrii Nakryiko struct file *link_file; 2462c4f6699dSAlexei Starovoitov struct bpf_prog *prog; 2463ac4414b5SAlexei Starovoitov const char *tp_name; 2464ac4414b5SAlexei Starovoitov char buf[128]; 246570ed506cSAndrii Nakryiko int link_fd, err; 2466c4f6699dSAlexei Starovoitov 2467ac4414b5SAlexei Starovoitov if (CHECK_ATTR(BPF_RAW_TRACEPOINT_OPEN)) 2468ac4414b5SAlexei Starovoitov return -EINVAL; 2469ac4414b5SAlexei Starovoitov 2470ac4414b5SAlexei Starovoitov prog = bpf_prog_get(attr->raw_tracepoint.prog_fd); 2471ac4414b5SAlexei Starovoitov if (IS_ERR(prog)) 2472ac4414b5SAlexei Starovoitov return PTR_ERR(prog); 2473ac4414b5SAlexei Starovoitov 24749e4e01dfSKP Singh switch (prog->type) { 24759e4e01dfSKP Singh case BPF_PROG_TYPE_TRACING: 24769e4e01dfSKP Singh case BPF_PROG_TYPE_EXT: 24779e4e01dfSKP Singh case BPF_PROG_TYPE_LSM: 2478ac4414b5SAlexei Starovoitov if (attr->raw_tracepoint.name) { 2479fec56f58SAlexei Starovoitov /* The attach point for this category of programs 2480fec56f58SAlexei Starovoitov * should be specified via btf_id during program load. 2481ac4414b5SAlexei Starovoitov */ 2482ac4414b5SAlexei Starovoitov err = -EINVAL; 2483ac4414b5SAlexei Starovoitov goto out_put_prog; 2484ac4414b5SAlexei Starovoitov } 24859e4e01dfSKP Singh if (prog->type == BPF_PROG_TYPE_TRACING && 24869e4e01dfSKP Singh prog->expected_attach_type == BPF_TRACE_RAW_TP) { 248738207291SMartin KaFai Lau tp_name = prog->aux->attach_func_name; 24889e4e01dfSKP Singh break; 24899e4e01dfSKP Singh } 2490fec56f58SAlexei Starovoitov return bpf_tracing_prog_attach(prog); 24919e4e01dfSKP Singh case BPF_PROG_TYPE_RAW_TRACEPOINT: 24929e4e01dfSKP Singh case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE: 2493ac4414b5SAlexei Starovoitov if (strncpy_from_user(buf, 2494ac4414b5SAlexei Starovoitov u64_to_user_ptr(attr->raw_tracepoint.name), 2495ac4414b5SAlexei Starovoitov sizeof(buf) - 1) < 0) { 2496ac4414b5SAlexei Starovoitov err = -EFAULT; 2497ac4414b5SAlexei Starovoitov goto out_put_prog; 2498ac4414b5SAlexei Starovoitov } 2499ac4414b5SAlexei Starovoitov buf[sizeof(buf) - 1] = 0; 2500ac4414b5SAlexei Starovoitov tp_name = buf; 25019e4e01dfSKP Singh break; 25029e4e01dfSKP Singh default: 25039e4e01dfSKP Singh err = -EINVAL; 25049e4e01dfSKP Singh goto out_put_prog; 2505ac4414b5SAlexei Starovoitov } 2506c4f6699dSAlexei Starovoitov 2507a38d1107SMatt Mullins btp = bpf_get_raw_tracepoint(tp_name); 2508ac4414b5SAlexei Starovoitov if (!btp) { 2509ac4414b5SAlexei Starovoitov err = -ENOENT; 2510ac4414b5SAlexei Starovoitov goto out_put_prog; 2511ac4414b5SAlexei Starovoitov } 2512c4f6699dSAlexei Starovoitov 2513babf3164SAndrii Nakryiko link = kzalloc(sizeof(*link), GFP_USER); 2514babf3164SAndrii Nakryiko if (!link) { 2515a38d1107SMatt Mullins err = -ENOMEM; 2516a38d1107SMatt Mullins goto out_put_btp; 2517a38d1107SMatt Mullins } 2518babf3164SAndrii Nakryiko bpf_link_init(&link->link, &bpf_raw_tp_lops, prog); 2519babf3164SAndrii Nakryiko link->btp = btp; 2520c4f6699dSAlexei Starovoitov 2521babf3164SAndrii Nakryiko link_file = bpf_link_new_file(&link->link, &link_fd); 2522babf3164SAndrii Nakryiko if (IS_ERR(link_file)) { 2523babf3164SAndrii Nakryiko kfree(link); 2524babf3164SAndrii Nakryiko err = PTR_ERR(link_file); 2525babf3164SAndrii Nakryiko goto out_put_btp; 2526c4f6699dSAlexei Starovoitov } 2527babf3164SAndrii Nakryiko 2528babf3164SAndrii Nakryiko err = bpf_probe_register(link->btp, prog); 2529babf3164SAndrii Nakryiko if (err) { 253098868668SAndrii Nakryiko bpf_link_cleanup(&link->link, link_file, link_fd); 2531babf3164SAndrii Nakryiko goto out_put_btp; 2532babf3164SAndrii Nakryiko } 2533babf3164SAndrii Nakryiko 2534babf3164SAndrii Nakryiko fd_install(link_fd, link_file); 253570ed506cSAndrii Nakryiko return link_fd; 2536c4f6699dSAlexei Starovoitov 2537a38d1107SMatt Mullins out_put_btp: 2538a38d1107SMatt Mullins bpf_put_raw_tracepoint(btp); 2539ac4414b5SAlexei Starovoitov out_put_prog: 2540ac4414b5SAlexei Starovoitov bpf_prog_put(prog); 2541c4f6699dSAlexei Starovoitov return err; 2542c4f6699dSAlexei Starovoitov } 2543c4f6699dSAlexei Starovoitov 254433491588SAnders Roxell static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog, 254533491588SAnders Roxell enum bpf_attach_type attach_type) 254633491588SAnders Roxell { 254733491588SAnders Roxell switch (prog->type) { 254833491588SAnders Roxell case BPF_PROG_TYPE_CGROUP_SOCK: 254933491588SAnders Roxell case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: 25500d01da6aSStanislav Fomichev case BPF_PROG_TYPE_CGROUP_SOCKOPT: 255133491588SAnders Roxell return attach_type == prog->expected_attach_type ? 0 : -EINVAL; 25525cf1e914Sbrakmo case BPF_PROG_TYPE_CGROUP_SKB: 25535cf1e914Sbrakmo return prog->enforce_expected_attach_type && 25545cf1e914Sbrakmo prog->expected_attach_type != attach_type ? 25555cf1e914Sbrakmo -EINVAL : 0; 255633491588SAnders Roxell default: 255733491588SAnders Roxell return 0; 255833491588SAnders Roxell } 255933491588SAnders Roxell } 256033491588SAnders Roxell 2561e28784e3SAndrii Nakryiko static enum bpf_prog_type 2562e28784e3SAndrii Nakryiko attach_type_to_prog_type(enum bpf_attach_type attach_type) 2563e28784e3SAndrii Nakryiko { 2564e28784e3SAndrii Nakryiko switch (attach_type) { 2565e28784e3SAndrii Nakryiko case BPF_CGROUP_INET_INGRESS: 2566e28784e3SAndrii Nakryiko case BPF_CGROUP_INET_EGRESS: 2567e28784e3SAndrii Nakryiko return BPF_PROG_TYPE_CGROUP_SKB; 2568e28784e3SAndrii Nakryiko break; 2569e28784e3SAndrii Nakryiko case BPF_CGROUP_INET_SOCK_CREATE: 2570e28784e3SAndrii Nakryiko case BPF_CGROUP_INET4_POST_BIND: 2571e28784e3SAndrii Nakryiko case BPF_CGROUP_INET6_POST_BIND: 2572e28784e3SAndrii Nakryiko return BPF_PROG_TYPE_CGROUP_SOCK; 2573e28784e3SAndrii Nakryiko case BPF_CGROUP_INET4_BIND: 2574e28784e3SAndrii Nakryiko case BPF_CGROUP_INET6_BIND: 2575e28784e3SAndrii Nakryiko case BPF_CGROUP_INET4_CONNECT: 2576e28784e3SAndrii Nakryiko case BPF_CGROUP_INET6_CONNECT: 2577e28784e3SAndrii Nakryiko case BPF_CGROUP_UDP4_SENDMSG: 2578e28784e3SAndrii Nakryiko case BPF_CGROUP_UDP6_SENDMSG: 2579e28784e3SAndrii Nakryiko case BPF_CGROUP_UDP4_RECVMSG: 2580e28784e3SAndrii Nakryiko case BPF_CGROUP_UDP6_RECVMSG: 2581e28784e3SAndrii Nakryiko return BPF_PROG_TYPE_CGROUP_SOCK_ADDR; 2582e28784e3SAndrii Nakryiko case BPF_CGROUP_SOCK_OPS: 2583e28784e3SAndrii Nakryiko return BPF_PROG_TYPE_SOCK_OPS; 2584e28784e3SAndrii Nakryiko case BPF_CGROUP_DEVICE: 2585e28784e3SAndrii Nakryiko return BPF_PROG_TYPE_CGROUP_DEVICE; 2586e28784e3SAndrii Nakryiko case BPF_SK_MSG_VERDICT: 2587e28784e3SAndrii Nakryiko return BPF_PROG_TYPE_SK_MSG; 2588e28784e3SAndrii Nakryiko case BPF_SK_SKB_STREAM_PARSER: 2589e28784e3SAndrii Nakryiko case BPF_SK_SKB_STREAM_VERDICT: 2590e28784e3SAndrii Nakryiko return BPF_PROG_TYPE_SK_SKB; 2591e28784e3SAndrii Nakryiko case BPF_LIRC_MODE2: 2592e28784e3SAndrii Nakryiko return BPF_PROG_TYPE_LIRC_MODE2; 2593e28784e3SAndrii Nakryiko case BPF_FLOW_DISSECTOR: 2594e28784e3SAndrii Nakryiko return BPF_PROG_TYPE_FLOW_DISSECTOR; 2595e28784e3SAndrii Nakryiko case BPF_CGROUP_SYSCTL: 2596e28784e3SAndrii Nakryiko return BPF_PROG_TYPE_CGROUP_SYSCTL; 2597e28784e3SAndrii Nakryiko case BPF_CGROUP_GETSOCKOPT: 2598e28784e3SAndrii Nakryiko case BPF_CGROUP_SETSOCKOPT: 2599e28784e3SAndrii Nakryiko return BPF_PROG_TYPE_CGROUP_SOCKOPT; 2600e28784e3SAndrii Nakryiko default: 2601e28784e3SAndrii Nakryiko return BPF_PROG_TYPE_UNSPEC; 2602e28784e3SAndrii Nakryiko } 2603e28784e3SAndrii Nakryiko } 2604e28784e3SAndrii Nakryiko 26057dd68b32SAndrey Ignatov #define BPF_PROG_ATTACH_LAST_FIELD replace_bpf_fd 2606174a79ffSJohn Fastabend 2607324bda9eSAlexei Starovoitov #define BPF_F_ATTACH_MASK \ 26087dd68b32SAndrey Ignatov (BPF_F_ALLOW_OVERRIDE | BPF_F_ALLOW_MULTI | BPF_F_REPLACE) 2609324bda9eSAlexei Starovoitov 2610f4324551SDaniel Mack static int bpf_prog_attach(const union bpf_attr *attr) 2611f4324551SDaniel Mack { 26127f677633SAlexei Starovoitov enum bpf_prog_type ptype; 2613f4324551SDaniel Mack struct bpf_prog *prog; 26147f677633SAlexei Starovoitov int ret; 2615f4324551SDaniel Mack 2616f4324551SDaniel Mack if (!capable(CAP_NET_ADMIN)) 2617f4324551SDaniel Mack return -EPERM; 2618f4324551SDaniel Mack 2619f4324551SDaniel Mack if (CHECK_ATTR(BPF_PROG_ATTACH)) 2620f4324551SDaniel Mack return -EINVAL; 2621f4324551SDaniel Mack 2622324bda9eSAlexei Starovoitov if (attr->attach_flags & ~BPF_F_ATTACH_MASK) 26237f677633SAlexei Starovoitov return -EINVAL; 26247f677633SAlexei Starovoitov 2625e28784e3SAndrii Nakryiko ptype = attach_type_to_prog_type(attr->attach_type); 2626e28784e3SAndrii Nakryiko if (ptype == BPF_PROG_TYPE_UNSPEC) 2627b2cd1257SDavid Ahern return -EINVAL; 2628b2cd1257SDavid Ahern 2629b2cd1257SDavid Ahern prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype); 2630f4324551SDaniel Mack if (IS_ERR(prog)) 2631f4324551SDaniel Mack return PTR_ERR(prog); 2632f4324551SDaniel Mack 26335e43f899SAndrey Ignatov if (bpf_prog_attach_check_attach_type(prog, attr->attach_type)) { 26345e43f899SAndrey Ignatov bpf_prog_put(prog); 26355e43f899SAndrey Ignatov return -EINVAL; 26365e43f899SAndrey Ignatov } 26375e43f899SAndrey Ignatov 2638fdb5c453SSean Young switch (ptype) { 2639fdb5c453SSean Young case BPF_PROG_TYPE_SK_SKB: 2640fdb5c453SSean Young case BPF_PROG_TYPE_SK_MSG: 2641604326b4SDaniel Borkmann ret = sock_map_get_from_fd(attr, prog); 2642fdb5c453SSean Young break; 2643fdb5c453SSean Young case BPF_PROG_TYPE_LIRC_MODE2: 2644fdb5c453SSean Young ret = lirc_prog_attach(attr, prog); 2645fdb5c453SSean Young break; 2646d58e468bSPetar Penkov case BPF_PROG_TYPE_FLOW_DISSECTOR: 2647d58e468bSPetar Penkov ret = skb_flow_dissector_bpf_prog_attach(attr, prog); 2648d58e468bSPetar Penkov break; 2649e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_DEVICE: 2650e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SKB: 2651e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SOCK: 2652e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: 2653e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SOCKOPT: 2654e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SYSCTL: 2655e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_SOCK_OPS: 2656fdb5c453SSean Young ret = cgroup_bpf_prog_attach(attr, ptype, prog); 2657e28784e3SAndrii Nakryiko break; 2658e28784e3SAndrii Nakryiko default: 2659e28784e3SAndrii Nakryiko ret = -EINVAL; 2660f4324551SDaniel Mack } 2661f4324551SDaniel Mack 26627f677633SAlexei Starovoitov if (ret) 26637f677633SAlexei Starovoitov bpf_prog_put(prog); 26647f677633SAlexei Starovoitov return ret; 2665f4324551SDaniel Mack } 2666f4324551SDaniel Mack 2667f4324551SDaniel Mack #define BPF_PROG_DETACH_LAST_FIELD attach_type 2668f4324551SDaniel Mack 2669f4324551SDaniel Mack static int bpf_prog_detach(const union bpf_attr *attr) 2670f4324551SDaniel Mack { 2671324bda9eSAlexei Starovoitov enum bpf_prog_type ptype; 2672f4324551SDaniel Mack 2673f4324551SDaniel Mack if (!capable(CAP_NET_ADMIN)) 2674f4324551SDaniel Mack return -EPERM; 2675f4324551SDaniel Mack 2676f4324551SDaniel Mack if (CHECK_ATTR(BPF_PROG_DETACH)) 2677f4324551SDaniel Mack return -EINVAL; 2678f4324551SDaniel Mack 2679e28784e3SAndrii Nakryiko ptype = attach_type_to_prog_type(attr->attach_type); 2680e28784e3SAndrii Nakryiko 2681e28784e3SAndrii Nakryiko switch (ptype) { 2682e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_SK_MSG: 2683e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_SK_SKB: 2684604326b4SDaniel Borkmann return sock_map_get_from_fd(attr, NULL); 2685e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_LIRC_MODE2: 2686f4364dcfSSean Young return lirc_prog_detach(attr); 2687e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_FLOW_DISSECTOR: 2688d58e468bSPetar Penkov return skb_flow_dissector_bpf_prog_detach(attr); 2689e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_DEVICE: 2690e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SKB: 2691e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SOCK: 2692e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: 2693e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SOCKOPT: 2694e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SYSCTL: 2695e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_SOCK_OPS: 2696e28784e3SAndrii Nakryiko return cgroup_bpf_prog_detach(attr, ptype); 2697f4324551SDaniel Mack default: 2698f4324551SDaniel Mack return -EINVAL; 2699f4324551SDaniel Mack } 2700f4324551SDaniel Mack } 270140304b2aSLawrence Brakmo 2702468e2f64SAlexei Starovoitov #define BPF_PROG_QUERY_LAST_FIELD query.prog_cnt 2703468e2f64SAlexei Starovoitov 2704468e2f64SAlexei Starovoitov static int bpf_prog_query(const union bpf_attr *attr, 2705468e2f64SAlexei Starovoitov union bpf_attr __user *uattr) 2706468e2f64SAlexei Starovoitov { 2707468e2f64SAlexei Starovoitov if (!capable(CAP_NET_ADMIN)) 2708468e2f64SAlexei Starovoitov return -EPERM; 2709468e2f64SAlexei Starovoitov if (CHECK_ATTR(BPF_PROG_QUERY)) 2710468e2f64SAlexei Starovoitov return -EINVAL; 2711468e2f64SAlexei Starovoitov if (attr->query.query_flags & ~BPF_F_QUERY_EFFECTIVE) 2712468e2f64SAlexei Starovoitov return -EINVAL; 2713468e2f64SAlexei Starovoitov 2714468e2f64SAlexei Starovoitov switch (attr->query.attach_type) { 2715468e2f64SAlexei Starovoitov case BPF_CGROUP_INET_INGRESS: 2716468e2f64SAlexei Starovoitov case BPF_CGROUP_INET_EGRESS: 2717468e2f64SAlexei Starovoitov case BPF_CGROUP_INET_SOCK_CREATE: 27184fbac77dSAndrey Ignatov case BPF_CGROUP_INET4_BIND: 27194fbac77dSAndrey Ignatov case BPF_CGROUP_INET6_BIND: 2720aac3fc32SAndrey Ignatov case BPF_CGROUP_INET4_POST_BIND: 2721aac3fc32SAndrey Ignatov case BPF_CGROUP_INET6_POST_BIND: 2722d74bad4eSAndrey Ignatov case BPF_CGROUP_INET4_CONNECT: 2723d74bad4eSAndrey Ignatov case BPF_CGROUP_INET6_CONNECT: 27241cedee13SAndrey Ignatov case BPF_CGROUP_UDP4_SENDMSG: 27251cedee13SAndrey Ignatov case BPF_CGROUP_UDP6_SENDMSG: 2726983695faSDaniel Borkmann case BPF_CGROUP_UDP4_RECVMSG: 2727983695faSDaniel Borkmann case BPF_CGROUP_UDP6_RECVMSG: 2728468e2f64SAlexei Starovoitov case BPF_CGROUP_SOCK_OPS: 2729ebc614f6SRoman Gushchin case BPF_CGROUP_DEVICE: 27307b146cebSAndrey Ignatov case BPF_CGROUP_SYSCTL: 27310d01da6aSStanislav Fomichev case BPF_CGROUP_GETSOCKOPT: 27320d01da6aSStanislav Fomichev case BPF_CGROUP_SETSOCKOPT: 2733e28784e3SAndrii Nakryiko return cgroup_bpf_prog_query(attr, uattr); 2734f4364dcfSSean Young case BPF_LIRC_MODE2: 2735f4364dcfSSean Young return lirc_prog_query(attr, uattr); 2736118c8e9aSStanislav Fomichev case BPF_FLOW_DISSECTOR: 2737118c8e9aSStanislav Fomichev return skb_flow_dissector_prog_query(attr, uattr); 2738468e2f64SAlexei Starovoitov default: 2739468e2f64SAlexei Starovoitov return -EINVAL; 2740468e2f64SAlexei Starovoitov } 2741468e2f64SAlexei Starovoitov } 2742f4324551SDaniel Mack 2743b0b9395dSStanislav Fomichev #define BPF_PROG_TEST_RUN_LAST_FIELD test.ctx_out 27441cf1cae9SAlexei Starovoitov 27451cf1cae9SAlexei Starovoitov static int bpf_prog_test_run(const union bpf_attr *attr, 27461cf1cae9SAlexei Starovoitov union bpf_attr __user *uattr) 27471cf1cae9SAlexei Starovoitov { 27481cf1cae9SAlexei Starovoitov struct bpf_prog *prog; 27491cf1cae9SAlexei Starovoitov int ret = -ENOTSUPP; 27501cf1cae9SAlexei Starovoitov 275161f3c964SAlexei Starovoitov if (!capable(CAP_SYS_ADMIN)) 275261f3c964SAlexei Starovoitov return -EPERM; 27531cf1cae9SAlexei Starovoitov if (CHECK_ATTR(BPF_PROG_TEST_RUN)) 27541cf1cae9SAlexei Starovoitov return -EINVAL; 27551cf1cae9SAlexei Starovoitov 2756b0b9395dSStanislav Fomichev if ((attr->test.ctx_size_in && !attr->test.ctx_in) || 2757b0b9395dSStanislav Fomichev (!attr->test.ctx_size_in && attr->test.ctx_in)) 2758b0b9395dSStanislav Fomichev return -EINVAL; 2759b0b9395dSStanislav Fomichev 2760b0b9395dSStanislav Fomichev if ((attr->test.ctx_size_out && !attr->test.ctx_out) || 2761b0b9395dSStanislav Fomichev (!attr->test.ctx_size_out && attr->test.ctx_out)) 2762b0b9395dSStanislav Fomichev return -EINVAL; 2763b0b9395dSStanislav Fomichev 27641cf1cae9SAlexei Starovoitov prog = bpf_prog_get(attr->test.prog_fd); 27651cf1cae9SAlexei Starovoitov if (IS_ERR(prog)) 27661cf1cae9SAlexei Starovoitov return PTR_ERR(prog); 27671cf1cae9SAlexei Starovoitov 27681cf1cae9SAlexei Starovoitov if (prog->aux->ops->test_run) 27691cf1cae9SAlexei Starovoitov ret = prog->aux->ops->test_run(prog, attr, uattr); 27701cf1cae9SAlexei Starovoitov 27711cf1cae9SAlexei Starovoitov bpf_prog_put(prog); 27721cf1cae9SAlexei Starovoitov return ret; 27731cf1cae9SAlexei Starovoitov } 27741cf1cae9SAlexei Starovoitov 277534ad5580SMartin KaFai Lau #define BPF_OBJ_GET_NEXT_ID_LAST_FIELD next_id 277634ad5580SMartin KaFai Lau 277734ad5580SMartin KaFai Lau static int bpf_obj_get_next_id(const union bpf_attr *attr, 277834ad5580SMartin KaFai Lau union bpf_attr __user *uattr, 277934ad5580SMartin KaFai Lau struct idr *idr, 278034ad5580SMartin KaFai Lau spinlock_t *lock) 278134ad5580SMartin KaFai Lau { 278234ad5580SMartin KaFai Lau u32 next_id = attr->start_id; 278334ad5580SMartin KaFai Lau int err = 0; 278434ad5580SMartin KaFai Lau 278534ad5580SMartin KaFai Lau if (CHECK_ATTR(BPF_OBJ_GET_NEXT_ID) || next_id >= INT_MAX) 278634ad5580SMartin KaFai Lau return -EINVAL; 278734ad5580SMartin KaFai Lau 278834ad5580SMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) 278934ad5580SMartin KaFai Lau return -EPERM; 279034ad5580SMartin KaFai Lau 279134ad5580SMartin KaFai Lau next_id++; 279234ad5580SMartin KaFai Lau spin_lock_bh(lock); 279334ad5580SMartin KaFai Lau if (!idr_get_next(idr, &next_id)) 279434ad5580SMartin KaFai Lau err = -ENOENT; 279534ad5580SMartin KaFai Lau spin_unlock_bh(lock); 279634ad5580SMartin KaFai Lau 279734ad5580SMartin KaFai Lau if (!err) 279834ad5580SMartin KaFai Lau err = put_user(next_id, &uattr->next_id); 279934ad5580SMartin KaFai Lau 280034ad5580SMartin KaFai Lau return err; 280134ad5580SMartin KaFai Lau } 280234ad5580SMartin KaFai Lau 2803b16d9aa4SMartin KaFai Lau #define BPF_PROG_GET_FD_BY_ID_LAST_FIELD prog_id 2804b16d9aa4SMartin KaFai Lau 28057e6897f9SBjörn Töpel struct bpf_prog *bpf_prog_by_id(u32 id) 28067e6897f9SBjörn Töpel { 28077e6897f9SBjörn Töpel struct bpf_prog *prog; 28087e6897f9SBjörn Töpel 28097e6897f9SBjörn Töpel if (!id) 28107e6897f9SBjörn Töpel return ERR_PTR(-ENOENT); 28117e6897f9SBjörn Töpel 28127e6897f9SBjörn Töpel spin_lock_bh(&prog_idr_lock); 28137e6897f9SBjörn Töpel prog = idr_find(&prog_idr, id); 28147e6897f9SBjörn Töpel if (prog) 28157e6897f9SBjörn Töpel prog = bpf_prog_inc_not_zero(prog); 28167e6897f9SBjörn Töpel else 28177e6897f9SBjörn Töpel prog = ERR_PTR(-ENOENT); 28187e6897f9SBjörn Töpel spin_unlock_bh(&prog_idr_lock); 28197e6897f9SBjörn Töpel return prog; 28207e6897f9SBjörn Töpel } 28217e6897f9SBjörn Töpel 2822b16d9aa4SMartin KaFai Lau static int bpf_prog_get_fd_by_id(const union bpf_attr *attr) 2823b16d9aa4SMartin KaFai Lau { 2824b16d9aa4SMartin KaFai Lau struct bpf_prog *prog; 2825b16d9aa4SMartin KaFai Lau u32 id = attr->prog_id; 2826b16d9aa4SMartin KaFai Lau int fd; 2827b16d9aa4SMartin KaFai Lau 2828b16d9aa4SMartin KaFai Lau if (CHECK_ATTR(BPF_PROG_GET_FD_BY_ID)) 2829b16d9aa4SMartin KaFai Lau return -EINVAL; 2830b16d9aa4SMartin KaFai Lau 2831b16d9aa4SMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) 2832b16d9aa4SMartin KaFai Lau return -EPERM; 2833b16d9aa4SMartin KaFai Lau 28347e6897f9SBjörn Töpel prog = bpf_prog_by_id(id); 2835b16d9aa4SMartin KaFai Lau if (IS_ERR(prog)) 2836b16d9aa4SMartin KaFai Lau return PTR_ERR(prog); 2837b16d9aa4SMartin KaFai Lau 2838b16d9aa4SMartin KaFai Lau fd = bpf_prog_new_fd(prog); 2839b16d9aa4SMartin KaFai Lau if (fd < 0) 2840b16d9aa4SMartin KaFai Lau bpf_prog_put(prog); 2841b16d9aa4SMartin KaFai Lau 2842b16d9aa4SMartin KaFai Lau return fd; 2843b16d9aa4SMartin KaFai Lau } 2844b16d9aa4SMartin KaFai Lau 28456e71b04aSChenbo Feng #define BPF_MAP_GET_FD_BY_ID_LAST_FIELD open_flags 2846bd5f5f4eSMartin KaFai Lau 2847bd5f5f4eSMartin KaFai Lau static int bpf_map_get_fd_by_id(const union bpf_attr *attr) 2848bd5f5f4eSMartin KaFai Lau { 2849bd5f5f4eSMartin KaFai Lau struct bpf_map *map; 2850bd5f5f4eSMartin KaFai Lau u32 id = attr->map_id; 28516e71b04aSChenbo Feng int f_flags; 2852bd5f5f4eSMartin KaFai Lau int fd; 2853bd5f5f4eSMartin KaFai Lau 28546e71b04aSChenbo Feng if (CHECK_ATTR(BPF_MAP_GET_FD_BY_ID) || 28556e71b04aSChenbo Feng attr->open_flags & ~BPF_OBJ_FLAG_MASK) 2856bd5f5f4eSMartin KaFai Lau return -EINVAL; 2857bd5f5f4eSMartin KaFai Lau 2858bd5f5f4eSMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) 2859bd5f5f4eSMartin KaFai Lau return -EPERM; 2860bd5f5f4eSMartin KaFai Lau 28616e71b04aSChenbo Feng f_flags = bpf_get_file_flag(attr->open_flags); 28626e71b04aSChenbo Feng if (f_flags < 0) 28636e71b04aSChenbo Feng return f_flags; 28646e71b04aSChenbo Feng 2865bd5f5f4eSMartin KaFai Lau spin_lock_bh(&map_idr_lock); 2866bd5f5f4eSMartin KaFai Lau map = idr_find(&map_idr, id); 2867bd5f5f4eSMartin KaFai Lau if (map) 2868b0e4701cSStanislav Fomichev map = __bpf_map_inc_not_zero(map, true); 2869bd5f5f4eSMartin KaFai Lau else 2870bd5f5f4eSMartin KaFai Lau map = ERR_PTR(-ENOENT); 2871bd5f5f4eSMartin KaFai Lau spin_unlock_bh(&map_idr_lock); 2872bd5f5f4eSMartin KaFai Lau 2873bd5f5f4eSMartin KaFai Lau if (IS_ERR(map)) 2874bd5f5f4eSMartin KaFai Lau return PTR_ERR(map); 2875bd5f5f4eSMartin KaFai Lau 28766e71b04aSChenbo Feng fd = bpf_map_new_fd(map, f_flags); 2877bd5f5f4eSMartin KaFai Lau if (fd < 0) 2878781e6282SPeng Sun bpf_map_put_with_uref(map); 2879bd5f5f4eSMartin KaFai Lau 2880bd5f5f4eSMartin KaFai Lau return fd; 2881bd5f5f4eSMartin KaFai Lau } 2882bd5f5f4eSMartin KaFai Lau 28837105e828SDaniel Borkmann static const struct bpf_map *bpf_map_from_imm(const struct bpf_prog *prog, 2884d8eca5bbSDaniel Borkmann unsigned long addr, u32 *off, 2885d8eca5bbSDaniel Borkmann u32 *type) 28867105e828SDaniel Borkmann { 2887d8eca5bbSDaniel Borkmann const struct bpf_map *map; 28887105e828SDaniel Borkmann int i; 28897105e828SDaniel Borkmann 2890d8eca5bbSDaniel Borkmann for (i = 0, *off = 0; i < prog->aux->used_map_cnt; i++) { 2891d8eca5bbSDaniel Borkmann map = prog->aux->used_maps[i]; 2892d8eca5bbSDaniel Borkmann if (map == (void *)addr) { 2893d8eca5bbSDaniel Borkmann *type = BPF_PSEUDO_MAP_FD; 2894d8eca5bbSDaniel Borkmann return map; 2895d8eca5bbSDaniel Borkmann } 2896d8eca5bbSDaniel Borkmann if (!map->ops->map_direct_value_meta) 2897d8eca5bbSDaniel Borkmann continue; 2898d8eca5bbSDaniel Borkmann if (!map->ops->map_direct_value_meta(map, addr, off)) { 2899d8eca5bbSDaniel Borkmann *type = BPF_PSEUDO_MAP_VALUE; 2900d8eca5bbSDaniel Borkmann return map; 2901d8eca5bbSDaniel Borkmann } 2902d8eca5bbSDaniel Borkmann } 2903d8eca5bbSDaniel Borkmann 29047105e828SDaniel Borkmann return NULL; 29057105e828SDaniel Borkmann } 29067105e828SDaniel Borkmann 29077105e828SDaniel Borkmann static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog) 29087105e828SDaniel Borkmann { 29097105e828SDaniel Borkmann const struct bpf_map *map; 29107105e828SDaniel Borkmann struct bpf_insn *insns; 2911d8eca5bbSDaniel Borkmann u32 off, type; 29127105e828SDaniel Borkmann u64 imm; 29137105e828SDaniel Borkmann int i; 29147105e828SDaniel Borkmann 29157105e828SDaniel Borkmann insns = kmemdup(prog->insnsi, bpf_prog_insn_size(prog), 29167105e828SDaniel Borkmann GFP_USER); 29177105e828SDaniel Borkmann if (!insns) 29187105e828SDaniel Borkmann return insns; 29197105e828SDaniel Borkmann 29207105e828SDaniel Borkmann for (i = 0; i < prog->len; i++) { 29217105e828SDaniel Borkmann if (insns[i].code == (BPF_JMP | BPF_TAIL_CALL)) { 29227105e828SDaniel Borkmann insns[i].code = BPF_JMP | BPF_CALL; 29237105e828SDaniel Borkmann insns[i].imm = BPF_FUNC_tail_call; 29247105e828SDaniel Borkmann /* fall-through */ 29257105e828SDaniel Borkmann } 29267105e828SDaniel Borkmann if (insns[i].code == (BPF_JMP | BPF_CALL) || 29277105e828SDaniel Borkmann insns[i].code == (BPF_JMP | BPF_CALL_ARGS)) { 29287105e828SDaniel Borkmann if (insns[i].code == (BPF_JMP | BPF_CALL_ARGS)) 29297105e828SDaniel Borkmann insns[i].code = BPF_JMP | BPF_CALL; 29307105e828SDaniel Borkmann if (!bpf_dump_raw_ok()) 29317105e828SDaniel Borkmann insns[i].imm = 0; 29327105e828SDaniel Borkmann continue; 29337105e828SDaniel Borkmann } 29347105e828SDaniel Borkmann 29357105e828SDaniel Borkmann if (insns[i].code != (BPF_LD | BPF_IMM | BPF_DW)) 29367105e828SDaniel Borkmann continue; 29377105e828SDaniel Borkmann 29387105e828SDaniel Borkmann imm = ((u64)insns[i + 1].imm << 32) | (u32)insns[i].imm; 2939d8eca5bbSDaniel Borkmann map = bpf_map_from_imm(prog, imm, &off, &type); 29407105e828SDaniel Borkmann if (map) { 2941d8eca5bbSDaniel Borkmann insns[i].src_reg = type; 29427105e828SDaniel Borkmann insns[i].imm = map->id; 2943d8eca5bbSDaniel Borkmann insns[i + 1].imm = off; 29447105e828SDaniel Borkmann continue; 29457105e828SDaniel Borkmann } 29467105e828SDaniel Borkmann } 29477105e828SDaniel Borkmann 29487105e828SDaniel Borkmann return insns; 29497105e828SDaniel Borkmann } 29507105e828SDaniel Borkmann 2951c454a46bSMartin KaFai Lau static int set_info_rec_size(struct bpf_prog_info *info) 2952c454a46bSMartin KaFai Lau { 2953c454a46bSMartin KaFai Lau /* 2954c454a46bSMartin KaFai Lau * Ensure info.*_rec_size is the same as kernel expected size 2955c454a46bSMartin KaFai Lau * 2956c454a46bSMartin KaFai Lau * or 2957c454a46bSMartin KaFai Lau * 2958c454a46bSMartin KaFai Lau * Only allow zero *_rec_size if both _rec_size and _cnt are 2959c454a46bSMartin KaFai Lau * zero. In this case, the kernel will set the expected 2960c454a46bSMartin KaFai Lau * _rec_size back to the info. 2961c454a46bSMartin KaFai Lau */ 2962c454a46bSMartin KaFai Lau 296311d8b82dSYonghong Song if ((info->nr_func_info || info->func_info_rec_size) && 2964c454a46bSMartin KaFai Lau info->func_info_rec_size != sizeof(struct bpf_func_info)) 2965c454a46bSMartin KaFai Lau return -EINVAL; 2966c454a46bSMartin KaFai Lau 296711d8b82dSYonghong Song if ((info->nr_line_info || info->line_info_rec_size) && 2968c454a46bSMartin KaFai Lau info->line_info_rec_size != sizeof(struct bpf_line_info)) 2969c454a46bSMartin KaFai Lau return -EINVAL; 2970c454a46bSMartin KaFai Lau 297111d8b82dSYonghong Song if ((info->nr_jited_line_info || info->jited_line_info_rec_size) && 2972c454a46bSMartin KaFai Lau info->jited_line_info_rec_size != sizeof(__u64)) 2973c454a46bSMartin KaFai Lau return -EINVAL; 2974c454a46bSMartin KaFai Lau 2975c454a46bSMartin KaFai Lau info->func_info_rec_size = sizeof(struct bpf_func_info); 2976c454a46bSMartin KaFai Lau info->line_info_rec_size = sizeof(struct bpf_line_info); 2977c454a46bSMartin KaFai Lau info->jited_line_info_rec_size = sizeof(__u64); 2978c454a46bSMartin KaFai Lau 2979c454a46bSMartin KaFai Lau return 0; 2980c454a46bSMartin KaFai Lau } 2981c454a46bSMartin KaFai Lau 29821e270976SMartin KaFai Lau static int bpf_prog_get_info_by_fd(struct bpf_prog *prog, 29831e270976SMartin KaFai Lau const union bpf_attr *attr, 29841e270976SMartin KaFai Lau union bpf_attr __user *uattr) 29851e270976SMartin KaFai Lau { 29861e270976SMartin KaFai Lau struct bpf_prog_info __user *uinfo = u64_to_user_ptr(attr->info.info); 29875c6f2588SGreg Kroah-Hartman struct bpf_prog_info info; 29881e270976SMartin KaFai Lau u32 info_len = attr->info.info_len; 29895f8f8b93SAlexei Starovoitov struct bpf_prog_stats stats; 29901e270976SMartin KaFai Lau char __user *uinsns; 29911e270976SMartin KaFai Lau u32 ulen; 29921e270976SMartin KaFai Lau int err; 29931e270976SMartin KaFai Lau 2994dcab51f1SMartin KaFai Lau err = bpf_check_uarg_tail_zero(uinfo, sizeof(info), info_len); 29951e270976SMartin KaFai Lau if (err) 29961e270976SMartin KaFai Lau return err; 29971e270976SMartin KaFai Lau info_len = min_t(u32, sizeof(info), info_len); 29981e270976SMartin KaFai Lau 29995c6f2588SGreg Kroah-Hartman memset(&info, 0, sizeof(info)); 30001e270976SMartin KaFai Lau if (copy_from_user(&info, uinfo, info_len)) 300189b09689SDaniel Borkmann return -EFAULT; 30021e270976SMartin KaFai Lau 30031e270976SMartin KaFai Lau info.type = prog->type; 30041e270976SMartin KaFai Lau info.id = prog->aux->id; 3005cb4d2b3fSMartin KaFai Lau info.load_time = prog->aux->load_time; 3006cb4d2b3fSMartin KaFai Lau info.created_by_uid = from_kuid_munged(current_user_ns(), 3007cb4d2b3fSMartin KaFai Lau prog->aux->user->uid); 3008b85fab0eSJiri Olsa info.gpl_compatible = prog->gpl_compatible; 30091e270976SMartin KaFai Lau 30101e270976SMartin KaFai Lau memcpy(info.tag, prog->tag, sizeof(prog->tag)); 3011cb4d2b3fSMartin KaFai Lau memcpy(info.name, prog->aux->name, sizeof(prog->aux->name)); 3012cb4d2b3fSMartin KaFai Lau 3013cb4d2b3fSMartin KaFai Lau ulen = info.nr_map_ids; 3014cb4d2b3fSMartin KaFai Lau info.nr_map_ids = prog->aux->used_map_cnt; 3015cb4d2b3fSMartin KaFai Lau ulen = min_t(u32, info.nr_map_ids, ulen); 3016cb4d2b3fSMartin KaFai Lau if (ulen) { 3017721e08daSMartin KaFai Lau u32 __user *user_map_ids = u64_to_user_ptr(info.map_ids); 3018cb4d2b3fSMartin KaFai Lau u32 i; 3019cb4d2b3fSMartin KaFai Lau 3020cb4d2b3fSMartin KaFai Lau for (i = 0; i < ulen; i++) 3021cb4d2b3fSMartin KaFai Lau if (put_user(prog->aux->used_maps[i]->id, 3022cb4d2b3fSMartin KaFai Lau &user_map_ids[i])) 3023cb4d2b3fSMartin KaFai Lau return -EFAULT; 3024cb4d2b3fSMartin KaFai Lau } 30251e270976SMartin KaFai Lau 3026c454a46bSMartin KaFai Lau err = set_info_rec_size(&info); 3027c454a46bSMartin KaFai Lau if (err) 3028c454a46bSMartin KaFai Lau return err; 30297337224fSMartin KaFai Lau 30305f8f8b93SAlexei Starovoitov bpf_prog_get_stats(prog, &stats); 30315f8f8b93SAlexei Starovoitov info.run_time_ns = stats.nsecs; 30325f8f8b93SAlexei Starovoitov info.run_cnt = stats.cnt; 30335f8f8b93SAlexei Starovoitov 30341e270976SMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) { 30351e270976SMartin KaFai Lau info.jited_prog_len = 0; 30361e270976SMartin KaFai Lau info.xlated_prog_len = 0; 3037dbecd738SSandipan Das info.nr_jited_ksyms = 0; 303828c2fae7SDaniel Borkmann info.nr_jited_func_lens = 0; 303911d8b82dSYonghong Song info.nr_func_info = 0; 304011d8b82dSYonghong Song info.nr_line_info = 0; 304111d8b82dSYonghong Song info.nr_jited_line_info = 0; 30421e270976SMartin KaFai Lau goto done; 30431e270976SMartin KaFai Lau } 30441e270976SMartin KaFai Lau 30451e270976SMartin KaFai Lau ulen = info.xlated_prog_len; 30469975a54bSDaniel Borkmann info.xlated_prog_len = bpf_prog_insn_size(prog); 30471e270976SMartin KaFai Lau if (info.xlated_prog_len && ulen) { 30487105e828SDaniel Borkmann struct bpf_insn *insns_sanitized; 30497105e828SDaniel Borkmann bool fault; 30507105e828SDaniel Borkmann 30517105e828SDaniel Borkmann if (prog->blinded && !bpf_dump_raw_ok()) { 30527105e828SDaniel Borkmann info.xlated_prog_insns = 0; 30537105e828SDaniel Borkmann goto done; 30547105e828SDaniel Borkmann } 30557105e828SDaniel Borkmann insns_sanitized = bpf_insn_prepare_dump(prog); 30567105e828SDaniel Borkmann if (!insns_sanitized) 30577105e828SDaniel Borkmann return -ENOMEM; 30581e270976SMartin KaFai Lau uinsns = u64_to_user_ptr(info.xlated_prog_insns); 30591e270976SMartin KaFai Lau ulen = min_t(u32, info.xlated_prog_len, ulen); 30607105e828SDaniel Borkmann fault = copy_to_user(uinsns, insns_sanitized, ulen); 30617105e828SDaniel Borkmann kfree(insns_sanitized); 30627105e828SDaniel Borkmann if (fault) 30631e270976SMartin KaFai Lau return -EFAULT; 30641e270976SMartin KaFai Lau } 30651e270976SMartin KaFai Lau 3066675fc275SJakub Kicinski if (bpf_prog_is_dev_bound(prog->aux)) { 3067675fc275SJakub Kicinski err = bpf_prog_offload_info_fill(&info, prog); 3068675fc275SJakub Kicinski if (err) 3069675fc275SJakub Kicinski return err; 3070fcfb126dSJiong Wang goto done; 3071fcfb126dSJiong Wang } 3072fcfb126dSJiong Wang 3073fcfb126dSJiong Wang /* NOTE: the following code is supposed to be skipped for offload. 3074fcfb126dSJiong Wang * bpf_prog_offload_info_fill() is the place to fill similar fields 3075fcfb126dSJiong Wang * for offload. 3076fcfb126dSJiong Wang */ 3077fcfb126dSJiong Wang ulen = info.jited_prog_len; 30784d56a76eSSandipan Das if (prog->aux->func_cnt) { 30794d56a76eSSandipan Das u32 i; 30804d56a76eSSandipan Das 30814d56a76eSSandipan Das info.jited_prog_len = 0; 30824d56a76eSSandipan Das for (i = 0; i < prog->aux->func_cnt; i++) 30834d56a76eSSandipan Das info.jited_prog_len += prog->aux->func[i]->jited_len; 30844d56a76eSSandipan Das } else { 3085fcfb126dSJiong Wang info.jited_prog_len = prog->jited_len; 30864d56a76eSSandipan Das } 30874d56a76eSSandipan Das 3088fcfb126dSJiong Wang if (info.jited_prog_len && ulen) { 3089fcfb126dSJiong Wang if (bpf_dump_raw_ok()) { 3090fcfb126dSJiong Wang uinsns = u64_to_user_ptr(info.jited_prog_insns); 3091fcfb126dSJiong Wang ulen = min_t(u32, info.jited_prog_len, ulen); 30924d56a76eSSandipan Das 30934d56a76eSSandipan Das /* for multi-function programs, copy the JITed 30944d56a76eSSandipan Das * instructions for all the functions 30954d56a76eSSandipan Das */ 30964d56a76eSSandipan Das if (prog->aux->func_cnt) { 30974d56a76eSSandipan Das u32 len, free, i; 30984d56a76eSSandipan Das u8 *img; 30994d56a76eSSandipan Das 31004d56a76eSSandipan Das free = ulen; 31014d56a76eSSandipan Das for (i = 0; i < prog->aux->func_cnt; i++) { 31024d56a76eSSandipan Das len = prog->aux->func[i]->jited_len; 31034d56a76eSSandipan Das len = min_t(u32, len, free); 31044d56a76eSSandipan Das img = (u8 *) prog->aux->func[i]->bpf_func; 31054d56a76eSSandipan Das if (copy_to_user(uinsns, img, len)) 31064d56a76eSSandipan Das return -EFAULT; 31074d56a76eSSandipan Das uinsns += len; 31084d56a76eSSandipan Das free -= len; 31094d56a76eSSandipan Das if (!free) 31104d56a76eSSandipan Das break; 31114d56a76eSSandipan Das } 31124d56a76eSSandipan Das } else { 3113fcfb126dSJiong Wang if (copy_to_user(uinsns, prog->bpf_func, ulen)) 3114fcfb126dSJiong Wang return -EFAULT; 31154d56a76eSSandipan Das } 3116fcfb126dSJiong Wang } else { 3117fcfb126dSJiong Wang info.jited_prog_insns = 0; 3118fcfb126dSJiong Wang } 3119675fc275SJakub Kicinski } 3120675fc275SJakub Kicinski 3121dbecd738SSandipan Das ulen = info.nr_jited_ksyms; 3122ff1889fcSSong Liu info.nr_jited_ksyms = prog->aux->func_cnt ? : 1; 31237a5725ddSSong Liu if (ulen) { 3124dbecd738SSandipan Das if (bpf_dump_raw_ok()) { 3125ff1889fcSSong Liu unsigned long ksym_addr; 3126dbecd738SSandipan Das u64 __user *user_ksyms; 3127dbecd738SSandipan Das u32 i; 3128dbecd738SSandipan Das 3129dbecd738SSandipan Das /* copy the address of the kernel symbol 3130dbecd738SSandipan Das * corresponding to each function 3131dbecd738SSandipan Das */ 3132dbecd738SSandipan Das ulen = min_t(u32, info.nr_jited_ksyms, ulen); 3133dbecd738SSandipan Das user_ksyms = u64_to_user_ptr(info.jited_ksyms); 3134ff1889fcSSong Liu if (prog->aux->func_cnt) { 3135dbecd738SSandipan Das for (i = 0; i < ulen; i++) { 3136ff1889fcSSong Liu ksym_addr = (unsigned long) 3137ff1889fcSSong Liu prog->aux->func[i]->bpf_func; 3138ff1889fcSSong Liu if (put_user((u64) ksym_addr, 3139ff1889fcSSong Liu &user_ksyms[i])) 3140ff1889fcSSong Liu return -EFAULT; 3141ff1889fcSSong Liu } 3142ff1889fcSSong Liu } else { 3143ff1889fcSSong Liu ksym_addr = (unsigned long) prog->bpf_func; 3144ff1889fcSSong Liu if (put_user((u64) ksym_addr, &user_ksyms[0])) 3145dbecd738SSandipan Das return -EFAULT; 3146dbecd738SSandipan Das } 3147dbecd738SSandipan Das } else { 3148dbecd738SSandipan Das info.jited_ksyms = 0; 3149dbecd738SSandipan Das } 3150dbecd738SSandipan Das } 3151dbecd738SSandipan Das 3152815581c1SSandipan Das ulen = info.nr_jited_func_lens; 3153ff1889fcSSong Liu info.nr_jited_func_lens = prog->aux->func_cnt ? : 1; 31547a5725ddSSong Liu if (ulen) { 3155815581c1SSandipan Das if (bpf_dump_raw_ok()) { 3156815581c1SSandipan Das u32 __user *user_lens; 3157815581c1SSandipan Das u32 func_len, i; 3158815581c1SSandipan Das 3159815581c1SSandipan Das /* copy the JITed image lengths for each function */ 3160815581c1SSandipan Das ulen = min_t(u32, info.nr_jited_func_lens, ulen); 3161815581c1SSandipan Das user_lens = u64_to_user_ptr(info.jited_func_lens); 3162ff1889fcSSong Liu if (prog->aux->func_cnt) { 3163815581c1SSandipan Das for (i = 0; i < ulen; i++) { 3164ff1889fcSSong Liu func_len = 3165ff1889fcSSong Liu prog->aux->func[i]->jited_len; 3166815581c1SSandipan Das if (put_user(func_len, &user_lens[i])) 3167815581c1SSandipan Das return -EFAULT; 3168815581c1SSandipan Das } 3169815581c1SSandipan Das } else { 3170ff1889fcSSong Liu func_len = prog->jited_len; 3171ff1889fcSSong Liu if (put_user(func_len, &user_lens[0])) 3172ff1889fcSSong Liu return -EFAULT; 3173ff1889fcSSong Liu } 3174ff1889fcSSong Liu } else { 3175815581c1SSandipan Das info.jited_func_lens = 0; 3176815581c1SSandipan Das } 3177815581c1SSandipan Das } 3178815581c1SSandipan Das 31797337224fSMartin KaFai Lau if (prog->aux->btf) 3180838e9690SYonghong Song info.btf_id = btf_id(prog->aux->btf); 3181838e9690SYonghong Song 318211d8b82dSYonghong Song ulen = info.nr_func_info; 318311d8b82dSYonghong Song info.nr_func_info = prog->aux->func_info_cnt; 318411d8b82dSYonghong Song if (info.nr_func_info && ulen) { 3185838e9690SYonghong Song char __user *user_finfo; 3186838e9690SYonghong Song 3187838e9690SYonghong Song user_finfo = u64_to_user_ptr(info.func_info); 318811d8b82dSYonghong Song ulen = min_t(u32, info.nr_func_info, ulen); 3189ba64e7d8SYonghong Song if (copy_to_user(user_finfo, prog->aux->func_info, 31907337224fSMartin KaFai Lau info.func_info_rec_size * ulen)) 3191838e9690SYonghong Song return -EFAULT; 3192838e9690SYonghong Song } 3193838e9690SYonghong Song 319411d8b82dSYonghong Song ulen = info.nr_line_info; 319511d8b82dSYonghong Song info.nr_line_info = prog->aux->nr_linfo; 319611d8b82dSYonghong Song if (info.nr_line_info && ulen) { 3197c454a46bSMartin KaFai Lau __u8 __user *user_linfo; 3198c454a46bSMartin KaFai Lau 3199c454a46bSMartin KaFai Lau user_linfo = u64_to_user_ptr(info.line_info); 320011d8b82dSYonghong Song ulen = min_t(u32, info.nr_line_info, ulen); 3201c454a46bSMartin KaFai Lau if (copy_to_user(user_linfo, prog->aux->linfo, 3202c454a46bSMartin KaFai Lau info.line_info_rec_size * ulen)) 3203c454a46bSMartin KaFai Lau return -EFAULT; 3204c454a46bSMartin KaFai Lau } 3205c454a46bSMartin KaFai Lau 320611d8b82dSYonghong Song ulen = info.nr_jited_line_info; 3207c454a46bSMartin KaFai Lau if (prog->aux->jited_linfo) 320811d8b82dSYonghong Song info.nr_jited_line_info = prog->aux->nr_linfo; 3209c454a46bSMartin KaFai Lau else 321011d8b82dSYonghong Song info.nr_jited_line_info = 0; 321111d8b82dSYonghong Song if (info.nr_jited_line_info && ulen) { 3212c454a46bSMartin KaFai Lau if (bpf_dump_raw_ok()) { 3213c454a46bSMartin KaFai Lau __u64 __user *user_linfo; 3214c454a46bSMartin KaFai Lau u32 i; 3215c454a46bSMartin KaFai Lau 3216c454a46bSMartin KaFai Lau user_linfo = u64_to_user_ptr(info.jited_line_info); 321711d8b82dSYonghong Song ulen = min_t(u32, info.nr_jited_line_info, ulen); 3218c454a46bSMartin KaFai Lau for (i = 0; i < ulen; i++) { 3219c454a46bSMartin KaFai Lau if (put_user((__u64)(long)prog->aux->jited_linfo[i], 3220c454a46bSMartin KaFai Lau &user_linfo[i])) 3221c454a46bSMartin KaFai Lau return -EFAULT; 3222c454a46bSMartin KaFai Lau } 3223c454a46bSMartin KaFai Lau } else { 3224c454a46bSMartin KaFai Lau info.jited_line_info = 0; 3225c454a46bSMartin KaFai Lau } 3226c454a46bSMartin KaFai Lau } 3227c454a46bSMartin KaFai Lau 3228c872bdb3SSong Liu ulen = info.nr_prog_tags; 3229c872bdb3SSong Liu info.nr_prog_tags = prog->aux->func_cnt ? : 1; 3230c872bdb3SSong Liu if (ulen) { 3231c872bdb3SSong Liu __u8 __user (*user_prog_tags)[BPF_TAG_SIZE]; 3232c872bdb3SSong Liu u32 i; 3233c872bdb3SSong Liu 3234c872bdb3SSong Liu user_prog_tags = u64_to_user_ptr(info.prog_tags); 3235c872bdb3SSong Liu ulen = min_t(u32, info.nr_prog_tags, ulen); 3236c872bdb3SSong Liu if (prog->aux->func_cnt) { 3237c872bdb3SSong Liu for (i = 0; i < ulen; i++) { 3238c872bdb3SSong Liu if (copy_to_user(user_prog_tags[i], 3239c872bdb3SSong Liu prog->aux->func[i]->tag, 3240c872bdb3SSong Liu BPF_TAG_SIZE)) 3241c872bdb3SSong Liu return -EFAULT; 3242c872bdb3SSong Liu } 3243c872bdb3SSong Liu } else { 3244c872bdb3SSong Liu if (copy_to_user(user_prog_tags[0], 3245c872bdb3SSong Liu prog->tag, BPF_TAG_SIZE)) 3246c872bdb3SSong Liu return -EFAULT; 3247c872bdb3SSong Liu } 3248c872bdb3SSong Liu } 3249c872bdb3SSong Liu 32501e270976SMartin KaFai Lau done: 32511e270976SMartin KaFai Lau if (copy_to_user(uinfo, &info, info_len) || 32521e270976SMartin KaFai Lau put_user(info_len, &uattr->info.info_len)) 32531e270976SMartin KaFai Lau return -EFAULT; 32541e270976SMartin KaFai Lau 32551e270976SMartin KaFai Lau return 0; 32561e270976SMartin KaFai Lau } 32571e270976SMartin KaFai Lau 32581e270976SMartin KaFai Lau static int bpf_map_get_info_by_fd(struct bpf_map *map, 32591e270976SMartin KaFai Lau const union bpf_attr *attr, 32601e270976SMartin KaFai Lau union bpf_attr __user *uattr) 32611e270976SMartin KaFai Lau { 32621e270976SMartin KaFai Lau struct bpf_map_info __user *uinfo = u64_to_user_ptr(attr->info.info); 32635c6f2588SGreg Kroah-Hartman struct bpf_map_info info; 32641e270976SMartin KaFai Lau u32 info_len = attr->info.info_len; 32651e270976SMartin KaFai Lau int err; 32661e270976SMartin KaFai Lau 3267dcab51f1SMartin KaFai Lau err = bpf_check_uarg_tail_zero(uinfo, sizeof(info), info_len); 32681e270976SMartin KaFai Lau if (err) 32691e270976SMartin KaFai Lau return err; 32701e270976SMartin KaFai Lau info_len = min_t(u32, sizeof(info), info_len); 32711e270976SMartin KaFai Lau 32725c6f2588SGreg Kroah-Hartman memset(&info, 0, sizeof(info)); 32731e270976SMartin KaFai Lau info.type = map->map_type; 32741e270976SMartin KaFai Lau info.id = map->id; 32751e270976SMartin KaFai Lau info.key_size = map->key_size; 32761e270976SMartin KaFai Lau info.value_size = map->value_size; 32771e270976SMartin KaFai Lau info.max_entries = map->max_entries; 32781e270976SMartin KaFai Lau info.map_flags = map->map_flags; 3279ad5b177bSMartin KaFai Lau memcpy(info.name, map->name, sizeof(map->name)); 32801e270976SMartin KaFai Lau 328178958fcaSMartin KaFai Lau if (map->btf) { 328278958fcaSMartin KaFai Lau info.btf_id = btf_id(map->btf); 32839b2cf328SMartin KaFai Lau info.btf_key_type_id = map->btf_key_type_id; 32849b2cf328SMartin KaFai Lau info.btf_value_type_id = map->btf_value_type_id; 328578958fcaSMartin KaFai Lau } 328685d33df3SMartin KaFai Lau info.btf_vmlinux_value_type_id = map->btf_vmlinux_value_type_id; 328778958fcaSMartin KaFai Lau 328852775b33SJakub Kicinski if (bpf_map_is_dev_bound(map)) { 328952775b33SJakub Kicinski err = bpf_map_offload_info_fill(&info, map); 329052775b33SJakub Kicinski if (err) 329152775b33SJakub Kicinski return err; 329252775b33SJakub Kicinski } 329352775b33SJakub Kicinski 32941e270976SMartin KaFai Lau if (copy_to_user(uinfo, &info, info_len) || 32951e270976SMartin KaFai Lau put_user(info_len, &uattr->info.info_len)) 32961e270976SMartin KaFai Lau return -EFAULT; 32971e270976SMartin KaFai Lau 32981e270976SMartin KaFai Lau return 0; 32991e270976SMartin KaFai Lau } 33001e270976SMartin KaFai Lau 330162dab84cSMartin KaFai Lau static int bpf_btf_get_info_by_fd(struct btf *btf, 330262dab84cSMartin KaFai Lau const union bpf_attr *attr, 330362dab84cSMartin KaFai Lau union bpf_attr __user *uattr) 330462dab84cSMartin KaFai Lau { 330562dab84cSMartin KaFai Lau struct bpf_btf_info __user *uinfo = u64_to_user_ptr(attr->info.info); 330662dab84cSMartin KaFai Lau u32 info_len = attr->info.info_len; 330762dab84cSMartin KaFai Lau int err; 330862dab84cSMartin KaFai Lau 3309dcab51f1SMartin KaFai Lau err = bpf_check_uarg_tail_zero(uinfo, sizeof(*uinfo), info_len); 331062dab84cSMartin KaFai Lau if (err) 331162dab84cSMartin KaFai Lau return err; 331262dab84cSMartin KaFai Lau 331362dab84cSMartin KaFai Lau return btf_get_info_by_fd(btf, attr, uattr); 331462dab84cSMartin KaFai Lau } 331562dab84cSMartin KaFai Lau 33161e270976SMartin KaFai Lau #define BPF_OBJ_GET_INFO_BY_FD_LAST_FIELD info.info 33171e270976SMartin KaFai Lau 33181e270976SMartin KaFai Lau static int bpf_obj_get_info_by_fd(const union bpf_attr *attr, 33191e270976SMartin KaFai Lau union bpf_attr __user *uattr) 33201e270976SMartin KaFai Lau { 33211e270976SMartin KaFai Lau int ufd = attr->info.bpf_fd; 33221e270976SMartin KaFai Lau struct fd f; 33231e270976SMartin KaFai Lau int err; 33241e270976SMartin KaFai Lau 33251e270976SMartin KaFai Lau if (CHECK_ATTR(BPF_OBJ_GET_INFO_BY_FD)) 33261e270976SMartin KaFai Lau return -EINVAL; 33271e270976SMartin KaFai Lau 33281e270976SMartin KaFai Lau f = fdget(ufd); 33291e270976SMartin KaFai Lau if (!f.file) 33301e270976SMartin KaFai Lau return -EBADFD; 33311e270976SMartin KaFai Lau 33321e270976SMartin KaFai Lau if (f.file->f_op == &bpf_prog_fops) 33331e270976SMartin KaFai Lau err = bpf_prog_get_info_by_fd(f.file->private_data, attr, 33341e270976SMartin KaFai Lau uattr); 33351e270976SMartin KaFai Lau else if (f.file->f_op == &bpf_map_fops) 33361e270976SMartin KaFai Lau err = bpf_map_get_info_by_fd(f.file->private_data, attr, 33371e270976SMartin KaFai Lau uattr); 333860197cfbSMartin KaFai Lau else if (f.file->f_op == &btf_fops) 333962dab84cSMartin KaFai Lau err = bpf_btf_get_info_by_fd(f.file->private_data, attr, uattr); 33401e270976SMartin KaFai Lau else 33411e270976SMartin KaFai Lau err = -EINVAL; 33421e270976SMartin KaFai Lau 33431e270976SMartin KaFai Lau fdput(f); 33441e270976SMartin KaFai Lau return err; 33451e270976SMartin KaFai Lau } 33461e270976SMartin KaFai Lau 3347f56a653cSMartin KaFai Lau #define BPF_BTF_LOAD_LAST_FIELD btf_log_level 3348f56a653cSMartin KaFai Lau 3349f56a653cSMartin KaFai Lau static int bpf_btf_load(const union bpf_attr *attr) 3350f56a653cSMartin KaFai Lau { 3351f56a653cSMartin KaFai Lau if (CHECK_ATTR(BPF_BTF_LOAD)) 3352f56a653cSMartin KaFai Lau return -EINVAL; 3353f56a653cSMartin KaFai Lau 3354f56a653cSMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) 3355f56a653cSMartin KaFai Lau return -EPERM; 3356f56a653cSMartin KaFai Lau 3357f56a653cSMartin KaFai Lau return btf_new_fd(attr); 3358f56a653cSMartin KaFai Lau } 3359f56a653cSMartin KaFai Lau 336078958fcaSMartin KaFai Lau #define BPF_BTF_GET_FD_BY_ID_LAST_FIELD btf_id 336178958fcaSMartin KaFai Lau 336278958fcaSMartin KaFai Lau static int bpf_btf_get_fd_by_id(const union bpf_attr *attr) 336378958fcaSMartin KaFai Lau { 336478958fcaSMartin KaFai Lau if (CHECK_ATTR(BPF_BTF_GET_FD_BY_ID)) 336578958fcaSMartin KaFai Lau return -EINVAL; 336678958fcaSMartin KaFai Lau 336778958fcaSMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) 336878958fcaSMartin KaFai Lau return -EPERM; 336978958fcaSMartin KaFai Lau 337078958fcaSMartin KaFai Lau return btf_get_fd_by_id(attr->btf_id); 337178958fcaSMartin KaFai Lau } 337278958fcaSMartin KaFai Lau 337341bdc4b4SYonghong Song static int bpf_task_fd_query_copy(const union bpf_attr *attr, 337441bdc4b4SYonghong Song union bpf_attr __user *uattr, 337541bdc4b4SYonghong Song u32 prog_id, u32 fd_type, 337641bdc4b4SYonghong Song const char *buf, u64 probe_offset, 337741bdc4b4SYonghong Song u64 probe_addr) 337841bdc4b4SYonghong Song { 337941bdc4b4SYonghong Song char __user *ubuf = u64_to_user_ptr(attr->task_fd_query.buf); 338041bdc4b4SYonghong Song u32 len = buf ? strlen(buf) : 0, input_len; 338141bdc4b4SYonghong Song int err = 0; 338241bdc4b4SYonghong Song 338341bdc4b4SYonghong Song if (put_user(len, &uattr->task_fd_query.buf_len)) 338441bdc4b4SYonghong Song return -EFAULT; 338541bdc4b4SYonghong Song input_len = attr->task_fd_query.buf_len; 338641bdc4b4SYonghong Song if (input_len && ubuf) { 338741bdc4b4SYonghong Song if (!len) { 338841bdc4b4SYonghong Song /* nothing to copy, just make ubuf NULL terminated */ 338941bdc4b4SYonghong Song char zero = '\0'; 339041bdc4b4SYonghong Song 339141bdc4b4SYonghong Song if (put_user(zero, ubuf)) 339241bdc4b4SYonghong Song return -EFAULT; 339341bdc4b4SYonghong Song } else if (input_len >= len + 1) { 339441bdc4b4SYonghong Song /* ubuf can hold the string with NULL terminator */ 339541bdc4b4SYonghong Song if (copy_to_user(ubuf, buf, len + 1)) 339641bdc4b4SYonghong Song return -EFAULT; 339741bdc4b4SYonghong Song } else { 339841bdc4b4SYonghong Song /* ubuf cannot hold the string with NULL terminator, 339941bdc4b4SYonghong Song * do a partial copy with NULL terminator. 340041bdc4b4SYonghong Song */ 340141bdc4b4SYonghong Song char zero = '\0'; 340241bdc4b4SYonghong Song 340341bdc4b4SYonghong Song err = -ENOSPC; 340441bdc4b4SYonghong Song if (copy_to_user(ubuf, buf, input_len - 1)) 340541bdc4b4SYonghong Song return -EFAULT; 340641bdc4b4SYonghong Song if (put_user(zero, ubuf + input_len - 1)) 340741bdc4b4SYonghong Song return -EFAULT; 340841bdc4b4SYonghong Song } 340941bdc4b4SYonghong Song } 341041bdc4b4SYonghong Song 341141bdc4b4SYonghong Song if (put_user(prog_id, &uattr->task_fd_query.prog_id) || 341241bdc4b4SYonghong Song put_user(fd_type, &uattr->task_fd_query.fd_type) || 341341bdc4b4SYonghong Song put_user(probe_offset, &uattr->task_fd_query.probe_offset) || 341441bdc4b4SYonghong Song put_user(probe_addr, &uattr->task_fd_query.probe_addr)) 341541bdc4b4SYonghong Song return -EFAULT; 341641bdc4b4SYonghong Song 341741bdc4b4SYonghong Song return err; 341841bdc4b4SYonghong Song } 341941bdc4b4SYonghong Song 342041bdc4b4SYonghong Song #define BPF_TASK_FD_QUERY_LAST_FIELD task_fd_query.probe_addr 342141bdc4b4SYonghong Song 342241bdc4b4SYonghong Song static int bpf_task_fd_query(const union bpf_attr *attr, 342341bdc4b4SYonghong Song union bpf_attr __user *uattr) 342441bdc4b4SYonghong Song { 342541bdc4b4SYonghong Song pid_t pid = attr->task_fd_query.pid; 342641bdc4b4SYonghong Song u32 fd = attr->task_fd_query.fd; 342741bdc4b4SYonghong Song const struct perf_event *event; 342841bdc4b4SYonghong Song struct files_struct *files; 342941bdc4b4SYonghong Song struct task_struct *task; 343041bdc4b4SYonghong Song struct file *file; 343141bdc4b4SYonghong Song int err; 343241bdc4b4SYonghong Song 343341bdc4b4SYonghong Song if (CHECK_ATTR(BPF_TASK_FD_QUERY)) 343441bdc4b4SYonghong Song return -EINVAL; 343541bdc4b4SYonghong Song 343641bdc4b4SYonghong Song if (!capable(CAP_SYS_ADMIN)) 343741bdc4b4SYonghong Song return -EPERM; 343841bdc4b4SYonghong Song 343941bdc4b4SYonghong Song if (attr->task_fd_query.flags != 0) 344041bdc4b4SYonghong Song return -EINVAL; 344141bdc4b4SYonghong Song 344241bdc4b4SYonghong Song task = get_pid_task(find_vpid(pid), PIDTYPE_PID); 344341bdc4b4SYonghong Song if (!task) 344441bdc4b4SYonghong Song return -ENOENT; 344541bdc4b4SYonghong Song 344641bdc4b4SYonghong Song files = get_files_struct(task); 344741bdc4b4SYonghong Song put_task_struct(task); 344841bdc4b4SYonghong Song if (!files) 344941bdc4b4SYonghong Song return -ENOENT; 345041bdc4b4SYonghong Song 345141bdc4b4SYonghong Song err = 0; 345241bdc4b4SYonghong Song spin_lock(&files->file_lock); 345341bdc4b4SYonghong Song file = fcheck_files(files, fd); 345441bdc4b4SYonghong Song if (!file) 345541bdc4b4SYonghong Song err = -EBADF; 345641bdc4b4SYonghong Song else 345741bdc4b4SYonghong Song get_file(file); 345841bdc4b4SYonghong Song spin_unlock(&files->file_lock); 345941bdc4b4SYonghong Song put_files_struct(files); 346041bdc4b4SYonghong Song 346141bdc4b4SYonghong Song if (err) 346241bdc4b4SYonghong Song goto out; 346341bdc4b4SYonghong Song 346470ed506cSAndrii Nakryiko if (file->f_op == &bpf_link_fops) { 346570ed506cSAndrii Nakryiko struct bpf_link *link = file->private_data; 346670ed506cSAndrii Nakryiko 346770ed506cSAndrii Nakryiko if (link->ops == &bpf_raw_tp_lops) { 346870ed506cSAndrii Nakryiko struct bpf_raw_tp_link *raw_tp = 346970ed506cSAndrii Nakryiko container_of(link, struct bpf_raw_tp_link, link); 347041bdc4b4SYonghong Song struct bpf_raw_event_map *btp = raw_tp->btp; 347141bdc4b4SYonghong Song 347241bdc4b4SYonghong Song err = bpf_task_fd_query_copy(attr, uattr, 347370ed506cSAndrii Nakryiko raw_tp->link.prog->aux->id, 347441bdc4b4SYonghong Song BPF_FD_TYPE_RAW_TRACEPOINT, 347541bdc4b4SYonghong Song btp->tp->name, 0, 0); 347641bdc4b4SYonghong Song goto put_file; 347741bdc4b4SYonghong Song } 347870ed506cSAndrii Nakryiko goto out_not_supp; 347970ed506cSAndrii Nakryiko } 348041bdc4b4SYonghong Song 348141bdc4b4SYonghong Song event = perf_get_event(file); 348241bdc4b4SYonghong Song if (!IS_ERR(event)) { 348341bdc4b4SYonghong Song u64 probe_offset, probe_addr; 348441bdc4b4SYonghong Song u32 prog_id, fd_type; 348541bdc4b4SYonghong Song const char *buf; 348641bdc4b4SYonghong Song 348741bdc4b4SYonghong Song err = bpf_get_perf_event_info(event, &prog_id, &fd_type, 348841bdc4b4SYonghong Song &buf, &probe_offset, 348941bdc4b4SYonghong Song &probe_addr); 349041bdc4b4SYonghong Song if (!err) 349141bdc4b4SYonghong Song err = bpf_task_fd_query_copy(attr, uattr, prog_id, 349241bdc4b4SYonghong Song fd_type, buf, 349341bdc4b4SYonghong Song probe_offset, 349441bdc4b4SYonghong Song probe_addr); 349541bdc4b4SYonghong Song goto put_file; 349641bdc4b4SYonghong Song } 349741bdc4b4SYonghong Song 349870ed506cSAndrii Nakryiko out_not_supp: 349941bdc4b4SYonghong Song err = -ENOTSUPP; 350041bdc4b4SYonghong Song put_file: 350141bdc4b4SYonghong Song fput(file); 350241bdc4b4SYonghong Song out: 350341bdc4b4SYonghong Song return err; 350441bdc4b4SYonghong Song } 350541bdc4b4SYonghong Song 3506cb4d03abSBrian Vazquez #define BPF_MAP_BATCH_LAST_FIELD batch.flags 3507cb4d03abSBrian Vazquez 3508cb4d03abSBrian Vazquez #define BPF_DO_BATCH(fn) \ 3509cb4d03abSBrian Vazquez do { \ 3510cb4d03abSBrian Vazquez if (!fn) { \ 3511cb4d03abSBrian Vazquez err = -ENOTSUPP; \ 3512cb4d03abSBrian Vazquez goto err_put; \ 3513cb4d03abSBrian Vazquez } \ 3514cb4d03abSBrian Vazquez err = fn(map, attr, uattr); \ 3515cb4d03abSBrian Vazquez } while (0) 3516cb4d03abSBrian Vazquez 3517cb4d03abSBrian Vazquez static int bpf_map_do_batch(const union bpf_attr *attr, 3518cb4d03abSBrian Vazquez union bpf_attr __user *uattr, 3519cb4d03abSBrian Vazquez int cmd) 3520cb4d03abSBrian Vazquez { 3521cb4d03abSBrian Vazquez struct bpf_map *map; 3522cb4d03abSBrian Vazquez int err, ufd; 3523cb4d03abSBrian Vazquez struct fd f; 3524cb4d03abSBrian Vazquez 3525cb4d03abSBrian Vazquez if (CHECK_ATTR(BPF_MAP_BATCH)) 3526cb4d03abSBrian Vazquez return -EINVAL; 3527cb4d03abSBrian Vazquez 3528cb4d03abSBrian Vazquez ufd = attr->batch.map_fd; 3529cb4d03abSBrian Vazquez f = fdget(ufd); 3530cb4d03abSBrian Vazquez map = __bpf_map_get(f); 3531cb4d03abSBrian Vazquez if (IS_ERR(map)) 3532cb4d03abSBrian Vazquez return PTR_ERR(map); 3533cb4d03abSBrian Vazquez 353405799638SYonghong Song if ((cmd == BPF_MAP_LOOKUP_BATCH || 353505799638SYonghong Song cmd == BPF_MAP_LOOKUP_AND_DELETE_BATCH) && 3536cb4d03abSBrian Vazquez !(map_get_sys_perms(map, f) & FMODE_CAN_READ)) { 3537cb4d03abSBrian Vazquez err = -EPERM; 3538cb4d03abSBrian Vazquez goto err_put; 3539cb4d03abSBrian Vazquez } 3540cb4d03abSBrian Vazquez 3541cb4d03abSBrian Vazquez if (cmd != BPF_MAP_LOOKUP_BATCH && 3542cb4d03abSBrian Vazquez !(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) { 3543cb4d03abSBrian Vazquez err = -EPERM; 3544cb4d03abSBrian Vazquez goto err_put; 3545cb4d03abSBrian Vazquez } 3546cb4d03abSBrian Vazquez 3547cb4d03abSBrian Vazquez if (cmd == BPF_MAP_LOOKUP_BATCH) 3548cb4d03abSBrian Vazquez BPF_DO_BATCH(map->ops->map_lookup_batch); 354905799638SYonghong Song else if (cmd == BPF_MAP_LOOKUP_AND_DELETE_BATCH) 355005799638SYonghong Song BPF_DO_BATCH(map->ops->map_lookup_and_delete_batch); 3551aa2e93b8SBrian Vazquez else if (cmd == BPF_MAP_UPDATE_BATCH) 3552aa2e93b8SBrian Vazquez BPF_DO_BATCH(map->ops->map_update_batch); 3553aa2e93b8SBrian Vazquez else 3554aa2e93b8SBrian Vazquez BPF_DO_BATCH(map->ops->map_delete_batch); 3555cb4d03abSBrian Vazquez 3556cb4d03abSBrian Vazquez err_put: 3557cb4d03abSBrian Vazquez fdput(f); 3558cb4d03abSBrian Vazquez return err; 3559cb4d03abSBrian Vazquez } 3560cb4d03abSBrian Vazquez 3561af6eea57SAndrii Nakryiko #define BPF_LINK_CREATE_LAST_FIELD link_create.flags 3562af6eea57SAndrii Nakryiko static int link_create(union bpf_attr *attr) 3563af6eea57SAndrii Nakryiko { 3564af6eea57SAndrii Nakryiko enum bpf_prog_type ptype; 3565af6eea57SAndrii Nakryiko struct bpf_prog *prog; 3566af6eea57SAndrii Nakryiko int ret; 3567af6eea57SAndrii Nakryiko 3568af6eea57SAndrii Nakryiko if (!capable(CAP_NET_ADMIN)) 3569af6eea57SAndrii Nakryiko return -EPERM; 3570af6eea57SAndrii Nakryiko 3571af6eea57SAndrii Nakryiko if (CHECK_ATTR(BPF_LINK_CREATE)) 3572af6eea57SAndrii Nakryiko return -EINVAL; 3573af6eea57SAndrii Nakryiko 3574af6eea57SAndrii Nakryiko ptype = attach_type_to_prog_type(attr->link_create.attach_type); 3575af6eea57SAndrii Nakryiko if (ptype == BPF_PROG_TYPE_UNSPEC) 3576af6eea57SAndrii Nakryiko return -EINVAL; 3577af6eea57SAndrii Nakryiko 3578af6eea57SAndrii Nakryiko prog = bpf_prog_get_type(attr->link_create.prog_fd, ptype); 3579af6eea57SAndrii Nakryiko if (IS_ERR(prog)) 3580af6eea57SAndrii Nakryiko return PTR_ERR(prog); 3581af6eea57SAndrii Nakryiko 3582af6eea57SAndrii Nakryiko ret = bpf_prog_attach_check_attach_type(prog, 3583af6eea57SAndrii Nakryiko attr->link_create.attach_type); 3584af6eea57SAndrii Nakryiko if (ret) 3585af6eea57SAndrii Nakryiko goto err_out; 3586af6eea57SAndrii Nakryiko 3587af6eea57SAndrii Nakryiko switch (ptype) { 3588af6eea57SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SKB: 3589af6eea57SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SOCK: 3590af6eea57SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: 3591af6eea57SAndrii Nakryiko case BPF_PROG_TYPE_SOCK_OPS: 3592af6eea57SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_DEVICE: 3593af6eea57SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SYSCTL: 3594af6eea57SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SOCKOPT: 3595af6eea57SAndrii Nakryiko ret = cgroup_bpf_link_attach(attr, prog); 3596af6eea57SAndrii Nakryiko break; 3597af6eea57SAndrii Nakryiko default: 3598af6eea57SAndrii Nakryiko ret = -EINVAL; 3599af6eea57SAndrii Nakryiko } 3600af6eea57SAndrii Nakryiko 3601af6eea57SAndrii Nakryiko err_out: 3602af6eea57SAndrii Nakryiko if (ret < 0) 3603af6eea57SAndrii Nakryiko bpf_prog_put(prog); 3604af6eea57SAndrii Nakryiko return ret; 3605af6eea57SAndrii Nakryiko } 3606af6eea57SAndrii Nakryiko 36070c991ebcSAndrii Nakryiko #define BPF_LINK_UPDATE_LAST_FIELD link_update.old_prog_fd 36080c991ebcSAndrii Nakryiko 36090c991ebcSAndrii Nakryiko static int link_update(union bpf_attr *attr) 36100c991ebcSAndrii Nakryiko { 36110c991ebcSAndrii Nakryiko struct bpf_prog *old_prog = NULL, *new_prog; 36120c991ebcSAndrii Nakryiko struct bpf_link *link; 36130c991ebcSAndrii Nakryiko u32 flags; 36140c991ebcSAndrii Nakryiko int ret; 36150c991ebcSAndrii Nakryiko 36160c991ebcSAndrii Nakryiko if (!capable(CAP_NET_ADMIN)) 36170c991ebcSAndrii Nakryiko return -EPERM; 36180c991ebcSAndrii Nakryiko 36190c991ebcSAndrii Nakryiko if (CHECK_ATTR(BPF_LINK_UPDATE)) 36200c991ebcSAndrii Nakryiko return -EINVAL; 36210c991ebcSAndrii Nakryiko 36220c991ebcSAndrii Nakryiko flags = attr->link_update.flags; 36230c991ebcSAndrii Nakryiko if (flags & ~BPF_F_REPLACE) 36240c991ebcSAndrii Nakryiko return -EINVAL; 36250c991ebcSAndrii Nakryiko 36260c991ebcSAndrii Nakryiko link = bpf_link_get_from_fd(attr->link_update.link_fd); 36270c991ebcSAndrii Nakryiko if (IS_ERR(link)) 36280c991ebcSAndrii Nakryiko return PTR_ERR(link); 36290c991ebcSAndrii Nakryiko 36300c991ebcSAndrii Nakryiko new_prog = bpf_prog_get(attr->link_update.new_prog_fd); 36314adb7a4aSAndrii Nakryiko if (IS_ERR(new_prog)) { 36324adb7a4aSAndrii Nakryiko ret = PTR_ERR(new_prog); 36334adb7a4aSAndrii Nakryiko goto out_put_link; 36344adb7a4aSAndrii Nakryiko } 36350c991ebcSAndrii Nakryiko 36360c991ebcSAndrii Nakryiko if (flags & BPF_F_REPLACE) { 36370c991ebcSAndrii Nakryiko old_prog = bpf_prog_get(attr->link_update.old_prog_fd); 36380c991ebcSAndrii Nakryiko if (IS_ERR(old_prog)) { 36390c991ebcSAndrii Nakryiko ret = PTR_ERR(old_prog); 36400c991ebcSAndrii Nakryiko old_prog = NULL; 36410c991ebcSAndrii Nakryiko goto out_put_progs; 36420c991ebcSAndrii Nakryiko } 36434adb7a4aSAndrii Nakryiko } else if (attr->link_update.old_prog_fd) { 36444adb7a4aSAndrii Nakryiko ret = -EINVAL; 36454adb7a4aSAndrii Nakryiko goto out_put_progs; 36460c991ebcSAndrii Nakryiko } 36470c991ebcSAndrii Nakryiko 36480c991ebcSAndrii Nakryiko #ifdef CONFIG_CGROUP_BPF 36490c991ebcSAndrii Nakryiko if (link->ops == &bpf_cgroup_link_lops) { 36500c991ebcSAndrii Nakryiko ret = cgroup_bpf_replace(link, old_prog, new_prog); 36510c991ebcSAndrii Nakryiko goto out_put_progs; 36520c991ebcSAndrii Nakryiko } 36530c991ebcSAndrii Nakryiko #endif 36540c991ebcSAndrii Nakryiko ret = -EINVAL; 36550c991ebcSAndrii Nakryiko 36560c991ebcSAndrii Nakryiko out_put_progs: 36570c991ebcSAndrii Nakryiko if (old_prog) 36580c991ebcSAndrii Nakryiko bpf_prog_put(old_prog); 36590c991ebcSAndrii Nakryiko if (ret) 36600c991ebcSAndrii Nakryiko bpf_prog_put(new_prog); 36614adb7a4aSAndrii Nakryiko out_put_link: 36624adb7a4aSAndrii Nakryiko bpf_link_put(link); 36630c991ebcSAndrii Nakryiko return ret; 36640c991ebcSAndrii Nakryiko } 36650c991ebcSAndrii Nakryiko 366699c55f7dSAlexei Starovoitov SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size) 366799c55f7dSAlexei Starovoitov { 36688096f229SGreg Kroah-Hartman union bpf_attr attr; 366999c55f7dSAlexei Starovoitov int err; 367099c55f7dSAlexei Starovoitov 36710fa4fe85SChenbo Feng if (sysctl_unprivileged_bpf_disabled && !capable(CAP_SYS_ADMIN)) 367299c55f7dSAlexei Starovoitov return -EPERM; 367399c55f7dSAlexei Starovoitov 3674dcab51f1SMartin KaFai Lau err = bpf_check_uarg_tail_zero(uattr, sizeof(attr), size); 367599c55f7dSAlexei Starovoitov if (err) 367699c55f7dSAlexei Starovoitov return err; 36771e270976SMartin KaFai Lau size = min_t(u32, size, sizeof(attr)); 367899c55f7dSAlexei Starovoitov 367999c55f7dSAlexei Starovoitov /* copy attributes from user space, may be less than sizeof(bpf_attr) */ 36808096f229SGreg Kroah-Hartman memset(&attr, 0, sizeof(attr)); 368199c55f7dSAlexei Starovoitov if (copy_from_user(&attr, uattr, size) != 0) 368299c55f7dSAlexei Starovoitov return -EFAULT; 368399c55f7dSAlexei Starovoitov 3684afdb09c7SChenbo Feng err = security_bpf(cmd, &attr, size); 3685afdb09c7SChenbo Feng if (err < 0) 3686afdb09c7SChenbo Feng return err; 3687afdb09c7SChenbo Feng 368899c55f7dSAlexei Starovoitov switch (cmd) { 368999c55f7dSAlexei Starovoitov case BPF_MAP_CREATE: 369099c55f7dSAlexei Starovoitov err = map_create(&attr); 369199c55f7dSAlexei Starovoitov break; 3692db20fd2bSAlexei Starovoitov case BPF_MAP_LOOKUP_ELEM: 3693db20fd2bSAlexei Starovoitov err = map_lookup_elem(&attr); 3694db20fd2bSAlexei Starovoitov break; 3695db20fd2bSAlexei Starovoitov case BPF_MAP_UPDATE_ELEM: 3696db20fd2bSAlexei Starovoitov err = map_update_elem(&attr); 3697db20fd2bSAlexei Starovoitov break; 3698db20fd2bSAlexei Starovoitov case BPF_MAP_DELETE_ELEM: 3699db20fd2bSAlexei Starovoitov err = map_delete_elem(&attr); 3700db20fd2bSAlexei Starovoitov break; 3701db20fd2bSAlexei Starovoitov case BPF_MAP_GET_NEXT_KEY: 3702db20fd2bSAlexei Starovoitov err = map_get_next_key(&attr); 3703db20fd2bSAlexei Starovoitov break; 370487df15deSDaniel Borkmann case BPF_MAP_FREEZE: 370587df15deSDaniel Borkmann err = map_freeze(&attr); 370687df15deSDaniel Borkmann break; 370709756af4SAlexei Starovoitov case BPF_PROG_LOAD: 3708838e9690SYonghong Song err = bpf_prog_load(&attr, uattr); 370909756af4SAlexei Starovoitov break; 3710b2197755SDaniel Borkmann case BPF_OBJ_PIN: 3711b2197755SDaniel Borkmann err = bpf_obj_pin(&attr); 3712b2197755SDaniel Borkmann break; 3713b2197755SDaniel Borkmann case BPF_OBJ_GET: 3714b2197755SDaniel Borkmann err = bpf_obj_get(&attr); 3715b2197755SDaniel Borkmann break; 3716f4324551SDaniel Mack case BPF_PROG_ATTACH: 3717f4324551SDaniel Mack err = bpf_prog_attach(&attr); 3718f4324551SDaniel Mack break; 3719f4324551SDaniel Mack case BPF_PROG_DETACH: 3720f4324551SDaniel Mack err = bpf_prog_detach(&attr); 3721f4324551SDaniel Mack break; 3722468e2f64SAlexei Starovoitov case BPF_PROG_QUERY: 3723468e2f64SAlexei Starovoitov err = bpf_prog_query(&attr, uattr); 3724468e2f64SAlexei Starovoitov break; 37251cf1cae9SAlexei Starovoitov case BPF_PROG_TEST_RUN: 37261cf1cae9SAlexei Starovoitov err = bpf_prog_test_run(&attr, uattr); 37271cf1cae9SAlexei Starovoitov break; 372834ad5580SMartin KaFai Lau case BPF_PROG_GET_NEXT_ID: 372934ad5580SMartin KaFai Lau err = bpf_obj_get_next_id(&attr, uattr, 373034ad5580SMartin KaFai Lau &prog_idr, &prog_idr_lock); 373134ad5580SMartin KaFai Lau break; 373234ad5580SMartin KaFai Lau case BPF_MAP_GET_NEXT_ID: 373334ad5580SMartin KaFai Lau err = bpf_obj_get_next_id(&attr, uattr, 373434ad5580SMartin KaFai Lau &map_idr, &map_idr_lock); 373534ad5580SMartin KaFai Lau break; 37361b9ed84eSQuentin Monnet case BPF_BTF_GET_NEXT_ID: 37371b9ed84eSQuentin Monnet err = bpf_obj_get_next_id(&attr, uattr, 37381b9ed84eSQuentin Monnet &btf_idr, &btf_idr_lock); 37391b9ed84eSQuentin Monnet break; 3740b16d9aa4SMartin KaFai Lau case BPF_PROG_GET_FD_BY_ID: 3741b16d9aa4SMartin KaFai Lau err = bpf_prog_get_fd_by_id(&attr); 3742b16d9aa4SMartin KaFai Lau break; 3743bd5f5f4eSMartin KaFai Lau case BPF_MAP_GET_FD_BY_ID: 3744bd5f5f4eSMartin KaFai Lau err = bpf_map_get_fd_by_id(&attr); 3745bd5f5f4eSMartin KaFai Lau break; 37461e270976SMartin KaFai Lau case BPF_OBJ_GET_INFO_BY_FD: 37471e270976SMartin KaFai Lau err = bpf_obj_get_info_by_fd(&attr, uattr); 37481e270976SMartin KaFai Lau break; 3749c4f6699dSAlexei Starovoitov case BPF_RAW_TRACEPOINT_OPEN: 3750c4f6699dSAlexei Starovoitov err = bpf_raw_tracepoint_open(&attr); 3751c4f6699dSAlexei Starovoitov break; 3752f56a653cSMartin KaFai Lau case BPF_BTF_LOAD: 3753f56a653cSMartin KaFai Lau err = bpf_btf_load(&attr); 3754f56a653cSMartin KaFai Lau break; 375578958fcaSMartin KaFai Lau case BPF_BTF_GET_FD_BY_ID: 375678958fcaSMartin KaFai Lau err = bpf_btf_get_fd_by_id(&attr); 375778958fcaSMartin KaFai Lau break; 375841bdc4b4SYonghong Song case BPF_TASK_FD_QUERY: 375941bdc4b4SYonghong Song err = bpf_task_fd_query(&attr, uattr); 376041bdc4b4SYonghong Song break; 3761bd513cd0SMauricio Vasquez B case BPF_MAP_LOOKUP_AND_DELETE_ELEM: 3762bd513cd0SMauricio Vasquez B err = map_lookup_and_delete_elem(&attr); 3763bd513cd0SMauricio Vasquez B break; 3764cb4d03abSBrian Vazquez case BPF_MAP_LOOKUP_BATCH: 3765cb4d03abSBrian Vazquez err = bpf_map_do_batch(&attr, uattr, BPF_MAP_LOOKUP_BATCH); 3766cb4d03abSBrian Vazquez break; 376705799638SYonghong Song case BPF_MAP_LOOKUP_AND_DELETE_BATCH: 376805799638SYonghong Song err = bpf_map_do_batch(&attr, uattr, 376905799638SYonghong Song BPF_MAP_LOOKUP_AND_DELETE_BATCH); 377005799638SYonghong Song break; 3771aa2e93b8SBrian Vazquez case BPF_MAP_UPDATE_BATCH: 3772aa2e93b8SBrian Vazquez err = bpf_map_do_batch(&attr, uattr, BPF_MAP_UPDATE_BATCH); 3773aa2e93b8SBrian Vazquez break; 3774aa2e93b8SBrian Vazquez case BPF_MAP_DELETE_BATCH: 3775aa2e93b8SBrian Vazquez err = bpf_map_do_batch(&attr, uattr, BPF_MAP_DELETE_BATCH); 3776aa2e93b8SBrian Vazquez break; 3777af6eea57SAndrii Nakryiko case BPF_LINK_CREATE: 3778af6eea57SAndrii Nakryiko err = link_create(&attr); 3779af6eea57SAndrii Nakryiko break; 37800c991ebcSAndrii Nakryiko case BPF_LINK_UPDATE: 37810c991ebcSAndrii Nakryiko err = link_update(&attr); 37820c991ebcSAndrii Nakryiko break; 378399c55f7dSAlexei Starovoitov default: 378499c55f7dSAlexei Starovoitov err = -EINVAL; 378599c55f7dSAlexei Starovoitov break; 378699c55f7dSAlexei Starovoitov } 378799c55f7dSAlexei Starovoitov 378899c55f7dSAlexei Starovoitov return err; 378999c55f7dSAlexei Starovoitov } 3790