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> 5aef2fedaSJakub Kicinski #include <linux/bpf-cgroup.h> 6a67edbf4SDaniel Borkmann #include <linux/bpf_trace.h> 7f4364dcfSSean Young #include <linux/bpf_lirc.h> 84a1e7c0cSToke Høiland-Jørgensen #include <linux/bpf_verifier.h> 961df10c7SKumar Kartikeya Dwivedi #include <linux/bsearch.h> 10f56a653cSMartin KaFai Lau #include <linux/btf.h> 1199c55f7dSAlexei Starovoitov #include <linux/syscalls.h> 1299c55f7dSAlexei Starovoitov #include <linux/slab.h> 133f07c014SIngo Molnar #include <linux/sched/signal.h> 14d407bd25SDaniel Borkmann #include <linux/vmalloc.h> 15d407bd25SDaniel Borkmann #include <linux/mmzone.h> 1699c55f7dSAlexei Starovoitov #include <linux/anon_inodes.h> 1741bdc4b4SYonghong Song #include <linux/fdtable.h> 18db20fd2bSAlexei Starovoitov #include <linux/file.h> 1941bdc4b4SYonghong Song #include <linux/fs.h> 2009756af4SAlexei Starovoitov #include <linux/license.h> 2109756af4SAlexei Starovoitov #include <linux/filter.h> 22535e7b4bSMickaël Salaün #include <linux/kernel.h> 23dc4bb0e2SMartin KaFai Lau #include <linux/idr.h> 24cb4d2b3fSMartin KaFai Lau #include <linux/cred.h> 25cb4d2b3fSMartin KaFai Lau #include <linux/timekeeping.h> 26cb4d2b3fSMartin KaFai Lau #include <linux/ctype.h> 279ef09e35SMark Rutland #include <linux/nospec.h> 28bae141f5SDaniel Borkmann #include <linux/audit.h> 29ccfe29ebSAlexei Starovoitov #include <uapi/linux/btf.h> 30ca5999fdSMike Rapoport #include <linux/pgtable.h> 319e4e01dfSKP Singh #include <linux/bpf_lsm.h> 32457f4436SAndrii Nakryiko #include <linux/poll.h> 334d7d7f69SKumar Kartikeya Dwivedi #include <linux/sort.h> 34a3fd7ceeSJakub Sitnicki #include <linux/bpf-netns.h> 351e6c62a8SAlexei Starovoitov #include <linux/rcupdate_trace.h> 3648edc1f7SRoman Gushchin #include <linux/memcontrol.h> 370dcac272SJiri Olsa #include <linux/trace_events.h> 3899c55f7dSAlexei Starovoitov 3935dfaad7SDaniel Borkmann #include <net/netfilter/nf_bpf_link.h> 4035dfaad7SDaniel Borkmann #include <net/netkit.h> 41e420bed0SDaniel Borkmann #include <net/tcx.h> 42e420bed0SDaniel Borkmann 43da765a2fSDaniel Borkmann #define IS_FD_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || \ 4414dc6f04SMartin KaFai Lau (map)->map_type == BPF_MAP_TYPE_CGROUP_ARRAY || \ 4514dc6f04SMartin KaFai Lau (map)->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS) 46da765a2fSDaniel Borkmann #define IS_FD_PROG_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PROG_ARRAY) 4714dc6f04SMartin KaFai Lau #define IS_FD_HASH(map) ((map)->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) 48da765a2fSDaniel Borkmann #define IS_FD_MAP(map) (IS_FD_ARRAY(map) || IS_FD_PROG_ARRAY(map) || \ 49da765a2fSDaniel Borkmann IS_FD_HASH(map)) 5014dc6f04SMartin KaFai Lau 516e71b04aSChenbo Feng #define BPF_OBJ_FLAG_MASK (BPF_F_RDONLY | BPF_F_WRONLY) 526e71b04aSChenbo Feng 53b121d1e7SAlexei Starovoitov DEFINE_PER_CPU(int, bpf_prog_active); 54dc4bb0e2SMartin KaFai Lau static DEFINE_IDR(prog_idr); 55dc4bb0e2SMartin KaFai Lau static DEFINE_SPINLOCK(prog_idr_lock); 56f3f1c054SMartin KaFai Lau static DEFINE_IDR(map_idr); 57f3f1c054SMartin KaFai Lau static DEFINE_SPINLOCK(map_idr_lock); 58a3b80e10SAndrii Nakryiko static DEFINE_IDR(link_idr); 59a3b80e10SAndrii Nakryiko static DEFINE_SPINLOCK(link_idr_lock); 60b121d1e7SAlexei Starovoitov 6108389d88SDaniel Borkmann int sysctl_unprivileged_bpf_disabled __read_mostly = 6208389d88SDaniel Borkmann IS_BUILTIN(CONFIG_BPF_UNPRIV_DEFAULT_OFF) ? 2 : 0; 631be7f75dSAlexei Starovoitov 6440077e0cSJohannes Berg static const struct bpf_map_ops * const bpf_map_types[] = { 6591cc1a99SAlexei Starovoitov #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) 6640077e0cSJohannes Berg #define BPF_MAP_TYPE(_id, _ops) \ 6740077e0cSJohannes Berg [_id] = &_ops, 68f2e10bffSAndrii Nakryiko #define BPF_LINK_TYPE(_id, _name) 6940077e0cSJohannes Berg #include <linux/bpf_types.h> 7040077e0cSJohannes Berg #undef BPF_PROG_TYPE 7140077e0cSJohannes Berg #undef BPF_MAP_TYPE 72f2e10bffSAndrii Nakryiko #undef BPF_LINK_TYPE 7340077e0cSJohannes Berg }; 7499c55f7dSAlexei Starovoitov 75752ba56fSMickaël Salaün /* 76752ba56fSMickaël Salaün * If we're handed a bigger struct than we know of, ensure all the unknown bits 77752ba56fSMickaël Salaün * are 0 - i.e. new user-space does not rely on any kernel feature extensions 78752ba56fSMickaël Salaün * we don't know about yet. 79752ba56fSMickaël Salaün * 80752ba56fSMickaël Salaün * There is a ToCToU between this function call and the following 81752ba56fSMickaël Salaün * copy_from_user() call. However, this is not a concern since this function is 82752ba56fSMickaël Salaün * meant to be a future-proofing of bits. 83752ba56fSMickaël Salaün */ 84af2ac3e1SAlexei Starovoitov int bpf_check_uarg_tail_zero(bpfptr_t uaddr, 8558291a74SMickaël Salaün size_t expected_size, 8658291a74SMickaël Salaün size_t actual_size) 8758291a74SMickaël Salaün { 88b7e4b65fSAl Viro int res; 8958291a74SMickaël Salaün 90752ba56fSMickaël Salaün if (unlikely(actual_size > PAGE_SIZE)) /* silly large */ 91752ba56fSMickaël Salaün return -E2BIG; 92752ba56fSMickaël Salaün 9358291a74SMickaël Salaün if (actual_size <= expected_size) 9458291a74SMickaël Salaün return 0; 9558291a74SMickaël Salaün 96af2ac3e1SAlexei Starovoitov if (uaddr.is_kernel) 97af2ac3e1SAlexei Starovoitov res = memchr_inv(uaddr.kernel + expected_size, 0, 98af2ac3e1SAlexei Starovoitov actual_size - expected_size) == NULL; 99af2ac3e1SAlexei Starovoitov else 100af2ac3e1SAlexei Starovoitov res = check_zeroed_user(uaddr.user + expected_size, 101af2ac3e1SAlexei Starovoitov actual_size - expected_size); 102b7e4b65fSAl Viro if (res < 0) 103b7e4b65fSAl Viro return res; 104b7e4b65fSAl Viro return res ? 0 : -E2BIG; 10558291a74SMickaël Salaün } 10658291a74SMickaël Salaün 107a3884572SJakub Kicinski const struct bpf_map_ops bpf_map_offload_ops = { 108f4d05259SMartin KaFai Lau .map_meta_equal = bpf_map_meta_equal, 109a3884572SJakub Kicinski .map_alloc = bpf_map_offload_map_alloc, 110a3884572SJakub Kicinski .map_free = bpf_map_offload_map_free, 111e8d2bec0SDaniel Borkmann .map_check_btf = map_check_no_btf, 1129629363cSYafang Shao .map_mem_usage = bpf_map_offload_map_mem_usage, 113a3884572SJakub Kicinski }; 114a3884572SJakub Kicinski 115353050beSDaniel Borkmann static void bpf_map_write_active_inc(struct bpf_map *map) 116353050beSDaniel Borkmann { 117353050beSDaniel Borkmann atomic64_inc(&map->writecnt); 118353050beSDaniel Borkmann } 119353050beSDaniel Borkmann 120353050beSDaniel Borkmann static void bpf_map_write_active_dec(struct bpf_map *map) 121353050beSDaniel Borkmann { 122353050beSDaniel Borkmann atomic64_dec(&map->writecnt); 123353050beSDaniel Borkmann } 124353050beSDaniel Borkmann 125353050beSDaniel Borkmann bool bpf_map_write_active(const struct bpf_map *map) 126353050beSDaniel Borkmann { 127353050beSDaniel Borkmann return atomic64_read(&map->writecnt) != 0; 128353050beSDaniel Borkmann } 129353050beSDaniel Borkmann 13080ee81e0SRoman Gushchin static u32 bpf_map_value_size(const struct bpf_map *map) 13115c14a3dSBrian Vazquez { 13215c14a3dSBrian Vazquez if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 13315c14a3dSBrian Vazquez map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH || 13415c14a3dSBrian Vazquez map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY || 13515c14a3dSBrian Vazquez map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) 13615c14a3dSBrian Vazquez return round_up(map->value_size, 8) * num_possible_cpus(); 13715c14a3dSBrian Vazquez else if (IS_FD_MAP(map)) 13815c14a3dSBrian Vazquez return sizeof(u32); 13915c14a3dSBrian Vazquez else 14015c14a3dSBrian Vazquez return map->value_size; 14115c14a3dSBrian Vazquez } 14215c14a3dSBrian Vazquez 14315c14a3dSBrian Vazquez static void maybe_wait_bpf_programs(struct bpf_map *map) 14415c14a3dSBrian Vazquez { 1452a0c6b41SHou Tao /* Wait for any running non-sleepable BPF programs to complete so that 1462a0c6b41SHou Tao * userspace, when we return to it, knows that all non-sleepable 1472a0c6b41SHou Tao * programs that could be running use the new map value. For sleepable 1482a0c6b41SHou Tao * BPF programs, synchronize_rcu_tasks_trace() should be used to wait 1492a0c6b41SHou Tao * for the completions of these programs, but considering the waiting 1502a0c6b41SHou Tao * time can be very long and userspace may think it will hang forever, 1512a0c6b41SHou Tao * so don't handle sleepable BPF programs now. 15215c14a3dSBrian Vazquez */ 15315c14a3dSBrian Vazquez if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS || 15415c14a3dSBrian Vazquez map->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS) 15515c14a3dSBrian Vazquez synchronize_rcu(); 15615c14a3dSBrian Vazquez } 15715c14a3dSBrian Vazquez 1583af43ba4SHou Tao static int bpf_map_update_value(struct bpf_map *map, struct file *map_file, 1593af43ba4SHou Tao void *key, void *value, __u64 flags) 16015c14a3dSBrian Vazquez { 16115c14a3dSBrian Vazquez int err; 16215c14a3dSBrian Vazquez 16315c14a3dSBrian Vazquez /* Need to create a kthread, thus must support schedule */ 1649d03ebc7SStanislav Fomichev if (bpf_map_is_offloaded(map)) { 16515c14a3dSBrian Vazquez return bpf_map_offload_update_elem(map, key, value, flags); 16615c14a3dSBrian Vazquez } else if (map->map_type == BPF_MAP_TYPE_CPUMAP || 16715c14a3dSBrian Vazquez map->map_type == BPF_MAP_TYPE_STRUCT_OPS) { 16815c14a3dSBrian Vazquez return map->ops->map_update_elem(map, key, value, flags); 16913b79d3fSLorenz Bauer } else if (map->map_type == BPF_MAP_TYPE_SOCKHASH || 17013b79d3fSLorenz Bauer map->map_type == BPF_MAP_TYPE_SOCKMAP) { 17113b79d3fSLorenz Bauer return sock_map_update_elem_sys(map, key, value, flags); 17215c14a3dSBrian Vazquez } else if (IS_FD_PROG_ARRAY(map)) { 1733af43ba4SHou Tao return bpf_fd_array_map_update_elem(map, map_file, key, value, 17415c14a3dSBrian Vazquez flags); 17515c14a3dSBrian Vazquez } 17615c14a3dSBrian Vazquez 177b6e5dae1SThomas Gleixner bpf_disable_instrumentation(); 17815c14a3dSBrian Vazquez if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 17915c14a3dSBrian Vazquez map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) { 18015c14a3dSBrian Vazquez err = bpf_percpu_hash_update(map, key, value, flags); 18115c14a3dSBrian Vazquez } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) { 18215c14a3dSBrian Vazquez err = bpf_percpu_array_update(map, key, value, flags); 18315c14a3dSBrian Vazquez } else if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) { 18415c14a3dSBrian Vazquez err = bpf_percpu_cgroup_storage_update(map, key, value, 18515c14a3dSBrian Vazquez flags); 18615c14a3dSBrian Vazquez } else if (IS_FD_ARRAY(map)) { 1873af43ba4SHou Tao err = bpf_fd_array_map_update_elem(map, map_file, key, value, 18815c14a3dSBrian Vazquez flags); 18915c14a3dSBrian Vazquez } else if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) { 1903af43ba4SHou Tao err = bpf_fd_htab_map_update_elem(map, map_file, key, value, 19115c14a3dSBrian Vazquez flags); 19215c14a3dSBrian Vazquez } else if (map->map_type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY) { 19315c14a3dSBrian Vazquez /* rcu_read_lock() is not needed */ 19415c14a3dSBrian Vazquez err = bpf_fd_reuseport_array_update_elem(map, key, value, 19515c14a3dSBrian Vazquez flags); 19615c14a3dSBrian Vazquez } else if (map->map_type == BPF_MAP_TYPE_QUEUE || 1979330986cSJoanne Koong map->map_type == BPF_MAP_TYPE_STACK || 1989330986cSJoanne Koong map->map_type == BPF_MAP_TYPE_BLOOM_FILTER) { 19915c14a3dSBrian Vazquez err = map->ops->map_push_elem(map, value, flags); 20015c14a3dSBrian Vazquez } else { 20115c14a3dSBrian Vazquez rcu_read_lock(); 20215c14a3dSBrian Vazquez err = map->ops->map_update_elem(map, key, value, flags); 20315c14a3dSBrian Vazquez rcu_read_unlock(); 20415c14a3dSBrian Vazquez } 205b6e5dae1SThomas Gleixner bpf_enable_instrumentation(); 20615c14a3dSBrian Vazquez 20715c14a3dSBrian Vazquez return err; 20815c14a3dSBrian Vazquez } 20915c14a3dSBrian Vazquez 21015c14a3dSBrian Vazquez static int bpf_map_copy_value(struct bpf_map *map, void *key, void *value, 21115c14a3dSBrian Vazquez __u64 flags) 21215c14a3dSBrian Vazquez { 21315c14a3dSBrian Vazquez void *ptr; 21415c14a3dSBrian Vazquez int err; 21515c14a3dSBrian Vazquez 2169d03ebc7SStanislav Fomichev if (bpf_map_is_offloaded(map)) 217cb4d03abSBrian Vazquez return bpf_map_offload_lookup_elem(map, key, value); 21815c14a3dSBrian Vazquez 219b6e5dae1SThomas Gleixner bpf_disable_instrumentation(); 22015c14a3dSBrian Vazquez if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 22115c14a3dSBrian Vazquez map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) { 22215c14a3dSBrian Vazquez err = bpf_percpu_hash_copy(map, key, value); 22315c14a3dSBrian Vazquez } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) { 22415c14a3dSBrian Vazquez err = bpf_percpu_array_copy(map, key, value); 22515c14a3dSBrian Vazquez } else if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) { 22615c14a3dSBrian Vazquez err = bpf_percpu_cgroup_storage_copy(map, key, value); 22715c14a3dSBrian Vazquez } else if (map->map_type == BPF_MAP_TYPE_STACK_TRACE) { 22815c14a3dSBrian Vazquez err = bpf_stackmap_copy(map, key, value); 22915c14a3dSBrian Vazquez } else if (IS_FD_ARRAY(map) || IS_FD_PROG_ARRAY(map)) { 23015c14a3dSBrian Vazquez err = bpf_fd_array_map_lookup_elem(map, key, value); 23115c14a3dSBrian Vazquez } else if (IS_FD_HASH(map)) { 23215c14a3dSBrian Vazquez err = bpf_fd_htab_map_lookup_elem(map, key, value); 23315c14a3dSBrian Vazquez } else if (map->map_type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY) { 23415c14a3dSBrian Vazquez err = bpf_fd_reuseport_array_lookup_elem(map, key, value); 23515c14a3dSBrian Vazquez } else if (map->map_type == BPF_MAP_TYPE_QUEUE || 2369330986cSJoanne Koong map->map_type == BPF_MAP_TYPE_STACK || 2379330986cSJoanne Koong map->map_type == BPF_MAP_TYPE_BLOOM_FILTER) { 23815c14a3dSBrian Vazquez err = map->ops->map_peek_elem(map, value); 23915c14a3dSBrian Vazquez } else if (map->map_type == BPF_MAP_TYPE_STRUCT_OPS) { 24015c14a3dSBrian Vazquez /* struct_ops map requires directly updating "value" */ 24115c14a3dSBrian Vazquez err = bpf_struct_ops_map_sys_lookup_elem(map, key, value); 24215c14a3dSBrian Vazquez } else { 24315c14a3dSBrian Vazquez rcu_read_lock(); 24415c14a3dSBrian Vazquez if (map->ops->map_lookup_elem_sys_only) 24515c14a3dSBrian Vazquez ptr = map->ops->map_lookup_elem_sys_only(map, key); 24615c14a3dSBrian Vazquez else 24715c14a3dSBrian Vazquez ptr = map->ops->map_lookup_elem(map, key); 24815c14a3dSBrian Vazquez if (IS_ERR(ptr)) { 24915c14a3dSBrian Vazquez err = PTR_ERR(ptr); 25015c14a3dSBrian Vazquez } else if (!ptr) { 25115c14a3dSBrian Vazquez err = -ENOENT; 25215c14a3dSBrian Vazquez } else { 25315c14a3dSBrian Vazquez err = 0; 25415c14a3dSBrian Vazquez if (flags & BPF_F_LOCK) 25515c14a3dSBrian Vazquez /* lock 'ptr' and copy everything but lock */ 25615c14a3dSBrian Vazquez copy_map_value_locked(map, value, ptr, true); 25715c14a3dSBrian Vazquez else 25815c14a3dSBrian Vazquez copy_map_value(map, value, ptr); 25968134668SAlexei Starovoitov /* mask lock and timer, since value wasn't zero inited */ 26068134668SAlexei Starovoitov check_and_init_map_value(map, value); 26115c14a3dSBrian Vazquez } 26215c14a3dSBrian Vazquez rcu_read_unlock(); 26315c14a3dSBrian Vazquez } 26415c14a3dSBrian Vazquez 265b6e5dae1SThomas Gleixner bpf_enable_instrumentation(); 26615c14a3dSBrian Vazquez 26715c14a3dSBrian Vazquez return err; 26815c14a3dSBrian Vazquez } 26915c14a3dSBrian Vazquez 270d5299b67SRoman Gushchin /* Please, do not use this function outside from the map creation path 271d5299b67SRoman Gushchin * (e.g. in map update path) without taking care of setting the active 272d5299b67SRoman Gushchin * memory cgroup (see at bpf_map_kmalloc_node() for example). 273d5299b67SRoman Gushchin */ 274196e8ca7SDaniel Borkmann static void *__bpf_map_area_alloc(u64 size, int numa_node, bool mmapable) 275d407bd25SDaniel Borkmann { 276f01a7dbeSMartynas Pumputis /* We really just want to fail instead of triggering OOM killer 277f01a7dbeSMartynas Pumputis * under memory pressure, therefore we set __GFP_NORETRY to kmalloc, 278f01a7dbeSMartynas Pumputis * which is used for lower order allocation requests. 279f01a7dbeSMartynas Pumputis * 280f01a7dbeSMartynas Pumputis * It has been observed that higher order allocation requests done by 281f01a7dbeSMartynas Pumputis * vmalloc with __GFP_NORETRY being set might fail due to not trying 282f01a7dbeSMartynas Pumputis * to reclaim memory from the page cache, thus we set 283f01a7dbeSMartynas Pumputis * __GFP_RETRY_MAYFAIL to avoid such situations. 284d407bd25SDaniel Borkmann */ 285f01a7dbeSMartynas Pumputis 286ee53cbfbSYafang Shao gfp_t gfp = bpf_memcg_flags(__GFP_NOWARN | __GFP_ZERO); 287041de93fSChristoph Hellwig unsigned int flags = 0; 288041de93fSChristoph Hellwig unsigned long align = 1; 289d407bd25SDaniel Borkmann void *area; 290d407bd25SDaniel Borkmann 291196e8ca7SDaniel Borkmann if (size >= SIZE_MAX) 292196e8ca7SDaniel Borkmann return NULL; 293196e8ca7SDaniel Borkmann 294fc970227SAndrii Nakryiko /* kmalloc()'ed memory can't be mmap()'ed */ 295041de93fSChristoph Hellwig if (mmapable) { 296041de93fSChristoph Hellwig BUG_ON(!PAGE_ALIGNED(size)); 297041de93fSChristoph Hellwig align = SHMLBA; 298041de93fSChristoph Hellwig flags = VM_USERMAP; 299041de93fSChristoph Hellwig } else if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) { 300041de93fSChristoph Hellwig area = kmalloc_node(size, gfp | GFP_USER | __GFP_NORETRY, 301f01a7dbeSMartynas Pumputis numa_node); 302d407bd25SDaniel Borkmann if (area != NULL) 303d407bd25SDaniel Borkmann return area; 304d407bd25SDaniel Borkmann } 305041de93fSChristoph Hellwig 306041de93fSChristoph Hellwig return __vmalloc_node_range(size, align, VMALLOC_START, VMALLOC_END, 307041de93fSChristoph Hellwig gfp | GFP_KERNEL | __GFP_RETRY_MAYFAIL, PAGE_KERNEL, 308041de93fSChristoph Hellwig flags, numa_node, __builtin_return_address(0)); 309d407bd25SDaniel Borkmann } 310d407bd25SDaniel Borkmann 311196e8ca7SDaniel Borkmann void *bpf_map_area_alloc(u64 size, int numa_node) 312fc970227SAndrii Nakryiko { 313fc970227SAndrii Nakryiko return __bpf_map_area_alloc(size, numa_node, false); 314fc970227SAndrii Nakryiko } 315fc970227SAndrii Nakryiko 316196e8ca7SDaniel Borkmann void *bpf_map_area_mmapable_alloc(u64 size, int numa_node) 317fc970227SAndrii Nakryiko { 318fc970227SAndrii Nakryiko return __bpf_map_area_alloc(size, numa_node, true); 319fc970227SAndrii Nakryiko } 320fc970227SAndrii Nakryiko 321d407bd25SDaniel Borkmann void bpf_map_area_free(void *area) 322d407bd25SDaniel Borkmann { 323d407bd25SDaniel Borkmann kvfree(area); 324d407bd25SDaniel Borkmann } 325d407bd25SDaniel Borkmann 326be70bcd5SDaniel Borkmann static u32 bpf_map_flags_retain_permanent(u32 flags) 327be70bcd5SDaniel Borkmann { 328be70bcd5SDaniel Borkmann /* Some map creation flags are not tied to the map object but 329be70bcd5SDaniel Borkmann * rather to the map fd instead, so they have no meaning upon 330be70bcd5SDaniel Borkmann * map object inspection since multiple file descriptors with 331be70bcd5SDaniel Borkmann * different (access) properties can exist here. Thus, given 332be70bcd5SDaniel Borkmann * this has zero meaning for the map itself, lets clear these 333be70bcd5SDaniel Borkmann * from here. 334be70bcd5SDaniel Borkmann */ 335be70bcd5SDaniel Borkmann return flags & ~(BPF_F_RDONLY | BPF_F_WRONLY); 336be70bcd5SDaniel Borkmann } 337be70bcd5SDaniel Borkmann 338bd475643SJakub Kicinski void bpf_map_init_from_attr(struct bpf_map *map, union bpf_attr *attr) 339bd475643SJakub Kicinski { 340bd475643SJakub Kicinski map->map_type = attr->map_type; 341bd475643SJakub Kicinski map->key_size = attr->key_size; 342bd475643SJakub Kicinski map->value_size = attr->value_size; 343bd475643SJakub Kicinski map->max_entries = attr->max_entries; 344be70bcd5SDaniel Borkmann map->map_flags = bpf_map_flags_retain_permanent(attr->map_flags); 345bd475643SJakub Kicinski map->numa_node = bpf_map_attr_numa_node(attr); 3469330986cSJoanne Koong map->map_extra = attr->map_extra; 347bd475643SJakub Kicinski } 348bd475643SJakub Kicinski 349f3f1c054SMartin KaFai Lau static int bpf_map_alloc_id(struct bpf_map *map) 350f3f1c054SMartin KaFai Lau { 351f3f1c054SMartin KaFai Lau int id; 352f3f1c054SMartin KaFai Lau 353b76354cdSShaohua Li idr_preload(GFP_KERNEL); 354f3f1c054SMartin KaFai Lau spin_lock_bh(&map_idr_lock); 355f3f1c054SMartin KaFai Lau id = idr_alloc_cyclic(&map_idr, map, 1, INT_MAX, GFP_ATOMIC); 356f3f1c054SMartin KaFai Lau if (id > 0) 357f3f1c054SMartin KaFai Lau map->id = id; 358f3f1c054SMartin KaFai Lau spin_unlock_bh(&map_idr_lock); 359b76354cdSShaohua Li idr_preload_end(); 360f3f1c054SMartin KaFai Lau 361f3f1c054SMartin KaFai Lau if (WARN_ON_ONCE(!id)) 362f3f1c054SMartin KaFai Lau return -ENOSPC; 363f3f1c054SMartin KaFai Lau 364f3f1c054SMartin KaFai Lau return id > 0 ? 0 : id; 365f3f1c054SMartin KaFai Lau } 366f3f1c054SMartin KaFai Lau 367158e5e9eSTobias Klauser void bpf_map_free_id(struct bpf_map *map) 368f3f1c054SMartin KaFai Lau { 369930651a7SEric Dumazet unsigned long flags; 370930651a7SEric Dumazet 371a3884572SJakub Kicinski /* Offloaded maps are removed from the IDR store when their device 372a3884572SJakub Kicinski * disappears - even if someone holds an fd to them they are unusable, 373a3884572SJakub Kicinski * the memory is gone, all ops will fail; they are simply waiting for 374a3884572SJakub Kicinski * refcnt to drop to be freed. 375a3884572SJakub Kicinski */ 376a3884572SJakub Kicinski if (!map->id) 377a3884572SJakub Kicinski return; 378a3884572SJakub Kicinski 379930651a7SEric Dumazet spin_lock_irqsave(&map_idr_lock, flags); 380bd5f5f4eSMartin KaFai Lau 381f3f1c054SMartin KaFai Lau idr_remove(&map_idr, map->id); 382a3884572SJakub Kicinski map->id = 0; 383bd5f5f4eSMartin KaFai Lau 384930651a7SEric Dumazet spin_unlock_irqrestore(&map_idr_lock, flags); 385f3f1c054SMartin KaFai Lau } 386f3f1c054SMartin KaFai Lau 38748edc1f7SRoman Gushchin #ifdef CONFIG_MEMCG_KMEM 38848edc1f7SRoman Gushchin static void bpf_map_save_memcg(struct bpf_map *map) 38948edc1f7SRoman Gushchin { 3904201d9abSRoman Gushchin /* Currently if a map is created by a process belonging to the root 3914201d9abSRoman Gushchin * memory cgroup, get_obj_cgroup_from_current() will return NULL. 3924201d9abSRoman Gushchin * So we have to check map->objcg for being NULL each time it's 3934201d9abSRoman Gushchin * being used. 3944201d9abSRoman Gushchin */ 395ee53cbfbSYafang Shao if (memcg_bpf_enabled()) 3964201d9abSRoman Gushchin map->objcg = get_obj_cgroup_from_current(); 39748edc1f7SRoman Gushchin } 39848edc1f7SRoman Gushchin 39948edc1f7SRoman Gushchin static void bpf_map_release_memcg(struct bpf_map *map) 40048edc1f7SRoman Gushchin { 4014201d9abSRoman Gushchin if (map->objcg) 4024201d9abSRoman Gushchin obj_cgroup_put(map->objcg); 4034201d9abSRoman Gushchin } 4044201d9abSRoman Gushchin 4054201d9abSRoman Gushchin static struct mem_cgroup *bpf_map_get_memcg(const struct bpf_map *map) 4064201d9abSRoman Gushchin { 4074201d9abSRoman Gushchin if (map->objcg) 4084201d9abSRoman Gushchin return get_mem_cgroup_from_objcg(map->objcg); 4094201d9abSRoman Gushchin 4104201d9abSRoman Gushchin return root_mem_cgroup; 41148edc1f7SRoman Gushchin } 41248edc1f7SRoman Gushchin 41348edc1f7SRoman Gushchin void *bpf_map_kmalloc_node(const struct bpf_map *map, size_t size, gfp_t flags, 41448edc1f7SRoman Gushchin int node) 41548edc1f7SRoman Gushchin { 4164201d9abSRoman Gushchin struct mem_cgroup *memcg, *old_memcg; 41748edc1f7SRoman Gushchin void *ptr; 41848edc1f7SRoman Gushchin 4194201d9abSRoman Gushchin memcg = bpf_map_get_memcg(map); 4204201d9abSRoman Gushchin old_memcg = set_active_memcg(memcg); 42148edc1f7SRoman Gushchin ptr = kmalloc_node(size, flags | __GFP_ACCOUNT, node); 42248edc1f7SRoman Gushchin set_active_memcg(old_memcg); 4234201d9abSRoman Gushchin mem_cgroup_put(memcg); 42448edc1f7SRoman Gushchin 42548edc1f7SRoman Gushchin return ptr; 42648edc1f7SRoman Gushchin } 42748edc1f7SRoman Gushchin 42848edc1f7SRoman Gushchin void *bpf_map_kzalloc(const struct bpf_map *map, size_t size, gfp_t flags) 42948edc1f7SRoman Gushchin { 4304201d9abSRoman Gushchin struct mem_cgroup *memcg, *old_memcg; 43148edc1f7SRoman Gushchin void *ptr; 43248edc1f7SRoman Gushchin 4334201d9abSRoman Gushchin memcg = bpf_map_get_memcg(map); 4344201d9abSRoman Gushchin old_memcg = set_active_memcg(memcg); 43548edc1f7SRoman Gushchin ptr = kzalloc(size, flags | __GFP_ACCOUNT); 43648edc1f7SRoman Gushchin set_active_memcg(old_memcg); 4374201d9abSRoman Gushchin mem_cgroup_put(memcg); 43848edc1f7SRoman Gushchin 43948edc1f7SRoman Gushchin return ptr; 44048edc1f7SRoman Gushchin } 44148edc1f7SRoman Gushchin 442ddef81b5SYafang Shao void *bpf_map_kvcalloc(struct bpf_map *map, size_t n, size_t size, 443ddef81b5SYafang Shao gfp_t flags) 444ddef81b5SYafang Shao { 445ddef81b5SYafang Shao struct mem_cgroup *memcg, *old_memcg; 446ddef81b5SYafang Shao void *ptr; 447ddef81b5SYafang Shao 448ddef81b5SYafang Shao memcg = bpf_map_get_memcg(map); 449ddef81b5SYafang Shao old_memcg = set_active_memcg(memcg); 450ddef81b5SYafang Shao ptr = kvcalloc(n, size, flags | __GFP_ACCOUNT); 451ddef81b5SYafang Shao set_active_memcg(old_memcg); 452ddef81b5SYafang Shao mem_cgroup_put(memcg); 453ddef81b5SYafang Shao 454ddef81b5SYafang Shao return ptr; 455ddef81b5SYafang Shao } 456ddef81b5SYafang Shao 45748edc1f7SRoman Gushchin void __percpu *bpf_map_alloc_percpu(const struct bpf_map *map, size_t size, 45848edc1f7SRoman Gushchin size_t align, gfp_t flags) 45948edc1f7SRoman Gushchin { 4604201d9abSRoman Gushchin struct mem_cgroup *memcg, *old_memcg; 46148edc1f7SRoman Gushchin void __percpu *ptr; 46248edc1f7SRoman Gushchin 4634201d9abSRoman Gushchin memcg = bpf_map_get_memcg(map); 4644201d9abSRoman Gushchin old_memcg = set_active_memcg(memcg); 46548edc1f7SRoman Gushchin ptr = __alloc_percpu_gfp(size, align, flags | __GFP_ACCOUNT); 46648edc1f7SRoman Gushchin set_active_memcg(old_memcg); 4674201d9abSRoman Gushchin mem_cgroup_put(memcg); 46848edc1f7SRoman Gushchin 46948edc1f7SRoman Gushchin return ptr; 47048edc1f7SRoman Gushchin } 47148edc1f7SRoman Gushchin 47248edc1f7SRoman Gushchin #else 47348edc1f7SRoman Gushchin static void bpf_map_save_memcg(struct bpf_map *map) 47448edc1f7SRoman Gushchin { 47548edc1f7SRoman Gushchin } 47648edc1f7SRoman Gushchin 47748edc1f7SRoman Gushchin static void bpf_map_release_memcg(struct bpf_map *map) 47848edc1f7SRoman Gushchin { 47948edc1f7SRoman Gushchin } 48048edc1f7SRoman Gushchin #endif 48148edc1f7SRoman Gushchin 482aa3496acSKumar Kartikeya Dwivedi static int btf_field_cmp(const void *a, const void *b) 48361df10c7SKumar Kartikeya Dwivedi { 484aa3496acSKumar Kartikeya Dwivedi const struct btf_field *f1 = a, *f2 = b; 48561df10c7SKumar Kartikeya Dwivedi 486aa3496acSKumar Kartikeya Dwivedi if (f1->offset < f2->offset) 48761df10c7SKumar Kartikeya Dwivedi return -1; 488aa3496acSKumar Kartikeya Dwivedi else if (f1->offset > f2->offset) 48961df10c7SKumar Kartikeya Dwivedi return 1; 49061df10c7SKumar Kartikeya Dwivedi return 0; 49161df10c7SKumar Kartikeya Dwivedi } 49261df10c7SKumar Kartikeya Dwivedi 493aa3496acSKumar Kartikeya Dwivedi struct btf_field *btf_record_find(const struct btf_record *rec, u32 offset, 49474843b57SDave Marchevsky u32 field_mask) 49561df10c7SKumar Kartikeya Dwivedi { 496aa3496acSKumar Kartikeya Dwivedi struct btf_field *field; 49761df10c7SKumar Kartikeya Dwivedi 49874843b57SDave Marchevsky if (IS_ERR_OR_NULL(rec) || !(rec->field_mask & field_mask)) 49961df10c7SKumar Kartikeya Dwivedi return NULL; 500aa3496acSKumar Kartikeya Dwivedi field = bsearch(&offset, rec->fields, rec->cnt, sizeof(rec->fields[0]), btf_field_cmp); 50174843b57SDave Marchevsky if (!field || !(field->type & field_mask)) 502aa3496acSKumar Kartikeya Dwivedi return NULL; 503aa3496acSKumar Kartikeya Dwivedi return field; 50461df10c7SKumar Kartikeya Dwivedi } 50561df10c7SKumar Kartikeya Dwivedi 506aa3496acSKumar Kartikeya Dwivedi void btf_record_free(struct btf_record *rec) 50761df10c7SKumar Kartikeya Dwivedi { 50861df10c7SKumar Kartikeya Dwivedi int i; 50961df10c7SKumar Kartikeya Dwivedi 510aa3496acSKumar Kartikeya Dwivedi if (IS_ERR_OR_NULL(rec)) 51161df10c7SKumar Kartikeya Dwivedi return; 512aa3496acSKumar Kartikeya Dwivedi for (i = 0; i < rec->cnt; i++) { 513aa3496acSKumar Kartikeya Dwivedi switch (rec->fields[i].type) { 514aa3496acSKumar Kartikeya Dwivedi case BPF_KPTR_UNREF: 515aa3496acSKumar Kartikeya Dwivedi case BPF_KPTR_REF: 51655db92f4SYonghong Song case BPF_KPTR_PERCPU: 517aa3496acSKumar Kartikeya Dwivedi if (rec->fields[i].kptr.module) 518aa3496acSKumar Kartikeya Dwivedi module_put(rec->fields[i].kptr.module); 519aa3496acSKumar Kartikeya Dwivedi btf_put(rec->fields[i].kptr.btf); 520aa3496acSKumar Kartikeya Dwivedi break; 521f0c5941fSKumar Kartikeya Dwivedi case BPF_LIST_HEAD: 5228ffa5cc1SKumar Kartikeya Dwivedi case BPF_LIST_NODE: 5239c395c1bSDave Marchevsky case BPF_RB_ROOT: 5249c395c1bSDave Marchevsky case BPF_RB_NODE: 5259c395c1bSDave Marchevsky case BPF_SPIN_LOCK: 5269c395c1bSDave Marchevsky case BPF_TIMER: 527d54730b5SDave Marchevsky case BPF_REFCOUNT: 5289c395c1bSDave Marchevsky /* Nothing to release */ 529f0c5941fSKumar Kartikeya Dwivedi break; 530aa3496acSKumar Kartikeya Dwivedi default: 531aa3496acSKumar Kartikeya Dwivedi WARN_ON_ONCE(1); 53214a324f6SKumar Kartikeya Dwivedi continue; 53314a324f6SKumar Kartikeya Dwivedi } 534aa3496acSKumar Kartikeya Dwivedi } 535aa3496acSKumar Kartikeya Dwivedi kfree(rec); 536aa3496acSKumar Kartikeya Dwivedi } 537aa3496acSKumar Kartikeya Dwivedi 538aa3496acSKumar Kartikeya Dwivedi void bpf_map_free_record(struct bpf_map *map) 539aa3496acSKumar Kartikeya Dwivedi { 540aa3496acSKumar Kartikeya Dwivedi btf_record_free(map->record); 541aa3496acSKumar Kartikeya Dwivedi map->record = NULL; 542aa3496acSKumar Kartikeya Dwivedi } 543aa3496acSKumar Kartikeya Dwivedi 544aa3496acSKumar Kartikeya Dwivedi struct btf_record *btf_record_dup(const struct btf_record *rec) 545aa3496acSKumar Kartikeya Dwivedi { 546aa3496acSKumar Kartikeya Dwivedi const struct btf_field *fields; 547aa3496acSKumar Kartikeya Dwivedi struct btf_record *new_rec; 548aa3496acSKumar Kartikeya Dwivedi int ret, size, i; 549aa3496acSKumar Kartikeya Dwivedi 550aa3496acSKumar Kartikeya Dwivedi if (IS_ERR_OR_NULL(rec)) 551aa3496acSKumar Kartikeya Dwivedi return NULL; 552aa3496acSKumar Kartikeya Dwivedi size = offsetof(struct btf_record, fields[rec->cnt]); 553aa3496acSKumar Kartikeya Dwivedi new_rec = kmemdup(rec, size, GFP_KERNEL | __GFP_NOWARN); 554aa3496acSKumar Kartikeya Dwivedi if (!new_rec) 555aa3496acSKumar Kartikeya Dwivedi return ERR_PTR(-ENOMEM); 556aa3496acSKumar Kartikeya Dwivedi /* Do a deep copy of the btf_record */ 557aa3496acSKumar Kartikeya Dwivedi fields = rec->fields; 558aa3496acSKumar Kartikeya Dwivedi new_rec->cnt = 0; 559aa3496acSKumar Kartikeya Dwivedi for (i = 0; i < rec->cnt; i++) { 560aa3496acSKumar Kartikeya Dwivedi switch (fields[i].type) { 561aa3496acSKumar Kartikeya Dwivedi case BPF_KPTR_UNREF: 562aa3496acSKumar Kartikeya Dwivedi case BPF_KPTR_REF: 56355db92f4SYonghong Song case BPF_KPTR_PERCPU: 564aa3496acSKumar Kartikeya Dwivedi btf_get(fields[i].kptr.btf); 565aa3496acSKumar Kartikeya Dwivedi if (fields[i].kptr.module && !try_module_get(fields[i].kptr.module)) { 566aa3496acSKumar Kartikeya Dwivedi ret = -ENXIO; 567aa3496acSKumar Kartikeya Dwivedi goto free; 568aa3496acSKumar Kartikeya Dwivedi } 569aa3496acSKumar Kartikeya Dwivedi break; 570f0c5941fSKumar Kartikeya Dwivedi case BPF_LIST_HEAD: 5718ffa5cc1SKumar Kartikeya Dwivedi case BPF_LIST_NODE: 5729c395c1bSDave Marchevsky case BPF_RB_ROOT: 5739c395c1bSDave Marchevsky case BPF_RB_NODE: 5749c395c1bSDave Marchevsky case BPF_SPIN_LOCK: 5759c395c1bSDave Marchevsky case BPF_TIMER: 576d54730b5SDave Marchevsky case BPF_REFCOUNT: 5779c395c1bSDave Marchevsky /* Nothing to acquire */ 578f0c5941fSKumar Kartikeya Dwivedi break; 579aa3496acSKumar Kartikeya Dwivedi default: 580aa3496acSKumar Kartikeya Dwivedi ret = -EFAULT; 581aa3496acSKumar Kartikeya Dwivedi WARN_ON_ONCE(1); 582aa3496acSKumar Kartikeya Dwivedi goto free; 583aa3496acSKumar Kartikeya Dwivedi } 584aa3496acSKumar Kartikeya Dwivedi new_rec->cnt++; 585aa3496acSKumar Kartikeya Dwivedi } 586aa3496acSKumar Kartikeya Dwivedi return new_rec; 587aa3496acSKumar Kartikeya Dwivedi free: 588aa3496acSKumar Kartikeya Dwivedi btf_record_free(new_rec); 589aa3496acSKumar Kartikeya Dwivedi return ERR_PTR(ret); 590aa3496acSKumar Kartikeya Dwivedi } 591aa3496acSKumar Kartikeya Dwivedi 592aa3496acSKumar Kartikeya Dwivedi bool btf_record_equal(const struct btf_record *rec_a, const struct btf_record *rec_b) 593aa3496acSKumar Kartikeya Dwivedi { 594aa3496acSKumar Kartikeya Dwivedi bool a_has_fields = !IS_ERR_OR_NULL(rec_a), b_has_fields = !IS_ERR_OR_NULL(rec_b); 595aa3496acSKumar Kartikeya Dwivedi int size; 596aa3496acSKumar Kartikeya Dwivedi 597aa3496acSKumar Kartikeya Dwivedi if (!a_has_fields && !b_has_fields) 598aa3496acSKumar Kartikeya Dwivedi return true; 599aa3496acSKumar Kartikeya Dwivedi if (a_has_fields != b_has_fields) 600aa3496acSKumar Kartikeya Dwivedi return false; 601aa3496acSKumar Kartikeya Dwivedi if (rec_a->cnt != rec_b->cnt) 602aa3496acSKumar Kartikeya Dwivedi return false; 603aa3496acSKumar Kartikeya Dwivedi size = offsetof(struct btf_record, fields[rec_a->cnt]); 604c22dfdd2SKumar Kartikeya Dwivedi /* btf_parse_fields uses kzalloc to allocate a btf_record, so unused 605c22dfdd2SKumar Kartikeya Dwivedi * members are zeroed out. So memcmp is safe to do without worrying 606c22dfdd2SKumar Kartikeya Dwivedi * about padding/unused fields. 607c22dfdd2SKumar Kartikeya Dwivedi * 608c22dfdd2SKumar Kartikeya Dwivedi * While spin_lock, timer, and kptr have no relation to map BTF, 609c22dfdd2SKumar Kartikeya Dwivedi * list_head metadata is specific to map BTF, the btf and value_rec 610c22dfdd2SKumar Kartikeya Dwivedi * members in particular. btf is the map BTF, while value_rec points to 611c22dfdd2SKumar Kartikeya Dwivedi * btf_record in that map BTF. 612c22dfdd2SKumar Kartikeya Dwivedi * 613c22dfdd2SKumar Kartikeya Dwivedi * So while by default, we don't rely on the map BTF (which the records 614c22dfdd2SKumar Kartikeya Dwivedi * were parsed from) matching for both records, which is not backwards 615c22dfdd2SKumar Kartikeya Dwivedi * compatible, in case list_head is part of it, we implicitly rely on 616c22dfdd2SKumar Kartikeya Dwivedi * that by way of depending on memcmp succeeding for it. 617c22dfdd2SKumar Kartikeya Dwivedi */ 618aa3496acSKumar Kartikeya Dwivedi return !memcmp(rec_a, rec_b, size); 619aa3496acSKumar Kartikeya Dwivedi } 620aa3496acSKumar Kartikeya Dwivedi 621db559117SKumar Kartikeya Dwivedi void bpf_obj_free_timer(const struct btf_record *rec, void *obj) 622db559117SKumar Kartikeya Dwivedi { 623db559117SKumar Kartikeya Dwivedi if (WARN_ON_ONCE(!btf_record_has_field(rec, BPF_TIMER))) 624db559117SKumar Kartikeya Dwivedi return; 625db559117SKumar Kartikeya Dwivedi bpf_timer_cancel_and_free(obj + rec->timer_off); 626db559117SKumar Kartikeya Dwivedi } 627db559117SKumar Kartikeya Dwivedi 628aa3496acSKumar Kartikeya Dwivedi void bpf_obj_free_fields(const struct btf_record *rec, void *obj) 629aa3496acSKumar Kartikeya Dwivedi { 630aa3496acSKumar Kartikeya Dwivedi const struct btf_field *fields; 631aa3496acSKumar Kartikeya Dwivedi int i; 632aa3496acSKumar Kartikeya Dwivedi 633aa3496acSKumar Kartikeya Dwivedi if (IS_ERR_OR_NULL(rec)) 634aa3496acSKumar Kartikeya Dwivedi return; 635aa3496acSKumar Kartikeya Dwivedi fields = rec->fields; 636aa3496acSKumar Kartikeya Dwivedi for (i = 0; i < rec->cnt; i++) { 637c8e18754SDave Marchevsky struct btf_struct_meta *pointee_struct_meta; 638aa3496acSKumar Kartikeya Dwivedi const struct btf_field *field = &fields[i]; 639aa3496acSKumar Kartikeya Dwivedi void *field_ptr = obj + field->offset; 640c8e18754SDave Marchevsky void *xchgd_field; 641aa3496acSKumar Kartikeya Dwivedi 642aa3496acSKumar Kartikeya Dwivedi switch (fields[i].type) { 643db559117SKumar Kartikeya Dwivedi case BPF_SPIN_LOCK: 644db559117SKumar Kartikeya Dwivedi break; 645db559117SKumar Kartikeya Dwivedi case BPF_TIMER: 646db559117SKumar Kartikeya Dwivedi bpf_timer_cancel_and_free(field_ptr); 647db559117SKumar Kartikeya Dwivedi break; 648aa3496acSKumar Kartikeya Dwivedi case BPF_KPTR_UNREF: 649aa3496acSKumar Kartikeya Dwivedi WRITE_ONCE(*(u64 *)field_ptr, 0); 650aa3496acSKumar Kartikeya Dwivedi break; 651aa3496acSKumar Kartikeya Dwivedi case BPF_KPTR_REF: 65255db92f4SYonghong Song case BPF_KPTR_PERCPU: 653c8e18754SDave Marchevsky xchgd_field = (void *)xchg((unsigned long *)field_ptr, 0); 6541431d0b5SDavid Vernet if (!xchgd_field) 6551431d0b5SDavid Vernet break; 6561431d0b5SDavid Vernet 657c8e18754SDave Marchevsky if (!btf_is_kernel(field->kptr.btf)) { 658c8e18754SDave Marchevsky pointee_struct_meta = btf_find_struct_meta(field->kptr.btf, 659c8e18754SDave Marchevsky field->kptr.btf_id); 6609e36a204SDave Marchevsky migrate_disable(); 6619e36a204SDave Marchevsky __bpf_obj_drop_impl(xchgd_field, pointee_struct_meta ? 662e383a459SHou Tao pointee_struct_meta->record : NULL, 663e383a459SHou Tao fields[i].type == BPF_KPTR_PERCPU); 6649e36a204SDave Marchevsky migrate_enable(); 665c8e18754SDave Marchevsky } else { 666c8e18754SDave Marchevsky field->kptr.dtor(xchgd_field); 667c8e18754SDave Marchevsky } 668aa3496acSKumar Kartikeya Dwivedi break; 669f0c5941fSKumar Kartikeya Dwivedi case BPF_LIST_HEAD: 670f0c5941fSKumar Kartikeya Dwivedi if (WARN_ON_ONCE(rec->spin_lock_off < 0)) 671f0c5941fSKumar Kartikeya Dwivedi continue; 672f0c5941fSKumar Kartikeya Dwivedi bpf_list_head_free(field, field_ptr, obj + rec->spin_lock_off); 673f0c5941fSKumar Kartikeya Dwivedi break; 6749c395c1bSDave Marchevsky case BPF_RB_ROOT: 6759c395c1bSDave Marchevsky if (WARN_ON_ONCE(rec->spin_lock_off < 0)) 6769c395c1bSDave Marchevsky continue; 6779c395c1bSDave Marchevsky bpf_rb_root_free(field, field_ptr, obj + rec->spin_lock_off); 6789c395c1bSDave Marchevsky break; 6798ffa5cc1SKumar Kartikeya Dwivedi case BPF_LIST_NODE: 6809c395c1bSDave Marchevsky case BPF_RB_NODE: 681d54730b5SDave Marchevsky case BPF_REFCOUNT: 6828ffa5cc1SKumar Kartikeya Dwivedi break; 683aa3496acSKumar Kartikeya Dwivedi default: 684aa3496acSKumar Kartikeya Dwivedi WARN_ON_ONCE(1); 685aa3496acSKumar Kartikeya Dwivedi continue; 686aa3496acSKumar Kartikeya Dwivedi } 68714a324f6SKumar Kartikeya Dwivedi } 68814a324f6SKumar Kartikeya Dwivedi } 68914a324f6SKumar Kartikeya Dwivedi 69099c55f7dSAlexei Starovoitov /* called from workqueue */ 69199c55f7dSAlexei Starovoitov static void bpf_map_free_deferred(struct work_struct *work) 69299c55f7dSAlexei Starovoitov { 69399c55f7dSAlexei Starovoitov struct bpf_map *map = container_of(work, struct bpf_map, work); 694d7f5ef65SKumar Kartikeya Dwivedi struct btf_record *rec = map->record; 69559e5791fSYonghong Song struct btf *btf = map->btf; 69699c55f7dSAlexei Starovoitov 697afdb09c7SChenbo Feng security_bpf_map_free(map); 69848edc1f7SRoman Gushchin bpf_map_release_memcg(map); 699d7f5ef65SKumar Kartikeya Dwivedi /* implementation dependent freeing */ 70099c55f7dSAlexei Starovoitov map->ops->map_free(map); 701cd2a8079SDave Marchevsky /* Delay freeing of btf_record for maps, as map_free 702d7f5ef65SKumar Kartikeya Dwivedi * callback usually needs access to them. It is better to do it here 703d7f5ef65SKumar Kartikeya Dwivedi * than require each callback to do the free itself manually. 704d7f5ef65SKumar Kartikeya Dwivedi * 705d7f5ef65SKumar Kartikeya Dwivedi * Note that the btf_record stashed in map->inner_map_meta->record was 706d7f5ef65SKumar Kartikeya Dwivedi * already freed using the map_free callback for map in map case which 707d7f5ef65SKumar Kartikeya Dwivedi * eventually calls bpf_map_free_meta, since inner_map_meta is only a 708d7f5ef65SKumar Kartikeya Dwivedi * template bpf_map struct used during verification. 709d7f5ef65SKumar Kartikeya Dwivedi */ 710d7f5ef65SKumar Kartikeya Dwivedi btf_record_free(rec); 71159e5791fSYonghong Song /* Delay freeing of btf for maps, as map_free callback may need 71259e5791fSYonghong Song * struct_meta info which will be freed with btf_put(). 71359e5791fSYonghong Song */ 71459e5791fSYonghong Song btf_put(btf); 71599c55f7dSAlexei Starovoitov } 71699c55f7dSAlexei Starovoitov 717c9da161cSDaniel Borkmann static void bpf_map_put_uref(struct bpf_map *map) 718c9da161cSDaniel Borkmann { 7191e0bd5a0SAndrii Nakryiko if (atomic64_dec_and_test(&map->usercnt)) { 720ba6b8de4SJohn Fastabend if (map->ops->map_release_uref) 721ba6b8de4SJohn Fastabend map->ops->map_release_uref(map); 722c9da161cSDaniel Borkmann } 723c9da161cSDaniel Borkmann } 724c9da161cSDaniel Borkmann 72587667336SHou Tao static void bpf_map_free_in_work(struct bpf_map *map) 72687667336SHou Tao { 72787667336SHou Tao INIT_WORK(&map->work, bpf_map_free_deferred); 72887667336SHou Tao /* Avoid spawning kworkers, since they all might contend 72987667336SHou Tao * for the same mutex like slab_mutex. 73087667336SHou Tao */ 73187667336SHou Tao queue_work(system_unbound_wq, &map->work); 73287667336SHou Tao } 73387667336SHou Tao 73487667336SHou Tao static void bpf_map_free_rcu_gp(struct rcu_head *rcu) 73587667336SHou Tao { 73687667336SHou Tao bpf_map_free_in_work(container_of(rcu, struct bpf_map, rcu)); 73787667336SHou Tao } 73887667336SHou Tao 73987667336SHou Tao static void bpf_map_free_mult_rcu_gp(struct rcu_head *rcu) 74087667336SHou Tao { 74187667336SHou Tao if (rcu_trace_implies_rcu_gp()) 74287667336SHou Tao bpf_map_free_rcu_gp(rcu); 74387667336SHou Tao else 74487667336SHou Tao call_rcu(rcu, bpf_map_free_rcu_gp); 74587667336SHou Tao } 74687667336SHou Tao 74799c55f7dSAlexei Starovoitov /* decrement map refcnt and schedule it for freeing via workqueue 748158e5e9eSTobias Klauser * (underlying map implementation ops->map_free() might sleep) 74999c55f7dSAlexei Starovoitov */ 750158e5e9eSTobias Klauser void bpf_map_put(struct bpf_map *map) 75199c55f7dSAlexei Starovoitov { 7521e0bd5a0SAndrii Nakryiko if (atomic64_dec_and_test(&map->refcnt)) { 75334ad5580SMartin KaFai Lau /* bpf_map_free_id() must be called first */ 754158e5e9eSTobias Klauser bpf_map_free_id(map); 75587667336SHou Tao 756af66bfd3SHou Tao WARN_ON_ONCE(atomic64_read(&map->sleepable_refcnt)); 75787667336SHou Tao if (READ_ONCE(map->free_after_mult_rcu_gp)) 75887667336SHou Tao call_rcu_tasks_trace(&map->rcu, bpf_map_free_mult_rcu_gp); 759af66bfd3SHou Tao else if (READ_ONCE(map->free_after_rcu_gp)) 760af66bfd3SHou Tao call_rcu(&map->rcu, bpf_map_free_rcu_gp); 76187667336SHou Tao else 76287667336SHou Tao bpf_map_free_in_work(map); 76399c55f7dSAlexei Starovoitov } 76499c55f7dSAlexei Starovoitov } 765630a4d38SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_map_put); 766bd5f5f4eSMartin KaFai Lau 767c9da161cSDaniel Borkmann void bpf_map_put_with_uref(struct bpf_map *map) 768c9da161cSDaniel Borkmann { 769c9da161cSDaniel Borkmann bpf_map_put_uref(map); 770c9da161cSDaniel Borkmann bpf_map_put(map); 771c9da161cSDaniel Borkmann } 772c9da161cSDaniel Borkmann 77399c55f7dSAlexei Starovoitov static int bpf_map_release(struct inode *inode, struct file *filp) 77499c55f7dSAlexei Starovoitov { 77561d1b6a4SDaniel Borkmann struct bpf_map *map = filp->private_data; 77661d1b6a4SDaniel Borkmann 77761d1b6a4SDaniel Borkmann if (map->ops->map_release) 77861d1b6a4SDaniel Borkmann map->ops->map_release(map, filp); 77961d1b6a4SDaniel Borkmann 78061d1b6a4SDaniel Borkmann bpf_map_put_with_uref(map); 78199c55f7dSAlexei Starovoitov return 0; 78299c55f7dSAlexei Starovoitov } 78399c55f7dSAlexei Starovoitov 78487df15deSDaniel Borkmann static fmode_t map_get_sys_perms(struct bpf_map *map, struct fd f) 78587df15deSDaniel Borkmann { 78687df15deSDaniel Borkmann fmode_t mode = f.file->f_mode; 78787df15deSDaniel Borkmann 78887df15deSDaniel Borkmann /* Our file permissions may have been overridden by global 78987df15deSDaniel Borkmann * map permissions facing syscall side. 79087df15deSDaniel Borkmann */ 79187df15deSDaniel Borkmann if (READ_ONCE(map->frozen)) 79287df15deSDaniel Borkmann mode &= ~FMODE_CAN_WRITE; 79387df15deSDaniel Borkmann return mode; 79487df15deSDaniel Borkmann } 79587df15deSDaniel Borkmann 796f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS 79790a5527dSYafang Shao /* Show the memory usage of a bpf map */ 79890a5527dSYafang Shao static u64 bpf_map_memory_usage(const struct bpf_map *map) 79980ee81e0SRoman Gushchin { 80090a5527dSYafang Shao return map->ops->map_mem_usage(map); 80180ee81e0SRoman Gushchin } 80280ee81e0SRoman Gushchin 803f99bf205SDaniel Borkmann static void bpf_map_show_fdinfo(struct seq_file *m, struct file *filp) 804f99bf205SDaniel Borkmann { 805f45d5b6cSToke Hoiland-Jorgensen struct bpf_map *map = filp->private_data; 8062beee5f5SDaniel Borkmann u32 type = 0, jited = 0; 80721116b70SDaniel Borkmann 808f45d5b6cSToke Hoiland-Jorgensen if (map_type_contains_progs(map)) { 809f45d5b6cSToke Hoiland-Jorgensen spin_lock(&map->owner.lock); 810f45d5b6cSToke Hoiland-Jorgensen type = map->owner.type; 811f45d5b6cSToke Hoiland-Jorgensen jited = map->owner.jited; 812f45d5b6cSToke Hoiland-Jorgensen spin_unlock(&map->owner.lock); 81321116b70SDaniel Borkmann } 814f99bf205SDaniel Borkmann 815f99bf205SDaniel Borkmann seq_printf(m, 816f99bf205SDaniel Borkmann "map_type:\t%u\n" 817f99bf205SDaniel Borkmann "key_size:\t%u\n" 818f99bf205SDaniel Borkmann "value_size:\t%u\n" 819322cea2fSDaniel Borkmann "max_entries:\t%u\n" 82021116b70SDaniel Borkmann "map_flags:\t%#x\n" 8219330986cSJoanne Koong "map_extra:\t%#llx\n" 82290a5527dSYafang Shao "memlock:\t%llu\n" 82387df15deSDaniel Borkmann "map_id:\t%u\n" 82487df15deSDaniel Borkmann "frozen:\t%u\n", 825f99bf205SDaniel Borkmann map->map_type, 826f99bf205SDaniel Borkmann map->key_size, 827f99bf205SDaniel Borkmann map->value_size, 828322cea2fSDaniel Borkmann map->max_entries, 82921116b70SDaniel Borkmann map->map_flags, 8309330986cSJoanne Koong (unsigned long long)map->map_extra, 83190a5527dSYafang Shao bpf_map_memory_usage(map), 83287df15deSDaniel Borkmann map->id, 83387df15deSDaniel Borkmann READ_ONCE(map->frozen)); 8342beee5f5SDaniel Borkmann if (type) { 8352beee5f5SDaniel Borkmann seq_printf(m, "owner_prog_type:\t%u\n", type); 8362beee5f5SDaniel Borkmann seq_printf(m, "owner_jited:\t%u\n", jited); 8379780c0abSDaniel Borkmann } 838f99bf205SDaniel Borkmann } 839f99bf205SDaniel Borkmann #endif 840f99bf205SDaniel Borkmann 8416e71b04aSChenbo Feng static ssize_t bpf_dummy_read(struct file *filp, char __user *buf, size_t siz, 8426e71b04aSChenbo Feng loff_t *ppos) 8436e71b04aSChenbo Feng { 8446e71b04aSChenbo Feng /* We need this handler such that alloc_file() enables 8456e71b04aSChenbo Feng * f_mode with FMODE_CAN_READ. 8466e71b04aSChenbo Feng */ 8476e71b04aSChenbo Feng return -EINVAL; 8486e71b04aSChenbo Feng } 8496e71b04aSChenbo Feng 8506e71b04aSChenbo Feng static ssize_t bpf_dummy_write(struct file *filp, const char __user *buf, 8516e71b04aSChenbo Feng size_t siz, loff_t *ppos) 8526e71b04aSChenbo Feng { 8536e71b04aSChenbo Feng /* We need this handler such that alloc_file() enables 8546e71b04aSChenbo Feng * f_mode with FMODE_CAN_WRITE. 8556e71b04aSChenbo Feng */ 8566e71b04aSChenbo Feng return -EINVAL; 8576e71b04aSChenbo Feng } 8586e71b04aSChenbo Feng 859fc970227SAndrii Nakryiko /* called for any extra memory-mapped regions (except initial) */ 860fc970227SAndrii Nakryiko static void bpf_map_mmap_open(struct vm_area_struct *vma) 861fc970227SAndrii Nakryiko { 862fc970227SAndrii Nakryiko struct bpf_map *map = vma->vm_file->private_data; 863fc970227SAndrii Nakryiko 864353050beSDaniel Borkmann if (vma->vm_flags & VM_MAYWRITE) 865353050beSDaniel Borkmann bpf_map_write_active_inc(map); 866fc970227SAndrii Nakryiko } 867fc970227SAndrii Nakryiko 868fc970227SAndrii Nakryiko /* called for all unmapped memory region (including initial) */ 869fc970227SAndrii Nakryiko static void bpf_map_mmap_close(struct vm_area_struct *vma) 870fc970227SAndrii Nakryiko { 871fc970227SAndrii Nakryiko struct bpf_map *map = vma->vm_file->private_data; 872fc970227SAndrii Nakryiko 873353050beSDaniel Borkmann if (vma->vm_flags & VM_MAYWRITE) 874353050beSDaniel Borkmann bpf_map_write_active_dec(map); 875fc970227SAndrii Nakryiko } 876fc970227SAndrii Nakryiko 877fc970227SAndrii Nakryiko static const struct vm_operations_struct bpf_map_default_vmops = { 878fc970227SAndrii Nakryiko .open = bpf_map_mmap_open, 879fc970227SAndrii Nakryiko .close = bpf_map_mmap_close, 880fc970227SAndrii Nakryiko }; 881fc970227SAndrii Nakryiko 882fc970227SAndrii Nakryiko static int bpf_map_mmap(struct file *filp, struct vm_area_struct *vma) 883fc970227SAndrii Nakryiko { 884fc970227SAndrii Nakryiko struct bpf_map *map = filp->private_data; 885fc970227SAndrii Nakryiko int err; 886fc970227SAndrii Nakryiko 887db559117SKumar Kartikeya Dwivedi if (!map->ops->map_mmap || !IS_ERR_OR_NULL(map->record)) 888fc970227SAndrii Nakryiko return -ENOTSUPP; 889fc970227SAndrii Nakryiko 890fc970227SAndrii Nakryiko if (!(vma->vm_flags & VM_SHARED)) 891fc970227SAndrii Nakryiko return -EINVAL; 892fc970227SAndrii Nakryiko 893fc970227SAndrii Nakryiko mutex_lock(&map->freeze_mutex); 894fc970227SAndrii Nakryiko 895dfeb376dSAndrii Nakryiko if (vma->vm_flags & VM_WRITE) { 896dfeb376dSAndrii Nakryiko if (map->frozen) { 897fc970227SAndrii Nakryiko err = -EPERM; 898fc970227SAndrii Nakryiko goto out; 899fc970227SAndrii Nakryiko } 900dfeb376dSAndrii Nakryiko /* map is meant to be read-only, so do not allow mapping as 901dfeb376dSAndrii Nakryiko * writable, because it's possible to leak a writable page 902dfeb376dSAndrii Nakryiko * reference and allows user-space to still modify it after 903dfeb376dSAndrii Nakryiko * freezing, while verifier will assume contents do not change 904dfeb376dSAndrii Nakryiko */ 905dfeb376dSAndrii Nakryiko if (map->map_flags & BPF_F_RDONLY_PROG) { 906dfeb376dSAndrii Nakryiko err = -EACCES; 907dfeb376dSAndrii Nakryiko goto out; 908dfeb376dSAndrii Nakryiko } 909dfeb376dSAndrii Nakryiko } 910fc970227SAndrii Nakryiko 911fc970227SAndrii Nakryiko /* set default open/close callbacks */ 912fc970227SAndrii Nakryiko vma->vm_ops = &bpf_map_default_vmops; 913fc970227SAndrii Nakryiko vma->vm_private_data = map; 9141c71222eSSuren Baghdasaryan vm_flags_clear(vma, VM_MAYEXEC); 9151f6cb19bSAndrii Nakryiko if (!(vma->vm_flags & VM_WRITE)) 9161f6cb19bSAndrii Nakryiko /* disallow re-mapping with PROT_WRITE */ 9171c71222eSSuren Baghdasaryan vm_flags_clear(vma, VM_MAYWRITE); 918fc970227SAndrii Nakryiko 919fc970227SAndrii Nakryiko err = map->ops->map_mmap(map, vma); 920fc970227SAndrii Nakryiko if (err) 921fc970227SAndrii Nakryiko goto out; 922fc970227SAndrii Nakryiko 9231f6cb19bSAndrii Nakryiko if (vma->vm_flags & VM_MAYWRITE) 924353050beSDaniel Borkmann bpf_map_write_active_inc(map); 925fc970227SAndrii Nakryiko out: 926fc970227SAndrii Nakryiko mutex_unlock(&map->freeze_mutex); 927fc970227SAndrii Nakryiko return err; 928fc970227SAndrii Nakryiko } 929fc970227SAndrii Nakryiko 930457f4436SAndrii Nakryiko static __poll_t bpf_map_poll(struct file *filp, struct poll_table_struct *pts) 931457f4436SAndrii Nakryiko { 932457f4436SAndrii Nakryiko struct bpf_map *map = filp->private_data; 933457f4436SAndrii Nakryiko 934457f4436SAndrii Nakryiko if (map->ops->map_poll) 935457f4436SAndrii Nakryiko return map->ops->map_poll(map, filp, pts); 936457f4436SAndrii Nakryiko 937457f4436SAndrii Nakryiko return EPOLLERR; 938457f4436SAndrii Nakryiko } 939457f4436SAndrii Nakryiko 940f66e448cSChenbo Feng const struct file_operations bpf_map_fops = { 941f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS 942f99bf205SDaniel Borkmann .show_fdinfo = bpf_map_show_fdinfo, 943f99bf205SDaniel Borkmann #endif 94499c55f7dSAlexei Starovoitov .release = bpf_map_release, 9456e71b04aSChenbo Feng .read = bpf_dummy_read, 9466e71b04aSChenbo Feng .write = bpf_dummy_write, 947fc970227SAndrii Nakryiko .mmap = bpf_map_mmap, 948457f4436SAndrii Nakryiko .poll = bpf_map_poll, 94999c55f7dSAlexei Starovoitov }; 95099c55f7dSAlexei Starovoitov 9516e71b04aSChenbo Feng int bpf_map_new_fd(struct bpf_map *map, int flags) 952aa79781bSDaniel Borkmann { 953afdb09c7SChenbo Feng int ret; 954afdb09c7SChenbo Feng 955afdb09c7SChenbo Feng ret = security_bpf_map(map, OPEN_FMODE(flags)); 956afdb09c7SChenbo Feng if (ret < 0) 957afdb09c7SChenbo Feng return ret; 958afdb09c7SChenbo Feng 959aa79781bSDaniel Borkmann return anon_inode_getfd("bpf-map", &bpf_map_fops, map, 9606e71b04aSChenbo Feng flags | O_CLOEXEC); 9616e71b04aSChenbo Feng } 9626e71b04aSChenbo Feng 9636e71b04aSChenbo Feng int bpf_get_file_flag(int flags) 9646e71b04aSChenbo Feng { 9656e71b04aSChenbo Feng if ((flags & BPF_F_RDONLY) && (flags & BPF_F_WRONLY)) 9666e71b04aSChenbo Feng return -EINVAL; 9676e71b04aSChenbo Feng if (flags & BPF_F_RDONLY) 9686e71b04aSChenbo Feng return O_RDONLY; 9696e71b04aSChenbo Feng if (flags & BPF_F_WRONLY) 9706e71b04aSChenbo Feng return O_WRONLY; 9716e71b04aSChenbo Feng return O_RDWR; 972aa79781bSDaniel Borkmann } 973aa79781bSDaniel Borkmann 97499c55f7dSAlexei Starovoitov /* helper macro to check that unused fields 'union bpf_attr' are zero */ 97599c55f7dSAlexei Starovoitov #define CHECK_ATTR(CMD) \ 97699c55f7dSAlexei Starovoitov memchr_inv((void *) &attr->CMD##_LAST_FIELD + \ 97799c55f7dSAlexei Starovoitov sizeof(attr->CMD##_LAST_FIELD), 0, \ 97899c55f7dSAlexei Starovoitov sizeof(*attr) - \ 97999c55f7dSAlexei Starovoitov offsetof(union bpf_attr, CMD##_LAST_FIELD) - \ 98099c55f7dSAlexei Starovoitov sizeof(attr->CMD##_LAST_FIELD)) != NULL 98199c55f7dSAlexei Starovoitov 9828e7ae251SMartin KaFai Lau /* dst and src must have at least "size" number of bytes. 9838e7ae251SMartin KaFai Lau * Return strlen on success and < 0 on error. 984cb4d2b3fSMartin KaFai Lau */ 9858e7ae251SMartin KaFai Lau int bpf_obj_name_cpy(char *dst, const char *src, unsigned int size) 986cb4d2b3fSMartin KaFai Lau { 9878e7ae251SMartin KaFai Lau const char *end = src + size; 9888e7ae251SMartin KaFai Lau const char *orig_src = src; 989cb4d2b3fSMartin KaFai Lau 9908e7ae251SMartin KaFai Lau memset(dst, 0, size); 9913e0ddc4fSDaniel Borkmann /* Copy all isalnum(), '_' and '.' chars. */ 992cb4d2b3fSMartin KaFai Lau while (src < end && *src) { 9933e0ddc4fSDaniel Borkmann if (!isalnum(*src) && 9943e0ddc4fSDaniel Borkmann *src != '_' && *src != '.') 995cb4d2b3fSMartin KaFai Lau return -EINVAL; 996cb4d2b3fSMartin KaFai Lau *dst++ = *src++; 997cb4d2b3fSMartin KaFai Lau } 998cb4d2b3fSMartin KaFai Lau 9998e7ae251SMartin KaFai Lau /* No '\0' found in "size" number of bytes */ 1000cb4d2b3fSMartin KaFai Lau if (src == end) 1001cb4d2b3fSMartin KaFai Lau return -EINVAL; 1002cb4d2b3fSMartin KaFai Lau 10038e7ae251SMartin KaFai Lau return src - orig_src; 1004cb4d2b3fSMartin KaFai Lau } 1005cb4d2b3fSMartin KaFai Lau 1006e8d2bec0SDaniel Borkmann int map_check_no_btf(const struct bpf_map *map, 10071b2b234bSRoman Gushchin const struct btf *btf, 1008e8d2bec0SDaniel Borkmann const struct btf_type *key_type, 1009e8d2bec0SDaniel Borkmann const struct btf_type *value_type) 1010e8d2bec0SDaniel Borkmann { 1011e8d2bec0SDaniel Borkmann return -ENOTSUPP; 1012e8d2bec0SDaniel Borkmann } 1013e8d2bec0SDaniel Borkmann 1014a177fc2bSAndrii Nakryiko static int map_check_btf(struct bpf_map *map, struct bpf_token *token, 1015a177fc2bSAndrii Nakryiko const struct btf *btf, u32 btf_key_id, u32 btf_value_id) 1016e8d2bec0SDaniel Borkmann { 1017e8d2bec0SDaniel Borkmann const struct btf_type *key_type, *value_type; 1018e8d2bec0SDaniel Borkmann u32 key_size, value_size; 1019e8d2bec0SDaniel Borkmann int ret = 0; 1020e8d2bec0SDaniel Borkmann 10212824ecb7SDaniel Borkmann /* Some maps allow key to be unspecified. */ 10222824ecb7SDaniel Borkmann if (btf_key_id) { 1023e8d2bec0SDaniel Borkmann key_type = btf_type_id_size(btf, &btf_key_id, &key_size); 1024e8d2bec0SDaniel Borkmann if (!key_type || key_size != map->key_size) 1025e8d2bec0SDaniel Borkmann return -EINVAL; 10262824ecb7SDaniel Borkmann } else { 10272824ecb7SDaniel Borkmann key_type = btf_type_by_id(btf, 0); 10282824ecb7SDaniel Borkmann if (!map->ops->map_check_btf) 10292824ecb7SDaniel Borkmann return -EINVAL; 10302824ecb7SDaniel Borkmann } 1031e8d2bec0SDaniel Borkmann 1032e8d2bec0SDaniel Borkmann value_type = btf_type_id_size(btf, &btf_value_id, &value_size); 1033e8d2bec0SDaniel Borkmann if (!value_type || value_size != map->value_size) 1034e8d2bec0SDaniel Borkmann return -EINVAL; 1035e8d2bec0SDaniel Borkmann 1036f0c5941fSKumar Kartikeya Dwivedi map->record = btf_parse_fields(btf, value_type, 10379c395c1bSDave Marchevsky BPF_SPIN_LOCK | BPF_TIMER | BPF_KPTR | BPF_LIST_HEAD | 1038d54730b5SDave Marchevsky BPF_RB_ROOT | BPF_REFCOUNT, 1039db559117SKumar Kartikeya Dwivedi map->value_size); 1040aa3496acSKumar Kartikeya Dwivedi if (!IS_ERR_OR_NULL(map->record)) { 1041aa3496acSKumar Kartikeya Dwivedi int i; 1042aa3496acSKumar Kartikeya Dwivedi 1043a177fc2bSAndrii Nakryiko if (!bpf_token_capable(token, CAP_BPF)) { 104461df10c7SKumar Kartikeya Dwivedi ret = -EPERM; 104561df10c7SKumar Kartikeya Dwivedi goto free_map_tab; 104661df10c7SKumar Kartikeya Dwivedi } 104761df10c7SKumar Kartikeya Dwivedi if (map->map_flags & (BPF_F_RDONLY_PROG | BPF_F_WRONLY_PROG)) { 104861df10c7SKumar Kartikeya Dwivedi ret = -EACCES; 104961df10c7SKumar Kartikeya Dwivedi goto free_map_tab; 105061df10c7SKumar Kartikeya Dwivedi } 1051aa3496acSKumar Kartikeya Dwivedi for (i = 0; i < sizeof(map->record->field_mask) * 8; i++) { 1052aa3496acSKumar Kartikeya Dwivedi switch (map->record->field_mask & (1 << i)) { 1053aa3496acSKumar Kartikeya Dwivedi case 0: 1054aa3496acSKumar Kartikeya Dwivedi continue; 1055db559117SKumar Kartikeya Dwivedi case BPF_SPIN_LOCK: 1056db559117SKumar Kartikeya Dwivedi if (map->map_type != BPF_MAP_TYPE_HASH && 1057db559117SKumar Kartikeya Dwivedi map->map_type != BPF_MAP_TYPE_ARRAY && 1058db559117SKumar Kartikeya Dwivedi map->map_type != BPF_MAP_TYPE_CGROUP_STORAGE && 1059db559117SKumar Kartikeya Dwivedi map->map_type != BPF_MAP_TYPE_SK_STORAGE && 1060db559117SKumar Kartikeya Dwivedi map->map_type != BPF_MAP_TYPE_INODE_STORAGE && 1061db559117SKumar Kartikeya Dwivedi map->map_type != BPF_MAP_TYPE_TASK_STORAGE && 1062db559117SKumar Kartikeya Dwivedi map->map_type != BPF_MAP_TYPE_CGRP_STORAGE) { 1063db559117SKumar Kartikeya Dwivedi ret = -EOPNOTSUPP; 1064db559117SKumar Kartikeya Dwivedi goto free_map_tab; 1065db559117SKumar Kartikeya Dwivedi } 1066db559117SKumar Kartikeya Dwivedi break; 1067db559117SKumar Kartikeya Dwivedi case BPF_TIMER: 1068db559117SKumar Kartikeya Dwivedi if (map->map_type != BPF_MAP_TYPE_HASH && 1069db559117SKumar Kartikeya Dwivedi map->map_type != BPF_MAP_TYPE_LRU_HASH && 1070db559117SKumar Kartikeya Dwivedi map->map_type != BPF_MAP_TYPE_ARRAY) { 1071c237bfa5SKumar Kartikeya Dwivedi ret = -EOPNOTSUPP; 1072db559117SKumar Kartikeya Dwivedi goto free_map_tab; 1073db559117SKumar Kartikeya Dwivedi } 1074db559117SKumar Kartikeya Dwivedi break; 1075aa3496acSKumar Kartikeya Dwivedi case BPF_KPTR_UNREF: 1076aa3496acSKumar Kartikeya Dwivedi case BPF_KPTR_REF: 107755db92f4SYonghong Song case BPF_KPTR_PERCPU: 1078d54730b5SDave Marchevsky case BPF_REFCOUNT: 107961df10c7SKumar Kartikeya Dwivedi if (map->map_type != BPF_MAP_TYPE_HASH && 108065334e64SKumar Kartikeya Dwivedi map->map_type != BPF_MAP_TYPE_PERCPU_HASH && 108161df10c7SKumar Kartikeya Dwivedi map->map_type != BPF_MAP_TYPE_LRU_HASH && 108265334e64SKumar Kartikeya Dwivedi map->map_type != BPF_MAP_TYPE_LRU_PERCPU_HASH && 10836df4ea1fSKumar Kartikeya Dwivedi map->map_type != BPF_MAP_TYPE_ARRAY && 10849db44fddSKumar Kartikeya Dwivedi map->map_type != BPF_MAP_TYPE_PERCPU_ARRAY && 10859db44fddSKumar Kartikeya Dwivedi map->map_type != BPF_MAP_TYPE_SK_STORAGE && 10869db44fddSKumar Kartikeya Dwivedi map->map_type != BPF_MAP_TYPE_INODE_STORAGE && 10879db44fddSKumar Kartikeya Dwivedi map->map_type != BPF_MAP_TYPE_TASK_STORAGE && 10889db44fddSKumar Kartikeya Dwivedi map->map_type != BPF_MAP_TYPE_CGRP_STORAGE) { 108961df10c7SKumar Kartikeya Dwivedi ret = -EOPNOTSUPP; 109061df10c7SKumar Kartikeya Dwivedi goto free_map_tab; 109161df10c7SKumar Kartikeya Dwivedi } 1092aa3496acSKumar Kartikeya Dwivedi break; 1093f0c5941fSKumar Kartikeya Dwivedi case BPF_LIST_HEAD: 10949c395c1bSDave Marchevsky case BPF_RB_ROOT: 1095f0c5941fSKumar Kartikeya Dwivedi if (map->map_type != BPF_MAP_TYPE_HASH && 1096f0c5941fSKumar Kartikeya Dwivedi map->map_type != BPF_MAP_TYPE_LRU_HASH && 1097f0c5941fSKumar Kartikeya Dwivedi map->map_type != BPF_MAP_TYPE_ARRAY) { 1098f0c5941fSKumar Kartikeya Dwivedi ret = -EOPNOTSUPP; 1099f0c5941fSKumar Kartikeya Dwivedi goto free_map_tab; 1100f0c5941fSKumar Kartikeya Dwivedi } 1101f0c5941fSKumar Kartikeya Dwivedi break; 1102aa3496acSKumar Kartikeya Dwivedi default: 1103aa3496acSKumar Kartikeya Dwivedi /* Fail if map_type checks are missing for a field type */ 1104aa3496acSKumar Kartikeya Dwivedi ret = -EOPNOTSUPP; 1105aa3496acSKumar Kartikeya Dwivedi goto free_map_tab; 1106aa3496acSKumar Kartikeya Dwivedi } 1107aa3496acSKumar Kartikeya Dwivedi } 110861df10c7SKumar Kartikeya Dwivedi } 1109e8d2bec0SDaniel Borkmann 1110865ce09aSKumar Kartikeya Dwivedi ret = btf_check_and_fixup_fields(btf, map->record); 1111865ce09aSKumar Kartikeya Dwivedi if (ret < 0) 1112865ce09aSKumar Kartikeya Dwivedi goto free_map_tab; 1113865ce09aSKumar Kartikeya Dwivedi 111461df10c7SKumar Kartikeya Dwivedi if (map->ops->map_check_btf) { 111561df10c7SKumar Kartikeya Dwivedi ret = map->ops->map_check_btf(map, btf, key_type, value_type); 111661df10c7SKumar Kartikeya Dwivedi if (ret < 0) 111761df10c7SKumar Kartikeya Dwivedi goto free_map_tab; 111861df10c7SKumar Kartikeya Dwivedi } 111961df10c7SKumar Kartikeya Dwivedi 112061df10c7SKumar Kartikeya Dwivedi return ret; 112161df10c7SKumar Kartikeya Dwivedi free_map_tab: 1122aa3496acSKumar Kartikeya Dwivedi bpf_map_free_record(map); 1123e8d2bec0SDaniel Borkmann return ret; 1124e8d2bec0SDaniel Borkmann } 1125e8d2bec0SDaniel Borkmann 1126ed1ad5a7SAndrii Nakryiko static bool bpf_net_capable(void) 1127ed1ad5a7SAndrii Nakryiko { 1128ed1ad5a7SAndrii Nakryiko return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN); 1129ed1ad5a7SAndrii Nakryiko } 1130ed1ad5a7SAndrii Nakryiko 1131a177fc2bSAndrii Nakryiko #define BPF_MAP_CREATE_LAST_FIELD map_token_fd 113299c55f7dSAlexei Starovoitov /* called via syscall */ 113399c55f7dSAlexei Starovoitov static int map_create(union bpf_attr *attr) 113499c55f7dSAlexei Starovoitov { 113522db4122SAndrii Nakryiko const struct bpf_map_ops *ops; 1136a177fc2bSAndrii Nakryiko struct bpf_token *token = NULL; 113796eabe7aSMartin KaFai Lau int numa_node = bpf_map_attr_numa_node(attr); 113822db4122SAndrii Nakryiko u32 map_type = attr->map_type; 113999c55f7dSAlexei Starovoitov struct bpf_map *map; 1140a177fc2bSAndrii Nakryiko bool token_flag; 11416e71b04aSChenbo Feng int f_flags; 114299c55f7dSAlexei Starovoitov int err; 114399c55f7dSAlexei Starovoitov 114499c55f7dSAlexei Starovoitov err = CHECK_ATTR(BPF_MAP_CREATE); 114599c55f7dSAlexei Starovoitov if (err) 114699c55f7dSAlexei Starovoitov return -EINVAL; 114799c55f7dSAlexei Starovoitov 1148a177fc2bSAndrii Nakryiko /* check BPF_F_TOKEN_FD flag, remember if it's set, and then clear it 1149a177fc2bSAndrii Nakryiko * to avoid per-map type checks tripping on unknown flag 1150a177fc2bSAndrii Nakryiko */ 1151a177fc2bSAndrii Nakryiko token_flag = attr->map_flags & BPF_F_TOKEN_FD; 1152a177fc2bSAndrii Nakryiko attr->map_flags &= ~BPF_F_TOKEN_FD; 1153a177fc2bSAndrii Nakryiko 115485d33df3SMartin KaFai Lau if (attr->btf_vmlinux_value_type_id) { 115585d33df3SMartin KaFai Lau if (attr->map_type != BPF_MAP_TYPE_STRUCT_OPS || 115685d33df3SMartin KaFai Lau attr->btf_key_type_id || attr->btf_value_type_id) 115785d33df3SMartin KaFai Lau return -EINVAL; 115885d33df3SMartin KaFai Lau } else if (attr->btf_key_type_id && !attr->btf_value_type_id) { 115985d33df3SMartin KaFai Lau return -EINVAL; 116085d33df3SMartin KaFai Lau } 116185d33df3SMartin KaFai Lau 11629330986cSJoanne Koong if (attr->map_type != BPF_MAP_TYPE_BLOOM_FILTER && 11639330986cSJoanne Koong attr->map_extra != 0) 11649330986cSJoanne Koong return -EINVAL; 11659330986cSJoanne Koong 11666e71b04aSChenbo Feng f_flags = bpf_get_file_flag(attr->map_flags); 11676e71b04aSChenbo Feng if (f_flags < 0) 11686e71b04aSChenbo Feng return f_flags; 11696e71b04aSChenbo Feng 117096eabe7aSMartin KaFai Lau if (numa_node != NUMA_NO_NODE && 117196e5ae4eSEric Dumazet ((unsigned int)numa_node >= nr_node_ids || 117296e5ae4eSEric Dumazet !node_online(numa_node))) 117396eabe7aSMartin KaFai Lau return -EINVAL; 117496eabe7aSMartin KaFai Lau 117599c55f7dSAlexei Starovoitov /* find map type and init map: hashtable vs rbtree vs bloom vs ... */ 117622db4122SAndrii Nakryiko map_type = attr->map_type; 117722db4122SAndrii Nakryiko if (map_type >= ARRAY_SIZE(bpf_map_types)) 117822db4122SAndrii Nakryiko return -EINVAL; 117922db4122SAndrii Nakryiko map_type = array_index_nospec(map_type, ARRAY_SIZE(bpf_map_types)); 118022db4122SAndrii Nakryiko ops = bpf_map_types[map_type]; 118122db4122SAndrii Nakryiko if (!ops) 118222db4122SAndrii Nakryiko return -EINVAL; 118322db4122SAndrii Nakryiko 118422db4122SAndrii Nakryiko if (ops->map_alloc_check) { 118522db4122SAndrii Nakryiko err = ops->map_alloc_check(attr); 118622db4122SAndrii Nakryiko if (err) 118722db4122SAndrii Nakryiko return err; 118822db4122SAndrii Nakryiko } 118922db4122SAndrii Nakryiko if (attr->map_ifindex) 119022db4122SAndrii Nakryiko ops = &bpf_map_offload_ops; 119122db4122SAndrii Nakryiko if (!ops->map_mem_usage) 119222db4122SAndrii Nakryiko return -EINVAL; 119322db4122SAndrii Nakryiko 1194a177fc2bSAndrii Nakryiko if (token_flag) { 1195a177fc2bSAndrii Nakryiko token = bpf_token_get_from_fd(attr->map_token_fd); 1196a177fc2bSAndrii Nakryiko if (IS_ERR(token)) 1197a177fc2bSAndrii Nakryiko return PTR_ERR(token); 1198a177fc2bSAndrii Nakryiko 1199a177fc2bSAndrii Nakryiko /* if current token doesn't grant map creation permissions, 1200a177fc2bSAndrii Nakryiko * then we can't use this token, so ignore it and rely on 1201a177fc2bSAndrii Nakryiko * system-wide capabilities checks 1202a177fc2bSAndrii Nakryiko */ 1203a177fc2bSAndrii Nakryiko if (!bpf_token_allow_cmd(token, BPF_MAP_CREATE) || 1204a177fc2bSAndrii Nakryiko !bpf_token_allow_map_type(token, attr->map_type)) { 1205a177fc2bSAndrii Nakryiko bpf_token_put(token); 1206a177fc2bSAndrii Nakryiko token = NULL; 1207a177fc2bSAndrii Nakryiko } 1208a177fc2bSAndrii Nakryiko } 1209a177fc2bSAndrii Nakryiko 1210a177fc2bSAndrii Nakryiko err = -EPERM; 1211a177fc2bSAndrii Nakryiko 12121d28635aSAndrii Nakryiko /* Intent here is for unprivileged_bpf_disabled to block BPF map 12131d28635aSAndrii Nakryiko * creation for unprivileged users; other actions depend 12141d28635aSAndrii Nakryiko * on fd availability and access to bpffs, so are dependent on 12151d28635aSAndrii Nakryiko * object creation success. Even with unprivileged BPF disabled, 12161d28635aSAndrii Nakryiko * capability checks are still carried out. 12171d28635aSAndrii Nakryiko */ 1218a177fc2bSAndrii Nakryiko if (sysctl_unprivileged_bpf_disabled && !bpf_token_capable(token, CAP_BPF)) 1219a177fc2bSAndrii Nakryiko goto put_token; 12201d28635aSAndrii Nakryiko 12216c3eba1cSAndrii Nakryiko /* check privileged map type permissions */ 12226c3eba1cSAndrii Nakryiko switch (map_type) { 12236c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_ARRAY: 12246c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_PERCPU_ARRAY: 12256c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_PROG_ARRAY: 12266c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_PERF_EVENT_ARRAY: 12276c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_CGROUP_ARRAY: 12286c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_ARRAY_OF_MAPS: 12296c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_HASH: 12306c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_PERCPU_HASH: 12316c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_HASH_OF_MAPS: 12326c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_RINGBUF: 12336c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_USER_RINGBUF: 12346c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_CGROUP_STORAGE: 12356c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE: 12366c3eba1cSAndrii Nakryiko /* unprivileged */ 12376c3eba1cSAndrii Nakryiko break; 12386c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_SK_STORAGE: 12396c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_INODE_STORAGE: 12406c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_TASK_STORAGE: 12416c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_CGRP_STORAGE: 12426c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_BLOOM_FILTER: 12436c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_LPM_TRIE: 12446c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_REUSEPORT_SOCKARRAY: 12456c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_STACK_TRACE: 12466c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_QUEUE: 12476c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_STACK: 12486c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_LRU_HASH: 12496c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_LRU_PERCPU_HASH: 12506c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_STRUCT_OPS: 12516c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_CPUMAP: 1252a177fc2bSAndrii Nakryiko if (!bpf_token_capable(token, CAP_BPF)) 1253a177fc2bSAndrii Nakryiko goto put_token; 12546c3eba1cSAndrii Nakryiko break; 12556c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_SOCKMAP: 12566c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_SOCKHASH: 12576c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_DEVMAP: 12586c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_DEVMAP_HASH: 12596c3eba1cSAndrii Nakryiko case BPF_MAP_TYPE_XSKMAP: 1260a177fc2bSAndrii Nakryiko if (!bpf_token_capable(token, CAP_NET_ADMIN)) 1261a177fc2bSAndrii Nakryiko goto put_token; 12626c3eba1cSAndrii Nakryiko break; 12636c3eba1cSAndrii Nakryiko default: 12646c3eba1cSAndrii Nakryiko WARN(1, "unsupported map type %d", map_type); 1265a177fc2bSAndrii Nakryiko goto put_token; 12666c3eba1cSAndrii Nakryiko } 12676c3eba1cSAndrii Nakryiko 126822db4122SAndrii Nakryiko map = ops->map_alloc(attr); 1269a177fc2bSAndrii Nakryiko if (IS_ERR(map)) { 1270a177fc2bSAndrii Nakryiko err = PTR_ERR(map); 1271a177fc2bSAndrii Nakryiko goto put_token; 1272a177fc2bSAndrii Nakryiko } 127322db4122SAndrii Nakryiko map->ops = ops; 127422db4122SAndrii Nakryiko map->map_type = map_type; 127599c55f7dSAlexei Starovoitov 12768e7ae251SMartin KaFai Lau err = bpf_obj_name_cpy(map->name, attr->map_name, 12778e7ae251SMartin KaFai Lau sizeof(attr->map_name)); 12788e7ae251SMartin KaFai Lau if (err < 0) 1279b936ca64SRoman Gushchin goto free_map; 1280ad5b177bSMartin KaFai Lau 12811e0bd5a0SAndrii Nakryiko atomic64_set(&map->refcnt, 1); 12821e0bd5a0SAndrii Nakryiko atomic64_set(&map->usercnt, 1); 1283fc970227SAndrii Nakryiko mutex_init(&map->freeze_mutex); 1284f45d5b6cSToke Hoiland-Jorgensen spin_lock_init(&map->owner.lock); 128599c55f7dSAlexei Starovoitov 128685d33df3SMartin KaFai Lau if (attr->btf_key_type_id || attr->btf_value_type_id || 128785d33df3SMartin KaFai Lau /* Even the map's value is a kernel's struct, 128885d33df3SMartin KaFai Lau * the bpf_prog.o must have BTF to begin with 128985d33df3SMartin KaFai Lau * to figure out the corresponding kernel's 129085d33df3SMartin KaFai Lau * counter part. Thus, attr->btf_fd has 129185d33df3SMartin KaFai Lau * to be valid also. 129285d33df3SMartin KaFai Lau */ 129385d33df3SMartin KaFai Lau attr->btf_vmlinux_value_type_id) { 1294a26ca7c9SMartin KaFai Lau struct btf *btf; 1295a26ca7c9SMartin KaFai Lau 1296a26ca7c9SMartin KaFai Lau btf = btf_get_by_fd(attr->btf_fd); 1297a26ca7c9SMartin KaFai Lau if (IS_ERR(btf)) { 1298a26ca7c9SMartin KaFai Lau err = PTR_ERR(btf); 1299b936ca64SRoman Gushchin goto free_map; 1300a26ca7c9SMartin KaFai Lau } 1301350a5c4dSAlexei Starovoitov if (btf_is_kernel(btf)) { 1302350a5c4dSAlexei Starovoitov btf_put(btf); 1303350a5c4dSAlexei Starovoitov err = -EACCES; 1304350a5c4dSAlexei Starovoitov goto free_map; 1305350a5c4dSAlexei Starovoitov } 130685d33df3SMartin KaFai Lau map->btf = btf; 1307a26ca7c9SMartin KaFai Lau 130885d33df3SMartin KaFai Lau if (attr->btf_value_type_id) { 1309a177fc2bSAndrii Nakryiko err = map_check_btf(map, token, btf, attr->btf_key_type_id, 13109b2cf328SMartin KaFai Lau attr->btf_value_type_id); 131185d33df3SMartin KaFai Lau if (err) 1312b936ca64SRoman Gushchin goto free_map; 1313a26ca7c9SMartin KaFai Lau } 1314a26ca7c9SMartin KaFai Lau 13159b2cf328SMartin KaFai Lau map->btf_key_type_id = attr->btf_key_type_id; 13169b2cf328SMartin KaFai Lau map->btf_value_type_id = attr->btf_value_type_id; 131785d33df3SMartin KaFai Lau map->btf_vmlinux_value_type_id = 131885d33df3SMartin KaFai Lau attr->btf_vmlinux_value_type_id; 1319a26ca7c9SMartin KaFai Lau } 1320a26ca7c9SMartin KaFai Lau 1321d17aff80SAndrii Nakryiko err = security_bpf_map_alloc(map); 13224d7d7f69SKumar Kartikeya Dwivedi if (err) 1323d17aff80SAndrii Nakryiko goto free_map; 13244d7d7f69SKumar Kartikeya Dwivedi 1325f3f1c054SMartin KaFai Lau err = bpf_map_alloc_id(map); 1326f3f1c054SMartin KaFai Lau if (err) 1327b936ca64SRoman Gushchin goto free_map_sec; 1328f3f1c054SMartin KaFai Lau 132948edc1f7SRoman Gushchin bpf_map_save_memcg(map); 1330a177fc2bSAndrii Nakryiko bpf_token_put(token); 133148edc1f7SRoman Gushchin 13326e71b04aSChenbo Feng err = bpf_map_new_fd(map, f_flags); 1333bd5f5f4eSMartin KaFai Lau if (err < 0) { 1334bd5f5f4eSMartin KaFai Lau /* failed to allocate fd. 1335352d20d6SPeng Sun * bpf_map_put_with_uref() is needed because the above 1336bd5f5f4eSMartin KaFai Lau * bpf_map_alloc_id() has published the map 1337bd5f5f4eSMartin KaFai Lau * to the userspace and the userspace may 1338bd5f5f4eSMartin KaFai Lau * have refcnt-ed it through BPF_MAP_GET_FD_BY_ID. 1339bd5f5f4eSMartin KaFai Lau */ 1340352d20d6SPeng Sun bpf_map_put_with_uref(map); 1341bd5f5f4eSMartin KaFai Lau return err; 1342bd5f5f4eSMartin KaFai Lau } 134399c55f7dSAlexei Starovoitov 134499c55f7dSAlexei Starovoitov return err; 134599c55f7dSAlexei Starovoitov 1346afdb09c7SChenbo Feng free_map_sec: 1347afdb09c7SChenbo Feng security_bpf_map_free(map); 1348b936ca64SRoman Gushchin free_map: 1349a26ca7c9SMartin KaFai Lau btf_put(map->btf); 135099c55f7dSAlexei Starovoitov map->ops->map_free(map); 1351a177fc2bSAndrii Nakryiko put_token: 1352a177fc2bSAndrii Nakryiko bpf_token_put(token); 135399c55f7dSAlexei Starovoitov return err; 135499c55f7dSAlexei Starovoitov } 135599c55f7dSAlexei Starovoitov 1356db20fd2bSAlexei Starovoitov /* if error is returned, fd is released. 1357db20fd2bSAlexei Starovoitov * On success caller should complete fd access with matching fdput() 1358db20fd2bSAlexei Starovoitov */ 1359c2101297SDaniel Borkmann struct bpf_map *__bpf_map_get(struct fd f) 1360db20fd2bSAlexei Starovoitov { 1361db20fd2bSAlexei Starovoitov if (!f.file) 1362db20fd2bSAlexei Starovoitov return ERR_PTR(-EBADF); 1363db20fd2bSAlexei Starovoitov if (f.file->f_op != &bpf_map_fops) { 1364db20fd2bSAlexei Starovoitov fdput(f); 1365db20fd2bSAlexei Starovoitov return ERR_PTR(-EINVAL); 1366db20fd2bSAlexei Starovoitov } 1367db20fd2bSAlexei Starovoitov 1368c2101297SDaniel Borkmann return f.file->private_data; 1369c2101297SDaniel Borkmann } 1370c2101297SDaniel Borkmann 13711e0bd5a0SAndrii Nakryiko void bpf_map_inc(struct bpf_map *map) 1372c9da161cSDaniel Borkmann { 13731e0bd5a0SAndrii Nakryiko atomic64_inc(&map->refcnt); 1374c9da161cSDaniel Borkmann } 1375630a4d38SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_map_inc); 1376c9da161cSDaniel Borkmann 13771e0bd5a0SAndrii Nakryiko void bpf_map_inc_with_uref(struct bpf_map *map) 13781e0bd5a0SAndrii Nakryiko { 13791e0bd5a0SAndrii Nakryiko atomic64_inc(&map->refcnt); 13801e0bd5a0SAndrii Nakryiko atomic64_inc(&map->usercnt); 13811e0bd5a0SAndrii Nakryiko } 13821e0bd5a0SAndrii Nakryiko EXPORT_SYMBOL_GPL(bpf_map_inc_with_uref); 13831e0bd5a0SAndrii Nakryiko 13841ed4d924SMartin KaFai Lau struct bpf_map *bpf_map_get(u32 ufd) 13851ed4d924SMartin KaFai Lau { 13861ed4d924SMartin KaFai Lau struct fd f = fdget(ufd); 13871ed4d924SMartin KaFai Lau struct bpf_map *map; 13881ed4d924SMartin KaFai Lau 13891ed4d924SMartin KaFai Lau map = __bpf_map_get(f); 13901ed4d924SMartin KaFai Lau if (IS_ERR(map)) 13911ed4d924SMartin KaFai Lau return map; 13921ed4d924SMartin KaFai Lau 13931ed4d924SMartin KaFai Lau bpf_map_inc(map); 13941ed4d924SMartin KaFai Lau fdput(f); 13951ed4d924SMartin KaFai Lau 13961ed4d924SMartin KaFai Lau return map; 13971ed4d924SMartin KaFai Lau } 1398b1d18a75SAlexei Starovoitov EXPORT_SYMBOL(bpf_map_get); 13991ed4d924SMartin KaFai Lau 1400c9da161cSDaniel Borkmann struct bpf_map *bpf_map_get_with_uref(u32 ufd) 1401c2101297SDaniel Borkmann { 1402c2101297SDaniel Borkmann struct fd f = fdget(ufd); 1403c2101297SDaniel Borkmann struct bpf_map *map; 1404c2101297SDaniel Borkmann 1405c2101297SDaniel Borkmann map = __bpf_map_get(f); 1406c2101297SDaniel Borkmann if (IS_ERR(map)) 1407c2101297SDaniel Borkmann return map; 1408c2101297SDaniel Borkmann 14091e0bd5a0SAndrii Nakryiko bpf_map_inc_with_uref(map); 1410c2101297SDaniel Borkmann fdput(f); 1411db20fd2bSAlexei Starovoitov 1412db20fd2bSAlexei Starovoitov return map; 1413db20fd2bSAlexei Starovoitov } 1414db20fd2bSAlexei Starovoitov 1415b671c206SKui-Feng Lee /* map_idr_lock should have been held or the map should have been 1416b671c206SKui-Feng Lee * protected by rcu read lock. 1417b671c206SKui-Feng Lee */ 1418b671c206SKui-Feng Lee struct bpf_map *__bpf_map_inc_not_zero(struct bpf_map *map, bool uref) 1419bd5f5f4eSMartin KaFai Lau { 1420bd5f5f4eSMartin KaFai Lau int refold; 1421bd5f5f4eSMartin KaFai Lau 14221e0bd5a0SAndrii Nakryiko refold = atomic64_fetch_add_unless(&map->refcnt, 1, 0); 1423bd5f5f4eSMartin KaFai Lau if (!refold) 1424bd5f5f4eSMartin KaFai Lau return ERR_PTR(-ENOENT); 1425bd5f5f4eSMartin KaFai Lau if (uref) 14261e0bd5a0SAndrii Nakryiko atomic64_inc(&map->usercnt); 1427bd5f5f4eSMartin KaFai Lau 1428bd5f5f4eSMartin KaFai Lau return map; 1429bd5f5f4eSMartin KaFai Lau } 1430bd5f5f4eSMartin KaFai Lau 14311e0bd5a0SAndrii Nakryiko struct bpf_map *bpf_map_inc_not_zero(struct bpf_map *map) 1432b0e4701cSStanislav Fomichev { 1433b0e4701cSStanislav Fomichev spin_lock_bh(&map_idr_lock); 14341e0bd5a0SAndrii Nakryiko map = __bpf_map_inc_not_zero(map, false); 1435b0e4701cSStanislav Fomichev spin_unlock_bh(&map_idr_lock); 1436b0e4701cSStanislav Fomichev 1437b0e4701cSStanislav Fomichev return map; 1438b0e4701cSStanislav Fomichev } 1439b0e4701cSStanislav Fomichev EXPORT_SYMBOL_GPL(bpf_map_inc_not_zero); 1440b0e4701cSStanislav Fomichev 1441b8cdc051SAlexei Starovoitov int __weak bpf_stackmap_copy(struct bpf_map *map, void *key, void *value) 1442b8cdc051SAlexei Starovoitov { 1443b8cdc051SAlexei Starovoitov return -ENOTSUPP; 1444b8cdc051SAlexei Starovoitov } 1445b8cdc051SAlexei Starovoitov 1446c9d29f46SMauricio Vasquez B static void *__bpf_copy_key(void __user *ukey, u64 key_size) 1447c9d29f46SMauricio Vasquez B { 1448c9d29f46SMauricio Vasquez B if (key_size) 144944779a4bSStanislav Fomichev return vmemdup_user(ukey, key_size); 1450c9d29f46SMauricio Vasquez B 1451c9d29f46SMauricio Vasquez B if (ukey) 1452c9d29f46SMauricio Vasquez B return ERR_PTR(-EINVAL); 1453c9d29f46SMauricio Vasquez B 1454c9d29f46SMauricio Vasquez B return NULL; 1455c9d29f46SMauricio Vasquez B } 1456c9d29f46SMauricio Vasquez B 1457af2ac3e1SAlexei Starovoitov static void *___bpf_copy_key(bpfptr_t ukey, u64 key_size) 1458af2ac3e1SAlexei Starovoitov { 1459af2ac3e1SAlexei Starovoitov if (key_size) 146044779a4bSStanislav Fomichev return kvmemdup_bpfptr(ukey, key_size); 1461af2ac3e1SAlexei Starovoitov 1462af2ac3e1SAlexei Starovoitov if (!bpfptr_is_null(ukey)) 1463af2ac3e1SAlexei Starovoitov return ERR_PTR(-EINVAL); 1464af2ac3e1SAlexei Starovoitov 1465af2ac3e1SAlexei Starovoitov return NULL; 1466af2ac3e1SAlexei Starovoitov } 1467af2ac3e1SAlexei Starovoitov 1468db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */ 146996049f3aSAlexei Starovoitov #define BPF_MAP_LOOKUP_ELEM_LAST_FIELD flags 1470db20fd2bSAlexei Starovoitov 1471db20fd2bSAlexei Starovoitov static int map_lookup_elem(union bpf_attr *attr) 1472db20fd2bSAlexei Starovoitov { 1473535e7b4bSMickaël Salaün void __user *ukey = u64_to_user_ptr(attr->key); 1474535e7b4bSMickaël Salaün void __user *uvalue = u64_to_user_ptr(attr->value); 1475db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 1476db20fd2bSAlexei Starovoitov struct bpf_map *map; 147715c14a3dSBrian Vazquez void *key, *value; 147815a07b33SAlexei Starovoitov u32 value_size; 1479592867bfSDaniel Borkmann struct fd f; 1480db20fd2bSAlexei Starovoitov int err; 1481db20fd2bSAlexei Starovoitov 1482db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM)) 1483db20fd2bSAlexei Starovoitov return -EINVAL; 1484db20fd2bSAlexei Starovoitov 148596049f3aSAlexei Starovoitov if (attr->flags & ~BPF_F_LOCK) 148696049f3aSAlexei Starovoitov return -EINVAL; 148796049f3aSAlexei Starovoitov 1488592867bfSDaniel Borkmann f = fdget(ufd); 1489c2101297SDaniel Borkmann map = __bpf_map_get(f); 1490db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 1491db20fd2bSAlexei Starovoitov return PTR_ERR(map); 149287df15deSDaniel Borkmann if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ)) { 14936e71b04aSChenbo Feng err = -EPERM; 14946e71b04aSChenbo Feng goto err_put; 14956e71b04aSChenbo Feng } 14966e71b04aSChenbo Feng 149796049f3aSAlexei Starovoitov if ((attr->flags & BPF_F_LOCK) && 1498db559117SKumar Kartikeya Dwivedi !btf_record_has_field(map->record, BPF_SPIN_LOCK)) { 149996049f3aSAlexei Starovoitov err = -EINVAL; 150096049f3aSAlexei Starovoitov goto err_put; 150196049f3aSAlexei Starovoitov } 150296049f3aSAlexei Starovoitov 1503c9d29f46SMauricio Vasquez B key = __bpf_copy_key(ukey, map->key_size); 1504e4448ed8SAl Viro if (IS_ERR(key)) { 1505e4448ed8SAl Viro err = PTR_ERR(key); 1506db20fd2bSAlexei Starovoitov goto err_put; 1507e4448ed8SAl Viro } 1508db20fd2bSAlexei Starovoitov 150915c14a3dSBrian Vazquez value_size = bpf_map_value_size(map); 151015a07b33SAlexei Starovoitov 15118ebe667cSAlexei Starovoitov err = -ENOMEM; 1512f0dce1d9SStanislav Fomichev value = kvmalloc(value_size, GFP_USER | __GFP_NOWARN); 1513db20fd2bSAlexei Starovoitov if (!value) 15148ebe667cSAlexei Starovoitov goto free_key; 15158ebe667cSAlexei Starovoitov 15169330986cSJoanne Koong if (map->map_type == BPF_MAP_TYPE_BLOOM_FILTER) { 15179330986cSJoanne Koong if (copy_from_user(value, uvalue, value_size)) 15189330986cSJoanne Koong err = -EFAULT; 15199330986cSJoanne Koong else 15209330986cSJoanne Koong err = bpf_map_copy_value(map, key, value, attr->flags); 15219330986cSJoanne Koong goto free_value; 15229330986cSJoanne Koong } 15239330986cSJoanne Koong 152415c14a3dSBrian Vazquez err = bpf_map_copy_value(map, key, value, attr->flags); 152515a07b33SAlexei Starovoitov if (err) 15268ebe667cSAlexei Starovoitov goto free_value; 1527db20fd2bSAlexei Starovoitov 1528db20fd2bSAlexei Starovoitov err = -EFAULT; 152915a07b33SAlexei Starovoitov if (copy_to_user(uvalue, value, value_size) != 0) 15308ebe667cSAlexei Starovoitov goto free_value; 1531db20fd2bSAlexei Starovoitov 1532db20fd2bSAlexei Starovoitov err = 0; 1533db20fd2bSAlexei Starovoitov 15348ebe667cSAlexei Starovoitov free_value: 1535f0dce1d9SStanislav Fomichev kvfree(value); 1536db20fd2bSAlexei Starovoitov free_key: 153744779a4bSStanislav Fomichev kvfree(key); 1538db20fd2bSAlexei Starovoitov err_put: 1539db20fd2bSAlexei Starovoitov fdput(f); 1540db20fd2bSAlexei Starovoitov return err; 1541db20fd2bSAlexei Starovoitov } 1542db20fd2bSAlexei Starovoitov 15431ae80cf3SDaniel Colascione 15443274f520SAlexei Starovoitov #define BPF_MAP_UPDATE_ELEM_LAST_FIELD flags 1545db20fd2bSAlexei Starovoitov 1546af2ac3e1SAlexei Starovoitov static int map_update_elem(union bpf_attr *attr, bpfptr_t uattr) 1547db20fd2bSAlexei Starovoitov { 1548af2ac3e1SAlexei Starovoitov bpfptr_t ukey = make_bpfptr(attr->key, uattr.is_kernel); 1549af2ac3e1SAlexei Starovoitov bpfptr_t uvalue = make_bpfptr(attr->value, uattr.is_kernel); 1550db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 1551db20fd2bSAlexei Starovoitov struct bpf_map *map; 1552db20fd2bSAlexei Starovoitov void *key, *value; 155315a07b33SAlexei Starovoitov u32 value_size; 1554592867bfSDaniel Borkmann struct fd f; 1555db20fd2bSAlexei Starovoitov int err; 1556db20fd2bSAlexei Starovoitov 1557db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_UPDATE_ELEM)) 1558db20fd2bSAlexei Starovoitov return -EINVAL; 1559db20fd2bSAlexei Starovoitov 1560592867bfSDaniel Borkmann f = fdget(ufd); 1561c2101297SDaniel Borkmann map = __bpf_map_get(f); 1562db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 1563db20fd2bSAlexei Starovoitov return PTR_ERR(map); 1564353050beSDaniel Borkmann bpf_map_write_active_inc(map); 156587df15deSDaniel Borkmann if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) { 15666e71b04aSChenbo Feng err = -EPERM; 15676e71b04aSChenbo Feng goto err_put; 15686e71b04aSChenbo Feng } 15696e71b04aSChenbo Feng 157096049f3aSAlexei Starovoitov if ((attr->flags & BPF_F_LOCK) && 1571db559117SKumar Kartikeya Dwivedi !btf_record_has_field(map->record, BPF_SPIN_LOCK)) { 157296049f3aSAlexei Starovoitov err = -EINVAL; 157396049f3aSAlexei Starovoitov goto err_put; 157496049f3aSAlexei Starovoitov } 157596049f3aSAlexei Starovoitov 1576af2ac3e1SAlexei Starovoitov key = ___bpf_copy_key(ukey, map->key_size); 1577e4448ed8SAl Viro if (IS_ERR(key)) { 1578e4448ed8SAl Viro err = PTR_ERR(key); 1579db20fd2bSAlexei Starovoitov goto err_put; 1580e4448ed8SAl Viro } 1581db20fd2bSAlexei Starovoitov 1582f0dce1d9SStanislav Fomichev value_size = bpf_map_value_size(map); 1583a02c118eSWang Yufen value = kvmemdup_bpfptr(uvalue, value_size); 1584a02c118eSWang Yufen if (IS_ERR(value)) { 1585a02c118eSWang Yufen err = PTR_ERR(value); 1586db20fd2bSAlexei Starovoitov goto free_key; 1587a02c118eSWang Yufen } 1588db20fd2bSAlexei Starovoitov 15893af43ba4SHou Tao err = bpf_map_update_value(map, f.file, key, value, attr->flags); 159067ad2c73SHou Tao if (!err) 159137ba5b59SHou Tao maybe_wait_bpf_programs(map); 15926710e112SJesper Dangaard Brouer 1593f0dce1d9SStanislav Fomichev kvfree(value); 1594db20fd2bSAlexei Starovoitov free_key: 159544779a4bSStanislav Fomichev kvfree(key); 1596db20fd2bSAlexei Starovoitov err_put: 1597353050beSDaniel Borkmann bpf_map_write_active_dec(map); 1598db20fd2bSAlexei Starovoitov fdput(f); 1599db20fd2bSAlexei Starovoitov return err; 1600db20fd2bSAlexei Starovoitov } 1601db20fd2bSAlexei Starovoitov 1602db20fd2bSAlexei Starovoitov #define BPF_MAP_DELETE_ELEM_LAST_FIELD key 1603db20fd2bSAlexei Starovoitov 1604b88df697SBenjamin Tissoires static int map_delete_elem(union bpf_attr *attr, bpfptr_t uattr) 1605db20fd2bSAlexei Starovoitov { 1606b88df697SBenjamin Tissoires bpfptr_t ukey = make_bpfptr(attr->key, uattr.is_kernel); 1607db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 1608db20fd2bSAlexei Starovoitov struct bpf_map *map; 1609592867bfSDaniel Borkmann struct fd f; 1610db20fd2bSAlexei Starovoitov void *key; 1611db20fd2bSAlexei Starovoitov int err; 1612db20fd2bSAlexei Starovoitov 1613db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_DELETE_ELEM)) 1614db20fd2bSAlexei Starovoitov return -EINVAL; 1615db20fd2bSAlexei Starovoitov 1616592867bfSDaniel Borkmann f = fdget(ufd); 1617c2101297SDaniel Borkmann map = __bpf_map_get(f); 1618db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 1619db20fd2bSAlexei Starovoitov return PTR_ERR(map); 1620353050beSDaniel Borkmann bpf_map_write_active_inc(map); 162187df15deSDaniel Borkmann if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) { 16226e71b04aSChenbo Feng err = -EPERM; 16236e71b04aSChenbo Feng goto err_put; 16246e71b04aSChenbo Feng } 16256e71b04aSChenbo Feng 1626b88df697SBenjamin Tissoires key = ___bpf_copy_key(ukey, map->key_size); 1627e4448ed8SAl Viro if (IS_ERR(key)) { 1628e4448ed8SAl Viro err = PTR_ERR(key); 1629db20fd2bSAlexei Starovoitov goto err_put; 1630e4448ed8SAl Viro } 1631db20fd2bSAlexei Starovoitov 16329d03ebc7SStanislav Fomichev if (bpf_map_is_offloaded(map)) { 1633a3884572SJakub Kicinski err = bpf_map_offload_delete_elem(map, key); 1634a3884572SJakub Kicinski goto out; 163585d33df3SMartin KaFai Lau } else if (IS_FD_PROG_ARRAY(map) || 163685d33df3SMartin KaFai Lau map->map_type == BPF_MAP_TYPE_STRUCT_OPS) { 163785d33df3SMartin KaFai Lau /* These maps require sleepable context */ 1638da765a2fSDaniel Borkmann err = map->ops->map_delete_elem(map, key); 1639da765a2fSDaniel Borkmann goto out; 1640a3884572SJakub Kicinski } 1641a3884572SJakub Kicinski 1642b6e5dae1SThomas Gleixner bpf_disable_instrumentation(); 1643db20fd2bSAlexei Starovoitov rcu_read_lock(); 1644db20fd2bSAlexei Starovoitov err = map->ops->map_delete_elem(map, key); 1645db20fd2bSAlexei Starovoitov rcu_read_unlock(); 1646b6e5dae1SThomas Gleixner bpf_enable_instrumentation(); 164767ad2c73SHou Tao if (!err) 16481ae80cf3SDaniel Colascione maybe_wait_bpf_programs(map); 1649a3884572SJakub Kicinski out: 165044779a4bSStanislav Fomichev kvfree(key); 1651db20fd2bSAlexei Starovoitov err_put: 1652353050beSDaniel Borkmann bpf_map_write_active_dec(map); 1653db20fd2bSAlexei Starovoitov fdput(f); 1654db20fd2bSAlexei Starovoitov return err; 1655db20fd2bSAlexei Starovoitov } 1656db20fd2bSAlexei Starovoitov 1657db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */ 1658db20fd2bSAlexei Starovoitov #define BPF_MAP_GET_NEXT_KEY_LAST_FIELD next_key 1659db20fd2bSAlexei Starovoitov 1660db20fd2bSAlexei Starovoitov static int map_get_next_key(union bpf_attr *attr) 1661db20fd2bSAlexei Starovoitov { 1662535e7b4bSMickaël Salaün void __user *ukey = u64_to_user_ptr(attr->key); 1663535e7b4bSMickaël Salaün void __user *unext_key = u64_to_user_ptr(attr->next_key); 1664db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 1665db20fd2bSAlexei Starovoitov struct bpf_map *map; 1666db20fd2bSAlexei Starovoitov void *key, *next_key; 1667592867bfSDaniel Borkmann struct fd f; 1668db20fd2bSAlexei Starovoitov int err; 1669db20fd2bSAlexei Starovoitov 1670db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_GET_NEXT_KEY)) 1671db20fd2bSAlexei Starovoitov return -EINVAL; 1672db20fd2bSAlexei Starovoitov 1673592867bfSDaniel Borkmann f = fdget(ufd); 1674c2101297SDaniel Borkmann map = __bpf_map_get(f); 1675db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 1676db20fd2bSAlexei Starovoitov return PTR_ERR(map); 167787df15deSDaniel Borkmann if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ)) { 16786e71b04aSChenbo Feng err = -EPERM; 16796e71b04aSChenbo Feng goto err_put; 16806e71b04aSChenbo Feng } 16816e71b04aSChenbo Feng 16828fe45924STeng Qin if (ukey) { 1683c9d29f46SMauricio Vasquez B key = __bpf_copy_key(ukey, map->key_size); 1684e4448ed8SAl Viro if (IS_ERR(key)) { 1685e4448ed8SAl Viro err = PTR_ERR(key); 1686db20fd2bSAlexei Starovoitov goto err_put; 1687e4448ed8SAl Viro } 16888fe45924STeng Qin } else { 16898fe45924STeng Qin key = NULL; 16908fe45924STeng Qin } 1691db20fd2bSAlexei Starovoitov 1692db20fd2bSAlexei Starovoitov err = -ENOMEM; 169344779a4bSStanislav Fomichev next_key = kvmalloc(map->key_size, GFP_USER); 1694db20fd2bSAlexei Starovoitov if (!next_key) 1695db20fd2bSAlexei Starovoitov goto free_key; 1696db20fd2bSAlexei Starovoitov 16979d03ebc7SStanislav Fomichev if (bpf_map_is_offloaded(map)) { 1698a3884572SJakub Kicinski err = bpf_map_offload_get_next_key(map, key, next_key); 1699a3884572SJakub Kicinski goto out; 1700a3884572SJakub Kicinski } 1701a3884572SJakub Kicinski 1702db20fd2bSAlexei Starovoitov rcu_read_lock(); 1703db20fd2bSAlexei Starovoitov err = map->ops->map_get_next_key(map, key, next_key); 1704db20fd2bSAlexei Starovoitov rcu_read_unlock(); 1705a3884572SJakub Kicinski out: 1706db20fd2bSAlexei Starovoitov if (err) 1707db20fd2bSAlexei Starovoitov goto free_next_key; 1708db20fd2bSAlexei Starovoitov 1709db20fd2bSAlexei Starovoitov err = -EFAULT; 1710db20fd2bSAlexei Starovoitov if (copy_to_user(unext_key, next_key, map->key_size) != 0) 1711db20fd2bSAlexei Starovoitov goto free_next_key; 1712db20fd2bSAlexei Starovoitov 1713db20fd2bSAlexei Starovoitov err = 0; 1714db20fd2bSAlexei Starovoitov 1715db20fd2bSAlexei Starovoitov free_next_key: 171644779a4bSStanislav Fomichev kvfree(next_key); 1717db20fd2bSAlexei Starovoitov free_key: 171844779a4bSStanislav Fomichev kvfree(key); 1719db20fd2bSAlexei Starovoitov err_put: 1720db20fd2bSAlexei Starovoitov fdput(f); 1721db20fd2bSAlexei Starovoitov return err; 1722db20fd2bSAlexei Starovoitov } 1723db20fd2bSAlexei Starovoitov 1724aa2e93b8SBrian Vazquez int generic_map_delete_batch(struct bpf_map *map, 1725aa2e93b8SBrian Vazquez const union bpf_attr *attr, 1726aa2e93b8SBrian Vazquez union bpf_attr __user *uattr) 1727aa2e93b8SBrian Vazquez { 1728aa2e93b8SBrian Vazquez void __user *keys = u64_to_user_ptr(attr->batch.keys); 1729aa2e93b8SBrian Vazquez u32 cp, max_count; 1730aa2e93b8SBrian Vazquez int err = 0; 1731aa2e93b8SBrian Vazquez void *key; 1732aa2e93b8SBrian Vazquez 1733aa2e93b8SBrian Vazquez if (attr->batch.elem_flags & ~BPF_F_LOCK) 1734aa2e93b8SBrian Vazquez return -EINVAL; 1735aa2e93b8SBrian Vazquez 1736aa2e93b8SBrian Vazquez if ((attr->batch.elem_flags & BPF_F_LOCK) && 1737db559117SKumar Kartikeya Dwivedi !btf_record_has_field(map->record, BPF_SPIN_LOCK)) { 1738aa2e93b8SBrian Vazquez return -EINVAL; 1739aa2e93b8SBrian Vazquez } 1740aa2e93b8SBrian Vazquez 1741aa2e93b8SBrian Vazquez max_count = attr->batch.count; 1742aa2e93b8SBrian Vazquez if (!max_count) 1743aa2e93b8SBrian Vazquez return 0; 1744aa2e93b8SBrian Vazquez 174506e5c999SHou Tao if (put_user(0, &uattr->batch.count)) 174606e5c999SHou Tao return -EFAULT; 174706e5c999SHou Tao 174844779a4bSStanislav Fomichev key = kvmalloc(map->key_size, GFP_USER | __GFP_NOWARN); 17492e3a94aaSBrian Vazquez if (!key) 17502e3a94aaSBrian Vazquez return -ENOMEM; 17512e3a94aaSBrian Vazquez 1752aa2e93b8SBrian Vazquez for (cp = 0; cp < max_count; cp++) { 17532e3a94aaSBrian Vazquez err = -EFAULT; 17542e3a94aaSBrian Vazquez if (copy_from_user(key, keys + cp * map->key_size, 17552e3a94aaSBrian Vazquez map->key_size)) 1756aa2e93b8SBrian Vazquez break; 1757aa2e93b8SBrian Vazquez 17589d03ebc7SStanislav Fomichev if (bpf_map_is_offloaded(map)) { 1759aa2e93b8SBrian Vazquez err = bpf_map_offload_delete_elem(map, key); 1760aa2e93b8SBrian Vazquez break; 1761aa2e93b8SBrian Vazquez } 1762aa2e93b8SBrian Vazquez 1763b6e5dae1SThomas Gleixner bpf_disable_instrumentation(); 1764aa2e93b8SBrian Vazquez rcu_read_lock(); 1765aa2e93b8SBrian Vazquez err = map->ops->map_delete_elem(map, key); 1766aa2e93b8SBrian Vazquez rcu_read_unlock(); 1767b6e5dae1SThomas Gleixner bpf_enable_instrumentation(); 1768aa2e93b8SBrian Vazquez if (err) 1769aa2e93b8SBrian Vazquez break; 177075134f16SEric Dumazet cond_resched(); 1771aa2e93b8SBrian Vazquez } 1772aa2e93b8SBrian Vazquez if (copy_to_user(&uattr->batch.count, &cp, sizeof(cp))) 1773aa2e93b8SBrian Vazquez err = -EFAULT; 17742e3a94aaSBrian Vazquez 177544779a4bSStanislav Fomichev kvfree(key); 17769087c6ffSEric Dumazet 1777aa2e93b8SBrian Vazquez return err; 1778aa2e93b8SBrian Vazquez } 1779aa2e93b8SBrian Vazquez 17803af43ba4SHou Tao int generic_map_update_batch(struct bpf_map *map, struct file *map_file, 1781aa2e93b8SBrian Vazquez const union bpf_attr *attr, 1782aa2e93b8SBrian Vazquez union bpf_attr __user *uattr) 1783aa2e93b8SBrian Vazquez { 1784aa2e93b8SBrian Vazquez void __user *values = u64_to_user_ptr(attr->batch.values); 1785aa2e93b8SBrian Vazquez void __user *keys = u64_to_user_ptr(attr->batch.keys); 1786aa2e93b8SBrian Vazquez u32 value_size, cp, max_count; 1787aa2e93b8SBrian Vazquez void *key, *value; 1788aa2e93b8SBrian Vazquez int err = 0; 1789aa2e93b8SBrian Vazquez 1790aa2e93b8SBrian Vazquez if (attr->batch.elem_flags & ~BPF_F_LOCK) 1791aa2e93b8SBrian Vazquez return -EINVAL; 1792aa2e93b8SBrian Vazquez 1793aa2e93b8SBrian Vazquez if ((attr->batch.elem_flags & BPF_F_LOCK) && 1794db559117SKumar Kartikeya Dwivedi !btf_record_has_field(map->record, BPF_SPIN_LOCK)) { 1795aa2e93b8SBrian Vazquez return -EINVAL; 1796aa2e93b8SBrian Vazquez } 1797aa2e93b8SBrian Vazquez 1798aa2e93b8SBrian Vazquez value_size = bpf_map_value_size(map); 1799aa2e93b8SBrian Vazquez 1800aa2e93b8SBrian Vazquez max_count = attr->batch.count; 1801aa2e93b8SBrian Vazquez if (!max_count) 1802aa2e93b8SBrian Vazquez return 0; 1803aa2e93b8SBrian Vazquez 180406e5c999SHou Tao if (put_user(0, &uattr->batch.count)) 180506e5c999SHou Tao return -EFAULT; 180606e5c999SHou Tao 180744779a4bSStanislav Fomichev key = kvmalloc(map->key_size, GFP_USER | __GFP_NOWARN); 18082e3a94aaSBrian Vazquez if (!key) 1809aa2e93b8SBrian Vazquez return -ENOMEM; 1810aa2e93b8SBrian Vazquez 1811f0dce1d9SStanislav Fomichev value = kvmalloc(value_size, GFP_USER | __GFP_NOWARN); 18122e3a94aaSBrian Vazquez if (!value) { 181344779a4bSStanislav Fomichev kvfree(key); 18142e3a94aaSBrian Vazquez return -ENOMEM; 1815aa2e93b8SBrian Vazquez } 18162e3a94aaSBrian Vazquez 18172e3a94aaSBrian Vazquez for (cp = 0; cp < max_count; cp++) { 1818aa2e93b8SBrian Vazquez err = -EFAULT; 18192e3a94aaSBrian Vazquez if (copy_from_user(key, keys + cp * map->key_size, 18202e3a94aaSBrian Vazquez map->key_size) || 18212e3a94aaSBrian Vazquez copy_from_user(value, values + cp * value_size, value_size)) 1822aa2e93b8SBrian Vazquez break; 1823aa2e93b8SBrian Vazquez 18243af43ba4SHou Tao err = bpf_map_update_value(map, map_file, key, value, 1825aa2e93b8SBrian Vazquez attr->batch.elem_flags); 1826aa2e93b8SBrian Vazquez 1827aa2e93b8SBrian Vazquez if (err) 1828aa2e93b8SBrian Vazquez break; 182975134f16SEric Dumazet cond_resched(); 1830aa2e93b8SBrian Vazquez } 1831aa2e93b8SBrian Vazquez 1832aa2e93b8SBrian Vazquez if (copy_to_user(&uattr->batch.count, &cp, sizeof(cp))) 1833aa2e93b8SBrian Vazquez err = -EFAULT; 1834aa2e93b8SBrian Vazquez 1835f0dce1d9SStanislav Fomichev kvfree(value); 183644779a4bSStanislav Fomichev kvfree(key); 183737ba5b59SHou Tao 1838aa2e93b8SBrian Vazquez return err; 1839aa2e93b8SBrian Vazquez } 1840aa2e93b8SBrian Vazquez 1841cb4d03abSBrian Vazquez #define MAP_LOOKUP_RETRIES 3 1842cb4d03abSBrian Vazquez 1843cb4d03abSBrian Vazquez int generic_map_lookup_batch(struct bpf_map *map, 1844cb4d03abSBrian Vazquez const union bpf_attr *attr, 1845cb4d03abSBrian Vazquez union bpf_attr __user *uattr) 1846cb4d03abSBrian Vazquez { 1847cb4d03abSBrian Vazquez void __user *uobatch = u64_to_user_ptr(attr->batch.out_batch); 1848cb4d03abSBrian Vazquez void __user *ubatch = u64_to_user_ptr(attr->batch.in_batch); 1849cb4d03abSBrian Vazquez void __user *values = u64_to_user_ptr(attr->batch.values); 1850cb4d03abSBrian Vazquez void __user *keys = u64_to_user_ptr(attr->batch.keys); 1851cb4d03abSBrian Vazquez void *buf, *buf_prevkey, *prev_key, *key, *value; 1852cb4d03abSBrian Vazquez int err, retry = MAP_LOOKUP_RETRIES; 1853cb4d03abSBrian Vazquez u32 value_size, cp, max_count; 1854cb4d03abSBrian Vazquez 1855cb4d03abSBrian Vazquez if (attr->batch.elem_flags & ~BPF_F_LOCK) 1856cb4d03abSBrian Vazquez return -EINVAL; 1857cb4d03abSBrian Vazquez 1858cb4d03abSBrian Vazquez if ((attr->batch.elem_flags & BPF_F_LOCK) && 1859db559117SKumar Kartikeya Dwivedi !btf_record_has_field(map->record, BPF_SPIN_LOCK)) 1860cb4d03abSBrian Vazquez return -EINVAL; 1861cb4d03abSBrian Vazquez 1862cb4d03abSBrian Vazquez value_size = bpf_map_value_size(map); 1863cb4d03abSBrian Vazquez 1864cb4d03abSBrian Vazquez max_count = attr->batch.count; 1865cb4d03abSBrian Vazquez if (!max_count) 1866cb4d03abSBrian Vazquez return 0; 1867cb4d03abSBrian Vazquez 1868cb4d03abSBrian Vazquez if (put_user(0, &uattr->batch.count)) 1869cb4d03abSBrian Vazquez return -EFAULT; 1870cb4d03abSBrian Vazquez 187144779a4bSStanislav Fomichev buf_prevkey = kvmalloc(map->key_size, GFP_USER | __GFP_NOWARN); 1872cb4d03abSBrian Vazquez if (!buf_prevkey) 1873cb4d03abSBrian Vazquez return -ENOMEM; 1874cb4d03abSBrian Vazquez 1875f0dce1d9SStanislav Fomichev buf = kvmalloc(map->key_size + value_size, GFP_USER | __GFP_NOWARN); 1876cb4d03abSBrian Vazquez if (!buf) { 187744779a4bSStanislav Fomichev kvfree(buf_prevkey); 1878cb4d03abSBrian Vazquez return -ENOMEM; 1879cb4d03abSBrian Vazquez } 1880cb4d03abSBrian Vazquez 1881cb4d03abSBrian Vazquez err = -EFAULT; 1882cb4d03abSBrian Vazquez prev_key = NULL; 1883cb4d03abSBrian Vazquez if (ubatch && copy_from_user(buf_prevkey, ubatch, map->key_size)) 1884cb4d03abSBrian Vazquez goto free_buf; 1885cb4d03abSBrian Vazquez key = buf; 1886cb4d03abSBrian Vazquez value = key + map->key_size; 1887cb4d03abSBrian Vazquez if (ubatch) 1888cb4d03abSBrian Vazquez prev_key = buf_prevkey; 1889cb4d03abSBrian Vazquez 1890cb4d03abSBrian Vazquez for (cp = 0; cp < max_count;) { 1891cb4d03abSBrian Vazquez rcu_read_lock(); 1892cb4d03abSBrian Vazquez err = map->ops->map_get_next_key(map, prev_key, key); 1893cb4d03abSBrian Vazquez rcu_read_unlock(); 1894cb4d03abSBrian Vazquez if (err) 1895cb4d03abSBrian Vazquez break; 1896cb4d03abSBrian Vazquez err = bpf_map_copy_value(map, key, value, 1897cb4d03abSBrian Vazquez attr->batch.elem_flags); 1898cb4d03abSBrian Vazquez 1899cb4d03abSBrian Vazquez if (err == -ENOENT) { 1900cb4d03abSBrian Vazquez if (retry) { 1901cb4d03abSBrian Vazquez retry--; 1902cb4d03abSBrian Vazquez continue; 1903cb4d03abSBrian Vazquez } 1904cb4d03abSBrian Vazquez err = -EINTR; 1905cb4d03abSBrian Vazquez break; 1906cb4d03abSBrian Vazquez } 1907cb4d03abSBrian Vazquez 1908cb4d03abSBrian Vazquez if (err) 1909cb4d03abSBrian Vazquez goto free_buf; 1910cb4d03abSBrian Vazquez 1911cb4d03abSBrian Vazquez if (copy_to_user(keys + cp * map->key_size, key, 1912cb4d03abSBrian Vazquez map->key_size)) { 1913cb4d03abSBrian Vazquez err = -EFAULT; 1914cb4d03abSBrian Vazquez goto free_buf; 1915cb4d03abSBrian Vazquez } 1916cb4d03abSBrian Vazquez if (copy_to_user(values + cp * value_size, value, value_size)) { 1917cb4d03abSBrian Vazquez err = -EFAULT; 1918cb4d03abSBrian Vazquez goto free_buf; 1919cb4d03abSBrian Vazquez } 1920cb4d03abSBrian Vazquez 1921cb4d03abSBrian Vazquez if (!prev_key) 1922cb4d03abSBrian Vazquez prev_key = buf_prevkey; 1923cb4d03abSBrian Vazquez 1924cb4d03abSBrian Vazquez swap(prev_key, key); 1925cb4d03abSBrian Vazquez retry = MAP_LOOKUP_RETRIES; 1926cb4d03abSBrian Vazquez cp++; 192775134f16SEric Dumazet cond_resched(); 1928cb4d03abSBrian Vazquez } 1929cb4d03abSBrian Vazquez 1930cb4d03abSBrian Vazquez if (err == -EFAULT) 1931cb4d03abSBrian Vazquez goto free_buf; 1932cb4d03abSBrian Vazquez 1933cb4d03abSBrian Vazquez if ((copy_to_user(&uattr->batch.count, &cp, sizeof(cp)) || 1934cb4d03abSBrian Vazquez (cp && copy_to_user(uobatch, prev_key, map->key_size)))) 1935cb4d03abSBrian Vazquez err = -EFAULT; 1936cb4d03abSBrian Vazquez 1937cb4d03abSBrian Vazquez free_buf: 193844779a4bSStanislav Fomichev kvfree(buf_prevkey); 1939f0dce1d9SStanislav Fomichev kvfree(buf); 1940cb4d03abSBrian Vazquez return err; 1941cb4d03abSBrian Vazquez } 1942cb4d03abSBrian Vazquez 19433e87f192SDenis Salopek #define BPF_MAP_LOOKUP_AND_DELETE_ELEM_LAST_FIELD flags 1944bd513cd0SMauricio Vasquez B 1945bd513cd0SMauricio Vasquez B static int map_lookup_and_delete_elem(union bpf_attr *attr) 1946bd513cd0SMauricio Vasquez B { 1947bd513cd0SMauricio Vasquez B void __user *ukey = u64_to_user_ptr(attr->key); 1948bd513cd0SMauricio Vasquez B void __user *uvalue = u64_to_user_ptr(attr->value); 1949bd513cd0SMauricio Vasquez B int ufd = attr->map_fd; 1950bd513cd0SMauricio Vasquez B struct bpf_map *map; 1951540fefc0SAlexei Starovoitov void *key, *value; 1952bd513cd0SMauricio Vasquez B u32 value_size; 1953bd513cd0SMauricio Vasquez B struct fd f; 1954bd513cd0SMauricio Vasquez B int err; 1955bd513cd0SMauricio Vasquez B 1956bd513cd0SMauricio Vasquez B if (CHECK_ATTR(BPF_MAP_LOOKUP_AND_DELETE_ELEM)) 1957bd513cd0SMauricio Vasquez B return -EINVAL; 1958bd513cd0SMauricio Vasquez B 19593e87f192SDenis Salopek if (attr->flags & ~BPF_F_LOCK) 19603e87f192SDenis Salopek return -EINVAL; 19613e87f192SDenis Salopek 1962bd513cd0SMauricio Vasquez B f = fdget(ufd); 1963bd513cd0SMauricio Vasquez B map = __bpf_map_get(f); 1964bd513cd0SMauricio Vasquez B if (IS_ERR(map)) 1965bd513cd0SMauricio Vasquez B return PTR_ERR(map); 1966353050beSDaniel Borkmann bpf_map_write_active_inc(map); 19671ea0f912SAnton Protopopov if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ) || 19681ea0f912SAnton Protopopov !(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) { 1969bd513cd0SMauricio Vasquez B err = -EPERM; 1970bd513cd0SMauricio Vasquez B goto err_put; 1971bd513cd0SMauricio Vasquez B } 1972bd513cd0SMauricio Vasquez B 19733e87f192SDenis Salopek if (attr->flags && 19743e87f192SDenis Salopek (map->map_type == BPF_MAP_TYPE_QUEUE || 19753e87f192SDenis Salopek map->map_type == BPF_MAP_TYPE_STACK)) { 19763e87f192SDenis Salopek err = -EINVAL; 19773e87f192SDenis Salopek goto err_put; 19783e87f192SDenis Salopek } 19793e87f192SDenis Salopek 19803e87f192SDenis Salopek if ((attr->flags & BPF_F_LOCK) && 1981db559117SKumar Kartikeya Dwivedi !btf_record_has_field(map->record, BPF_SPIN_LOCK)) { 19823e87f192SDenis Salopek err = -EINVAL; 19833e87f192SDenis Salopek goto err_put; 19843e87f192SDenis Salopek } 19853e87f192SDenis Salopek 1986bd513cd0SMauricio Vasquez B key = __bpf_copy_key(ukey, map->key_size); 1987bd513cd0SMauricio Vasquez B if (IS_ERR(key)) { 1988bd513cd0SMauricio Vasquez B err = PTR_ERR(key); 1989bd513cd0SMauricio Vasquez B goto err_put; 1990bd513cd0SMauricio Vasquez B } 1991bd513cd0SMauricio Vasquez B 19923e87f192SDenis Salopek value_size = bpf_map_value_size(map); 1993bd513cd0SMauricio Vasquez B 1994bd513cd0SMauricio Vasquez B err = -ENOMEM; 1995f0dce1d9SStanislav Fomichev value = kvmalloc(value_size, GFP_USER | __GFP_NOWARN); 1996bd513cd0SMauricio Vasquez B if (!value) 1997bd513cd0SMauricio Vasquez B goto free_key; 1998bd513cd0SMauricio Vasquez B 19993e87f192SDenis Salopek err = -ENOTSUPP; 2000bd513cd0SMauricio Vasquez B if (map->map_type == BPF_MAP_TYPE_QUEUE || 2001bd513cd0SMauricio Vasquez B map->map_type == BPF_MAP_TYPE_STACK) { 2002bd513cd0SMauricio Vasquez B err = map->ops->map_pop_elem(map, value); 20033e87f192SDenis Salopek } else if (map->map_type == BPF_MAP_TYPE_HASH || 20043e87f192SDenis Salopek map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 20053e87f192SDenis Salopek map->map_type == BPF_MAP_TYPE_LRU_HASH || 20063e87f192SDenis Salopek map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) { 20079d03ebc7SStanislav Fomichev if (!bpf_map_is_offloaded(map)) { 20083e87f192SDenis Salopek bpf_disable_instrumentation(); 20093e87f192SDenis Salopek rcu_read_lock(); 20103e87f192SDenis Salopek err = map->ops->map_lookup_and_delete_elem(map, key, value, attr->flags); 20113e87f192SDenis Salopek rcu_read_unlock(); 20123e87f192SDenis Salopek bpf_enable_instrumentation(); 20133e87f192SDenis Salopek } 2014bd513cd0SMauricio Vasquez B } 2015bd513cd0SMauricio Vasquez B 2016bd513cd0SMauricio Vasquez B if (err) 2017bd513cd0SMauricio Vasquez B goto free_value; 2018bd513cd0SMauricio Vasquez B 20197f645462SWei Yongjun if (copy_to_user(uvalue, value, value_size) != 0) { 20207f645462SWei Yongjun err = -EFAULT; 2021bd513cd0SMauricio Vasquez B goto free_value; 20227f645462SWei Yongjun } 2023bd513cd0SMauricio Vasquez B 2024bd513cd0SMauricio Vasquez B err = 0; 2025bd513cd0SMauricio Vasquez B 2026bd513cd0SMauricio Vasquez B free_value: 2027f0dce1d9SStanislav Fomichev kvfree(value); 2028bd513cd0SMauricio Vasquez B free_key: 202944779a4bSStanislav Fomichev kvfree(key); 2030bd513cd0SMauricio Vasquez B err_put: 2031353050beSDaniel Borkmann bpf_map_write_active_dec(map); 2032bd513cd0SMauricio Vasquez B fdput(f); 2033bd513cd0SMauricio Vasquez B return err; 2034bd513cd0SMauricio Vasquez B } 2035bd513cd0SMauricio Vasquez B 203687df15deSDaniel Borkmann #define BPF_MAP_FREEZE_LAST_FIELD map_fd 203787df15deSDaniel Borkmann 203887df15deSDaniel Borkmann static int map_freeze(const union bpf_attr *attr) 203987df15deSDaniel Borkmann { 204087df15deSDaniel Borkmann int err = 0, ufd = attr->map_fd; 204187df15deSDaniel Borkmann struct bpf_map *map; 204287df15deSDaniel Borkmann struct fd f; 204387df15deSDaniel Borkmann 204487df15deSDaniel Borkmann if (CHECK_ATTR(BPF_MAP_FREEZE)) 204587df15deSDaniel Borkmann return -EINVAL; 204687df15deSDaniel Borkmann 204787df15deSDaniel Borkmann f = fdget(ufd); 204887df15deSDaniel Borkmann map = __bpf_map_get(f); 204987df15deSDaniel Borkmann if (IS_ERR(map)) 205087df15deSDaniel Borkmann return PTR_ERR(map); 2051fc970227SAndrii Nakryiko 2052db559117SKumar Kartikeya Dwivedi if (map->map_type == BPF_MAP_TYPE_STRUCT_OPS || !IS_ERR_OR_NULL(map->record)) { 2053849b4d94SMartin KaFai Lau fdput(f); 2054849b4d94SMartin KaFai Lau return -ENOTSUPP; 2055849b4d94SMartin KaFai Lau } 2056849b4d94SMartin KaFai Lau 2057c4c84f6fSAndrii Nakryiko if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) { 20584266f41fSDaniel Borkmann fdput(f); 20594266f41fSDaniel Borkmann return -EPERM; 2060c4c84f6fSAndrii Nakryiko } 2061c4c84f6fSAndrii Nakryiko 2062fc970227SAndrii Nakryiko mutex_lock(&map->freeze_mutex); 2063353050beSDaniel Borkmann if (bpf_map_write_active(map)) { 2064fc970227SAndrii Nakryiko err = -EBUSY; 2065fc970227SAndrii Nakryiko goto err_put; 2066fc970227SAndrii Nakryiko } 206787df15deSDaniel Borkmann if (READ_ONCE(map->frozen)) { 206887df15deSDaniel Borkmann err = -EBUSY; 206987df15deSDaniel Borkmann goto err_put; 207087df15deSDaniel Borkmann } 207187df15deSDaniel Borkmann 207287df15deSDaniel Borkmann WRITE_ONCE(map->frozen, true); 207387df15deSDaniel Borkmann err_put: 2074fc970227SAndrii Nakryiko mutex_unlock(&map->freeze_mutex); 207587df15deSDaniel Borkmann fdput(f); 207687df15deSDaniel Borkmann return err; 207787df15deSDaniel Borkmann } 207887df15deSDaniel Borkmann 20797de16e3aSJakub Kicinski static const struct bpf_prog_ops * const bpf_prog_types[] = { 208091cc1a99SAlexei Starovoitov #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) \ 20817de16e3aSJakub Kicinski [_id] = & _name ## _prog_ops, 20827de16e3aSJakub Kicinski #define BPF_MAP_TYPE(_id, _ops) 2083f2e10bffSAndrii Nakryiko #define BPF_LINK_TYPE(_id, _name) 20847de16e3aSJakub Kicinski #include <linux/bpf_types.h> 20857de16e3aSJakub Kicinski #undef BPF_PROG_TYPE 20867de16e3aSJakub Kicinski #undef BPF_MAP_TYPE 2087f2e10bffSAndrii Nakryiko #undef BPF_LINK_TYPE 20887de16e3aSJakub Kicinski }; 20897de16e3aSJakub Kicinski 209009756af4SAlexei Starovoitov static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog) 209109756af4SAlexei Starovoitov { 2092d0f1a451SDaniel Borkmann const struct bpf_prog_ops *ops; 2093d0f1a451SDaniel Borkmann 2094d0f1a451SDaniel Borkmann if (type >= ARRAY_SIZE(bpf_prog_types)) 2095d0f1a451SDaniel Borkmann return -EINVAL; 2096d0f1a451SDaniel Borkmann type = array_index_nospec(type, ARRAY_SIZE(bpf_prog_types)); 2097d0f1a451SDaniel Borkmann ops = bpf_prog_types[type]; 2098d0f1a451SDaniel Borkmann if (!ops) 2099be9370a7SJohannes Berg return -EINVAL; 210009756af4SAlexei Starovoitov 21019d03ebc7SStanislav Fomichev if (!bpf_prog_is_offloaded(prog->aux)) 2102d0f1a451SDaniel Borkmann prog->aux->ops = ops; 2103ab3f0063SJakub Kicinski else 2104ab3f0063SJakub Kicinski prog->aux->ops = &bpf_offload_prog_ops; 210524701eceSDaniel Borkmann prog->type = type; 210609756af4SAlexei Starovoitov return 0; 210709756af4SAlexei Starovoitov } 210809756af4SAlexei Starovoitov 2109bae141f5SDaniel Borkmann enum bpf_audit { 2110bae141f5SDaniel Borkmann BPF_AUDIT_LOAD, 2111bae141f5SDaniel Borkmann BPF_AUDIT_UNLOAD, 2112bae141f5SDaniel Borkmann BPF_AUDIT_MAX, 2113bae141f5SDaniel Borkmann }; 2114bae141f5SDaniel Borkmann 2115bae141f5SDaniel Borkmann static const char * const bpf_audit_str[BPF_AUDIT_MAX] = { 2116bae141f5SDaniel Borkmann [BPF_AUDIT_LOAD] = "LOAD", 2117bae141f5SDaniel Borkmann [BPF_AUDIT_UNLOAD] = "UNLOAD", 2118bae141f5SDaniel Borkmann }; 2119bae141f5SDaniel Borkmann 2120bae141f5SDaniel Borkmann static void bpf_audit_prog(const struct bpf_prog *prog, unsigned int op) 2121bae141f5SDaniel Borkmann { 2122bae141f5SDaniel Borkmann struct audit_context *ctx = NULL; 2123bae141f5SDaniel Borkmann struct audit_buffer *ab; 2124bae141f5SDaniel Borkmann 2125bae141f5SDaniel Borkmann if (WARN_ON_ONCE(op >= BPF_AUDIT_MAX)) 2126bae141f5SDaniel Borkmann return; 2127bae141f5SDaniel Borkmann if (audit_enabled == AUDIT_OFF) 2128bae141f5SDaniel Borkmann return; 2129ef01f4e2SPaul Moore if (!in_irq() && !irqs_disabled()) 2130bae141f5SDaniel Borkmann ctx = audit_context(); 2131bae141f5SDaniel Borkmann ab = audit_log_start(ctx, GFP_ATOMIC, AUDIT_BPF); 2132bae141f5SDaniel Borkmann if (unlikely(!ab)) 2133bae141f5SDaniel Borkmann return; 2134bae141f5SDaniel Borkmann audit_log_format(ab, "prog-id=%u op=%s", 2135bae141f5SDaniel Borkmann prog->aux->id, bpf_audit_str[op]); 2136bae141f5SDaniel Borkmann audit_log_end(ab); 2137bae141f5SDaniel Borkmann } 2138bae141f5SDaniel Borkmann 2139dc4bb0e2SMartin KaFai Lau static int bpf_prog_alloc_id(struct bpf_prog *prog) 2140dc4bb0e2SMartin KaFai Lau { 2141dc4bb0e2SMartin KaFai Lau int id; 2142dc4bb0e2SMartin KaFai Lau 2143b76354cdSShaohua Li idr_preload(GFP_KERNEL); 2144dc4bb0e2SMartin KaFai Lau spin_lock_bh(&prog_idr_lock); 2145dc4bb0e2SMartin KaFai Lau id = idr_alloc_cyclic(&prog_idr, prog, 1, INT_MAX, GFP_ATOMIC); 2146dc4bb0e2SMartin KaFai Lau if (id > 0) 2147dc4bb0e2SMartin KaFai Lau prog->aux->id = id; 2148dc4bb0e2SMartin KaFai Lau spin_unlock_bh(&prog_idr_lock); 2149b76354cdSShaohua Li idr_preload_end(); 2150dc4bb0e2SMartin KaFai Lau 2151dc4bb0e2SMartin KaFai Lau /* id is in [1, INT_MAX) */ 2152dc4bb0e2SMartin KaFai Lau if (WARN_ON_ONCE(!id)) 2153dc4bb0e2SMartin KaFai Lau return -ENOSPC; 2154dc4bb0e2SMartin KaFai Lau 2155dc4bb0e2SMartin KaFai Lau return id > 0 ? 0 : id; 2156dc4bb0e2SMartin KaFai Lau } 2157dc4bb0e2SMartin KaFai Lau 2158e7895f01SPaul Moore void bpf_prog_free_id(struct bpf_prog *prog) 2159dc4bb0e2SMartin KaFai Lau { 2160d809e134SAlexei Starovoitov unsigned long flags; 2161d809e134SAlexei Starovoitov 2162ad8ad79fSJakub Kicinski /* cBPF to eBPF migrations are currently not in the idr store. 2163ad8ad79fSJakub Kicinski * Offloaded programs are removed from the store when their device 2164ad8ad79fSJakub Kicinski * disappears - even if someone grabs an fd to them they are unusable, 2165ad8ad79fSJakub Kicinski * simply waiting for refcnt to drop to be freed. 2166ad8ad79fSJakub Kicinski */ 2167dc4bb0e2SMartin KaFai Lau if (!prog->aux->id) 2168dc4bb0e2SMartin KaFai Lau return; 2169dc4bb0e2SMartin KaFai Lau 2170d809e134SAlexei Starovoitov spin_lock_irqsave(&prog_idr_lock, flags); 2171dc4bb0e2SMartin KaFai Lau idr_remove(&prog_idr, prog->aux->id); 2172ad8ad79fSJakub Kicinski prog->aux->id = 0; 2173d809e134SAlexei Starovoitov spin_unlock_irqrestore(&prog_idr_lock, flags); 2174dc4bb0e2SMartin KaFai Lau } 2175dc4bb0e2SMartin KaFai Lau 21761aacde3dSDaniel Borkmann static void __bpf_prog_put_rcu(struct rcu_head *rcu) 2177abf2e7d6SAlexei Starovoitov { 2178abf2e7d6SAlexei Starovoitov struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu); 2179abf2e7d6SAlexei Starovoitov 21803b4d9eb2SDaniel Borkmann kvfree(aux->func_info); 21818c1b6e69SAlexei Starovoitov kfree(aux->func_info_aux); 21823ac1f01bSRoman Gushchin free_uid(aux->user); 2183d17aff80SAndrii Nakryiko security_bpf_prog_free(aux); 2184abf2e7d6SAlexei Starovoitov bpf_prog_free(aux->prog); 2185abf2e7d6SAlexei Starovoitov } 2186abf2e7d6SAlexei Starovoitov 2187cd7455f1SDaniel Borkmann static void __bpf_prog_put_noref(struct bpf_prog *prog, bool deferred) 2188cd7455f1SDaniel Borkmann { 2189cd7455f1SDaniel Borkmann bpf_prog_kallsyms_del_all(prog); 2190cd7455f1SDaniel Borkmann btf_put(prog->aux->btf); 219131bf1dbcSViktor Malik module_put(prog->aux->mod); 2192e16301fbSMartin KaFai Lau kvfree(prog->aux->jited_linfo); 2193e16301fbSMartin KaFai Lau kvfree(prog->aux->linfo); 2194e6ac2450SMartin KaFai Lau kfree(prog->aux->kfunc_tab); 219522dc4a0fSAndrii Nakryiko if (prog->aux->attach_btf) 219622dc4a0fSAndrii Nakryiko btf_put(prog->aux->attach_btf); 2197cd7455f1SDaniel Borkmann 21981e6c62a8SAlexei Starovoitov if (deferred) { 21991e6c62a8SAlexei Starovoitov if (prog->aux->sleepable) 22001e6c62a8SAlexei Starovoitov call_rcu_tasks_trace(&prog->aux->rcu, __bpf_prog_put_rcu); 2201cd7455f1SDaniel Borkmann else 22021e6c62a8SAlexei Starovoitov call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu); 22031e6c62a8SAlexei Starovoitov } else { 2204cd7455f1SDaniel Borkmann __bpf_prog_put_rcu(&prog->aux->rcu); 2205cd7455f1SDaniel Borkmann } 22061e6c62a8SAlexei Starovoitov } 2207cd7455f1SDaniel Borkmann 2208d809e134SAlexei Starovoitov static void bpf_prog_put_deferred(struct work_struct *work) 220909756af4SAlexei Starovoitov { 2210d809e134SAlexei Starovoitov struct bpf_prog_aux *aux; 2211d809e134SAlexei Starovoitov struct bpf_prog *prog; 2212d809e134SAlexei Starovoitov 2213d809e134SAlexei Starovoitov aux = container_of(work, struct bpf_prog_aux, work); 2214d809e134SAlexei Starovoitov prog = aux->prog; 22156ee52e2aSSong Liu perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_UNLOAD, 0); 2216bae141f5SDaniel Borkmann bpf_audit_prog(prog, BPF_AUDIT_UNLOAD); 2217e7895f01SPaul Moore bpf_prog_free_id(prog); 2218d809e134SAlexei Starovoitov __bpf_prog_put_noref(prog, true); 2219d809e134SAlexei Starovoitov } 2220d809e134SAlexei Starovoitov 2221e7895f01SPaul Moore static void __bpf_prog_put(struct bpf_prog *prog) 2222d809e134SAlexei Starovoitov { 2223d809e134SAlexei Starovoitov struct bpf_prog_aux *aux = prog->aux; 2224d809e134SAlexei Starovoitov 2225d809e134SAlexei Starovoitov if (atomic64_dec_and_test(&aux->refcnt)) { 2226d809e134SAlexei Starovoitov if (in_irq() || irqs_disabled()) { 2227d809e134SAlexei Starovoitov INIT_WORK(&aux->work, bpf_prog_put_deferred); 2228d809e134SAlexei Starovoitov schedule_work(&aux->work); 2229d809e134SAlexei Starovoitov } else { 2230d809e134SAlexei Starovoitov bpf_prog_put_deferred(&aux->work); 2231d809e134SAlexei Starovoitov } 223209756af4SAlexei Starovoitov } 2233a67edbf4SDaniel Borkmann } 2234b16d9aa4SMartin KaFai Lau 2235b16d9aa4SMartin KaFai Lau void bpf_prog_put(struct bpf_prog *prog) 2236b16d9aa4SMartin KaFai Lau { 2237e7895f01SPaul Moore __bpf_prog_put(prog); 2238b16d9aa4SMartin KaFai Lau } 2239e2e9b654SDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_put); 224009756af4SAlexei Starovoitov 224109756af4SAlexei Starovoitov static int bpf_prog_release(struct inode *inode, struct file *filp) 224209756af4SAlexei Starovoitov { 224309756af4SAlexei Starovoitov struct bpf_prog *prog = filp->private_data; 224409756af4SAlexei Starovoitov 22451aacde3dSDaniel Borkmann bpf_prog_put(prog); 224609756af4SAlexei Starovoitov return 0; 224709756af4SAlexei Starovoitov } 224809756af4SAlexei Starovoitov 224961a0abaeSEric Dumazet struct bpf_prog_kstats { 225061a0abaeSEric Dumazet u64 nsecs; 225161a0abaeSEric Dumazet u64 cnt; 225261a0abaeSEric Dumazet u64 misses; 225361a0abaeSEric Dumazet }; 225461a0abaeSEric Dumazet 225505b24ff9SJiri Olsa void notrace bpf_prog_inc_misses_counter(struct bpf_prog *prog) 225605b24ff9SJiri Olsa { 225705b24ff9SJiri Olsa struct bpf_prog_stats *stats; 225805b24ff9SJiri Olsa unsigned int flags; 225905b24ff9SJiri Olsa 226005b24ff9SJiri Olsa stats = this_cpu_ptr(prog->stats); 226105b24ff9SJiri Olsa flags = u64_stats_update_begin_irqsave(&stats->syncp); 226205b24ff9SJiri Olsa u64_stats_inc(&stats->misses); 226305b24ff9SJiri Olsa u64_stats_update_end_irqrestore(&stats->syncp, flags); 226405b24ff9SJiri Olsa } 226505b24ff9SJiri Olsa 2266492ecee8SAlexei Starovoitov static void bpf_prog_get_stats(const struct bpf_prog *prog, 226761a0abaeSEric Dumazet struct bpf_prog_kstats *stats) 2268492ecee8SAlexei Starovoitov { 22699ed9e9baSAlexei Starovoitov u64 nsecs = 0, cnt = 0, misses = 0; 2270492ecee8SAlexei Starovoitov int cpu; 2271492ecee8SAlexei Starovoitov 2272492ecee8SAlexei Starovoitov for_each_possible_cpu(cpu) { 2273492ecee8SAlexei Starovoitov const struct bpf_prog_stats *st; 2274492ecee8SAlexei Starovoitov unsigned int start; 22759ed9e9baSAlexei Starovoitov u64 tnsecs, tcnt, tmisses; 2276492ecee8SAlexei Starovoitov 2277700d4796SAlexei Starovoitov st = per_cpu_ptr(prog->stats, cpu); 2278492ecee8SAlexei Starovoitov do { 227997c4090bSThomas Gleixner start = u64_stats_fetch_begin(&st->syncp); 228061a0abaeSEric Dumazet tnsecs = u64_stats_read(&st->nsecs); 228161a0abaeSEric Dumazet tcnt = u64_stats_read(&st->cnt); 228261a0abaeSEric Dumazet tmisses = u64_stats_read(&st->misses); 228397c4090bSThomas Gleixner } while (u64_stats_fetch_retry(&st->syncp, start)); 2284492ecee8SAlexei Starovoitov nsecs += tnsecs; 2285492ecee8SAlexei Starovoitov cnt += tcnt; 22869ed9e9baSAlexei Starovoitov misses += tmisses; 2287492ecee8SAlexei Starovoitov } 2288492ecee8SAlexei Starovoitov stats->nsecs = nsecs; 2289492ecee8SAlexei Starovoitov stats->cnt = cnt; 22909ed9e9baSAlexei Starovoitov stats->misses = misses; 2291492ecee8SAlexei Starovoitov } 2292492ecee8SAlexei Starovoitov 22937bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS 22947bd509e3SDaniel Borkmann static void bpf_prog_show_fdinfo(struct seq_file *m, struct file *filp) 22957bd509e3SDaniel Borkmann { 22967bd509e3SDaniel Borkmann const struct bpf_prog *prog = filp->private_data; 2297f1f7714eSDaniel Borkmann char prog_tag[sizeof(prog->tag) * 2 + 1] = { }; 229861a0abaeSEric Dumazet struct bpf_prog_kstats stats; 22997bd509e3SDaniel Borkmann 2300492ecee8SAlexei Starovoitov bpf_prog_get_stats(prog, &stats); 2301f1f7714eSDaniel Borkmann bin2hex(prog_tag, prog->tag, sizeof(prog->tag)); 23027bd509e3SDaniel Borkmann seq_printf(m, 23037bd509e3SDaniel Borkmann "prog_type:\t%u\n" 23047bd509e3SDaniel Borkmann "prog_jited:\t%u\n" 2305f1f7714eSDaniel Borkmann "prog_tag:\t%s\n" 23064316b409SDaniel Borkmann "memlock:\t%llu\n" 2307492ecee8SAlexei Starovoitov "prog_id:\t%u\n" 2308492ecee8SAlexei Starovoitov "run_time_ns:\t%llu\n" 23099ed9e9baSAlexei Starovoitov "run_cnt:\t%llu\n" 2310aba64c7dSDave Marchevsky "recursion_misses:\t%llu\n" 2311aba64c7dSDave Marchevsky "verified_insns:\t%u\n", 23127bd509e3SDaniel Borkmann prog->type, 23137bd509e3SDaniel Borkmann prog->jited, 2314f1f7714eSDaniel Borkmann prog_tag, 23154316b409SDaniel Borkmann prog->pages * 1ULL << PAGE_SHIFT, 2316492ecee8SAlexei Starovoitov prog->aux->id, 2317492ecee8SAlexei Starovoitov stats.nsecs, 23189ed9e9baSAlexei Starovoitov stats.cnt, 2319aba64c7dSDave Marchevsky stats.misses, 2320aba64c7dSDave Marchevsky prog->aux->verified_insns); 23217bd509e3SDaniel Borkmann } 23227bd509e3SDaniel Borkmann #endif 23237bd509e3SDaniel Borkmann 2324f66e448cSChenbo Feng const struct file_operations bpf_prog_fops = { 23257bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS 23267bd509e3SDaniel Borkmann .show_fdinfo = bpf_prog_show_fdinfo, 23277bd509e3SDaniel Borkmann #endif 232809756af4SAlexei Starovoitov .release = bpf_prog_release, 23296e71b04aSChenbo Feng .read = bpf_dummy_read, 23306e71b04aSChenbo Feng .write = bpf_dummy_write, 233109756af4SAlexei Starovoitov }; 233209756af4SAlexei Starovoitov 2333b2197755SDaniel Borkmann int bpf_prog_new_fd(struct bpf_prog *prog) 2334aa79781bSDaniel Borkmann { 2335afdb09c7SChenbo Feng int ret; 2336afdb09c7SChenbo Feng 2337afdb09c7SChenbo Feng ret = security_bpf_prog(prog); 2338afdb09c7SChenbo Feng if (ret < 0) 2339afdb09c7SChenbo Feng return ret; 2340afdb09c7SChenbo Feng 2341aa79781bSDaniel Borkmann return anon_inode_getfd("bpf-prog", &bpf_prog_fops, prog, 2342aa79781bSDaniel Borkmann O_RDWR | O_CLOEXEC); 2343aa79781bSDaniel Borkmann } 2344aa79781bSDaniel Borkmann 2345113214beSDaniel Borkmann static struct bpf_prog *____bpf_prog_get(struct fd f) 234609756af4SAlexei Starovoitov { 234709756af4SAlexei Starovoitov if (!f.file) 234809756af4SAlexei Starovoitov return ERR_PTR(-EBADF); 234909756af4SAlexei Starovoitov if (f.file->f_op != &bpf_prog_fops) { 235009756af4SAlexei Starovoitov fdput(f); 235109756af4SAlexei Starovoitov return ERR_PTR(-EINVAL); 235209756af4SAlexei Starovoitov } 235309756af4SAlexei Starovoitov 2354c2101297SDaniel Borkmann return f.file->private_data; 235509756af4SAlexei Starovoitov } 235609756af4SAlexei Starovoitov 235785192dbfSAndrii Nakryiko void bpf_prog_add(struct bpf_prog *prog, int i) 235892117d84SAlexei Starovoitov { 235985192dbfSAndrii Nakryiko atomic64_add(i, &prog->aux->refcnt); 236092117d84SAlexei Starovoitov } 236159d3656dSBrenden Blanco EXPORT_SYMBOL_GPL(bpf_prog_add); 236259d3656dSBrenden Blanco 2363c540594fSDaniel Borkmann void bpf_prog_sub(struct bpf_prog *prog, int i) 2364c540594fSDaniel Borkmann { 2365c540594fSDaniel Borkmann /* Only to be used for undoing previous bpf_prog_add() in some 2366c540594fSDaniel Borkmann * error path. We still know that another entity in our call 2367c540594fSDaniel Borkmann * path holds a reference to the program, thus atomic_sub() can 2368c540594fSDaniel Borkmann * be safely used in such cases! 2369c540594fSDaniel Borkmann */ 237085192dbfSAndrii Nakryiko WARN_ON(atomic64_sub_return(i, &prog->aux->refcnt) == 0); 2371c540594fSDaniel Borkmann } 2372c540594fSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_sub); 2373c540594fSDaniel Borkmann 237485192dbfSAndrii Nakryiko void bpf_prog_inc(struct bpf_prog *prog) 237559d3656dSBrenden Blanco { 237685192dbfSAndrii Nakryiko atomic64_inc(&prog->aux->refcnt); 237759d3656dSBrenden Blanco } 237897bc402dSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_inc); 237992117d84SAlexei Starovoitov 2380b16d9aa4SMartin KaFai Lau /* prog_idr_lock should have been held */ 2381a6f6df69SJohn Fastabend struct bpf_prog *bpf_prog_inc_not_zero(struct bpf_prog *prog) 2382b16d9aa4SMartin KaFai Lau { 2383b16d9aa4SMartin KaFai Lau int refold; 2384b16d9aa4SMartin KaFai Lau 238585192dbfSAndrii Nakryiko refold = atomic64_fetch_add_unless(&prog->aux->refcnt, 1, 0); 2386b16d9aa4SMartin KaFai Lau 2387b16d9aa4SMartin KaFai Lau if (!refold) 2388b16d9aa4SMartin KaFai Lau return ERR_PTR(-ENOENT); 2389b16d9aa4SMartin KaFai Lau 2390b16d9aa4SMartin KaFai Lau return prog; 2391b16d9aa4SMartin KaFai Lau } 2392a6f6df69SJohn Fastabend EXPORT_SYMBOL_GPL(bpf_prog_inc_not_zero); 2393b16d9aa4SMartin KaFai Lau 2394040ee692SAl Viro bool bpf_prog_get_ok(struct bpf_prog *prog, 2395288b3de5SJakub Kicinski enum bpf_prog_type *attach_type, bool attach_drv) 2396248f346fSJakub Kicinski { 2397288b3de5SJakub Kicinski /* not an attachment, just a refcount inc, always allow */ 2398288b3de5SJakub Kicinski if (!attach_type) 2399288b3de5SJakub Kicinski return true; 2400248f346fSJakub Kicinski 2401248f346fSJakub Kicinski if (prog->type != *attach_type) 2402248f346fSJakub Kicinski return false; 24039d03ebc7SStanislav Fomichev if (bpf_prog_is_offloaded(prog->aux) && !attach_drv) 2404248f346fSJakub Kicinski return false; 2405248f346fSJakub Kicinski 2406248f346fSJakub Kicinski return true; 2407248f346fSJakub Kicinski } 2408248f346fSJakub Kicinski 2409248f346fSJakub Kicinski static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *attach_type, 2410288b3de5SJakub Kicinski bool attach_drv) 241109756af4SAlexei Starovoitov { 241209756af4SAlexei Starovoitov struct fd f = fdget(ufd); 241309756af4SAlexei Starovoitov struct bpf_prog *prog; 241409756af4SAlexei Starovoitov 2415113214beSDaniel Borkmann prog = ____bpf_prog_get(f); 241609756af4SAlexei Starovoitov if (IS_ERR(prog)) 241709756af4SAlexei Starovoitov return prog; 2418288b3de5SJakub Kicinski if (!bpf_prog_get_ok(prog, attach_type, attach_drv)) { 2419113214beSDaniel Borkmann prog = ERR_PTR(-EINVAL); 2420113214beSDaniel Borkmann goto out; 2421113214beSDaniel Borkmann } 242209756af4SAlexei Starovoitov 242385192dbfSAndrii Nakryiko bpf_prog_inc(prog); 2424113214beSDaniel Borkmann out: 242509756af4SAlexei Starovoitov fdput(f); 242609756af4SAlexei Starovoitov return prog; 242709756af4SAlexei Starovoitov } 2428113214beSDaniel Borkmann 2429113214beSDaniel Borkmann struct bpf_prog *bpf_prog_get(u32 ufd) 2430113214beSDaniel Borkmann { 2431288b3de5SJakub Kicinski return __bpf_prog_get(ufd, NULL, false); 2432113214beSDaniel Borkmann } 2433113214beSDaniel Borkmann 2434248f346fSJakub Kicinski struct bpf_prog *bpf_prog_get_type_dev(u32 ufd, enum bpf_prog_type type, 2435288b3de5SJakub Kicinski bool attach_drv) 2436248f346fSJakub Kicinski { 24374d220ed0SAlexei Starovoitov return __bpf_prog_get(ufd, &type, attach_drv); 2438248f346fSJakub Kicinski } 24396c8dfe21SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_prog_get_type_dev); 2440248f346fSJakub Kicinski 2441aac3fc32SAndrey Ignatov /* Initially all BPF programs could be loaded w/o specifying 2442aac3fc32SAndrey Ignatov * expected_attach_type. Later for some of them specifying expected_attach_type 2443aac3fc32SAndrey Ignatov * at load time became required so that program could be validated properly. 2444aac3fc32SAndrey Ignatov * Programs of types that are allowed to be loaded both w/ and w/o (for 2445aac3fc32SAndrey Ignatov * backward compatibility) expected_attach_type, should have the default attach 2446aac3fc32SAndrey Ignatov * type assigned to expected_attach_type for the latter case, so that it can be 2447aac3fc32SAndrey Ignatov * validated later at attach time. 2448aac3fc32SAndrey Ignatov * 2449aac3fc32SAndrey Ignatov * bpf_prog_load_fixup_attach_type() sets expected_attach_type in @attr if 2450aac3fc32SAndrey Ignatov * prog type requires it but has some attach types that have to be backward 2451aac3fc32SAndrey Ignatov * compatible. 2452aac3fc32SAndrey Ignatov */ 2453aac3fc32SAndrey Ignatov static void bpf_prog_load_fixup_attach_type(union bpf_attr *attr) 2454aac3fc32SAndrey Ignatov { 2455aac3fc32SAndrey Ignatov switch (attr->prog_type) { 2456aac3fc32SAndrey Ignatov case BPF_PROG_TYPE_CGROUP_SOCK: 2457aac3fc32SAndrey Ignatov /* Unfortunately BPF_ATTACH_TYPE_UNSPEC enumeration doesn't 2458aac3fc32SAndrey Ignatov * exist so checking for non-zero is the way to go here. 2459aac3fc32SAndrey Ignatov */ 2460aac3fc32SAndrey Ignatov if (!attr->expected_attach_type) 2461aac3fc32SAndrey Ignatov attr->expected_attach_type = 2462aac3fc32SAndrey Ignatov BPF_CGROUP_INET_SOCK_CREATE; 2463aac3fc32SAndrey Ignatov break; 2464d5e4ddaeSKuniyuki Iwashima case BPF_PROG_TYPE_SK_REUSEPORT: 2465d5e4ddaeSKuniyuki Iwashima if (!attr->expected_attach_type) 2466d5e4ddaeSKuniyuki Iwashima attr->expected_attach_type = 2467d5e4ddaeSKuniyuki Iwashima BPF_SK_REUSEPORT_SELECT; 2468d5e4ddaeSKuniyuki Iwashima break; 2469aac3fc32SAndrey Ignatov } 2470aac3fc32SAndrey Ignatov } 2471aac3fc32SAndrey Ignatov 24725e43f899SAndrey Ignatov static int 2473ccfe29ebSAlexei Starovoitov bpf_prog_load_check_attach(enum bpf_prog_type prog_type, 2474ccfe29ebSAlexei Starovoitov enum bpf_attach_type expected_attach_type, 2475290248a5SAndrii Nakryiko struct btf *attach_btf, u32 btf_id, 2476290248a5SAndrii Nakryiko struct bpf_prog *dst_prog) 24775e43f899SAndrey Ignatov { 247827ae7997SMartin KaFai Lau if (btf_id) { 2479c108e3c1SAlexei Starovoitov if (btf_id > BTF_MAX_TYPE) 2480c108e3c1SAlexei Starovoitov return -EINVAL; 248127ae7997SMartin KaFai Lau 2482290248a5SAndrii Nakryiko if (!attach_btf && !dst_prog) 2483290248a5SAndrii Nakryiko return -EINVAL; 2484290248a5SAndrii Nakryiko 248527ae7997SMartin KaFai Lau switch (prog_type) { 248627ae7997SMartin KaFai Lau case BPF_PROG_TYPE_TRACING: 24879e4e01dfSKP Singh case BPF_PROG_TYPE_LSM: 248827ae7997SMartin KaFai Lau case BPF_PROG_TYPE_STRUCT_OPS: 2489be8704ffSAlexei Starovoitov case BPF_PROG_TYPE_EXT: 2490c108e3c1SAlexei Starovoitov break; 2491c108e3c1SAlexei Starovoitov default: 2492c108e3c1SAlexei Starovoitov return -EINVAL; 2493c108e3c1SAlexei Starovoitov } 249427ae7997SMartin KaFai Lau } 249527ae7997SMartin KaFai Lau 2496290248a5SAndrii Nakryiko if (attach_btf && (!btf_id || dst_prog)) 2497290248a5SAndrii Nakryiko return -EINVAL; 2498290248a5SAndrii Nakryiko 2499290248a5SAndrii Nakryiko if (dst_prog && prog_type != BPF_PROG_TYPE_TRACING && 2500be8704ffSAlexei Starovoitov prog_type != BPF_PROG_TYPE_EXT) 250127ae7997SMartin KaFai Lau return -EINVAL; 2502c108e3c1SAlexei Starovoitov 2503c108e3c1SAlexei Starovoitov switch (prog_type) { 2504aac3fc32SAndrey Ignatov case BPF_PROG_TYPE_CGROUP_SOCK: 2505aac3fc32SAndrey Ignatov switch (expected_attach_type) { 2506aac3fc32SAndrey Ignatov case BPF_CGROUP_INET_SOCK_CREATE: 2507f5836749SStanislav Fomichev case BPF_CGROUP_INET_SOCK_RELEASE: 2508aac3fc32SAndrey Ignatov case BPF_CGROUP_INET4_POST_BIND: 2509aac3fc32SAndrey Ignatov case BPF_CGROUP_INET6_POST_BIND: 2510aac3fc32SAndrey Ignatov return 0; 2511aac3fc32SAndrey Ignatov default: 2512aac3fc32SAndrey Ignatov return -EINVAL; 2513aac3fc32SAndrey Ignatov } 25144fbac77dSAndrey Ignatov case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: 25154fbac77dSAndrey Ignatov switch (expected_attach_type) { 25164fbac77dSAndrey Ignatov case BPF_CGROUP_INET4_BIND: 25174fbac77dSAndrey Ignatov case BPF_CGROUP_INET6_BIND: 2518d74bad4eSAndrey Ignatov case BPF_CGROUP_INET4_CONNECT: 2519d74bad4eSAndrey Ignatov case BPF_CGROUP_INET6_CONNECT: 2520859051ddSDaan De Meyer case BPF_CGROUP_UNIX_CONNECT: 25211b66d253SDaniel Borkmann case BPF_CGROUP_INET4_GETPEERNAME: 25221b66d253SDaniel Borkmann case BPF_CGROUP_INET6_GETPEERNAME: 2523859051ddSDaan De Meyer case BPF_CGROUP_UNIX_GETPEERNAME: 25241b66d253SDaniel Borkmann case BPF_CGROUP_INET4_GETSOCKNAME: 25251b66d253SDaniel Borkmann case BPF_CGROUP_INET6_GETSOCKNAME: 2526859051ddSDaan De Meyer case BPF_CGROUP_UNIX_GETSOCKNAME: 25271cedee13SAndrey Ignatov case BPF_CGROUP_UDP4_SENDMSG: 25281cedee13SAndrey Ignatov case BPF_CGROUP_UDP6_SENDMSG: 2529859051ddSDaan De Meyer case BPF_CGROUP_UNIX_SENDMSG: 2530983695faSDaniel Borkmann case BPF_CGROUP_UDP4_RECVMSG: 2531983695faSDaniel Borkmann case BPF_CGROUP_UDP6_RECVMSG: 2532859051ddSDaan De Meyer case BPF_CGROUP_UNIX_RECVMSG: 25335e43f899SAndrey Ignatov return 0; 25344fbac77dSAndrey Ignatov default: 25354fbac77dSAndrey Ignatov return -EINVAL; 25364fbac77dSAndrey Ignatov } 25375cf1e914Sbrakmo case BPF_PROG_TYPE_CGROUP_SKB: 25385cf1e914Sbrakmo switch (expected_attach_type) { 25395cf1e914Sbrakmo case BPF_CGROUP_INET_INGRESS: 25405cf1e914Sbrakmo case BPF_CGROUP_INET_EGRESS: 25415cf1e914Sbrakmo return 0; 25425cf1e914Sbrakmo default: 25435cf1e914Sbrakmo return -EINVAL; 25445cf1e914Sbrakmo } 25450d01da6aSStanislav Fomichev case BPF_PROG_TYPE_CGROUP_SOCKOPT: 25460d01da6aSStanislav Fomichev switch (expected_attach_type) { 25470d01da6aSStanislav Fomichev case BPF_CGROUP_SETSOCKOPT: 25480d01da6aSStanislav Fomichev case BPF_CGROUP_GETSOCKOPT: 25490d01da6aSStanislav Fomichev return 0; 25500d01da6aSStanislav Fomichev default: 25510d01da6aSStanislav Fomichev return -EINVAL; 25520d01da6aSStanislav Fomichev } 2553e9ddbb77SJakub Sitnicki case BPF_PROG_TYPE_SK_LOOKUP: 2554e9ddbb77SJakub Sitnicki if (expected_attach_type == BPF_SK_LOOKUP) 2555e9ddbb77SJakub Sitnicki return 0; 2556e9ddbb77SJakub Sitnicki return -EINVAL; 2557d5e4ddaeSKuniyuki Iwashima case BPF_PROG_TYPE_SK_REUSEPORT: 2558d5e4ddaeSKuniyuki Iwashima switch (expected_attach_type) { 2559d5e4ddaeSKuniyuki Iwashima case BPF_SK_REUSEPORT_SELECT: 2560d5e4ddaeSKuniyuki Iwashima case BPF_SK_REUSEPORT_SELECT_OR_MIGRATE: 2561d5e4ddaeSKuniyuki Iwashima return 0; 2562d5e4ddaeSKuniyuki Iwashima default: 2563d5e4ddaeSKuniyuki Iwashima return -EINVAL; 2564d5e4ddaeSKuniyuki Iwashima } 2565132328e8SFlorian Westphal case BPF_PROG_TYPE_NETFILTER: 2566132328e8SFlorian Westphal if (expected_attach_type == BPF_NETFILTER) 2567132328e8SFlorian Westphal return 0; 2568132328e8SFlorian Westphal return -EINVAL; 256979a7f8bdSAlexei Starovoitov case BPF_PROG_TYPE_SYSCALL: 2570be8704ffSAlexei Starovoitov case BPF_PROG_TYPE_EXT: 2571be8704ffSAlexei Starovoitov if (expected_attach_type) 2572be8704ffSAlexei Starovoitov return -EINVAL; 2573df561f66SGustavo A. R. Silva fallthrough; 25744fbac77dSAndrey Ignatov default: 25754fbac77dSAndrey Ignatov return 0; 25764fbac77dSAndrey Ignatov } 25775e43f899SAndrey Ignatov } 25785e43f899SAndrey Ignatov 25792c78ee89SAlexei Starovoitov static bool is_net_admin_prog_type(enum bpf_prog_type prog_type) 25802c78ee89SAlexei Starovoitov { 25812c78ee89SAlexei Starovoitov switch (prog_type) { 25822c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_SCHED_CLS: 25832c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_SCHED_ACT: 25842c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_XDP: 25852c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_LWT_IN: 25862c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_LWT_OUT: 25872c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_LWT_XMIT: 25882c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_LWT_SEG6LOCAL: 25892c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_SK_SKB: 25902c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_SK_MSG: 25912c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_FLOW_DISSECTOR: 25922c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_CGROUP_DEVICE: 25932c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_CGROUP_SOCK: 25942c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: 25952c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_CGROUP_SOCKOPT: 25962c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_CGROUP_SYSCTL: 25972c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_SOCK_OPS: 25982c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_EXT: /* extends any prog */ 259984601d6eSFlorian Westphal case BPF_PROG_TYPE_NETFILTER: 26002c78ee89SAlexei Starovoitov return true; 26012c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_CGROUP_SKB: 26022c78ee89SAlexei Starovoitov /* always unpriv */ 26032c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_SK_REUSEPORT: 26042c78ee89SAlexei Starovoitov /* equivalent to SOCKET_FILTER. need CAP_BPF only */ 26052c78ee89SAlexei Starovoitov default: 26062c78ee89SAlexei Starovoitov return false; 26072c78ee89SAlexei Starovoitov } 26082c78ee89SAlexei Starovoitov } 26092c78ee89SAlexei Starovoitov 26102c78ee89SAlexei Starovoitov static bool is_perfmon_prog_type(enum bpf_prog_type prog_type) 26112c78ee89SAlexei Starovoitov { 26122c78ee89SAlexei Starovoitov switch (prog_type) { 26132c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_KPROBE: 26142c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_TRACEPOINT: 26152c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_PERF_EVENT: 26162c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_RAW_TRACEPOINT: 26172c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE: 26182c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_TRACING: 26192c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_LSM: 26202c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_STRUCT_OPS: /* has access to struct sock */ 26212c78ee89SAlexei Starovoitov case BPF_PROG_TYPE_EXT: /* extends any prog */ 26222c78ee89SAlexei Starovoitov return true; 26232c78ee89SAlexei Starovoitov default: 26242c78ee89SAlexei Starovoitov return false; 26252c78ee89SAlexei Starovoitov } 26262c78ee89SAlexei Starovoitov } 26272c78ee89SAlexei Starovoitov 262809756af4SAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */ 2629caf8f28eSAndrii Nakryiko #define BPF_PROG_LOAD_LAST_FIELD prog_token_fd 263009756af4SAlexei Starovoitov 263147a71c1fSAndrii Nakryiko static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) 263209756af4SAlexei Starovoitov { 263309756af4SAlexei Starovoitov enum bpf_prog_type type = attr->prog_type; 2634290248a5SAndrii Nakryiko struct bpf_prog *prog, *dst_prog = NULL; 2635290248a5SAndrii Nakryiko struct btf *attach_btf = NULL; 2636caf8f28eSAndrii Nakryiko struct bpf_token *token = NULL; 2637caf8f28eSAndrii Nakryiko bool bpf_cap; 263809756af4SAlexei Starovoitov int err; 263909756af4SAlexei Starovoitov char license[128]; 264009756af4SAlexei Starovoitov 264109756af4SAlexei Starovoitov if (CHECK_ATTR(BPF_PROG_LOAD)) 264209756af4SAlexei Starovoitov return -EINVAL; 264309756af4SAlexei Starovoitov 2644c240eff6SJiong Wang if (attr->prog_flags & ~(BPF_F_STRICT_ALIGNMENT | 2645c240eff6SJiong Wang BPF_F_ANY_ALIGNMENT | 264610d274e8SAlexei Starovoitov BPF_F_TEST_STATE_FREQ | 26471e6c62a8SAlexei Starovoitov BPF_F_SLEEPABLE | 2648c2f2cdbeSLorenzo Bianconi BPF_F_TEST_RND_HI32 | 26492b3486bcSStanislav Fomichev BPF_F_XDP_HAS_FRAGS | 26505f99f312SAndrii Nakryiko BPF_F_XDP_DEV_BOUND_ONLY | 2651caf8f28eSAndrii Nakryiko BPF_F_TEST_REG_INVARIANTS | 2652caf8f28eSAndrii Nakryiko BPF_F_TOKEN_FD)) 2653e07b98d9SDavid S. Miller return -EINVAL; 2654e07b98d9SDavid S. Miller 2655caf8f28eSAndrii Nakryiko bpf_prog_load_fixup_attach_type(attr); 2656caf8f28eSAndrii Nakryiko 2657caf8f28eSAndrii Nakryiko if (attr->prog_flags & BPF_F_TOKEN_FD) { 2658caf8f28eSAndrii Nakryiko token = bpf_token_get_from_fd(attr->prog_token_fd); 2659caf8f28eSAndrii Nakryiko if (IS_ERR(token)) 2660caf8f28eSAndrii Nakryiko return PTR_ERR(token); 2661caf8f28eSAndrii Nakryiko /* if current token doesn't grant prog loading permissions, 2662caf8f28eSAndrii Nakryiko * then we can't use this token, so ignore it and rely on 2663caf8f28eSAndrii Nakryiko * system-wide capabilities checks 2664caf8f28eSAndrii Nakryiko */ 2665caf8f28eSAndrii Nakryiko if (!bpf_token_allow_cmd(token, BPF_PROG_LOAD) || 2666caf8f28eSAndrii Nakryiko !bpf_token_allow_prog_type(token, attr->prog_type, 2667caf8f28eSAndrii Nakryiko attr->expected_attach_type)) { 2668caf8f28eSAndrii Nakryiko bpf_token_put(token); 2669caf8f28eSAndrii Nakryiko token = NULL; 2670caf8f28eSAndrii Nakryiko } 2671caf8f28eSAndrii Nakryiko } 2672caf8f28eSAndrii Nakryiko 2673caf8f28eSAndrii Nakryiko bpf_cap = bpf_token_capable(token, CAP_BPF); 2674caf8f28eSAndrii Nakryiko err = -EPERM; 2675caf8f28eSAndrii Nakryiko 2676e9ee9efcSDavid Miller if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && 2677e9ee9efcSDavid Miller (attr->prog_flags & BPF_F_ANY_ALIGNMENT) && 2678caf8f28eSAndrii Nakryiko !bpf_cap) 2679caf8f28eSAndrii Nakryiko goto put_token; 2680e9ee9efcSDavid Miller 26811d28635aSAndrii Nakryiko /* Intent here is for unprivileged_bpf_disabled to block BPF program 26821d28635aSAndrii Nakryiko * creation for unprivileged users; other actions depend 26831d28635aSAndrii Nakryiko * on fd availability and access to bpffs, so are dependent on 26841d28635aSAndrii Nakryiko * object creation success. Even with unprivileged BPF disabled, 26851d28635aSAndrii Nakryiko * capability checks are still carried out for these 26861d28635aSAndrii Nakryiko * and other operations. 26871d28635aSAndrii Nakryiko */ 2688caf8f28eSAndrii Nakryiko if (sysctl_unprivileged_bpf_disabled && !bpf_cap) 2689caf8f28eSAndrii Nakryiko goto put_token; 269009756af4SAlexei Starovoitov 2691c04c0d2bSAlexei Starovoitov if (attr->insn_cnt == 0 || 2692caf8f28eSAndrii Nakryiko attr->insn_cnt > (bpf_cap ? BPF_COMPLEXITY_LIMIT_INSNS : BPF_MAXINSNS)) { 2693caf8f28eSAndrii Nakryiko err = -E2BIG; 2694caf8f28eSAndrii Nakryiko goto put_token; 2695caf8f28eSAndrii Nakryiko } 269680b7d819SChenbo Feng if (type != BPF_PROG_TYPE_SOCKET_FILTER && 269780b7d819SChenbo Feng type != BPF_PROG_TYPE_CGROUP_SKB && 2698caf8f28eSAndrii Nakryiko !bpf_cap) 2699caf8f28eSAndrii Nakryiko goto put_token; 27002c78ee89SAlexei Starovoitov 2701caf8f28eSAndrii Nakryiko if (is_net_admin_prog_type(type) && !bpf_token_capable(token, CAP_NET_ADMIN)) 2702caf8f28eSAndrii Nakryiko goto put_token; 2703caf8f28eSAndrii Nakryiko if (is_perfmon_prog_type(type) && !bpf_token_capable(token, CAP_PERFMON)) 2704caf8f28eSAndrii Nakryiko goto put_token; 27051be7f75dSAlexei Starovoitov 2706290248a5SAndrii Nakryiko /* attach_prog_fd/attach_btf_obj_fd can specify fd of either bpf_prog 2707290248a5SAndrii Nakryiko * or btf, we need to check which one it is 2708290248a5SAndrii Nakryiko */ 2709290248a5SAndrii Nakryiko if (attr->attach_prog_fd) { 2710290248a5SAndrii Nakryiko dst_prog = bpf_prog_get(attr->attach_prog_fd); 2711290248a5SAndrii Nakryiko if (IS_ERR(dst_prog)) { 2712290248a5SAndrii Nakryiko dst_prog = NULL; 2713290248a5SAndrii Nakryiko attach_btf = btf_get_by_fd(attr->attach_btf_obj_fd); 2714caf8f28eSAndrii Nakryiko if (IS_ERR(attach_btf)) { 2715caf8f28eSAndrii Nakryiko err = -EINVAL; 2716caf8f28eSAndrii Nakryiko goto put_token; 2717caf8f28eSAndrii Nakryiko } 2718290248a5SAndrii Nakryiko if (!btf_is_kernel(attach_btf)) { 27198bdd8e27SAndrii Nakryiko /* attaching through specifying bpf_prog's BTF 27208bdd8e27SAndrii Nakryiko * objects directly might be supported eventually 27218bdd8e27SAndrii Nakryiko */ 2722290248a5SAndrii Nakryiko btf_put(attach_btf); 2723caf8f28eSAndrii Nakryiko err = -ENOTSUPP; 2724caf8f28eSAndrii Nakryiko goto put_token; 2725290248a5SAndrii Nakryiko } 2726290248a5SAndrii Nakryiko } 2727290248a5SAndrii Nakryiko } else if (attr->attach_btf_id) { 2728290248a5SAndrii Nakryiko /* fall back to vmlinux BTF, if BTF type ID is specified */ 2729290248a5SAndrii Nakryiko attach_btf = bpf_get_btf_vmlinux(); 2730caf8f28eSAndrii Nakryiko if (IS_ERR(attach_btf)) { 2731caf8f28eSAndrii Nakryiko err = PTR_ERR(attach_btf); 2732caf8f28eSAndrii Nakryiko goto put_token; 2733caf8f28eSAndrii Nakryiko } 2734caf8f28eSAndrii Nakryiko if (!attach_btf) { 2735caf8f28eSAndrii Nakryiko err = -EINVAL; 2736caf8f28eSAndrii Nakryiko goto put_token; 2737caf8f28eSAndrii Nakryiko } 2738290248a5SAndrii Nakryiko btf_get(attach_btf); 2739290248a5SAndrii Nakryiko } 2740290248a5SAndrii Nakryiko 2741ccfe29ebSAlexei Starovoitov if (bpf_prog_load_check_attach(type, attr->expected_attach_type, 2742290248a5SAndrii Nakryiko attach_btf, attr->attach_btf_id, 2743290248a5SAndrii Nakryiko dst_prog)) { 2744290248a5SAndrii Nakryiko if (dst_prog) 2745290248a5SAndrii Nakryiko bpf_prog_put(dst_prog); 2746290248a5SAndrii Nakryiko if (attach_btf) 2747290248a5SAndrii Nakryiko btf_put(attach_btf); 2748caf8f28eSAndrii Nakryiko err = -EINVAL; 2749caf8f28eSAndrii Nakryiko goto put_token; 2750290248a5SAndrii Nakryiko } 27515e43f899SAndrey Ignatov 275209756af4SAlexei Starovoitov /* plain bpf_prog allocation */ 275309756af4SAlexei Starovoitov prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER); 2754290248a5SAndrii Nakryiko if (!prog) { 2755290248a5SAndrii Nakryiko if (dst_prog) 2756290248a5SAndrii Nakryiko bpf_prog_put(dst_prog); 2757290248a5SAndrii Nakryiko if (attach_btf) 2758290248a5SAndrii Nakryiko btf_put(attach_btf); 2759caf8f28eSAndrii Nakryiko err = -EINVAL; 2760caf8f28eSAndrii Nakryiko goto put_token; 2761290248a5SAndrii Nakryiko } 276209756af4SAlexei Starovoitov 27635e43f899SAndrey Ignatov prog->expected_attach_type = attr->expected_attach_type; 2764290248a5SAndrii Nakryiko prog->aux->attach_btf = attach_btf; 2765ccfe29ebSAlexei Starovoitov prog->aux->attach_btf_id = attr->attach_btf_id; 27663aac1eadSToke Høiland-Jørgensen prog->aux->dst_prog = dst_prog; 27672b3486bcSStanislav Fomichev prog->aux->dev_bound = !!attr->prog_ifindex; 27681e6c62a8SAlexei Starovoitov prog->aux->sleepable = attr->prog_flags & BPF_F_SLEEPABLE; 2769c2f2cdbeSLorenzo Bianconi prog->aux->xdp_has_frags = attr->prog_flags & BPF_F_XDP_HAS_FRAGS; 27709a18eedbSJakub Kicinski 2771caf8f28eSAndrii Nakryiko /* move token into prog->aux, reuse taken refcnt */ 2772caf8f28eSAndrii Nakryiko prog->aux->token = token; 2773caf8f28eSAndrii Nakryiko token = NULL; 2774caf8f28eSAndrii Nakryiko 2775d17aff80SAndrii Nakryiko err = security_bpf_prog_alloc(prog->aux); 2776d17aff80SAndrii Nakryiko if (err) 2777d17aff80SAndrii Nakryiko goto free_prog; 2778e1cef620SAndrii Nakryiko 27793ac1f01bSRoman Gushchin prog->aux->user = get_current_user(); 278009756af4SAlexei Starovoitov prog->len = attr->insn_cnt; 278109756af4SAlexei Starovoitov 278209756af4SAlexei Starovoitov err = -EFAULT; 2783af2ac3e1SAlexei Starovoitov if (copy_from_bpfptr(prog->insns, 2784af2ac3e1SAlexei Starovoitov make_bpfptr(attr->insns, uattr.is_kernel), 2785aafe6ae9SDaniel Borkmann bpf_prog_insn_size(prog)) != 0) 2786d17aff80SAndrii Nakryiko goto free_prog_sec; 27877f6719f7SAndrii Nakryiko /* copy eBPF program license from user space */ 27887f6719f7SAndrii Nakryiko if (strncpy_from_bpfptr(license, 27897f6719f7SAndrii Nakryiko make_bpfptr(attr->license, uattr.is_kernel), 27907f6719f7SAndrii Nakryiko sizeof(license) - 1) < 0) 2791d17aff80SAndrii Nakryiko goto free_prog_sec; 27927f6719f7SAndrii Nakryiko license[sizeof(license) - 1] = 0; 27937f6719f7SAndrii Nakryiko 27947f6719f7SAndrii Nakryiko /* eBPF programs must be GPL compatible to use GPL-ed functions */ 27957f6719f7SAndrii Nakryiko prog->gpl_compatible = license_is_gpl_compatible(license) ? 1 : 0; 279609756af4SAlexei Starovoitov 279709756af4SAlexei Starovoitov prog->orig_prog = NULL; 2798a91263d5SDaniel Borkmann prog->jited = 0; 279909756af4SAlexei Starovoitov 280085192dbfSAndrii Nakryiko atomic64_set(&prog->aux->refcnt, 1); 280109756af4SAlexei Starovoitov 28029a18eedbSJakub Kicinski if (bpf_prog_is_dev_bound(prog->aux)) { 28032b3486bcSStanislav Fomichev err = bpf_prog_dev_bound_init(prog, attr); 2804ab3f0063SJakub Kicinski if (err) 2805d17aff80SAndrii Nakryiko goto free_prog_sec; 2806ab3f0063SJakub Kicinski } 2807ab3f0063SJakub Kicinski 2808fd7c211dSToke Høiland-Jørgensen if (type == BPF_PROG_TYPE_EXT && dst_prog && 2809fd7c211dSToke Høiland-Jørgensen bpf_prog_is_dev_bound(dst_prog->aux)) { 2810fd7c211dSToke Høiland-Jørgensen err = bpf_prog_dev_bound_inherit(prog, dst_prog); 2811cb4d2b3fSMartin KaFai Lau if (err) 2812d17aff80SAndrii Nakryiko goto free_prog_sec; 2813cb4d2b3fSMartin KaFai Lau } 2814cb4d2b3fSMartin KaFai Lau 281519bfcdf9SDmitrii Dolgov /* 281619bfcdf9SDmitrii Dolgov * Bookkeeping for managing the program attachment chain. 281719bfcdf9SDmitrii Dolgov * 281819bfcdf9SDmitrii Dolgov * It might be tempting to set attach_tracing_prog flag at the attachment 281919bfcdf9SDmitrii Dolgov * time, but this will not prevent from loading bunch of tracing prog 282019bfcdf9SDmitrii Dolgov * first, then attach them one to another. 282119bfcdf9SDmitrii Dolgov * 282219bfcdf9SDmitrii Dolgov * The flag attach_tracing_prog is set for the whole program lifecycle, and 282319bfcdf9SDmitrii Dolgov * doesn't have to be cleared in bpf_tracing_link_release, since tracing 282419bfcdf9SDmitrii Dolgov * programs cannot change attachment target. 282519bfcdf9SDmitrii Dolgov */ 282619bfcdf9SDmitrii Dolgov if (type == BPF_PROG_TYPE_TRACING && dst_prog && 282719bfcdf9SDmitrii Dolgov dst_prog->type == BPF_PROG_TYPE_TRACING) { 282819bfcdf9SDmitrii Dolgov prog->aux->attach_tracing_prog = true; 282919bfcdf9SDmitrii Dolgov } 283019bfcdf9SDmitrii Dolgov 283109756af4SAlexei Starovoitov /* find program type: socket_filter vs tracing_filter */ 283209756af4SAlexei Starovoitov err = find_prog_type(type, prog); 283309756af4SAlexei Starovoitov if (err < 0) 2834d17aff80SAndrii Nakryiko goto free_prog_sec; 283509756af4SAlexei Starovoitov 28369285ec4cSJason A. Donenfeld prog->aux->load_time = ktime_get_boottime_ns(); 28378e7ae251SMartin KaFai Lau err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name, 28388e7ae251SMartin KaFai Lau sizeof(attr->prog_name)); 28398e7ae251SMartin KaFai Lau if (err < 0) 28403ac1f01bSRoman Gushchin goto free_prog_sec; 2841cb4d2b3fSMartin KaFai Lau 284209756af4SAlexei Starovoitov /* run eBPF verifier */ 284347a71c1fSAndrii Nakryiko err = bpf_check(&prog, attr, uattr, uattr_size); 284409756af4SAlexei Starovoitov if (err < 0) 284509756af4SAlexei Starovoitov goto free_used_maps; 284609756af4SAlexei Starovoitov 2847d1c55ab5SDaniel Borkmann prog = bpf_prog_select_runtime(prog, &err); 284804fd61abSAlexei Starovoitov if (err < 0) 284904fd61abSAlexei Starovoitov goto free_used_maps; 285009756af4SAlexei Starovoitov 2851dc4bb0e2SMartin KaFai Lau err = bpf_prog_alloc_id(prog); 2852dc4bb0e2SMartin KaFai Lau if (err) 2853dc4bb0e2SMartin KaFai Lau goto free_used_maps; 2854dc4bb0e2SMartin KaFai Lau 2855c751798aSDaniel Borkmann /* Upon success of bpf_prog_alloc_id(), the BPF prog is 2856c751798aSDaniel Borkmann * effectively publicly exposed. However, retrieving via 2857c751798aSDaniel Borkmann * bpf_prog_get_fd_by_id() will take another reference, 2858c751798aSDaniel Borkmann * therefore it cannot be gone underneath us. 2859c751798aSDaniel Borkmann * 2860c751798aSDaniel Borkmann * Only for the time /after/ successful bpf_prog_new_fd() 2861c751798aSDaniel Borkmann * and before returning to userspace, we might just hold 2862c751798aSDaniel Borkmann * one reference and any parallel close on that fd could 2863c751798aSDaniel Borkmann * rip everything out. Hence, below notifications must 2864c751798aSDaniel Borkmann * happen before bpf_prog_new_fd(). 2865c751798aSDaniel Borkmann * 2866c751798aSDaniel Borkmann * Also, any failure handling from this point onwards must 2867c751798aSDaniel Borkmann * be using bpf_prog_put() given the program is exposed. 2868b16d9aa4SMartin KaFai Lau */ 286974451e66SDaniel Borkmann bpf_prog_kallsyms_add(prog); 28706ee52e2aSSong Liu perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_LOAD, 0); 2871bae141f5SDaniel Borkmann bpf_audit_prog(prog, BPF_AUDIT_LOAD); 2872c751798aSDaniel Borkmann 2873c751798aSDaniel Borkmann err = bpf_prog_new_fd(prog); 2874c751798aSDaniel Borkmann if (err < 0) 2875c751798aSDaniel Borkmann bpf_prog_put(prog); 287609756af4SAlexei Starovoitov return err; 287709756af4SAlexei Starovoitov 287809756af4SAlexei Starovoitov free_used_maps: 2879cd7455f1SDaniel Borkmann /* In case we have subprogs, we need to wait for a grace 2880cd7455f1SDaniel Borkmann * period before we can tear down JIT memory since symbols 2881cd7455f1SDaniel Borkmann * are already exposed under kallsyms. 2882cd7455f1SDaniel Borkmann */ 2883335d1c5bSKumar Kartikeya Dwivedi __bpf_prog_put_noref(prog, prog->aux->real_func_cnt); 2884cd7455f1SDaniel Borkmann return err; 2885afdb09c7SChenbo Feng free_prog_sec: 2886c3dd6e94SAndrii Nakryiko free_uid(prog->aux->user); 2887d17aff80SAndrii Nakryiko security_bpf_prog_free(prog->aux); 2888d17aff80SAndrii Nakryiko free_prog: 288922dc4a0fSAndrii Nakryiko if (prog->aux->attach_btf) 289022dc4a0fSAndrii Nakryiko btf_put(prog->aux->attach_btf); 289109756af4SAlexei Starovoitov bpf_prog_free(prog); 2892caf8f28eSAndrii Nakryiko put_token: 2893caf8f28eSAndrii Nakryiko bpf_token_put(token); 289409756af4SAlexei Starovoitov return err; 289509756af4SAlexei Starovoitov } 289609756af4SAlexei Starovoitov 2897cb8edce2SAndrii Nakryiko #define BPF_OBJ_LAST_FIELD path_fd 2898b2197755SDaniel Borkmann 2899b2197755SDaniel Borkmann static int bpf_obj_pin(const union bpf_attr *attr) 2900b2197755SDaniel Borkmann { 2901cb8edce2SAndrii Nakryiko int path_fd; 2902cb8edce2SAndrii Nakryiko 2903cb8edce2SAndrii Nakryiko if (CHECK_ATTR(BPF_OBJ) || attr->file_flags & ~BPF_F_PATH_FD) 2904b2197755SDaniel Borkmann return -EINVAL; 2905b2197755SDaniel Borkmann 2906cb8edce2SAndrii Nakryiko /* path_fd has to be accompanied by BPF_F_PATH_FD flag */ 2907cb8edce2SAndrii Nakryiko if (!(attr->file_flags & BPF_F_PATH_FD) && attr->path_fd) 2908cb8edce2SAndrii Nakryiko return -EINVAL; 2909cb8edce2SAndrii Nakryiko 2910cb8edce2SAndrii Nakryiko path_fd = attr->file_flags & BPF_F_PATH_FD ? attr->path_fd : AT_FDCWD; 2911cb8edce2SAndrii Nakryiko return bpf_obj_pin_user(attr->bpf_fd, path_fd, 2912cb8edce2SAndrii Nakryiko u64_to_user_ptr(attr->pathname)); 2913b2197755SDaniel Borkmann } 2914b2197755SDaniel Borkmann 2915b2197755SDaniel Borkmann static int bpf_obj_get(const union bpf_attr *attr) 2916b2197755SDaniel Borkmann { 2917cb8edce2SAndrii Nakryiko int path_fd; 2918cb8edce2SAndrii Nakryiko 29196e71b04aSChenbo Feng if (CHECK_ATTR(BPF_OBJ) || attr->bpf_fd != 0 || 2920cb8edce2SAndrii Nakryiko attr->file_flags & ~(BPF_OBJ_FLAG_MASK | BPF_F_PATH_FD)) 2921b2197755SDaniel Borkmann return -EINVAL; 2922b2197755SDaniel Borkmann 2923cb8edce2SAndrii Nakryiko /* path_fd has to be accompanied by BPF_F_PATH_FD flag */ 2924cb8edce2SAndrii Nakryiko if (!(attr->file_flags & BPF_F_PATH_FD) && attr->path_fd) 2925cb8edce2SAndrii Nakryiko return -EINVAL; 2926cb8edce2SAndrii Nakryiko 2927cb8edce2SAndrii Nakryiko path_fd = attr->file_flags & BPF_F_PATH_FD ? attr->path_fd : AT_FDCWD; 2928cb8edce2SAndrii Nakryiko return bpf_obj_get_user(path_fd, u64_to_user_ptr(attr->pathname), 29296e71b04aSChenbo Feng attr->file_flags); 2930b2197755SDaniel Borkmann } 2931b2197755SDaniel Borkmann 2932f2e10bffSAndrii Nakryiko void bpf_link_init(struct bpf_link *link, enum bpf_link_type type, 2933a3b80e10SAndrii Nakryiko const struct bpf_link_ops *ops, struct bpf_prog *prog) 293470ed506cSAndrii Nakryiko { 293570ed506cSAndrii Nakryiko atomic64_set(&link->refcnt, 1); 2936f2e10bffSAndrii Nakryiko link->type = type; 2937a3b80e10SAndrii Nakryiko link->id = 0; 293870ed506cSAndrii Nakryiko link->ops = ops; 293970ed506cSAndrii Nakryiko link->prog = prog; 294070ed506cSAndrii Nakryiko } 294170ed506cSAndrii Nakryiko 2942a3b80e10SAndrii Nakryiko static void bpf_link_free_id(int id) 2943a3b80e10SAndrii Nakryiko { 2944a3b80e10SAndrii Nakryiko if (!id) 2945a3b80e10SAndrii Nakryiko return; 2946a3b80e10SAndrii Nakryiko 2947a3b80e10SAndrii Nakryiko spin_lock_bh(&link_idr_lock); 2948a3b80e10SAndrii Nakryiko idr_remove(&link_idr, id); 2949a3b80e10SAndrii Nakryiko spin_unlock_bh(&link_idr_lock); 2950a3b80e10SAndrii Nakryiko } 2951a3b80e10SAndrii Nakryiko 295298868668SAndrii Nakryiko /* Clean up bpf_link and corresponding anon_inode file and FD. After 295398868668SAndrii Nakryiko * anon_inode is created, bpf_link can't be just kfree()'d due to deferred 2954a3b80e10SAndrii Nakryiko * anon_inode's release() call. This helper marks bpf_link as 2955a3b80e10SAndrii Nakryiko * defunct, releases anon_inode file and puts reserved FD. bpf_prog's refcnt 2956a3b80e10SAndrii Nakryiko * is not decremented, it's the responsibility of a calling code that failed 2957a3b80e10SAndrii Nakryiko * to complete bpf_link initialization. 295889ae89f5SJiri Olsa * This helper eventually calls link's dealloc callback, but does not call 295989ae89f5SJiri Olsa * link's release callback. 296098868668SAndrii Nakryiko */ 2961a3b80e10SAndrii Nakryiko void bpf_link_cleanup(struct bpf_link_primer *primer) 2962babf3164SAndrii Nakryiko { 2963a3b80e10SAndrii Nakryiko primer->link->prog = NULL; 2964a3b80e10SAndrii Nakryiko bpf_link_free_id(primer->id); 2965a3b80e10SAndrii Nakryiko fput(primer->file); 2966a3b80e10SAndrii Nakryiko put_unused_fd(primer->fd); 2967babf3164SAndrii Nakryiko } 2968babf3164SAndrii Nakryiko 296970ed506cSAndrii Nakryiko void bpf_link_inc(struct bpf_link *link) 297070ed506cSAndrii Nakryiko { 297170ed506cSAndrii Nakryiko atomic64_inc(&link->refcnt); 297270ed506cSAndrii Nakryiko } 297370ed506cSAndrii Nakryiko 297470ed506cSAndrii Nakryiko /* bpf_link_free is guaranteed to be called from process context */ 297570ed506cSAndrii Nakryiko static void bpf_link_free(struct bpf_link *link) 297670ed506cSAndrii Nakryiko { 2977a3b80e10SAndrii Nakryiko bpf_link_free_id(link->id); 2978babf3164SAndrii Nakryiko if (link->prog) { 2979babf3164SAndrii Nakryiko /* detach BPF program, clean up used resources */ 298070ed506cSAndrii Nakryiko link->ops->release(link); 2981babf3164SAndrii Nakryiko bpf_prog_put(link->prog); 2982babf3164SAndrii Nakryiko } 2983babf3164SAndrii Nakryiko /* free bpf_link and its containing memory */ 2984babf3164SAndrii Nakryiko link->ops->dealloc(link); 298570ed506cSAndrii Nakryiko } 298670ed506cSAndrii Nakryiko 298770ed506cSAndrii Nakryiko static void bpf_link_put_deferred(struct work_struct *work) 298870ed506cSAndrii Nakryiko { 298970ed506cSAndrii Nakryiko struct bpf_link *link = container_of(work, struct bpf_link, work); 299070ed506cSAndrii Nakryiko 299170ed506cSAndrii Nakryiko bpf_link_free(link); 299270ed506cSAndrii Nakryiko } 299370ed506cSAndrii Nakryiko 2994ab5d47bdSSebastian Andrzej Siewior /* bpf_link_put might be called from atomic context. It needs to be called 2995ab5d47bdSSebastian Andrzej Siewior * from sleepable context in order to acquire sleeping locks during the process. 299670ed506cSAndrii Nakryiko */ 299770ed506cSAndrii Nakryiko void bpf_link_put(struct bpf_link *link) 299870ed506cSAndrii Nakryiko { 299970ed506cSAndrii Nakryiko if (!atomic64_dec_and_test(&link->refcnt)) 300070ed506cSAndrii Nakryiko return; 300170ed506cSAndrii Nakryiko 300270ed506cSAndrii Nakryiko INIT_WORK(&link->work, bpf_link_put_deferred); 300370ed506cSAndrii Nakryiko schedule_work(&link->work); 300470ed506cSAndrii Nakryiko } 3005cb80ddc6SAlexei Starovoitov EXPORT_SYMBOL(bpf_link_put); 300670ed506cSAndrii Nakryiko 3007ab5d47bdSSebastian Andrzej Siewior static void bpf_link_put_direct(struct bpf_link *link) 3008ab5d47bdSSebastian Andrzej Siewior { 3009ab5d47bdSSebastian Andrzej Siewior if (!atomic64_dec_and_test(&link->refcnt)) 3010ab5d47bdSSebastian Andrzej Siewior return; 3011ab5d47bdSSebastian Andrzej Siewior bpf_link_free(link); 3012ab5d47bdSSebastian Andrzej Siewior } 3013ab5d47bdSSebastian Andrzej Siewior 301470ed506cSAndrii Nakryiko static int bpf_link_release(struct inode *inode, struct file *filp) 301570ed506cSAndrii Nakryiko { 301670ed506cSAndrii Nakryiko struct bpf_link *link = filp->private_data; 301770ed506cSAndrii Nakryiko 3018ab5d47bdSSebastian Andrzej Siewior bpf_link_put_direct(link); 3019fec56f58SAlexei Starovoitov return 0; 3020fec56f58SAlexei Starovoitov } 3021fec56f58SAlexei Starovoitov 302270ed506cSAndrii Nakryiko #ifdef CONFIG_PROC_FS 3023f2e10bffSAndrii Nakryiko #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) 3024f2e10bffSAndrii Nakryiko #define BPF_MAP_TYPE(_id, _ops) 3025f2e10bffSAndrii Nakryiko #define BPF_LINK_TYPE(_id, _name) [_id] = #_name, 3026f2e10bffSAndrii Nakryiko static const char *bpf_link_type_strs[] = { 3027f2e10bffSAndrii Nakryiko [BPF_LINK_TYPE_UNSPEC] = "<invalid>", 3028f2e10bffSAndrii Nakryiko #include <linux/bpf_types.h> 3029f2e10bffSAndrii Nakryiko }; 3030f2e10bffSAndrii Nakryiko #undef BPF_PROG_TYPE 3031f2e10bffSAndrii Nakryiko #undef BPF_MAP_TYPE 3032f2e10bffSAndrii Nakryiko #undef BPF_LINK_TYPE 303370ed506cSAndrii Nakryiko 303470ed506cSAndrii Nakryiko static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp) 303570ed506cSAndrii Nakryiko { 303670ed506cSAndrii Nakryiko const struct bpf_link *link = filp->private_data; 303770ed506cSAndrii Nakryiko const struct bpf_prog *prog = link->prog; 303870ed506cSAndrii Nakryiko char prog_tag[sizeof(prog->tag) * 2 + 1] = { }; 303970ed506cSAndrii Nakryiko 304070ed506cSAndrii Nakryiko seq_printf(m, 304170ed506cSAndrii Nakryiko "link_type:\t%s\n" 304268b04864SKui-Feng Lee "link_id:\t%u\n", 304368b04864SKui-Feng Lee bpf_link_type_strs[link->type], 304468b04864SKui-Feng Lee link->id); 304568b04864SKui-Feng Lee if (prog) { 304668b04864SKui-Feng Lee bin2hex(prog_tag, prog->tag, sizeof(prog->tag)); 304768b04864SKui-Feng Lee seq_printf(m, 304870ed506cSAndrii Nakryiko "prog_tag:\t%s\n" 304970ed506cSAndrii Nakryiko "prog_id:\t%u\n", 305070ed506cSAndrii Nakryiko prog_tag, 305170ed506cSAndrii Nakryiko prog->aux->id); 305268b04864SKui-Feng Lee } 3053f2e10bffSAndrii Nakryiko if (link->ops->show_fdinfo) 3054f2e10bffSAndrii Nakryiko link->ops->show_fdinfo(link, m); 305570ed506cSAndrii Nakryiko } 305670ed506cSAndrii Nakryiko #endif 305770ed506cSAndrii Nakryiko 30586f302bfbSZou Wei static const struct file_operations bpf_link_fops = { 305970ed506cSAndrii Nakryiko #ifdef CONFIG_PROC_FS 306070ed506cSAndrii Nakryiko .show_fdinfo = bpf_link_show_fdinfo, 306170ed506cSAndrii Nakryiko #endif 306270ed506cSAndrii Nakryiko .release = bpf_link_release, 3063fec56f58SAlexei Starovoitov .read = bpf_dummy_read, 3064fec56f58SAlexei Starovoitov .write = bpf_dummy_write, 3065fec56f58SAlexei Starovoitov }; 3066fec56f58SAlexei Starovoitov 3067a3b80e10SAndrii Nakryiko static int bpf_link_alloc_id(struct bpf_link *link) 306870ed506cSAndrii Nakryiko { 3069a3b80e10SAndrii Nakryiko int id; 3070a3b80e10SAndrii Nakryiko 3071a3b80e10SAndrii Nakryiko idr_preload(GFP_KERNEL); 3072a3b80e10SAndrii Nakryiko spin_lock_bh(&link_idr_lock); 3073a3b80e10SAndrii Nakryiko id = idr_alloc_cyclic(&link_idr, link, 1, INT_MAX, GFP_ATOMIC); 3074a3b80e10SAndrii Nakryiko spin_unlock_bh(&link_idr_lock); 3075a3b80e10SAndrii Nakryiko idr_preload_end(); 3076a3b80e10SAndrii Nakryiko 3077a3b80e10SAndrii Nakryiko return id; 307870ed506cSAndrii Nakryiko } 307970ed506cSAndrii Nakryiko 3080a3b80e10SAndrii Nakryiko /* Prepare bpf_link to be exposed to user-space by allocating anon_inode file, 3081a3b80e10SAndrii Nakryiko * reserving unused FD and allocating ID from link_idr. This is to be paired 3082a3b80e10SAndrii Nakryiko * with bpf_link_settle() to install FD and ID and expose bpf_link to 3083a3b80e10SAndrii Nakryiko * user-space, if bpf_link is successfully attached. If not, bpf_link and 3084a3b80e10SAndrii Nakryiko * pre-allocated resources are to be freed with bpf_cleanup() call. All the 3085a3b80e10SAndrii Nakryiko * transient state is passed around in struct bpf_link_primer. 3086a3b80e10SAndrii Nakryiko * This is preferred way to create and initialize bpf_link, especially when 3087a3b80e10SAndrii Nakryiko * there are complicated and expensive operations in between creating bpf_link 3088a3b80e10SAndrii Nakryiko * itself and attaching it to BPF hook. By using bpf_link_prime() and 3089a3b80e10SAndrii Nakryiko * bpf_link_settle() kernel code using bpf_link doesn't have to perform 3090a3b80e10SAndrii Nakryiko * expensive (and potentially failing) roll back operations in a rare case 3091a3b80e10SAndrii Nakryiko * that file, FD, or ID can't be allocated. 3092babf3164SAndrii Nakryiko */ 3093a3b80e10SAndrii Nakryiko int bpf_link_prime(struct bpf_link *link, struct bpf_link_primer *primer) 3094babf3164SAndrii Nakryiko { 3095babf3164SAndrii Nakryiko struct file *file; 3096a3b80e10SAndrii Nakryiko int fd, id; 3097babf3164SAndrii Nakryiko 3098babf3164SAndrii Nakryiko fd = get_unused_fd_flags(O_CLOEXEC); 3099babf3164SAndrii Nakryiko if (fd < 0) 3100a3b80e10SAndrii Nakryiko return fd; 3101babf3164SAndrii Nakryiko 3102babf3164SAndrii Nakryiko 3103a3b80e10SAndrii Nakryiko id = bpf_link_alloc_id(link); 3104a3b80e10SAndrii Nakryiko if (id < 0) { 3105a3b80e10SAndrii Nakryiko put_unused_fd(fd); 3106a3b80e10SAndrii Nakryiko return id; 3107a3b80e10SAndrii Nakryiko } 3108babf3164SAndrii Nakryiko 3109babf3164SAndrii Nakryiko file = anon_inode_getfile("bpf_link", &bpf_link_fops, link, O_CLOEXEC); 3110babf3164SAndrii Nakryiko if (IS_ERR(file)) { 3111138c6767SAndrii Nakryiko bpf_link_free_id(id); 3112babf3164SAndrii Nakryiko put_unused_fd(fd); 3113138c6767SAndrii Nakryiko return PTR_ERR(file); 3114babf3164SAndrii Nakryiko } 3115babf3164SAndrii Nakryiko 3116a3b80e10SAndrii Nakryiko primer->link = link; 3117a3b80e10SAndrii Nakryiko primer->file = file; 3118a3b80e10SAndrii Nakryiko primer->fd = fd; 3119a3b80e10SAndrii Nakryiko primer->id = id; 3120a3b80e10SAndrii Nakryiko return 0; 3121a3b80e10SAndrii Nakryiko } 3122a3b80e10SAndrii Nakryiko 3123a3b80e10SAndrii Nakryiko int bpf_link_settle(struct bpf_link_primer *primer) 3124a3b80e10SAndrii Nakryiko { 3125a3b80e10SAndrii Nakryiko /* make bpf_link fetchable by ID */ 3126a3b80e10SAndrii Nakryiko spin_lock_bh(&link_idr_lock); 3127a3b80e10SAndrii Nakryiko primer->link->id = primer->id; 3128a3b80e10SAndrii Nakryiko spin_unlock_bh(&link_idr_lock); 3129a3b80e10SAndrii Nakryiko /* make bpf_link fetchable by FD */ 3130a3b80e10SAndrii Nakryiko fd_install(primer->fd, primer->file); 3131a3b80e10SAndrii Nakryiko /* pass through installed FD */ 3132a3b80e10SAndrii Nakryiko return primer->fd; 3133a3b80e10SAndrii Nakryiko } 3134a3b80e10SAndrii Nakryiko 3135a3b80e10SAndrii Nakryiko int bpf_link_new_fd(struct bpf_link *link) 3136a3b80e10SAndrii Nakryiko { 3137a3b80e10SAndrii Nakryiko return anon_inode_getfd("bpf-link", &bpf_link_fops, link, O_CLOEXEC); 3138babf3164SAndrii Nakryiko } 3139babf3164SAndrii Nakryiko 314070ed506cSAndrii Nakryiko struct bpf_link *bpf_link_get_from_fd(u32 ufd) 314170ed506cSAndrii Nakryiko { 314270ed506cSAndrii Nakryiko struct fd f = fdget(ufd); 314370ed506cSAndrii Nakryiko struct bpf_link *link; 314470ed506cSAndrii Nakryiko 314570ed506cSAndrii Nakryiko if (!f.file) 314670ed506cSAndrii Nakryiko return ERR_PTR(-EBADF); 314770ed506cSAndrii Nakryiko if (f.file->f_op != &bpf_link_fops) { 314870ed506cSAndrii Nakryiko fdput(f); 314970ed506cSAndrii Nakryiko return ERR_PTR(-EINVAL); 315070ed506cSAndrii Nakryiko } 315170ed506cSAndrii Nakryiko 315270ed506cSAndrii Nakryiko link = f.file->private_data; 315370ed506cSAndrii Nakryiko bpf_link_inc(link); 315470ed506cSAndrii Nakryiko fdput(f); 315570ed506cSAndrii Nakryiko 315670ed506cSAndrii Nakryiko return link; 315770ed506cSAndrii Nakryiko } 3158cb80ddc6SAlexei Starovoitov EXPORT_SYMBOL(bpf_link_get_from_fd); 315970ed506cSAndrii Nakryiko 316070ed506cSAndrii Nakryiko static void bpf_tracing_link_release(struct bpf_link *link) 316170ed506cSAndrii Nakryiko { 31623aac1eadSToke Høiland-Jørgensen struct bpf_tracing_link *tr_link = 3163f7e0beafSKui-Feng Lee container_of(link, struct bpf_tracing_link, link.link); 31643aac1eadSToke Høiland-Jørgensen 3165f7e0beafSKui-Feng Lee WARN_ON_ONCE(bpf_trampoline_unlink_prog(&tr_link->link, 31663aac1eadSToke Høiland-Jørgensen tr_link->trampoline)); 31673aac1eadSToke Høiland-Jørgensen 31683aac1eadSToke Høiland-Jørgensen bpf_trampoline_put(tr_link->trampoline); 31693aac1eadSToke Høiland-Jørgensen 31703aac1eadSToke Høiland-Jørgensen /* tgt_prog is NULL if target is a kernel function */ 31713aac1eadSToke Høiland-Jørgensen if (tr_link->tgt_prog) 31723aac1eadSToke Høiland-Jørgensen bpf_prog_put(tr_link->tgt_prog); 3173babf3164SAndrii Nakryiko } 3174babf3164SAndrii Nakryiko 3175babf3164SAndrii Nakryiko static void bpf_tracing_link_dealloc(struct bpf_link *link) 3176babf3164SAndrii Nakryiko { 317770ed506cSAndrii Nakryiko struct bpf_tracing_link *tr_link = 3178f7e0beafSKui-Feng Lee container_of(link, struct bpf_tracing_link, link.link); 317970ed506cSAndrii Nakryiko 318070ed506cSAndrii Nakryiko kfree(tr_link); 318170ed506cSAndrii Nakryiko } 318270ed506cSAndrii Nakryiko 3183f2e10bffSAndrii Nakryiko static void bpf_tracing_link_show_fdinfo(const struct bpf_link *link, 3184f2e10bffSAndrii Nakryiko struct seq_file *seq) 3185f2e10bffSAndrii Nakryiko { 3186f2e10bffSAndrii Nakryiko struct bpf_tracing_link *tr_link = 3187f7e0beafSKui-Feng Lee container_of(link, struct bpf_tracing_link, link.link); 3188e859e429SYafang Shao u32 target_btf_id, target_obj_id; 3189f2e10bffSAndrii Nakryiko 3190e859e429SYafang Shao bpf_trampoline_unpack_key(tr_link->trampoline->key, 3191e859e429SYafang Shao &target_obj_id, &target_btf_id); 3192f2e10bffSAndrii Nakryiko seq_printf(seq, 3193e859e429SYafang Shao "attach_type:\t%d\n" 3194e859e429SYafang Shao "target_obj_id:\t%u\n" 3195e859e429SYafang Shao "target_btf_id:\t%u\n", 3196e859e429SYafang Shao tr_link->attach_type, 3197e859e429SYafang Shao target_obj_id, 3198e859e429SYafang Shao target_btf_id); 3199f2e10bffSAndrii Nakryiko } 3200f2e10bffSAndrii Nakryiko 3201f2e10bffSAndrii Nakryiko static int bpf_tracing_link_fill_link_info(const struct bpf_link *link, 3202f2e10bffSAndrii Nakryiko struct bpf_link_info *info) 3203f2e10bffSAndrii Nakryiko { 3204f2e10bffSAndrii Nakryiko struct bpf_tracing_link *tr_link = 3205f7e0beafSKui-Feng Lee container_of(link, struct bpf_tracing_link, link.link); 3206f2e10bffSAndrii Nakryiko 3207f2e10bffSAndrii Nakryiko info->tracing.attach_type = tr_link->attach_type; 3208441e8c66SToke Høiland-Jørgensen bpf_trampoline_unpack_key(tr_link->trampoline->key, 3209441e8c66SToke Høiland-Jørgensen &info->tracing.target_obj_id, 3210441e8c66SToke Høiland-Jørgensen &info->tracing.target_btf_id); 3211f2e10bffSAndrii Nakryiko 3212f2e10bffSAndrii Nakryiko return 0; 3213f2e10bffSAndrii Nakryiko } 3214f2e10bffSAndrii Nakryiko 321570ed506cSAndrii Nakryiko static const struct bpf_link_ops bpf_tracing_link_lops = { 321670ed506cSAndrii Nakryiko .release = bpf_tracing_link_release, 3217babf3164SAndrii Nakryiko .dealloc = bpf_tracing_link_dealloc, 3218f2e10bffSAndrii Nakryiko .show_fdinfo = bpf_tracing_link_show_fdinfo, 3219f2e10bffSAndrii Nakryiko .fill_link_info = bpf_tracing_link_fill_link_info, 322070ed506cSAndrii Nakryiko }; 322170ed506cSAndrii Nakryiko 32224a1e7c0cSToke Høiland-Jørgensen static int bpf_tracing_prog_attach(struct bpf_prog *prog, 32234a1e7c0cSToke Høiland-Jørgensen int tgt_prog_fd, 32242fcc8241SKui-Feng Lee u32 btf_id, 32252fcc8241SKui-Feng Lee u64 bpf_cookie) 3226fec56f58SAlexei Starovoitov { 3227a3b80e10SAndrii Nakryiko struct bpf_link_primer link_primer; 32283aac1eadSToke Høiland-Jørgensen struct bpf_prog *tgt_prog = NULL; 32294a1e7c0cSToke Høiland-Jørgensen struct bpf_trampoline *tr = NULL; 323070ed506cSAndrii Nakryiko struct bpf_tracing_link *link; 32314a1e7c0cSToke Høiland-Jørgensen u64 key = 0; 3232a3b80e10SAndrii Nakryiko int err; 3233fec56f58SAlexei Starovoitov 32349e4e01dfSKP Singh switch (prog->type) { 32359e4e01dfSKP Singh case BPF_PROG_TYPE_TRACING: 3236fec56f58SAlexei Starovoitov if (prog->expected_attach_type != BPF_TRACE_FENTRY && 3237be8704ffSAlexei Starovoitov prog->expected_attach_type != BPF_TRACE_FEXIT && 32389e4e01dfSKP Singh prog->expected_attach_type != BPF_MODIFY_RETURN) { 32399e4e01dfSKP Singh err = -EINVAL; 32409e4e01dfSKP Singh goto out_put_prog; 32419e4e01dfSKP Singh } 32429e4e01dfSKP Singh break; 32439e4e01dfSKP Singh case BPF_PROG_TYPE_EXT: 32449e4e01dfSKP Singh if (prog->expected_attach_type != 0) { 32459e4e01dfSKP Singh err = -EINVAL; 32469e4e01dfSKP Singh goto out_put_prog; 32479e4e01dfSKP Singh } 32489e4e01dfSKP Singh break; 32499e4e01dfSKP Singh case BPF_PROG_TYPE_LSM: 32509e4e01dfSKP Singh if (prog->expected_attach_type != BPF_LSM_MAC) { 32519e4e01dfSKP Singh err = -EINVAL; 32529e4e01dfSKP Singh goto out_put_prog; 32539e4e01dfSKP Singh } 32549e4e01dfSKP Singh break; 32559e4e01dfSKP Singh default: 3256fec56f58SAlexei Starovoitov err = -EINVAL; 3257fec56f58SAlexei Starovoitov goto out_put_prog; 3258fec56f58SAlexei Starovoitov } 3259fec56f58SAlexei Starovoitov 32604a1e7c0cSToke Høiland-Jørgensen if (!!tgt_prog_fd != !!btf_id) { 32614a1e7c0cSToke Høiland-Jørgensen err = -EINVAL; 32624a1e7c0cSToke Høiland-Jørgensen goto out_put_prog; 32634a1e7c0cSToke Høiland-Jørgensen } 32644a1e7c0cSToke Høiland-Jørgensen 32654a1e7c0cSToke Høiland-Jørgensen if (tgt_prog_fd) { 326619bfcdf9SDmitrii Dolgov /* 326719bfcdf9SDmitrii Dolgov * For now we only allow new targets for BPF_PROG_TYPE_EXT. If this 326819bfcdf9SDmitrii Dolgov * part would be changed to implement the same for 326919bfcdf9SDmitrii Dolgov * BPF_PROG_TYPE_TRACING, do not forget to update the way how 327019bfcdf9SDmitrii Dolgov * attach_tracing_prog flag is set. 327119bfcdf9SDmitrii Dolgov */ 32724a1e7c0cSToke Høiland-Jørgensen if (prog->type != BPF_PROG_TYPE_EXT) { 32734a1e7c0cSToke Høiland-Jørgensen err = -EINVAL; 32744a1e7c0cSToke Høiland-Jørgensen goto out_put_prog; 32754a1e7c0cSToke Høiland-Jørgensen } 32764a1e7c0cSToke Høiland-Jørgensen 32774a1e7c0cSToke Høiland-Jørgensen tgt_prog = bpf_prog_get(tgt_prog_fd); 32784a1e7c0cSToke Høiland-Jørgensen if (IS_ERR(tgt_prog)) { 32794a1e7c0cSToke Høiland-Jørgensen err = PTR_ERR(tgt_prog); 32804a1e7c0cSToke Høiland-Jørgensen tgt_prog = NULL; 32814a1e7c0cSToke Høiland-Jørgensen goto out_put_prog; 32824a1e7c0cSToke Høiland-Jørgensen } 32834a1e7c0cSToke Høiland-Jørgensen 328422dc4a0fSAndrii Nakryiko key = bpf_trampoline_compute_key(tgt_prog, NULL, btf_id); 32854a1e7c0cSToke Høiland-Jørgensen } 32864a1e7c0cSToke Høiland-Jørgensen 328770ed506cSAndrii Nakryiko link = kzalloc(sizeof(*link), GFP_USER); 328870ed506cSAndrii Nakryiko if (!link) { 328970ed506cSAndrii Nakryiko err = -ENOMEM; 3290fec56f58SAlexei Starovoitov goto out_put_prog; 3291fec56f58SAlexei Starovoitov } 3292f7e0beafSKui-Feng Lee bpf_link_init(&link->link.link, BPF_LINK_TYPE_TRACING, 3293f2e10bffSAndrii Nakryiko &bpf_tracing_link_lops, prog); 3294f2e10bffSAndrii Nakryiko link->attach_type = prog->expected_attach_type; 32952fcc8241SKui-Feng Lee link->link.cookie = bpf_cookie; 3296fec56f58SAlexei Starovoitov 32973aac1eadSToke Høiland-Jørgensen mutex_lock(&prog->aux->dst_mutex); 3298babf3164SAndrii Nakryiko 32994a1e7c0cSToke Høiland-Jørgensen /* There are a few possible cases here: 33004a1e7c0cSToke Høiland-Jørgensen * 33014a1e7c0cSToke Høiland-Jørgensen * - if prog->aux->dst_trampoline is set, the program was just loaded 33024a1e7c0cSToke Høiland-Jørgensen * and not yet attached to anything, so we can use the values stored 33034a1e7c0cSToke Høiland-Jørgensen * in prog->aux 33044a1e7c0cSToke Høiland-Jørgensen * 33054a1e7c0cSToke Høiland-Jørgensen * - if prog->aux->dst_trampoline is NULL, the program has already been 33064a1e7c0cSToke Høiland-Jørgensen * attached to a target and its initial target was cleared (below) 33074a1e7c0cSToke Høiland-Jørgensen * 33084a1e7c0cSToke Høiland-Jørgensen * - if tgt_prog != NULL, the caller specified tgt_prog_fd + 33094a1e7c0cSToke Høiland-Jørgensen * target_btf_id using the link_create API. 33104a1e7c0cSToke Høiland-Jørgensen * 33114a1e7c0cSToke Høiland-Jørgensen * - if tgt_prog == NULL when this function was called using the old 33124a1e7c0cSToke Høiland-Jørgensen * raw_tracepoint_open API, and we need a target from prog->aux 33134a1e7c0cSToke Høiland-Jørgensen * 3314f3a95075SJiri Olsa * - if prog->aux->dst_trampoline and tgt_prog is NULL, the program 3315f3a95075SJiri Olsa * was detached and is going for re-attachment. 3316715d82baSJiri Olsa * 3317715d82baSJiri Olsa * - if prog->aux->dst_trampoline is NULL and tgt_prog and prog->aux->attach_btf 3318715d82baSJiri Olsa * are NULL, then program was already attached and user did not provide 3319715d82baSJiri Olsa * tgt_prog_fd so we have no way to find out or create trampoline 33204a1e7c0cSToke Høiland-Jørgensen */ 33214a1e7c0cSToke Høiland-Jørgensen if (!prog->aux->dst_trampoline && !tgt_prog) { 3322f3a95075SJiri Olsa /* 3323f3a95075SJiri Olsa * Allow re-attach for TRACING and LSM programs. If it's 3324f3a95075SJiri Olsa * currently linked, bpf_trampoline_link_prog will fail. 3325f3a95075SJiri Olsa * EXT programs need to specify tgt_prog_fd, so they 3326f3a95075SJiri Olsa * re-attach in separate code path. 3327f3a95075SJiri Olsa */ 3328f3a95075SJiri Olsa if (prog->type != BPF_PROG_TYPE_TRACING && 3329f3a95075SJiri Olsa prog->type != BPF_PROG_TYPE_LSM) { 3330f3a95075SJiri Olsa err = -EINVAL; 33313aac1eadSToke Høiland-Jørgensen goto out_unlock; 33323aac1eadSToke Høiland-Jørgensen } 3333715d82baSJiri Olsa /* We can allow re-attach only if we have valid attach_btf. */ 3334715d82baSJiri Olsa if (!prog->aux->attach_btf) { 3335715d82baSJiri Olsa err = -EINVAL; 3336715d82baSJiri Olsa goto out_unlock; 3337715d82baSJiri Olsa } 3338f3a95075SJiri Olsa btf_id = prog->aux->attach_btf_id; 3339f3a95075SJiri Olsa key = bpf_trampoline_compute_key(NULL, prog->aux->attach_btf, btf_id); 3340f3a95075SJiri Olsa } 33414a1e7c0cSToke Høiland-Jørgensen 33424a1e7c0cSToke Høiland-Jørgensen if (!prog->aux->dst_trampoline || 33434a1e7c0cSToke Høiland-Jørgensen (key && key != prog->aux->dst_trampoline->key)) { 33444a1e7c0cSToke Høiland-Jørgensen /* If there is no saved target, or the specified target is 33454a1e7c0cSToke Høiland-Jørgensen * different from the destination specified at load time, we 33464a1e7c0cSToke Høiland-Jørgensen * need a new trampoline and a check for compatibility 33474a1e7c0cSToke Høiland-Jørgensen */ 33484a1e7c0cSToke Høiland-Jørgensen struct bpf_attach_target_info tgt_info = {}; 33494a1e7c0cSToke Høiland-Jørgensen 33504a1e7c0cSToke Høiland-Jørgensen err = bpf_check_attach_target(NULL, prog, tgt_prog, btf_id, 33514a1e7c0cSToke Høiland-Jørgensen &tgt_info); 33524a1e7c0cSToke Høiland-Jørgensen if (err) 33534a1e7c0cSToke Høiland-Jørgensen goto out_unlock; 33544a1e7c0cSToke Høiland-Jørgensen 335531bf1dbcSViktor Malik if (tgt_info.tgt_mod) { 335631bf1dbcSViktor Malik module_put(prog->aux->mod); 335731bf1dbcSViktor Malik prog->aux->mod = tgt_info.tgt_mod; 335831bf1dbcSViktor Malik } 335931bf1dbcSViktor Malik 33604a1e7c0cSToke Høiland-Jørgensen tr = bpf_trampoline_get(key, &tgt_info); 33614a1e7c0cSToke Høiland-Jørgensen if (!tr) { 33624a1e7c0cSToke Høiland-Jørgensen err = -ENOMEM; 33634a1e7c0cSToke Høiland-Jørgensen goto out_unlock; 33644a1e7c0cSToke Høiland-Jørgensen } 33654a1e7c0cSToke Høiland-Jørgensen } else { 33664a1e7c0cSToke Høiland-Jørgensen /* The caller didn't specify a target, or the target was the 33674a1e7c0cSToke Høiland-Jørgensen * same as the destination supplied during program load. This 33684a1e7c0cSToke Høiland-Jørgensen * means we can reuse the trampoline and reference from program 33694a1e7c0cSToke Høiland-Jørgensen * load time, and there is no need to allocate a new one. This 33704a1e7c0cSToke Høiland-Jørgensen * can only happen once for any program, as the saved values in 33714a1e7c0cSToke Høiland-Jørgensen * prog->aux are cleared below. 33724a1e7c0cSToke Høiland-Jørgensen */ 33733aac1eadSToke Høiland-Jørgensen tr = prog->aux->dst_trampoline; 33743aac1eadSToke Høiland-Jørgensen tgt_prog = prog->aux->dst_prog; 33754a1e7c0cSToke Høiland-Jørgensen } 33763aac1eadSToke Høiland-Jørgensen 3377f7e0beafSKui-Feng Lee err = bpf_link_prime(&link->link.link, &link_primer); 33783aac1eadSToke Høiland-Jørgensen if (err) 33793aac1eadSToke Høiland-Jørgensen goto out_unlock; 33803aac1eadSToke Høiland-Jørgensen 3381f7e0beafSKui-Feng Lee err = bpf_trampoline_link_prog(&link->link, tr); 3382babf3164SAndrii Nakryiko if (err) { 3383a3b80e10SAndrii Nakryiko bpf_link_cleanup(&link_primer); 33843aac1eadSToke Høiland-Jørgensen link = NULL; 33853aac1eadSToke Høiland-Jørgensen goto out_unlock; 3386babf3164SAndrii Nakryiko } 3387babf3164SAndrii Nakryiko 33883aac1eadSToke Høiland-Jørgensen link->tgt_prog = tgt_prog; 33893aac1eadSToke Høiland-Jørgensen link->trampoline = tr; 33903aac1eadSToke Høiland-Jørgensen 33914a1e7c0cSToke Høiland-Jørgensen /* Always clear the trampoline and target prog from prog->aux to make 33924a1e7c0cSToke Høiland-Jørgensen * sure the original attach destination is not kept alive after a 33934a1e7c0cSToke Høiland-Jørgensen * program is (re-)attached to another target. 33944a1e7c0cSToke Høiland-Jørgensen */ 33954a1e7c0cSToke Høiland-Jørgensen if (prog->aux->dst_prog && 33964a1e7c0cSToke Høiland-Jørgensen (tgt_prog_fd || tr != prog->aux->dst_trampoline)) 33974a1e7c0cSToke Høiland-Jørgensen /* got extra prog ref from syscall, or attaching to different prog */ 33984a1e7c0cSToke Høiland-Jørgensen bpf_prog_put(prog->aux->dst_prog); 33994a1e7c0cSToke Høiland-Jørgensen if (prog->aux->dst_trampoline && tr != prog->aux->dst_trampoline) 34004a1e7c0cSToke Høiland-Jørgensen /* we allocated a new trampoline, so free the old one */ 34014a1e7c0cSToke Høiland-Jørgensen bpf_trampoline_put(prog->aux->dst_trampoline); 34024a1e7c0cSToke Høiland-Jørgensen 34033aac1eadSToke Høiland-Jørgensen prog->aux->dst_prog = NULL; 34043aac1eadSToke Høiland-Jørgensen prog->aux->dst_trampoline = NULL; 34053aac1eadSToke Høiland-Jørgensen mutex_unlock(&prog->aux->dst_mutex); 34063aac1eadSToke Høiland-Jørgensen 3407a3b80e10SAndrii Nakryiko return bpf_link_settle(&link_primer); 34083aac1eadSToke Høiland-Jørgensen out_unlock: 34094a1e7c0cSToke Høiland-Jørgensen if (tr && tr != prog->aux->dst_trampoline) 34104a1e7c0cSToke Høiland-Jørgensen bpf_trampoline_put(tr); 34113aac1eadSToke Høiland-Jørgensen mutex_unlock(&prog->aux->dst_mutex); 34123aac1eadSToke Høiland-Jørgensen kfree(link); 3413fec56f58SAlexei Starovoitov out_put_prog: 34144a1e7c0cSToke Høiland-Jørgensen if (tgt_prog_fd && tgt_prog) 34154a1e7c0cSToke Høiland-Jørgensen bpf_prog_put(tgt_prog); 3416fec56f58SAlexei Starovoitov return err; 3417fec56f58SAlexei Starovoitov } 3418fec56f58SAlexei Starovoitov 341970ed506cSAndrii Nakryiko struct bpf_raw_tp_link { 342070ed506cSAndrii Nakryiko struct bpf_link link; 3421c4f6699dSAlexei Starovoitov struct bpf_raw_event_map *btp; 3422c4f6699dSAlexei Starovoitov }; 3423c4f6699dSAlexei Starovoitov 342470ed506cSAndrii Nakryiko static void bpf_raw_tp_link_release(struct bpf_link *link) 3425c4f6699dSAlexei Starovoitov { 342670ed506cSAndrii Nakryiko struct bpf_raw_tp_link *raw_tp = 342770ed506cSAndrii Nakryiko container_of(link, struct bpf_raw_tp_link, link); 3428c4f6699dSAlexei Starovoitov 342970ed506cSAndrii Nakryiko bpf_probe_unregister(raw_tp->btp, raw_tp->link.prog); 3430a38d1107SMatt Mullins bpf_put_raw_tracepoint(raw_tp->btp); 3431babf3164SAndrii Nakryiko } 3432babf3164SAndrii Nakryiko 3433babf3164SAndrii Nakryiko static void bpf_raw_tp_link_dealloc(struct bpf_link *link) 3434babf3164SAndrii Nakryiko { 3435babf3164SAndrii Nakryiko struct bpf_raw_tp_link *raw_tp = 3436babf3164SAndrii Nakryiko container_of(link, struct bpf_raw_tp_link, link); 3437babf3164SAndrii Nakryiko 3438c4f6699dSAlexei Starovoitov kfree(raw_tp); 3439c4f6699dSAlexei Starovoitov } 3440c4f6699dSAlexei Starovoitov 3441f2e10bffSAndrii Nakryiko static void bpf_raw_tp_link_show_fdinfo(const struct bpf_link *link, 3442f2e10bffSAndrii Nakryiko struct seq_file *seq) 3443f2e10bffSAndrii Nakryiko { 3444f2e10bffSAndrii Nakryiko struct bpf_raw_tp_link *raw_tp_link = 3445f2e10bffSAndrii Nakryiko container_of(link, struct bpf_raw_tp_link, link); 3446f2e10bffSAndrii Nakryiko 3447f2e10bffSAndrii Nakryiko seq_printf(seq, 3448f2e10bffSAndrii Nakryiko "tp_name:\t%s\n", 3449f2e10bffSAndrii Nakryiko raw_tp_link->btp->tp->name); 3450f2e10bffSAndrii Nakryiko } 3451f2e10bffSAndrii Nakryiko 345257d48537SYafang Shao static int bpf_copy_to_user(char __user *ubuf, const char *buf, u32 ulen, 345357d48537SYafang Shao u32 len) 345457d48537SYafang Shao { 345557d48537SYafang Shao if (ulen >= len + 1) { 345657d48537SYafang Shao if (copy_to_user(ubuf, buf, len + 1)) 345757d48537SYafang Shao return -EFAULT; 345857d48537SYafang Shao } else { 345957d48537SYafang Shao char zero = '\0'; 346057d48537SYafang Shao 346157d48537SYafang Shao if (copy_to_user(ubuf, buf, ulen - 1)) 346257d48537SYafang Shao return -EFAULT; 346357d48537SYafang Shao if (put_user(zero, ubuf + ulen - 1)) 346457d48537SYafang Shao return -EFAULT; 346557d48537SYafang Shao return -ENOSPC; 346657d48537SYafang Shao } 346757d48537SYafang Shao 346857d48537SYafang Shao return 0; 346957d48537SYafang Shao } 347057d48537SYafang Shao 3471f2e10bffSAndrii Nakryiko static int bpf_raw_tp_link_fill_link_info(const struct bpf_link *link, 3472f2e10bffSAndrii Nakryiko struct bpf_link_info *info) 3473f2e10bffSAndrii Nakryiko { 3474f2e10bffSAndrii Nakryiko struct bpf_raw_tp_link *raw_tp_link = 3475f2e10bffSAndrii Nakryiko container_of(link, struct bpf_raw_tp_link, link); 3476f2e10bffSAndrii Nakryiko char __user *ubuf = u64_to_user_ptr(info->raw_tracepoint.tp_name); 3477f2e10bffSAndrii Nakryiko const char *tp_name = raw_tp_link->btp->tp->name; 3478f2e10bffSAndrii Nakryiko u32 ulen = info->raw_tracepoint.tp_name_len; 3479f2e10bffSAndrii Nakryiko size_t tp_len = strlen(tp_name); 3480f2e10bffSAndrii Nakryiko 3481b474959dSYonghong Song if (!ulen ^ !ubuf) 3482f2e10bffSAndrii Nakryiko return -EINVAL; 3483f2e10bffSAndrii Nakryiko 3484f2e10bffSAndrii Nakryiko info->raw_tracepoint.tp_name_len = tp_len + 1; 3485f2e10bffSAndrii Nakryiko 3486f2e10bffSAndrii Nakryiko if (!ubuf) 3487f2e10bffSAndrii Nakryiko return 0; 3488f2e10bffSAndrii Nakryiko 348957d48537SYafang Shao return bpf_copy_to_user(ubuf, tp_name, ulen, tp_len); 3490f2e10bffSAndrii Nakryiko } 3491f2e10bffSAndrii Nakryiko 3492a3b80e10SAndrii Nakryiko static const struct bpf_link_ops bpf_raw_tp_link_lops = { 349370ed506cSAndrii Nakryiko .release = bpf_raw_tp_link_release, 3494babf3164SAndrii Nakryiko .dealloc = bpf_raw_tp_link_dealloc, 3495f2e10bffSAndrii Nakryiko .show_fdinfo = bpf_raw_tp_link_show_fdinfo, 3496f2e10bffSAndrii Nakryiko .fill_link_info = bpf_raw_tp_link_fill_link_info, 3497c4f6699dSAlexei Starovoitov }; 3498c4f6699dSAlexei Starovoitov 3499b89fbfbbSAndrii Nakryiko #ifdef CONFIG_PERF_EVENTS 3500b89fbfbbSAndrii Nakryiko struct bpf_perf_link { 3501b89fbfbbSAndrii Nakryiko struct bpf_link link; 3502b89fbfbbSAndrii Nakryiko struct file *perf_file; 3503b89fbfbbSAndrii Nakryiko }; 3504b89fbfbbSAndrii Nakryiko 3505b89fbfbbSAndrii Nakryiko static void bpf_perf_link_release(struct bpf_link *link) 3506b89fbfbbSAndrii Nakryiko { 3507b89fbfbbSAndrii Nakryiko struct bpf_perf_link *perf_link = container_of(link, struct bpf_perf_link, link); 3508b89fbfbbSAndrii Nakryiko struct perf_event *event = perf_link->perf_file->private_data; 3509b89fbfbbSAndrii Nakryiko 3510b89fbfbbSAndrii Nakryiko perf_event_free_bpf_prog(event); 3511b89fbfbbSAndrii Nakryiko fput(perf_link->perf_file); 3512b89fbfbbSAndrii Nakryiko } 3513b89fbfbbSAndrii Nakryiko 3514b89fbfbbSAndrii Nakryiko static void bpf_perf_link_dealloc(struct bpf_link *link) 3515b89fbfbbSAndrii Nakryiko { 3516b89fbfbbSAndrii Nakryiko struct bpf_perf_link *perf_link = container_of(link, struct bpf_perf_link, link); 3517b89fbfbbSAndrii Nakryiko 3518b89fbfbbSAndrii Nakryiko kfree(perf_link); 3519b89fbfbbSAndrii Nakryiko } 3520b89fbfbbSAndrii Nakryiko 35211b715e1bSYafang Shao static int bpf_perf_link_fill_common(const struct perf_event *event, 35221b715e1bSYafang Shao char __user *uname, u32 ulen, 35231b715e1bSYafang Shao u64 *probe_offset, u64 *probe_addr, 35243acf8aceSJiri Olsa u32 *fd_type, unsigned long *missed) 35251b715e1bSYafang Shao { 35261b715e1bSYafang Shao const char *buf; 35271b715e1bSYafang Shao u32 prog_id; 35281b715e1bSYafang Shao size_t len; 35291b715e1bSYafang Shao int err; 35301b715e1bSYafang Shao 35311b715e1bSYafang Shao if (!ulen ^ !uname) 35321b715e1bSYafang Shao return -EINVAL; 35331b715e1bSYafang Shao 35341b715e1bSYafang Shao err = bpf_get_perf_event_info(event, &prog_id, fd_type, &buf, 35353acf8aceSJiri Olsa probe_offset, probe_addr, missed); 35361b715e1bSYafang Shao if (err) 35371b715e1bSYafang Shao return err; 35380aa35162SYafang Shao if (!uname) 35390aa35162SYafang Shao return 0; 35401b715e1bSYafang Shao if (buf) { 35411b715e1bSYafang Shao len = strlen(buf); 35421b715e1bSYafang Shao err = bpf_copy_to_user(uname, buf, ulen, len); 35431b715e1bSYafang Shao if (err) 35441b715e1bSYafang Shao return err; 35451b715e1bSYafang Shao } else { 35461b715e1bSYafang Shao char zero = '\0'; 35471b715e1bSYafang Shao 35481b715e1bSYafang Shao if (put_user(zero, uname)) 35491b715e1bSYafang Shao return -EFAULT; 35501b715e1bSYafang Shao } 35511b715e1bSYafang Shao return 0; 35521b715e1bSYafang Shao } 35531b715e1bSYafang Shao 35541b715e1bSYafang Shao #ifdef CONFIG_KPROBE_EVENTS 35551b715e1bSYafang Shao static int bpf_perf_link_fill_kprobe(const struct perf_event *event, 35561b715e1bSYafang Shao struct bpf_link_info *info) 35571b715e1bSYafang Shao { 35583acf8aceSJiri Olsa unsigned long missed; 35591b715e1bSYafang Shao char __user *uname; 35601b715e1bSYafang Shao u64 addr, offset; 35611b715e1bSYafang Shao u32 ulen, type; 35621b715e1bSYafang Shao int err; 35631b715e1bSYafang Shao 35641b715e1bSYafang Shao uname = u64_to_user_ptr(info->perf_event.kprobe.func_name); 35651b715e1bSYafang Shao ulen = info->perf_event.kprobe.name_len; 35661b715e1bSYafang Shao err = bpf_perf_link_fill_common(event, uname, ulen, &offset, &addr, 35673acf8aceSJiri Olsa &type, &missed); 35681b715e1bSYafang Shao if (err) 35691b715e1bSYafang Shao return err; 35701b715e1bSYafang Shao if (type == BPF_FD_TYPE_KRETPROBE) 35711b715e1bSYafang Shao info->perf_event.type = BPF_PERF_EVENT_KRETPROBE; 35721b715e1bSYafang Shao else 35731b715e1bSYafang Shao info->perf_event.type = BPF_PERF_EVENT_KPROBE; 35741b715e1bSYafang Shao 35751b715e1bSYafang Shao info->perf_event.kprobe.offset = offset; 35763acf8aceSJiri Olsa info->perf_event.kprobe.missed = missed; 35771b715e1bSYafang Shao if (!kallsyms_show_value(current_cred())) 35781b715e1bSYafang Shao addr = 0; 35791b715e1bSYafang Shao info->perf_event.kprobe.addr = addr; 3580d5c16492SJiri Olsa info->perf_event.kprobe.cookie = event->bpf_cookie; 35811b715e1bSYafang Shao return 0; 35821b715e1bSYafang Shao } 35831b715e1bSYafang Shao #endif 35841b715e1bSYafang Shao 35851b715e1bSYafang Shao #ifdef CONFIG_UPROBE_EVENTS 35861b715e1bSYafang Shao static int bpf_perf_link_fill_uprobe(const struct perf_event *event, 35871b715e1bSYafang Shao struct bpf_link_info *info) 35881b715e1bSYafang Shao { 35891b715e1bSYafang Shao char __user *uname; 35901b715e1bSYafang Shao u64 addr, offset; 35911b715e1bSYafang Shao u32 ulen, type; 35921b715e1bSYafang Shao int err; 35931b715e1bSYafang Shao 35941b715e1bSYafang Shao uname = u64_to_user_ptr(info->perf_event.uprobe.file_name); 35951b715e1bSYafang Shao ulen = info->perf_event.uprobe.name_len; 35961b715e1bSYafang Shao err = bpf_perf_link_fill_common(event, uname, ulen, &offset, &addr, 35973acf8aceSJiri Olsa &type, NULL); 35981b715e1bSYafang Shao if (err) 35991b715e1bSYafang Shao return err; 36001b715e1bSYafang Shao 36011b715e1bSYafang Shao if (type == BPF_FD_TYPE_URETPROBE) 36021b715e1bSYafang Shao info->perf_event.type = BPF_PERF_EVENT_URETPROBE; 36031b715e1bSYafang Shao else 36041b715e1bSYafang Shao info->perf_event.type = BPF_PERF_EVENT_UPROBE; 36051b715e1bSYafang Shao info->perf_event.uprobe.offset = offset; 3606d5c16492SJiri Olsa info->perf_event.uprobe.cookie = event->bpf_cookie; 36071b715e1bSYafang Shao return 0; 36081b715e1bSYafang Shao } 36091b715e1bSYafang Shao #endif 36101b715e1bSYafang Shao 36111b715e1bSYafang Shao static int bpf_perf_link_fill_probe(const struct perf_event *event, 36121b715e1bSYafang Shao struct bpf_link_info *info) 36131b715e1bSYafang Shao { 36141b715e1bSYafang Shao #ifdef CONFIG_KPROBE_EVENTS 36151b715e1bSYafang Shao if (event->tp_event->flags & TRACE_EVENT_FL_KPROBE) 36161b715e1bSYafang Shao return bpf_perf_link_fill_kprobe(event, info); 36171b715e1bSYafang Shao #endif 36181b715e1bSYafang Shao #ifdef CONFIG_UPROBE_EVENTS 36191b715e1bSYafang Shao if (event->tp_event->flags & TRACE_EVENT_FL_UPROBE) 36201b715e1bSYafang Shao return bpf_perf_link_fill_uprobe(event, info); 36211b715e1bSYafang Shao #endif 36221b715e1bSYafang Shao return -EOPNOTSUPP; 36231b715e1bSYafang Shao } 36241b715e1bSYafang Shao 36251b715e1bSYafang Shao static int bpf_perf_link_fill_tracepoint(const struct perf_event *event, 36261b715e1bSYafang Shao struct bpf_link_info *info) 36271b715e1bSYafang Shao { 36281b715e1bSYafang Shao char __user *uname; 36291b715e1bSYafang Shao u32 ulen; 36301b715e1bSYafang Shao 36311b715e1bSYafang Shao uname = u64_to_user_ptr(info->perf_event.tracepoint.tp_name); 36321b715e1bSYafang Shao ulen = info->perf_event.tracepoint.name_len; 36331b715e1bSYafang Shao info->perf_event.type = BPF_PERF_EVENT_TRACEPOINT; 3634d5c16492SJiri Olsa info->perf_event.tracepoint.cookie = event->bpf_cookie; 36353acf8aceSJiri Olsa return bpf_perf_link_fill_common(event, uname, ulen, NULL, NULL, NULL, NULL); 36361b715e1bSYafang Shao } 36371b715e1bSYafang Shao 36381b715e1bSYafang Shao static int bpf_perf_link_fill_perf_event(const struct perf_event *event, 36391b715e1bSYafang Shao struct bpf_link_info *info) 36401b715e1bSYafang Shao { 36411b715e1bSYafang Shao info->perf_event.event.type = event->attr.type; 36421b715e1bSYafang Shao info->perf_event.event.config = event->attr.config; 3643d5c16492SJiri Olsa info->perf_event.event.cookie = event->bpf_cookie; 36441b715e1bSYafang Shao info->perf_event.type = BPF_PERF_EVENT_EVENT; 36451b715e1bSYafang Shao return 0; 36461b715e1bSYafang Shao } 36471b715e1bSYafang Shao 36481b715e1bSYafang Shao static int bpf_perf_link_fill_link_info(const struct bpf_link *link, 36491b715e1bSYafang Shao struct bpf_link_info *info) 36501b715e1bSYafang Shao { 36511b715e1bSYafang Shao struct bpf_perf_link *perf_link; 36521b715e1bSYafang Shao const struct perf_event *event; 36531b715e1bSYafang Shao 36541b715e1bSYafang Shao perf_link = container_of(link, struct bpf_perf_link, link); 36551b715e1bSYafang Shao event = perf_get_event(perf_link->perf_file); 36561b715e1bSYafang Shao if (IS_ERR(event)) 36571b715e1bSYafang Shao return PTR_ERR(event); 36581b715e1bSYafang Shao 36591b715e1bSYafang Shao switch (event->prog->type) { 36601b715e1bSYafang Shao case BPF_PROG_TYPE_PERF_EVENT: 36611b715e1bSYafang Shao return bpf_perf_link_fill_perf_event(event, info); 36621b715e1bSYafang Shao case BPF_PROG_TYPE_TRACEPOINT: 36631b715e1bSYafang Shao return bpf_perf_link_fill_tracepoint(event, info); 36641b715e1bSYafang Shao case BPF_PROG_TYPE_KPROBE: 36651b715e1bSYafang Shao return bpf_perf_link_fill_probe(event, info); 36661b715e1bSYafang Shao default: 36671b715e1bSYafang Shao return -EOPNOTSUPP; 36681b715e1bSYafang Shao } 36691b715e1bSYafang Shao } 36701b715e1bSYafang Shao 3671b89fbfbbSAndrii Nakryiko static const struct bpf_link_ops bpf_perf_link_lops = { 3672b89fbfbbSAndrii Nakryiko .release = bpf_perf_link_release, 3673b89fbfbbSAndrii Nakryiko .dealloc = bpf_perf_link_dealloc, 36741b715e1bSYafang Shao .fill_link_info = bpf_perf_link_fill_link_info, 3675b89fbfbbSAndrii Nakryiko }; 3676b89fbfbbSAndrii Nakryiko 3677b89fbfbbSAndrii Nakryiko static int bpf_perf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog) 3678b89fbfbbSAndrii Nakryiko { 3679b89fbfbbSAndrii Nakryiko struct bpf_link_primer link_primer; 3680b89fbfbbSAndrii Nakryiko struct bpf_perf_link *link; 3681b89fbfbbSAndrii Nakryiko struct perf_event *event; 3682b89fbfbbSAndrii Nakryiko struct file *perf_file; 3683b89fbfbbSAndrii Nakryiko int err; 3684b89fbfbbSAndrii Nakryiko 3685b89fbfbbSAndrii Nakryiko if (attr->link_create.flags) 3686b89fbfbbSAndrii Nakryiko return -EINVAL; 3687b89fbfbbSAndrii Nakryiko 3688b89fbfbbSAndrii Nakryiko perf_file = perf_event_get(attr->link_create.target_fd); 3689b89fbfbbSAndrii Nakryiko if (IS_ERR(perf_file)) 3690b89fbfbbSAndrii Nakryiko return PTR_ERR(perf_file); 3691b89fbfbbSAndrii Nakryiko 3692b89fbfbbSAndrii Nakryiko link = kzalloc(sizeof(*link), GFP_USER); 3693b89fbfbbSAndrii Nakryiko if (!link) { 3694b89fbfbbSAndrii Nakryiko err = -ENOMEM; 3695b89fbfbbSAndrii Nakryiko goto out_put_file; 3696b89fbfbbSAndrii Nakryiko } 3697b89fbfbbSAndrii Nakryiko bpf_link_init(&link->link, BPF_LINK_TYPE_PERF_EVENT, &bpf_perf_link_lops, prog); 3698b89fbfbbSAndrii Nakryiko link->perf_file = perf_file; 3699b89fbfbbSAndrii Nakryiko 3700b89fbfbbSAndrii Nakryiko err = bpf_link_prime(&link->link, &link_primer); 3701b89fbfbbSAndrii Nakryiko if (err) { 3702b89fbfbbSAndrii Nakryiko kfree(link); 3703b89fbfbbSAndrii Nakryiko goto out_put_file; 3704b89fbfbbSAndrii Nakryiko } 3705b89fbfbbSAndrii Nakryiko 3706b89fbfbbSAndrii Nakryiko event = perf_file->private_data; 370782e6b1eeSAndrii Nakryiko err = perf_event_set_bpf_prog(event, prog, attr->link_create.perf_event.bpf_cookie); 3708b89fbfbbSAndrii Nakryiko if (err) { 3709b89fbfbbSAndrii Nakryiko bpf_link_cleanup(&link_primer); 3710b89fbfbbSAndrii Nakryiko goto out_put_file; 3711b89fbfbbSAndrii Nakryiko } 3712b89fbfbbSAndrii Nakryiko /* perf_event_set_bpf_prog() doesn't take its own refcnt on prog */ 3713b89fbfbbSAndrii Nakryiko bpf_prog_inc(prog); 3714b89fbfbbSAndrii Nakryiko 3715b89fbfbbSAndrii Nakryiko return bpf_link_settle(&link_primer); 3716b89fbfbbSAndrii Nakryiko 3717b89fbfbbSAndrii Nakryiko out_put_file: 3718b89fbfbbSAndrii Nakryiko fput(perf_file); 3719b89fbfbbSAndrii Nakryiko return err; 3720b89fbfbbSAndrii Nakryiko } 37210dcac272SJiri Olsa #else 37220dcac272SJiri Olsa static int bpf_perf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog) 37230dcac272SJiri Olsa { 37240dcac272SJiri Olsa return -EOPNOTSUPP; 37250dcac272SJiri Olsa } 3726b89fbfbbSAndrii Nakryiko #endif /* CONFIG_PERF_EVENTS */ 3727b89fbfbbSAndrii Nakryiko 3728df86ca0dSAndrii Nakryiko static int bpf_raw_tp_link_attach(struct bpf_prog *prog, 3729df86ca0dSAndrii Nakryiko const char __user *user_tp_name) 3730c4f6699dSAlexei Starovoitov { 3731a3b80e10SAndrii Nakryiko struct bpf_link_primer link_primer; 3732babf3164SAndrii Nakryiko struct bpf_raw_tp_link *link; 3733c4f6699dSAlexei Starovoitov struct bpf_raw_event_map *btp; 3734ac4414b5SAlexei Starovoitov const char *tp_name; 3735ac4414b5SAlexei Starovoitov char buf[128]; 3736a3b80e10SAndrii Nakryiko int err; 3737c4f6699dSAlexei Starovoitov 37389e4e01dfSKP Singh switch (prog->type) { 37399e4e01dfSKP Singh case BPF_PROG_TYPE_TRACING: 37409e4e01dfSKP Singh case BPF_PROG_TYPE_EXT: 37419e4e01dfSKP Singh case BPF_PROG_TYPE_LSM: 3742df86ca0dSAndrii Nakryiko if (user_tp_name) 3743fec56f58SAlexei Starovoitov /* The attach point for this category of programs 3744fec56f58SAlexei Starovoitov * should be specified via btf_id during program load. 3745ac4414b5SAlexei Starovoitov */ 3746df86ca0dSAndrii Nakryiko return -EINVAL; 37479e4e01dfSKP Singh if (prog->type == BPF_PROG_TYPE_TRACING && 37489e4e01dfSKP Singh prog->expected_attach_type == BPF_TRACE_RAW_TP) { 374938207291SMartin KaFai Lau tp_name = prog->aux->attach_func_name; 37509e4e01dfSKP Singh break; 37519e4e01dfSKP Singh } 37522fcc8241SKui-Feng Lee return bpf_tracing_prog_attach(prog, 0, 0, 0); 37539e4e01dfSKP Singh case BPF_PROG_TYPE_RAW_TRACEPOINT: 37549e4e01dfSKP Singh case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE: 3755df86ca0dSAndrii Nakryiko if (strncpy_from_user(buf, user_tp_name, sizeof(buf) - 1) < 0) 3756df86ca0dSAndrii Nakryiko return -EFAULT; 3757ac4414b5SAlexei Starovoitov buf[sizeof(buf) - 1] = 0; 3758ac4414b5SAlexei Starovoitov tp_name = buf; 37599e4e01dfSKP Singh break; 37609e4e01dfSKP Singh default: 3761df86ca0dSAndrii Nakryiko return -EINVAL; 3762ac4414b5SAlexei Starovoitov } 3763c4f6699dSAlexei Starovoitov 3764a38d1107SMatt Mullins btp = bpf_get_raw_tracepoint(tp_name); 3765df86ca0dSAndrii Nakryiko if (!btp) 3766df86ca0dSAndrii Nakryiko return -ENOENT; 3767c4f6699dSAlexei Starovoitov 3768babf3164SAndrii Nakryiko link = kzalloc(sizeof(*link), GFP_USER); 3769babf3164SAndrii Nakryiko if (!link) { 3770a38d1107SMatt Mullins err = -ENOMEM; 3771a38d1107SMatt Mullins goto out_put_btp; 3772a38d1107SMatt Mullins } 3773f2e10bffSAndrii Nakryiko bpf_link_init(&link->link, BPF_LINK_TYPE_RAW_TRACEPOINT, 3774f2e10bffSAndrii Nakryiko &bpf_raw_tp_link_lops, prog); 3775babf3164SAndrii Nakryiko link->btp = btp; 3776c4f6699dSAlexei Starovoitov 3777a3b80e10SAndrii Nakryiko err = bpf_link_prime(&link->link, &link_primer); 3778a3b80e10SAndrii Nakryiko if (err) { 3779babf3164SAndrii Nakryiko kfree(link); 3780babf3164SAndrii Nakryiko goto out_put_btp; 3781c4f6699dSAlexei Starovoitov } 3782babf3164SAndrii Nakryiko 3783babf3164SAndrii Nakryiko err = bpf_probe_register(link->btp, prog); 3784babf3164SAndrii Nakryiko if (err) { 3785a3b80e10SAndrii Nakryiko bpf_link_cleanup(&link_primer); 3786babf3164SAndrii Nakryiko goto out_put_btp; 3787babf3164SAndrii Nakryiko } 3788babf3164SAndrii Nakryiko 3789a3b80e10SAndrii Nakryiko return bpf_link_settle(&link_primer); 3790c4f6699dSAlexei Starovoitov 3791a38d1107SMatt Mullins out_put_btp: 3792a38d1107SMatt Mullins bpf_put_raw_tracepoint(btp); 3793c4f6699dSAlexei Starovoitov return err; 3794c4f6699dSAlexei Starovoitov } 3795c4f6699dSAlexei Starovoitov 3796df86ca0dSAndrii Nakryiko #define BPF_RAW_TRACEPOINT_OPEN_LAST_FIELD raw_tracepoint.prog_fd 3797df86ca0dSAndrii Nakryiko 3798df86ca0dSAndrii Nakryiko static int bpf_raw_tracepoint_open(const union bpf_attr *attr) 3799df86ca0dSAndrii Nakryiko { 3800df86ca0dSAndrii Nakryiko struct bpf_prog *prog; 3801df86ca0dSAndrii Nakryiko int fd; 3802df86ca0dSAndrii Nakryiko 3803df86ca0dSAndrii Nakryiko if (CHECK_ATTR(BPF_RAW_TRACEPOINT_OPEN)) 3804df86ca0dSAndrii Nakryiko return -EINVAL; 3805df86ca0dSAndrii Nakryiko 3806df86ca0dSAndrii Nakryiko prog = bpf_prog_get(attr->raw_tracepoint.prog_fd); 3807df86ca0dSAndrii Nakryiko if (IS_ERR(prog)) 3808df86ca0dSAndrii Nakryiko return PTR_ERR(prog); 3809df86ca0dSAndrii Nakryiko 3810df86ca0dSAndrii Nakryiko fd = bpf_raw_tp_link_attach(prog, u64_to_user_ptr(attr->raw_tracepoint.name)); 3811df86ca0dSAndrii Nakryiko if (fd < 0) 3812df86ca0dSAndrii Nakryiko bpf_prog_put(prog); 3813df86ca0dSAndrii Nakryiko return fd; 3814df86ca0dSAndrii Nakryiko } 3815df86ca0dSAndrii Nakryiko 3816e28784e3SAndrii Nakryiko static enum bpf_prog_type 3817e28784e3SAndrii Nakryiko attach_type_to_prog_type(enum bpf_attach_type attach_type) 3818e28784e3SAndrii Nakryiko { 3819e28784e3SAndrii Nakryiko switch (attach_type) { 3820e28784e3SAndrii Nakryiko case BPF_CGROUP_INET_INGRESS: 3821e28784e3SAndrii Nakryiko case BPF_CGROUP_INET_EGRESS: 3822e28784e3SAndrii Nakryiko return BPF_PROG_TYPE_CGROUP_SKB; 3823e28784e3SAndrii Nakryiko case BPF_CGROUP_INET_SOCK_CREATE: 3824f5836749SStanislav Fomichev case BPF_CGROUP_INET_SOCK_RELEASE: 3825e28784e3SAndrii Nakryiko case BPF_CGROUP_INET4_POST_BIND: 3826e28784e3SAndrii Nakryiko case BPF_CGROUP_INET6_POST_BIND: 3827e28784e3SAndrii Nakryiko return BPF_PROG_TYPE_CGROUP_SOCK; 3828e28784e3SAndrii Nakryiko case BPF_CGROUP_INET4_BIND: 3829e28784e3SAndrii Nakryiko case BPF_CGROUP_INET6_BIND: 3830e28784e3SAndrii Nakryiko case BPF_CGROUP_INET4_CONNECT: 3831e28784e3SAndrii Nakryiko case BPF_CGROUP_INET6_CONNECT: 3832859051ddSDaan De Meyer case BPF_CGROUP_UNIX_CONNECT: 38331b66d253SDaniel Borkmann case BPF_CGROUP_INET4_GETPEERNAME: 38341b66d253SDaniel Borkmann case BPF_CGROUP_INET6_GETPEERNAME: 3835859051ddSDaan De Meyer case BPF_CGROUP_UNIX_GETPEERNAME: 38361b66d253SDaniel Borkmann case BPF_CGROUP_INET4_GETSOCKNAME: 38371b66d253SDaniel Borkmann case BPF_CGROUP_INET6_GETSOCKNAME: 3838859051ddSDaan De Meyer case BPF_CGROUP_UNIX_GETSOCKNAME: 3839e28784e3SAndrii Nakryiko case BPF_CGROUP_UDP4_SENDMSG: 3840e28784e3SAndrii Nakryiko case BPF_CGROUP_UDP6_SENDMSG: 3841859051ddSDaan De Meyer case BPF_CGROUP_UNIX_SENDMSG: 3842e28784e3SAndrii Nakryiko case BPF_CGROUP_UDP4_RECVMSG: 3843e28784e3SAndrii Nakryiko case BPF_CGROUP_UDP6_RECVMSG: 3844859051ddSDaan De Meyer case BPF_CGROUP_UNIX_RECVMSG: 3845e28784e3SAndrii Nakryiko return BPF_PROG_TYPE_CGROUP_SOCK_ADDR; 3846e28784e3SAndrii Nakryiko case BPF_CGROUP_SOCK_OPS: 3847e28784e3SAndrii Nakryiko return BPF_PROG_TYPE_SOCK_OPS; 3848e28784e3SAndrii Nakryiko case BPF_CGROUP_DEVICE: 3849e28784e3SAndrii Nakryiko return BPF_PROG_TYPE_CGROUP_DEVICE; 3850e28784e3SAndrii Nakryiko case BPF_SK_MSG_VERDICT: 3851e28784e3SAndrii Nakryiko return BPF_PROG_TYPE_SK_MSG; 3852e28784e3SAndrii Nakryiko case BPF_SK_SKB_STREAM_PARSER: 3853e28784e3SAndrii Nakryiko case BPF_SK_SKB_STREAM_VERDICT: 3854a7ba4558SCong Wang case BPF_SK_SKB_VERDICT: 3855e28784e3SAndrii Nakryiko return BPF_PROG_TYPE_SK_SKB; 3856e28784e3SAndrii Nakryiko case BPF_LIRC_MODE2: 3857e28784e3SAndrii Nakryiko return BPF_PROG_TYPE_LIRC_MODE2; 3858e28784e3SAndrii Nakryiko case BPF_FLOW_DISSECTOR: 3859e28784e3SAndrii Nakryiko return BPF_PROG_TYPE_FLOW_DISSECTOR; 3860e28784e3SAndrii Nakryiko case BPF_CGROUP_SYSCTL: 3861e28784e3SAndrii Nakryiko return BPF_PROG_TYPE_CGROUP_SYSCTL; 3862e28784e3SAndrii Nakryiko case BPF_CGROUP_GETSOCKOPT: 3863e28784e3SAndrii Nakryiko case BPF_CGROUP_SETSOCKOPT: 3864e28784e3SAndrii Nakryiko return BPF_PROG_TYPE_CGROUP_SOCKOPT; 3865de4e05caSYonghong Song case BPF_TRACE_ITER: 3866df86ca0dSAndrii Nakryiko case BPF_TRACE_RAW_TP: 3867df86ca0dSAndrii Nakryiko case BPF_TRACE_FENTRY: 3868df86ca0dSAndrii Nakryiko case BPF_TRACE_FEXIT: 3869df86ca0dSAndrii Nakryiko case BPF_MODIFY_RETURN: 3870de4e05caSYonghong Song return BPF_PROG_TYPE_TRACING; 3871df86ca0dSAndrii Nakryiko case BPF_LSM_MAC: 3872df86ca0dSAndrii Nakryiko return BPF_PROG_TYPE_LSM; 3873e9ddbb77SJakub Sitnicki case BPF_SK_LOOKUP: 3874e9ddbb77SJakub Sitnicki return BPF_PROG_TYPE_SK_LOOKUP; 3875aa8d3a71SAndrii Nakryiko case BPF_XDP: 3876aa8d3a71SAndrii Nakryiko return BPF_PROG_TYPE_XDP; 387769fd337aSStanislav Fomichev case BPF_LSM_CGROUP: 387869fd337aSStanislav Fomichev return BPF_PROG_TYPE_LSM; 3879e420bed0SDaniel Borkmann case BPF_TCX_INGRESS: 3880e420bed0SDaniel Borkmann case BPF_TCX_EGRESS: 388135dfaad7SDaniel Borkmann case BPF_NETKIT_PRIMARY: 388235dfaad7SDaniel Borkmann case BPF_NETKIT_PEER: 3883e420bed0SDaniel Borkmann return BPF_PROG_TYPE_SCHED_CLS; 3884e28784e3SAndrii Nakryiko default: 3885e28784e3SAndrii Nakryiko return BPF_PROG_TYPE_UNSPEC; 3886e28784e3SAndrii Nakryiko } 3887e28784e3SAndrii Nakryiko } 3888e28784e3SAndrii Nakryiko 38893505cb9fSJiri Olsa static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog, 38903505cb9fSJiri Olsa enum bpf_attach_type attach_type) 38913505cb9fSJiri Olsa { 38923505cb9fSJiri Olsa enum bpf_prog_type ptype; 38933505cb9fSJiri Olsa 38943505cb9fSJiri Olsa switch (prog->type) { 38953505cb9fSJiri Olsa case BPF_PROG_TYPE_CGROUP_SOCK: 38963505cb9fSJiri Olsa case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: 38973505cb9fSJiri Olsa case BPF_PROG_TYPE_CGROUP_SOCKOPT: 38983505cb9fSJiri Olsa case BPF_PROG_TYPE_SK_LOOKUP: 38993505cb9fSJiri Olsa return attach_type == prog->expected_attach_type ? 0 : -EINVAL; 39003505cb9fSJiri Olsa case BPF_PROG_TYPE_CGROUP_SKB: 3901caf8f28eSAndrii Nakryiko if (!bpf_token_capable(prog->aux->token, CAP_NET_ADMIN)) 39023505cb9fSJiri Olsa /* cg-skb progs can be loaded by unpriv user. 39033505cb9fSJiri Olsa * check permissions at attach time. 39043505cb9fSJiri Olsa */ 39053505cb9fSJiri Olsa return -EPERM; 39063505cb9fSJiri Olsa return prog->enforce_expected_attach_type && 39073505cb9fSJiri Olsa prog->expected_attach_type != attach_type ? 39083505cb9fSJiri Olsa -EINVAL : 0; 39093505cb9fSJiri Olsa case BPF_PROG_TYPE_EXT: 39103505cb9fSJiri Olsa return 0; 39113505cb9fSJiri Olsa case BPF_PROG_TYPE_NETFILTER: 39123505cb9fSJiri Olsa if (attach_type != BPF_NETFILTER) 39133505cb9fSJiri Olsa return -EINVAL; 39143505cb9fSJiri Olsa return 0; 39153505cb9fSJiri Olsa case BPF_PROG_TYPE_PERF_EVENT: 39163505cb9fSJiri Olsa case BPF_PROG_TYPE_TRACEPOINT: 39173505cb9fSJiri Olsa if (attach_type != BPF_PERF_EVENT) 39183505cb9fSJiri Olsa return -EINVAL; 39193505cb9fSJiri Olsa return 0; 39203505cb9fSJiri Olsa case BPF_PROG_TYPE_KPROBE: 39213505cb9fSJiri Olsa if (prog->expected_attach_type == BPF_TRACE_KPROBE_MULTI && 39223505cb9fSJiri Olsa attach_type != BPF_TRACE_KPROBE_MULTI) 39233505cb9fSJiri Olsa return -EINVAL; 392489ae89f5SJiri Olsa if (prog->expected_attach_type == BPF_TRACE_UPROBE_MULTI && 392589ae89f5SJiri Olsa attach_type != BPF_TRACE_UPROBE_MULTI) 392689ae89f5SJiri Olsa return -EINVAL; 39273505cb9fSJiri Olsa if (attach_type != BPF_PERF_EVENT && 392889ae89f5SJiri Olsa attach_type != BPF_TRACE_KPROBE_MULTI && 392989ae89f5SJiri Olsa attach_type != BPF_TRACE_UPROBE_MULTI) 39303505cb9fSJiri Olsa return -EINVAL; 39313505cb9fSJiri Olsa return 0; 39323505cb9fSJiri Olsa case BPF_PROG_TYPE_SCHED_CLS: 39333505cb9fSJiri Olsa if (attach_type != BPF_TCX_INGRESS && 393435dfaad7SDaniel Borkmann attach_type != BPF_TCX_EGRESS && 393535dfaad7SDaniel Borkmann attach_type != BPF_NETKIT_PRIMARY && 393635dfaad7SDaniel Borkmann attach_type != BPF_NETKIT_PEER) 39373505cb9fSJiri Olsa return -EINVAL; 39383505cb9fSJiri Olsa return 0; 39393505cb9fSJiri Olsa default: 39403505cb9fSJiri Olsa ptype = attach_type_to_prog_type(attach_type); 39413505cb9fSJiri Olsa if (ptype == BPF_PROG_TYPE_UNSPEC || ptype != prog->type) 39423505cb9fSJiri Olsa return -EINVAL; 39433505cb9fSJiri Olsa return 0; 39443505cb9fSJiri Olsa } 39453505cb9fSJiri Olsa } 39463505cb9fSJiri Olsa 3947e420bed0SDaniel Borkmann #define BPF_PROG_ATTACH_LAST_FIELD expected_revision 3948174a79ffSJohn Fastabend 3949e420bed0SDaniel Borkmann #define BPF_F_ATTACH_MASK_BASE \ 3950e420bed0SDaniel Borkmann (BPF_F_ALLOW_OVERRIDE | \ 3951e420bed0SDaniel Borkmann BPF_F_ALLOW_MULTI | \ 3952e420bed0SDaniel Borkmann BPF_F_REPLACE) 3953e420bed0SDaniel Borkmann 3954e420bed0SDaniel Borkmann #define BPF_F_ATTACH_MASK_MPROG \ 3955e420bed0SDaniel Borkmann (BPF_F_REPLACE | \ 3956e420bed0SDaniel Borkmann BPF_F_BEFORE | \ 3957e420bed0SDaniel Borkmann BPF_F_AFTER | \ 3958e420bed0SDaniel Borkmann BPF_F_ID | \ 3959e420bed0SDaniel Borkmann BPF_F_LINK) 3960324bda9eSAlexei Starovoitov 3961f4324551SDaniel Mack static int bpf_prog_attach(const union bpf_attr *attr) 3962f4324551SDaniel Mack { 39637f677633SAlexei Starovoitov enum bpf_prog_type ptype; 3964f4324551SDaniel Mack struct bpf_prog *prog; 39657f677633SAlexei Starovoitov int ret; 3966f4324551SDaniel Mack 3967f4324551SDaniel Mack if (CHECK_ATTR(BPF_PROG_ATTACH)) 3968f4324551SDaniel Mack return -EINVAL; 3969f4324551SDaniel Mack 3970e28784e3SAndrii Nakryiko ptype = attach_type_to_prog_type(attr->attach_type); 3971e28784e3SAndrii Nakryiko if (ptype == BPF_PROG_TYPE_UNSPEC) 3972b2cd1257SDavid Ahern return -EINVAL; 3973ba62d611SLorenz Bauer if (bpf_mprog_supported(ptype)) { 3974ba62d611SLorenz Bauer if (attr->attach_flags & ~BPF_F_ATTACH_MASK_MPROG) 3975e420bed0SDaniel Borkmann return -EINVAL; 3976ba62d611SLorenz Bauer } else { 3977ba62d611SLorenz Bauer if (attr->attach_flags & ~BPF_F_ATTACH_MASK_BASE) 3978ba62d611SLorenz Bauer return -EINVAL; 3979ba62d611SLorenz Bauer if (attr->relative_fd || 3980ba62d611SLorenz Bauer attr->expected_revision) 3981ba62d611SLorenz Bauer return -EINVAL; 3982ba62d611SLorenz Bauer } 3983b2cd1257SDavid Ahern 3984b2cd1257SDavid Ahern prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype); 3985f4324551SDaniel Mack if (IS_ERR(prog)) 3986f4324551SDaniel Mack return PTR_ERR(prog); 3987f4324551SDaniel Mack 39885e43f899SAndrey Ignatov if (bpf_prog_attach_check_attach_type(prog, attr->attach_type)) { 39895e43f899SAndrey Ignatov bpf_prog_put(prog); 39905e43f899SAndrey Ignatov return -EINVAL; 39915e43f899SAndrey Ignatov } 39925e43f899SAndrey Ignatov 3993fdb5c453SSean Young switch (ptype) { 3994fdb5c453SSean Young case BPF_PROG_TYPE_SK_SKB: 3995fdb5c453SSean Young case BPF_PROG_TYPE_SK_MSG: 3996604326b4SDaniel Borkmann ret = sock_map_get_from_fd(attr, prog); 3997fdb5c453SSean Young break; 3998fdb5c453SSean Young case BPF_PROG_TYPE_LIRC_MODE2: 3999fdb5c453SSean Young ret = lirc_prog_attach(attr, prog); 4000fdb5c453SSean Young break; 4001d58e468bSPetar Penkov case BPF_PROG_TYPE_FLOW_DISSECTOR: 4002a3fd7ceeSJakub Sitnicki ret = netns_bpf_prog_attach(attr, prog); 4003d58e468bSPetar Penkov break; 4004e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_DEVICE: 4005e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SKB: 4006e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SOCK: 4007e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: 4008e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SOCKOPT: 4009e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SYSCTL: 4010e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_SOCK_OPS: 401169fd337aSStanislav Fomichev case BPF_PROG_TYPE_LSM: 401269fd337aSStanislav Fomichev if (ptype == BPF_PROG_TYPE_LSM && 401369fd337aSStanislav Fomichev prog->expected_attach_type != BPF_LSM_CGROUP) 4014e89f3edfSMilan Landaverde ret = -EINVAL; 4015e89f3edfSMilan Landaverde else 4016fdb5c453SSean Young ret = cgroup_bpf_prog_attach(attr, ptype, prog); 4017e28784e3SAndrii Nakryiko break; 4018e420bed0SDaniel Borkmann case BPF_PROG_TYPE_SCHED_CLS: 401935dfaad7SDaniel Borkmann if (attr->attach_type == BPF_TCX_INGRESS || 402035dfaad7SDaniel Borkmann attr->attach_type == BPF_TCX_EGRESS) 4021e420bed0SDaniel Borkmann ret = tcx_prog_attach(attr, prog); 402235dfaad7SDaniel Borkmann else 402335dfaad7SDaniel Borkmann ret = netkit_prog_attach(attr, prog); 4024e420bed0SDaniel Borkmann break; 4025e28784e3SAndrii Nakryiko default: 4026e28784e3SAndrii Nakryiko ret = -EINVAL; 4027f4324551SDaniel Mack } 4028f4324551SDaniel Mack 40297f677633SAlexei Starovoitov if (ret) 40307f677633SAlexei Starovoitov bpf_prog_put(prog); 40317f677633SAlexei Starovoitov return ret; 4032f4324551SDaniel Mack } 4033f4324551SDaniel Mack 4034e420bed0SDaniel Borkmann #define BPF_PROG_DETACH_LAST_FIELD expected_revision 4035f4324551SDaniel Mack 4036f4324551SDaniel Mack static int bpf_prog_detach(const union bpf_attr *attr) 4037f4324551SDaniel Mack { 4038e420bed0SDaniel Borkmann struct bpf_prog *prog = NULL; 4039324bda9eSAlexei Starovoitov enum bpf_prog_type ptype; 4040e420bed0SDaniel Borkmann int ret; 4041f4324551SDaniel Mack 4042f4324551SDaniel Mack if (CHECK_ATTR(BPF_PROG_DETACH)) 4043f4324551SDaniel Mack return -EINVAL; 4044f4324551SDaniel Mack 4045e28784e3SAndrii Nakryiko ptype = attach_type_to_prog_type(attr->attach_type); 4046e420bed0SDaniel Borkmann if (bpf_mprog_supported(ptype)) { 4047e420bed0SDaniel Borkmann if (ptype == BPF_PROG_TYPE_UNSPEC) 4048e420bed0SDaniel Borkmann return -EINVAL; 4049e420bed0SDaniel Borkmann if (attr->attach_flags & ~BPF_F_ATTACH_MASK_MPROG) 4050e420bed0SDaniel Borkmann return -EINVAL; 4051e420bed0SDaniel Borkmann if (attr->attach_bpf_fd) { 4052e420bed0SDaniel Borkmann prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype); 4053e420bed0SDaniel Borkmann if (IS_ERR(prog)) 4054e420bed0SDaniel Borkmann return PTR_ERR(prog); 4055e420bed0SDaniel Borkmann } 4056ba62d611SLorenz Bauer } else if (attr->attach_flags || 4057ba62d611SLorenz Bauer attr->relative_fd || 4058ba62d611SLorenz Bauer attr->expected_revision) { 4059ba62d611SLorenz Bauer return -EINVAL; 4060e420bed0SDaniel Borkmann } 4061e28784e3SAndrii Nakryiko 4062e28784e3SAndrii Nakryiko switch (ptype) { 4063e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_SK_MSG: 4064e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_SK_SKB: 4065e420bed0SDaniel Borkmann ret = sock_map_prog_detach(attr, ptype); 4066e420bed0SDaniel Borkmann break; 4067e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_LIRC_MODE2: 4068e420bed0SDaniel Borkmann ret = lirc_prog_detach(attr); 4069e420bed0SDaniel Borkmann break; 4070e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_FLOW_DISSECTOR: 4071e420bed0SDaniel Borkmann ret = netns_bpf_prog_detach(attr, ptype); 4072e420bed0SDaniel Borkmann break; 4073e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_DEVICE: 4074e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SKB: 4075e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SOCK: 4076e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: 4077e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SOCKOPT: 4078e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SYSCTL: 4079e28784e3SAndrii Nakryiko case BPF_PROG_TYPE_SOCK_OPS: 408069fd337aSStanislav Fomichev case BPF_PROG_TYPE_LSM: 4081e420bed0SDaniel Borkmann ret = cgroup_bpf_prog_detach(attr, ptype); 4082e420bed0SDaniel Borkmann break; 4083e420bed0SDaniel Borkmann case BPF_PROG_TYPE_SCHED_CLS: 408435dfaad7SDaniel Borkmann if (attr->attach_type == BPF_TCX_INGRESS || 408535dfaad7SDaniel Borkmann attr->attach_type == BPF_TCX_EGRESS) 4086e420bed0SDaniel Borkmann ret = tcx_prog_detach(attr, prog); 408735dfaad7SDaniel Borkmann else 408835dfaad7SDaniel Borkmann ret = netkit_prog_detach(attr, prog); 4089e420bed0SDaniel Borkmann break; 4090f4324551SDaniel Mack default: 4091e420bed0SDaniel Borkmann ret = -EINVAL; 4092f4324551SDaniel Mack } 409340304b2aSLawrence Brakmo 4094e420bed0SDaniel Borkmann if (prog) 4095e420bed0SDaniel Borkmann bpf_prog_put(prog); 4096e420bed0SDaniel Borkmann return ret; 4097e420bed0SDaniel Borkmann } 4098e420bed0SDaniel Borkmann 4099a4fe7838SDaniel Borkmann #define BPF_PROG_QUERY_LAST_FIELD query.revision 4100468e2f64SAlexei Starovoitov 4101468e2f64SAlexei Starovoitov static int bpf_prog_query(const union bpf_attr *attr, 4102468e2f64SAlexei Starovoitov union bpf_attr __user *uattr) 4103468e2f64SAlexei Starovoitov { 4104ed1ad5a7SAndrii Nakryiko if (!bpf_net_capable()) 4105468e2f64SAlexei Starovoitov return -EPERM; 4106468e2f64SAlexei Starovoitov if (CHECK_ATTR(BPF_PROG_QUERY)) 4107468e2f64SAlexei Starovoitov return -EINVAL; 4108468e2f64SAlexei Starovoitov if (attr->query.query_flags & ~BPF_F_QUERY_EFFECTIVE) 4109468e2f64SAlexei Starovoitov return -EINVAL; 4110468e2f64SAlexei Starovoitov 4111468e2f64SAlexei Starovoitov switch (attr->query.attach_type) { 4112468e2f64SAlexei Starovoitov case BPF_CGROUP_INET_INGRESS: 4113468e2f64SAlexei Starovoitov case BPF_CGROUP_INET_EGRESS: 4114468e2f64SAlexei Starovoitov case BPF_CGROUP_INET_SOCK_CREATE: 4115f5836749SStanislav Fomichev case BPF_CGROUP_INET_SOCK_RELEASE: 41164fbac77dSAndrey Ignatov case BPF_CGROUP_INET4_BIND: 41174fbac77dSAndrey Ignatov case BPF_CGROUP_INET6_BIND: 4118aac3fc32SAndrey Ignatov case BPF_CGROUP_INET4_POST_BIND: 4119aac3fc32SAndrey Ignatov case BPF_CGROUP_INET6_POST_BIND: 4120d74bad4eSAndrey Ignatov case BPF_CGROUP_INET4_CONNECT: 4121d74bad4eSAndrey Ignatov case BPF_CGROUP_INET6_CONNECT: 4122859051ddSDaan De Meyer case BPF_CGROUP_UNIX_CONNECT: 41231b66d253SDaniel Borkmann case BPF_CGROUP_INET4_GETPEERNAME: 41241b66d253SDaniel Borkmann case BPF_CGROUP_INET6_GETPEERNAME: 4125859051ddSDaan De Meyer case BPF_CGROUP_UNIX_GETPEERNAME: 41261b66d253SDaniel Borkmann case BPF_CGROUP_INET4_GETSOCKNAME: 41271b66d253SDaniel Borkmann case BPF_CGROUP_INET6_GETSOCKNAME: 4128859051ddSDaan De Meyer case BPF_CGROUP_UNIX_GETSOCKNAME: 41291cedee13SAndrey Ignatov case BPF_CGROUP_UDP4_SENDMSG: 41301cedee13SAndrey Ignatov case BPF_CGROUP_UDP6_SENDMSG: 4131859051ddSDaan De Meyer case BPF_CGROUP_UNIX_SENDMSG: 4132983695faSDaniel Borkmann case BPF_CGROUP_UDP4_RECVMSG: 4133983695faSDaniel Borkmann case BPF_CGROUP_UDP6_RECVMSG: 4134859051ddSDaan De Meyer case BPF_CGROUP_UNIX_RECVMSG: 4135468e2f64SAlexei Starovoitov case BPF_CGROUP_SOCK_OPS: 4136ebc614f6SRoman Gushchin case BPF_CGROUP_DEVICE: 41377b146cebSAndrey Ignatov case BPF_CGROUP_SYSCTL: 41380d01da6aSStanislav Fomichev case BPF_CGROUP_GETSOCKOPT: 41390d01da6aSStanislav Fomichev case BPF_CGROUP_SETSOCKOPT: 4140b79c9fc9SStanislav Fomichev case BPF_LSM_CGROUP: 4141e28784e3SAndrii Nakryiko return cgroup_bpf_prog_query(attr, uattr); 4142f4364dcfSSean Young case BPF_LIRC_MODE2: 4143f4364dcfSSean Young return lirc_prog_query(attr, uattr); 4144118c8e9aSStanislav Fomichev case BPF_FLOW_DISSECTOR: 4145e9ddbb77SJakub Sitnicki case BPF_SK_LOOKUP: 4146a3fd7ceeSJakub Sitnicki return netns_bpf_prog_query(attr, uattr); 4147748cd572SDi Zhu case BPF_SK_SKB_STREAM_PARSER: 4148748cd572SDi Zhu case BPF_SK_SKB_STREAM_VERDICT: 4149748cd572SDi Zhu case BPF_SK_MSG_VERDICT: 4150748cd572SDi Zhu case BPF_SK_SKB_VERDICT: 4151748cd572SDi Zhu return sock_map_bpf_prog_query(attr, uattr); 4152e420bed0SDaniel Borkmann case BPF_TCX_INGRESS: 4153e420bed0SDaniel Borkmann case BPF_TCX_EGRESS: 4154e420bed0SDaniel Borkmann return tcx_prog_query(attr, uattr); 415535dfaad7SDaniel Borkmann case BPF_NETKIT_PRIMARY: 415635dfaad7SDaniel Borkmann case BPF_NETKIT_PEER: 415735dfaad7SDaniel Borkmann return netkit_prog_query(attr, uattr); 4158468e2f64SAlexei Starovoitov default: 4159468e2f64SAlexei Starovoitov return -EINVAL; 4160468e2f64SAlexei Starovoitov } 4161468e2f64SAlexei Starovoitov } 4162f4324551SDaniel Mack 4163b530e9e1SToke Høiland-Jørgensen #define BPF_PROG_TEST_RUN_LAST_FIELD test.batch_size 41641cf1cae9SAlexei Starovoitov 41651cf1cae9SAlexei Starovoitov static int bpf_prog_test_run(const union bpf_attr *attr, 41661cf1cae9SAlexei Starovoitov union bpf_attr __user *uattr) 41671cf1cae9SAlexei Starovoitov { 41681cf1cae9SAlexei Starovoitov struct bpf_prog *prog; 41691cf1cae9SAlexei Starovoitov int ret = -ENOTSUPP; 41701cf1cae9SAlexei Starovoitov 41711cf1cae9SAlexei Starovoitov if (CHECK_ATTR(BPF_PROG_TEST_RUN)) 41721cf1cae9SAlexei Starovoitov return -EINVAL; 41731cf1cae9SAlexei Starovoitov 4174b0b9395dSStanislav Fomichev if ((attr->test.ctx_size_in && !attr->test.ctx_in) || 4175b0b9395dSStanislav Fomichev (!attr->test.ctx_size_in && attr->test.ctx_in)) 4176b0b9395dSStanislav Fomichev return -EINVAL; 4177b0b9395dSStanislav Fomichev 4178b0b9395dSStanislav Fomichev if ((attr->test.ctx_size_out && !attr->test.ctx_out) || 4179b0b9395dSStanislav Fomichev (!attr->test.ctx_size_out && attr->test.ctx_out)) 4180b0b9395dSStanislav Fomichev return -EINVAL; 4181b0b9395dSStanislav Fomichev 41821cf1cae9SAlexei Starovoitov prog = bpf_prog_get(attr->test.prog_fd); 41831cf1cae9SAlexei Starovoitov if (IS_ERR(prog)) 41841cf1cae9SAlexei Starovoitov return PTR_ERR(prog); 41851cf1cae9SAlexei Starovoitov 41861cf1cae9SAlexei Starovoitov if (prog->aux->ops->test_run) 41871cf1cae9SAlexei Starovoitov ret = prog->aux->ops->test_run(prog, attr, uattr); 41881cf1cae9SAlexei Starovoitov 41891cf1cae9SAlexei Starovoitov bpf_prog_put(prog); 41901cf1cae9SAlexei Starovoitov return ret; 41911cf1cae9SAlexei Starovoitov } 41921cf1cae9SAlexei Starovoitov 419334ad5580SMartin KaFai Lau #define BPF_OBJ_GET_NEXT_ID_LAST_FIELD next_id 419434ad5580SMartin KaFai Lau 419534ad5580SMartin KaFai Lau static int bpf_obj_get_next_id(const union bpf_attr *attr, 419634ad5580SMartin KaFai Lau union bpf_attr __user *uattr, 419734ad5580SMartin KaFai Lau struct idr *idr, 419834ad5580SMartin KaFai Lau spinlock_t *lock) 419934ad5580SMartin KaFai Lau { 420034ad5580SMartin KaFai Lau u32 next_id = attr->start_id; 420134ad5580SMartin KaFai Lau int err = 0; 420234ad5580SMartin KaFai Lau 420334ad5580SMartin KaFai Lau if (CHECK_ATTR(BPF_OBJ_GET_NEXT_ID) || next_id >= INT_MAX) 420434ad5580SMartin KaFai Lau return -EINVAL; 420534ad5580SMartin KaFai Lau 420634ad5580SMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) 420734ad5580SMartin KaFai Lau return -EPERM; 420834ad5580SMartin KaFai Lau 420934ad5580SMartin KaFai Lau next_id++; 421034ad5580SMartin KaFai Lau spin_lock_bh(lock); 421134ad5580SMartin KaFai Lau if (!idr_get_next(idr, &next_id)) 421234ad5580SMartin KaFai Lau err = -ENOENT; 421334ad5580SMartin KaFai Lau spin_unlock_bh(lock); 421434ad5580SMartin KaFai Lau 421534ad5580SMartin KaFai Lau if (!err) 421634ad5580SMartin KaFai Lau err = put_user(next_id, &uattr->next_id); 421734ad5580SMartin KaFai Lau 421834ad5580SMartin KaFai Lau return err; 421934ad5580SMartin KaFai Lau } 422034ad5580SMartin KaFai Lau 42216086d29dSYonghong Song struct bpf_map *bpf_map_get_curr_or_next(u32 *id) 42226086d29dSYonghong Song { 42236086d29dSYonghong Song struct bpf_map *map; 42246086d29dSYonghong Song 42256086d29dSYonghong Song spin_lock_bh(&map_idr_lock); 42266086d29dSYonghong Song again: 42276086d29dSYonghong Song map = idr_get_next(&map_idr, id); 42286086d29dSYonghong Song if (map) { 42296086d29dSYonghong Song map = __bpf_map_inc_not_zero(map, false); 42306086d29dSYonghong Song if (IS_ERR(map)) { 42316086d29dSYonghong Song (*id)++; 42326086d29dSYonghong Song goto again; 42336086d29dSYonghong Song } 42346086d29dSYonghong Song } 42356086d29dSYonghong Song spin_unlock_bh(&map_idr_lock); 42366086d29dSYonghong Song 42376086d29dSYonghong Song return map; 42386086d29dSYonghong Song } 42396086d29dSYonghong Song 4240a228a64fSAlexei Starovoitov struct bpf_prog *bpf_prog_get_curr_or_next(u32 *id) 4241a228a64fSAlexei Starovoitov { 4242a228a64fSAlexei Starovoitov struct bpf_prog *prog; 4243a228a64fSAlexei Starovoitov 4244a228a64fSAlexei Starovoitov spin_lock_bh(&prog_idr_lock); 4245a228a64fSAlexei Starovoitov again: 4246a228a64fSAlexei Starovoitov prog = idr_get_next(&prog_idr, id); 4247a228a64fSAlexei Starovoitov if (prog) { 4248a228a64fSAlexei Starovoitov prog = bpf_prog_inc_not_zero(prog); 4249a228a64fSAlexei Starovoitov if (IS_ERR(prog)) { 4250a228a64fSAlexei Starovoitov (*id)++; 4251a228a64fSAlexei Starovoitov goto again; 4252a228a64fSAlexei Starovoitov } 4253a228a64fSAlexei Starovoitov } 4254a228a64fSAlexei Starovoitov spin_unlock_bh(&prog_idr_lock); 4255a228a64fSAlexei Starovoitov 4256a228a64fSAlexei Starovoitov return prog; 4257a228a64fSAlexei Starovoitov } 4258a228a64fSAlexei Starovoitov 4259b16d9aa4SMartin KaFai Lau #define BPF_PROG_GET_FD_BY_ID_LAST_FIELD prog_id 4260b16d9aa4SMartin KaFai Lau 42617e6897f9SBjörn Töpel struct bpf_prog *bpf_prog_by_id(u32 id) 42627e6897f9SBjörn Töpel { 42637e6897f9SBjörn Töpel struct bpf_prog *prog; 42647e6897f9SBjörn Töpel 42657e6897f9SBjörn Töpel if (!id) 42667e6897f9SBjörn Töpel return ERR_PTR(-ENOENT); 42677e6897f9SBjörn Töpel 42687e6897f9SBjörn Töpel spin_lock_bh(&prog_idr_lock); 42697e6897f9SBjörn Töpel prog = idr_find(&prog_idr, id); 42707e6897f9SBjörn Töpel if (prog) 42717e6897f9SBjörn Töpel prog = bpf_prog_inc_not_zero(prog); 42727e6897f9SBjörn Töpel else 42737e6897f9SBjörn Töpel prog = ERR_PTR(-ENOENT); 42747e6897f9SBjörn Töpel spin_unlock_bh(&prog_idr_lock); 42757e6897f9SBjörn Töpel return prog; 42767e6897f9SBjörn Töpel } 42777e6897f9SBjörn Töpel 4278b16d9aa4SMartin KaFai Lau static int bpf_prog_get_fd_by_id(const union bpf_attr *attr) 4279b16d9aa4SMartin KaFai Lau { 4280b16d9aa4SMartin KaFai Lau struct bpf_prog *prog; 4281b16d9aa4SMartin KaFai Lau u32 id = attr->prog_id; 4282b16d9aa4SMartin KaFai Lau int fd; 4283b16d9aa4SMartin KaFai Lau 4284b16d9aa4SMartin KaFai Lau if (CHECK_ATTR(BPF_PROG_GET_FD_BY_ID)) 4285b16d9aa4SMartin KaFai Lau return -EINVAL; 4286b16d9aa4SMartin KaFai Lau 4287b16d9aa4SMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) 4288b16d9aa4SMartin KaFai Lau return -EPERM; 4289b16d9aa4SMartin KaFai Lau 42907e6897f9SBjörn Töpel prog = bpf_prog_by_id(id); 4291b16d9aa4SMartin KaFai Lau if (IS_ERR(prog)) 4292b16d9aa4SMartin KaFai Lau return PTR_ERR(prog); 4293b16d9aa4SMartin KaFai Lau 4294b16d9aa4SMartin KaFai Lau fd = bpf_prog_new_fd(prog); 4295b16d9aa4SMartin KaFai Lau if (fd < 0) 4296b16d9aa4SMartin KaFai Lau bpf_prog_put(prog); 4297b16d9aa4SMartin KaFai Lau 4298b16d9aa4SMartin KaFai Lau return fd; 4299b16d9aa4SMartin KaFai Lau } 4300b16d9aa4SMartin KaFai Lau 43016e71b04aSChenbo Feng #define BPF_MAP_GET_FD_BY_ID_LAST_FIELD open_flags 4302bd5f5f4eSMartin KaFai Lau 4303bd5f5f4eSMartin KaFai Lau static int bpf_map_get_fd_by_id(const union bpf_attr *attr) 4304bd5f5f4eSMartin KaFai Lau { 4305bd5f5f4eSMartin KaFai Lau struct bpf_map *map; 4306bd5f5f4eSMartin KaFai Lau u32 id = attr->map_id; 43076e71b04aSChenbo Feng int f_flags; 4308bd5f5f4eSMartin KaFai Lau int fd; 4309bd5f5f4eSMartin KaFai Lau 43106e71b04aSChenbo Feng if (CHECK_ATTR(BPF_MAP_GET_FD_BY_ID) || 43116e71b04aSChenbo Feng attr->open_flags & ~BPF_OBJ_FLAG_MASK) 4312bd5f5f4eSMartin KaFai Lau return -EINVAL; 4313bd5f5f4eSMartin KaFai Lau 4314bd5f5f4eSMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) 4315bd5f5f4eSMartin KaFai Lau return -EPERM; 4316bd5f5f4eSMartin KaFai Lau 43176e71b04aSChenbo Feng f_flags = bpf_get_file_flag(attr->open_flags); 43186e71b04aSChenbo Feng if (f_flags < 0) 43196e71b04aSChenbo Feng return f_flags; 43206e71b04aSChenbo Feng 4321bd5f5f4eSMartin KaFai Lau spin_lock_bh(&map_idr_lock); 4322bd5f5f4eSMartin KaFai Lau map = idr_find(&map_idr, id); 4323bd5f5f4eSMartin KaFai Lau if (map) 4324b0e4701cSStanislav Fomichev map = __bpf_map_inc_not_zero(map, true); 4325bd5f5f4eSMartin KaFai Lau else 4326bd5f5f4eSMartin KaFai Lau map = ERR_PTR(-ENOENT); 4327bd5f5f4eSMartin KaFai Lau spin_unlock_bh(&map_idr_lock); 4328bd5f5f4eSMartin KaFai Lau 4329bd5f5f4eSMartin KaFai Lau if (IS_ERR(map)) 4330bd5f5f4eSMartin KaFai Lau return PTR_ERR(map); 4331bd5f5f4eSMartin KaFai Lau 43326e71b04aSChenbo Feng fd = bpf_map_new_fd(map, f_flags); 4333bd5f5f4eSMartin KaFai Lau if (fd < 0) 4334781e6282SPeng Sun bpf_map_put_with_uref(map); 4335bd5f5f4eSMartin KaFai Lau 4336bd5f5f4eSMartin KaFai Lau return fd; 4337bd5f5f4eSMartin KaFai Lau } 4338bd5f5f4eSMartin KaFai Lau 43397105e828SDaniel Borkmann static const struct bpf_map *bpf_map_from_imm(const struct bpf_prog *prog, 4340d8eca5bbSDaniel Borkmann unsigned long addr, u32 *off, 4341d8eca5bbSDaniel Borkmann u32 *type) 43427105e828SDaniel Borkmann { 4343d8eca5bbSDaniel Borkmann const struct bpf_map *map; 43447105e828SDaniel Borkmann int i; 43457105e828SDaniel Borkmann 4346984fe94fSYiFei Zhu mutex_lock(&prog->aux->used_maps_mutex); 4347d8eca5bbSDaniel Borkmann for (i = 0, *off = 0; i < prog->aux->used_map_cnt; i++) { 4348d8eca5bbSDaniel Borkmann map = prog->aux->used_maps[i]; 4349d8eca5bbSDaniel Borkmann if (map == (void *)addr) { 4350d8eca5bbSDaniel Borkmann *type = BPF_PSEUDO_MAP_FD; 4351984fe94fSYiFei Zhu goto out; 4352d8eca5bbSDaniel Borkmann } 4353d8eca5bbSDaniel Borkmann if (!map->ops->map_direct_value_meta) 4354d8eca5bbSDaniel Borkmann continue; 4355d8eca5bbSDaniel Borkmann if (!map->ops->map_direct_value_meta(map, addr, off)) { 4356d8eca5bbSDaniel Borkmann *type = BPF_PSEUDO_MAP_VALUE; 4357984fe94fSYiFei Zhu goto out; 4358d8eca5bbSDaniel Borkmann } 4359d8eca5bbSDaniel Borkmann } 4360984fe94fSYiFei Zhu map = NULL; 4361d8eca5bbSDaniel Borkmann 4362984fe94fSYiFei Zhu out: 4363984fe94fSYiFei Zhu mutex_unlock(&prog->aux->used_maps_mutex); 4364984fe94fSYiFei Zhu return map; 43657105e828SDaniel Borkmann } 43667105e828SDaniel Borkmann 436763960260SKees Cook static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog, 436863960260SKees Cook const struct cred *f_cred) 43697105e828SDaniel Borkmann { 43707105e828SDaniel Borkmann const struct bpf_map *map; 43717105e828SDaniel Borkmann struct bpf_insn *insns; 4372d8eca5bbSDaniel Borkmann u32 off, type; 43737105e828SDaniel Borkmann u64 imm; 437429fcb05bSAndrii Nakryiko u8 code; 43757105e828SDaniel Borkmann int i; 43767105e828SDaniel Borkmann 43777105e828SDaniel Borkmann insns = kmemdup(prog->insnsi, bpf_prog_insn_size(prog), 43787105e828SDaniel Borkmann GFP_USER); 43797105e828SDaniel Borkmann if (!insns) 43807105e828SDaniel Borkmann return insns; 43817105e828SDaniel Borkmann 43827105e828SDaniel Borkmann for (i = 0; i < prog->len; i++) { 438329fcb05bSAndrii Nakryiko code = insns[i].code; 438429fcb05bSAndrii Nakryiko 438529fcb05bSAndrii Nakryiko if (code == (BPF_JMP | BPF_TAIL_CALL)) { 43867105e828SDaniel Borkmann insns[i].code = BPF_JMP | BPF_CALL; 43877105e828SDaniel Borkmann insns[i].imm = BPF_FUNC_tail_call; 43887105e828SDaniel Borkmann /* fall-through */ 43897105e828SDaniel Borkmann } 439029fcb05bSAndrii Nakryiko if (code == (BPF_JMP | BPF_CALL) || 439129fcb05bSAndrii Nakryiko code == (BPF_JMP | BPF_CALL_ARGS)) { 439229fcb05bSAndrii Nakryiko if (code == (BPF_JMP | BPF_CALL_ARGS)) 43937105e828SDaniel Borkmann insns[i].code = BPF_JMP | BPF_CALL; 439463960260SKees Cook if (!bpf_dump_raw_ok(f_cred)) 43957105e828SDaniel Borkmann insns[i].imm = 0; 43967105e828SDaniel Borkmann continue; 43977105e828SDaniel Borkmann } 439829fcb05bSAndrii Nakryiko if (BPF_CLASS(code) == BPF_LDX && BPF_MODE(code) == BPF_PROBE_MEM) { 439929fcb05bSAndrii Nakryiko insns[i].code = BPF_LDX | BPF_SIZE(code) | BPF_MEM; 440029fcb05bSAndrii Nakryiko continue; 440129fcb05bSAndrii Nakryiko } 44027105e828SDaniel Borkmann 440329fcb05bSAndrii Nakryiko if (code != (BPF_LD | BPF_IMM | BPF_DW)) 44047105e828SDaniel Borkmann continue; 44057105e828SDaniel Borkmann 44067105e828SDaniel Borkmann imm = ((u64)insns[i + 1].imm << 32) | (u32)insns[i].imm; 4407d8eca5bbSDaniel Borkmann map = bpf_map_from_imm(prog, imm, &off, &type); 44087105e828SDaniel Borkmann if (map) { 4409d8eca5bbSDaniel Borkmann insns[i].src_reg = type; 44107105e828SDaniel Borkmann insns[i].imm = map->id; 4411d8eca5bbSDaniel Borkmann insns[i + 1].imm = off; 44127105e828SDaniel Borkmann continue; 44137105e828SDaniel Borkmann } 44147105e828SDaniel Borkmann } 44157105e828SDaniel Borkmann 44167105e828SDaniel Borkmann return insns; 44177105e828SDaniel Borkmann } 44187105e828SDaniel Borkmann 4419c454a46bSMartin KaFai Lau static int set_info_rec_size(struct bpf_prog_info *info) 4420c454a46bSMartin KaFai Lau { 4421c454a46bSMartin KaFai Lau /* 4422c454a46bSMartin KaFai Lau * Ensure info.*_rec_size is the same as kernel expected size 4423c454a46bSMartin KaFai Lau * 4424c454a46bSMartin KaFai Lau * or 4425c454a46bSMartin KaFai Lau * 4426c454a46bSMartin KaFai Lau * Only allow zero *_rec_size if both _rec_size and _cnt are 4427c454a46bSMartin KaFai Lau * zero. In this case, the kernel will set the expected 4428c454a46bSMartin KaFai Lau * _rec_size back to the info. 4429c454a46bSMartin KaFai Lau */ 4430c454a46bSMartin KaFai Lau 443111d8b82dSYonghong Song if ((info->nr_func_info || info->func_info_rec_size) && 4432c454a46bSMartin KaFai Lau info->func_info_rec_size != sizeof(struct bpf_func_info)) 4433c454a46bSMartin KaFai Lau return -EINVAL; 4434c454a46bSMartin KaFai Lau 443511d8b82dSYonghong Song if ((info->nr_line_info || info->line_info_rec_size) && 4436c454a46bSMartin KaFai Lau info->line_info_rec_size != sizeof(struct bpf_line_info)) 4437c454a46bSMartin KaFai Lau return -EINVAL; 4438c454a46bSMartin KaFai Lau 443911d8b82dSYonghong Song if ((info->nr_jited_line_info || info->jited_line_info_rec_size) && 4440c454a46bSMartin KaFai Lau info->jited_line_info_rec_size != sizeof(__u64)) 4441c454a46bSMartin KaFai Lau return -EINVAL; 4442c454a46bSMartin KaFai Lau 4443c454a46bSMartin KaFai Lau info->func_info_rec_size = sizeof(struct bpf_func_info); 4444c454a46bSMartin KaFai Lau info->line_info_rec_size = sizeof(struct bpf_line_info); 4445c454a46bSMartin KaFai Lau info->jited_line_info_rec_size = sizeof(__u64); 4446c454a46bSMartin KaFai Lau 4447c454a46bSMartin KaFai Lau return 0; 4448c454a46bSMartin KaFai Lau } 4449c454a46bSMartin KaFai Lau 445063960260SKees Cook static int bpf_prog_get_info_by_fd(struct file *file, 445163960260SKees Cook struct bpf_prog *prog, 44521e270976SMartin KaFai Lau const union bpf_attr *attr, 44531e270976SMartin KaFai Lau union bpf_attr __user *uattr) 44541e270976SMartin KaFai Lau { 44551e270976SMartin KaFai Lau struct bpf_prog_info __user *uinfo = u64_to_user_ptr(attr->info.info); 44566644aabbSStanislav Fomichev struct btf *attach_btf = bpf_prog_get_target_btf(prog); 44575c6f2588SGreg Kroah-Hartman struct bpf_prog_info info; 44581e270976SMartin KaFai Lau u32 info_len = attr->info.info_len; 445961a0abaeSEric Dumazet struct bpf_prog_kstats stats; 44601e270976SMartin KaFai Lau char __user *uinsns; 44611e270976SMartin KaFai Lau u32 ulen; 44621e270976SMartin KaFai Lau int err; 44631e270976SMartin KaFai Lau 4464af2ac3e1SAlexei Starovoitov err = bpf_check_uarg_tail_zero(USER_BPFPTR(uinfo), sizeof(info), info_len); 44651e270976SMartin KaFai Lau if (err) 44661e270976SMartin KaFai Lau return err; 44671e270976SMartin KaFai Lau info_len = min_t(u32, sizeof(info), info_len); 44681e270976SMartin KaFai Lau 44695c6f2588SGreg Kroah-Hartman memset(&info, 0, sizeof(info)); 44701e270976SMartin KaFai Lau if (copy_from_user(&info, uinfo, info_len)) 447189b09689SDaniel Borkmann return -EFAULT; 44721e270976SMartin KaFai Lau 44731e270976SMartin KaFai Lau info.type = prog->type; 44741e270976SMartin KaFai Lau info.id = prog->aux->id; 4475cb4d2b3fSMartin KaFai Lau info.load_time = prog->aux->load_time; 4476cb4d2b3fSMartin KaFai Lau info.created_by_uid = from_kuid_munged(current_user_ns(), 4477cb4d2b3fSMartin KaFai Lau prog->aux->user->uid); 4478b85fab0eSJiri Olsa info.gpl_compatible = prog->gpl_compatible; 44791e270976SMartin KaFai Lau 44801e270976SMartin KaFai Lau memcpy(info.tag, prog->tag, sizeof(prog->tag)); 4481cb4d2b3fSMartin KaFai Lau memcpy(info.name, prog->aux->name, sizeof(prog->aux->name)); 4482cb4d2b3fSMartin KaFai Lau 4483984fe94fSYiFei Zhu mutex_lock(&prog->aux->used_maps_mutex); 4484cb4d2b3fSMartin KaFai Lau ulen = info.nr_map_ids; 4485cb4d2b3fSMartin KaFai Lau info.nr_map_ids = prog->aux->used_map_cnt; 4486cb4d2b3fSMartin KaFai Lau ulen = min_t(u32, info.nr_map_ids, ulen); 4487cb4d2b3fSMartin KaFai Lau if (ulen) { 4488721e08daSMartin KaFai Lau u32 __user *user_map_ids = u64_to_user_ptr(info.map_ids); 4489cb4d2b3fSMartin KaFai Lau u32 i; 4490cb4d2b3fSMartin KaFai Lau 4491cb4d2b3fSMartin KaFai Lau for (i = 0; i < ulen; i++) 4492cb4d2b3fSMartin KaFai Lau if (put_user(prog->aux->used_maps[i]->id, 4493984fe94fSYiFei Zhu &user_map_ids[i])) { 4494984fe94fSYiFei Zhu mutex_unlock(&prog->aux->used_maps_mutex); 4495cb4d2b3fSMartin KaFai Lau return -EFAULT; 4496cb4d2b3fSMartin KaFai Lau } 4497984fe94fSYiFei Zhu } 4498984fe94fSYiFei Zhu mutex_unlock(&prog->aux->used_maps_mutex); 44991e270976SMartin KaFai Lau 4500c454a46bSMartin KaFai Lau err = set_info_rec_size(&info); 4501c454a46bSMartin KaFai Lau if (err) 4502c454a46bSMartin KaFai Lau return err; 45037337224fSMartin KaFai Lau 45045f8f8b93SAlexei Starovoitov bpf_prog_get_stats(prog, &stats); 45055f8f8b93SAlexei Starovoitov info.run_time_ns = stats.nsecs; 45065f8f8b93SAlexei Starovoitov info.run_cnt = stats.cnt; 45079ed9e9baSAlexei Starovoitov info.recursion_misses = stats.misses; 45085f8f8b93SAlexei Starovoitov 4509aba64c7dSDave Marchevsky info.verified_insns = prog->aux->verified_insns; 4510aba64c7dSDave Marchevsky 45112c78ee89SAlexei Starovoitov if (!bpf_capable()) { 45121e270976SMartin KaFai Lau info.jited_prog_len = 0; 45131e270976SMartin KaFai Lau info.xlated_prog_len = 0; 4514dbecd738SSandipan Das info.nr_jited_ksyms = 0; 451528c2fae7SDaniel Borkmann info.nr_jited_func_lens = 0; 451611d8b82dSYonghong Song info.nr_func_info = 0; 451711d8b82dSYonghong Song info.nr_line_info = 0; 451811d8b82dSYonghong Song info.nr_jited_line_info = 0; 45191e270976SMartin KaFai Lau goto done; 45201e270976SMartin KaFai Lau } 45211e270976SMartin KaFai Lau 45221e270976SMartin KaFai Lau ulen = info.xlated_prog_len; 45239975a54bSDaniel Borkmann info.xlated_prog_len = bpf_prog_insn_size(prog); 45241e270976SMartin KaFai Lau if (info.xlated_prog_len && ulen) { 45257105e828SDaniel Borkmann struct bpf_insn *insns_sanitized; 45267105e828SDaniel Borkmann bool fault; 45277105e828SDaniel Borkmann 452863960260SKees Cook if (prog->blinded && !bpf_dump_raw_ok(file->f_cred)) { 45297105e828SDaniel Borkmann info.xlated_prog_insns = 0; 45307105e828SDaniel Borkmann goto done; 45317105e828SDaniel Borkmann } 453263960260SKees Cook insns_sanitized = bpf_insn_prepare_dump(prog, file->f_cred); 45337105e828SDaniel Borkmann if (!insns_sanitized) 45347105e828SDaniel Borkmann return -ENOMEM; 45351e270976SMartin KaFai Lau uinsns = u64_to_user_ptr(info.xlated_prog_insns); 45361e270976SMartin KaFai Lau ulen = min_t(u32, info.xlated_prog_len, ulen); 45377105e828SDaniel Borkmann fault = copy_to_user(uinsns, insns_sanitized, ulen); 45387105e828SDaniel Borkmann kfree(insns_sanitized); 45397105e828SDaniel Borkmann if (fault) 45401e270976SMartin KaFai Lau return -EFAULT; 45411e270976SMartin KaFai Lau } 45421e270976SMartin KaFai Lau 45439d03ebc7SStanislav Fomichev if (bpf_prog_is_offloaded(prog->aux)) { 4544675fc275SJakub Kicinski err = bpf_prog_offload_info_fill(&info, prog); 4545675fc275SJakub Kicinski if (err) 4546675fc275SJakub Kicinski return err; 4547fcfb126dSJiong Wang goto done; 4548fcfb126dSJiong Wang } 4549fcfb126dSJiong Wang 4550fcfb126dSJiong Wang /* NOTE: the following code is supposed to be skipped for offload. 4551fcfb126dSJiong Wang * bpf_prog_offload_info_fill() is the place to fill similar fields 4552fcfb126dSJiong Wang * for offload. 4553fcfb126dSJiong Wang */ 4554fcfb126dSJiong Wang ulen = info.jited_prog_len; 45554d56a76eSSandipan Das if (prog->aux->func_cnt) { 45564d56a76eSSandipan Das u32 i; 45574d56a76eSSandipan Das 45584d56a76eSSandipan Das info.jited_prog_len = 0; 45594d56a76eSSandipan Das for (i = 0; i < prog->aux->func_cnt; i++) 45604d56a76eSSandipan Das info.jited_prog_len += prog->aux->func[i]->jited_len; 45614d56a76eSSandipan Das } else { 4562fcfb126dSJiong Wang info.jited_prog_len = prog->jited_len; 45634d56a76eSSandipan Das } 45644d56a76eSSandipan Das 4565fcfb126dSJiong Wang if (info.jited_prog_len && ulen) { 456663960260SKees Cook if (bpf_dump_raw_ok(file->f_cred)) { 4567fcfb126dSJiong Wang uinsns = u64_to_user_ptr(info.jited_prog_insns); 4568fcfb126dSJiong Wang ulen = min_t(u32, info.jited_prog_len, ulen); 45694d56a76eSSandipan Das 45704d56a76eSSandipan Das /* for multi-function programs, copy the JITed 45714d56a76eSSandipan Das * instructions for all the functions 45724d56a76eSSandipan Das */ 45734d56a76eSSandipan Das if (prog->aux->func_cnt) { 45744d56a76eSSandipan Das u32 len, free, i; 45754d56a76eSSandipan Das u8 *img; 45764d56a76eSSandipan Das 45774d56a76eSSandipan Das free = ulen; 45784d56a76eSSandipan Das for (i = 0; i < prog->aux->func_cnt; i++) { 45794d56a76eSSandipan Das len = prog->aux->func[i]->jited_len; 45804d56a76eSSandipan Das len = min_t(u32, len, free); 45814d56a76eSSandipan Das img = (u8 *) prog->aux->func[i]->bpf_func; 45824d56a76eSSandipan Das if (copy_to_user(uinsns, img, len)) 45834d56a76eSSandipan Das return -EFAULT; 45844d56a76eSSandipan Das uinsns += len; 45854d56a76eSSandipan Das free -= len; 45864d56a76eSSandipan Das if (!free) 45874d56a76eSSandipan Das break; 45884d56a76eSSandipan Das } 45894d56a76eSSandipan Das } else { 4590fcfb126dSJiong Wang if (copy_to_user(uinsns, prog->bpf_func, ulen)) 4591fcfb126dSJiong Wang return -EFAULT; 45924d56a76eSSandipan Das } 4593fcfb126dSJiong Wang } else { 4594fcfb126dSJiong Wang info.jited_prog_insns = 0; 4595fcfb126dSJiong Wang } 4596675fc275SJakub Kicinski } 4597675fc275SJakub Kicinski 4598dbecd738SSandipan Das ulen = info.nr_jited_ksyms; 4599ff1889fcSSong Liu info.nr_jited_ksyms = prog->aux->func_cnt ? : 1; 46007a5725ddSSong Liu if (ulen) { 460163960260SKees Cook if (bpf_dump_raw_ok(file->f_cred)) { 4602ff1889fcSSong Liu unsigned long ksym_addr; 4603dbecd738SSandipan Das u64 __user *user_ksyms; 4604dbecd738SSandipan Das u32 i; 4605dbecd738SSandipan Das 4606dbecd738SSandipan Das /* copy the address of the kernel symbol 4607dbecd738SSandipan Das * corresponding to each function 4608dbecd738SSandipan Das */ 4609dbecd738SSandipan Das ulen = min_t(u32, info.nr_jited_ksyms, ulen); 4610dbecd738SSandipan Das user_ksyms = u64_to_user_ptr(info.jited_ksyms); 4611ff1889fcSSong Liu if (prog->aux->func_cnt) { 4612dbecd738SSandipan Das for (i = 0; i < ulen; i++) { 4613ff1889fcSSong Liu ksym_addr = (unsigned long) 4614ff1889fcSSong Liu prog->aux->func[i]->bpf_func; 4615ff1889fcSSong Liu if (put_user((u64) ksym_addr, 4616ff1889fcSSong Liu &user_ksyms[i])) 4617ff1889fcSSong Liu return -EFAULT; 4618ff1889fcSSong Liu } 4619ff1889fcSSong Liu } else { 4620ff1889fcSSong Liu ksym_addr = (unsigned long) prog->bpf_func; 4621ff1889fcSSong Liu if (put_user((u64) ksym_addr, &user_ksyms[0])) 4622dbecd738SSandipan Das return -EFAULT; 4623dbecd738SSandipan Das } 4624dbecd738SSandipan Das } else { 4625dbecd738SSandipan Das info.jited_ksyms = 0; 4626dbecd738SSandipan Das } 4627dbecd738SSandipan Das } 4628dbecd738SSandipan Das 4629815581c1SSandipan Das ulen = info.nr_jited_func_lens; 4630ff1889fcSSong Liu info.nr_jited_func_lens = prog->aux->func_cnt ? : 1; 46317a5725ddSSong Liu if (ulen) { 463263960260SKees Cook if (bpf_dump_raw_ok(file->f_cred)) { 4633815581c1SSandipan Das u32 __user *user_lens; 4634815581c1SSandipan Das u32 func_len, i; 4635815581c1SSandipan Das 4636815581c1SSandipan Das /* copy the JITed image lengths for each function */ 4637815581c1SSandipan Das ulen = min_t(u32, info.nr_jited_func_lens, ulen); 4638815581c1SSandipan Das user_lens = u64_to_user_ptr(info.jited_func_lens); 4639ff1889fcSSong Liu if (prog->aux->func_cnt) { 4640815581c1SSandipan Das for (i = 0; i < ulen; i++) { 4641ff1889fcSSong Liu func_len = 4642ff1889fcSSong Liu prog->aux->func[i]->jited_len; 4643815581c1SSandipan Das if (put_user(func_len, &user_lens[i])) 4644815581c1SSandipan Das return -EFAULT; 4645815581c1SSandipan Das } 4646815581c1SSandipan Das } else { 4647ff1889fcSSong Liu func_len = prog->jited_len; 4648ff1889fcSSong Liu if (put_user(func_len, &user_lens[0])) 4649ff1889fcSSong Liu return -EFAULT; 4650ff1889fcSSong Liu } 4651ff1889fcSSong Liu } else { 4652815581c1SSandipan Das info.jited_func_lens = 0; 4653815581c1SSandipan Das } 4654815581c1SSandipan Das } 4655815581c1SSandipan Das 46567337224fSMartin KaFai Lau if (prog->aux->btf) 465722dc4a0fSAndrii Nakryiko info.btf_id = btf_obj_id(prog->aux->btf); 4658b79c9fc9SStanislav Fomichev info.attach_btf_id = prog->aux->attach_btf_id; 46596644aabbSStanislav Fomichev if (attach_btf) 46606644aabbSStanislav Fomichev info.attach_btf_obj_id = btf_obj_id(attach_btf); 4661838e9690SYonghong Song 466211d8b82dSYonghong Song ulen = info.nr_func_info; 466311d8b82dSYonghong Song info.nr_func_info = prog->aux->func_info_cnt; 466411d8b82dSYonghong Song if (info.nr_func_info && ulen) { 4665838e9690SYonghong Song char __user *user_finfo; 4666838e9690SYonghong Song 4667838e9690SYonghong Song user_finfo = u64_to_user_ptr(info.func_info); 466811d8b82dSYonghong Song ulen = min_t(u32, info.nr_func_info, ulen); 4669ba64e7d8SYonghong Song if (copy_to_user(user_finfo, prog->aux->func_info, 46707337224fSMartin KaFai Lau info.func_info_rec_size * ulen)) 4671838e9690SYonghong Song return -EFAULT; 4672838e9690SYonghong Song } 4673838e9690SYonghong Song 467411d8b82dSYonghong Song ulen = info.nr_line_info; 467511d8b82dSYonghong Song info.nr_line_info = prog->aux->nr_linfo; 467611d8b82dSYonghong Song if (info.nr_line_info && ulen) { 4677c454a46bSMartin KaFai Lau __u8 __user *user_linfo; 4678c454a46bSMartin KaFai Lau 4679c454a46bSMartin KaFai Lau user_linfo = u64_to_user_ptr(info.line_info); 468011d8b82dSYonghong Song ulen = min_t(u32, info.nr_line_info, ulen); 4681c454a46bSMartin KaFai Lau if (copy_to_user(user_linfo, prog->aux->linfo, 4682c454a46bSMartin KaFai Lau info.line_info_rec_size * ulen)) 4683c454a46bSMartin KaFai Lau return -EFAULT; 4684c454a46bSMartin KaFai Lau } 4685c454a46bSMartin KaFai Lau 468611d8b82dSYonghong Song ulen = info.nr_jited_line_info; 4687c454a46bSMartin KaFai Lau if (prog->aux->jited_linfo) 468811d8b82dSYonghong Song info.nr_jited_line_info = prog->aux->nr_linfo; 4689c454a46bSMartin KaFai Lau else 469011d8b82dSYonghong Song info.nr_jited_line_info = 0; 469111d8b82dSYonghong Song if (info.nr_jited_line_info && ulen) { 469263960260SKees Cook if (bpf_dump_raw_ok(file->f_cred)) { 46932cd00852SPu Lehui unsigned long line_addr; 4694c454a46bSMartin KaFai Lau __u64 __user *user_linfo; 4695c454a46bSMartin KaFai Lau u32 i; 4696c454a46bSMartin KaFai Lau 4697c454a46bSMartin KaFai Lau user_linfo = u64_to_user_ptr(info.jited_line_info); 469811d8b82dSYonghong Song ulen = min_t(u32, info.nr_jited_line_info, ulen); 4699c454a46bSMartin KaFai Lau for (i = 0; i < ulen; i++) { 47002cd00852SPu Lehui line_addr = (unsigned long)prog->aux->jited_linfo[i]; 47012cd00852SPu Lehui if (put_user((__u64)line_addr, &user_linfo[i])) 4702c454a46bSMartin KaFai Lau return -EFAULT; 4703c454a46bSMartin KaFai Lau } 4704c454a46bSMartin KaFai Lau } else { 4705c454a46bSMartin KaFai Lau info.jited_line_info = 0; 4706c454a46bSMartin KaFai Lau } 4707c454a46bSMartin KaFai Lau } 4708c454a46bSMartin KaFai Lau 4709c872bdb3SSong Liu ulen = info.nr_prog_tags; 4710c872bdb3SSong Liu info.nr_prog_tags = prog->aux->func_cnt ? : 1; 4711c872bdb3SSong Liu if (ulen) { 4712c872bdb3SSong Liu __u8 __user (*user_prog_tags)[BPF_TAG_SIZE]; 4713c872bdb3SSong Liu u32 i; 4714c872bdb3SSong Liu 4715c872bdb3SSong Liu user_prog_tags = u64_to_user_ptr(info.prog_tags); 4716c872bdb3SSong Liu ulen = min_t(u32, info.nr_prog_tags, ulen); 4717c872bdb3SSong Liu if (prog->aux->func_cnt) { 4718c872bdb3SSong Liu for (i = 0; i < ulen; i++) { 4719c872bdb3SSong Liu if (copy_to_user(user_prog_tags[i], 4720c872bdb3SSong Liu prog->aux->func[i]->tag, 4721c872bdb3SSong Liu BPF_TAG_SIZE)) 4722c872bdb3SSong Liu return -EFAULT; 4723c872bdb3SSong Liu } 4724c872bdb3SSong Liu } else { 4725c872bdb3SSong Liu if (copy_to_user(user_prog_tags[0], 4726c872bdb3SSong Liu prog->tag, BPF_TAG_SIZE)) 4727c872bdb3SSong Liu return -EFAULT; 4728c872bdb3SSong Liu } 4729c872bdb3SSong Liu } 4730c872bdb3SSong Liu 47311e270976SMartin KaFai Lau done: 47321e270976SMartin KaFai Lau if (copy_to_user(uinfo, &info, info_len) || 47331e270976SMartin KaFai Lau put_user(info_len, &uattr->info.info_len)) 47341e270976SMartin KaFai Lau return -EFAULT; 47351e270976SMartin KaFai Lau 47361e270976SMartin KaFai Lau return 0; 47371e270976SMartin KaFai Lau } 47381e270976SMartin KaFai Lau 473963960260SKees Cook static int bpf_map_get_info_by_fd(struct file *file, 474063960260SKees Cook struct bpf_map *map, 47411e270976SMartin KaFai Lau const union bpf_attr *attr, 47421e270976SMartin KaFai Lau union bpf_attr __user *uattr) 47431e270976SMartin KaFai Lau { 47441e270976SMartin KaFai Lau struct bpf_map_info __user *uinfo = u64_to_user_ptr(attr->info.info); 47455c6f2588SGreg Kroah-Hartman struct bpf_map_info info; 47461e270976SMartin KaFai Lau u32 info_len = attr->info.info_len; 47471e270976SMartin KaFai Lau int err; 47481e270976SMartin KaFai Lau 4749af2ac3e1SAlexei Starovoitov err = bpf_check_uarg_tail_zero(USER_BPFPTR(uinfo), sizeof(info), info_len); 47501e270976SMartin KaFai Lau if (err) 47511e270976SMartin KaFai Lau return err; 47521e270976SMartin KaFai Lau info_len = min_t(u32, sizeof(info), info_len); 47531e270976SMartin KaFai Lau 47545c6f2588SGreg Kroah-Hartman memset(&info, 0, sizeof(info)); 47551e270976SMartin KaFai Lau info.type = map->map_type; 47561e270976SMartin KaFai Lau info.id = map->id; 47571e270976SMartin KaFai Lau info.key_size = map->key_size; 47581e270976SMartin KaFai Lau info.value_size = map->value_size; 47591e270976SMartin KaFai Lau info.max_entries = map->max_entries; 47601e270976SMartin KaFai Lau info.map_flags = map->map_flags; 47619330986cSJoanne Koong info.map_extra = map->map_extra; 4762ad5b177bSMartin KaFai Lau memcpy(info.name, map->name, sizeof(map->name)); 47631e270976SMartin KaFai Lau 476478958fcaSMartin KaFai Lau if (map->btf) { 476522dc4a0fSAndrii Nakryiko info.btf_id = btf_obj_id(map->btf); 47669b2cf328SMartin KaFai Lau info.btf_key_type_id = map->btf_key_type_id; 47679b2cf328SMartin KaFai Lau info.btf_value_type_id = map->btf_value_type_id; 476878958fcaSMartin KaFai Lau } 476985d33df3SMartin KaFai Lau info.btf_vmlinux_value_type_id = map->btf_vmlinux_value_type_id; 47701338b933SKui-Feng Lee if (map->map_type == BPF_MAP_TYPE_STRUCT_OPS) 47711338b933SKui-Feng Lee bpf_map_struct_ops_info_fill(&info, map); 477278958fcaSMartin KaFai Lau 47739d03ebc7SStanislav Fomichev if (bpf_map_is_offloaded(map)) { 477452775b33SJakub Kicinski err = bpf_map_offload_info_fill(&info, map); 477552775b33SJakub Kicinski if (err) 477652775b33SJakub Kicinski return err; 477752775b33SJakub Kicinski } 477852775b33SJakub Kicinski 47791e270976SMartin KaFai Lau if (copy_to_user(uinfo, &info, info_len) || 47801e270976SMartin KaFai Lau put_user(info_len, &uattr->info.info_len)) 47811e270976SMartin KaFai Lau return -EFAULT; 47821e270976SMartin KaFai Lau 47831e270976SMartin KaFai Lau return 0; 47841e270976SMartin KaFai Lau } 47851e270976SMartin KaFai Lau 478663960260SKees Cook static int bpf_btf_get_info_by_fd(struct file *file, 478763960260SKees Cook struct btf *btf, 478862dab84cSMartin KaFai Lau const union bpf_attr *attr, 478962dab84cSMartin KaFai Lau union bpf_attr __user *uattr) 479062dab84cSMartin KaFai Lau { 479162dab84cSMartin KaFai Lau struct bpf_btf_info __user *uinfo = u64_to_user_ptr(attr->info.info); 479262dab84cSMartin KaFai Lau u32 info_len = attr->info.info_len; 479362dab84cSMartin KaFai Lau int err; 479462dab84cSMartin KaFai Lau 4795af2ac3e1SAlexei Starovoitov err = bpf_check_uarg_tail_zero(USER_BPFPTR(uinfo), sizeof(*uinfo), info_len); 479662dab84cSMartin KaFai Lau if (err) 479762dab84cSMartin KaFai Lau return err; 479862dab84cSMartin KaFai Lau 479962dab84cSMartin KaFai Lau return btf_get_info_by_fd(btf, attr, uattr); 480062dab84cSMartin KaFai Lau } 480162dab84cSMartin KaFai Lau 480263960260SKees Cook static int bpf_link_get_info_by_fd(struct file *file, 480363960260SKees Cook struct bpf_link *link, 4804f2e10bffSAndrii Nakryiko const union bpf_attr *attr, 4805f2e10bffSAndrii Nakryiko union bpf_attr __user *uattr) 4806f2e10bffSAndrii Nakryiko { 4807f2e10bffSAndrii Nakryiko struct bpf_link_info __user *uinfo = u64_to_user_ptr(attr->info.info); 4808f2e10bffSAndrii Nakryiko struct bpf_link_info info; 4809f2e10bffSAndrii Nakryiko u32 info_len = attr->info.info_len; 4810f2e10bffSAndrii Nakryiko int err; 4811f2e10bffSAndrii Nakryiko 4812af2ac3e1SAlexei Starovoitov err = bpf_check_uarg_tail_zero(USER_BPFPTR(uinfo), sizeof(info), info_len); 4813f2e10bffSAndrii Nakryiko if (err) 4814f2e10bffSAndrii Nakryiko return err; 4815f2e10bffSAndrii Nakryiko info_len = min_t(u32, sizeof(info), info_len); 4816f2e10bffSAndrii Nakryiko 4817f2e10bffSAndrii Nakryiko memset(&info, 0, sizeof(info)); 4818f2e10bffSAndrii Nakryiko if (copy_from_user(&info, uinfo, info_len)) 4819f2e10bffSAndrii Nakryiko return -EFAULT; 4820f2e10bffSAndrii Nakryiko 4821f2e10bffSAndrii Nakryiko info.type = link->type; 4822f2e10bffSAndrii Nakryiko info.id = link->id; 482368b04864SKui-Feng Lee if (link->prog) 4824f2e10bffSAndrii Nakryiko info.prog_id = link->prog->aux->id; 4825f2e10bffSAndrii Nakryiko 4826f2e10bffSAndrii Nakryiko if (link->ops->fill_link_info) { 4827f2e10bffSAndrii Nakryiko err = link->ops->fill_link_info(link, &info); 4828f2e10bffSAndrii Nakryiko if (err) 4829f2e10bffSAndrii Nakryiko return err; 4830f2e10bffSAndrii Nakryiko } 4831f2e10bffSAndrii Nakryiko 4832f2e10bffSAndrii Nakryiko if (copy_to_user(uinfo, &info, info_len) || 4833f2e10bffSAndrii Nakryiko put_user(info_len, &uattr->info.info_len)) 4834f2e10bffSAndrii Nakryiko return -EFAULT; 4835f2e10bffSAndrii Nakryiko 4836f2e10bffSAndrii Nakryiko return 0; 4837f2e10bffSAndrii Nakryiko } 4838f2e10bffSAndrii Nakryiko 4839f2e10bffSAndrii Nakryiko 48401e270976SMartin KaFai Lau #define BPF_OBJ_GET_INFO_BY_FD_LAST_FIELD info.info 48411e270976SMartin KaFai Lau 48421e270976SMartin KaFai Lau static int bpf_obj_get_info_by_fd(const union bpf_attr *attr, 48431e270976SMartin KaFai Lau union bpf_attr __user *uattr) 48441e270976SMartin KaFai Lau { 48451e270976SMartin KaFai Lau int ufd = attr->info.bpf_fd; 48461e270976SMartin KaFai Lau struct fd f; 48471e270976SMartin KaFai Lau int err; 48481e270976SMartin KaFai Lau 48491e270976SMartin KaFai Lau if (CHECK_ATTR(BPF_OBJ_GET_INFO_BY_FD)) 48501e270976SMartin KaFai Lau return -EINVAL; 48511e270976SMartin KaFai Lau 48521e270976SMartin KaFai Lau f = fdget(ufd); 48531e270976SMartin KaFai Lau if (!f.file) 48541e270976SMartin KaFai Lau return -EBADFD; 48551e270976SMartin KaFai Lau 48561e270976SMartin KaFai Lau if (f.file->f_op == &bpf_prog_fops) 485763960260SKees Cook err = bpf_prog_get_info_by_fd(f.file, f.file->private_data, attr, 48581e270976SMartin KaFai Lau uattr); 48591e270976SMartin KaFai Lau else if (f.file->f_op == &bpf_map_fops) 486063960260SKees Cook err = bpf_map_get_info_by_fd(f.file, f.file->private_data, attr, 48611e270976SMartin KaFai Lau uattr); 486260197cfbSMartin KaFai Lau else if (f.file->f_op == &btf_fops) 486363960260SKees Cook err = bpf_btf_get_info_by_fd(f.file, f.file->private_data, attr, uattr); 4864f2e10bffSAndrii Nakryiko else if (f.file->f_op == &bpf_link_fops) 486563960260SKees Cook err = bpf_link_get_info_by_fd(f.file, f.file->private_data, 4866f2e10bffSAndrii Nakryiko attr, uattr); 48671e270976SMartin KaFai Lau else 48681e270976SMartin KaFai Lau err = -EINVAL; 48691e270976SMartin KaFai Lau 48701e270976SMartin KaFai Lau fdput(f); 48711e270976SMartin KaFai Lau return err; 48721e270976SMartin KaFai Lau } 48731e270976SMartin KaFai Lau 48749ea7c4bfSAndrii Nakryiko #define BPF_BTF_LOAD_LAST_FIELD btf_token_fd 4875f56a653cSMartin KaFai Lau 487647a71c1fSAndrii Nakryiko static int bpf_btf_load(const union bpf_attr *attr, bpfptr_t uattr, __u32 uattr_size) 4877f56a653cSMartin KaFai Lau { 48789ea7c4bfSAndrii Nakryiko struct bpf_token *token = NULL; 48799ea7c4bfSAndrii Nakryiko 4880f56a653cSMartin KaFai Lau if (CHECK_ATTR(BPF_BTF_LOAD)) 4881f56a653cSMartin KaFai Lau return -EINVAL; 4882f56a653cSMartin KaFai Lau 48839ea7c4bfSAndrii Nakryiko if (attr->btf_flags & ~BPF_F_TOKEN_FD) 48849ea7c4bfSAndrii Nakryiko return -EINVAL; 48859ea7c4bfSAndrii Nakryiko 48869ea7c4bfSAndrii Nakryiko if (attr->btf_flags & BPF_F_TOKEN_FD) { 48879ea7c4bfSAndrii Nakryiko token = bpf_token_get_from_fd(attr->btf_token_fd); 48889ea7c4bfSAndrii Nakryiko if (IS_ERR(token)) 48899ea7c4bfSAndrii Nakryiko return PTR_ERR(token); 48909ea7c4bfSAndrii Nakryiko if (!bpf_token_allow_cmd(token, BPF_BTF_LOAD)) { 48919ea7c4bfSAndrii Nakryiko bpf_token_put(token); 48929ea7c4bfSAndrii Nakryiko token = NULL; 48939ea7c4bfSAndrii Nakryiko } 48949ea7c4bfSAndrii Nakryiko } 48959ea7c4bfSAndrii Nakryiko 48969ea7c4bfSAndrii Nakryiko if (!bpf_token_capable(token, CAP_BPF)) { 48979ea7c4bfSAndrii Nakryiko bpf_token_put(token); 4898f56a653cSMartin KaFai Lau return -EPERM; 48999ea7c4bfSAndrii Nakryiko } 49009ea7c4bfSAndrii Nakryiko 49019ea7c4bfSAndrii Nakryiko bpf_token_put(token); 4902f56a653cSMartin KaFai Lau 490347a71c1fSAndrii Nakryiko return btf_new_fd(attr, uattr, uattr_size); 4904f56a653cSMartin KaFai Lau } 4905f56a653cSMartin KaFai Lau 490678958fcaSMartin KaFai Lau #define BPF_BTF_GET_FD_BY_ID_LAST_FIELD btf_id 490778958fcaSMartin KaFai Lau 490878958fcaSMartin KaFai Lau static int bpf_btf_get_fd_by_id(const union bpf_attr *attr) 490978958fcaSMartin KaFai Lau { 491078958fcaSMartin KaFai Lau if (CHECK_ATTR(BPF_BTF_GET_FD_BY_ID)) 491178958fcaSMartin KaFai Lau return -EINVAL; 491278958fcaSMartin KaFai Lau 491378958fcaSMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) 491478958fcaSMartin KaFai Lau return -EPERM; 491578958fcaSMartin KaFai Lau 491678958fcaSMartin KaFai Lau return btf_get_fd_by_id(attr->btf_id); 491778958fcaSMartin KaFai Lau } 491878958fcaSMartin KaFai Lau 491941bdc4b4SYonghong Song static int bpf_task_fd_query_copy(const union bpf_attr *attr, 492041bdc4b4SYonghong Song union bpf_attr __user *uattr, 492141bdc4b4SYonghong Song u32 prog_id, u32 fd_type, 492241bdc4b4SYonghong Song const char *buf, u64 probe_offset, 492341bdc4b4SYonghong Song u64 probe_addr) 492441bdc4b4SYonghong Song { 492541bdc4b4SYonghong Song char __user *ubuf = u64_to_user_ptr(attr->task_fd_query.buf); 492641bdc4b4SYonghong Song u32 len = buf ? strlen(buf) : 0, input_len; 492741bdc4b4SYonghong Song int err = 0; 492841bdc4b4SYonghong Song 492941bdc4b4SYonghong Song if (put_user(len, &uattr->task_fd_query.buf_len)) 493041bdc4b4SYonghong Song return -EFAULT; 493141bdc4b4SYonghong Song input_len = attr->task_fd_query.buf_len; 493241bdc4b4SYonghong Song if (input_len && ubuf) { 493341bdc4b4SYonghong Song if (!len) { 493441bdc4b4SYonghong Song /* nothing to copy, just make ubuf NULL terminated */ 493541bdc4b4SYonghong Song char zero = '\0'; 493641bdc4b4SYonghong Song 493741bdc4b4SYonghong Song if (put_user(zero, ubuf)) 493841bdc4b4SYonghong Song return -EFAULT; 493941bdc4b4SYonghong Song } else if (input_len >= len + 1) { 494041bdc4b4SYonghong Song /* ubuf can hold the string with NULL terminator */ 494141bdc4b4SYonghong Song if (copy_to_user(ubuf, buf, len + 1)) 494241bdc4b4SYonghong Song return -EFAULT; 494341bdc4b4SYonghong Song } else { 494441bdc4b4SYonghong Song /* ubuf cannot hold the string with NULL terminator, 494541bdc4b4SYonghong Song * do a partial copy with NULL terminator. 494641bdc4b4SYonghong Song */ 494741bdc4b4SYonghong Song char zero = '\0'; 494841bdc4b4SYonghong Song 494941bdc4b4SYonghong Song err = -ENOSPC; 495041bdc4b4SYonghong Song if (copy_to_user(ubuf, buf, input_len - 1)) 495141bdc4b4SYonghong Song return -EFAULT; 495241bdc4b4SYonghong Song if (put_user(zero, ubuf + input_len - 1)) 495341bdc4b4SYonghong Song return -EFAULT; 495441bdc4b4SYonghong Song } 495541bdc4b4SYonghong Song } 495641bdc4b4SYonghong Song 495741bdc4b4SYonghong Song if (put_user(prog_id, &uattr->task_fd_query.prog_id) || 495841bdc4b4SYonghong Song put_user(fd_type, &uattr->task_fd_query.fd_type) || 495941bdc4b4SYonghong Song put_user(probe_offset, &uattr->task_fd_query.probe_offset) || 496041bdc4b4SYonghong Song put_user(probe_addr, &uattr->task_fd_query.probe_addr)) 496141bdc4b4SYonghong Song return -EFAULT; 496241bdc4b4SYonghong Song 496341bdc4b4SYonghong Song return err; 496441bdc4b4SYonghong Song } 496541bdc4b4SYonghong Song 496641bdc4b4SYonghong Song #define BPF_TASK_FD_QUERY_LAST_FIELD task_fd_query.probe_addr 496741bdc4b4SYonghong Song 496841bdc4b4SYonghong Song static int bpf_task_fd_query(const union bpf_attr *attr, 496941bdc4b4SYonghong Song union bpf_attr __user *uattr) 497041bdc4b4SYonghong Song { 497141bdc4b4SYonghong Song pid_t pid = attr->task_fd_query.pid; 497241bdc4b4SYonghong Song u32 fd = attr->task_fd_query.fd; 497341bdc4b4SYonghong Song const struct perf_event *event; 497441bdc4b4SYonghong Song struct task_struct *task; 497541bdc4b4SYonghong Song struct file *file; 497641bdc4b4SYonghong Song int err; 497741bdc4b4SYonghong Song 497841bdc4b4SYonghong Song if (CHECK_ATTR(BPF_TASK_FD_QUERY)) 497941bdc4b4SYonghong Song return -EINVAL; 498041bdc4b4SYonghong Song 498141bdc4b4SYonghong Song if (!capable(CAP_SYS_ADMIN)) 498241bdc4b4SYonghong Song return -EPERM; 498341bdc4b4SYonghong Song 498441bdc4b4SYonghong Song if (attr->task_fd_query.flags != 0) 498541bdc4b4SYonghong Song return -EINVAL; 498641bdc4b4SYonghong Song 498783c10cc3SLee Jones rcu_read_lock(); 498841bdc4b4SYonghong Song task = get_pid_task(find_vpid(pid), PIDTYPE_PID); 498983c10cc3SLee Jones rcu_read_unlock(); 499041bdc4b4SYonghong Song if (!task) 499141bdc4b4SYonghong Song return -ENOENT; 499241bdc4b4SYonghong Song 499341bdc4b4SYonghong Song err = 0; 4994b48845afSEric W. Biederman file = fget_task(task, fd); 4995b48845afSEric W. Biederman put_task_struct(task); 499641bdc4b4SYonghong Song if (!file) 4997b48845afSEric W. Biederman return -EBADF; 499841bdc4b4SYonghong Song 499970ed506cSAndrii Nakryiko if (file->f_op == &bpf_link_fops) { 500070ed506cSAndrii Nakryiko struct bpf_link *link = file->private_data; 500170ed506cSAndrii Nakryiko 5002a3b80e10SAndrii Nakryiko if (link->ops == &bpf_raw_tp_link_lops) { 500370ed506cSAndrii Nakryiko struct bpf_raw_tp_link *raw_tp = 500470ed506cSAndrii Nakryiko container_of(link, struct bpf_raw_tp_link, link); 500541bdc4b4SYonghong Song struct bpf_raw_event_map *btp = raw_tp->btp; 500641bdc4b4SYonghong Song 500741bdc4b4SYonghong Song err = bpf_task_fd_query_copy(attr, uattr, 500870ed506cSAndrii Nakryiko raw_tp->link.prog->aux->id, 500941bdc4b4SYonghong Song BPF_FD_TYPE_RAW_TRACEPOINT, 501041bdc4b4SYonghong Song btp->tp->name, 0, 0); 501141bdc4b4SYonghong Song goto put_file; 501241bdc4b4SYonghong Song } 501370ed506cSAndrii Nakryiko goto out_not_supp; 501470ed506cSAndrii Nakryiko } 501541bdc4b4SYonghong Song 501641bdc4b4SYonghong Song event = perf_get_event(file); 501741bdc4b4SYonghong Song if (!IS_ERR(event)) { 501841bdc4b4SYonghong Song u64 probe_offset, probe_addr; 501941bdc4b4SYonghong Song u32 prog_id, fd_type; 502041bdc4b4SYonghong Song const char *buf; 502141bdc4b4SYonghong Song 502241bdc4b4SYonghong Song err = bpf_get_perf_event_info(event, &prog_id, &fd_type, 502341bdc4b4SYonghong Song &buf, &probe_offset, 50243acf8aceSJiri Olsa &probe_addr, NULL); 502541bdc4b4SYonghong Song if (!err) 502641bdc4b4SYonghong Song err = bpf_task_fd_query_copy(attr, uattr, prog_id, 502741bdc4b4SYonghong Song fd_type, buf, 502841bdc4b4SYonghong Song probe_offset, 502941bdc4b4SYonghong Song probe_addr); 503041bdc4b4SYonghong Song goto put_file; 503141bdc4b4SYonghong Song } 503241bdc4b4SYonghong Song 503370ed506cSAndrii Nakryiko out_not_supp: 503441bdc4b4SYonghong Song err = -ENOTSUPP; 503541bdc4b4SYonghong Song put_file: 503641bdc4b4SYonghong Song fput(file); 503741bdc4b4SYonghong Song return err; 503841bdc4b4SYonghong Song } 503941bdc4b4SYonghong Song 5040cb4d03abSBrian Vazquez #define BPF_MAP_BATCH_LAST_FIELD batch.flags 5041cb4d03abSBrian Vazquez 50423af43ba4SHou Tao #define BPF_DO_BATCH(fn, ...) \ 5043cb4d03abSBrian Vazquez do { \ 5044cb4d03abSBrian Vazquez if (!fn) { \ 5045cb4d03abSBrian Vazquez err = -ENOTSUPP; \ 5046cb4d03abSBrian Vazquez goto err_put; \ 5047cb4d03abSBrian Vazquez } \ 50483af43ba4SHou Tao err = fn(__VA_ARGS__); \ 5049cb4d03abSBrian Vazquez } while (0) 5050cb4d03abSBrian Vazquez 5051cb4d03abSBrian Vazquez static int bpf_map_do_batch(const union bpf_attr *attr, 5052cb4d03abSBrian Vazquez union bpf_attr __user *uattr, 5053cb4d03abSBrian Vazquez int cmd) 5054cb4d03abSBrian Vazquez { 5055353050beSDaniel Borkmann bool has_read = cmd == BPF_MAP_LOOKUP_BATCH || 5056353050beSDaniel Borkmann cmd == BPF_MAP_LOOKUP_AND_DELETE_BATCH; 5057353050beSDaniel Borkmann bool has_write = cmd != BPF_MAP_LOOKUP_BATCH; 5058cb4d03abSBrian Vazquez struct bpf_map *map; 5059cb4d03abSBrian Vazquez int err, ufd; 5060cb4d03abSBrian Vazquez struct fd f; 5061cb4d03abSBrian Vazquez 5062cb4d03abSBrian Vazquez if (CHECK_ATTR(BPF_MAP_BATCH)) 5063cb4d03abSBrian Vazquez return -EINVAL; 5064cb4d03abSBrian Vazquez 5065cb4d03abSBrian Vazquez ufd = attr->batch.map_fd; 5066cb4d03abSBrian Vazquez f = fdget(ufd); 5067cb4d03abSBrian Vazquez map = __bpf_map_get(f); 5068cb4d03abSBrian Vazquez if (IS_ERR(map)) 5069cb4d03abSBrian Vazquez return PTR_ERR(map); 5070353050beSDaniel Borkmann if (has_write) 5071353050beSDaniel Borkmann bpf_map_write_active_inc(map); 5072353050beSDaniel Borkmann if (has_read && !(map_get_sys_perms(map, f) & FMODE_CAN_READ)) { 5073cb4d03abSBrian Vazquez err = -EPERM; 5074cb4d03abSBrian Vazquez goto err_put; 5075cb4d03abSBrian Vazquez } 5076353050beSDaniel Borkmann if (has_write && !(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) { 5077cb4d03abSBrian Vazquez err = -EPERM; 5078cb4d03abSBrian Vazquez goto err_put; 5079cb4d03abSBrian Vazquez } 5080cb4d03abSBrian Vazquez 5081cb4d03abSBrian Vazquez if (cmd == BPF_MAP_LOOKUP_BATCH) 50823af43ba4SHou Tao BPF_DO_BATCH(map->ops->map_lookup_batch, map, attr, uattr); 508305799638SYonghong Song else if (cmd == BPF_MAP_LOOKUP_AND_DELETE_BATCH) 50843af43ba4SHou Tao BPF_DO_BATCH(map->ops->map_lookup_and_delete_batch, map, attr, uattr); 5085aa2e93b8SBrian Vazquez else if (cmd == BPF_MAP_UPDATE_BATCH) 50863af43ba4SHou Tao BPF_DO_BATCH(map->ops->map_update_batch, map, f.file, attr, uattr); 5087aa2e93b8SBrian Vazquez else 50883af43ba4SHou Tao BPF_DO_BATCH(map->ops->map_delete_batch, map, attr, uattr); 5089cb4d03abSBrian Vazquez err_put: 509001277258SHou Tao if (has_write) { 509101277258SHou Tao maybe_wait_bpf_programs(map); 5092353050beSDaniel Borkmann bpf_map_write_active_dec(map); 509301277258SHou Tao } 5094cb4d03abSBrian Vazquez fdput(f); 5095cb4d03abSBrian Vazquez return err; 5096cb4d03abSBrian Vazquez } 5097cb4d03abSBrian Vazquez 5098b733eeadSJiri Olsa #define BPF_LINK_CREATE_LAST_FIELD link_create.uprobe_multi.pid 5099af2ac3e1SAlexei Starovoitov static int link_create(union bpf_attr *attr, bpfptr_t uattr) 5100af6eea57SAndrii Nakryiko { 5101af6eea57SAndrii Nakryiko struct bpf_prog *prog; 5102af6eea57SAndrii Nakryiko int ret; 5103af6eea57SAndrii Nakryiko 5104af6eea57SAndrii Nakryiko if (CHECK_ATTR(BPF_LINK_CREATE)) 5105af6eea57SAndrii Nakryiko return -EINVAL; 5106af6eea57SAndrii Nakryiko 510768b04864SKui-Feng Lee if (attr->link_create.attach_type == BPF_STRUCT_OPS) 510868b04864SKui-Feng Lee return bpf_struct_ops_link_create(attr); 510968b04864SKui-Feng Lee 51104a1e7c0cSToke Høiland-Jørgensen prog = bpf_prog_get(attr->link_create.prog_fd); 5111af6eea57SAndrii Nakryiko if (IS_ERR(prog)) 5112af6eea57SAndrii Nakryiko return PTR_ERR(prog); 5113af6eea57SAndrii Nakryiko 5114af6eea57SAndrii Nakryiko ret = bpf_prog_attach_check_attach_type(prog, 5115af6eea57SAndrii Nakryiko attr->link_create.attach_type); 5116af6eea57SAndrii Nakryiko if (ret) 51174a1e7c0cSToke Høiland-Jørgensen goto out; 51184a1e7c0cSToke Høiland-Jørgensen 5119b89fbfbbSAndrii Nakryiko switch (prog->type) { 5120af6eea57SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SKB: 5121af6eea57SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SOCK: 5122af6eea57SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: 5123af6eea57SAndrii Nakryiko case BPF_PROG_TYPE_SOCK_OPS: 5124af6eea57SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_DEVICE: 5125af6eea57SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SYSCTL: 5126af6eea57SAndrii Nakryiko case BPF_PROG_TYPE_CGROUP_SOCKOPT: 5127af6eea57SAndrii Nakryiko ret = cgroup_bpf_link_attach(attr, prog); 5128af6eea57SAndrii Nakryiko break; 5129df86ca0dSAndrii Nakryiko case BPF_PROG_TYPE_EXT: 5130df86ca0dSAndrii Nakryiko ret = bpf_tracing_prog_attach(prog, 5131df86ca0dSAndrii Nakryiko attr->link_create.target_fd, 51322fcc8241SKui-Feng Lee attr->link_create.target_btf_id, 51332fcc8241SKui-Feng Lee attr->link_create.tracing.cookie); 5134df86ca0dSAndrii Nakryiko break; 5135df86ca0dSAndrii Nakryiko case BPF_PROG_TYPE_LSM: 5136de4e05caSYonghong Song case BPF_PROG_TYPE_TRACING: 5137df86ca0dSAndrii Nakryiko if (attr->link_create.attach_type != prog->expected_attach_type) { 5138df86ca0dSAndrii Nakryiko ret = -EINVAL; 5139df86ca0dSAndrii Nakryiko goto out; 5140df86ca0dSAndrii Nakryiko } 5141df86ca0dSAndrii Nakryiko if (prog->expected_attach_type == BPF_TRACE_RAW_TP) 5142df86ca0dSAndrii Nakryiko ret = bpf_raw_tp_link_attach(prog, NULL); 5143df86ca0dSAndrii Nakryiko else if (prog->expected_attach_type == BPF_TRACE_ITER) 5144df86ca0dSAndrii Nakryiko ret = bpf_iter_link_attach(attr, uattr, prog); 514569fd337aSStanislav Fomichev else if (prog->expected_attach_type == BPF_LSM_CGROUP) 514669fd337aSStanislav Fomichev ret = cgroup_bpf_link_attach(attr, prog); 5147df86ca0dSAndrii Nakryiko else 5148df86ca0dSAndrii Nakryiko ret = bpf_tracing_prog_attach(prog, 5149df86ca0dSAndrii Nakryiko attr->link_create.target_fd, 51502fcc8241SKui-Feng Lee attr->link_create.target_btf_id, 51512fcc8241SKui-Feng Lee attr->link_create.tracing.cookie); 5152de4e05caSYonghong Song break; 51537f045a49SJakub Sitnicki case BPF_PROG_TYPE_FLOW_DISSECTOR: 5154e9ddbb77SJakub Sitnicki case BPF_PROG_TYPE_SK_LOOKUP: 51557f045a49SJakub Sitnicki ret = netns_bpf_link_create(attr, prog); 51567f045a49SJakub Sitnicki break; 5157310ad797SAndrii Nakryiko #ifdef CONFIG_NET 5158aa8d3a71SAndrii Nakryiko case BPF_PROG_TYPE_XDP: 5159aa8d3a71SAndrii Nakryiko ret = bpf_xdp_link_attach(attr, prog); 5160aa8d3a71SAndrii Nakryiko break; 5161e420bed0SDaniel Borkmann case BPF_PROG_TYPE_SCHED_CLS: 516235dfaad7SDaniel Borkmann if (attr->link_create.attach_type == BPF_TCX_INGRESS || 516335dfaad7SDaniel Borkmann attr->link_create.attach_type == BPF_TCX_EGRESS) 5164e420bed0SDaniel Borkmann ret = tcx_link_attach(attr, prog); 516535dfaad7SDaniel Borkmann else 516635dfaad7SDaniel Borkmann ret = netkit_link_attach(attr, prog); 5167e420bed0SDaniel Borkmann break; 516884601d6eSFlorian Westphal case BPF_PROG_TYPE_NETFILTER: 516984601d6eSFlorian Westphal ret = bpf_nf_link_attach(attr, prog); 517084601d6eSFlorian Westphal break; 5171310ad797SAndrii Nakryiko #endif 5172b89fbfbbSAndrii Nakryiko case BPF_PROG_TYPE_PERF_EVENT: 5173b89fbfbbSAndrii Nakryiko case BPF_PROG_TYPE_TRACEPOINT: 5174b89fbfbbSAndrii Nakryiko ret = bpf_perf_link_attach(attr, prog); 5175b89fbfbbSAndrii Nakryiko break; 51760dcac272SJiri Olsa case BPF_PROG_TYPE_KPROBE: 51770dcac272SJiri Olsa if (attr->link_create.attach_type == BPF_PERF_EVENT) 51780dcac272SJiri Olsa ret = bpf_perf_link_attach(attr, prog); 517989ae89f5SJiri Olsa else if (attr->link_create.attach_type == BPF_TRACE_KPROBE_MULTI) 51800dcac272SJiri Olsa ret = bpf_kprobe_multi_link_attach(attr, prog); 518189ae89f5SJiri Olsa else if (attr->link_create.attach_type == BPF_TRACE_UPROBE_MULTI) 518289ae89f5SJiri Olsa ret = bpf_uprobe_multi_link_attach(attr, prog); 51830dcac272SJiri Olsa break; 5184af6eea57SAndrii Nakryiko default: 5185af6eea57SAndrii Nakryiko ret = -EINVAL; 5186af6eea57SAndrii Nakryiko } 5187af6eea57SAndrii Nakryiko 51884a1e7c0cSToke Høiland-Jørgensen out: 5189af6eea57SAndrii Nakryiko if (ret < 0) 5190af6eea57SAndrii Nakryiko bpf_prog_put(prog); 5191af6eea57SAndrii Nakryiko return ret; 5192af6eea57SAndrii Nakryiko } 5193af6eea57SAndrii Nakryiko 5194aef56f2eSKui-Feng Lee static int link_update_map(struct bpf_link *link, union bpf_attr *attr) 5195aef56f2eSKui-Feng Lee { 5196aef56f2eSKui-Feng Lee struct bpf_map *new_map, *old_map = NULL; 5197aef56f2eSKui-Feng Lee int ret; 5198aef56f2eSKui-Feng Lee 5199aef56f2eSKui-Feng Lee new_map = bpf_map_get(attr->link_update.new_map_fd); 5200aef56f2eSKui-Feng Lee if (IS_ERR(new_map)) 520155fbae05SMartin KaFai Lau return PTR_ERR(new_map); 5202aef56f2eSKui-Feng Lee 5203aef56f2eSKui-Feng Lee if (attr->link_update.flags & BPF_F_REPLACE) { 5204aef56f2eSKui-Feng Lee old_map = bpf_map_get(attr->link_update.old_map_fd); 5205aef56f2eSKui-Feng Lee if (IS_ERR(old_map)) { 520655fbae05SMartin KaFai Lau ret = PTR_ERR(old_map); 5207aef56f2eSKui-Feng Lee goto out_put; 5208aef56f2eSKui-Feng Lee } 5209aef56f2eSKui-Feng Lee } else if (attr->link_update.old_map_fd) { 5210aef56f2eSKui-Feng Lee ret = -EINVAL; 5211aef56f2eSKui-Feng Lee goto out_put; 5212aef56f2eSKui-Feng Lee } 5213aef56f2eSKui-Feng Lee 5214aef56f2eSKui-Feng Lee ret = link->ops->update_map(link, new_map, old_map); 5215aef56f2eSKui-Feng Lee 5216aef56f2eSKui-Feng Lee if (old_map) 5217aef56f2eSKui-Feng Lee bpf_map_put(old_map); 5218aef56f2eSKui-Feng Lee out_put: 5219aef56f2eSKui-Feng Lee bpf_map_put(new_map); 5220aef56f2eSKui-Feng Lee return ret; 5221aef56f2eSKui-Feng Lee } 5222aef56f2eSKui-Feng Lee 52230c991ebcSAndrii Nakryiko #define BPF_LINK_UPDATE_LAST_FIELD link_update.old_prog_fd 52240c991ebcSAndrii Nakryiko 52250c991ebcSAndrii Nakryiko static int link_update(union bpf_attr *attr) 52260c991ebcSAndrii Nakryiko { 52270c991ebcSAndrii Nakryiko struct bpf_prog *old_prog = NULL, *new_prog; 52280c991ebcSAndrii Nakryiko struct bpf_link *link; 52290c991ebcSAndrii Nakryiko u32 flags; 52300c991ebcSAndrii Nakryiko int ret; 52310c991ebcSAndrii Nakryiko 52320c991ebcSAndrii Nakryiko if (CHECK_ATTR(BPF_LINK_UPDATE)) 52330c991ebcSAndrii Nakryiko return -EINVAL; 52340c991ebcSAndrii Nakryiko 52350c991ebcSAndrii Nakryiko flags = attr->link_update.flags; 52360c991ebcSAndrii Nakryiko if (flags & ~BPF_F_REPLACE) 52370c991ebcSAndrii Nakryiko return -EINVAL; 52380c991ebcSAndrii Nakryiko 52390c991ebcSAndrii Nakryiko link = bpf_link_get_from_fd(attr->link_update.link_fd); 52400c991ebcSAndrii Nakryiko if (IS_ERR(link)) 52410c991ebcSAndrii Nakryiko return PTR_ERR(link); 52420c991ebcSAndrii Nakryiko 5243aef56f2eSKui-Feng Lee if (link->ops->update_map) { 5244aef56f2eSKui-Feng Lee ret = link_update_map(link, attr); 5245aef56f2eSKui-Feng Lee goto out_put_link; 5246aef56f2eSKui-Feng Lee } 5247aef56f2eSKui-Feng Lee 52480c991ebcSAndrii Nakryiko new_prog = bpf_prog_get(attr->link_update.new_prog_fd); 52494adb7a4aSAndrii Nakryiko if (IS_ERR(new_prog)) { 52504adb7a4aSAndrii Nakryiko ret = PTR_ERR(new_prog); 52514adb7a4aSAndrii Nakryiko goto out_put_link; 52524adb7a4aSAndrii Nakryiko } 52530c991ebcSAndrii Nakryiko 52540c991ebcSAndrii Nakryiko if (flags & BPF_F_REPLACE) { 52550c991ebcSAndrii Nakryiko old_prog = bpf_prog_get(attr->link_update.old_prog_fd); 52560c991ebcSAndrii Nakryiko if (IS_ERR(old_prog)) { 52570c991ebcSAndrii Nakryiko ret = PTR_ERR(old_prog); 52580c991ebcSAndrii Nakryiko old_prog = NULL; 52590c991ebcSAndrii Nakryiko goto out_put_progs; 52600c991ebcSAndrii Nakryiko } 52614adb7a4aSAndrii Nakryiko } else if (attr->link_update.old_prog_fd) { 52624adb7a4aSAndrii Nakryiko ret = -EINVAL; 52634adb7a4aSAndrii Nakryiko goto out_put_progs; 52640c991ebcSAndrii Nakryiko } 52650c991ebcSAndrii Nakryiko 5266f9d04127SAndrii Nakryiko if (link->ops->update_prog) 5267f9d04127SAndrii Nakryiko ret = link->ops->update_prog(link, new_prog, old_prog); 5268f9d04127SAndrii Nakryiko else 52690c991ebcSAndrii Nakryiko ret = -EINVAL; 52700c991ebcSAndrii Nakryiko 52710c991ebcSAndrii Nakryiko out_put_progs: 52720c991ebcSAndrii Nakryiko if (old_prog) 52730c991ebcSAndrii Nakryiko bpf_prog_put(old_prog); 52740c991ebcSAndrii Nakryiko if (ret) 52750c991ebcSAndrii Nakryiko bpf_prog_put(new_prog); 52764adb7a4aSAndrii Nakryiko out_put_link: 5277ab5d47bdSSebastian Andrzej Siewior bpf_link_put_direct(link); 52780c991ebcSAndrii Nakryiko return ret; 52790c991ebcSAndrii Nakryiko } 52800c991ebcSAndrii Nakryiko 528173b11c2aSAndrii Nakryiko #define BPF_LINK_DETACH_LAST_FIELD link_detach.link_fd 528273b11c2aSAndrii Nakryiko 528373b11c2aSAndrii Nakryiko static int link_detach(union bpf_attr *attr) 528473b11c2aSAndrii Nakryiko { 528573b11c2aSAndrii Nakryiko struct bpf_link *link; 528673b11c2aSAndrii Nakryiko int ret; 528773b11c2aSAndrii Nakryiko 528873b11c2aSAndrii Nakryiko if (CHECK_ATTR(BPF_LINK_DETACH)) 528973b11c2aSAndrii Nakryiko return -EINVAL; 529073b11c2aSAndrii Nakryiko 529173b11c2aSAndrii Nakryiko link = bpf_link_get_from_fd(attr->link_detach.link_fd); 529273b11c2aSAndrii Nakryiko if (IS_ERR(link)) 529373b11c2aSAndrii Nakryiko return PTR_ERR(link); 529473b11c2aSAndrii Nakryiko 529573b11c2aSAndrii Nakryiko if (link->ops->detach) 529673b11c2aSAndrii Nakryiko ret = link->ops->detach(link); 529773b11c2aSAndrii Nakryiko else 529873b11c2aSAndrii Nakryiko ret = -EOPNOTSUPP; 529973b11c2aSAndrii Nakryiko 5300ab5d47bdSSebastian Andrzej Siewior bpf_link_put_direct(link); 530173b11c2aSAndrii Nakryiko return ret; 530273b11c2aSAndrii Nakryiko } 530373b11c2aSAndrii Nakryiko 5304005142b8SAlexei Starovoitov static struct bpf_link *bpf_link_inc_not_zero(struct bpf_link *link) 53052d602c8cSAndrii Nakryiko { 5306005142b8SAlexei Starovoitov return atomic64_fetch_add_unless(&link->refcnt, 1, 0) ? link : ERR_PTR(-ENOENT); 5307005142b8SAlexei Starovoitov } 5308005142b8SAlexei Starovoitov 5309005142b8SAlexei Starovoitov struct bpf_link *bpf_link_by_id(u32 id) 5310005142b8SAlexei Starovoitov { 5311005142b8SAlexei Starovoitov struct bpf_link *link; 5312005142b8SAlexei Starovoitov 5313005142b8SAlexei Starovoitov if (!id) 5314005142b8SAlexei Starovoitov return ERR_PTR(-ENOENT); 5315005142b8SAlexei Starovoitov 5316005142b8SAlexei Starovoitov spin_lock_bh(&link_idr_lock); 5317005142b8SAlexei Starovoitov /* before link is "settled", ID is 0, pretend it doesn't exist yet */ 5318005142b8SAlexei Starovoitov link = idr_find(&link_idr, id); 5319005142b8SAlexei Starovoitov if (link) { 5320005142b8SAlexei Starovoitov if (link->id) 5321005142b8SAlexei Starovoitov link = bpf_link_inc_not_zero(link); 5322005142b8SAlexei Starovoitov else 5323005142b8SAlexei Starovoitov link = ERR_PTR(-EAGAIN); 5324005142b8SAlexei Starovoitov } else { 5325005142b8SAlexei Starovoitov link = ERR_PTR(-ENOENT); 5326005142b8SAlexei Starovoitov } 5327005142b8SAlexei Starovoitov spin_unlock_bh(&link_idr_lock); 5328005142b8SAlexei Starovoitov return link; 53292d602c8cSAndrii Nakryiko } 53302d602c8cSAndrii Nakryiko 53319f883612SDmitrii Dolgov struct bpf_link *bpf_link_get_curr_or_next(u32 *id) 53329f883612SDmitrii Dolgov { 53339f883612SDmitrii Dolgov struct bpf_link *link; 53349f883612SDmitrii Dolgov 53359f883612SDmitrii Dolgov spin_lock_bh(&link_idr_lock); 53369f883612SDmitrii Dolgov again: 53379f883612SDmitrii Dolgov link = idr_get_next(&link_idr, id); 53389f883612SDmitrii Dolgov if (link) { 53399f883612SDmitrii Dolgov link = bpf_link_inc_not_zero(link); 53409f883612SDmitrii Dolgov if (IS_ERR(link)) { 53419f883612SDmitrii Dolgov (*id)++; 53429f883612SDmitrii Dolgov goto again; 53439f883612SDmitrii Dolgov } 53449f883612SDmitrii Dolgov } 53459f883612SDmitrii Dolgov spin_unlock_bh(&link_idr_lock); 53469f883612SDmitrii Dolgov 53479f883612SDmitrii Dolgov return link; 53489f883612SDmitrii Dolgov } 53499f883612SDmitrii Dolgov 53502d602c8cSAndrii Nakryiko #define BPF_LINK_GET_FD_BY_ID_LAST_FIELD link_id 53512d602c8cSAndrii Nakryiko 53522d602c8cSAndrii Nakryiko static int bpf_link_get_fd_by_id(const union bpf_attr *attr) 53532d602c8cSAndrii Nakryiko { 53542d602c8cSAndrii Nakryiko struct bpf_link *link; 53552d602c8cSAndrii Nakryiko u32 id = attr->link_id; 5356005142b8SAlexei Starovoitov int fd; 53572d602c8cSAndrii Nakryiko 53582d602c8cSAndrii Nakryiko if (CHECK_ATTR(BPF_LINK_GET_FD_BY_ID)) 53592d602c8cSAndrii Nakryiko return -EINVAL; 53602d602c8cSAndrii Nakryiko 53612d602c8cSAndrii Nakryiko if (!capable(CAP_SYS_ADMIN)) 53622d602c8cSAndrii Nakryiko return -EPERM; 53632d602c8cSAndrii Nakryiko 5364005142b8SAlexei Starovoitov link = bpf_link_by_id(id); 5365005142b8SAlexei Starovoitov if (IS_ERR(link)) 5366005142b8SAlexei Starovoitov return PTR_ERR(link); 53672d602c8cSAndrii Nakryiko 53682d602c8cSAndrii Nakryiko fd = bpf_link_new_fd(link); 53692d602c8cSAndrii Nakryiko if (fd < 0) 5370ab5d47bdSSebastian Andrzej Siewior bpf_link_put_direct(link); 53712d602c8cSAndrii Nakryiko 53722d602c8cSAndrii Nakryiko return fd; 53732d602c8cSAndrii Nakryiko } 53742d602c8cSAndrii Nakryiko 5375d46edd67SSong Liu DEFINE_MUTEX(bpf_stats_enabled_mutex); 5376d46edd67SSong Liu 5377d46edd67SSong Liu static int bpf_stats_release(struct inode *inode, struct file *file) 5378d46edd67SSong Liu { 5379d46edd67SSong Liu mutex_lock(&bpf_stats_enabled_mutex); 5380d46edd67SSong Liu static_key_slow_dec(&bpf_stats_enabled_key.key); 5381d46edd67SSong Liu mutex_unlock(&bpf_stats_enabled_mutex); 5382d46edd67SSong Liu return 0; 5383d46edd67SSong Liu } 5384d46edd67SSong Liu 5385d46edd67SSong Liu static const struct file_operations bpf_stats_fops = { 5386d46edd67SSong Liu .release = bpf_stats_release, 5387d46edd67SSong Liu }; 5388d46edd67SSong Liu 5389d46edd67SSong Liu static int bpf_enable_runtime_stats(void) 5390d46edd67SSong Liu { 5391d46edd67SSong Liu int fd; 5392d46edd67SSong Liu 5393d46edd67SSong Liu mutex_lock(&bpf_stats_enabled_mutex); 5394d46edd67SSong Liu 5395d46edd67SSong Liu /* Set a very high limit to avoid overflow */ 5396d46edd67SSong Liu if (static_key_count(&bpf_stats_enabled_key.key) > INT_MAX / 2) { 5397d46edd67SSong Liu mutex_unlock(&bpf_stats_enabled_mutex); 5398d46edd67SSong Liu return -EBUSY; 5399d46edd67SSong Liu } 5400d46edd67SSong Liu 5401d46edd67SSong Liu fd = anon_inode_getfd("bpf-stats", &bpf_stats_fops, NULL, O_CLOEXEC); 5402d46edd67SSong Liu if (fd >= 0) 5403d46edd67SSong Liu static_key_slow_inc(&bpf_stats_enabled_key.key); 5404d46edd67SSong Liu 5405d46edd67SSong Liu mutex_unlock(&bpf_stats_enabled_mutex); 5406d46edd67SSong Liu return fd; 5407d46edd67SSong Liu } 5408d46edd67SSong Liu 5409d46edd67SSong Liu #define BPF_ENABLE_STATS_LAST_FIELD enable_stats.type 5410d46edd67SSong Liu 5411d46edd67SSong Liu static int bpf_enable_stats(union bpf_attr *attr) 5412d46edd67SSong Liu { 5413d46edd67SSong Liu 5414d46edd67SSong Liu if (CHECK_ATTR(BPF_ENABLE_STATS)) 5415d46edd67SSong Liu return -EINVAL; 5416d46edd67SSong Liu 5417d46edd67SSong Liu if (!capable(CAP_SYS_ADMIN)) 5418d46edd67SSong Liu return -EPERM; 5419d46edd67SSong Liu 5420d46edd67SSong Liu switch (attr->enable_stats.type) { 5421d46edd67SSong Liu case BPF_STATS_RUN_TIME: 5422d46edd67SSong Liu return bpf_enable_runtime_stats(); 5423d46edd67SSong Liu default: 5424d46edd67SSong Liu break; 5425d46edd67SSong Liu } 5426d46edd67SSong Liu return -EINVAL; 5427d46edd67SSong Liu } 5428d46edd67SSong Liu 5429ac51d99bSYonghong Song #define BPF_ITER_CREATE_LAST_FIELD iter_create.flags 5430ac51d99bSYonghong Song 5431ac51d99bSYonghong Song static int bpf_iter_create(union bpf_attr *attr) 5432ac51d99bSYonghong Song { 5433ac51d99bSYonghong Song struct bpf_link *link; 5434ac51d99bSYonghong Song int err; 5435ac51d99bSYonghong Song 5436ac51d99bSYonghong Song if (CHECK_ATTR(BPF_ITER_CREATE)) 5437ac51d99bSYonghong Song return -EINVAL; 5438ac51d99bSYonghong Song 5439ac51d99bSYonghong Song if (attr->iter_create.flags) 5440ac51d99bSYonghong Song return -EINVAL; 5441ac51d99bSYonghong Song 5442ac51d99bSYonghong Song link = bpf_link_get_from_fd(attr->iter_create.link_fd); 5443ac51d99bSYonghong Song if (IS_ERR(link)) 5444ac51d99bSYonghong Song return PTR_ERR(link); 5445ac51d99bSYonghong Song 5446ac51d99bSYonghong Song err = bpf_iter_new_fd(link); 5447ab5d47bdSSebastian Andrzej Siewior bpf_link_put_direct(link); 5448ac51d99bSYonghong Song 5449ac51d99bSYonghong Song return err; 5450ac51d99bSYonghong Song } 5451ac51d99bSYonghong Song 5452ef15314aSYiFei Zhu #define BPF_PROG_BIND_MAP_LAST_FIELD prog_bind_map.flags 5453ef15314aSYiFei Zhu 5454ef15314aSYiFei Zhu static int bpf_prog_bind_map(union bpf_attr *attr) 5455ef15314aSYiFei Zhu { 5456ef15314aSYiFei Zhu struct bpf_prog *prog; 5457ef15314aSYiFei Zhu struct bpf_map *map; 5458ef15314aSYiFei Zhu struct bpf_map **used_maps_old, **used_maps_new; 5459ef15314aSYiFei Zhu int i, ret = 0; 5460ef15314aSYiFei Zhu 5461ef15314aSYiFei Zhu if (CHECK_ATTR(BPF_PROG_BIND_MAP)) 5462ef15314aSYiFei Zhu return -EINVAL; 5463ef15314aSYiFei Zhu 5464ef15314aSYiFei Zhu if (attr->prog_bind_map.flags) 5465ef15314aSYiFei Zhu return -EINVAL; 5466ef15314aSYiFei Zhu 5467ef15314aSYiFei Zhu prog = bpf_prog_get(attr->prog_bind_map.prog_fd); 5468ef15314aSYiFei Zhu if (IS_ERR(prog)) 5469ef15314aSYiFei Zhu return PTR_ERR(prog); 5470ef15314aSYiFei Zhu 5471ef15314aSYiFei Zhu map = bpf_map_get(attr->prog_bind_map.map_fd); 5472ef15314aSYiFei Zhu if (IS_ERR(map)) { 5473ef15314aSYiFei Zhu ret = PTR_ERR(map); 5474ef15314aSYiFei Zhu goto out_prog_put; 5475ef15314aSYiFei Zhu } 5476ef15314aSYiFei Zhu 5477ef15314aSYiFei Zhu mutex_lock(&prog->aux->used_maps_mutex); 5478ef15314aSYiFei Zhu 5479ef15314aSYiFei Zhu used_maps_old = prog->aux->used_maps; 5480ef15314aSYiFei Zhu 5481ef15314aSYiFei Zhu for (i = 0; i < prog->aux->used_map_cnt; i++) 54821028ae40SStanislav Fomichev if (used_maps_old[i] == map) { 54831028ae40SStanislav Fomichev bpf_map_put(map); 5484ef15314aSYiFei Zhu goto out_unlock; 54851028ae40SStanislav Fomichev } 5486ef15314aSYiFei Zhu 5487ef15314aSYiFei Zhu used_maps_new = kmalloc_array(prog->aux->used_map_cnt + 1, 5488ef15314aSYiFei Zhu sizeof(used_maps_new[0]), 5489ef15314aSYiFei Zhu GFP_KERNEL); 5490ef15314aSYiFei Zhu if (!used_maps_new) { 5491ef15314aSYiFei Zhu ret = -ENOMEM; 5492ef15314aSYiFei Zhu goto out_unlock; 5493ef15314aSYiFei Zhu } 5494ef15314aSYiFei Zhu 5495af66bfd3SHou Tao /* The bpf program will not access the bpf map, but for the sake of 5496af66bfd3SHou Tao * simplicity, increase sleepable_refcnt for sleepable program as well. 5497af66bfd3SHou Tao */ 5498af66bfd3SHou Tao if (prog->aux->sleepable) 5499af66bfd3SHou Tao atomic64_inc(&map->sleepable_refcnt); 5500ef15314aSYiFei Zhu memcpy(used_maps_new, used_maps_old, 5501ef15314aSYiFei Zhu sizeof(used_maps_old[0]) * prog->aux->used_map_cnt); 5502ef15314aSYiFei Zhu used_maps_new[prog->aux->used_map_cnt] = map; 5503ef15314aSYiFei Zhu 5504ef15314aSYiFei Zhu prog->aux->used_map_cnt++; 5505ef15314aSYiFei Zhu prog->aux->used_maps = used_maps_new; 5506ef15314aSYiFei Zhu 5507ef15314aSYiFei Zhu kfree(used_maps_old); 5508ef15314aSYiFei Zhu 5509ef15314aSYiFei Zhu out_unlock: 5510ef15314aSYiFei Zhu mutex_unlock(&prog->aux->used_maps_mutex); 5511ef15314aSYiFei Zhu 5512ef15314aSYiFei Zhu if (ret) 5513ef15314aSYiFei Zhu bpf_map_put(map); 5514ef15314aSYiFei Zhu out_prog_put: 5515ef15314aSYiFei Zhu bpf_prog_put(prog); 5516ef15314aSYiFei Zhu return ret; 5517ef15314aSYiFei Zhu } 5518ef15314aSYiFei Zhu 551935f96de0SAndrii Nakryiko #define BPF_TOKEN_CREATE_LAST_FIELD token_create.bpffs_fd 552035f96de0SAndrii Nakryiko 552135f96de0SAndrii Nakryiko static int token_create(union bpf_attr *attr) 552235f96de0SAndrii Nakryiko { 552335f96de0SAndrii Nakryiko if (CHECK_ATTR(BPF_TOKEN_CREATE)) 552435f96de0SAndrii Nakryiko return -EINVAL; 552535f96de0SAndrii Nakryiko 552635f96de0SAndrii Nakryiko /* no flags are supported yet */ 552735f96de0SAndrii Nakryiko if (attr->token_create.flags) 552835f96de0SAndrii Nakryiko return -EINVAL; 552935f96de0SAndrii Nakryiko 553035f96de0SAndrii Nakryiko return bpf_token_create(attr); 553135f96de0SAndrii Nakryiko } 553235f96de0SAndrii Nakryiko 5533af2ac3e1SAlexei Starovoitov static int __sys_bpf(int cmd, bpfptr_t uattr, unsigned int size) 553499c55f7dSAlexei Starovoitov { 55358096f229SGreg Kroah-Hartman union bpf_attr attr; 553699c55f7dSAlexei Starovoitov int err; 553799c55f7dSAlexei Starovoitov 5538dcab51f1SMartin KaFai Lau err = bpf_check_uarg_tail_zero(uattr, sizeof(attr), size); 553999c55f7dSAlexei Starovoitov if (err) 554099c55f7dSAlexei Starovoitov return err; 55411e270976SMartin KaFai Lau size = min_t(u32, size, sizeof(attr)); 554299c55f7dSAlexei Starovoitov 554399c55f7dSAlexei Starovoitov /* copy attributes from user space, may be less than sizeof(bpf_attr) */ 55448096f229SGreg Kroah-Hartman memset(&attr, 0, sizeof(attr)); 5545af2ac3e1SAlexei Starovoitov if (copy_from_bpfptr(&attr, uattr, size) != 0) 554699c55f7dSAlexei Starovoitov return -EFAULT; 554799c55f7dSAlexei Starovoitov 5548afdb09c7SChenbo Feng err = security_bpf(cmd, &attr, size); 5549afdb09c7SChenbo Feng if (err < 0) 5550afdb09c7SChenbo Feng return err; 5551afdb09c7SChenbo Feng 555299c55f7dSAlexei Starovoitov switch (cmd) { 555399c55f7dSAlexei Starovoitov case BPF_MAP_CREATE: 555499c55f7dSAlexei Starovoitov err = map_create(&attr); 555599c55f7dSAlexei Starovoitov break; 5556db20fd2bSAlexei Starovoitov case BPF_MAP_LOOKUP_ELEM: 5557db20fd2bSAlexei Starovoitov err = map_lookup_elem(&attr); 5558db20fd2bSAlexei Starovoitov break; 5559db20fd2bSAlexei Starovoitov case BPF_MAP_UPDATE_ELEM: 5560af2ac3e1SAlexei Starovoitov err = map_update_elem(&attr, uattr); 5561db20fd2bSAlexei Starovoitov break; 5562db20fd2bSAlexei Starovoitov case BPF_MAP_DELETE_ELEM: 5563b88df697SBenjamin Tissoires err = map_delete_elem(&attr, uattr); 5564db20fd2bSAlexei Starovoitov break; 5565db20fd2bSAlexei Starovoitov case BPF_MAP_GET_NEXT_KEY: 5566db20fd2bSAlexei Starovoitov err = map_get_next_key(&attr); 5567db20fd2bSAlexei Starovoitov break; 556887df15deSDaniel Borkmann case BPF_MAP_FREEZE: 556987df15deSDaniel Borkmann err = map_freeze(&attr); 557087df15deSDaniel Borkmann break; 557109756af4SAlexei Starovoitov case BPF_PROG_LOAD: 557247a71c1fSAndrii Nakryiko err = bpf_prog_load(&attr, uattr, size); 557309756af4SAlexei Starovoitov break; 5574b2197755SDaniel Borkmann case BPF_OBJ_PIN: 5575b2197755SDaniel Borkmann err = bpf_obj_pin(&attr); 5576b2197755SDaniel Borkmann break; 5577b2197755SDaniel Borkmann case BPF_OBJ_GET: 5578b2197755SDaniel Borkmann err = bpf_obj_get(&attr); 5579b2197755SDaniel Borkmann break; 5580f4324551SDaniel Mack case BPF_PROG_ATTACH: 5581f4324551SDaniel Mack err = bpf_prog_attach(&attr); 5582f4324551SDaniel Mack break; 5583f4324551SDaniel Mack case BPF_PROG_DETACH: 5584f4324551SDaniel Mack err = bpf_prog_detach(&attr); 5585f4324551SDaniel Mack break; 5586468e2f64SAlexei Starovoitov case BPF_PROG_QUERY: 5587af2ac3e1SAlexei Starovoitov err = bpf_prog_query(&attr, uattr.user); 5588468e2f64SAlexei Starovoitov break; 55891cf1cae9SAlexei Starovoitov case BPF_PROG_TEST_RUN: 5590af2ac3e1SAlexei Starovoitov err = bpf_prog_test_run(&attr, uattr.user); 55911cf1cae9SAlexei Starovoitov break; 559234ad5580SMartin KaFai Lau case BPF_PROG_GET_NEXT_ID: 5593af2ac3e1SAlexei Starovoitov err = bpf_obj_get_next_id(&attr, uattr.user, 559434ad5580SMartin KaFai Lau &prog_idr, &prog_idr_lock); 559534ad5580SMartin KaFai Lau break; 559634ad5580SMartin KaFai Lau case BPF_MAP_GET_NEXT_ID: 5597af2ac3e1SAlexei Starovoitov err = bpf_obj_get_next_id(&attr, uattr.user, 559834ad5580SMartin KaFai Lau &map_idr, &map_idr_lock); 559934ad5580SMartin KaFai Lau break; 56001b9ed84eSQuentin Monnet case BPF_BTF_GET_NEXT_ID: 5601af2ac3e1SAlexei Starovoitov err = bpf_obj_get_next_id(&attr, uattr.user, 56021b9ed84eSQuentin Monnet &btf_idr, &btf_idr_lock); 56031b9ed84eSQuentin Monnet break; 5604b16d9aa4SMartin KaFai Lau case BPF_PROG_GET_FD_BY_ID: 5605b16d9aa4SMartin KaFai Lau err = bpf_prog_get_fd_by_id(&attr); 5606b16d9aa4SMartin KaFai Lau break; 5607bd5f5f4eSMartin KaFai Lau case BPF_MAP_GET_FD_BY_ID: 5608bd5f5f4eSMartin KaFai Lau err = bpf_map_get_fd_by_id(&attr); 5609bd5f5f4eSMartin KaFai Lau break; 56101e270976SMartin KaFai Lau case BPF_OBJ_GET_INFO_BY_FD: 5611af2ac3e1SAlexei Starovoitov err = bpf_obj_get_info_by_fd(&attr, uattr.user); 56121e270976SMartin KaFai Lau break; 5613c4f6699dSAlexei Starovoitov case BPF_RAW_TRACEPOINT_OPEN: 5614c4f6699dSAlexei Starovoitov err = bpf_raw_tracepoint_open(&attr); 5615c4f6699dSAlexei Starovoitov break; 5616f56a653cSMartin KaFai Lau case BPF_BTF_LOAD: 561747a71c1fSAndrii Nakryiko err = bpf_btf_load(&attr, uattr, size); 5618f56a653cSMartin KaFai Lau break; 561978958fcaSMartin KaFai Lau case BPF_BTF_GET_FD_BY_ID: 562078958fcaSMartin KaFai Lau err = bpf_btf_get_fd_by_id(&attr); 562178958fcaSMartin KaFai Lau break; 562241bdc4b4SYonghong Song case BPF_TASK_FD_QUERY: 5623af2ac3e1SAlexei Starovoitov err = bpf_task_fd_query(&attr, uattr.user); 562441bdc4b4SYonghong Song break; 5625bd513cd0SMauricio Vasquez B case BPF_MAP_LOOKUP_AND_DELETE_ELEM: 5626bd513cd0SMauricio Vasquez B err = map_lookup_and_delete_elem(&attr); 5627bd513cd0SMauricio Vasquez B break; 5628cb4d03abSBrian Vazquez case BPF_MAP_LOOKUP_BATCH: 5629af2ac3e1SAlexei Starovoitov err = bpf_map_do_batch(&attr, uattr.user, BPF_MAP_LOOKUP_BATCH); 5630cb4d03abSBrian Vazquez break; 563105799638SYonghong Song case BPF_MAP_LOOKUP_AND_DELETE_BATCH: 5632af2ac3e1SAlexei Starovoitov err = bpf_map_do_batch(&attr, uattr.user, 563305799638SYonghong Song BPF_MAP_LOOKUP_AND_DELETE_BATCH); 563405799638SYonghong Song break; 5635aa2e93b8SBrian Vazquez case BPF_MAP_UPDATE_BATCH: 5636af2ac3e1SAlexei Starovoitov err = bpf_map_do_batch(&attr, uattr.user, BPF_MAP_UPDATE_BATCH); 5637aa2e93b8SBrian Vazquez break; 5638aa2e93b8SBrian Vazquez case BPF_MAP_DELETE_BATCH: 5639af2ac3e1SAlexei Starovoitov err = bpf_map_do_batch(&attr, uattr.user, BPF_MAP_DELETE_BATCH); 5640aa2e93b8SBrian Vazquez break; 5641af6eea57SAndrii Nakryiko case BPF_LINK_CREATE: 5642af2ac3e1SAlexei Starovoitov err = link_create(&attr, uattr); 5643af6eea57SAndrii Nakryiko break; 56440c991ebcSAndrii Nakryiko case BPF_LINK_UPDATE: 56450c991ebcSAndrii Nakryiko err = link_update(&attr); 56460c991ebcSAndrii Nakryiko break; 56472d602c8cSAndrii Nakryiko case BPF_LINK_GET_FD_BY_ID: 56482d602c8cSAndrii Nakryiko err = bpf_link_get_fd_by_id(&attr); 56492d602c8cSAndrii Nakryiko break; 56502d602c8cSAndrii Nakryiko case BPF_LINK_GET_NEXT_ID: 5651af2ac3e1SAlexei Starovoitov err = bpf_obj_get_next_id(&attr, uattr.user, 56522d602c8cSAndrii Nakryiko &link_idr, &link_idr_lock); 56532d602c8cSAndrii Nakryiko break; 5654d46edd67SSong Liu case BPF_ENABLE_STATS: 5655d46edd67SSong Liu err = bpf_enable_stats(&attr); 5656d46edd67SSong Liu break; 5657ac51d99bSYonghong Song case BPF_ITER_CREATE: 5658ac51d99bSYonghong Song err = bpf_iter_create(&attr); 5659ac51d99bSYonghong Song break; 566073b11c2aSAndrii Nakryiko case BPF_LINK_DETACH: 566173b11c2aSAndrii Nakryiko err = link_detach(&attr); 566273b11c2aSAndrii Nakryiko break; 5663ef15314aSYiFei Zhu case BPF_PROG_BIND_MAP: 5664ef15314aSYiFei Zhu err = bpf_prog_bind_map(&attr); 5665ef15314aSYiFei Zhu break; 566635f96de0SAndrii Nakryiko case BPF_TOKEN_CREATE: 566735f96de0SAndrii Nakryiko err = token_create(&attr); 566835f96de0SAndrii Nakryiko break; 566999c55f7dSAlexei Starovoitov default: 567099c55f7dSAlexei Starovoitov err = -EINVAL; 567199c55f7dSAlexei Starovoitov break; 567299c55f7dSAlexei Starovoitov } 567399c55f7dSAlexei Starovoitov 567499c55f7dSAlexei Starovoitov return err; 567599c55f7dSAlexei Starovoitov } 567679a7f8bdSAlexei Starovoitov 5677af2ac3e1SAlexei Starovoitov SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size) 5678af2ac3e1SAlexei Starovoitov { 5679af2ac3e1SAlexei Starovoitov return __sys_bpf(cmd, USER_BPFPTR(uattr), size); 5680af2ac3e1SAlexei Starovoitov } 5681af2ac3e1SAlexei Starovoitov 568279a7f8bdSAlexei Starovoitov static bool syscall_prog_is_valid_access(int off, int size, 568379a7f8bdSAlexei Starovoitov enum bpf_access_type type, 568479a7f8bdSAlexei Starovoitov const struct bpf_prog *prog, 568579a7f8bdSAlexei Starovoitov struct bpf_insn_access_aux *info) 568679a7f8bdSAlexei Starovoitov { 568779a7f8bdSAlexei Starovoitov if (off < 0 || off >= U16_MAX) 568879a7f8bdSAlexei Starovoitov return false; 568979a7f8bdSAlexei Starovoitov if (off % size != 0) 569079a7f8bdSAlexei Starovoitov return false; 569179a7f8bdSAlexei Starovoitov return true; 569279a7f8bdSAlexei Starovoitov } 569379a7f8bdSAlexei Starovoitov 5694b1d18a75SAlexei Starovoitov BPF_CALL_3(bpf_sys_bpf, int, cmd, union bpf_attr *, attr, u32, attr_size) 569579a7f8bdSAlexei Starovoitov { 5696af2ac3e1SAlexei Starovoitov switch (cmd) { 5697af2ac3e1SAlexei Starovoitov case BPF_MAP_CREATE: 5698b88df697SBenjamin Tissoires case BPF_MAP_DELETE_ELEM: 5699af2ac3e1SAlexei Starovoitov case BPF_MAP_UPDATE_ELEM: 5700af2ac3e1SAlexei Starovoitov case BPF_MAP_FREEZE: 5701b88df697SBenjamin Tissoires case BPF_MAP_GET_FD_BY_ID: 5702af2ac3e1SAlexei Starovoitov case BPF_PROG_LOAD: 5703c571bd75SAlexei Starovoitov case BPF_BTF_LOAD: 5704b1d18a75SAlexei Starovoitov case BPF_LINK_CREATE: 5705b1d18a75SAlexei Starovoitov case BPF_RAW_TRACEPOINT_OPEN: 5706af2ac3e1SAlexei Starovoitov break; 570786f44fceSAlexei Starovoitov default: 570886f44fceSAlexei Starovoitov return -EINVAL; 570986f44fceSAlexei Starovoitov } 571086f44fceSAlexei Starovoitov return __sys_bpf(cmd, KERNEL_BPFPTR(attr), attr_size); 571186f44fceSAlexei Starovoitov } 571286f44fceSAlexei Starovoitov 57134e4588f1SAlexei Starovoitov 57144e4588f1SAlexei Starovoitov /* To shut up -Wmissing-prototypes. 57154e4588f1SAlexei Starovoitov * This function is used by the kernel light skeleton 57164e4588f1SAlexei Starovoitov * to load bpf programs when modules are loaded or during kernel boot. 57174e4588f1SAlexei Starovoitov * See tools/lib/bpf/skel_internal.h 57184e4588f1SAlexei Starovoitov */ 57194e4588f1SAlexei Starovoitov int kern_sys_bpf(int cmd, union bpf_attr *attr, unsigned int size); 57204e4588f1SAlexei Starovoitov 572186f44fceSAlexei Starovoitov int kern_sys_bpf(int cmd, union bpf_attr *attr, unsigned int size) 572286f44fceSAlexei Starovoitov { 572386f44fceSAlexei Starovoitov struct bpf_prog * __maybe_unused prog; 572486f44fceSAlexei Starovoitov struct bpf_tramp_run_ctx __maybe_unused run_ctx; 572586f44fceSAlexei Starovoitov 572686f44fceSAlexei Starovoitov switch (cmd) { 5727b1d18a75SAlexei Starovoitov #ifdef CONFIG_BPF_JIT /* __bpf_prog_enter_sleepable used by trampoline and JIT */ 5728b1d18a75SAlexei Starovoitov case BPF_PROG_TEST_RUN: 5729b1d18a75SAlexei Starovoitov if (attr->test.data_in || attr->test.data_out || 5730b1d18a75SAlexei Starovoitov attr->test.ctx_out || attr->test.duration || 5731b1d18a75SAlexei Starovoitov attr->test.repeat || attr->test.flags) 5732b1d18a75SAlexei Starovoitov return -EINVAL; 5733b1d18a75SAlexei Starovoitov 5734b1d18a75SAlexei Starovoitov prog = bpf_prog_get_type(attr->test.prog_fd, BPF_PROG_TYPE_SYSCALL); 5735b1d18a75SAlexei Starovoitov if (IS_ERR(prog)) 5736b1d18a75SAlexei Starovoitov return PTR_ERR(prog); 5737b1d18a75SAlexei Starovoitov 5738b1d18a75SAlexei Starovoitov if (attr->test.ctx_size_in < prog->aux->max_ctx_offset || 5739b1d18a75SAlexei Starovoitov attr->test.ctx_size_in > U16_MAX) { 5740b1d18a75SAlexei Starovoitov bpf_prog_put(prog); 5741b1d18a75SAlexei Starovoitov return -EINVAL; 5742b1d18a75SAlexei Starovoitov } 5743b1d18a75SAlexei Starovoitov 5744e384c7b7SKui-Feng Lee run_ctx.bpf_cookie = 0; 5745271de525SMartin KaFai Lau if (!__bpf_prog_enter_sleepable_recur(prog, &run_ctx)) { 5746b1d18a75SAlexei Starovoitov /* recursion detected */ 57477645629fSSebastian Andrzej Siewior __bpf_prog_exit_sleepable_recur(prog, 0, &run_ctx); 5748b1d18a75SAlexei Starovoitov bpf_prog_put(prog); 5749b1d18a75SAlexei Starovoitov return -EBUSY; 5750b1d18a75SAlexei Starovoitov } 5751b1d18a75SAlexei Starovoitov attr->test.retval = bpf_prog_run(prog, (void *) (long) attr->test.ctx_in); 5752271de525SMartin KaFai Lau __bpf_prog_exit_sleepable_recur(prog, 0 /* bpf_prog_run does runtime stats */, 5753271de525SMartin KaFai Lau &run_ctx); 5754b1d18a75SAlexei Starovoitov bpf_prog_put(prog); 5755b1d18a75SAlexei Starovoitov return 0; 5756b1d18a75SAlexei Starovoitov #endif 5757af2ac3e1SAlexei Starovoitov default: 575886f44fceSAlexei Starovoitov return ____bpf_sys_bpf(cmd, attr, size); 575979a7f8bdSAlexei Starovoitov } 5760af2ac3e1SAlexei Starovoitov } 576186f44fceSAlexei Starovoitov EXPORT_SYMBOL(kern_sys_bpf); 576279a7f8bdSAlexei Starovoitov 57633a2daa72SPu Lehui static const struct bpf_func_proto bpf_sys_bpf_proto = { 576479a7f8bdSAlexei Starovoitov .func = bpf_sys_bpf, 576579a7f8bdSAlexei Starovoitov .gpl_only = false, 576679a7f8bdSAlexei Starovoitov .ret_type = RET_INTEGER, 576779a7f8bdSAlexei Starovoitov .arg1_type = ARG_ANYTHING, 5768216e3cd2SHao Luo .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 576979a7f8bdSAlexei Starovoitov .arg3_type = ARG_CONST_SIZE, 577079a7f8bdSAlexei Starovoitov }; 577179a7f8bdSAlexei Starovoitov 577279a7f8bdSAlexei Starovoitov const struct bpf_func_proto * __weak 577379a7f8bdSAlexei Starovoitov tracing_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) 577479a7f8bdSAlexei Starovoitov { 5775*bbc1d247SAndrii Nakryiko return bpf_base_func_proto(func_id, prog); 577679a7f8bdSAlexei Starovoitov } 577779a7f8bdSAlexei Starovoitov 57783abea089SAlexei Starovoitov BPF_CALL_1(bpf_sys_close, u32, fd) 57793abea089SAlexei Starovoitov { 57803abea089SAlexei Starovoitov /* When bpf program calls this helper there should not be 57813abea089SAlexei Starovoitov * an fdget() without matching completed fdput(). 57823abea089SAlexei Starovoitov * This helper is allowed in the following callchain only: 57833abea089SAlexei Starovoitov * sys_bpf->prog_test_run->bpf_prog->bpf_sys_close 57843abea089SAlexei Starovoitov */ 57853abea089SAlexei Starovoitov return close_fd(fd); 57863abea089SAlexei Starovoitov } 57873abea089SAlexei Starovoitov 57883a2daa72SPu Lehui static const struct bpf_func_proto bpf_sys_close_proto = { 57893abea089SAlexei Starovoitov .func = bpf_sys_close, 57903abea089SAlexei Starovoitov .gpl_only = false, 57913abea089SAlexei Starovoitov .ret_type = RET_INTEGER, 57923abea089SAlexei Starovoitov .arg1_type = ARG_ANYTHING, 57933abea089SAlexei Starovoitov }; 57943abea089SAlexei Starovoitov 5795d6aef08aSKumar Kartikeya Dwivedi BPF_CALL_4(bpf_kallsyms_lookup_name, const char *, name, int, name_sz, int, flags, u64 *, res) 5796d6aef08aSKumar Kartikeya Dwivedi { 5797d6aef08aSKumar Kartikeya Dwivedi if (flags) 5798d6aef08aSKumar Kartikeya Dwivedi return -EINVAL; 5799d6aef08aSKumar Kartikeya Dwivedi 5800d6aef08aSKumar Kartikeya Dwivedi if (name_sz <= 1 || name[name_sz - 1]) 5801d6aef08aSKumar Kartikeya Dwivedi return -EINVAL; 5802d6aef08aSKumar Kartikeya Dwivedi 5803d6aef08aSKumar Kartikeya Dwivedi if (!bpf_dump_raw_ok(current_cred())) 5804d6aef08aSKumar Kartikeya Dwivedi return -EPERM; 5805d6aef08aSKumar Kartikeya Dwivedi 5806d6aef08aSKumar Kartikeya Dwivedi *res = kallsyms_lookup_name(name); 5807d6aef08aSKumar Kartikeya Dwivedi return *res ? 0 : -ENOENT; 5808d6aef08aSKumar Kartikeya Dwivedi } 5809d6aef08aSKumar Kartikeya Dwivedi 5810dc368e1cSJoanne Koong static const struct bpf_func_proto bpf_kallsyms_lookup_name_proto = { 5811d6aef08aSKumar Kartikeya Dwivedi .func = bpf_kallsyms_lookup_name, 5812d6aef08aSKumar Kartikeya Dwivedi .gpl_only = false, 5813d6aef08aSKumar Kartikeya Dwivedi .ret_type = RET_INTEGER, 5814d6aef08aSKumar Kartikeya Dwivedi .arg1_type = ARG_PTR_TO_MEM, 5815d4efb170SKumar Kartikeya Dwivedi .arg2_type = ARG_CONST_SIZE_OR_ZERO, 5816d6aef08aSKumar Kartikeya Dwivedi .arg3_type = ARG_ANYTHING, 5817d6aef08aSKumar Kartikeya Dwivedi .arg4_type = ARG_PTR_TO_LONG, 5818d6aef08aSKumar Kartikeya Dwivedi }; 5819d6aef08aSKumar Kartikeya Dwivedi 582079a7f8bdSAlexei Starovoitov static const struct bpf_func_proto * 582179a7f8bdSAlexei Starovoitov syscall_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) 582279a7f8bdSAlexei Starovoitov { 582379a7f8bdSAlexei Starovoitov switch (func_id) { 582479a7f8bdSAlexei Starovoitov case BPF_FUNC_sys_bpf: 5825*bbc1d247SAndrii Nakryiko return !bpf_token_capable(prog->aux->token, CAP_PERFMON) 5826*bbc1d247SAndrii Nakryiko ? NULL : &bpf_sys_bpf_proto; 58273d78417bSAlexei Starovoitov case BPF_FUNC_btf_find_by_name_kind: 58283d78417bSAlexei Starovoitov return &bpf_btf_find_by_name_kind_proto; 58293abea089SAlexei Starovoitov case BPF_FUNC_sys_close: 58303abea089SAlexei Starovoitov return &bpf_sys_close_proto; 5831d6aef08aSKumar Kartikeya Dwivedi case BPF_FUNC_kallsyms_lookup_name: 5832d6aef08aSKumar Kartikeya Dwivedi return &bpf_kallsyms_lookup_name_proto; 583379a7f8bdSAlexei Starovoitov default: 583479a7f8bdSAlexei Starovoitov return tracing_prog_func_proto(func_id, prog); 583579a7f8bdSAlexei Starovoitov } 583679a7f8bdSAlexei Starovoitov } 583779a7f8bdSAlexei Starovoitov 583879a7f8bdSAlexei Starovoitov const struct bpf_verifier_ops bpf_syscall_verifier_ops = { 583979a7f8bdSAlexei Starovoitov .get_func_proto = syscall_prog_func_proto, 584079a7f8bdSAlexei Starovoitov .is_valid_access = syscall_prog_is_valid_access, 584179a7f8bdSAlexei Starovoitov }; 584279a7f8bdSAlexei Starovoitov 584379a7f8bdSAlexei Starovoitov const struct bpf_prog_ops bpf_syscall_prog_ops = { 584479a7f8bdSAlexei Starovoitov .test_run = bpf_prog_test_run_syscall, 584579a7f8bdSAlexei Starovoitov }; 58462900005eSYan Zhu 58472900005eSYan Zhu #ifdef CONFIG_SYSCTL 58482900005eSYan Zhu static int bpf_stats_handler(struct ctl_table *table, int write, 58492900005eSYan Zhu void *buffer, size_t *lenp, loff_t *ppos) 58502900005eSYan Zhu { 58512900005eSYan Zhu struct static_key *key = (struct static_key *)table->data; 58522900005eSYan Zhu static int saved_val; 58532900005eSYan Zhu int val, ret; 58542900005eSYan Zhu struct ctl_table tmp = { 58552900005eSYan Zhu .data = &val, 58562900005eSYan Zhu .maxlen = sizeof(val), 58572900005eSYan Zhu .mode = table->mode, 58582900005eSYan Zhu .extra1 = SYSCTL_ZERO, 58592900005eSYan Zhu .extra2 = SYSCTL_ONE, 58602900005eSYan Zhu }; 58612900005eSYan Zhu 58622900005eSYan Zhu if (write && !capable(CAP_SYS_ADMIN)) 58632900005eSYan Zhu return -EPERM; 58642900005eSYan Zhu 58652900005eSYan Zhu mutex_lock(&bpf_stats_enabled_mutex); 58662900005eSYan Zhu val = saved_val; 58672900005eSYan Zhu ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); 58682900005eSYan Zhu if (write && !ret && val != saved_val) { 58692900005eSYan Zhu if (val) 58702900005eSYan Zhu static_key_slow_inc(key); 58712900005eSYan Zhu else 58722900005eSYan Zhu static_key_slow_dec(key); 58732900005eSYan Zhu saved_val = val; 58742900005eSYan Zhu } 58752900005eSYan Zhu mutex_unlock(&bpf_stats_enabled_mutex); 58762900005eSYan Zhu return ret; 58772900005eSYan Zhu } 58782900005eSYan Zhu 58792900005eSYan Zhu void __weak unpriv_ebpf_notify(int new_state) 58802900005eSYan Zhu { 58812900005eSYan Zhu } 58822900005eSYan Zhu 58832900005eSYan Zhu static int bpf_unpriv_handler(struct ctl_table *table, int write, 58842900005eSYan Zhu void *buffer, size_t *lenp, loff_t *ppos) 58852900005eSYan Zhu { 58862900005eSYan Zhu int ret, unpriv_enable = *(int *)table->data; 58872900005eSYan Zhu bool locked_state = unpriv_enable == 1; 58882900005eSYan Zhu struct ctl_table tmp = *table; 58892900005eSYan Zhu 58902900005eSYan Zhu if (write && !capable(CAP_SYS_ADMIN)) 58912900005eSYan Zhu return -EPERM; 58922900005eSYan Zhu 58932900005eSYan Zhu tmp.data = &unpriv_enable; 58942900005eSYan Zhu ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); 58952900005eSYan Zhu if (write && !ret) { 58962900005eSYan Zhu if (locked_state && unpriv_enable != 1) 58972900005eSYan Zhu return -EPERM; 58982900005eSYan Zhu *(int *)table->data = unpriv_enable; 58992900005eSYan Zhu } 59002900005eSYan Zhu 5901fedf9920SKui-Feng Lee if (write) 59022900005eSYan Zhu unpriv_ebpf_notify(unpriv_enable); 59032900005eSYan Zhu 59042900005eSYan Zhu return ret; 59052900005eSYan Zhu } 59062900005eSYan Zhu 59072900005eSYan Zhu static struct ctl_table bpf_syscall_table[] = { 59082900005eSYan Zhu { 59092900005eSYan Zhu .procname = "unprivileged_bpf_disabled", 59102900005eSYan Zhu .data = &sysctl_unprivileged_bpf_disabled, 59112900005eSYan Zhu .maxlen = sizeof(sysctl_unprivileged_bpf_disabled), 59122900005eSYan Zhu .mode = 0644, 59132900005eSYan Zhu .proc_handler = bpf_unpriv_handler, 59142900005eSYan Zhu .extra1 = SYSCTL_ZERO, 59152900005eSYan Zhu .extra2 = SYSCTL_TWO, 59162900005eSYan Zhu }, 59172900005eSYan Zhu { 59182900005eSYan Zhu .procname = "bpf_stats_enabled", 59192900005eSYan Zhu .data = &bpf_stats_enabled_key.key, 59202900005eSYan Zhu .mode = 0644, 59212900005eSYan Zhu .proc_handler = bpf_stats_handler, 59222900005eSYan Zhu }, 59232900005eSYan Zhu { } 59242900005eSYan Zhu }; 59252900005eSYan Zhu 59262900005eSYan Zhu static int __init bpf_syscall_sysctl_init(void) 59272900005eSYan Zhu { 59282900005eSYan Zhu register_sysctl_init("kernel", bpf_syscall_table); 59292900005eSYan Zhu return 0; 59302900005eSYan Zhu } 59312900005eSYan Zhu late_initcall(bpf_syscall_sysctl_init); 59322900005eSYan Zhu #endif /* CONFIG_SYSCTL */ 5933