13d0407baSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 23d0407baSopenharmony_ci/* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com 33d0407baSopenharmony_ci */ 43d0407baSopenharmony_ci#include <linux/bpf.h> 53d0407baSopenharmony_ci#include <linux/bpf_trace.h> 63d0407baSopenharmony_ci#include <linux/bpf_lirc.h> 73d0407baSopenharmony_ci#include <linux/bpf_verifier.h> 83d0407baSopenharmony_ci#include <linux/btf.h> 93d0407baSopenharmony_ci#include <linux/syscalls.h> 103d0407baSopenharmony_ci#include <linux/slab.h> 113d0407baSopenharmony_ci#include <linux/sched/signal.h> 123d0407baSopenharmony_ci#include <linux/vmalloc.h> 133d0407baSopenharmony_ci#include <linux/mmzone.h> 143d0407baSopenharmony_ci#include <linux/anon_inodes.h> 153d0407baSopenharmony_ci#include <linux/fdtable.h> 163d0407baSopenharmony_ci#include <linux/file.h> 173d0407baSopenharmony_ci#include <linux/fs.h> 183d0407baSopenharmony_ci#include <linux/license.h> 193d0407baSopenharmony_ci#include <linux/filter.h> 203d0407baSopenharmony_ci#include <linux/version.h> 213d0407baSopenharmony_ci#include <linux/kernel.h> 223d0407baSopenharmony_ci#include <linux/idr.h> 233d0407baSopenharmony_ci#include <linux/cred.h> 243d0407baSopenharmony_ci#include <linux/timekeeping.h> 253d0407baSopenharmony_ci#include <linux/ctype.h> 263d0407baSopenharmony_ci#include <linux/nospec.h> 273d0407baSopenharmony_ci#include <linux/audit.h> 283d0407baSopenharmony_ci#include <uapi/linux/btf.h> 293d0407baSopenharmony_ci#include <linux/pgtable.h> 303d0407baSopenharmony_ci#include <linux/bpf_lsm.h> 313d0407baSopenharmony_ci#include <linux/poll.h> 323d0407baSopenharmony_ci#include <linux/bpf-netns.h> 333d0407baSopenharmony_ci#include <linux/rcupdate_trace.h> 343d0407baSopenharmony_ci 353d0407baSopenharmony_ci#define IS_FD_ARRAY(map) \ 363d0407baSopenharmony_ci ((map)->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || (map)->map_type == BPF_MAP_TYPE_CGROUP_ARRAY || \ 373d0407baSopenharmony_ci (map)->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS) 383d0407baSopenharmony_ci#define IS_FD_PROG_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PROG_ARRAY) 393d0407baSopenharmony_ci#define IS_FD_HASH(map) ((map)->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) 403d0407baSopenharmony_ci#define IS_FD_MAP(map) (IS_FD_ARRAY(map) || IS_FD_PROG_ARRAY(map) || IS_FD_HASH(map)) 413d0407baSopenharmony_ci 423d0407baSopenharmony_ci#define BPF_OBJ_FLAG_MASK (BPF_F_RDONLY | BPF_F_WRONLY) 433d0407baSopenharmony_ci 443d0407baSopenharmony_ciDEFINE_PER_CPU(int, bpf_prog_active); 453d0407baSopenharmony_cistatic DEFINE_IDR(prog_idr); 463d0407baSopenharmony_cistatic DEFINE_SPINLOCK(prog_idr_lock); 473d0407baSopenharmony_cistatic DEFINE_IDR(map_idr); 483d0407baSopenharmony_cistatic DEFINE_SPINLOCK(map_idr_lock); 493d0407baSopenharmony_cistatic DEFINE_IDR(link_idr); 503d0407baSopenharmony_cistatic DEFINE_SPINLOCK(link_idr_lock); 513d0407baSopenharmony_ci 523d0407baSopenharmony_ciint sysctl_unprivileged_bpf_disabled __read_mostly = IS_BUILTIN(CONFIG_BPF_UNPRIV_DEFAULT_OFF) ? 2 : 0; 533d0407baSopenharmony_ci 543d0407baSopenharmony_cistatic const struct bpf_map_ops *const bpf_map_types[] = { 553d0407baSopenharmony_ci#define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) 563d0407baSopenharmony_ci#define BPF_MAP_TYPE(_id, _ops) [_id] = &(_ops), 573d0407baSopenharmony_ci#define BPF_LINK_TYPE(_id, _name) 583d0407baSopenharmony_ci#include <linux/bpf_types.h> 593d0407baSopenharmony_ci#undef BPF_PROG_TYPE 603d0407baSopenharmony_ci#undef BPF_MAP_TYPE 613d0407baSopenharmony_ci#undef BPF_LINK_TYPE 623d0407baSopenharmony_ci}; 633d0407baSopenharmony_ci 643d0407baSopenharmony_ci/* 653d0407baSopenharmony_ci * If we're handed a bigger struct than we know of, ensure all the unknown bits 663d0407baSopenharmony_ci * are 0 - i.e. new user-space does not rely on any kernel feature extensions 673d0407baSopenharmony_ci * we don't know about yet. 683d0407baSopenharmony_ci * 693d0407baSopenharmony_ci * There is a ToCToU between this function call and the following 703d0407baSopenharmony_ci * copy_from_user() call. However, this is not a concern since this function is 713d0407baSopenharmony_ci * meant to be a future-proofing of bits. 723d0407baSopenharmony_ci */ 733d0407baSopenharmony_ciint bpf_check_uarg_tail_zero(void __user *uaddr, size_t expected_size, size_t actual_size) 743d0407baSopenharmony_ci{ 753d0407baSopenharmony_ci unsigned char __user *addr = uaddr + expected_size; 763d0407baSopenharmony_ci int res; 773d0407baSopenharmony_ci 783d0407baSopenharmony_ci if (unlikely(actual_size > PAGE_SIZE)) { /* silly large */ 793d0407baSopenharmony_ci return -E2BIG; 803d0407baSopenharmony_ci } 813d0407baSopenharmony_ci 823d0407baSopenharmony_ci if (actual_size <= expected_size) { 833d0407baSopenharmony_ci return 0; 843d0407baSopenharmony_ci } 853d0407baSopenharmony_ci 863d0407baSopenharmony_ci res = check_zeroed_user(addr, actual_size - expected_size); 873d0407baSopenharmony_ci if (res < 0) { 883d0407baSopenharmony_ci return res; 893d0407baSopenharmony_ci } 903d0407baSopenharmony_ci return res ? 0 : -E2BIG; 913d0407baSopenharmony_ci} 923d0407baSopenharmony_ci 933d0407baSopenharmony_ciconst struct bpf_map_ops bpf_map_offload_ops = { 943d0407baSopenharmony_ci .map_meta_equal = bpf_map_meta_equal, 953d0407baSopenharmony_ci .map_alloc = bpf_map_offload_map_alloc, 963d0407baSopenharmony_ci .map_free = bpf_map_offload_map_free, 973d0407baSopenharmony_ci .map_check_btf = map_check_no_btf, 983d0407baSopenharmony_ci}; 993d0407baSopenharmony_ci 1003d0407baSopenharmony_cistatic struct bpf_map *find_and_alloc_map(union bpf_attr *attr) 1013d0407baSopenharmony_ci{ 1023d0407baSopenharmony_ci const struct bpf_map_ops *ops; 1033d0407baSopenharmony_ci u32 type = attr->map_type; 1043d0407baSopenharmony_ci struct bpf_map *map; 1053d0407baSopenharmony_ci int err; 1063d0407baSopenharmony_ci 1073d0407baSopenharmony_ci if (type >= ARRAY_SIZE(bpf_map_types)) { 1083d0407baSopenharmony_ci return ERR_PTR(-EINVAL); 1093d0407baSopenharmony_ci } 1103d0407baSopenharmony_ci type = array_index_nospec(type, ARRAY_SIZE(bpf_map_types)); 1113d0407baSopenharmony_ci ops = bpf_map_types[type]; 1123d0407baSopenharmony_ci if (!ops) { 1133d0407baSopenharmony_ci return ERR_PTR(-EINVAL); 1143d0407baSopenharmony_ci } 1153d0407baSopenharmony_ci 1163d0407baSopenharmony_ci if (ops->map_alloc_check) { 1173d0407baSopenharmony_ci err = ops->map_alloc_check(attr); 1183d0407baSopenharmony_ci if (err) { 1193d0407baSopenharmony_ci return ERR_PTR(err); 1203d0407baSopenharmony_ci } 1213d0407baSopenharmony_ci } 1223d0407baSopenharmony_ci if (attr->map_ifindex) { 1233d0407baSopenharmony_ci ops = &bpf_map_offload_ops; 1243d0407baSopenharmony_ci } 1253d0407baSopenharmony_ci map = ops->map_alloc(attr); 1263d0407baSopenharmony_ci if (IS_ERR(map)) { 1273d0407baSopenharmony_ci return map; 1283d0407baSopenharmony_ci } 1293d0407baSopenharmony_ci map->ops = ops; 1303d0407baSopenharmony_ci map->map_type = type; 1313d0407baSopenharmony_ci return map; 1323d0407baSopenharmony_ci} 1333d0407baSopenharmony_ci 1343d0407baSopenharmony_cistatic u32 bpf_map_value_size(struct bpf_map *map) 1353d0407baSopenharmony_ci{ 1363d0407baSopenharmony_ci if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH || 1373d0407baSopenharmony_ci map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY || map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) { 1383d0407baSopenharmony_ci return round_up(map->value_size, 0x8) * num_possible_cpus(); 1393d0407baSopenharmony_ci } else if (IS_FD_MAP(map)) { 1403d0407baSopenharmony_ci return sizeof(u32); 1413d0407baSopenharmony_ci } else { 1423d0407baSopenharmony_ci return map->value_size; 1433d0407baSopenharmony_ci } 1443d0407baSopenharmony_ci} 1453d0407baSopenharmony_ci 1463d0407baSopenharmony_cistatic void maybe_wait_bpf_programs(struct bpf_map *map) 1473d0407baSopenharmony_ci{ 1483d0407baSopenharmony_ci /* Wait for any running BPF programs to complete so that 1493d0407baSopenharmony_ci * userspace, when we return to it, knows that all programs 1503d0407baSopenharmony_ci * that could be running use the new map value. 1513d0407baSopenharmony_ci */ 1523d0407baSopenharmony_ci if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS || map->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS) { 1533d0407baSopenharmony_ci synchronize_rcu(); 1543d0407baSopenharmony_ci } 1553d0407baSopenharmony_ci} 1563d0407baSopenharmony_ci 1573d0407baSopenharmony_cistatic int bpf_map_update_value(struct bpf_map *map, struct fd f, void *key, void *value, __u64 flags) 1583d0407baSopenharmony_ci{ 1593d0407baSopenharmony_ci int err; 1603d0407baSopenharmony_ci 1613d0407baSopenharmony_ci /* Need to create a kthread, thus must support schedule */ 1623d0407baSopenharmony_ci if (bpf_map_is_dev_bound(map)) { 1633d0407baSopenharmony_ci return bpf_map_offload_update_elem(map, key, value, flags); 1643d0407baSopenharmony_ci } else if (map->map_type == BPF_MAP_TYPE_CPUMAP || map->map_type == BPF_MAP_TYPE_STRUCT_OPS) { 1653d0407baSopenharmony_ci return map->ops->map_update_elem(map, key, value, flags); 1663d0407baSopenharmony_ci } else if (map->map_type == BPF_MAP_TYPE_SOCKHASH || map->map_type == BPF_MAP_TYPE_SOCKMAP) { 1673d0407baSopenharmony_ci return sock_map_update_elem_sys(map, key, value, flags); 1683d0407baSopenharmony_ci } else if (IS_FD_PROG_ARRAY(map)) { 1693d0407baSopenharmony_ci return bpf_fd_array_map_update_elem(map, f.file, key, value, flags); 1703d0407baSopenharmony_ci } 1713d0407baSopenharmony_ci 1723d0407baSopenharmony_ci bpf_disable_instrumentation(); 1733d0407baSopenharmony_ci if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) { 1743d0407baSopenharmony_ci err = bpf_percpu_hash_update(map, key, value, flags); 1753d0407baSopenharmony_ci } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) { 1763d0407baSopenharmony_ci err = bpf_percpu_array_update(map, key, value, flags); 1773d0407baSopenharmony_ci } else if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) { 1783d0407baSopenharmony_ci err = bpf_percpu_cgroup_storage_update(map, key, value, flags); 1793d0407baSopenharmony_ci } else if (IS_FD_ARRAY(map)) { 1803d0407baSopenharmony_ci rcu_read_lock(); 1813d0407baSopenharmony_ci err = bpf_fd_array_map_update_elem(map, f.file, key, value, flags); 1823d0407baSopenharmony_ci rcu_read_unlock(); 1833d0407baSopenharmony_ci } else if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) { 1843d0407baSopenharmony_ci rcu_read_lock(); 1853d0407baSopenharmony_ci err = bpf_fd_htab_map_update_elem(map, f.file, key, value, flags); 1863d0407baSopenharmony_ci rcu_read_unlock(); 1873d0407baSopenharmony_ci } else if (map->map_type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY) { 1883d0407baSopenharmony_ci /* rcu_read_lock() is not needed */ 1893d0407baSopenharmony_ci err = bpf_fd_reuseport_array_update_elem(map, key, value, flags); 1903d0407baSopenharmony_ci } else if (map->map_type == BPF_MAP_TYPE_QUEUE || map->map_type == BPF_MAP_TYPE_STACK) { 1913d0407baSopenharmony_ci err = map->ops->map_push_elem(map, value, flags); 1923d0407baSopenharmony_ci } else { 1933d0407baSopenharmony_ci rcu_read_lock(); 1943d0407baSopenharmony_ci err = map->ops->map_update_elem(map, key, value, flags); 1953d0407baSopenharmony_ci rcu_read_unlock(); 1963d0407baSopenharmony_ci } 1973d0407baSopenharmony_ci bpf_enable_instrumentation(); 1983d0407baSopenharmony_ci maybe_wait_bpf_programs(map); 1993d0407baSopenharmony_ci 2003d0407baSopenharmony_ci return err; 2013d0407baSopenharmony_ci} 2023d0407baSopenharmony_ci 2033d0407baSopenharmony_cistatic int bpf_map_copy_value(struct bpf_map *map, void *key, void *value, __u64 flags) 2043d0407baSopenharmony_ci{ 2053d0407baSopenharmony_ci void *ptr; 2063d0407baSopenharmony_ci int err; 2073d0407baSopenharmony_ci 2083d0407baSopenharmony_ci if (bpf_map_is_dev_bound(map)) { 2093d0407baSopenharmony_ci return bpf_map_offload_lookup_elem(map, key, value); 2103d0407baSopenharmony_ci } 2113d0407baSopenharmony_ci 2123d0407baSopenharmony_ci bpf_disable_instrumentation(); 2133d0407baSopenharmony_ci if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) { 2143d0407baSopenharmony_ci err = bpf_percpu_hash_copy(map, key, value); 2153d0407baSopenharmony_ci } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) { 2163d0407baSopenharmony_ci err = bpf_percpu_array_copy(map, key, value); 2173d0407baSopenharmony_ci } else if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) { 2183d0407baSopenharmony_ci err = bpf_percpu_cgroup_storage_copy(map, key, value); 2193d0407baSopenharmony_ci } else if (map->map_type == BPF_MAP_TYPE_STACK_TRACE) { 2203d0407baSopenharmony_ci err = bpf_stackmap_copy(map, key, value); 2213d0407baSopenharmony_ci } else if (IS_FD_ARRAY(map) || IS_FD_PROG_ARRAY(map)) { 2223d0407baSopenharmony_ci err = bpf_fd_array_map_lookup_elem(map, key, value); 2233d0407baSopenharmony_ci } else if (IS_FD_HASH(map)) { 2243d0407baSopenharmony_ci err = bpf_fd_htab_map_lookup_elem(map, key, value); 2253d0407baSopenharmony_ci } else if (map->map_type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY) { 2263d0407baSopenharmony_ci err = bpf_fd_reuseport_array_lookup_elem(map, key, value); 2273d0407baSopenharmony_ci } else if (map->map_type == BPF_MAP_TYPE_QUEUE || map->map_type == BPF_MAP_TYPE_STACK) { 2283d0407baSopenharmony_ci err = map->ops->map_peek_elem(map, value); 2293d0407baSopenharmony_ci } else if (map->map_type == BPF_MAP_TYPE_STRUCT_OPS) { 2303d0407baSopenharmony_ci /* struct_ops map requires directly updating "value" */ 2313d0407baSopenharmony_ci err = bpf_struct_ops_map_sys_lookup_elem(map, key, value); 2323d0407baSopenharmony_ci } else { 2333d0407baSopenharmony_ci rcu_read_lock(); 2343d0407baSopenharmony_ci if (map->ops->map_lookup_elem_sys_only) { 2353d0407baSopenharmony_ci ptr = map->ops->map_lookup_elem_sys_only(map, key); 2363d0407baSopenharmony_ci } else { 2373d0407baSopenharmony_ci ptr = map->ops->map_lookup_elem(map, key); 2383d0407baSopenharmony_ci } 2393d0407baSopenharmony_ci if (IS_ERR(ptr)) { 2403d0407baSopenharmony_ci err = PTR_ERR(ptr); 2413d0407baSopenharmony_ci } else if (!ptr) { 2423d0407baSopenharmony_ci err = -ENOENT; 2433d0407baSopenharmony_ci } else { 2443d0407baSopenharmony_ci err = 0; 2453d0407baSopenharmony_ci if (flags & BPF_F_LOCK) { 2463d0407baSopenharmony_ci /* lock 'ptr' and copy everything but lock */ 2473d0407baSopenharmony_ci copy_map_value_locked(map, value, ptr, true); 2483d0407baSopenharmony_ci } else { 2493d0407baSopenharmony_ci copy_map_value(map, value, ptr); 2503d0407baSopenharmony_ci } 2513d0407baSopenharmony_ci /* mask lock, since value wasn't zero inited */ 2523d0407baSopenharmony_ci check_and_init_map_lock(map, value); 2533d0407baSopenharmony_ci } 2543d0407baSopenharmony_ci rcu_read_unlock(); 2553d0407baSopenharmony_ci } 2563d0407baSopenharmony_ci 2573d0407baSopenharmony_ci bpf_enable_instrumentation(); 2583d0407baSopenharmony_ci maybe_wait_bpf_programs(map); 2593d0407baSopenharmony_ci 2603d0407baSopenharmony_ci return err; 2613d0407baSopenharmony_ci} 2623d0407baSopenharmony_ci 2633d0407baSopenharmony_cistatic void *_bpf_map_area_alloc(u64 size, int numa_node, bool mmapable) 2643d0407baSopenharmony_ci{ 2653d0407baSopenharmony_ci /* We really just want to fail instead of triggering OOM killer 2663d0407baSopenharmony_ci * under memory pressure, therefore we set __GFP_NORETRY to kmalloc, 2673d0407baSopenharmony_ci * which is used for lower order allocation requests. 2683d0407baSopenharmony_ci * 2693d0407baSopenharmony_ci * It has been observed that higher order allocation requests done by 2703d0407baSopenharmony_ci * vmalloc with __GFP_NORETRY being set might fail due to not trying 2713d0407baSopenharmony_ci * to reclaim memory from the page cache, thus we set 2723d0407baSopenharmony_ci * __GFP_RETRY_MAYFAIL to avoid such situations. 2733d0407baSopenharmony_ci */ 2743d0407baSopenharmony_ci 2753d0407baSopenharmony_ci const gfp_t gfp = __GFP_NOWARN | __GFP_ZERO; 2763d0407baSopenharmony_ci unsigned int flags = 0; 2773d0407baSopenharmony_ci unsigned long align = 1; 2783d0407baSopenharmony_ci void *area; 2793d0407baSopenharmony_ci 2803d0407baSopenharmony_ci if (size >= SIZE_MAX) { 2813d0407baSopenharmony_ci return NULL; 2823d0407baSopenharmony_ci } 2833d0407baSopenharmony_ci 2843d0407baSopenharmony_ci /* kmalloc()'ed memory can't be mmap()'ed */ 2853d0407baSopenharmony_ci if (mmapable) { 2863d0407baSopenharmony_ci BUG_ON(!PAGE_ALIGNED(size)); 2873d0407baSopenharmony_ci align = SHMLBA; 2883d0407baSopenharmony_ci flags = VM_USERMAP; 2893d0407baSopenharmony_ci } else if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) { 2903d0407baSopenharmony_ci area = kmalloc_node(size, gfp | GFP_USER | __GFP_NORETRY, numa_node); 2913d0407baSopenharmony_ci if (area != NULL) { 2923d0407baSopenharmony_ci return area; 2933d0407baSopenharmony_ci } 2943d0407baSopenharmony_ci } 2953d0407baSopenharmony_ci 2963d0407baSopenharmony_ci return __vmalloc_node_range(size, align, VMALLOC_START, VMALLOC_END, gfp | GFP_KERNEL | __GFP_RETRY_MAYFAIL, 2973d0407baSopenharmony_ci PAGE_KERNEL, flags, numa_node, __builtin_return_address(0)); 2983d0407baSopenharmony_ci} 2993d0407baSopenharmony_ci 3003d0407baSopenharmony_civoid *bpf_map_area_alloc(u64 size, int numa_node) 3013d0407baSopenharmony_ci{ 3023d0407baSopenharmony_ci return _bpf_map_area_alloc(size, numa_node, false); 3033d0407baSopenharmony_ci} 3043d0407baSopenharmony_ci 3053d0407baSopenharmony_civoid *bpf_map_area_mmapable_alloc(u64 size, int numa_node) 3063d0407baSopenharmony_ci{ 3073d0407baSopenharmony_ci return _bpf_map_area_alloc(size, numa_node, true); 3083d0407baSopenharmony_ci} 3093d0407baSopenharmony_ci 3103d0407baSopenharmony_civoid bpf_map_area_free(void *area) 3113d0407baSopenharmony_ci{ 3123d0407baSopenharmony_ci kvfree(area); 3133d0407baSopenharmony_ci} 3143d0407baSopenharmony_ci 3153d0407baSopenharmony_cistatic u32 bpf_map_flags_retain_permanent(u32 flags) 3163d0407baSopenharmony_ci{ 3173d0407baSopenharmony_ci /* Some map creation flags are not tied to the map object but 3183d0407baSopenharmony_ci * rather to the map fd instead, so they have no meaning upon 3193d0407baSopenharmony_ci * map object inspection since multiple file descriptors with 3203d0407baSopenharmony_ci * different (access) properties can exist here. Thus, given 3213d0407baSopenharmony_ci * this has zero meaning for the map itself, lets clear these 3223d0407baSopenharmony_ci * from here. 3233d0407baSopenharmony_ci */ 3243d0407baSopenharmony_ci return flags & ~(BPF_F_RDONLY | BPF_F_WRONLY); 3253d0407baSopenharmony_ci} 3263d0407baSopenharmony_ci 3273d0407baSopenharmony_civoid bpf_map_init_from_attr(struct bpf_map *map, union bpf_attr *attr) 3283d0407baSopenharmony_ci{ 3293d0407baSopenharmony_ci map->map_type = attr->map_type; 3303d0407baSopenharmony_ci map->key_size = attr->key_size; 3313d0407baSopenharmony_ci map->value_size = attr->value_size; 3323d0407baSopenharmony_ci map->max_entries = attr->max_entries; 3333d0407baSopenharmony_ci map->map_flags = bpf_map_flags_retain_permanent(attr->map_flags); 3343d0407baSopenharmony_ci map->numa_node = bpf_map_attr_numa_node(attr); 3353d0407baSopenharmony_ci} 3363d0407baSopenharmony_ci 3373d0407baSopenharmony_cistatic int bpf_charge_memlock(struct user_struct *user, u32 pages) 3383d0407baSopenharmony_ci{ 3393d0407baSopenharmony_ci unsigned long memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; 3403d0407baSopenharmony_ci if (atomic_long_add_return(pages, &user->locked_vm) > memlock_limit) { 3413d0407baSopenharmony_ci atomic_long_sub(pages, &user->locked_vm); 3423d0407baSopenharmony_ci return -EPERM; 3433d0407baSopenharmony_ci } 3443d0407baSopenharmony_ci return 0; 3453d0407baSopenharmony_ci} 3463d0407baSopenharmony_ci 3473d0407baSopenharmony_cistatic void bpf_uncharge_memlock(struct user_struct *user, u32 pages) 3483d0407baSopenharmony_ci{ 3493d0407baSopenharmony_ci if (user) { 3503d0407baSopenharmony_ci atomic_long_sub(pages, &user->locked_vm); 3513d0407baSopenharmony_ci } 3523d0407baSopenharmony_ci} 3533d0407baSopenharmony_ci 3543d0407baSopenharmony_ciint bpf_map_charge_init(struct bpf_map_memory *mem, u64 size) 3553d0407baSopenharmony_ci{ 3563d0407baSopenharmony_ci u32 pages = round_up(size, PAGE_SIZE) >> PAGE_SHIFT; 3573d0407baSopenharmony_ci struct user_struct *user; 3583d0407baSopenharmony_ci int ret; 3593d0407baSopenharmony_ci 3603d0407baSopenharmony_ci if (size >= U32_MAX - PAGE_SIZE) { 3613d0407baSopenharmony_ci return -E2BIG; 3623d0407baSopenharmony_ci } 3633d0407baSopenharmony_ci 3643d0407baSopenharmony_ci user = get_current_user(); 3653d0407baSopenharmony_ci ret = bpf_charge_memlock(user, pages); 3663d0407baSopenharmony_ci if (ret) { 3673d0407baSopenharmony_ci free_uid(user); 3683d0407baSopenharmony_ci return ret; 3693d0407baSopenharmony_ci } 3703d0407baSopenharmony_ci 3713d0407baSopenharmony_ci mem->pages = pages; 3723d0407baSopenharmony_ci mem->user = user; 3733d0407baSopenharmony_ci 3743d0407baSopenharmony_ci return 0; 3753d0407baSopenharmony_ci} 3763d0407baSopenharmony_ci 3773d0407baSopenharmony_civoid bpf_map_charge_finish(struct bpf_map_memory *mem) 3783d0407baSopenharmony_ci{ 3793d0407baSopenharmony_ci bpf_uncharge_memlock(mem->user, mem->pages); 3803d0407baSopenharmony_ci free_uid(mem->user); 3813d0407baSopenharmony_ci} 3823d0407baSopenharmony_ci 3833d0407baSopenharmony_civoid bpf_map_charge_move(struct bpf_map_memory *dst, struct bpf_map_memory *src) 3843d0407baSopenharmony_ci{ 3853d0407baSopenharmony_ci *dst = *src; 3863d0407baSopenharmony_ci 3873d0407baSopenharmony_ci /* Make sure src will not be used for the redundant uncharging. */ 3883d0407baSopenharmony_ci memset(src, 0, sizeof(struct bpf_map_memory)); 3893d0407baSopenharmony_ci} 3903d0407baSopenharmony_ci 3913d0407baSopenharmony_ciint bpf_map_charge_memlock(struct bpf_map *map, u32 pages) 3923d0407baSopenharmony_ci{ 3933d0407baSopenharmony_ci int ret; 3943d0407baSopenharmony_ci 3953d0407baSopenharmony_ci ret = bpf_charge_memlock(map->memory.user, pages); 3963d0407baSopenharmony_ci if (ret) { 3973d0407baSopenharmony_ci return ret; 3983d0407baSopenharmony_ci } 3993d0407baSopenharmony_ci map->memory.pages += pages; 4003d0407baSopenharmony_ci return ret; 4013d0407baSopenharmony_ci} 4023d0407baSopenharmony_ci 4033d0407baSopenharmony_civoid bpf_map_uncharge_memlock(struct bpf_map *map, u32 pages) 4043d0407baSopenharmony_ci{ 4053d0407baSopenharmony_ci bpf_uncharge_memlock(map->memory.user, pages); 4063d0407baSopenharmony_ci map->memory.pages -= pages; 4073d0407baSopenharmony_ci} 4083d0407baSopenharmony_ci 4093d0407baSopenharmony_cistatic int bpf_map_alloc_id(struct bpf_map *map) 4103d0407baSopenharmony_ci{ 4113d0407baSopenharmony_ci int id; 4123d0407baSopenharmony_ci 4133d0407baSopenharmony_ci idr_preload(GFP_KERNEL); 4143d0407baSopenharmony_ci spin_lock_bh(&map_idr_lock); 4153d0407baSopenharmony_ci id = idr_alloc_cyclic(&map_idr, map, 1, INT_MAX, GFP_ATOMIC); 4163d0407baSopenharmony_ci if (id > 0) { 4173d0407baSopenharmony_ci map->id = id; 4183d0407baSopenharmony_ci } 4193d0407baSopenharmony_ci spin_unlock_bh(&map_idr_lock); 4203d0407baSopenharmony_ci idr_preload_end(); 4213d0407baSopenharmony_ci 4223d0407baSopenharmony_ci if (WARN_ON_ONCE(!id)) { 4233d0407baSopenharmony_ci return -ENOSPC; 4243d0407baSopenharmony_ci } 4253d0407baSopenharmony_ci 4263d0407baSopenharmony_ci return id > 0 ? 0 : id; 4273d0407baSopenharmony_ci} 4283d0407baSopenharmony_ci 4293d0407baSopenharmony_civoid bpf_map_free_id(struct bpf_map *map, bool do_idr_lock) 4303d0407baSopenharmony_ci{ 4313d0407baSopenharmony_ci unsigned long flags; 4323d0407baSopenharmony_ci 4333d0407baSopenharmony_ci /* Offloaded maps are removed from the IDR store when their device 4343d0407baSopenharmony_ci * disappears - even if someone holds an fd to them they are unusable, 4353d0407baSopenharmony_ci * the memory is gone, all ops will fail; they are simply waiting for 4363d0407baSopenharmony_ci * refcnt to drop to be freed. 4373d0407baSopenharmony_ci */ 4383d0407baSopenharmony_ci if (!map->id) { 4393d0407baSopenharmony_ci return; 4403d0407baSopenharmony_ci } 4413d0407baSopenharmony_ci 4423d0407baSopenharmony_ci if (do_idr_lock) { 4433d0407baSopenharmony_ci spin_lock_irqsave(&map_idr_lock, flags); 4443d0407baSopenharmony_ci } else { 4453d0407baSopenharmony_ci __acquire(&map_idr_lock); 4463d0407baSopenharmony_ci } 4473d0407baSopenharmony_ci 4483d0407baSopenharmony_ci idr_remove(&map_idr, map->id); 4493d0407baSopenharmony_ci map->id = 0; 4503d0407baSopenharmony_ci 4513d0407baSopenharmony_ci if (do_idr_lock) { 4523d0407baSopenharmony_ci spin_unlock_irqrestore(&map_idr_lock, flags); 4533d0407baSopenharmony_ci } else { 4543d0407baSopenharmony_ci __release(&map_idr_lock); 4553d0407baSopenharmony_ci } 4563d0407baSopenharmony_ci} 4573d0407baSopenharmony_ci 4583d0407baSopenharmony_ci/* called from workqueue */ 4593d0407baSopenharmony_cistatic void bpf_map_free_deferred(struct work_struct *work) 4603d0407baSopenharmony_ci{ 4613d0407baSopenharmony_ci struct bpf_map *map = container_of(work, struct bpf_map, work); 4623d0407baSopenharmony_ci struct bpf_map_memory mem; 4633d0407baSopenharmony_ci 4643d0407baSopenharmony_ci bpf_map_charge_move(&mem, &map->memory); 4653d0407baSopenharmony_ci security_bpf_map_free(map); 4663d0407baSopenharmony_ci /* implementation dependent freeing */ 4673d0407baSopenharmony_ci map->ops->map_free(map); 4683d0407baSopenharmony_ci bpf_map_charge_finish(&mem); 4693d0407baSopenharmony_ci} 4703d0407baSopenharmony_ci 4713d0407baSopenharmony_cistatic void bpf_map_put_uref(struct bpf_map *map) 4723d0407baSopenharmony_ci{ 4733d0407baSopenharmony_ci if (atomic64_dec_and_test(&map->usercnt)) { 4743d0407baSopenharmony_ci if (map->ops->map_release_uref) { 4753d0407baSopenharmony_ci map->ops->map_release_uref(map); 4763d0407baSopenharmony_ci } 4773d0407baSopenharmony_ci } 4783d0407baSopenharmony_ci} 4793d0407baSopenharmony_ci 4803d0407baSopenharmony_ci/* decrement map refcnt and schedule it for freeing via workqueue 4813d0407baSopenharmony_ci * (unrelying map implementation ops->map_free() might sleep) 4823d0407baSopenharmony_ci */ 4833d0407baSopenharmony_cistatic void _bpf_map_put(struct bpf_map *map, bool do_idr_lock) 4843d0407baSopenharmony_ci{ 4853d0407baSopenharmony_ci if (atomic64_dec_and_test(&map->refcnt)) { 4863d0407baSopenharmony_ci /* bpf_map_free_id() must be called first */ 4873d0407baSopenharmony_ci bpf_map_free_id(map, do_idr_lock); 4883d0407baSopenharmony_ci btf_put(map->btf); 4893d0407baSopenharmony_ci INIT_WORK(&map->work, bpf_map_free_deferred); 4903d0407baSopenharmony_ci schedule_work(&map->work); 4913d0407baSopenharmony_ci } 4923d0407baSopenharmony_ci} 4933d0407baSopenharmony_ci 4943d0407baSopenharmony_civoid bpf_map_put(struct bpf_map *map) 4953d0407baSopenharmony_ci{ 4963d0407baSopenharmony_ci _bpf_map_put(map, true); 4973d0407baSopenharmony_ci} 4983d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(bpf_map_put); 4993d0407baSopenharmony_ci 5003d0407baSopenharmony_civoid bpf_map_put_with_uref(struct bpf_map *map) 5013d0407baSopenharmony_ci{ 5023d0407baSopenharmony_ci bpf_map_put_uref(map); 5033d0407baSopenharmony_ci bpf_map_put(map); 5043d0407baSopenharmony_ci} 5053d0407baSopenharmony_ci 5063d0407baSopenharmony_cistatic int bpf_map_release(struct inode *inode, struct file *filp) 5073d0407baSopenharmony_ci{ 5083d0407baSopenharmony_ci struct bpf_map *map = filp->private_data; 5093d0407baSopenharmony_ci 5103d0407baSopenharmony_ci if (map->ops->map_release) { 5113d0407baSopenharmony_ci map->ops->map_release(map, filp); 5123d0407baSopenharmony_ci } 5133d0407baSopenharmony_ci 5143d0407baSopenharmony_ci bpf_map_put_with_uref(map); 5153d0407baSopenharmony_ci return 0; 5163d0407baSopenharmony_ci} 5173d0407baSopenharmony_ci 5183d0407baSopenharmony_cistatic fmode_t map_get_sys_perms(struct bpf_map *map, struct fd f) 5193d0407baSopenharmony_ci{ 5203d0407baSopenharmony_ci fmode_t mode = f.file->f_mode; 5213d0407baSopenharmony_ci 5223d0407baSopenharmony_ci /* Our file permissions may have been overridden by global 5233d0407baSopenharmony_ci * map permissions facing syscall side. 5243d0407baSopenharmony_ci */ 5253d0407baSopenharmony_ci if (READ_ONCE(map->frozen)) { 5263d0407baSopenharmony_ci mode &= ~FMODE_CAN_WRITE; 5273d0407baSopenharmony_ci } 5283d0407baSopenharmony_ci return mode; 5293d0407baSopenharmony_ci} 5303d0407baSopenharmony_ci 5313d0407baSopenharmony_ci#ifdef CONFIG_PROC_FS 5323d0407baSopenharmony_cistatic void bpf_map_show_fdinfo(struct seq_file *m, struct file *filp) 5333d0407baSopenharmony_ci{ 5343d0407baSopenharmony_ci const struct bpf_map *map = filp->private_data; 5353d0407baSopenharmony_ci const struct bpf_array *array; 5363d0407baSopenharmony_ci u32 type = 0, jited = 0; 5373d0407baSopenharmony_ci 5383d0407baSopenharmony_ci if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY) { 5393d0407baSopenharmony_ci array = container_of(map, struct bpf_array, map); 5403d0407baSopenharmony_ci spin_lock(&array->aux->owner.lock); 5413d0407baSopenharmony_ci type = array->aux->owner.type; 5423d0407baSopenharmony_ci jited = array->aux->owner.jited; 5433d0407baSopenharmony_ci spin_unlock(&array->aux->owner.lock); 5443d0407baSopenharmony_ci } 5453d0407baSopenharmony_ci 5463d0407baSopenharmony_ci seq_printf(m, 5473d0407baSopenharmony_ci "map_type:\t%u\n" 5483d0407baSopenharmony_ci "key_size:\t%u\n" 5493d0407baSopenharmony_ci "value_size:\t%u\n" 5503d0407baSopenharmony_ci "max_entries:\t%u\n" 5513d0407baSopenharmony_ci "map_flags:\t%#x\n" 5523d0407baSopenharmony_ci "memlock:\t%llu\n" 5533d0407baSopenharmony_ci "map_id:\t%u\n" 5543d0407baSopenharmony_ci "frozen:\t%u\n", 5553d0407baSopenharmony_ci map->map_type, map->key_size, map->value_size, map->max_entries, map->map_flags, 5563d0407baSopenharmony_ci map->memory.pages * 1ULL << PAGE_SHIFT, map->id, READ_ONCE(map->frozen)); 5573d0407baSopenharmony_ci if (type) { 5583d0407baSopenharmony_ci seq_printf(m, "owner_prog_type:\t%u\n", type); 5593d0407baSopenharmony_ci seq_printf(m, "owner_jited:\t%u\n", jited); 5603d0407baSopenharmony_ci } 5613d0407baSopenharmony_ci} 5623d0407baSopenharmony_ci#endif 5633d0407baSopenharmony_ci 5643d0407baSopenharmony_cistatic ssize_t bpf_dummy_read(struct file *filp, char __user *buf, size_t siz, loff_t *ppos) 5653d0407baSopenharmony_ci{ 5663d0407baSopenharmony_ci /* We need this handler such that alloc_file() enables 5673d0407baSopenharmony_ci * f_mode with FMODE_CAN_READ. 5683d0407baSopenharmony_ci */ 5693d0407baSopenharmony_ci return -EINVAL; 5703d0407baSopenharmony_ci} 5713d0407baSopenharmony_ci 5723d0407baSopenharmony_cistatic ssize_t bpf_dummy_write(struct file *filp, const char __user *buf, size_t siz, loff_t *ppos) 5733d0407baSopenharmony_ci{ 5743d0407baSopenharmony_ci /* We need this handler such that alloc_file() enables 5753d0407baSopenharmony_ci * f_mode with FMODE_CAN_WRITE. 5763d0407baSopenharmony_ci */ 5773d0407baSopenharmony_ci return -EINVAL; 5783d0407baSopenharmony_ci} 5793d0407baSopenharmony_ci 5803d0407baSopenharmony_ci/* called for any extra memory-mapped regions (except initial) */ 5813d0407baSopenharmony_cistatic void bpf_map_mmap_open(struct vm_area_struct *vma) 5823d0407baSopenharmony_ci{ 5833d0407baSopenharmony_ci struct bpf_map *map = vma->vm_file->private_data; 5843d0407baSopenharmony_ci 5853d0407baSopenharmony_ci if (vma->vm_flags & VM_MAYWRITE) { 5863d0407baSopenharmony_ci mutex_lock(&map->freeze_mutex); 5873d0407baSopenharmony_ci map->writecnt++; 5883d0407baSopenharmony_ci mutex_unlock(&map->freeze_mutex); 5893d0407baSopenharmony_ci } 5903d0407baSopenharmony_ci} 5913d0407baSopenharmony_ci 5923d0407baSopenharmony_ci/* called for all unmapped memory region (including initial) */ 5933d0407baSopenharmony_cistatic void bpf_map_mmap_close(struct vm_area_struct *vma) 5943d0407baSopenharmony_ci{ 5953d0407baSopenharmony_ci struct bpf_map *map = vma->vm_file->private_data; 5963d0407baSopenharmony_ci 5973d0407baSopenharmony_ci if (vma->vm_flags & VM_MAYWRITE) { 5983d0407baSopenharmony_ci mutex_lock(&map->freeze_mutex); 5993d0407baSopenharmony_ci map->writecnt--; 6003d0407baSopenharmony_ci mutex_unlock(&map->freeze_mutex); 6013d0407baSopenharmony_ci } 6023d0407baSopenharmony_ci} 6033d0407baSopenharmony_ci 6043d0407baSopenharmony_cistatic const struct vm_operations_struct bpf_map_default_vmops = { 6053d0407baSopenharmony_ci .open = bpf_map_mmap_open, 6063d0407baSopenharmony_ci .close = bpf_map_mmap_close, 6073d0407baSopenharmony_ci}; 6083d0407baSopenharmony_ci 6093d0407baSopenharmony_cistatic int bpf_map_mmap(struct file *filp, struct vm_area_struct *vma) 6103d0407baSopenharmony_ci{ 6113d0407baSopenharmony_ci struct bpf_map *map = filp->private_data; 6123d0407baSopenharmony_ci int err; 6133d0407baSopenharmony_ci 6143d0407baSopenharmony_ci if (!map->ops->map_mmap || map_value_has_spin_lock(map)) { 6153d0407baSopenharmony_ci return -ENOTSUPP; 6163d0407baSopenharmony_ci } 6173d0407baSopenharmony_ci 6183d0407baSopenharmony_ci if (!(vma->vm_flags & VM_SHARED)) { 6193d0407baSopenharmony_ci return -EINVAL; 6203d0407baSopenharmony_ci } 6213d0407baSopenharmony_ci 6223d0407baSopenharmony_ci mutex_lock(&map->freeze_mutex); 6233d0407baSopenharmony_ci 6243d0407baSopenharmony_ci if (vma->vm_flags & VM_WRITE) { 6253d0407baSopenharmony_ci if (map->frozen) { 6263d0407baSopenharmony_ci err = -EPERM; 6273d0407baSopenharmony_ci goto out; 6283d0407baSopenharmony_ci } 6293d0407baSopenharmony_ci /* map is meant to be read-only, so do not allow mapping as 6303d0407baSopenharmony_ci * writable, because it's possible to leak a writable page 6313d0407baSopenharmony_ci * reference and allows user-space to still modify it after 6323d0407baSopenharmony_ci * freezing, while verifier will assume contents do not change 6333d0407baSopenharmony_ci */ 6343d0407baSopenharmony_ci if (map->map_flags & BPF_F_RDONLY_PROG) { 6353d0407baSopenharmony_ci err = -EACCES; 6363d0407baSopenharmony_ci goto out; 6373d0407baSopenharmony_ci } 6383d0407baSopenharmony_ci } 6393d0407baSopenharmony_ci 6403d0407baSopenharmony_ci /* set default open/close callbacks */ 6413d0407baSopenharmony_ci vma->vm_ops = &bpf_map_default_vmops; 6423d0407baSopenharmony_ci vma->vm_private_data = map; 6433d0407baSopenharmony_ci vma->vm_flags &= ~VM_MAYEXEC; 6443d0407baSopenharmony_ci if (!(vma->vm_flags & VM_WRITE)) { 6453d0407baSopenharmony_ci /* disallow re-mapping with PROT_WRITE */ 6463d0407baSopenharmony_ci vma->vm_flags &= ~VM_MAYWRITE; 6473d0407baSopenharmony_ci } 6483d0407baSopenharmony_ci 6493d0407baSopenharmony_ci err = map->ops->map_mmap(map, vma); 6503d0407baSopenharmony_ci if (err) { 6513d0407baSopenharmony_ci goto out; 6523d0407baSopenharmony_ci } 6533d0407baSopenharmony_ci 6543d0407baSopenharmony_ci if (vma->vm_flags & VM_MAYWRITE) { 6553d0407baSopenharmony_ci map->writecnt++; 6563d0407baSopenharmony_ci } 6573d0407baSopenharmony_ciout: 6583d0407baSopenharmony_ci mutex_unlock(&map->freeze_mutex); 6593d0407baSopenharmony_ci return err; 6603d0407baSopenharmony_ci} 6613d0407baSopenharmony_ci 6623d0407baSopenharmony_cistatic __poll_t bpf_map_poll(struct file *filp, struct poll_table_struct *pts) 6633d0407baSopenharmony_ci{ 6643d0407baSopenharmony_ci struct bpf_map *map = filp->private_data; 6653d0407baSopenharmony_ci 6663d0407baSopenharmony_ci if (map->ops->map_poll) { 6673d0407baSopenharmony_ci return map->ops->map_poll(map, filp, pts); 6683d0407baSopenharmony_ci } 6693d0407baSopenharmony_ci 6703d0407baSopenharmony_ci return EPOLLERR; 6713d0407baSopenharmony_ci} 6723d0407baSopenharmony_ci 6733d0407baSopenharmony_ciconst struct file_operations bpf_map_fops = { 6743d0407baSopenharmony_ci#ifdef CONFIG_PROC_FS 6753d0407baSopenharmony_ci .show_fdinfo = bpf_map_show_fdinfo, 6763d0407baSopenharmony_ci#endif 6773d0407baSopenharmony_ci .release = bpf_map_release, 6783d0407baSopenharmony_ci .read = bpf_dummy_read, 6793d0407baSopenharmony_ci .write = bpf_dummy_write, 6803d0407baSopenharmony_ci .mmap = bpf_map_mmap, 6813d0407baSopenharmony_ci .poll = bpf_map_poll, 6823d0407baSopenharmony_ci}; 6833d0407baSopenharmony_ci 6843d0407baSopenharmony_ciint bpf_map_new_fd(struct bpf_map *map, int flags) 6853d0407baSopenharmony_ci{ 6863d0407baSopenharmony_ci int ret; 6873d0407baSopenharmony_ci 6883d0407baSopenharmony_ci ret = security_bpf_map(map, OPEN_FMODE(flags)); 6893d0407baSopenharmony_ci if (ret < 0) { 6903d0407baSopenharmony_ci return ret; 6913d0407baSopenharmony_ci } 6923d0407baSopenharmony_ci 6933d0407baSopenharmony_ci return anon_inode_getfd("bpf-map", &bpf_map_fops, map, flags | O_CLOEXEC); 6943d0407baSopenharmony_ci} 6953d0407baSopenharmony_ci 6963d0407baSopenharmony_ciint bpf_get_file_flag(int flags) 6973d0407baSopenharmony_ci{ 6983d0407baSopenharmony_ci if ((flags & BPF_F_RDONLY) && (flags & BPF_F_WRONLY)) { 6993d0407baSopenharmony_ci return -EINVAL; 7003d0407baSopenharmony_ci } 7013d0407baSopenharmony_ci if (flags & BPF_F_RDONLY) { 7023d0407baSopenharmony_ci return O_RDONLY; 7033d0407baSopenharmony_ci } 7043d0407baSopenharmony_ci if (flags & BPF_F_WRONLY) { 7053d0407baSopenharmony_ci return O_WRONLY; 7063d0407baSopenharmony_ci } 7073d0407baSopenharmony_ci return O_RDWR; 7083d0407baSopenharmony_ci} 7093d0407baSopenharmony_ci 7103d0407baSopenharmony_ci/* helper macro to check that unused fields 'union bpf_attr' are zero */ 7113d0407baSopenharmony_ci#define CHECK_ATTR(CMD) \ 7123d0407baSopenharmony_ci memchr_inv((void *)&attr->CMD##_LAST_FIELD + sizeof(attr->CMD##_LAST_FIELD), 0, \ 7133d0407baSopenharmony_ci sizeof(*attr) - offsetof(union bpf_attr, CMD##_LAST_FIELD) - sizeof(attr->CMD##_LAST_FIELD)) != NULL 7143d0407baSopenharmony_ci 7153d0407baSopenharmony_ci/* dst and src must have at least "size" number of bytes. 7163d0407baSopenharmony_ci * Return strlen on success and < 0 on error. 7173d0407baSopenharmony_ci */ 7183d0407baSopenharmony_ciint bpf_obj_name_cpy(char *dst, const char *src, unsigned int size) 7193d0407baSopenharmony_ci{ 7203d0407baSopenharmony_ci const char *end = src + size; 7213d0407baSopenharmony_ci const char *orig_src = src; 7223d0407baSopenharmony_ci 7233d0407baSopenharmony_ci memset(dst, 0, size); 7243d0407baSopenharmony_ci /* Copy all isalnum(), '_' and '.' chars. */ 7253d0407baSopenharmony_ci while (src < end && *src) { 7263d0407baSopenharmony_ci if (!isalnum(*src) && *src != '_' && *src != '.') { 7273d0407baSopenharmony_ci return -EINVAL; 7283d0407baSopenharmony_ci } 7293d0407baSopenharmony_ci *dst++ = *src++; 7303d0407baSopenharmony_ci } 7313d0407baSopenharmony_ci 7323d0407baSopenharmony_ci /* No '\0' found in "size" number of bytes */ 7333d0407baSopenharmony_ci if (src == end) { 7343d0407baSopenharmony_ci return -EINVAL; 7353d0407baSopenharmony_ci } 7363d0407baSopenharmony_ci 7373d0407baSopenharmony_ci return src - orig_src; 7383d0407baSopenharmony_ci} 7393d0407baSopenharmony_ci 7403d0407baSopenharmony_ciint map_check_no_btf(const struct bpf_map *map, const struct btf *btf, const struct btf_type *key_type, 7413d0407baSopenharmony_ci const struct btf_type *value_type) 7423d0407baSopenharmony_ci{ 7433d0407baSopenharmony_ci return -ENOTSUPP; 7443d0407baSopenharmony_ci} 7453d0407baSopenharmony_ci 7463d0407baSopenharmony_cistatic int map_check_btf(struct bpf_map *map, const struct btf *btf, u32 btf_key_id, u32 btf_value_id) 7473d0407baSopenharmony_ci{ 7483d0407baSopenharmony_ci const struct btf_type *key_type, *value_type; 7493d0407baSopenharmony_ci u32 key_size, value_size; 7503d0407baSopenharmony_ci int ret = 0; 7513d0407baSopenharmony_ci 7523d0407baSopenharmony_ci /* Some maps allow key to be unspecified. */ 7533d0407baSopenharmony_ci if (btf_key_id) { 7543d0407baSopenharmony_ci key_type = btf_type_id_size(btf, &btf_key_id, &key_size); 7553d0407baSopenharmony_ci if (!key_type || key_size != map->key_size) { 7563d0407baSopenharmony_ci return -EINVAL; 7573d0407baSopenharmony_ci } 7583d0407baSopenharmony_ci } else { 7593d0407baSopenharmony_ci key_type = btf_type_by_id(btf, 0); 7603d0407baSopenharmony_ci if (!map->ops->map_check_btf) { 7613d0407baSopenharmony_ci return -EINVAL; 7623d0407baSopenharmony_ci } 7633d0407baSopenharmony_ci } 7643d0407baSopenharmony_ci 7653d0407baSopenharmony_ci value_type = btf_type_id_size(btf, &btf_value_id, &value_size); 7663d0407baSopenharmony_ci if (!value_type || value_size != map->value_size) { 7673d0407baSopenharmony_ci return -EINVAL; 7683d0407baSopenharmony_ci } 7693d0407baSopenharmony_ci 7703d0407baSopenharmony_ci map->spin_lock_off = btf_find_spin_lock(btf, value_type); 7713d0407baSopenharmony_ci 7723d0407baSopenharmony_ci if (map_value_has_spin_lock(map)) { 7733d0407baSopenharmony_ci if (map->map_flags & BPF_F_RDONLY_PROG) { 7743d0407baSopenharmony_ci return -EACCES; 7753d0407baSopenharmony_ci } 7763d0407baSopenharmony_ci if (map->map_type != BPF_MAP_TYPE_HASH && map->map_type != BPF_MAP_TYPE_ARRAY && 7773d0407baSopenharmony_ci map->map_type != BPF_MAP_TYPE_CGROUP_STORAGE && map->map_type != BPF_MAP_TYPE_SK_STORAGE && 7783d0407baSopenharmony_ci map->map_type != BPF_MAP_TYPE_INODE_STORAGE) { 7793d0407baSopenharmony_ci return -ENOTSUPP; 7803d0407baSopenharmony_ci } 7813d0407baSopenharmony_ci if (map->spin_lock_off + sizeof(struct bpf_spin_lock) > map->value_size) { 7823d0407baSopenharmony_ci WARN_ONCE(1, "verifier bug spin_lock_off %d value_size %d\n", map->spin_lock_off, map->value_size); 7833d0407baSopenharmony_ci return -EFAULT; 7843d0407baSopenharmony_ci } 7853d0407baSopenharmony_ci } 7863d0407baSopenharmony_ci 7873d0407baSopenharmony_ci if (map->ops->map_check_btf) { 7883d0407baSopenharmony_ci ret = map->ops->map_check_btf(map, btf, key_type, value_type); 7893d0407baSopenharmony_ci } 7903d0407baSopenharmony_ci 7913d0407baSopenharmony_ci return ret; 7923d0407baSopenharmony_ci} 7933d0407baSopenharmony_ci 7943d0407baSopenharmony_ci#define BPF_MAP_CREATE_LAST_FIELD btf_vmlinux_value_type_id 7953d0407baSopenharmony_ci/* called via syscall */ 7963d0407baSopenharmony_cistatic int map_create(union bpf_attr *attr) 7973d0407baSopenharmony_ci{ 7983d0407baSopenharmony_ci int numa_node = bpf_map_attr_numa_node(attr); 7993d0407baSopenharmony_ci struct bpf_map_memory mem; 8003d0407baSopenharmony_ci struct bpf_map *map; 8013d0407baSopenharmony_ci int f_flags; 8023d0407baSopenharmony_ci int err; 8033d0407baSopenharmony_ci 8043d0407baSopenharmony_ci err = CHECK_ATTR(BPF_MAP_CREATE); 8053d0407baSopenharmony_ci if (err) { 8063d0407baSopenharmony_ci return -EINVAL; 8073d0407baSopenharmony_ci } 8083d0407baSopenharmony_ci 8093d0407baSopenharmony_ci if (attr->btf_vmlinux_value_type_id) { 8103d0407baSopenharmony_ci if (attr->map_type != BPF_MAP_TYPE_STRUCT_OPS || attr->btf_key_type_id || attr->btf_value_type_id) { 8113d0407baSopenharmony_ci return -EINVAL; 8123d0407baSopenharmony_ci } 8133d0407baSopenharmony_ci } else if (attr->btf_key_type_id && !attr->btf_value_type_id) { 8143d0407baSopenharmony_ci return -EINVAL; 8153d0407baSopenharmony_ci } 8163d0407baSopenharmony_ci 8173d0407baSopenharmony_ci f_flags = bpf_get_file_flag(attr->map_flags); 8183d0407baSopenharmony_ci if (f_flags < 0) { 8193d0407baSopenharmony_ci return f_flags; 8203d0407baSopenharmony_ci } 8213d0407baSopenharmony_ci 8223d0407baSopenharmony_ci if (numa_node != NUMA_NO_NODE && ((unsigned int)numa_node >= nr_node_ids || !node_online(numa_node))) { 8233d0407baSopenharmony_ci return -EINVAL; 8243d0407baSopenharmony_ci } 8253d0407baSopenharmony_ci 8263d0407baSopenharmony_ci /* find map type and init map: hashtable vs rbtree vs bloom vs ... */ 8273d0407baSopenharmony_ci map = find_and_alloc_map(attr); 8283d0407baSopenharmony_ci if (IS_ERR(map)) { 8293d0407baSopenharmony_ci return PTR_ERR(map); 8303d0407baSopenharmony_ci } 8313d0407baSopenharmony_ci 8323d0407baSopenharmony_ci err = bpf_obj_name_cpy(map->name, attr->map_name, sizeof(attr->map_name)); 8333d0407baSopenharmony_ci if (err < 0) { 8343d0407baSopenharmony_ci goto free_map; 8353d0407baSopenharmony_ci } 8363d0407baSopenharmony_ci 8373d0407baSopenharmony_ci atomic64_set(&map->refcnt, 1); 8383d0407baSopenharmony_ci atomic64_set(&map->usercnt, 1); 8393d0407baSopenharmony_ci mutex_init(&map->freeze_mutex); 8403d0407baSopenharmony_ci 8413d0407baSopenharmony_ci map->spin_lock_off = -EINVAL; 8423d0407baSopenharmony_ci if (attr->btf_key_type_id || attr->btf_value_type_id || 8433d0407baSopenharmony_ci /* Even the map's value is a kernel's struct, 8443d0407baSopenharmony_ci * the bpf_prog.o must have BTF to begin with 8453d0407baSopenharmony_ci * to figure out the corresponding kernel's 8463d0407baSopenharmony_ci * counter part. Thus, attr->btf_fd has 8473d0407baSopenharmony_ci * to be valid also. 8483d0407baSopenharmony_ci */ 8493d0407baSopenharmony_ci attr->btf_vmlinux_value_type_id) { 8503d0407baSopenharmony_ci struct btf *btf; 8513d0407baSopenharmony_ci 8523d0407baSopenharmony_ci btf = btf_get_by_fd(attr->btf_fd); 8533d0407baSopenharmony_ci if (IS_ERR(btf)) { 8543d0407baSopenharmony_ci err = PTR_ERR(btf); 8553d0407baSopenharmony_ci goto free_map; 8563d0407baSopenharmony_ci } 8573d0407baSopenharmony_ci map->btf = btf; 8583d0407baSopenharmony_ci 8593d0407baSopenharmony_ci if (attr->btf_value_type_id) { 8603d0407baSopenharmony_ci err = map_check_btf(map, btf, attr->btf_key_type_id, attr->btf_value_type_id); 8613d0407baSopenharmony_ci if (err) { 8623d0407baSopenharmony_ci goto free_map; 8633d0407baSopenharmony_ci } 8643d0407baSopenharmony_ci } 8653d0407baSopenharmony_ci 8663d0407baSopenharmony_ci map->btf_key_type_id = attr->btf_key_type_id; 8673d0407baSopenharmony_ci map->btf_value_type_id = attr->btf_value_type_id; 8683d0407baSopenharmony_ci map->btf_vmlinux_value_type_id = attr->btf_vmlinux_value_type_id; 8693d0407baSopenharmony_ci } 8703d0407baSopenharmony_ci 8713d0407baSopenharmony_ci err = security_bpf_map_alloc(map); 8723d0407baSopenharmony_ci if (err) { 8733d0407baSopenharmony_ci goto free_map; 8743d0407baSopenharmony_ci } 8753d0407baSopenharmony_ci 8763d0407baSopenharmony_ci err = bpf_map_alloc_id(map); 8773d0407baSopenharmony_ci if (err) { 8783d0407baSopenharmony_ci goto free_map_sec; 8793d0407baSopenharmony_ci } 8803d0407baSopenharmony_ci 8813d0407baSopenharmony_ci err = bpf_map_new_fd(map, f_flags); 8823d0407baSopenharmony_ci if (err < 0) { 8833d0407baSopenharmony_ci /* failed to allocate fd. 8843d0407baSopenharmony_ci * bpf_map_put_with_uref() is needed because the above 8853d0407baSopenharmony_ci * bpf_map_alloc_id() has published the map 8863d0407baSopenharmony_ci * to the userspace and the userspace may 8873d0407baSopenharmony_ci * have refcnt-ed it through BPF_MAP_GET_FD_BY_ID. 8883d0407baSopenharmony_ci */ 8893d0407baSopenharmony_ci bpf_map_put_with_uref(map); 8903d0407baSopenharmony_ci return err; 8913d0407baSopenharmony_ci } 8923d0407baSopenharmony_ci 8933d0407baSopenharmony_ci return err; 8943d0407baSopenharmony_ci 8953d0407baSopenharmony_cifree_map_sec: 8963d0407baSopenharmony_ci security_bpf_map_free(map); 8973d0407baSopenharmony_cifree_map: 8983d0407baSopenharmony_ci btf_put(map->btf); 8993d0407baSopenharmony_ci bpf_map_charge_move(&mem, &map->memory); 9003d0407baSopenharmony_ci map->ops->map_free(map); 9013d0407baSopenharmony_ci bpf_map_charge_finish(&mem); 9023d0407baSopenharmony_ci return err; 9033d0407baSopenharmony_ci} 9043d0407baSopenharmony_ci 9053d0407baSopenharmony_ci/* if error is returned, fd is released. 9063d0407baSopenharmony_ci * On success caller should complete fd access with matching fdput() 9073d0407baSopenharmony_ci */ 9083d0407baSopenharmony_cistruct bpf_map *__bpf_map_get(struct fd f) 9093d0407baSopenharmony_ci{ 9103d0407baSopenharmony_ci if (!f.file) { 9113d0407baSopenharmony_ci return ERR_PTR(-EBADF); 9123d0407baSopenharmony_ci } 9133d0407baSopenharmony_ci if (f.file->f_op != &bpf_map_fops) { 9143d0407baSopenharmony_ci fdput(f); 9153d0407baSopenharmony_ci return ERR_PTR(-EINVAL); 9163d0407baSopenharmony_ci } 9173d0407baSopenharmony_ci 9183d0407baSopenharmony_ci return f.file->private_data; 9193d0407baSopenharmony_ci} 9203d0407baSopenharmony_ci 9213d0407baSopenharmony_civoid bpf_map_inc(struct bpf_map *map) 9223d0407baSopenharmony_ci{ 9233d0407baSopenharmony_ci atomic64_inc(&map->refcnt); 9243d0407baSopenharmony_ci} 9253d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(bpf_map_inc); 9263d0407baSopenharmony_ci 9273d0407baSopenharmony_civoid bpf_map_inc_with_uref(struct bpf_map *map) 9283d0407baSopenharmony_ci{ 9293d0407baSopenharmony_ci atomic64_inc(&map->refcnt); 9303d0407baSopenharmony_ci atomic64_inc(&map->usercnt); 9313d0407baSopenharmony_ci} 9323d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(bpf_map_inc_with_uref); 9333d0407baSopenharmony_ci 9343d0407baSopenharmony_cistruct bpf_map *bpf_map_get(u32 ufd) 9353d0407baSopenharmony_ci{ 9363d0407baSopenharmony_ci struct fd f = fdget(ufd); 9373d0407baSopenharmony_ci struct bpf_map *map; 9383d0407baSopenharmony_ci 9393d0407baSopenharmony_ci map = __bpf_map_get(f); 9403d0407baSopenharmony_ci if (IS_ERR(map)) { 9413d0407baSopenharmony_ci return map; 9423d0407baSopenharmony_ci } 9433d0407baSopenharmony_ci 9443d0407baSopenharmony_ci bpf_map_inc(map); 9453d0407baSopenharmony_ci fdput(f); 9463d0407baSopenharmony_ci 9473d0407baSopenharmony_ci return map; 9483d0407baSopenharmony_ci} 9493d0407baSopenharmony_ci 9503d0407baSopenharmony_cistruct bpf_map *bpf_map_get_with_uref(u32 ufd) 9513d0407baSopenharmony_ci{ 9523d0407baSopenharmony_ci struct fd f = fdget(ufd); 9533d0407baSopenharmony_ci struct bpf_map *map; 9543d0407baSopenharmony_ci 9553d0407baSopenharmony_ci map = __bpf_map_get(f); 9563d0407baSopenharmony_ci if (IS_ERR(map)) { 9573d0407baSopenharmony_ci return map; 9583d0407baSopenharmony_ci } 9593d0407baSopenharmony_ci 9603d0407baSopenharmony_ci bpf_map_inc_with_uref(map); 9613d0407baSopenharmony_ci fdput(f); 9623d0407baSopenharmony_ci 9633d0407baSopenharmony_ci return map; 9643d0407baSopenharmony_ci} 9653d0407baSopenharmony_ci 9663d0407baSopenharmony_ci/* map_idr_lock should have been held */ 9673d0407baSopenharmony_cistatic struct bpf_map *_bpf_map_inc_not_zero(struct bpf_map *map, bool uref) 9683d0407baSopenharmony_ci{ 9693d0407baSopenharmony_ci int refold; 9703d0407baSopenharmony_ci 9713d0407baSopenharmony_ci refold = atomic64_fetch_add_unless(&map->refcnt, 1, 0); 9723d0407baSopenharmony_ci if (!refold) { 9733d0407baSopenharmony_ci return ERR_PTR(-ENOENT); 9743d0407baSopenharmony_ci } 9753d0407baSopenharmony_ci if (uref) { 9763d0407baSopenharmony_ci atomic64_inc(&map->usercnt); 9773d0407baSopenharmony_ci } 9783d0407baSopenharmony_ci 9793d0407baSopenharmony_ci return map; 9803d0407baSopenharmony_ci} 9813d0407baSopenharmony_ci 9823d0407baSopenharmony_cistruct bpf_map *bpf_map_inc_not_zero(struct bpf_map *map) 9833d0407baSopenharmony_ci{ 9843d0407baSopenharmony_ci spin_lock_bh(&map_idr_lock); 9853d0407baSopenharmony_ci map = _bpf_map_inc_not_zero(map, false); 9863d0407baSopenharmony_ci spin_unlock_bh(&map_idr_lock); 9873d0407baSopenharmony_ci 9883d0407baSopenharmony_ci return map; 9893d0407baSopenharmony_ci} 9903d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(bpf_map_inc_not_zero); 9913d0407baSopenharmony_ci 9923d0407baSopenharmony_ciint __weak bpf_stackmap_copy(struct bpf_map *map, void *key, void *value) 9933d0407baSopenharmony_ci{ 9943d0407baSopenharmony_ci return -ENOTSUPP; 9953d0407baSopenharmony_ci} 9963d0407baSopenharmony_ci 9973d0407baSopenharmony_cistatic void *__bpf_copy_key(void __user *ukey, u64 key_size) 9983d0407baSopenharmony_ci{ 9993d0407baSopenharmony_ci if (key_size) { 10003d0407baSopenharmony_ci return memdup_user(ukey, key_size); 10013d0407baSopenharmony_ci } 10023d0407baSopenharmony_ci 10033d0407baSopenharmony_ci if (ukey) { 10043d0407baSopenharmony_ci return ERR_PTR(-EINVAL); 10053d0407baSopenharmony_ci } 10063d0407baSopenharmony_ci 10073d0407baSopenharmony_ci return NULL; 10083d0407baSopenharmony_ci} 10093d0407baSopenharmony_ci 10103d0407baSopenharmony_ci/* last field in 'union bpf_attr' used by this command */ 10113d0407baSopenharmony_ci#define BPF_MAP_LOOKUP_ELEM_LAST_FIELD flags 10123d0407baSopenharmony_ci 10133d0407baSopenharmony_cistatic int map_lookup_elem(union bpf_attr *attr) 10143d0407baSopenharmony_ci{ 10153d0407baSopenharmony_ci void __user *ukey = u64_to_user_ptr(attr->key); 10163d0407baSopenharmony_ci void __user *uvalue = u64_to_user_ptr(attr->value); 10173d0407baSopenharmony_ci int ufd = attr->map_fd; 10183d0407baSopenharmony_ci struct bpf_map *map; 10193d0407baSopenharmony_ci void *key, *value; 10203d0407baSopenharmony_ci u32 value_size; 10213d0407baSopenharmony_ci struct fd f; 10223d0407baSopenharmony_ci int err; 10233d0407baSopenharmony_ci 10243d0407baSopenharmony_ci if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM)) { 10253d0407baSopenharmony_ci return -EINVAL; 10263d0407baSopenharmony_ci } 10273d0407baSopenharmony_ci 10283d0407baSopenharmony_ci if (attr->flags & ~BPF_F_LOCK) { 10293d0407baSopenharmony_ci return -EINVAL; 10303d0407baSopenharmony_ci } 10313d0407baSopenharmony_ci 10323d0407baSopenharmony_ci f = fdget(ufd); 10333d0407baSopenharmony_ci map = __bpf_map_get(f); 10343d0407baSopenharmony_ci if (IS_ERR(map)) { 10353d0407baSopenharmony_ci return PTR_ERR(map); 10363d0407baSopenharmony_ci } 10373d0407baSopenharmony_ci if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ)) { 10383d0407baSopenharmony_ci err = -EPERM; 10393d0407baSopenharmony_ci goto err_put; 10403d0407baSopenharmony_ci } 10413d0407baSopenharmony_ci 10423d0407baSopenharmony_ci if ((attr->flags & BPF_F_LOCK) && !map_value_has_spin_lock(map)) { 10433d0407baSopenharmony_ci err = -EINVAL; 10443d0407baSopenharmony_ci goto err_put; 10453d0407baSopenharmony_ci } 10463d0407baSopenharmony_ci 10473d0407baSopenharmony_ci key = __bpf_copy_key(ukey, map->key_size); 10483d0407baSopenharmony_ci if (IS_ERR(key)) { 10493d0407baSopenharmony_ci err = PTR_ERR(key); 10503d0407baSopenharmony_ci goto err_put; 10513d0407baSopenharmony_ci } 10523d0407baSopenharmony_ci 10533d0407baSopenharmony_ci value_size = bpf_map_value_size(map); 10543d0407baSopenharmony_ci 10553d0407baSopenharmony_ci err = -ENOMEM; 10563d0407baSopenharmony_ci value = kmalloc(value_size, GFP_USER | __GFP_NOWARN); 10573d0407baSopenharmony_ci if (!value) { 10583d0407baSopenharmony_ci goto free_key; 10593d0407baSopenharmony_ci } 10603d0407baSopenharmony_ci 10613d0407baSopenharmony_ci err = bpf_map_copy_value(map, key, value, attr->flags); 10623d0407baSopenharmony_ci if (err) { 10633d0407baSopenharmony_ci goto free_value; 10643d0407baSopenharmony_ci } 10653d0407baSopenharmony_ci 10663d0407baSopenharmony_ci err = -EFAULT; 10673d0407baSopenharmony_ci if (copy_to_user(uvalue, value, value_size) != 0) { 10683d0407baSopenharmony_ci goto free_value; 10693d0407baSopenharmony_ci } 10703d0407baSopenharmony_ci 10713d0407baSopenharmony_ci err = 0; 10723d0407baSopenharmony_ci 10733d0407baSopenharmony_cifree_value: 10743d0407baSopenharmony_ci kfree(value); 10753d0407baSopenharmony_cifree_key: 10763d0407baSopenharmony_ci kfree(key); 10773d0407baSopenharmony_cierr_put: 10783d0407baSopenharmony_ci fdput(f); 10793d0407baSopenharmony_ci return err; 10803d0407baSopenharmony_ci} 10813d0407baSopenharmony_ci 10823d0407baSopenharmony_ci#define BPF_MAP_UPDATE_ELEM_LAST_FIELD flags 10833d0407baSopenharmony_ci 10843d0407baSopenharmony_cistatic int map_update_elem(union bpf_attr *attr) 10853d0407baSopenharmony_ci{ 10863d0407baSopenharmony_ci void __user *ukey = u64_to_user_ptr(attr->key); 10873d0407baSopenharmony_ci void __user *uvalue = u64_to_user_ptr(attr->value); 10883d0407baSopenharmony_ci int ufd = attr->map_fd; 10893d0407baSopenharmony_ci struct bpf_map *map; 10903d0407baSopenharmony_ci void *key, *value; 10913d0407baSopenharmony_ci u32 value_size; 10923d0407baSopenharmony_ci struct fd f; 10933d0407baSopenharmony_ci int err; 10943d0407baSopenharmony_ci 10953d0407baSopenharmony_ci if (CHECK_ATTR(BPF_MAP_UPDATE_ELEM)) { 10963d0407baSopenharmony_ci return -EINVAL; 10973d0407baSopenharmony_ci } 10983d0407baSopenharmony_ci 10993d0407baSopenharmony_ci f = fdget(ufd); 11003d0407baSopenharmony_ci map = __bpf_map_get(f); 11013d0407baSopenharmony_ci if (IS_ERR(map)) { 11023d0407baSopenharmony_ci return PTR_ERR(map); 11033d0407baSopenharmony_ci } 11043d0407baSopenharmony_ci if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) { 11053d0407baSopenharmony_ci err = -EPERM; 11063d0407baSopenharmony_ci goto err_put; 11073d0407baSopenharmony_ci } 11083d0407baSopenharmony_ci 11093d0407baSopenharmony_ci if ((attr->flags & BPF_F_LOCK) && !map_value_has_spin_lock(map)) { 11103d0407baSopenharmony_ci err = -EINVAL; 11113d0407baSopenharmony_ci goto err_put; 11123d0407baSopenharmony_ci } 11133d0407baSopenharmony_ci 11143d0407baSopenharmony_ci key = __bpf_copy_key(ukey, map->key_size); 11153d0407baSopenharmony_ci if (IS_ERR(key)) { 11163d0407baSopenharmony_ci err = PTR_ERR(key); 11173d0407baSopenharmony_ci goto err_put; 11183d0407baSopenharmony_ci } 11193d0407baSopenharmony_ci 11203d0407baSopenharmony_ci if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH || 11213d0407baSopenharmony_ci map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY || map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) { 11223d0407baSopenharmony_ci value_size = round_up(map->value_size, 0x8) * num_possible_cpus(); 11233d0407baSopenharmony_ci } else { 11243d0407baSopenharmony_ci value_size = map->value_size; 11253d0407baSopenharmony_ci } 11263d0407baSopenharmony_ci 11273d0407baSopenharmony_ci err = -ENOMEM; 11283d0407baSopenharmony_ci value = kmalloc(value_size, GFP_USER | __GFP_NOWARN); 11293d0407baSopenharmony_ci if (!value) { 11303d0407baSopenharmony_ci goto free_key; 11313d0407baSopenharmony_ci } 11323d0407baSopenharmony_ci 11333d0407baSopenharmony_ci err = -EFAULT; 11343d0407baSopenharmony_ci if (copy_from_user(value, uvalue, value_size) != 0) { 11353d0407baSopenharmony_ci goto free_value; 11363d0407baSopenharmony_ci } 11373d0407baSopenharmony_ci 11383d0407baSopenharmony_ci err = bpf_map_update_value(map, f, key, value, attr->flags); 11393d0407baSopenharmony_ci 11403d0407baSopenharmony_cifree_value: 11413d0407baSopenharmony_ci kfree(value); 11423d0407baSopenharmony_cifree_key: 11433d0407baSopenharmony_ci kfree(key); 11443d0407baSopenharmony_cierr_put: 11453d0407baSopenharmony_ci fdput(f); 11463d0407baSopenharmony_ci return err; 11473d0407baSopenharmony_ci} 11483d0407baSopenharmony_ci 11493d0407baSopenharmony_ci#define BPF_MAP_DELETE_ELEM_LAST_FIELD key 11503d0407baSopenharmony_ci 11513d0407baSopenharmony_cistatic int map_delete_elem(union bpf_attr *attr) 11523d0407baSopenharmony_ci{ 11533d0407baSopenharmony_ci void __user *ukey = u64_to_user_ptr(attr->key); 11543d0407baSopenharmony_ci int ufd = attr->map_fd; 11553d0407baSopenharmony_ci struct bpf_map *map; 11563d0407baSopenharmony_ci struct fd f; 11573d0407baSopenharmony_ci void *key; 11583d0407baSopenharmony_ci int err; 11593d0407baSopenharmony_ci 11603d0407baSopenharmony_ci if (CHECK_ATTR(BPF_MAP_DELETE_ELEM)) { 11613d0407baSopenharmony_ci return -EINVAL; 11623d0407baSopenharmony_ci } 11633d0407baSopenharmony_ci 11643d0407baSopenharmony_ci f = fdget(ufd); 11653d0407baSopenharmony_ci map = __bpf_map_get(f); 11663d0407baSopenharmony_ci if (IS_ERR(map)) { 11673d0407baSopenharmony_ci return PTR_ERR(map); 11683d0407baSopenharmony_ci } 11693d0407baSopenharmony_ci if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) { 11703d0407baSopenharmony_ci err = -EPERM; 11713d0407baSopenharmony_ci goto err_put; 11723d0407baSopenharmony_ci } 11733d0407baSopenharmony_ci 11743d0407baSopenharmony_ci key = __bpf_copy_key(ukey, map->key_size); 11753d0407baSopenharmony_ci if (IS_ERR(key)) { 11763d0407baSopenharmony_ci err = PTR_ERR(key); 11773d0407baSopenharmony_ci goto err_put; 11783d0407baSopenharmony_ci } 11793d0407baSopenharmony_ci 11803d0407baSopenharmony_ci if (bpf_map_is_dev_bound(map)) { 11813d0407baSopenharmony_ci err = bpf_map_offload_delete_elem(map, key); 11823d0407baSopenharmony_ci goto out; 11833d0407baSopenharmony_ci } else if (IS_FD_PROG_ARRAY(map) || map->map_type == BPF_MAP_TYPE_STRUCT_OPS) { 11843d0407baSopenharmony_ci /* These maps require sleepable context */ 11853d0407baSopenharmony_ci err = map->ops->map_delete_elem(map, key); 11863d0407baSopenharmony_ci goto out; 11873d0407baSopenharmony_ci } 11883d0407baSopenharmony_ci 11893d0407baSopenharmony_ci bpf_disable_instrumentation(); 11903d0407baSopenharmony_ci rcu_read_lock(); 11913d0407baSopenharmony_ci err = map->ops->map_delete_elem(map, key); 11923d0407baSopenharmony_ci rcu_read_unlock(); 11933d0407baSopenharmony_ci bpf_enable_instrumentation(); 11943d0407baSopenharmony_ci maybe_wait_bpf_programs(map); 11953d0407baSopenharmony_ciout: 11963d0407baSopenharmony_ci kfree(key); 11973d0407baSopenharmony_cierr_put: 11983d0407baSopenharmony_ci fdput(f); 11993d0407baSopenharmony_ci return err; 12003d0407baSopenharmony_ci} 12013d0407baSopenharmony_ci 12023d0407baSopenharmony_ci/* last field in 'union bpf_attr' used by this command */ 12033d0407baSopenharmony_ci#define BPF_MAP_GET_NEXT_KEY_LAST_FIELD next_key 12043d0407baSopenharmony_ci 12053d0407baSopenharmony_cistatic int map_get_next_key(union bpf_attr *attr) 12063d0407baSopenharmony_ci{ 12073d0407baSopenharmony_ci void __user *ukey = u64_to_user_ptr(attr->key); 12083d0407baSopenharmony_ci void __user *unext_key = u64_to_user_ptr(attr->next_key); 12093d0407baSopenharmony_ci int ufd = attr->map_fd; 12103d0407baSopenharmony_ci struct bpf_map *map; 12113d0407baSopenharmony_ci void *key, *next_key; 12123d0407baSopenharmony_ci struct fd f; 12133d0407baSopenharmony_ci int err; 12143d0407baSopenharmony_ci 12153d0407baSopenharmony_ci if (CHECK_ATTR(BPF_MAP_GET_NEXT_KEY)) { 12163d0407baSopenharmony_ci return -EINVAL; 12173d0407baSopenharmony_ci } 12183d0407baSopenharmony_ci 12193d0407baSopenharmony_ci f = fdget(ufd); 12203d0407baSopenharmony_ci map = __bpf_map_get(f); 12213d0407baSopenharmony_ci if (IS_ERR(map)) { 12223d0407baSopenharmony_ci return PTR_ERR(map); 12233d0407baSopenharmony_ci } 12243d0407baSopenharmony_ci if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ)) { 12253d0407baSopenharmony_ci err = -EPERM; 12263d0407baSopenharmony_ci goto err_put; 12273d0407baSopenharmony_ci } 12283d0407baSopenharmony_ci 12293d0407baSopenharmony_ci if (ukey) { 12303d0407baSopenharmony_ci key = __bpf_copy_key(ukey, map->key_size); 12313d0407baSopenharmony_ci if (IS_ERR(key)) { 12323d0407baSopenharmony_ci err = PTR_ERR(key); 12333d0407baSopenharmony_ci goto err_put; 12343d0407baSopenharmony_ci } 12353d0407baSopenharmony_ci } else { 12363d0407baSopenharmony_ci key = NULL; 12373d0407baSopenharmony_ci } 12383d0407baSopenharmony_ci 12393d0407baSopenharmony_ci err = -ENOMEM; 12403d0407baSopenharmony_ci next_key = kmalloc(map->key_size, GFP_USER); 12413d0407baSopenharmony_ci if (!next_key) { 12423d0407baSopenharmony_ci goto free_key; 12433d0407baSopenharmony_ci } 12443d0407baSopenharmony_ci 12453d0407baSopenharmony_ci if (bpf_map_is_dev_bound(map)) { 12463d0407baSopenharmony_ci err = bpf_map_offload_get_next_key(map, key, next_key); 12473d0407baSopenharmony_ci goto out; 12483d0407baSopenharmony_ci } 12493d0407baSopenharmony_ci 12503d0407baSopenharmony_ci rcu_read_lock(); 12513d0407baSopenharmony_ci err = map->ops->map_get_next_key(map, key, next_key); 12523d0407baSopenharmony_ci rcu_read_unlock(); 12533d0407baSopenharmony_ciout: 12543d0407baSopenharmony_ci if (err) { 12553d0407baSopenharmony_ci goto free_next_key; 12563d0407baSopenharmony_ci } 12573d0407baSopenharmony_ci 12583d0407baSopenharmony_ci err = -EFAULT; 12593d0407baSopenharmony_ci if (copy_to_user(unext_key, next_key, map->key_size) != 0) { 12603d0407baSopenharmony_ci goto free_next_key; 12613d0407baSopenharmony_ci } 12623d0407baSopenharmony_ci 12633d0407baSopenharmony_ci err = 0; 12643d0407baSopenharmony_ci 12653d0407baSopenharmony_cifree_next_key: 12663d0407baSopenharmony_ci kfree(next_key); 12673d0407baSopenharmony_cifree_key: 12683d0407baSopenharmony_ci kfree(key); 12693d0407baSopenharmony_cierr_put: 12703d0407baSopenharmony_ci fdput(f); 12713d0407baSopenharmony_ci return err; 12723d0407baSopenharmony_ci} 12733d0407baSopenharmony_ci 12743d0407baSopenharmony_ciint generic_map_delete_batch(struct bpf_map *map, const union bpf_attr *attr, union bpf_attr __user *uattr) 12753d0407baSopenharmony_ci{ 12763d0407baSopenharmony_ci void __user *keys = u64_to_user_ptr(attr->batch.keys); 12773d0407baSopenharmony_ci u32 cp, max_count; 12783d0407baSopenharmony_ci int err = 0; 12793d0407baSopenharmony_ci void *key; 12803d0407baSopenharmony_ci 12813d0407baSopenharmony_ci if (attr->batch.elem_flags & ~BPF_F_LOCK) { 12823d0407baSopenharmony_ci return -EINVAL; 12833d0407baSopenharmony_ci } 12843d0407baSopenharmony_ci 12853d0407baSopenharmony_ci if ((attr->batch.elem_flags & BPF_F_LOCK) && !map_value_has_spin_lock(map)) { 12863d0407baSopenharmony_ci return -EINVAL; 12873d0407baSopenharmony_ci } 12883d0407baSopenharmony_ci 12893d0407baSopenharmony_ci max_count = attr->batch.count; 12903d0407baSopenharmony_ci if (!max_count) { 12913d0407baSopenharmony_ci return 0; 12923d0407baSopenharmony_ci } 12933d0407baSopenharmony_ci 12943d0407baSopenharmony_ci key = kmalloc(map->key_size, GFP_USER | __GFP_NOWARN); 12953d0407baSopenharmony_ci if (!key) { 12963d0407baSopenharmony_ci return -ENOMEM; 12973d0407baSopenharmony_ci } 12983d0407baSopenharmony_ci 12993d0407baSopenharmony_ci for (cp = 0; cp < max_count; cp++) { 13003d0407baSopenharmony_ci err = -EFAULT; 13013d0407baSopenharmony_ci if (copy_from_user(key, keys + cp * map->key_size, map->key_size)) { 13023d0407baSopenharmony_ci break; 13033d0407baSopenharmony_ci } 13043d0407baSopenharmony_ci 13053d0407baSopenharmony_ci if (bpf_map_is_dev_bound(map)) { 13063d0407baSopenharmony_ci err = bpf_map_offload_delete_elem(map, key); 13073d0407baSopenharmony_ci break; 13083d0407baSopenharmony_ci } 13093d0407baSopenharmony_ci 13103d0407baSopenharmony_ci bpf_disable_instrumentation(); 13113d0407baSopenharmony_ci rcu_read_lock(); 13123d0407baSopenharmony_ci err = map->ops->map_delete_elem(map, key); 13133d0407baSopenharmony_ci rcu_read_unlock(); 13143d0407baSopenharmony_ci bpf_enable_instrumentation(); 13153d0407baSopenharmony_ci maybe_wait_bpf_programs(map); 13163d0407baSopenharmony_ci if (err) { 13173d0407baSopenharmony_ci break; 13183d0407baSopenharmony_ci } 13193d0407baSopenharmony_ci } 13203d0407baSopenharmony_ci if (copy_to_user(&uattr->batch.count, &cp, sizeof(cp))) { 13213d0407baSopenharmony_ci err = -EFAULT; 13223d0407baSopenharmony_ci } 13233d0407baSopenharmony_ci 13243d0407baSopenharmony_ci kfree(key); 13253d0407baSopenharmony_ci return err; 13263d0407baSopenharmony_ci} 13273d0407baSopenharmony_ci 13283d0407baSopenharmony_ciint generic_map_update_batch(struct bpf_map *map, const union bpf_attr *attr, union bpf_attr __user *uattr) 13293d0407baSopenharmony_ci{ 13303d0407baSopenharmony_ci void __user *values = u64_to_user_ptr(attr->batch.values); 13313d0407baSopenharmony_ci void __user *keys = u64_to_user_ptr(attr->batch.keys); 13323d0407baSopenharmony_ci u32 value_size, cp, max_count; 13333d0407baSopenharmony_ci int ufd = attr->batch.map_fd; 13343d0407baSopenharmony_ci void *key, *value; 13353d0407baSopenharmony_ci struct fd f; 13363d0407baSopenharmony_ci int err = 0; 13373d0407baSopenharmony_ci 13383d0407baSopenharmony_ci if (attr->batch.elem_flags & ~BPF_F_LOCK) { 13393d0407baSopenharmony_ci return -EINVAL; 13403d0407baSopenharmony_ci } 13413d0407baSopenharmony_ci 13423d0407baSopenharmony_ci if ((attr->batch.elem_flags & BPF_F_LOCK) && !map_value_has_spin_lock(map)) { 13433d0407baSopenharmony_ci return -EINVAL; 13443d0407baSopenharmony_ci } 13453d0407baSopenharmony_ci 13463d0407baSopenharmony_ci value_size = bpf_map_value_size(map); 13473d0407baSopenharmony_ci 13483d0407baSopenharmony_ci max_count = attr->batch.count; 13493d0407baSopenharmony_ci if (!max_count) { 13503d0407baSopenharmony_ci return 0; 13513d0407baSopenharmony_ci } 13523d0407baSopenharmony_ci 13533d0407baSopenharmony_ci key = kmalloc(map->key_size, GFP_USER | __GFP_NOWARN); 13543d0407baSopenharmony_ci if (!key) { 13553d0407baSopenharmony_ci return -ENOMEM; 13563d0407baSopenharmony_ci } 13573d0407baSopenharmony_ci 13583d0407baSopenharmony_ci value = kmalloc(value_size, GFP_USER | __GFP_NOWARN); 13593d0407baSopenharmony_ci if (!value) { 13603d0407baSopenharmony_ci kfree(key); 13613d0407baSopenharmony_ci return -ENOMEM; 13623d0407baSopenharmony_ci } 13633d0407baSopenharmony_ci 13643d0407baSopenharmony_ci f = fdget(ufd); /* bpf_map_do_batch() guarantees ufd is valid */ 13653d0407baSopenharmony_ci for (cp = 0; cp < max_count; cp++) { 13663d0407baSopenharmony_ci err = -EFAULT; 13673d0407baSopenharmony_ci if (copy_from_user(key, keys + cp * map->key_size, map->key_size) || 13683d0407baSopenharmony_ci copy_from_user(value, values + cp * value_size, value_size)) { 13693d0407baSopenharmony_ci break; 13703d0407baSopenharmony_ci } 13713d0407baSopenharmony_ci 13723d0407baSopenharmony_ci err = bpf_map_update_value(map, f, key, value, attr->batch.elem_flags); 13733d0407baSopenharmony_ci 13743d0407baSopenharmony_ci if (err) { 13753d0407baSopenharmony_ci break; 13763d0407baSopenharmony_ci cond_resched(); 13773d0407baSopenharmony_ci } 13783d0407baSopenharmony_ci } 13793d0407baSopenharmony_ci 13803d0407baSopenharmony_ci if (copy_to_user(&uattr->batch.count, &cp, sizeof(cp))) { 13813d0407baSopenharmony_ci err = -EFAULT; 13823d0407baSopenharmony_ci } 13833d0407baSopenharmony_ci 13843d0407baSopenharmony_ci kfree(value); 13853d0407baSopenharmony_ci kfree(key); 13863d0407baSopenharmony_ci fdput(f); 13873d0407baSopenharmony_ci return err; 13883d0407baSopenharmony_ci} 13893d0407baSopenharmony_ci 13903d0407baSopenharmony_ci#define MAP_LOOKUP_RETRIES 3 13913d0407baSopenharmony_ci 13923d0407baSopenharmony_ciint generic_map_lookup_batch(struct bpf_map *map, const union bpf_attr *attr, union bpf_attr __user *uattr) 13933d0407baSopenharmony_ci{ 13943d0407baSopenharmony_ci void __user *uobatch = u64_to_user_ptr(attr->batch.out_batch); 13953d0407baSopenharmony_ci void __user *ubatch = u64_to_user_ptr(attr->batch.in_batch); 13963d0407baSopenharmony_ci void __user *values = u64_to_user_ptr(attr->batch.values); 13973d0407baSopenharmony_ci void __user *keys = u64_to_user_ptr(attr->batch.keys); 13983d0407baSopenharmony_ci void *buf, *buf_prevkey, *prev_key, *key, *value; 13993d0407baSopenharmony_ci int err, retry = MAP_LOOKUP_RETRIES; 14003d0407baSopenharmony_ci u32 value_size, cp, max_count; 14013d0407baSopenharmony_ci 14023d0407baSopenharmony_ci if (attr->batch.elem_flags & ~BPF_F_LOCK) { 14033d0407baSopenharmony_ci return -EINVAL; 14043d0407baSopenharmony_ci } 14053d0407baSopenharmony_ci 14063d0407baSopenharmony_ci if ((attr->batch.elem_flags & BPF_F_LOCK) && !map_value_has_spin_lock(map)) { 14073d0407baSopenharmony_ci return -EINVAL; 14083d0407baSopenharmony_ci } 14093d0407baSopenharmony_ci 14103d0407baSopenharmony_ci value_size = bpf_map_value_size(map); 14113d0407baSopenharmony_ci 14123d0407baSopenharmony_ci max_count = attr->batch.count; 14133d0407baSopenharmony_ci if (!max_count) { 14143d0407baSopenharmony_ci return 0; 14153d0407baSopenharmony_ci } 14163d0407baSopenharmony_ci 14173d0407baSopenharmony_ci if (put_user(0, &uattr->batch.count)) { 14183d0407baSopenharmony_ci return -EFAULT; 14193d0407baSopenharmony_ci } 14203d0407baSopenharmony_ci 14213d0407baSopenharmony_ci buf_prevkey = kmalloc(map->key_size, GFP_USER | __GFP_NOWARN); 14223d0407baSopenharmony_ci if (!buf_prevkey) { 14233d0407baSopenharmony_ci return -ENOMEM; 14243d0407baSopenharmony_ci } 14253d0407baSopenharmony_ci 14263d0407baSopenharmony_ci buf = kmalloc(map->key_size + value_size, GFP_USER | __GFP_NOWARN); 14273d0407baSopenharmony_ci if (!buf) { 14283d0407baSopenharmony_ci kfree(buf_prevkey); 14293d0407baSopenharmony_ci return -ENOMEM; 14303d0407baSopenharmony_ci } 14313d0407baSopenharmony_ci 14323d0407baSopenharmony_ci err = -EFAULT; 14333d0407baSopenharmony_ci prev_key = NULL; 14343d0407baSopenharmony_ci if (ubatch && copy_from_user(buf_prevkey, ubatch, map->key_size)) { 14353d0407baSopenharmony_ci goto free_buf; 14363d0407baSopenharmony_ci } 14373d0407baSopenharmony_ci key = buf; 14383d0407baSopenharmony_ci value = key + map->key_size; 14393d0407baSopenharmony_ci if (ubatch) { 14403d0407baSopenharmony_ci prev_key = buf_prevkey; 14413d0407baSopenharmony_ci } 14423d0407baSopenharmony_ci 14433d0407baSopenharmony_ci for (cp = 0; cp < max_count;) { 14443d0407baSopenharmony_ci rcu_read_lock(); 14453d0407baSopenharmony_ci err = map->ops->map_get_next_key(map, prev_key, key); 14463d0407baSopenharmony_ci rcu_read_unlock(); 14473d0407baSopenharmony_ci if (err) { 14483d0407baSopenharmony_ci break; 14493d0407baSopenharmony_ci } 14503d0407baSopenharmony_ci err = bpf_map_copy_value(map, key, value, attr->batch.elem_flags); 14513d0407baSopenharmony_ci 14523d0407baSopenharmony_ci if (err == -ENOENT) { 14533d0407baSopenharmony_ci if (retry) { 14543d0407baSopenharmony_ci retry--; 14553d0407baSopenharmony_ci continue; 14563d0407baSopenharmony_ci } 14573d0407baSopenharmony_ci err = -EINTR; 14583d0407baSopenharmony_ci break; 14593d0407baSopenharmony_ci } 14603d0407baSopenharmony_ci 14613d0407baSopenharmony_ci if (err) { 14623d0407baSopenharmony_ci goto free_buf; 14633d0407baSopenharmony_ci } 14643d0407baSopenharmony_ci 14653d0407baSopenharmony_ci if (copy_to_user(keys + cp * map->key_size, key, map->key_size)) { 14663d0407baSopenharmony_ci err = -EFAULT; 14673d0407baSopenharmony_ci goto free_buf; 14683d0407baSopenharmony_ci } 14693d0407baSopenharmony_ci if (copy_to_user(values + cp * value_size, value, value_size)) { 14703d0407baSopenharmony_ci err = -EFAULT; 14713d0407baSopenharmony_ci goto free_buf; 14723d0407baSopenharmony_ci } 14733d0407baSopenharmony_ci 14743d0407baSopenharmony_ci if (!prev_key) { 14753d0407baSopenharmony_ci prev_key = buf_prevkey; 14763d0407baSopenharmony_ci } 14773d0407baSopenharmony_ci 14783d0407baSopenharmony_ci swap(prev_key, key); 14793d0407baSopenharmony_ci retry = MAP_LOOKUP_RETRIES; 14803d0407baSopenharmony_ci cp++; 14813d0407baSopenharmony_ci cond_resched(); 14823d0407baSopenharmony_ci } 14833d0407baSopenharmony_ci 14843d0407baSopenharmony_ci if (err == -EFAULT) { 14853d0407baSopenharmony_ci goto free_buf; 14863d0407baSopenharmony_ci } 14873d0407baSopenharmony_ci 14883d0407baSopenharmony_ci if ((copy_to_user(&uattr->batch.count, &cp, sizeof(cp)) || 14893d0407baSopenharmony_ci (cp && copy_to_user(uobatch, prev_key, map->key_size)))) { 14903d0407baSopenharmony_ci err = -EFAULT; 14913d0407baSopenharmony_ci } 14923d0407baSopenharmony_ci 14933d0407baSopenharmony_cifree_buf: 14943d0407baSopenharmony_ci kfree(buf_prevkey); 14953d0407baSopenharmony_ci kfree(buf); 14963d0407baSopenharmony_ci return err; 14973d0407baSopenharmony_ci} 14983d0407baSopenharmony_ci 14993d0407baSopenharmony_ci#define BPF_MAP_LOOKUP_AND_DELETE_ELEM_LAST_FIELD value 15003d0407baSopenharmony_ci 15013d0407baSopenharmony_cistatic int map_lookup_and_delete_elem(union bpf_attr *attr) 15023d0407baSopenharmony_ci{ 15033d0407baSopenharmony_ci void __user *ukey = u64_to_user_ptr(attr->key); 15043d0407baSopenharmony_ci void __user *uvalue = u64_to_user_ptr(attr->value); 15053d0407baSopenharmony_ci int ufd = attr->map_fd; 15063d0407baSopenharmony_ci struct bpf_map *map; 15073d0407baSopenharmony_ci void *key, *value; 15083d0407baSopenharmony_ci u32 value_size; 15093d0407baSopenharmony_ci struct fd f; 15103d0407baSopenharmony_ci int err; 15113d0407baSopenharmony_ci 15123d0407baSopenharmony_ci if (CHECK_ATTR(BPF_MAP_LOOKUP_AND_DELETE_ELEM)) { 15133d0407baSopenharmony_ci return -EINVAL; 15143d0407baSopenharmony_ci } 15153d0407baSopenharmony_ci 15163d0407baSopenharmony_ci f = fdget(ufd); 15173d0407baSopenharmony_ci map = __bpf_map_get(f); 15183d0407baSopenharmony_ci if (IS_ERR(map)) { 15193d0407baSopenharmony_ci return PTR_ERR(map); 15203d0407baSopenharmony_ci } 15213d0407baSopenharmony_ci if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ) || !(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) { 15223d0407baSopenharmony_ci err = -EPERM; 15233d0407baSopenharmony_ci goto err_put; 15243d0407baSopenharmony_ci } 15253d0407baSopenharmony_ci 15263d0407baSopenharmony_ci key = __bpf_copy_key(ukey, map->key_size); 15273d0407baSopenharmony_ci if (IS_ERR(key)) { 15283d0407baSopenharmony_ci err = PTR_ERR(key); 15293d0407baSopenharmony_ci goto err_put; 15303d0407baSopenharmony_ci } 15313d0407baSopenharmony_ci 15323d0407baSopenharmony_ci value_size = map->value_size; 15333d0407baSopenharmony_ci 15343d0407baSopenharmony_ci err = -ENOMEM; 15353d0407baSopenharmony_ci value = kmalloc(value_size, GFP_USER | __GFP_NOWARN); 15363d0407baSopenharmony_ci if (!value) { 15373d0407baSopenharmony_ci goto free_key; 15383d0407baSopenharmony_ci } 15393d0407baSopenharmony_ci 15403d0407baSopenharmony_ci if (map->map_type == BPF_MAP_TYPE_QUEUE || map->map_type == BPF_MAP_TYPE_STACK) { 15413d0407baSopenharmony_ci err = map->ops->map_pop_elem(map, value); 15423d0407baSopenharmony_ci } else { 15433d0407baSopenharmony_ci err = -ENOTSUPP; 15443d0407baSopenharmony_ci } 15453d0407baSopenharmony_ci 15463d0407baSopenharmony_ci if (err) { 15473d0407baSopenharmony_ci goto free_value; 15483d0407baSopenharmony_ci } 15493d0407baSopenharmony_ci 15503d0407baSopenharmony_ci if (copy_to_user(uvalue, value, value_size) != 0) { 15513d0407baSopenharmony_ci err = -EFAULT; 15523d0407baSopenharmony_ci goto free_value; 15533d0407baSopenharmony_ci } 15543d0407baSopenharmony_ci 15553d0407baSopenharmony_ci err = 0; 15563d0407baSopenharmony_ci 15573d0407baSopenharmony_cifree_value: 15583d0407baSopenharmony_ci kfree(value); 15593d0407baSopenharmony_cifree_key: 15603d0407baSopenharmony_ci kfree(key); 15613d0407baSopenharmony_cierr_put: 15623d0407baSopenharmony_ci fdput(f); 15633d0407baSopenharmony_ci return err; 15643d0407baSopenharmony_ci} 15653d0407baSopenharmony_ci 15663d0407baSopenharmony_ci#define BPF_MAP_FREEZE_LAST_FIELD map_fd 15673d0407baSopenharmony_ci 15683d0407baSopenharmony_cistatic int map_freeze(const union bpf_attr *attr) 15693d0407baSopenharmony_ci{ 15703d0407baSopenharmony_ci int err = 0, ufd = attr->map_fd; 15713d0407baSopenharmony_ci struct bpf_map *map; 15723d0407baSopenharmony_ci struct fd f; 15733d0407baSopenharmony_ci 15743d0407baSopenharmony_ci if (CHECK_ATTR(BPF_MAP_FREEZE)) { 15753d0407baSopenharmony_ci return -EINVAL; 15763d0407baSopenharmony_ci } 15773d0407baSopenharmony_ci 15783d0407baSopenharmony_ci f = fdget(ufd); 15793d0407baSopenharmony_ci map = __bpf_map_get(f); 15803d0407baSopenharmony_ci if (IS_ERR(map)) { 15813d0407baSopenharmony_ci return PTR_ERR(map); 15823d0407baSopenharmony_ci } 15833d0407baSopenharmony_ci 15843d0407baSopenharmony_ci if (map->map_type == BPF_MAP_TYPE_STRUCT_OPS) { 15853d0407baSopenharmony_ci fdput(f); 15863d0407baSopenharmony_ci return -ENOTSUPP; 15873d0407baSopenharmony_ci } 15883d0407baSopenharmony_ci 15893d0407baSopenharmony_ci mutex_lock(&map->freeze_mutex); 15903d0407baSopenharmony_ci 15913d0407baSopenharmony_ci if (map->writecnt) { 15923d0407baSopenharmony_ci err = -EBUSY; 15933d0407baSopenharmony_ci goto err_put; 15943d0407baSopenharmony_ci } 15953d0407baSopenharmony_ci if (READ_ONCE(map->frozen)) { 15963d0407baSopenharmony_ci err = -EBUSY; 15973d0407baSopenharmony_ci goto err_put; 15983d0407baSopenharmony_ci } 15993d0407baSopenharmony_ci if (!bpf_capable()) { 16003d0407baSopenharmony_ci err = -EPERM; 16013d0407baSopenharmony_ci goto err_put; 16023d0407baSopenharmony_ci } 16033d0407baSopenharmony_ci 16043d0407baSopenharmony_ci WRITE_ONCE(map->frozen, true); 16053d0407baSopenharmony_cierr_put: 16063d0407baSopenharmony_ci mutex_unlock(&map->freeze_mutex); 16073d0407baSopenharmony_ci fdput(f); 16083d0407baSopenharmony_ci return err; 16093d0407baSopenharmony_ci} 16103d0407baSopenharmony_ci 16113d0407baSopenharmony_cistatic const struct bpf_prog_ops *const bpf_prog_types[] = { 16123d0407baSopenharmony_ci#define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) [_id] = &_name##_prog_ops, 16133d0407baSopenharmony_ci#define BPF_MAP_TYPE(_id, _ops) 16143d0407baSopenharmony_ci#define BPF_LINK_TYPE(_id, _name) 16153d0407baSopenharmony_ci#include <linux/bpf_types.h> 16163d0407baSopenharmony_ci#undef BPF_PROG_TYPE 16173d0407baSopenharmony_ci#undef BPF_MAP_TYPE 16183d0407baSopenharmony_ci#undef BPF_LINK_TYPE 16193d0407baSopenharmony_ci}; 16203d0407baSopenharmony_ci 16213d0407baSopenharmony_cistatic int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog) 16223d0407baSopenharmony_ci{ 16233d0407baSopenharmony_ci const struct bpf_prog_ops *ops; 16243d0407baSopenharmony_ci 16253d0407baSopenharmony_ci if (type >= ARRAY_SIZE(bpf_prog_types)) { 16263d0407baSopenharmony_ci return -EINVAL; 16273d0407baSopenharmony_ci } 16283d0407baSopenharmony_ci type = array_index_nospec(type, ARRAY_SIZE(bpf_prog_types)); 16293d0407baSopenharmony_ci ops = bpf_prog_types[type]; 16303d0407baSopenharmony_ci if (!ops) { 16313d0407baSopenharmony_ci return -EINVAL; 16323d0407baSopenharmony_ci } 16333d0407baSopenharmony_ci 16343d0407baSopenharmony_ci if (!bpf_prog_is_dev_bound(prog->aux)) { 16353d0407baSopenharmony_ci prog->aux->ops = ops; 16363d0407baSopenharmony_ci } else { 16373d0407baSopenharmony_ci prog->aux->ops = &bpf_offload_prog_ops; 16383d0407baSopenharmony_ci } 16393d0407baSopenharmony_ci prog->type = type; 16403d0407baSopenharmony_ci return 0; 16413d0407baSopenharmony_ci} 16423d0407baSopenharmony_ci 16433d0407baSopenharmony_cienum bpf_audit { 16443d0407baSopenharmony_ci BPF_AUDIT_LOAD, 16453d0407baSopenharmony_ci BPF_AUDIT_UNLOAD, 16463d0407baSopenharmony_ci BPF_AUDIT_MAX, 16473d0407baSopenharmony_ci}; 16483d0407baSopenharmony_ci 16493d0407baSopenharmony_cistatic const char *const bpf_audit_str[BPF_AUDIT_MAX] = { 16503d0407baSopenharmony_ci [BPF_AUDIT_LOAD] = "LOAD", 16513d0407baSopenharmony_ci [BPF_AUDIT_UNLOAD] = "UNLOAD", 16523d0407baSopenharmony_ci}; 16533d0407baSopenharmony_ci 16543d0407baSopenharmony_cistatic void bpf_audit_prog(const struct bpf_prog *prog, unsigned int op) 16553d0407baSopenharmony_ci{ 16563d0407baSopenharmony_ci struct audit_context *ctx = NULL; 16573d0407baSopenharmony_ci struct audit_buffer *ab; 16583d0407baSopenharmony_ci 16593d0407baSopenharmony_ci if (WARN_ON_ONCE(op >= BPF_AUDIT_MAX)) { 16603d0407baSopenharmony_ci return; 16613d0407baSopenharmony_ci } 16623d0407baSopenharmony_ci if (audit_enabled == AUDIT_OFF) { 16633d0407baSopenharmony_ci return; 16643d0407baSopenharmony_ci } 16653d0407baSopenharmony_ci if (op == BPF_AUDIT_LOAD) { 16663d0407baSopenharmony_ci ctx = audit_context(); 16673d0407baSopenharmony_ci } 16683d0407baSopenharmony_ci ab = audit_log_start(ctx, GFP_ATOMIC, AUDIT_BPF); 16693d0407baSopenharmony_ci if (unlikely(!ab)) { 16703d0407baSopenharmony_ci return; 16713d0407baSopenharmony_ci } 16723d0407baSopenharmony_ci audit_log_format(ab, "prog-id=%u op=%s", prog->aux->id, bpf_audit_str[op]); 16733d0407baSopenharmony_ci audit_log_end(ab); 16743d0407baSopenharmony_ci} 16753d0407baSopenharmony_ci 16763d0407baSopenharmony_ciint __bpf_prog_charge(struct user_struct *user, u32 pages) 16773d0407baSopenharmony_ci{ 16783d0407baSopenharmony_ci unsigned long memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; 16793d0407baSopenharmony_ci unsigned long user_bufs; 16803d0407baSopenharmony_ci 16813d0407baSopenharmony_ci if (user) { 16823d0407baSopenharmony_ci user_bufs = atomic_long_add_return(pages, &user->locked_vm); 16833d0407baSopenharmony_ci if (user_bufs > memlock_limit) { 16843d0407baSopenharmony_ci atomic_long_sub(pages, &user->locked_vm); 16853d0407baSopenharmony_ci return -EPERM; 16863d0407baSopenharmony_ci } 16873d0407baSopenharmony_ci } 16883d0407baSopenharmony_ci 16893d0407baSopenharmony_ci return 0; 16903d0407baSopenharmony_ci} 16913d0407baSopenharmony_ci 16923d0407baSopenharmony_civoid __bpf_prog_uncharge(struct user_struct *user, u32 pages) 16933d0407baSopenharmony_ci{ 16943d0407baSopenharmony_ci if (user) { 16953d0407baSopenharmony_ci atomic_long_sub(pages, &user->locked_vm); 16963d0407baSopenharmony_ci } 16973d0407baSopenharmony_ci} 16983d0407baSopenharmony_ci 16993d0407baSopenharmony_cistatic int bpf_prog_charge_memlock(struct bpf_prog *prog) 17003d0407baSopenharmony_ci{ 17013d0407baSopenharmony_ci struct user_struct *user = get_current_user(); 17023d0407baSopenharmony_ci int ret; 17033d0407baSopenharmony_ci 17043d0407baSopenharmony_ci ret = __bpf_prog_charge(user, prog->pages); 17053d0407baSopenharmony_ci if (ret) { 17063d0407baSopenharmony_ci free_uid(user); 17073d0407baSopenharmony_ci return ret; 17083d0407baSopenharmony_ci } 17093d0407baSopenharmony_ci 17103d0407baSopenharmony_ci prog->aux->user = user; 17113d0407baSopenharmony_ci return 0; 17123d0407baSopenharmony_ci} 17133d0407baSopenharmony_ci 17143d0407baSopenharmony_cistatic void bpf_prog_uncharge_memlock(struct bpf_prog *prog) 17153d0407baSopenharmony_ci{ 17163d0407baSopenharmony_ci struct user_struct *user = prog->aux->user; 17173d0407baSopenharmony_ci 17183d0407baSopenharmony_ci __bpf_prog_uncharge(user, prog->pages); 17193d0407baSopenharmony_ci free_uid(user); 17203d0407baSopenharmony_ci} 17213d0407baSopenharmony_ci 17223d0407baSopenharmony_cistatic int bpf_prog_alloc_id(struct bpf_prog *prog) 17233d0407baSopenharmony_ci{ 17243d0407baSopenharmony_ci int id; 17253d0407baSopenharmony_ci 17263d0407baSopenharmony_ci idr_preload(GFP_KERNEL); 17273d0407baSopenharmony_ci spin_lock_bh(&prog_idr_lock); 17283d0407baSopenharmony_ci id = idr_alloc_cyclic(&prog_idr, prog, 1, INT_MAX, GFP_ATOMIC); 17293d0407baSopenharmony_ci if (id > 0) { 17303d0407baSopenharmony_ci prog->aux->id = id; 17313d0407baSopenharmony_ci } 17323d0407baSopenharmony_ci spin_unlock_bh(&prog_idr_lock); 17333d0407baSopenharmony_ci idr_preload_end(); 17343d0407baSopenharmony_ci 17353d0407baSopenharmony_ci /* id is in [1, INT_MAX) */ 17363d0407baSopenharmony_ci if (WARN_ON_ONCE(!id)) { 17373d0407baSopenharmony_ci return -ENOSPC; 17383d0407baSopenharmony_ci } 17393d0407baSopenharmony_ci 17403d0407baSopenharmony_ci return id > 0 ? 0 : id; 17413d0407baSopenharmony_ci} 17423d0407baSopenharmony_ci 17433d0407baSopenharmony_civoid bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock) 17443d0407baSopenharmony_ci{ 17453d0407baSopenharmony_ci /* cBPF to eBPF migrations are currently not in the idr store. 17463d0407baSopenharmony_ci * Offloaded programs are removed from the store when their device 17473d0407baSopenharmony_ci * disappears - even if someone grabs an fd to them they are unusable, 17483d0407baSopenharmony_ci * simply waiting for refcnt to drop to be freed. 17493d0407baSopenharmony_ci */ 17503d0407baSopenharmony_ci if (!prog->aux->id) { 17513d0407baSopenharmony_ci return; 17523d0407baSopenharmony_ci } 17533d0407baSopenharmony_ci 17543d0407baSopenharmony_ci if (do_idr_lock) { 17553d0407baSopenharmony_ci spin_lock_bh(&prog_idr_lock); 17563d0407baSopenharmony_ci } else { 17573d0407baSopenharmony_ci __acquire(&prog_idr_lock); 17583d0407baSopenharmony_ci } 17593d0407baSopenharmony_ci 17603d0407baSopenharmony_ci idr_remove(&prog_idr, prog->aux->id); 17613d0407baSopenharmony_ci prog->aux->id = 0; 17623d0407baSopenharmony_ci 17633d0407baSopenharmony_ci if (do_idr_lock) { 17643d0407baSopenharmony_ci spin_unlock_bh(&prog_idr_lock); 17653d0407baSopenharmony_ci } else { 17663d0407baSopenharmony_ci __release(&prog_idr_lock); 17673d0407baSopenharmony_ci } 17683d0407baSopenharmony_ci} 17693d0407baSopenharmony_ci 17703d0407baSopenharmony_cistatic void _bpf_prog_put_rcu(struct rcu_head *rcu) 17713d0407baSopenharmony_ci{ 17723d0407baSopenharmony_ci struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu); 17733d0407baSopenharmony_ci 17743d0407baSopenharmony_ci kvfree(aux->func_info); 17753d0407baSopenharmony_ci kfree(aux->func_info_aux); 17763d0407baSopenharmony_ci bpf_prog_uncharge_memlock(aux->prog); 17773d0407baSopenharmony_ci security_bpf_prog_free(aux); 17783d0407baSopenharmony_ci bpf_prog_free(aux->prog); 17793d0407baSopenharmony_ci} 17803d0407baSopenharmony_ci 17813d0407baSopenharmony_cistatic void _bpf_prog_put_noref(struct bpf_prog *prog, bool deferred) 17823d0407baSopenharmony_ci{ 17833d0407baSopenharmony_ci bpf_prog_kallsyms_del_all(prog); 17843d0407baSopenharmony_ci btf_put(prog->aux->btf); 17853d0407baSopenharmony_ci bpf_prog_free_linfo(prog); 17863d0407baSopenharmony_ci 17873d0407baSopenharmony_ci if (deferred) { 17883d0407baSopenharmony_ci if (prog->aux->sleepable) { 17893d0407baSopenharmony_ci call_rcu_tasks_trace(&prog->aux->rcu, _bpf_prog_put_rcu); 17903d0407baSopenharmony_ci } else { 17913d0407baSopenharmony_ci call_rcu(&prog->aux->rcu, _bpf_prog_put_rcu); 17923d0407baSopenharmony_ci } 17933d0407baSopenharmony_ci } else { 17943d0407baSopenharmony_ci _bpf_prog_put_rcu(&prog->aux->rcu); 17953d0407baSopenharmony_ci } 17963d0407baSopenharmony_ci} 17973d0407baSopenharmony_ci 17983d0407baSopenharmony_cistatic void _bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock) 17993d0407baSopenharmony_ci{ 18003d0407baSopenharmony_ci if (atomic64_dec_and_test(&prog->aux->refcnt)) { 18013d0407baSopenharmony_ci perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_UNLOAD, 0); 18023d0407baSopenharmony_ci bpf_audit_prog(prog, BPF_AUDIT_UNLOAD); 18033d0407baSopenharmony_ci /* bpf_prog_free_id() must be called first */ 18043d0407baSopenharmony_ci bpf_prog_free_id(prog, do_idr_lock); 18053d0407baSopenharmony_ci _bpf_prog_put_noref(prog, true); 18063d0407baSopenharmony_ci } 18073d0407baSopenharmony_ci} 18083d0407baSopenharmony_ci 18093d0407baSopenharmony_civoid bpf_prog_put(struct bpf_prog *prog) 18103d0407baSopenharmony_ci{ 18113d0407baSopenharmony_ci _bpf_prog_put(prog, true); 18123d0407baSopenharmony_ci} 18133d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(bpf_prog_put); 18143d0407baSopenharmony_ci 18153d0407baSopenharmony_cistatic int bpf_prog_release(struct inode *inode, struct file *filp) 18163d0407baSopenharmony_ci{ 18173d0407baSopenharmony_ci struct bpf_prog *prog = filp->private_data; 18183d0407baSopenharmony_ci 18193d0407baSopenharmony_ci bpf_prog_put(prog); 18203d0407baSopenharmony_ci return 0; 18213d0407baSopenharmony_ci} 18223d0407baSopenharmony_ci 18233d0407baSopenharmony_cistatic void bpf_prog_get_stats(const struct bpf_prog *prog, struct bpf_prog_stats *stats) 18243d0407baSopenharmony_ci{ 18253d0407baSopenharmony_ci u64 nsecs = 0, cnt = 0; 18263d0407baSopenharmony_ci int cpu; 18273d0407baSopenharmony_ci 18283d0407baSopenharmony_ci for_each_possible_cpu(cpu) 18293d0407baSopenharmony_ci { 18303d0407baSopenharmony_ci const struct bpf_prog_stats *st; 18313d0407baSopenharmony_ci unsigned int start; 18323d0407baSopenharmony_ci u64 tnsecs, tcnt; 18333d0407baSopenharmony_ci 18343d0407baSopenharmony_ci st = per_cpu_ptr(prog->aux->stats, cpu); 18353d0407baSopenharmony_ci do { 18363d0407baSopenharmony_ci start = u64_stats_fetch_begin_irq(&st->syncp); 18373d0407baSopenharmony_ci tnsecs = st->nsecs; 18383d0407baSopenharmony_ci tcnt = st->cnt; 18393d0407baSopenharmony_ci } while (u64_stats_fetch_retry_irq(&st->syncp, start)); 18403d0407baSopenharmony_ci nsecs += tnsecs; 18413d0407baSopenharmony_ci cnt += tcnt; 18423d0407baSopenharmony_ci } 18433d0407baSopenharmony_ci stats->nsecs = nsecs; 18443d0407baSopenharmony_ci stats->cnt = cnt; 18453d0407baSopenharmony_ci} 18463d0407baSopenharmony_ci 18473d0407baSopenharmony_ci#ifdef CONFIG_PROC_FS 18483d0407baSopenharmony_cistatic void bpf_prog_show_fdinfo(struct seq_file *m, struct file *filp) 18493d0407baSopenharmony_ci{ 18503d0407baSopenharmony_ci const struct bpf_prog *prog = filp->private_data; 18513d0407baSopenharmony_ci char prog_tag[sizeof(prog->tag) * 0x2 + 1] = {}; 18523d0407baSopenharmony_ci struct bpf_prog_stats stats; 18533d0407baSopenharmony_ci 18543d0407baSopenharmony_ci bpf_prog_get_stats(prog, &stats); 18553d0407baSopenharmony_ci bin2hex(prog_tag, prog->tag, sizeof(prog->tag)); 18563d0407baSopenharmony_ci seq_printf(m, 18573d0407baSopenharmony_ci "prog_type:\t%u\n" 18583d0407baSopenharmony_ci "prog_jited:\t%u\n" 18593d0407baSopenharmony_ci "prog_tag:\t%s\n" 18603d0407baSopenharmony_ci "memlock:\t%llu\n" 18613d0407baSopenharmony_ci "prog_id:\t%u\n" 18623d0407baSopenharmony_ci "run_time_ns:\t%llu\n" 18633d0407baSopenharmony_ci "run_cnt:\t%llu\n", 18643d0407baSopenharmony_ci prog->type, prog->jited, prog_tag, prog->pages * 1ULL << PAGE_SHIFT, prog->aux->id, stats.nsecs, 18653d0407baSopenharmony_ci stats.cnt); 18663d0407baSopenharmony_ci} 18673d0407baSopenharmony_ci#endif 18683d0407baSopenharmony_ci 18693d0407baSopenharmony_ciconst struct file_operations bpf_prog_fops = { 18703d0407baSopenharmony_ci#ifdef CONFIG_PROC_FS 18713d0407baSopenharmony_ci .show_fdinfo = bpf_prog_show_fdinfo, 18723d0407baSopenharmony_ci#endif 18733d0407baSopenharmony_ci .release = bpf_prog_release, 18743d0407baSopenharmony_ci .read = bpf_dummy_read, 18753d0407baSopenharmony_ci .write = bpf_dummy_write, 18763d0407baSopenharmony_ci}; 18773d0407baSopenharmony_ci 18783d0407baSopenharmony_ciint bpf_prog_new_fd(struct bpf_prog *prog) 18793d0407baSopenharmony_ci{ 18803d0407baSopenharmony_ci int ret; 18813d0407baSopenharmony_ci 18823d0407baSopenharmony_ci ret = security_bpf_prog(prog); 18833d0407baSopenharmony_ci if (ret < 0) { 18843d0407baSopenharmony_ci return ret; 18853d0407baSopenharmony_ci } 18863d0407baSopenharmony_ci 18873d0407baSopenharmony_ci return anon_inode_getfd("bpf-prog", &bpf_prog_fops, prog, O_RDWR | O_CLOEXEC); 18883d0407baSopenharmony_ci} 18893d0407baSopenharmony_ci 18903d0407baSopenharmony_cistatic struct bpf_prog *i_bpf_prog_get(struct fd f) 18913d0407baSopenharmony_ci{ 18923d0407baSopenharmony_ci if (!f.file) { 18933d0407baSopenharmony_ci return ERR_PTR(-EBADF); 18943d0407baSopenharmony_ci } 18953d0407baSopenharmony_ci if (f.file->f_op != &bpf_prog_fops) { 18963d0407baSopenharmony_ci fdput(f); 18973d0407baSopenharmony_ci return ERR_PTR(-EINVAL); 18983d0407baSopenharmony_ci } 18993d0407baSopenharmony_ci 19003d0407baSopenharmony_ci return f.file->private_data; 19013d0407baSopenharmony_ci} 19023d0407baSopenharmony_ci 19033d0407baSopenharmony_civoid bpf_prog_add(struct bpf_prog *prog, int i) 19043d0407baSopenharmony_ci{ 19053d0407baSopenharmony_ci atomic64_add(i, &prog->aux->refcnt); 19063d0407baSopenharmony_ci} 19073d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(bpf_prog_add); 19083d0407baSopenharmony_ci 19093d0407baSopenharmony_civoid bpf_prog_sub(struct bpf_prog *prog, int i) 19103d0407baSopenharmony_ci{ 19113d0407baSopenharmony_ci /* Only to be used for undoing previous bpf_prog_add() in some 19123d0407baSopenharmony_ci * error path. We still know that another entity in our call 19133d0407baSopenharmony_ci * path holds a reference to the program, thus atomic_sub() can 19143d0407baSopenharmony_ci * be safely used in such cases! 19153d0407baSopenharmony_ci */ 19163d0407baSopenharmony_ci WARN_ON(atomic64_sub_return(i, &prog->aux->refcnt) == 0); 19173d0407baSopenharmony_ci} 19183d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(bpf_prog_sub); 19193d0407baSopenharmony_ci 19203d0407baSopenharmony_civoid bpf_prog_inc(struct bpf_prog *prog) 19213d0407baSopenharmony_ci{ 19223d0407baSopenharmony_ci atomic64_inc(&prog->aux->refcnt); 19233d0407baSopenharmony_ci} 19243d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(bpf_prog_inc); 19253d0407baSopenharmony_ci 19263d0407baSopenharmony_ci/* prog_idr_lock should have been held */ 19273d0407baSopenharmony_cistruct bpf_prog *bpf_prog_inc_not_zero(struct bpf_prog *prog) 19283d0407baSopenharmony_ci{ 19293d0407baSopenharmony_ci int refold; 19303d0407baSopenharmony_ci 19313d0407baSopenharmony_ci refold = atomic64_fetch_add_unless(&prog->aux->refcnt, 1, 0); 19323d0407baSopenharmony_ci if (!refold) { 19333d0407baSopenharmony_ci return ERR_PTR(-ENOENT); 19343d0407baSopenharmony_ci } 19353d0407baSopenharmony_ci 19363d0407baSopenharmony_ci return prog; 19373d0407baSopenharmony_ci} 19383d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(bpf_prog_inc_not_zero); 19393d0407baSopenharmony_ci 19403d0407baSopenharmony_cibool bpf_prog_get_ok(struct bpf_prog *prog, enum bpf_prog_type *attach_type, bool attach_drv) 19413d0407baSopenharmony_ci{ 19423d0407baSopenharmony_ci /* not an attachment, just a refcount inc, always allow */ 19433d0407baSopenharmony_ci if (!attach_type) { 19443d0407baSopenharmony_ci return true; 19453d0407baSopenharmony_ci } 19463d0407baSopenharmony_ci 19473d0407baSopenharmony_ci if (prog->type != *attach_type) { 19483d0407baSopenharmony_ci return false; 19493d0407baSopenharmony_ci } 19503d0407baSopenharmony_ci if (bpf_prog_is_dev_bound(prog->aux) && !attach_drv) { 19513d0407baSopenharmony_ci return false; 19523d0407baSopenharmony_ci } 19533d0407baSopenharmony_ci 19543d0407baSopenharmony_ci return true; 19553d0407baSopenharmony_ci} 19563d0407baSopenharmony_ci 19573d0407baSopenharmony_cistatic struct bpf_prog *_bpf_prog_get(u32 ufd, enum bpf_prog_type *attach_type, bool attach_drv) 19583d0407baSopenharmony_ci{ 19593d0407baSopenharmony_ci struct fd f = fdget(ufd); 19603d0407baSopenharmony_ci struct bpf_prog *prog; 19613d0407baSopenharmony_ci 19623d0407baSopenharmony_ci prog = i_bpf_prog_get(f); 19633d0407baSopenharmony_ci if (IS_ERR(prog)) { 19643d0407baSopenharmony_ci return prog; 19653d0407baSopenharmony_ci } 19663d0407baSopenharmony_ci if (!bpf_prog_get_ok(prog, attach_type, attach_drv)) { 19673d0407baSopenharmony_ci prog = ERR_PTR(-EINVAL); 19683d0407baSopenharmony_ci goto out; 19693d0407baSopenharmony_ci } 19703d0407baSopenharmony_ci 19713d0407baSopenharmony_ci bpf_prog_inc(prog); 19723d0407baSopenharmony_ciout: 19733d0407baSopenharmony_ci fdput(f); 19743d0407baSopenharmony_ci return prog; 19753d0407baSopenharmony_ci} 19763d0407baSopenharmony_ci 19773d0407baSopenharmony_cistruct bpf_prog *bpf_prog_get(u32 ufd) 19783d0407baSopenharmony_ci{ 19793d0407baSopenharmony_ci return _bpf_prog_get(ufd, NULL, false); 19803d0407baSopenharmony_ci} 19813d0407baSopenharmony_ci 19823d0407baSopenharmony_cistruct bpf_prog *bpf_prog_get_type_dev(u32 ufd, enum bpf_prog_type type, bool attach_drv) 19833d0407baSopenharmony_ci{ 19843d0407baSopenharmony_ci return _bpf_prog_get(ufd, &type, attach_drv); 19853d0407baSopenharmony_ci} 19863d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(bpf_prog_get_type_dev); 19873d0407baSopenharmony_ci 19883d0407baSopenharmony_ci/* Initially all BPF programs could be loaded w/o specifying 19893d0407baSopenharmony_ci * expected_attach_type. Later for some of them specifying expected_attach_type 19903d0407baSopenharmony_ci * at load time became required so that program could be validated properly. 19913d0407baSopenharmony_ci * Programs of types that are allowed to be loaded both w/ and w/o (for 19923d0407baSopenharmony_ci * backward compatibility) expected_attach_type, should have the default attach 19933d0407baSopenharmony_ci * type assigned to expected_attach_type for the latter case, so that it can be 19943d0407baSopenharmony_ci * validated later at attach time. 19953d0407baSopenharmony_ci * 19963d0407baSopenharmony_ci * bpf_prog_load_fixup_attach_type() sets expected_attach_type in @attr if 19973d0407baSopenharmony_ci * prog type requires it but has some attach types that have to be backward 19983d0407baSopenharmony_ci * compatible. 19993d0407baSopenharmony_ci */ 20003d0407baSopenharmony_cistatic void bpf_prog_load_fixup_attach_type(union bpf_attr *attr) 20013d0407baSopenharmony_ci{ 20023d0407baSopenharmony_ci if (attr->prog_type == BPF_PROG_TYPE_CGROUP_SOCK) { 20033d0407baSopenharmony_ci /* Unfortunately BPF_ATTACH_TYPE_UNSPEC enumeration doesn't 20043d0407baSopenharmony_ci * exist so checking for non-zero is the way to go here. 20053d0407baSopenharmony_ci */ 20063d0407baSopenharmony_ci if (!attr->expected_attach_type) { 20073d0407baSopenharmony_ci attr->expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE; 20083d0407baSopenharmony_ci } 20093d0407baSopenharmony_ci } 20103d0407baSopenharmony_ci} 20113d0407baSopenharmony_ci 20123d0407baSopenharmony_cistatic int bpf_prog_load_check_attach(enum bpf_prog_type prog_type, enum bpf_attach_type expected_attach_type, 20133d0407baSopenharmony_ci u32 btf_id, u32 prog_fd) 20143d0407baSopenharmony_ci{ 20153d0407baSopenharmony_ci if (btf_id) { 20163d0407baSopenharmony_ci if (btf_id > BTF_MAX_TYPE) { 20173d0407baSopenharmony_ci return -EINVAL; 20183d0407baSopenharmony_ci } 20193d0407baSopenharmony_ci 20203d0407baSopenharmony_ci switch (prog_type) { 20213d0407baSopenharmony_ci case BPF_PROG_TYPE_TRACING: 20223d0407baSopenharmony_ci case BPF_PROG_TYPE_LSM: 20233d0407baSopenharmony_ci case BPF_PROG_TYPE_STRUCT_OPS: 20243d0407baSopenharmony_ci case BPF_PROG_TYPE_EXT: 20253d0407baSopenharmony_ci break; 20263d0407baSopenharmony_ci default: 20273d0407baSopenharmony_ci return -EINVAL; 20283d0407baSopenharmony_ci } 20293d0407baSopenharmony_ci } 20303d0407baSopenharmony_ci 20313d0407baSopenharmony_ci if (prog_fd && prog_type != BPF_PROG_TYPE_TRACING && prog_type != BPF_PROG_TYPE_EXT) { 20323d0407baSopenharmony_ci return -EINVAL; 20333d0407baSopenharmony_ci } 20343d0407baSopenharmony_ci 20353d0407baSopenharmony_ci switch (prog_type) { 20363d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SOCK: 20373d0407baSopenharmony_ci switch (expected_attach_type) { 20383d0407baSopenharmony_ci case BPF_CGROUP_INET_SOCK_CREATE: 20393d0407baSopenharmony_ci case BPF_CGROUP_INET_SOCK_RELEASE: 20403d0407baSopenharmony_ci case BPF_CGROUP_INET4_POST_BIND: 20413d0407baSopenharmony_ci case BPF_CGROUP_INET6_POST_BIND: 20423d0407baSopenharmony_ci return 0; 20433d0407baSopenharmony_ci default: 20443d0407baSopenharmony_ci return -EINVAL; 20453d0407baSopenharmony_ci } 20463d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: 20473d0407baSopenharmony_ci switch (expected_attach_type) { 20483d0407baSopenharmony_ci case BPF_CGROUP_INET4_BIND: 20493d0407baSopenharmony_ci case BPF_CGROUP_INET6_BIND: 20503d0407baSopenharmony_ci case BPF_CGROUP_INET4_CONNECT: 20513d0407baSopenharmony_ci case BPF_CGROUP_INET6_CONNECT: 20523d0407baSopenharmony_ci case BPF_CGROUP_INET4_GETPEERNAME: 20533d0407baSopenharmony_ci case BPF_CGROUP_INET6_GETPEERNAME: 20543d0407baSopenharmony_ci case BPF_CGROUP_INET4_GETSOCKNAME: 20553d0407baSopenharmony_ci case BPF_CGROUP_INET6_GETSOCKNAME: 20563d0407baSopenharmony_ci case BPF_CGROUP_UDP4_SENDMSG: 20573d0407baSopenharmony_ci case BPF_CGROUP_UDP6_SENDMSG: 20583d0407baSopenharmony_ci case BPF_CGROUP_UDP4_RECVMSG: 20593d0407baSopenharmony_ci case BPF_CGROUP_UDP6_RECVMSG: 20603d0407baSopenharmony_ci return 0; 20613d0407baSopenharmony_ci default: 20623d0407baSopenharmony_ci return -EINVAL; 20633d0407baSopenharmony_ci } 20643d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SKB: 20653d0407baSopenharmony_ci switch (expected_attach_type) { 20663d0407baSopenharmony_ci case BPF_CGROUP_INET_INGRESS: 20673d0407baSopenharmony_ci case BPF_CGROUP_INET_EGRESS: 20683d0407baSopenharmony_ci return 0; 20693d0407baSopenharmony_ci default: 20703d0407baSopenharmony_ci return -EINVAL; 20713d0407baSopenharmony_ci } 20723d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SOCKOPT: 20733d0407baSopenharmony_ci switch (expected_attach_type) { 20743d0407baSopenharmony_ci case BPF_CGROUP_SETSOCKOPT: 20753d0407baSopenharmony_ci case BPF_CGROUP_GETSOCKOPT: 20763d0407baSopenharmony_ci return 0; 20773d0407baSopenharmony_ci default: 20783d0407baSopenharmony_ci return -EINVAL; 20793d0407baSopenharmony_ci } 20803d0407baSopenharmony_ci case BPF_PROG_TYPE_SK_LOOKUP: 20813d0407baSopenharmony_ci if (expected_attach_type == BPF_SK_LOOKUP) { 20823d0407baSopenharmony_ci return 0; 20833d0407baSopenharmony_ci } 20843d0407baSopenharmony_ci return -EINVAL; 20853d0407baSopenharmony_ci case BPF_PROG_TYPE_EXT: 20863d0407baSopenharmony_ci if (expected_attach_type) { 20873d0407baSopenharmony_ci return -EINVAL; 20883d0407baSopenharmony_ci } 20893d0407baSopenharmony_ci fallthrough; 20903d0407baSopenharmony_ci default: 20913d0407baSopenharmony_ci return 0; 20923d0407baSopenharmony_ci } 20933d0407baSopenharmony_ci} 20943d0407baSopenharmony_ci 20953d0407baSopenharmony_cistatic bool is_net_admin_prog_type(enum bpf_prog_type prog_type) 20963d0407baSopenharmony_ci{ 20973d0407baSopenharmony_ci switch (prog_type) { 20983d0407baSopenharmony_ci case BPF_PROG_TYPE_SCHED_CLS: 20993d0407baSopenharmony_ci case BPF_PROG_TYPE_SCHED_ACT: 21003d0407baSopenharmony_ci case BPF_PROG_TYPE_XDP: 21013d0407baSopenharmony_ci case BPF_PROG_TYPE_LWT_IN: 21023d0407baSopenharmony_ci case BPF_PROG_TYPE_LWT_OUT: 21033d0407baSopenharmony_ci case BPF_PROG_TYPE_LWT_XMIT: 21043d0407baSopenharmony_ci case BPF_PROG_TYPE_LWT_SEG6LOCAL: 21053d0407baSopenharmony_ci case BPF_PROG_TYPE_SK_SKB: 21063d0407baSopenharmony_ci case BPF_PROG_TYPE_SK_MSG: 21073d0407baSopenharmony_ci case BPF_PROG_TYPE_LIRC_MODE2: 21083d0407baSopenharmony_ci case BPF_PROG_TYPE_FLOW_DISSECTOR: 21093d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_DEVICE: 21103d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SOCK: 21113d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: 21123d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SOCKOPT: 21133d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SYSCTL: 21143d0407baSopenharmony_ci case BPF_PROG_TYPE_SOCK_OPS: 21153d0407baSopenharmony_ci case BPF_PROG_TYPE_EXT: /* extends any prog */ 21163d0407baSopenharmony_ci return true; 21173d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SKB: 21183d0407baSopenharmony_ci /* always unpriv */ 21193d0407baSopenharmony_ci case BPF_PROG_TYPE_SK_REUSEPORT: 21203d0407baSopenharmony_ci /* equivalent to SOCKET_FILTER. need CAP_BPF only */ 21213d0407baSopenharmony_ci default: 21223d0407baSopenharmony_ci return false; 21233d0407baSopenharmony_ci } 21243d0407baSopenharmony_ci} 21253d0407baSopenharmony_ci 21263d0407baSopenharmony_cistatic bool is_perfmon_prog_type(enum bpf_prog_type prog_type) 21273d0407baSopenharmony_ci{ 21283d0407baSopenharmony_ci switch (prog_type) { 21293d0407baSopenharmony_ci case BPF_PROG_TYPE_KPROBE: 21303d0407baSopenharmony_ci case BPF_PROG_TYPE_TRACEPOINT: 21313d0407baSopenharmony_ci case BPF_PROG_TYPE_PERF_EVENT: 21323d0407baSopenharmony_ci case BPF_PROG_TYPE_RAW_TRACEPOINT: 21333d0407baSopenharmony_ci case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE: 21343d0407baSopenharmony_ci case BPF_PROG_TYPE_TRACING: 21353d0407baSopenharmony_ci case BPF_PROG_TYPE_LSM: 21363d0407baSopenharmony_ci case BPF_PROG_TYPE_STRUCT_OPS: /* has access to struct sock */ 21373d0407baSopenharmony_ci case BPF_PROG_TYPE_EXT: /* extends any prog */ 21383d0407baSopenharmony_ci return true; 21393d0407baSopenharmony_ci default: 21403d0407baSopenharmony_ci return false; 21413d0407baSopenharmony_ci } 21423d0407baSopenharmony_ci} 21433d0407baSopenharmony_ci 21443d0407baSopenharmony_ci/* last field in 'union bpf_attr' used by this command */ 21453d0407baSopenharmony_ci#define BPF_PROG_LOAD_LAST_FIELD attach_prog_fd 21463d0407baSopenharmony_ci 21473d0407baSopenharmony_cistatic int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr) 21483d0407baSopenharmony_ci{ 21493d0407baSopenharmony_ci enum bpf_prog_type type = attr->prog_type; 21503d0407baSopenharmony_ci struct bpf_prog *prog; 21513d0407baSopenharmony_ci int err; 21523d0407baSopenharmony_ci char license[128]; 21533d0407baSopenharmony_ci bool is_gpl; 21543d0407baSopenharmony_ci 21553d0407baSopenharmony_ci if (CHECK_ATTR(BPF_PROG_LOAD)) { 21563d0407baSopenharmony_ci return -EINVAL; 21573d0407baSopenharmony_ci } 21583d0407baSopenharmony_ci 21593d0407baSopenharmony_ci if (attr->prog_flags & ~(BPF_F_STRICT_ALIGNMENT | BPF_F_ANY_ALIGNMENT | BPF_F_TEST_STATE_FREQ | BPF_F_SLEEPABLE | 21603d0407baSopenharmony_ci BPF_F_TEST_RND_HI32)) { 21613d0407baSopenharmony_ci return -EINVAL; 21623d0407baSopenharmony_ci } 21633d0407baSopenharmony_ci 21643d0407baSopenharmony_ci if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && (attr->prog_flags & BPF_F_ANY_ALIGNMENT) && 21653d0407baSopenharmony_ci !bpf_capable()) { 21663d0407baSopenharmony_ci return -EPERM; 21673d0407baSopenharmony_ci } 21683d0407baSopenharmony_ci 21693d0407baSopenharmony_ci /* copy eBPF program license from user space */ 21703d0407baSopenharmony_ci if (strncpy_from_user(license, u64_to_user_ptr(attr->license), sizeof(license) - 1) < 0) { 21713d0407baSopenharmony_ci return -EFAULT; 21723d0407baSopenharmony_ci } 21733d0407baSopenharmony_ci license[sizeof(license) - 1] = 0; 21743d0407baSopenharmony_ci 21753d0407baSopenharmony_ci /* eBPF programs must be GPL compatible to use GPL-ed functions */ 21763d0407baSopenharmony_ci is_gpl = license_is_gpl_compatible(license); 21773d0407baSopenharmony_ci 21783d0407baSopenharmony_ci if (attr->insn_cnt == 0 || attr->insn_cnt > (bpf_capable() ? BPF_COMPLEXITY_LIMIT_INSNS : BPF_MAXINSNS)) { 21793d0407baSopenharmony_ci return -E2BIG; 21803d0407baSopenharmony_ci } 21813d0407baSopenharmony_ci if (type != BPF_PROG_TYPE_SOCKET_FILTER && type != BPF_PROG_TYPE_CGROUP_SKB && !bpf_capable()) { 21823d0407baSopenharmony_ci return -EPERM; 21833d0407baSopenharmony_ci } 21843d0407baSopenharmony_ci 21853d0407baSopenharmony_ci if (is_net_admin_prog_type(type) && !capable(CAP_NET_ADMIN) && !capable(CAP_SYS_ADMIN)) { 21863d0407baSopenharmony_ci return -EPERM; 21873d0407baSopenharmony_ci } 21883d0407baSopenharmony_ci if (is_perfmon_prog_type(type) && !perfmon_capable()) { 21893d0407baSopenharmony_ci return -EPERM; 21903d0407baSopenharmony_ci } 21913d0407baSopenharmony_ci 21923d0407baSopenharmony_ci bpf_prog_load_fixup_attach_type(attr); 21933d0407baSopenharmony_ci if (bpf_prog_load_check_attach(type, attr->expected_attach_type, attr->attach_btf_id, attr->attach_prog_fd)) { 21943d0407baSopenharmony_ci return -EINVAL; 21953d0407baSopenharmony_ci } 21963d0407baSopenharmony_ci 21973d0407baSopenharmony_ci /* plain bpf_prog allocation */ 21983d0407baSopenharmony_ci prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER); 21993d0407baSopenharmony_ci if (!prog) { 22003d0407baSopenharmony_ci return -ENOMEM; 22013d0407baSopenharmony_ci } 22023d0407baSopenharmony_ci 22033d0407baSopenharmony_ci prog->expected_attach_type = attr->expected_attach_type; 22043d0407baSopenharmony_ci prog->aux->attach_btf_id = attr->attach_btf_id; 22053d0407baSopenharmony_ci if (attr->attach_prog_fd) { 22063d0407baSopenharmony_ci struct bpf_prog *dst_prog; 22073d0407baSopenharmony_ci 22083d0407baSopenharmony_ci dst_prog = bpf_prog_get(attr->attach_prog_fd); 22093d0407baSopenharmony_ci if (IS_ERR(dst_prog)) { 22103d0407baSopenharmony_ci err = PTR_ERR(dst_prog); 22113d0407baSopenharmony_ci goto free_prog_nouncharge; 22123d0407baSopenharmony_ci } 22133d0407baSopenharmony_ci prog->aux->dst_prog = dst_prog; 22143d0407baSopenharmony_ci } 22153d0407baSopenharmony_ci 22163d0407baSopenharmony_ci prog->aux->offload_requested = !!attr->prog_ifindex; 22173d0407baSopenharmony_ci prog->aux->sleepable = attr->prog_flags & BPF_F_SLEEPABLE; 22183d0407baSopenharmony_ci 22193d0407baSopenharmony_ci err = security_bpf_prog_alloc(prog->aux); 22203d0407baSopenharmony_ci if (err) { 22213d0407baSopenharmony_ci goto free_prog_nouncharge; 22223d0407baSopenharmony_ci } 22233d0407baSopenharmony_ci 22243d0407baSopenharmony_ci err = bpf_prog_charge_memlock(prog); 22253d0407baSopenharmony_ci if (err) { 22263d0407baSopenharmony_ci goto free_prog_sec; 22273d0407baSopenharmony_ci } 22283d0407baSopenharmony_ci 22293d0407baSopenharmony_ci prog->len = attr->insn_cnt; 22303d0407baSopenharmony_ci 22313d0407baSopenharmony_ci err = -EFAULT; 22323d0407baSopenharmony_ci if (copy_from_user(prog->insns, u64_to_user_ptr(attr->insns), bpf_prog_insn_size(prog)) != 0) { 22333d0407baSopenharmony_ci goto free_prog; 22343d0407baSopenharmony_ci } 22353d0407baSopenharmony_ci 22363d0407baSopenharmony_ci prog->orig_prog = NULL; 22373d0407baSopenharmony_ci prog->jited = 0; 22383d0407baSopenharmony_ci 22393d0407baSopenharmony_ci atomic64_set(&prog->aux->refcnt, 1); 22403d0407baSopenharmony_ci prog->gpl_compatible = is_gpl ? 1 : 0; 22413d0407baSopenharmony_ci 22423d0407baSopenharmony_ci if (bpf_prog_is_dev_bound(prog->aux)) { 22433d0407baSopenharmony_ci err = bpf_prog_offload_init(prog, attr); 22443d0407baSopenharmony_ci if (err) { 22453d0407baSopenharmony_ci goto free_prog; 22463d0407baSopenharmony_ci } 22473d0407baSopenharmony_ci } 22483d0407baSopenharmony_ci 22493d0407baSopenharmony_ci /* find program type: socket_filter vs tracing_filter */ 22503d0407baSopenharmony_ci err = find_prog_type(type, prog); 22513d0407baSopenharmony_ci if (err < 0) { 22523d0407baSopenharmony_ci goto free_prog; 22533d0407baSopenharmony_ci } 22543d0407baSopenharmony_ci 22553d0407baSopenharmony_ci prog->aux->load_time = ktime_get_boottime_ns(); 22563d0407baSopenharmony_ci err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name, sizeof(attr->prog_name)); 22573d0407baSopenharmony_ci if (err < 0) { 22583d0407baSopenharmony_ci goto free_prog; 22593d0407baSopenharmony_ci } 22603d0407baSopenharmony_ci 22613d0407baSopenharmony_ci /* run eBPF verifier */ 22623d0407baSopenharmony_ci err = bpf_check(&prog, attr, uattr); 22633d0407baSopenharmony_ci if (err < 0) { 22643d0407baSopenharmony_ci goto free_used_maps; 22653d0407baSopenharmony_ci } 22663d0407baSopenharmony_ci 22673d0407baSopenharmony_ci prog = bpf_prog_select_runtime(prog, &err); 22683d0407baSopenharmony_ci if (err < 0) { 22693d0407baSopenharmony_ci goto free_used_maps; 22703d0407baSopenharmony_ci } 22713d0407baSopenharmony_ci 22723d0407baSopenharmony_ci err = bpf_prog_alloc_id(prog); 22733d0407baSopenharmony_ci if (err) { 22743d0407baSopenharmony_ci goto free_used_maps; 22753d0407baSopenharmony_ci } 22763d0407baSopenharmony_ci 22773d0407baSopenharmony_ci /* Upon success of bpf_prog_alloc_id(), the BPF prog is 22783d0407baSopenharmony_ci * effectively publicly exposed. However, retrieving via 22793d0407baSopenharmony_ci * bpf_prog_get_fd_by_id() will take another reference, 22803d0407baSopenharmony_ci * therefore it cannot be gone underneath us. 22813d0407baSopenharmony_ci * 22823d0407baSopenharmony_ci * Only for the time /after/ successful bpf_prog_new_fd() 22833d0407baSopenharmony_ci * and before returning to userspace, we might just hold 22843d0407baSopenharmony_ci * one reference and any parallel close on that fd could 22853d0407baSopenharmony_ci * rip everything out. Hence, below notifications must 22863d0407baSopenharmony_ci * happen before bpf_prog_new_fd(). 22873d0407baSopenharmony_ci * 22883d0407baSopenharmony_ci * Also, any failure handling from this point onwards must 22893d0407baSopenharmony_ci * be using bpf_prog_put() given the program is exposed. 22903d0407baSopenharmony_ci */ 22913d0407baSopenharmony_ci bpf_prog_kallsyms_add(prog); 22923d0407baSopenharmony_ci perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_LOAD, 0); 22933d0407baSopenharmony_ci bpf_audit_prog(prog, BPF_AUDIT_LOAD); 22943d0407baSopenharmony_ci 22953d0407baSopenharmony_ci err = bpf_prog_new_fd(prog); 22963d0407baSopenharmony_ci if (err < 0) { 22973d0407baSopenharmony_ci bpf_prog_put(prog); 22983d0407baSopenharmony_ci } 22993d0407baSopenharmony_ci return err; 23003d0407baSopenharmony_ci 23013d0407baSopenharmony_cifree_used_maps: 23023d0407baSopenharmony_ci /* In case we have subprogs, we need to wait for a grace 23033d0407baSopenharmony_ci * period before we can tear down JIT memory since symbols 23043d0407baSopenharmony_ci * are already exposed under kallsyms. 23053d0407baSopenharmony_ci */ 23063d0407baSopenharmony_ci _bpf_prog_put_noref(prog, prog->aux->func_cnt); 23073d0407baSopenharmony_ci return err; 23083d0407baSopenharmony_cifree_prog: 23093d0407baSopenharmony_ci bpf_prog_uncharge_memlock(prog); 23103d0407baSopenharmony_cifree_prog_sec: 23113d0407baSopenharmony_ci security_bpf_prog_free(prog->aux); 23123d0407baSopenharmony_cifree_prog_nouncharge: 23133d0407baSopenharmony_ci bpf_prog_free(prog); 23143d0407baSopenharmony_ci return err; 23153d0407baSopenharmony_ci} 23163d0407baSopenharmony_ci 23173d0407baSopenharmony_ci#define BPF_OBJ_LAST_FIELD file_flags 23183d0407baSopenharmony_ci 23193d0407baSopenharmony_cistatic int bpf_obj_pin(const union bpf_attr *attr) 23203d0407baSopenharmony_ci{ 23213d0407baSopenharmony_ci if (CHECK_ATTR(BPF_OBJ) || attr->file_flags != 0) { 23223d0407baSopenharmony_ci return -EINVAL; 23233d0407baSopenharmony_ci } 23243d0407baSopenharmony_ci 23253d0407baSopenharmony_ci return bpf_obj_pin_user(attr->bpf_fd, u64_to_user_ptr(attr->pathname)); 23263d0407baSopenharmony_ci} 23273d0407baSopenharmony_ci 23283d0407baSopenharmony_cistatic int bpf_obj_get(const union bpf_attr *attr) 23293d0407baSopenharmony_ci{ 23303d0407baSopenharmony_ci if (CHECK_ATTR(BPF_OBJ) || attr->bpf_fd != 0 || attr->file_flags & ~BPF_OBJ_FLAG_MASK) { 23313d0407baSopenharmony_ci return -EINVAL; 23323d0407baSopenharmony_ci } 23333d0407baSopenharmony_ci 23343d0407baSopenharmony_ci return bpf_obj_get_user(u64_to_user_ptr(attr->pathname), attr->file_flags); 23353d0407baSopenharmony_ci} 23363d0407baSopenharmony_ci 23373d0407baSopenharmony_civoid bpf_link_init(struct bpf_link *link, enum bpf_link_type type, const struct bpf_link_ops *ops, 23383d0407baSopenharmony_ci struct bpf_prog *prog) 23393d0407baSopenharmony_ci{ 23403d0407baSopenharmony_ci atomic64_set(&link->refcnt, 1); 23413d0407baSopenharmony_ci link->type = type; 23423d0407baSopenharmony_ci link->id = 0; 23433d0407baSopenharmony_ci link->ops = ops; 23443d0407baSopenharmony_ci link->prog = prog; 23453d0407baSopenharmony_ci} 23463d0407baSopenharmony_ci 23473d0407baSopenharmony_cistatic void bpf_link_free_id(int id) 23483d0407baSopenharmony_ci{ 23493d0407baSopenharmony_ci if (!id) { 23503d0407baSopenharmony_ci return; 23513d0407baSopenharmony_ci } 23523d0407baSopenharmony_ci 23533d0407baSopenharmony_ci spin_lock_bh(&link_idr_lock); 23543d0407baSopenharmony_ci idr_remove(&link_idr, id); 23553d0407baSopenharmony_ci spin_unlock_bh(&link_idr_lock); 23563d0407baSopenharmony_ci} 23573d0407baSopenharmony_ci 23583d0407baSopenharmony_ci/* Clean up bpf_link and corresponding anon_inode file and FD. After 23593d0407baSopenharmony_ci * anon_inode is created, bpf_link can't be just kfree()'d due to deferred 23603d0407baSopenharmony_ci * anon_inode's release() call. This helper marksbpf_link as 23613d0407baSopenharmony_ci * defunct, releases anon_inode file and puts reserved FD. bpf_prog's refcnt 23623d0407baSopenharmony_ci * is not decremented, it's the responsibility of a calling code that failed 23633d0407baSopenharmony_ci * to complete bpf_link initialization. 23643d0407baSopenharmony_ci */ 23653d0407baSopenharmony_civoid bpf_link_cleanup(struct bpf_link_primer *primer) 23663d0407baSopenharmony_ci{ 23673d0407baSopenharmony_ci primer->link->prog = NULL; 23683d0407baSopenharmony_ci bpf_link_free_id(primer->id); 23693d0407baSopenharmony_ci fput(primer->file); 23703d0407baSopenharmony_ci put_unused_fd(primer->fd); 23713d0407baSopenharmony_ci} 23723d0407baSopenharmony_ci 23733d0407baSopenharmony_civoid bpf_link_inc(struct bpf_link *link) 23743d0407baSopenharmony_ci{ 23753d0407baSopenharmony_ci atomic64_inc(&link->refcnt); 23763d0407baSopenharmony_ci} 23773d0407baSopenharmony_ci 23783d0407baSopenharmony_ci/* bpf_link_free is guaranteed to be called from process context */ 23793d0407baSopenharmony_cistatic void bpf_link_free(struct bpf_link *link) 23803d0407baSopenharmony_ci{ 23813d0407baSopenharmony_ci bpf_link_free_id(link->id); 23823d0407baSopenharmony_ci if (link->prog) { 23833d0407baSopenharmony_ci /* detach BPF program, clean up used resources */ 23843d0407baSopenharmony_ci link->ops->release(link); 23853d0407baSopenharmony_ci bpf_prog_put(link->prog); 23863d0407baSopenharmony_ci } 23873d0407baSopenharmony_ci /* free bpf_link and its containing memory */ 23883d0407baSopenharmony_ci link->ops->dealloc(link); 23893d0407baSopenharmony_ci} 23903d0407baSopenharmony_ci 23913d0407baSopenharmony_cistatic void bpf_link_put_deferred(struct work_struct *work) 23923d0407baSopenharmony_ci{ 23933d0407baSopenharmony_ci struct bpf_link *link = container_of(work, struct bpf_link, work); 23943d0407baSopenharmony_ci 23953d0407baSopenharmony_ci bpf_link_free(link); 23963d0407baSopenharmony_ci} 23973d0407baSopenharmony_ci 23983d0407baSopenharmony_ci/* bpf_link_put can be called from atomic context, but ensures that resources 23993d0407baSopenharmony_ci * are freed from process context 24003d0407baSopenharmony_ci */ 24013d0407baSopenharmony_civoid bpf_link_put(struct bpf_link *link) 24023d0407baSopenharmony_ci{ 24033d0407baSopenharmony_ci if (!atomic64_dec_and_test(&link->refcnt)) { 24043d0407baSopenharmony_ci return; 24053d0407baSopenharmony_ci } 24063d0407baSopenharmony_ci 24073d0407baSopenharmony_ci if (in_atomic()) { 24083d0407baSopenharmony_ci INIT_WORK(&link->work, bpf_link_put_deferred); 24093d0407baSopenharmony_ci schedule_work(&link->work); 24103d0407baSopenharmony_ci } else { 24113d0407baSopenharmony_ci bpf_link_free(link); 24123d0407baSopenharmony_ci } 24133d0407baSopenharmony_ci} 24143d0407baSopenharmony_ci 24153d0407baSopenharmony_cistatic int bpf_link_release(struct inode *inode, struct file *filp) 24163d0407baSopenharmony_ci{ 24173d0407baSopenharmony_ci struct bpf_link *link = filp->private_data; 24183d0407baSopenharmony_ci 24193d0407baSopenharmony_ci bpf_link_put(link); 24203d0407baSopenharmony_ci return 0; 24213d0407baSopenharmony_ci} 24223d0407baSopenharmony_ci 24233d0407baSopenharmony_ci#ifdef CONFIG_PROC_FS 24243d0407baSopenharmony_ci#define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) 24253d0407baSopenharmony_ci#define BPF_MAP_TYPE(_id, _ops) 24263d0407baSopenharmony_ci#define BPF_LINK_TYPE(_id, _name) [_id] = #_name, 24273d0407baSopenharmony_cistatic const char *bpf_link_type_strs[] = { 24283d0407baSopenharmony_ci [BPF_LINK_TYPE_UNSPEC] = "<invalid>", 24293d0407baSopenharmony_ci#include <linux/bpf_types.h> 24303d0407baSopenharmony_ci}; 24313d0407baSopenharmony_ci#undef BPF_PROG_TYPE 24323d0407baSopenharmony_ci#undef BPF_MAP_TYPE 24333d0407baSopenharmony_ci#undef BPF_LINK_TYPE 24343d0407baSopenharmony_ci 24353d0407baSopenharmony_cistatic void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp) 24363d0407baSopenharmony_ci{ 24373d0407baSopenharmony_ci const struct bpf_link *link = filp->private_data; 24383d0407baSopenharmony_ci const struct bpf_prog *prog = link->prog; 24393d0407baSopenharmony_ci char prog_tag[sizeof(prog->tag) * 0x2 + 1] = {}; 24403d0407baSopenharmony_ci 24413d0407baSopenharmony_ci bin2hex(prog_tag, prog->tag, sizeof(prog->tag)); 24423d0407baSopenharmony_ci seq_printf(m, 24433d0407baSopenharmony_ci "link_type:\t%s\n" 24443d0407baSopenharmony_ci "link_id:\t%u\n" 24453d0407baSopenharmony_ci "prog_tag:\t%s\n" 24463d0407baSopenharmony_ci "prog_id:\t%u\n", 24473d0407baSopenharmony_ci bpf_link_type_strs[link->type], link->id, prog_tag, prog->aux->id); 24483d0407baSopenharmony_ci if (link->ops->show_fdinfo) { 24493d0407baSopenharmony_ci link->ops->show_fdinfo(link, m); 24503d0407baSopenharmony_ci } 24513d0407baSopenharmony_ci} 24523d0407baSopenharmony_ci#endif 24533d0407baSopenharmony_ci 24543d0407baSopenharmony_cistatic const struct file_operations bpf_link_fops = { 24553d0407baSopenharmony_ci#ifdef CONFIG_PROC_FS 24563d0407baSopenharmony_ci .show_fdinfo = bpf_link_show_fdinfo, 24573d0407baSopenharmony_ci#endif 24583d0407baSopenharmony_ci .release = bpf_link_release, 24593d0407baSopenharmony_ci .read = bpf_dummy_read, 24603d0407baSopenharmony_ci .write = bpf_dummy_write, 24613d0407baSopenharmony_ci}; 24623d0407baSopenharmony_ci 24633d0407baSopenharmony_cistatic int bpf_link_alloc_id(struct bpf_link *link) 24643d0407baSopenharmony_ci{ 24653d0407baSopenharmony_ci int id; 24663d0407baSopenharmony_ci 24673d0407baSopenharmony_ci idr_preload(GFP_KERNEL); 24683d0407baSopenharmony_ci spin_lock_bh(&link_idr_lock); 24693d0407baSopenharmony_ci id = idr_alloc_cyclic(&link_idr, link, 1, INT_MAX, GFP_ATOMIC); 24703d0407baSopenharmony_ci spin_unlock_bh(&link_idr_lock); 24713d0407baSopenharmony_ci idr_preload_end(); 24723d0407baSopenharmony_ci 24733d0407baSopenharmony_ci return id; 24743d0407baSopenharmony_ci} 24753d0407baSopenharmony_ci 24763d0407baSopenharmony_ci/* Prepare bpf_link to be exposed to user-space by allocating anon_inode file, 24773d0407baSopenharmony_ci * reserving unused FD and allocating ID from link_idr. This is to be paired 24783d0407baSopenharmony_ci * with bpf_link_settle() to install FD and ID and expose bpf_link to 24793d0407baSopenharmony_ci * user-space, if bpf_link is successfully attached. If not, bpf_link and 24803d0407baSopenharmony_ci * pre-allocated resources are to be freed with bpf_cleanup() call. All the 24813d0407baSopenharmony_ci * transient state is passed around in struct bpf_link_primer. 24823d0407baSopenharmony_ci * This is preferred way to create and initialize bpf_link, especially when 24833d0407baSopenharmony_ci * there are complicated and expensive operations inbetween creating bpf_link 24843d0407baSopenharmony_ci * itself and attaching it to BPF hook. By using bpf_link_prime() and 24853d0407baSopenharmony_ci * bpf_link_settle() kernel code using bpf_link doesn't have to perform 24863d0407baSopenharmony_ci * expensive (and potentially failing) roll back operations in a rare case 24873d0407baSopenharmony_ci * that file, FD, or ID can't be allocated. 24883d0407baSopenharmony_ci */ 24893d0407baSopenharmony_ciint bpf_link_prime(struct bpf_link *link, struct bpf_link_primer *primer) 24903d0407baSopenharmony_ci{ 24913d0407baSopenharmony_ci struct file *file; 24923d0407baSopenharmony_ci int fd, id; 24933d0407baSopenharmony_ci 24943d0407baSopenharmony_ci fd = get_unused_fd_flags(O_CLOEXEC); 24953d0407baSopenharmony_ci if (fd < 0) { 24963d0407baSopenharmony_ci return fd; 24973d0407baSopenharmony_ci } 24983d0407baSopenharmony_ci 24993d0407baSopenharmony_ci id = bpf_link_alloc_id(link); 25003d0407baSopenharmony_ci if (id < 0) { 25013d0407baSopenharmony_ci put_unused_fd(fd); 25023d0407baSopenharmony_ci return id; 25033d0407baSopenharmony_ci } 25043d0407baSopenharmony_ci 25053d0407baSopenharmony_ci file = anon_inode_getfile("bpf_link", &bpf_link_fops, link, O_CLOEXEC); 25063d0407baSopenharmony_ci if (IS_ERR(file)) { 25073d0407baSopenharmony_ci bpf_link_free_id(id); 25083d0407baSopenharmony_ci put_unused_fd(fd); 25093d0407baSopenharmony_ci return PTR_ERR(file); 25103d0407baSopenharmony_ci } 25113d0407baSopenharmony_ci 25123d0407baSopenharmony_ci primer->link = link; 25133d0407baSopenharmony_ci primer->file = file; 25143d0407baSopenharmony_ci primer->fd = fd; 25153d0407baSopenharmony_ci primer->id = id; 25163d0407baSopenharmony_ci return 0; 25173d0407baSopenharmony_ci} 25183d0407baSopenharmony_ci 25193d0407baSopenharmony_ciint bpf_link_settle(struct bpf_link_primer *primer) 25203d0407baSopenharmony_ci{ 25213d0407baSopenharmony_ci /* make bpf_link fetchable by ID */ 25223d0407baSopenharmony_ci spin_lock_bh(&link_idr_lock); 25233d0407baSopenharmony_ci primer->link->id = primer->id; 25243d0407baSopenharmony_ci spin_unlock_bh(&link_idr_lock); 25253d0407baSopenharmony_ci /* make bpf_link fetchable by FD */ 25263d0407baSopenharmony_ci fd_install(primer->fd, primer->file); 25273d0407baSopenharmony_ci /* pass through installed FD */ 25283d0407baSopenharmony_ci return primer->fd; 25293d0407baSopenharmony_ci} 25303d0407baSopenharmony_ci 25313d0407baSopenharmony_ciint bpf_link_new_fd(struct bpf_link *link) 25323d0407baSopenharmony_ci{ 25333d0407baSopenharmony_ci return anon_inode_getfd("bpf-link", &bpf_link_fops, link, O_CLOEXEC); 25343d0407baSopenharmony_ci} 25353d0407baSopenharmony_ci 25363d0407baSopenharmony_cistruct bpf_link *bpf_link_get_from_fd(u32 ufd) 25373d0407baSopenharmony_ci{ 25383d0407baSopenharmony_ci struct fd f = fdget(ufd); 25393d0407baSopenharmony_ci struct bpf_link *link; 25403d0407baSopenharmony_ci 25413d0407baSopenharmony_ci if (!f.file) { 25423d0407baSopenharmony_ci return ERR_PTR(-EBADF); 25433d0407baSopenharmony_ci } 25443d0407baSopenharmony_ci if (f.file->f_op != &bpf_link_fops) { 25453d0407baSopenharmony_ci fdput(f); 25463d0407baSopenharmony_ci return ERR_PTR(-EINVAL); 25473d0407baSopenharmony_ci } 25483d0407baSopenharmony_ci 25493d0407baSopenharmony_ci link = f.file->private_data; 25503d0407baSopenharmony_ci bpf_link_inc(link); 25513d0407baSopenharmony_ci fdput(f); 25523d0407baSopenharmony_ci 25533d0407baSopenharmony_ci return link; 25543d0407baSopenharmony_ci} 25553d0407baSopenharmony_ci 25563d0407baSopenharmony_cistruct bpf_tracing_link { 25573d0407baSopenharmony_ci struct bpf_link link; 25583d0407baSopenharmony_ci enum bpf_attach_type attach_type; 25593d0407baSopenharmony_ci struct bpf_trampoline *trampoline; 25603d0407baSopenharmony_ci struct bpf_prog *tgt_prog; 25613d0407baSopenharmony_ci}; 25623d0407baSopenharmony_ci 25633d0407baSopenharmony_cistatic void bpf_tracing_link_release(struct bpf_link *link) 25643d0407baSopenharmony_ci{ 25653d0407baSopenharmony_ci struct bpf_tracing_link *tr_link = container_of(link, struct bpf_tracing_link, link); 25663d0407baSopenharmony_ci 25673d0407baSopenharmony_ci WARN_ON_ONCE(bpf_trampoline_unlink_prog(link->prog, tr_link->trampoline)); 25683d0407baSopenharmony_ci 25693d0407baSopenharmony_ci bpf_trampoline_put(tr_link->trampoline); 25703d0407baSopenharmony_ci 25713d0407baSopenharmony_ci /* tgt_prog is NULL if target is a kernel function */ 25723d0407baSopenharmony_ci if (tr_link->tgt_prog) { 25733d0407baSopenharmony_ci bpf_prog_put(tr_link->tgt_prog); 25743d0407baSopenharmony_ci } 25753d0407baSopenharmony_ci} 25763d0407baSopenharmony_ci 25773d0407baSopenharmony_cistatic void bpf_tracing_link_dealloc(struct bpf_link *link) 25783d0407baSopenharmony_ci{ 25793d0407baSopenharmony_ci struct bpf_tracing_link *tr_link = container_of(link, struct bpf_tracing_link, link); 25803d0407baSopenharmony_ci 25813d0407baSopenharmony_ci kfree(tr_link); 25823d0407baSopenharmony_ci} 25833d0407baSopenharmony_ci 25843d0407baSopenharmony_cistatic void bpf_tracing_link_show_fdinfo(const struct bpf_link *link, struct seq_file *seq) 25853d0407baSopenharmony_ci{ 25863d0407baSopenharmony_ci struct bpf_tracing_link *tr_link = container_of(link, struct bpf_tracing_link, link); 25873d0407baSopenharmony_ci 25883d0407baSopenharmony_ci seq_printf(seq, "attach_type:\t%d\n", tr_link->attach_type); 25893d0407baSopenharmony_ci} 25903d0407baSopenharmony_ci 25913d0407baSopenharmony_cistatic int bpf_tracing_link_fill_link_info(const struct bpf_link *link, struct bpf_link_info *info) 25923d0407baSopenharmony_ci{ 25933d0407baSopenharmony_ci struct bpf_tracing_link *tr_link = container_of(link, struct bpf_tracing_link, link); 25943d0407baSopenharmony_ci 25953d0407baSopenharmony_ci info->tracing.attach_type = tr_link->attach_type; 25963d0407baSopenharmony_ci 25973d0407baSopenharmony_ci return 0; 25983d0407baSopenharmony_ci} 25993d0407baSopenharmony_ci 26003d0407baSopenharmony_cistatic const struct bpf_link_ops bpf_tracing_link_lops = { 26013d0407baSopenharmony_ci .release = bpf_tracing_link_release, 26023d0407baSopenharmony_ci .dealloc = bpf_tracing_link_dealloc, 26033d0407baSopenharmony_ci .show_fdinfo = bpf_tracing_link_show_fdinfo, 26043d0407baSopenharmony_ci .fill_link_info = bpf_tracing_link_fill_link_info, 26053d0407baSopenharmony_ci}; 26063d0407baSopenharmony_ci 26073d0407baSopenharmony_cistatic int bpf_tracing_prog_attach(struct bpf_prog *prog, int tgt_prog_fd, u32 btf_id) 26083d0407baSopenharmony_ci{ 26093d0407baSopenharmony_ci struct bpf_link_primer link_primer; 26103d0407baSopenharmony_ci struct bpf_prog *tgt_prog = NULL; 26113d0407baSopenharmony_ci struct bpf_trampoline *tr = NULL; 26123d0407baSopenharmony_ci struct bpf_tracing_link *link; 26133d0407baSopenharmony_ci u64 key = 0; 26143d0407baSopenharmony_ci int err; 26153d0407baSopenharmony_ci 26163d0407baSopenharmony_ci switch (prog->type) { 26173d0407baSopenharmony_ci case BPF_PROG_TYPE_TRACING: 26183d0407baSopenharmony_ci if (prog->expected_attach_type != BPF_TRACE_FENTRY && prog->expected_attach_type != BPF_TRACE_FEXIT && 26193d0407baSopenharmony_ci prog->expected_attach_type != BPF_MODIFY_RETURN) { 26203d0407baSopenharmony_ci err = -EINVAL; 26213d0407baSopenharmony_ci goto out_put_prog; 26223d0407baSopenharmony_ci } 26233d0407baSopenharmony_ci break; 26243d0407baSopenharmony_ci case BPF_PROG_TYPE_EXT: 26253d0407baSopenharmony_ci if (prog->expected_attach_type != 0) { 26263d0407baSopenharmony_ci err = -EINVAL; 26273d0407baSopenharmony_ci goto out_put_prog; 26283d0407baSopenharmony_ci } 26293d0407baSopenharmony_ci break; 26303d0407baSopenharmony_ci case BPF_PROG_TYPE_LSM: 26313d0407baSopenharmony_ci if (prog->expected_attach_type != BPF_LSM_MAC) { 26323d0407baSopenharmony_ci err = -EINVAL; 26333d0407baSopenharmony_ci goto out_put_prog; 26343d0407baSopenharmony_ci } 26353d0407baSopenharmony_ci break; 26363d0407baSopenharmony_ci default: 26373d0407baSopenharmony_ci err = -EINVAL; 26383d0407baSopenharmony_ci goto out_put_prog; 26393d0407baSopenharmony_ci } 26403d0407baSopenharmony_ci 26413d0407baSopenharmony_ci if (!!tgt_prog_fd != !!btf_id) { 26423d0407baSopenharmony_ci err = -EINVAL; 26433d0407baSopenharmony_ci goto out_put_prog; 26443d0407baSopenharmony_ci } 26453d0407baSopenharmony_ci 26463d0407baSopenharmony_ci if (tgt_prog_fd) { 26473d0407baSopenharmony_ci /* For now we only allow new targets for BPF_PROG_TYPE_EXT */ 26483d0407baSopenharmony_ci if (prog->type != BPF_PROG_TYPE_EXT) { 26493d0407baSopenharmony_ci err = -EINVAL; 26503d0407baSopenharmony_ci goto out_put_prog; 26513d0407baSopenharmony_ci } 26523d0407baSopenharmony_ci 26533d0407baSopenharmony_ci tgt_prog = bpf_prog_get(tgt_prog_fd); 26543d0407baSopenharmony_ci if (IS_ERR(tgt_prog)) { 26553d0407baSopenharmony_ci err = PTR_ERR(tgt_prog); 26563d0407baSopenharmony_ci tgt_prog = NULL; 26573d0407baSopenharmony_ci goto out_put_prog; 26583d0407baSopenharmony_ci } 26593d0407baSopenharmony_ci 26603d0407baSopenharmony_ci key = bpf_trampoline_compute_key(tgt_prog, btf_id); 26613d0407baSopenharmony_ci } 26623d0407baSopenharmony_ci 26633d0407baSopenharmony_ci link = kzalloc(sizeof(*link), GFP_USER); 26643d0407baSopenharmony_ci if (!link) { 26653d0407baSopenharmony_ci err = -ENOMEM; 26663d0407baSopenharmony_ci goto out_put_prog; 26673d0407baSopenharmony_ci } 26683d0407baSopenharmony_ci bpf_link_init(&link->link, BPF_LINK_TYPE_TRACING, &bpf_tracing_link_lops, prog); 26693d0407baSopenharmony_ci link->attach_type = prog->expected_attach_type; 26703d0407baSopenharmony_ci 26713d0407baSopenharmony_ci mutex_lock(&prog->aux->dst_mutex); 26723d0407baSopenharmony_ci 26733d0407baSopenharmony_ci /* There are a few possible cases here: 26743d0407baSopenharmony_ci * 26753d0407baSopenharmony_ci * - if prog->aux->dst_trampoline is set, the program was just loaded 26763d0407baSopenharmony_ci * and not yet attached to anything, so we can use the values stored 26773d0407baSopenharmony_ci * in prog->aux 26783d0407baSopenharmony_ci * 26793d0407baSopenharmony_ci * - if prog->aux->dst_trampoline is NULL, the program has already been 26803d0407baSopenharmony_ci * attached to a target and its initial target was cleared (below) 26813d0407baSopenharmony_ci * 26823d0407baSopenharmony_ci * - if tgt_prog != NULL, the caller specified tgt_prog_fd + 26833d0407baSopenharmony_ci * target_btf_id using the link_create API. 26843d0407baSopenharmony_ci * 26853d0407baSopenharmony_ci * - if tgt_prog == NULL when this function was called using the old 26863d0407baSopenharmony_ci * raw_tracepoint_open API, and we need a target from prog->aux 26873d0407baSopenharmony_ci * 26883d0407baSopenharmony_ci * The combination of no saved target in prog->aux, and no target 26893d0407baSopenharmony_ci * specified on load is illegal, and we reject that here. 26903d0407baSopenharmony_ci */ 26913d0407baSopenharmony_ci if (!prog->aux->dst_trampoline && !tgt_prog) { 26923d0407baSopenharmony_ci err = -ENOENT; 26933d0407baSopenharmony_ci goto out_unlock; 26943d0407baSopenharmony_ci } 26953d0407baSopenharmony_ci 26963d0407baSopenharmony_ci if (!prog->aux->dst_trampoline || (key && key != prog->aux->dst_trampoline->key)) { 26973d0407baSopenharmony_ci /* If there is no saved target, or the specified target is 26983d0407baSopenharmony_ci * different from the destination specified at load time, we 26993d0407baSopenharmony_ci * need a new trampoline and a check for compatibility 27003d0407baSopenharmony_ci */ 27013d0407baSopenharmony_ci struct bpf_attach_target_info tgt_info = {}; 27023d0407baSopenharmony_ci 27033d0407baSopenharmony_ci err = bpf_check_attach_target(NULL, prog, tgt_prog, btf_id, &tgt_info); 27043d0407baSopenharmony_ci if (err) { 27053d0407baSopenharmony_ci goto out_unlock; 27063d0407baSopenharmony_ci } 27073d0407baSopenharmony_ci 27083d0407baSopenharmony_ci tr = bpf_trampoline_get(key, &tgt_info); 27093d0407baSopenharmony_ci if (!tr) { 27103d0407baSopenharmony_ci err = -ENOMEM; 27113d0407baSopenharmony_ci goto out_unlock; 27123d0407baSopenharmony_ci } 27133d0407baSopenharmony_ci } else { 27143d0407baSopenharmony_ci /* The caller didn't specify a target, or the target was the 27153d0407baSopenharmony_ci * same as the destination supplied during program load. This 27163d0407baSopenharmony_ci * means we can reuse the trampoline and reference from program 27173d0407baSopenharmony_ci * load time, and there is no need to allocate a new one. This 27183d0407baSopenharmony_ci * can only happen once for any program, as the saved values in 27193d0407baSopenharmony_ci * prog->aux are cleared below. 27203d0407baSopenharmony_ci */ 27213d0407baSopenharmony_ci tr = prog->aux->dst_trampoline; 27223d0407baSopenharmony_ci tgt_prog = prog->aux->dst_prog; 27233d0407baSopenharmony_ci } 27243d0407baSopenharmony_ci 27253d0407baSopenharmony_ci err = bpf_link_prime(&link->link, &link_primer); 27263d0407baSopenharmony_ci if (err) { 27273d0407baSopenharmony_ci goto out_unlock; 27283d0407baSopenharmony_ci } 27293d0407baSopenharmony_ci 27303d0407baSopenharmony_ci err = bpf_trampoline_link_prog(prog, tr); 27313d0407baSopenharmony_ci if (err) { 27323d0407baSopenharmony_ci bpf_link_cleanup(&link_primer); 27333d0407baSopenharmony_ci link = NULL; 27343d0407baSopenharmony_ci goto out_unlock; 27353d0407baSopenharmony_ci } 27363d0407baSopenharmony_ci 27373d0407baSopenharmony_ci link->tgt_prog = tgt_prog; 27383d0407baSopenharmony_ci link->trampoline = tr; 27393d0407baSopenharmony_ci 27403d0407baSopenharmony_ci /* Always clear the trampoline and target prog from prog->aux to make 27413d0407baSopenharmony_ci * sure the original attach destination is not kept alive after a 27423d0407baSopenharmony_ci * program is (re-)attached to another target. 27433d0407baSopenharmony_ci */ 27443d0407baSopenharmony_ci if (prog->aux->dst_prog && (tgt_prog_fd || tr != prog->aux->dst_trampoline)) { 27453d0407baSopenharmony_ci /* got extra prog ref from syscall, or attaching to different prog */ 27463d0407baSopenharmony_ci bpf_prog_put(prog->aux->dst_prog); 27473d0407baSopenharmony_ci } 27483d0407baSopenharmony_ci if (prog->aux->dst_trampoline && tr != prog->aux->dst_trampoline) { 27493d0407baSopenharmony_ci /* we allocated a new trampoline, so free the old one */ 27503d0407baSopenharmony_ci bpf_trampoline_put(prog->aux->dst_trampoline); 27513d0407baSopenharmony_ci } 27523d0407baSopenharmony_ci 27533d0407baSopenharmony_ci prog->aux->dst_prog = NULL; 27543d0407baSopenharmony_ci prog->aux->dst_trampoline = NULL; 27553d0407baSopenharmony_ci mutex_unlock(&prog->aux->dst_mutex); 27563d0407baSopenharmony_ci 27573d0407baSopenharmony_ci return bpf_link_settle(&link_primer); 27583d0407baSopenharmony_ciout_unlock: 27593d0407baSopenharmony_ci if (tr && tr != prog->aux->dst_trampoline) { 27603d0407baSopenharmony_ci bpf_trampoline_put(tr); 27613d0407baSopenharmony_ci } 27623d0407baSopenharmony_ci mutex_unlock(&prog->aux->dst_mutex); 27633d0407baSopenharmony_ci kfree(link); 27643d0407baSopenharmony_ciout_put_prog: 27653d0407baSopenharmony_ci if (tgt_prog_fd && tgt_prog) { 27663d0407baSopenharmony_ci bpf_prog_put(tgt_prog); 27673d0407baSopenharmony_ci } 27683d0407baSopenharmony_ci return err; 27693d0407baSopenharmony_ci} 27703d0407baSopenharmony_ci 27713d0407baSopenharmony_cistruct bpf_raw_tp_link { 27723d0407baSopenharmony_ci struct bpf_link link; 27733d0407baSopenharmony_ci struct bpf_raw_event_map *btp; 27743d0407baSopenharmony_ci}; 27753d0407baSopenharmony_ci 27763d0407baSopenharmony_cistatic void bpf_raw_tp_link_release(struct bpf_link *link) 27773d0407baSopenharmony_ci{ 27783d0407baSopenharmony_ci struct bpf_raw_tp_link *raw_tp = container_of(link, struct bpf_raw_tp_link, link); 27793d0407baSopenharmony_ci 27803d0407baSopenharmony_ci bpf_probe_unregister(raw_tp->btp, raw_tp->link.prog); 27813d0407baSopenharmony_ci bpf_put_raw_tracepoint(raw_tp->btp); 27823d0407baSopenharmony_ci} 27833d0407baSopenharmony_ci 27843d0407baSopenharmony_cistatic void bpf_raw_tp_link_dealloc(struct bpf_link *link) 27853d0407baSopenharmony_ci{ 27863d0407baSopenharmony_ci struct bpf_raw_tp_link *raw_tp = container_of(link, struct bpf_raw_tp_link, link); 27873d0407baSopenharmony_ci 27883d0407baSopenharmony_ci kfree(raw_tp); 27893d0407baSopenharmony_ci} 27903d0407baSopenharmony_ci 27913d0407baSopenharmony_cistatic void bpf_raw_tp_link_show_fdinfo(const struct bpf_link *link, struct seq_file *seq) 27923d0407baSopenharmony_ci{ 27933d0407baSopenharmony_ci struct bpf_raw_tp_link *raw_tp_link = container_of(link, struct bpf_raw_tp_link, link); 27943d0407baSopenharmony_ci 27953d0407baSopenharmony_ci seq_printf(seq, "tp_name:\t%s\n", raw_tp_link->btp->tp->name); 27963d0407baSopenharmony_ci} 27973d0407baSopenharmony_ci 27983d0407baSopenharmony_cistatic int bpf_raw_tp_link_fill_link_info(const struct bpf_link *link, struct bpf_link_info *info) 27993d0407baSopenharmony_ci{ 28003d0407baSopenharmony_ci struct bpf_raw_tp_link *raw_tp_link = container_of(link, struct bpf_raw_tp_link, link); 28013d0407baSopenharmony_ci char __user *ubuf = u64_to_user_ptr(info->raw_tracepoint.tp_name); 28023d0407baSopenharmony_ci const char *tp_name = raw_tp_link->btp->tp->name; 28033d0407baSopenharmony_ci u32 ulen = info->raw_tracepoint.tp_name_len; 28043d0407baSopenharmony_ci size_t tp_len = strlen(tp_name); 28053d0407baSopenharmony_ci 28063d0407baSopenharmony_ci if (!ulen ^ !ubuf) { 28073d0407baSopenharmony_ci return -EINVAL; 28083d0407baSopenharmony_ci } 28093d0407baSopenharmony_ci 28103d0407baSopenharmony_ci info->raw_tracepoint.tp_name_len = tp_len + 1; 28113d0407baSopenharmony_ci 28123d0407baSopenharmony_ci if (!ubuf) { 28133d0407baSopenharmony_ci return 0; 28143d0407baSopenharmony_ci } 28153d0407baSopenharmony_ci 28163d0407baSopenharmony_ci if (ulen >= tp_len + 1) { 28173d0407baSopenharmony_ci if (copy_to_user(ubuf, tp_name, tp_len + 1)) { 28183d0407baSopenharmony_ci return -EFAULT; 28193d0407baSopenharmony_ci } 28203d0407baSopenharmony_ci } else { 28213d0407baSopenharmony_ci char zero = '\0'; 28223d0407baSopenharmony_ci 28233d0407baSopenharmony_ci if (copy_to_user(ubuf, tp_name, ulen - 1)) { 28243d0407baSopenharmony_ci return -EFAULT; 28253d0407baSopenharmony_ci } 28263d0407baSopenharmony_ci if (put_user(zero, ubuf + ulen - 1)) { 28273d0407baSopenharmony_ci return -EFAULT; 28283d0407baSopenharmony_ci } 28293d0407baSopenharmony_ci return -ENOSPC; 28303d0407baSopenharmony_ci } 28313d0407baSopenharmony_ci 28323d0407baSopenharmony_ci return 0; 28333d0407baSopenharmony_ci} 28343d0407baSopenharmony_ci 28353d0407baSopenharmony_cistatic const struct bpf_link_ops bpf_raw_tp_link_lops = { 28363d0407baSopenharmony_ci .release = bpf_raw_tp_link_release, 28373d0407baSopenharmony_ci .dealloc = bpf_raw_tp_link_dealloc, 28383d0407baSopenharmony_ci .show_fdinfo = bpf_raw_tp_link_show_fdinfo, 28393d0407baSopenharmony_ci .fill_link_info = bpf_raw_tp_link_fill_link_info, 28403d0407baSopenharmony_ci}; 28413d0407baSopenharmony_ci 28423d0407baSopenharmony_ci#define BPF_RAW_TRACEPOINT_OPEN_LAST_FIELD raw_tracepoint.prog_fd 28433d0407baSopenharmony_ci 28443d0407baSopenharmony_cistatic int bpf_raw_tracepoint_open(const union bpf_attr *attr) 28453d0407baSopenharmony_ci{ 28463d0407baSopenharmony_ci struct bpf_link_primer link_primer; 28473d0407baSopenharmony_ci struct bpf_raw_tp_link *link; 28483d0407baSopenharmony_ci struct bpf_raw_event_map *btp; 28493d0407baSopenharmony_ci struct bpf_prog *prog; 28503d0407baSopenharmony_ci const char *tp_name; 28513d0407baSopenharmony_ci char buf[128]; 28523d0407baSopenharmony_ci int err; 28533d0407baSopenharmony_ci 28543d0407baSopenharmony_ci if (CHECK_ATTR(BPF_RAW_TRACEPOINT_OPEN)) { 28553d0407baSopenharmony_ci return -EINVAL; 28563d0407baSopenharmony_ci } 28573d0407baSopenharmony_ci 28583d0407baSopenharmony_ci prog = bpf_prog_get(attr->raw_tracepoint.prog_fd); 28593d0407baSopenharmony_ci if (IS_ERR(prog)) { 28603d0407baSopenharmony_ci return PTR_ERR(prog); 28613d0407baSopenharmony_ci } 28623d0407baSopenharmony_ci 28633d0407baSopenharmony_ci switch (prog->type) { 28643d0407baSopenharmony_ci case BPF_PROG_TYPE_TRACING: 28653d0407baSopenharmony_ci case BPF_PROG_TYPE_EXT: 28663d0407baSopenharmony_ci case BPF_PROG_TYPE_LSM: 28673d0407baSopenharmony_ci if (attr->raw_tracepoint.name) { 28683d0407baSopenharmony_ci /* The attach point for this category of programs 28693d0407baSopenharmony_ci * should be specified via btf_id during program load. 28703d0407baSopenharmony_ci */ 28713d0407baSopenharmony_ci err = -EINVAL; 28723d0407baSopenharmony_ci goto out_put_prog; 28733d0407baSopenharmony_ci } 28743d0407baSopenharmony_ci if (prog->type == BPF_PROG_TYPE_TRACING && prog->expected_attach_type == BPF_TRACE_RAW_TP) { 28753d0407baSopenharmony_ci tp_name = prog->aux->attach_func_name; 28763d0407baSopenharmony_ci break; 28773d0407baSopenharmony_ci } 28783d0407baSopenharmony_ci err = bpf_tracing_prog_attach(prog, 0, 0); 28793d0407baSopenharmony_ci if (err >= 0) { 28803d0407baSopenharmony_ci return err; 28813d0407baSopenharmony_ci } 28823d0407baSopenharmony_ci goto out_put_prog; 28833d0407baSopenharmony_ci case BPF_PROG_TYPE_RAW_TRACEPOINT: 28843d0407baSopenharmony_ci case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE: 28853d0407baSopenharmony_ci if (strncpy_from_user(buf, u64_to_user_ptr(attr->raw_tracepoint.name), sizeof(buf) - 1) < 0) { 28863d0407baSopenharmony_ci err = -EFAULT; 28873d0407baSopenharmony_ci goto out_put_prog; 28883d0407baSopenharmony_ci } 28893d0407baSopenharmony_ci buf[sizeof(buf) - 1] = 0; 28903d0407baSopenharmony_ci tp_name = buf; 28913d0407baSopenharmony_ci break; 28923d0407baSopenharmony_ci default: 28933d0407baSopenharmony_ci err = -EINVAL; 28943d0407baSopenharmony_ci goto out_put_prog; 28953d0407baSopenharmony_ci } 28963d0407baSopenharmony_ci 28973d0407baSopenharmony_ci btp = bpf_get_raw_tracepoint(tp_name); 28983d0407baSopenharmony_ci if (!btp) { 28993d0407baSopenharmony_ci err = -ENOENT; 29003d0407baSopenharmony_ci goto out_put_prog; 29013d0407baSopenharmony_ci } 29023d0407baSopenharmony_ci 29033d0407baSopenharmony_ci link = kzalloc(sizeof(*link), GFP_USER); 29043d0407baSopenharmony_ci if (!link) { 29053d0407baSopenharmony_ci err = -ENOMEM; 29063d0407baSopenharmony_ci goto out_put_btp; 29073d0407baSopenharmony_ci } 29083d0407baSopenharmony_ci bpf_link_init(&link->link, BPF_LINK_TYPE_RAW_TRACEPOINT, &bpf_raw_tp_link_lops, prog); 29093d0407baSopenharmony_ci link->btp = btp; 29103d0407baSopenharmony_ci 29113d0407baSopenharmony_ci err = bpf_link_prime(&link->link, &link_primer); 29123d0407baSopenharmony_ci if (err) { 29133d0407baSopenharmony_ci kfree(link); 29143d0407baSopenharmony_ci goto out_put_btp; 29153d0407baSopenharmony_ci } 29163d0407baSopenharmony_ci 29173d0407baSopenharmony_ci err = bpf_probe_register(link->btp, prog); 29183d0407baSopenharmony_ci if (err) { 29193d0407baSopenharmony_ci bpf_link_cleanup(&link_primer); 29203d0407baSopenharmony_ci goto out_put_btp; 29213d0407baSopenharmony_ci } 29223d0407baSopenharmony_ci 29233d0407baSopenharmony_ci return bpf_link_settle(&link_primer); 29243d0407baSopenharmony_ci 29253d0407baSopenharmony_ciout_put_btp: 29263d0407baSopenharmony_ci bpf_put_raw_tracepoint(btp); 29273d0407baSopenharmony_ciout_put_prog: 29283d0407baSopenharmony_ci bpf_prog_put(prog); 29293d0407baSopenharmony_ci return err; 29303d0407baSopenharmony_ci} 29313d0407baSopenharmony_ci 29323d0407baSopenharmony_cistatic int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog, enum bpf_attach_type attach_type) 29333d0407baSopenharmony_ci{ 29343d0407baSopenharmony_ci switch (prog->type) { 29353d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SOCK: 29363d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: 29373d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SOCKOPT: 29383d0407baSopenharmony_ci case BPF_PROG_TYPE_SK_LOOKUP: 29393d0407baSopenharmony_ci return attach_type == prog->expected_attach_type ? 0 : -EINVAL; 29403d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SKB: 29413d0407baSopenharmony_ci if (!capable(CAP_NET_ADMIN)) { 29423d0407baSopenharmony_ci /* cg-skb progs can be loaded by unpriv user. 29433d0407baSopenharmony_ci * check permissions at attach time. 29443d0407baSopenharmony_ci */ 29453d0407baSopenharmony_ci return -EPERM; 29463d0407baSopenharmony_ci } 29473d0407baSopenharmony_ci return prog->enforce_expected_attach_type && prog->expected_attach_type != attach_type ? -EINVAL : 0; 29483d0407baSopenharmony_ci default: 29493d0407baSopenharmony_ci return 0; 29503d0407baSopenharmony_ci } 29513d0407baSopenharmony_ci} 29523d0407baSopenharmony_ci 29533d0407baSopenharmony_cistatic enum bpf_prog_type attach_type_to_prog_type(enum bpf_attach_type attach_type) 29543d0407baSopenharmony_ci{ 29553d0407baSopenharmony_ci switch (attach_type) { 29563d0407baSopenharmony_ci case BPF_CGROUP_INET_INGRESS: 29573d0407baSopenharmony_ci case BPF_CGROUP_INET_EGRESS: 29583d0407baSopenharmony_ci return BPF_PROG_TYPE_CGROUP_SKB; 29593d0407baSopenharmony_ci case BPF_CGROUP_INET_SOCK_CREATE: 29603d0407baSopenharmony_ci case BPF_CGROUP_INET_SOCK_RELEASE: 29613d0407baSopenharmony_ci case BPF_CGROUP_INET4_POST_BIND: 29623d0407baSopenharmony_ci case BPF_CGROUP_INET6_POST_BIND: 29633d0407baSopenharmony_ci return BPF_PROG_TYPE_CGROUP_SOCK; 29643d0407baSopenharmony_ci case BPF_CGROUP_INET4_BIND: 29653d0407baSopenharmony_ci case BPF_CGROUP_INET6_BIND: 29663d0407baSopenharmony_ci case BPF_CGROUP_INET4_CONNECT: 29673d0407baSopenharmony_ci case BPF_CGROUP_INET6_CONNECT: 29683d0407baSopenharmony_ci case BPF_CGROUP_INET4_GETPEERNAME: 29693d0407baSopenharmony_ci case BPF_CGROUP_INET6_GETPEERNAME: 29703d0407baSopenharmony_ci case BPF_CGROUP_INET4_GETSOCKNAME: 29713d0407baSopenharmony_ci case BPF_CGROUP_INET6_GETSOCKNAME: 29723d0407baSopenharmony_ci case BPF_CGROUP_UDP4_SENDMSG: 29733d0407baSopenharmony_ci case BPF_CGROUP_UDP6_SENDMSG: 29743d0407baSopenharmony_ci case BPF_CGROUP_UDP4_RECVMSG: 29753d0407baSopenharmony_ci case BPF_CGROUP_UDP6_RECVMSG: 29763d0407baSopenharmony_ci return BPF_PROG_TYPE_CGROUP_SOCK_ADDR; 29773d0407baSopenharmony_ci case BPF_CGROUP_SOCK_OPS: 29783d0407baSopenharmony_ci return BPF_PROG_TYPE_SOCK_OPS; 29793d0407baSopenharmony_ci case BPF_CGROUP_DEVICE: 29803d0407baSopenharmony_ci return BPF_PROG_TYPE_CGROUP_DEVICE; 29813d0407baSopenharmony_ci case BPF_SK_MSG_VERDICT: 29823d0407baSopenharmony_ci return BPF_PROG_TYPE_SK_MSG; 29833d0407baSopenharmony_ci case BPF_SK_SKB_STREAM_PARSER: 29843d0407baSopenharmony_ci case BPF_SK_SKB_STREAM_VERDICT: 29853d0407baSopenharmony_ci return BPF_PROG_TYPE_SK_SKB; 29863d0407baSopenharmony_ci case BPF_LIRC_MODE2: 29873d0407baSopenharmony_ci return BPF_PROG_TYPE_LIRC_MODE2; 29883d0407baSopenharmony_ci case BPF_FLOW_DISSECTOR: 29893d0407baSopenharmony_ci return BPF_PROG_TYPE_FLOW_DISSECTOR; 29903d0407baSopenharmony_ci case BPF_CGROUP_SYSCTL: 29913d0407baSopenharmony_ci return BPF_PROG_TYPE_CGROUP_SYSCTL; 29923d0407baSopenharmony_ci case BPF_CGROUP_GETSOCKOPT: 29933d0407baSopenharmony_ci case BPF_CGROUP_SETSOCKOPT: 29943d0407baSopenharmony_ci return BPF_PROG_TYPE_CGROUP_SOCKOPT; 29953d0407baSopenharmony_ci case BPF_TRACE_ITER: 29963d0407baSopenharmony_ci return BPF_PROG_TYPE_TRACING; 29973d0407baSopenharmony_ci case BPF_SK_LOOKUP: 29983d0407baSopenharmony_ci return BPF_PROG_TYPE_SK_LOOKUP; 29993d0407baSopenharmony_ci case BPF_XDP: 30003d0407baSopenharmony_ci return BPF_PROG_TYPE_XDP; 30013d0407baSopenharmony_ci default: 30023d0407baSopenharmony_ci return BPF_PROG_TYPE_UNSPEC; 30033d0407baSopenharmony_ci } 30043d0407baSopenharmony_ci} 30053d0407baSopenharmony_ci 30063d0407baSopenharmony_ci#define BPF_PROG_ATTACH_LAST_FIELD replace_bpf_fd 30073d0407baSopenharmony_ci 30083d0407baSopenharmony_ci#define BPF_F_ATTACH_MASK (BPF_F_ALLOW_OVERRIDE | BPF_F_ALLOW_MULTI | BPF_F_REPLACE) 30093d0407baSopenharmony_ci 30103d0407baSopenharmony_cistatic int bpf_prog_attach(const union bpf_attr *attr) 30113d0407baSopenharmony_ci{ 30123d0407baSopenharmony_ci enum bpf_prog_type ptype; 30133d0407baSopenharmony_ci struct bpf_prog *prog; 30143d0407baSopenharmony_ci int ret; 30153d0407baSopenharmony_ci 30163d0407baSopenharmony_ci if (CHECK_ATTR(BPF_PROG_ATTACH)) { 30173d0407baSopenharmony_ci return -EINVAL; 30183d0407baSopenharmony_ci } 30193d0407baSopenharmony_ci 30203d0407baSopenharmony_ci if (attr->attach_flags & ~BPF_F_ATTACH_MASK) { 30213d0407baSopenharmony_ci return -EINVAL; 30223d0407baSopenharmony_ci } 30233d0407baSopenharmony_ci 30243d0407baSopenharmony_ci ptype = attach_type_to_prog_type(attr->attach_type); 30253d0407baSopenharmony_ci if (ptype == BPF_PROG_TYPE_UNSPEC) { 30263d0407baSopenharmony_ci return -EINVAL; 30273d0407baSopenharmony_ci } 30283d0407baSopenharmony_ci 30293d0407baSopenharmony_ci prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype); 30303d0407baSopenharmony_ci if (IS_ERR(prog)) { 30313d0407baSopenharmony_ci return PTR_ERR(prog); 30323d0407baSopenharmony_ci } 30333d0407baSopenharmony_ci 30343d0407baSopenharmony_ci if (bpf_prog_attach_check_attach_type(prog, attr->attach_type)) { 30353d0407baSopenharmony_ci bpf_prog_put(prog); 30363d0407baSopenharmony_ci return -EINVAL; 30373d0407baSopenharmony_ci } 30383d0407baSopenharmony_ci 30393d0407baSopenharmony_ci switch (ptype) { 30403d0407baSopenharmony_ci case BPF_PROG_TYPE_SK_SKB: 30413d0407baSopenharmony_ci case BPF_PROG_TYPE_SK_MSG: 30423d0407baSopenharmony_ci ret = sock_map_get_from_fd(attr, prog); 30433d0407baSopenharmony_ci break; 30443d0407baSopenharmony_ci case BPF_PROG_TYPE_LIRC_MODE2: 30453d0407baSopenharmony_ci ret = lirc_prog_attach(attr, prog); 30463d0407baSopenharmony_ci break; 30473d0407baSopenharmony_ci case BPF_PROG_TYPE_FLOW_DISSECTOR: 30483d0407baSopenharmony_ci ret = netns_bpf_prog_attach(attr, prog); 30493d0407baSopenharmony_ci break; 30503d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_DEVICE: 30513d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SKB: 30523d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SOCK: 30533d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: 30543d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SOCKOPT: 30553d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SYSCTL: 30563d0407baSopenharmony_ci case BPF_PROG_TYPE_SOCK_OPS: 30573d0407baSopenharmony_ci ret = cgroup_bpf_prog_attach(attr, ptype, prog); 30583d0407baSopenharmony_ci break; 30593d0407baSopenharmony_ci default: 30603d0407baSopenharmony_ci ret = -EINVAL; 30613d0407baSopenharmony_ci } 30623d0407baSopenharmony_ci 30633d0407baSopenharmony_ci if (ret) { 30643d0407baSopenharmony_ci bpf_prog_put(prog); 30653d0407baSopenharmony_ci } 30663d0407baSopenharmony_ci return ret; 30673d0407baSopenharmony_ci} 30683d0407baSopenharmony_ci 30693d0407baSopenharmony_ci#define BPF_PROG_DETACH_LAST_FIELD attach_type 30703d0407baSopenharmony_ci 30713d0407baSopenharmony_cistatic int bpf_prog_detach(const union bpf_attr *attr) 30723d0407baSopenharmony_ci{ 30733d0407baSopenharmony_ci enum bpf_prog_type ptype; 30743d0407baSopenharmony_ci 30753d0407baSopenharmony_ci if (CHECK_ATTR(BPF_PROG_DETACH)) { 30763d0407baSopenharmony_ci return -EINVAL; 30773d0407baSopenharmony_ci } 30783d0407baSopenharmony_ci 30793d0407baSopenharmony_ci ptype = attach_type_to_prog_type(attr->attach_type); 30803d0407baSopenharmony_ci 30813d0407baSopenharmony_ci switch (ptype) { 30823d0407baSopenharmony_ci case BPF_PROG_TYPE_SK_MSG: 30833d0407baSopenharmony_ci case BPF_PROG_TYPE_SK_SKB: 30843d0407baSopenharmony_ci return sock_map_prog_detach(attr, ptype); 30853d0407baSopenharmony_ci case BPF_PROG_TYPE_LIRC_MODE2: 30863d0407baSopenharmony_ci return lirc_prog_detach(attr); 30873d0407baSopenharmony_ci case BPF_PROG_TYPE_FLOW_DISSECTOR: 30883d0407baSopenharmony_ci return netns_bpf_prog_detach(attr, ptype); 30893d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_DEVICE: 30903d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SKB: 30913d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SOCK: 30923d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: 30933d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SOCKOPT: 30943d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SYSCTL: 30953d0407baSopenharmony_ci case BPF_PROG_TYPE_SOCK_OPS: 30963d0407baSopenharmony_ci return cgroup_bpf_prog_detach(attr, ptype); 30973d0407baSopenharmony_ci default: 30983d0407baSopenharmony_ci return -EINVAL; 30993d0407baSopenharmony_ci } 31003d0407baSopenharmony_ci} 31013d0407baSopenharmony_ci 31023d0407baSopenharmony_ci#define BPF_PROG_QUERY_LAST_FIELD query.prog_cnt 31033d0407baSopenharmony_ci 31043d0407baSopenharmony_cistatic int bpf_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr) 31053d0407baSopenharmony_ci{ 31063d0407baSopenharmony_ci if (!capable(CAP_NET_ADMIN)) { 31073d0407baSopenharmony_ci return -EPERM; 31083d0407baSopenharmony_ci } 31093d0407baSopenharmony_ci if (CHECK_ATTR(BPF_PROG_QUERY)) { 31103d0407baSopenharmony_ci return -EINVAL; 31113d0407baSopenharmony_ci } 31123d0407baSopenharmony_ci if (attr->query.query_flags & ~BPF_F_QUERY_EFFECTIVE) { 31133d0407baSopenharmony_ci return -EINVAL; 31143d0407baSopenharmony_ci } 31153d0407baSopenharmony_ci 31163d0407baSopenharmony_ci switch (attr->query.attach_type) { 31173d0407baSopenharmony_ci case BPF_CGROUP_INET_INGRESS: 31183d0407baSopenharmony_ci case BPF_CGROUP_INET_EGRESS: 31193d0407baSopenharmony_ci case BPF_CGROUP_INET_SOCK_CREATE: 31203d0407baSopenharmony_ci case BPF_CGROUP_INET_SOCK_RELEASE: 31213d0407baSopenharmony_ci case BPF_CGROUP_INET4_BIND: 31223d0407baSopenharmony_ci case BPF_CGROUP_INET6_BIND: 31233d0407baSopenharmony_ci case BPF_CGROUP_INET4_POST_BIND: 31243d0407baSopenharmony_ci case BPF_CGROUP_INET6_POST_BIND: 31253d0407baSopenharmony_ci case BPF_CGROUP_INET4_CONNECT: 31263d0407baSopenharmony_ci case BPF_CGROUP_INET6_CONNECT: 31273d0407baSopenharmony_ci case BPF_CGROUP_INET4_GETPEERNAME: 31283d0407baSopenharmony_ci case BPF_CGROUP_INET6_GETPEERNAME: 31293d0407baSopenharmony_ci case BPF_CGROUP_INET4_GETSOCKNAME: 31303d0407baSopenharmony_ci case BPF_CGROUP_INET6_GETSOCKNAME: 31313d0407baSopenharmony_ci case BPF_CGROUP_UDP4_SENDMSG: 31323d0407baSopenharmony_ci case BPF_CGROUP_UDP6_SENDMSG: 31333d0407baSopenharmony_ci case BPF_CGROUP_UDP4_RECVMSG: 31343d0407baSopenharmony_ci case BPF_CGROUP_UDP6_RECVMSG: 31353d0407baSopenharmony_ci case BPF_CGROUP_SOCK_OPS: 31363d0407baSopenharmony_ci case BPF_CGROUP_DEVICE: 31373d0407baSopenharmony_ci case BPF_CGROUP_SYSCTL: 31383d0407baSopenharmony_ci case BPF_CGROUP_GETSOCKOPT: 31393d0407baSopenharmony_ci case BPF_CGROUP_SETSOCKOPT: 31403d0407baSopenharmony_ci return cgroup_bpf_prog_query(attr, uattr); 31413d0407baSopenharmony_ci case BPF_LIRC_MODE2: 31423d0407baSopenharmony_ci return lirc_prog_query(attr, uattr); 31433d0407baSopenharmony_ci case BPF_FLOW_DISSECTOR: 31443d0407baSopenharmony_ci case BPF_SK_LOOKUP: 31453d0407baSopenharmony_ci return netns_bpf_prog_query(attr, uattr); 31463d0407baSopenharmony_ci default: 31473d0407baSopenharmony_ci return -EINVAL; 31483d0407baSopenharmony_ci } 31493d0407baSopenharmony_ci} 31503d0407baSopenharmony_ci 31513d0407baSopenharmony_ci#define BPF_PROG_TEST_RUN_LAST_FIELD test.cpu 31523d0407baSopenharmony_ci 31533d0407baSopenharmony_cistatic int bpf_prog_test_run(const union bpf_attr *attr, union bpf_attr __user *uattr) 31543d0407baSopenharmony_ci{ 31553d0407baSopenharmony_ci struct bpf_prog *prog; 31563d0407baSopenharmony_ci int ret = -ENOTSUPP; 31573d0407baSopenharmony_ci 31583d0407baSopenharmony_ci if (CHECK_ATTR(BPF_PROG_TEST_RUN)) { 31593d0407baSopenharmony_ci return -EINVAL; 31603d0407baSopenharmony_ci } 31613d0407baSopenharmony_ci 31623d0407baSopenharmony_ci if ((attr->test.ctx_size_in && !attr->test.ctx_in) || (!attr->test.ctx_size_in && attr->test.ctx_in)) { 31633d0407baSopenharmony_ci return -EINVAL; 31643d0407baSopenharmony_ci } 31653d0407baSopenharmony_ci 31663d0407baSopenharmony_ci if ((attr->test.ctx_size_out && !attr->test.ctx_out) || (!attr->test.ctx_size_out && attr->test.ctx_out)) { 31673d0407baSopenharmony_ci return -EINVAL; 31683d0407baSopenharmony_ci } 31693d0407baSopenharmony_ci 31703d0407baSopenharmony_ci prog = bpf_prog_get(attr->test.prog_fd); 31713d0407baSopenharmony_ci if (IS_ERR(prog)) { 31723d0407baSopenharmony_ci return PTR_ERR(prog); 31733d0407baSopenharmony_ci } 31743d0407baSopenharmony_ci 31753d0407baSopenharmony_ci if (prog->aux->ops->test_run) { 31763d0407baSopenharmony_ci ret = prog->aux->ops->test_run(prog, attr, uattr); 31773d0407baSopenharmony_ci } 31783d0407baSopenharmony_ci 31793d0407baSopenharmony_ci bpf_prog_put(prog); 31803d0407baSopenharmony_ci return ret; 31813d0407baSopenharmony_ci} 31823d0407baSopenharmony_ci 31833d0407baSopenharmony_ci#define BPF_OBJ_GET_NEXT_ID_LAST_FIELD next_id 31843d0407baSopenharmony_ci 31853d0407baSopenharmony_cistatic int bpf_obj_get_next_id(const union bpf_attr *attr, union bpf_attr __user *uattr, struct idr *idr, 31863d0407baSopenharmony_ci spinlock_t *lock) 31873d0407baSopenharmony_ci{ 31883d0407baSopenharmony_ci u32 next_id = attr->start_id; 31893d0407baSopenharmony_ci int err = 0; 31903d0407baSopenharmony_ci 31913d0407baSopenharmony_ci if (CHECK_ATTR(BPF_OBJ_GET_NEXT_ID) || next_id >= INT_MAX) { 31923d0407baSopenharmony_ci return -EINVAL; 31933d0407baSopenharmony_ci } 31943d0407baSopenharmony_ci 31953d0407baSopenharmony_ci if (!capable(CAP_SYS_ADMIN)) { 31963d0407baSopenharmony_ci return -EPERM; 31973d0407baSopenharmony_ci } 31983d0407baSopenharmony_ci 31993d0407baSopenharmony_ci next_id++; 32003d0407baSopenharmony_ci spin_lock_bh(lock); 32013d0407baSopenharmony_ci if (!idr_get_next(idr, &next_id)) { 32023d0407baSopenharmony_ci err = -ENOENT; 32033d0407baSopenharmony_ci } 32043d0407baSopenharmony_ci spin_unlock_bh(lock); 32053d0407baSopenharmony_ci 32063d0407baSopenharmony_ci if (!err) { 32073d0407baSopenharmony_ci err = put_user(next_id, &uattr->next_id); 32083d0407baSopenharmony_ci } 32093d0407baSopenharmony_ci 32103d0407baSopenharmony_ci return err; 32113d0407baSopenharmony_ci} 32123d0407baSopenharmony_ci 32133d0407baSopenharmony_cistruct bpf_map *bpf_map_get_curr_or_next(u32 *id) 32143d0407baSopenharmony_ci{ 32153d0407baSopenharmony_ci struct bpf_map *map; 32163d0407baSopenharmony_ci 32173d0407baSopenharmony_ci spin_lock_bh(&map_idr_lock); 32183d0407baSopenharmony_ci 32193d0407baSopenharmony_ci while (1) { 32203d0407baSopenharmony_ci map = idr_get_next(&map_idr, id); 32213d0407baSopenharmony_ci if (map) { 32223d0407baSopenharmony_ci map = _bpf_map_inc_not_zero(map, false); 32233d0407baSopenharmony_ci if (IS_ERR(map)) { 32243d0407baSopenharmony_ci (*id)++; 32253d0407baSopenharmony_ci continue; 32263d0407baSopenharmony_ci } 32273d0407baSopenharmony_ci } 32283d0407baSopenharmony_ci break; 32293d0407baSopenharmony_ci } 32303d0407baSopenharmony_ci spin_unlock_bh(&map_idr_lock); 32313d0407baSopenharmony_ci 32323d0407baSopenharmony_ci return map; 32333d0407baSopenharmony_ci} 32343d0407baSopenharmony_ci 32353d0407baSopenharmony_cistruct bpf_prog *bpf_prog_get_curr_or_next(u32 *id) 32363d0407baSopenharmony_ci{ 32373d0407baSopenharmony_ci struct bpf_prog *prog; 32383d0407baSopenharmony_ci 32393d0407baSopenharmony_ci spin_lock_bh(&prog_idr_lock); 32403d0407baSopenharmony_ci while (1) { 32413d0407baSopenharmony_ci prog = idr_get_next(&prog_idr, id); 32423d0407baSopenharmony_ci if (prog) { 32433d0407baSopenharmony_ci prog = bpf_prog_inc_not_zero(prog); 32443d0407baSopenharmony_ci if (IS_ERR(prog)) { 32453d0407baSopenharmony_ci (*id)++; 32463d0407baSopenharmony_ci continue; 32473d0407baSopenharmony_ci } 32483d0407baSopenharmony_ci } 32493d0407baSopenharmony_ci break; 32503d0407baSopenharmony_ci } 32513d0407baSopenharmony_ci spin_unlock_bh(&prog_idr_lock); 32523d0407baSopenharmony_ci 32533d0407baSopenharmony_ci return prog; 32543d0407baSopenharmony_ci} 32553d0407baSopenharmony_ci 32563d0407baSopenharmony_ci#define BPF_PROG_GET_FD_BY_ID_LAST_FIELD prog_id 32573d0407baSopenharmony_ci 32583d0407baSopenharmony_cistruct bpf_prog *bpf_prog_by_id(u32 id) 32593d0407baSopenharmony_ci{ 32603d0407baSopenharmony_ci struct bpf_prog *prog; 32613d0407baSopenharmony_ci 32623d0407baSopenharmony_ci if (!id) { 32633d0407baSopenharmony_ci return ERR_PTR(-ENOENT); 32643d0407baSopenharmony_ci } 32653d0407baSopenharmony_ci 32663d0407baSopenharmony_ci spin_lock_bh(&prog_idr_lock); 32673d0407baSopenharmony_ci prog = idr_find(&prog_idr, id); 32683d0407baSopenharmony_ci if (prog) { 32693d0407baSopenharmony_ci prog = bpf_prog_inc_not_zero(prog); 32703d0407baSopenharmony_ci } else { 32713d0407baSopenharmony_ci prog = ERR_PTR(-ENOENT); 32723d0407baSopenharmony_ci } 32733d0407baSopenharmony_ci spin_unlock_bh(&prog_idr_lock); 32743d0407baSopenharmony_ci return prog; 32753d0407baSopenharmony_ci} 32763d0407baSopenharmony_ci 32773d0407baSopenharmony_cistatic int bpf_prog_get_fd_by_id(const union bpf_attr *attr) 32783d0407baSopenharmony_ci{ 32793d0407baSopenharmony_ci struct bpf_prog *prog; 32803d0407baSopenharmony_ci u32 id = attr->prog_id; 32813d0407baSopenharmony_ci int fd; 32823d0407baSopenharmony_ci 32833d0407baSopenharmony_ci if (CHECK_ATTR(BPF_PROG_GET_FD_BY_ID)) { 32843d0407baSopenharmony_ci return -EINVAL; 32853d0407baSopenharmony_ci } 32863d0407baSopenharmony_ci 32873d0407baSopenharmony_ci if (!capable(CAP_SYS_ADMIN)) { 32883d0407baSopenharmony_ci return -EPERM; 32893d0407baSopenharmony_ci } 32903d0407baSopenharmony_ci 32913d0407baSopenharmony_ci prog = bpf_prog_by_id(id); 32923d0407baSopenharmony_ci if (IS_ERR(prog)) { 32933d0407baSopenharmony_ci return PTR_ERR(prog); 32943d0407baSopenharmony_ci } 32953d0407baSopenharmony_ci 32963d0407baSopenharmony_ci fd = bpf_prog_new_fd(prog); 32973d0407baSopenharmony_ci if (fd < 0) { 32983d0407baSopenharmony_ci bpf_prog_put(prog); 32993d0407baSopenharmony_ci } 33003d0407baSopenharmony_ci 33013d0407baSopenharmony_ci return fd; 33023d0407baSopenharmony_ci} 33033d0407baSopenharmony_ci 33043d0407baSopenharmony_ci#define BPF_MAP_GET_FD_BY_ID_LAST_FIELD open_flags 33053d0407baSopenharmony_ci 33063d0407baSopenharmony_cistatic int bpf_map_get_fd_by_id(const union bpf_attr *attr) 33073d0407baSopenharmony_ci{ 33083d0407baSopenharmony_ci struct bpf_map *map; 33093d0407baSopenharmony_ci u32 id = attr->map_id; 33103d0407baSopenharmony_ci int f_flags; 33113d0407baSopenharmony_ci int fd; 33123d0407baSopenharmony_ci 33133d0407baSopenharmony_ci if (CHECK_ATTR(BPF_MAP_GET_FD_BY_ID) || attr->open_flags & ~BPF_OBJ_FLAG_MASK) { 33143d0407baSopenharmony_ci return -EINVAL; 33153d0407baSopenharmony_ci } 33163d0407baSopenharmony_ci 33173d0407baSopenharmony_ci if (!capable(CAP_SYS_ADMIN)) { 33183d0407baSopenharmony_ci return -EPERM; 33193d0407baSopenharmony_ci } 33203d0407baSopenharmony_ci 33213d0407baSopenharmony_ci f_flags = bpf_get_file_flag(attr->open_flags); 33223d0407baSopenharmony_ci if (f_flags < 0) { 33233d0407baSopenharmony_ci return f_flags; 33243d0407baSopenharmony_ci } 33253d0407baSopenharmony_ci 33263d0407baSopenharmony_ci spin_lock_bh(&map_idr_lock); 33273d0407baSopenharmony_ci map = idr_find(&map_idr, id); 33283d0407baSopenharmony_ci if (map) { 33293d0407baSopenharmony_ci map = _bpf_map_inc_not_zero(map, true); 33303d0407baSopenharmony_ci } else { 33313d0407baSopenharmony_ci map = ERR_PTR(-ENOENT); 33323d0407baSopenharmony_ci } 33333d0407baSopenharmony_ci spin_unlock_bh(&map_idr_lock); 33343d0407baSopenharmony_ci 33353d0407baSopenharmony_ci if (IS_ERR(map)) { 33363d0407baSopenharmony_ci return PTR_ERR(map); 33373d0407baSopenharmony_ci } 33383d0407baSopenharmony_ci 33393d0407baSopenharmony_ci fd = bpf_map_new_fd(map, f_flags); 33403d0407baSopenharmony_ci if (fd < 0) { 33413d0407baSopenharmony_ci bpf_map_put_with_uref(map); 33423d0407baSopenharmony_ci } 33433d0407baSopenharmony_ci 33443d0407baSopenharmony_ci return fd; 33453d0407baSopenharmony_ci} 33463d0407baSopenharmony_ci 33473d0407baSopenharmony_cistatic const struct bpf_map *bpf_map_from_imm(const struct bpf_prog *prog, unsigned long addr, u32 *off, u32 *type) 33483d0407baSopenharmony_ci{ 33493d0407baSopenharmony_ci const struct bpf_map *map; 33503d0407baSopenharmony_ci int i; 33513d0407baSopenharmony_ci 33523d0407baSopenharmony_ci mutex_lock(&prog->aux->used_maps_mutex); 33533d0407baSopenharmony_ci for (i = 0, *off = 0; i < prog->aux->used_map_cnt; i++) { 33543d0407baSopenharmony_ci map = prog->aux->used_maps[i]; 33553d0407baSopenharmony_ci if (map == (void *)addr) { 33563d0407baSopenharmony_ci *type = BPF_PSEUDO_MAP_FD; 33573d0407baSopenharmony_ci goto out; 33583d0407baSopenharmony_ci } 33593d0407baSopenharmony_ci if (!map->ops->map_direct_value_meta) { 33603d0407baSopenharmony_ci continue; 33613d0407baSopenharmony_ci } 33623d0407baSopenharmony_ci if (!map->ops->map_direct_value_meta(map, addr, off)) { 33633d0407baSopenharmony_ci *type = BPF_PSEUDO_MAP_VALUE; 33643d0407baSopenharmony_ci goto out; 33653d0407baSopenharmony_ci } 33663d0407baSopenharmony_ci } 33673d0407baSopenharmony_ci map = NULL; 33683d0407baSopenharmony_ci 33693d0407baSopenharmony_ciout: 33703d0407baSopenharmony_ci mutex_unlock(&prog->aux->used_maps_mutex); 33713d0407baSopenharmony_ci return map; 33723d0407baSopenharmony_ci} 33733d0407baSopenharmony_ci 33743d0407baSopenharmony_cistatic struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog, const struct cred *f_cred) 33753d0407baSopenharmony_ci{ 33763d0407baSopenharmony_ci const struct bpf_map *map; 33773d0407baSopenharmony_ci struct bpf_insn *insns; 33783d0407baSopenharmony_ci u32 off, type; 33793d0407baSopenharmony_ci u64 imm; 33803d0407baSopenharmony_ci u8 code; 33813d0407baSopenharmony_ci int i; 33823d0407baSopenharmony_ci 33833d0407baSopenharmony_ci insns = kmemdup(prog->insnsi, bpf_prog_insn_size(prog), GFP_USER); 33843d0407baSopenharmony_ci if (!insns) { 33853d0407baSopenharmony_ci return insns; 33863d0407baSopenharmony_ci } 33873d0407baSopenharmony_ci 33883d0407baSopenharmony_ci for (i = 0; i < prog->len; i++) { 33893d0407baSopenharmony_ci code = insns[i].code; 33903d0407baSopenharmony_ci 33913d0407baSopenharmony_ci if (code == (BPF_JMP | BPF_TAIL_CALL)) { 33923d0407baSopenharmony_ci insns[i].code = BPF_JMP | BPF_CALL; 33933d0407baSopenharmony_ci insns[i].imm = BPF_FUNC_tail_call; 33943d0407baSopenharmony_ci /* fall-through */ 33953d0407baSopenharmony_ci } 33963d0407baSopenharmony_ci if (code == (BPF_JMP | BPF_CALL) || code == (BPF_JMP | BPF_CALL_ARGS)) { 33973d0407baSopenharmony_ci if (code == (BPF_JMP | BPF_CALL_ARGS)) { 33983d0407baSopenharmony_ci insns[i].code = BPF_JMP | BPF_CALL; 33993d0407baSopenharmony_ci } 34003d0407baSopenharmony_ci if (!bpf_dump_raw_ok(f_cred)) { 34013d0407baSopenharmony_ci insns[i].imm = 0; 34023d0407baSopenharmony_ci } 34033d0407baSopenharmony_ci continue; 34043d0407baSopenharmony_ci } 34053d0407baSopenharmony_ci if (BPF_CLASS(code) == BPF_LDX && BPF_MODE(code) == BPF_PROBE_MEM) { 34063d0407baSopenharmony_ci insns[i].code = BPF_LDX | BPF_SIZE(code) | BPF_MEM; 34073d0407baSopenharmony_ci continue; 34083d0407baSopenharmony_ci } 34093d0407baSopenharmony_ci 34103d0407baSopenharmony_ci if (code != (BPF_LD | BPF_IMM | BPF_DW)) { 34113d0407baSopenharmony_ci continue; 34123d0407baSopenharmony_ci } 34133d0407baSopenharmony_ci 34143d0407baSopenharmony_ci imm = ((u64)insns[i + 1].imm << 32) | (u32)insns[i].imm; 34153d0407baSopenharmony_ci map = bpf_map_from_imm(prog, imm, &off, &type); 34163d0407baSopenharmony_ci if (map) { 34173d0407baSopenharmony_ci insns[i].src_reg = type; 34183d0407baSopenharmony_ci insns[i].imm = map->id; 34193d0407baSopenharmony_ci insns[i + 1].imm = off; 34203d0407baSopenharmony_ci continue; 34213d0407baSopenharmony_ci } 34223d0407baSopenharmony_ci } 34233d0407baSopenharmony_ci 34243d0407baSopenharmony_ci return insns; 34253d0407baSopenharmony_ci} 34263d0407baSopenharmony_ci 34273d0407baSopenharmony_cistatic int set_info_rec_size(struct bpf_prog_info *info) 34283d0407baSopenharmony_ci{ 34293d0407baSopenharmony_ci /* 34303d0407baSopenharmony_ci * Ensure info.*_rec_size is the same as kernel expected size 34313d0407baSopenharmony_ci * 34323d0407baSopenharmony_ci * or 34333d0407baSopenharmony_ci * 34343d0407baSopenharmony_ci * Only allow zero *_rec_size if both _rec_size and _cnt are 34353d0407baSopenharmony_ci * zero. In this case, the kernel will set the expected 34363d0407baSopenharmony_ci * _rec_size back to the info. 34373d0407baSopenharmony_ci */ 34383d0407baSopenharmony_ci 34393d0407baSopenharmony_ci if ((info->nr_func_info || info->func_info_rec_size) && info->func_info_rec_size != sizeof(struct bpf_func_info)) { 34403d0407baSopenharmony_ci return -EINVAL; 34413d0407baSopenharmony_ci } 34423d0407baSopenharmony_ci 34433d0407baSopenharmony_ci if ((info->nr_line_info || info->line_info_rec_size) && info->line_info_rec_size != sizeof(struct bpf_line_info)) { 34443d0407baSopenharmony_ci return -EINVAL; 34453d0407baSopenharmony_ci } 34463d0407baSopenharmony_ci 34473d0407baSopenharmony_ci if ((info->nr_jited_line_info || info->jited_line_info_rec_size) && 34483d0407baSopenharmony_ci info->jited_line_info_rec_size != sizeof(__u64)) { 34493d0407baSopenharmony_ci return -EINVAL; 34503d0407baSopenharmony_ci } 34513d0407baSopenharmony_ci 34523d0407baSopenharmony_ci info->func_info_rec_size = sizeof(struct bpf_func_info); 34533d0407baSopenharmony_ci info->line_info_rec_size = sizeof(struct bpf_line_info); 34543d0407baSopenharmony_ci info->jited_line_info_rec_size = sizeof(__u64); 34553d0407baSopenharmony_ci 34563d0407baSopenharmony_ci return 0; 34573d0407baSopenharmony_ci} 34583d0407baSopenharmony_ci 34593d0407baSopenharmony_cistatic int bpf_prog_get_info_by_fd(struct file *file, struct bpf_prog *prog, const union bpf_attr *attr, 34603d0407baSopenharmony_ci union bpf_attr __user *uattr) 34613d0407baSopenharmony_ci{ 34623d0407baSopenharmony_ci struct bpf_prog_info __user *uinfo = u64_to_user_ptr(attr->info.info); 34633d0407baSopenharmony_ci struct bpf_prog_info info; 34643d0407baSopenharmony_ci u32 info_len = attr->info.info_len; 34653d0407baSopenharmony_ci struct bpf_prog_stats stats; 34663d0407baSopenharmony_ci char __user *uinsns; 34673d0407baSopenharmony_ci u32 ulen; 34683d0407baSopenharmony_ci int err; 34693d0407baSopenharmony_ci 34703d0407baSopenharmony_ci err = bpf_check_uarg_tail_zero(uinfo, sizeof(info), info_len); 34713d0407baSopenharmony_ci if (err) { 34723d0407baSopenharmony_ci return err; 34733d0407baSopenharmony_ci } 34743d0407baSopenharmony_ci info_len = min_t(u32, sizeof(info), info_len); 34753d0407baSopenharmony_ci 34763d0407baSopenharmony_ci memset(&info, 0, sizeof(info)); 34773d0407baSopenharmony_ci if (copy_from_user(&info, uinfo, info_len)) { 34783d0407baSopenharmony_ci return -EFAULT; 34793d0407baSopenharmony_ci } 34803d0407baSopenharmony_ci 34813d0407baSopenharmony_ci info.type = prog->type; 34823d0407baSopenharmony_ci info.id = prog->aux->id; 34833d0407baSopenharmony_ci info.load_time = prog->aux->load_time; 34843d0407baSopenharmony_ci info.created_by_uid = from_kuid_munged(current_user_ns(), prog->aux->user->uid); 34853d0407baSopenharmony_ci info.gpl_compatible = prog->gpl_compatible; 34863d0407baSopenharmony_ci 34873d0407baSopenharmony_ci memcpy(info.tag, prog->tag, sizeof(prog->tag)); 34883d0407baSopenharmony_ci memcpy(info.name, prog->aux->name, sizeof(prog->aux->name)); 34893d0407baSopenharmony_ci 34903d0407baSopenharmony_ci mutex_lock(&prog->aux->used_maps_mutex); 34913d0407baSopenharmony_ci ulen = info.nr_map_ids; 34923d0407baSopenharmony_ci info.nr_map_ids = prog->aux->used_map_cnt; 34933d0407baSopenharmony_ci ulen = min_t(u32, info.nr_map_ids, ulen); 34943d0407baSopenharmony_ci if (ulen) { 34953d0407baSopenharmony_ci u32 __user *user_map_ids = u64_to_user_ptr(info.map_ids); 34963d0407baSopenharmony_ci u32 i; 34973d0407baSopenharmony_ci 34983d0407baSopenharmony_ci for (i = 0; i < ulen; i++) { 34993d0407baSopenharmony_ci if (put_user(prog->aux->used_maps[i]->id, &user_map_ids[i])) { 35003d0407baSopenharmony_ci mutex_unlock(&prog->aux->used_maps_mutex); 35013d0407baSopenharmony_ci return -EFAULT; 35023d0407baSopenharmony_ci } 35033d0407baSopenharmony_ci } 35043d0407baSopenharmony_ci } 35053d0407baSopenharmony_ci mutex_unlock(&prog->aux->used_maps_mutex); 35063d0407baSopenharmony_ci 35073d0407baSopenharmony_ci err = set_info_rec_size(&info); 35083d0407baSopenharmony_ci if (err) { 35093d0407baSopenharmony_ci return err; 35103d0407baSopenharmony_ci } 35113d0407baSopenharmony_ci 35123d0407baSopenharmony_ci bpf_prog_get_stats(prog, &stats); 35133d0407baSopenharmony_ci info.run_time_ns = stats.nsecs; 35143d0407baSopenharmony_ci info.run_cnt = stats.cnt; 35153d0407baSopenharmony_ci 35163d0407baSopenharmony_ci if (!bpf_capable()) { 35173d0407baSopenharmony_ci info.jited_prog_len = 0; 35183d0407baSopenharmony_ci info.xlated_prog_len = 0; 35193d0407baSopenharmony_ci info.nr_jited_ksyms = 0; 35203d0407baSopenharmony_ci info.nr_jited_func_lens = 0; 35213d0407baSopenharmony_ci info.nr_func_info = 0; 35223d0407baSopenharmony_ci info.nr_line_info = 0; 35233d0407baSopenharmony_ci info.nr_jited_line_info = 0; 35243d0407baSopenharmony_ci goto done; 35253d0407baSopenharmony_ci } 35263d0407baSopenharmony_ci 35273d0407baSopenharmony_ci ulen = info.xlated_prog_len; 35283d0407baSopenharmony_ci info.xlated_prog_len = bpf_prog_insn_size(prog); 35293d0407baSopenharmony_ci if (info.xlated_prog_len && ulen) { 35303d0407baSopenharmony_ci struct bpf_insn *insns_sanitized; 35313d0407baSopenharmony_ci bool fault; 35323d0407baSopenharmony_ci 35333d0407baSopenharmony_ci if (prog->blinded && !bpf_dump_raw_ok(file->f_cred)) { 35343d0407baSopenharmony_ci info.xlated_prog_insns = 0; 35353d0407baSopenharmony_ci goto done; 35363d0407baSopenharmony_ci } 35373d0407baSopenharmony_ci insns_sanitized = bpf_insn_prepare_dump(prog, file->f_cred); 35383d0407baSopenharmony_ci if (!insns_sanitized) { 35393d0407baSopenharmony_ci return -ENOMEM; 35403d0407baSopenharmony_ci } 35413d0407baSopenharmony_ci uinsns = u64_to_user_ptr(info.xlated_prog_insns); 35423d0407baSopenharmony_ci ulen = min_t(u32, info.xlated_prog_len, ulen); 35433d0407baSopenharmony_ci fault = copy_to_user(uinsns, insns_sanitized, ulen); 35443d0407baSopenharmony_ci kfree(insns_sanitized); 35453d0407baSopenharmony_ci if (fault) { 35463d0407baSopenharmony_ci return -EFAULT; 35473d0407baSopenharmony_ci } 35483d0407baSopenharmony_ci } 35493d0407baSopenharmony_ci 35503d0407baSopenharmony_ci if (bpf_prog_is_dev_bound(prog->aux)) { 35513d0407baSopenharmony_ci err = bpf_prog_offload_info_fill(&info, prog); 35523d0407baSopenharmony_ci if (err) { 35533d0407baSopenharmony_ci return err; 35543d0407baSopenharmony_ci } 35553d0407baSopenharmony_ci goto done; 35563d0407baSopenharmony_ci } 35573d0407baSopenharmony_ci 35583d0407baSopenharmony_ci /* NOTE: the following code is supposed to be skipped for offload. 35593d0407baSopenharmony_ci * bpf_prog_offload_info_fill() is the place to fill similar fields 35603d0407baSopenharmony_ci * for offload. 35613d0407baSopenharmony_ci */ 35623d0407baSopenharmony_ci ulen = info.jited_prog_len; 35633d0407baSopenharmony_ci if (prog->aux->func_cnt) { 35643d0407baSopenharmony_ci u32 i; 35653d0407baSopenharmony_ci 35663d0407baSopenharmony_ci info.jited_prog_len = 0; 35673d0407baSopenharmony_ci for (i = 0; i < prog->aux->func_cnt; i++) { 35683d0407baSopenharmony_ci info.jited_prog_len += prog->aux->func[i]->jited_len; 35693d0407baSopenharmony_ci } 35703d0407baSopenharmony_ci } else { 35713d0407baSopenharmony_ci info.jited_prog_len = prog->jited_len; 35723d0407baSopenharmony_ci } 35733d0407baSopenharmony_ci 35743d0407baSopenharmony_ci if (info.jited_prog_len && ulen) { 35753d0407baSopenharmony_ci if (bpf_dump_raw_ok(file->f_cred)) { 35763d0407baSopenharmony_ci uinsns = u64_to_user_ptr(info.jited_prog_insns); 35773d0407baSopenharmony_ci ulen = min_t(u32, info.jited_prog_len, ulen); 35783d0407baSopenharmony_ci 35793d0407baSopenharmony_ci /* for multi-function programs, copy the JITed 35803d0407baSopenharmony_ci * instructions for all the functions 35813d0407baSopenharmony_ci */ 35823d0407baSopenharmony_ci if (prog->aux->func_cnt) { 35833d0407baSopenharmony_ci u32 len, free, i; 35843d0407baSopenharmony_ci u8 *img; 35853d0407baSopenharmony_ci 35863d0407baSopenharmony_ci free = ulen; 35873d0407baSopenharmony_ci for (i = 0; i < prog->aux->func_cnt; i++) { 35883d0407baSopenharmony_ci len = prog->aux->func[i]->jited_len; 35893d0407baSopenharmony_ci len = min_t(u32, len, free); 35903d0407baSopenharmony_ci img = (u8 *)prog->aux->func[i]->bpf_func; 35913d0407baSopenharmony_ci if (copy_to_user(uinsns, img, len)) { 35923d0407baSopenharmony_ci return -EFAULT; 35933d0407baSopenharmony_ci } 35943d0407baSopenharmony_ci uinsns += len; 35953d0407baSopenharmony_ci free -= len; 35963d0407baSopenharmony_ci if (!free) { 35973d0407baSopenharmony_ci break; 35983d0407baSopenharmony_ci } 35993d0407baSopenharmony_ci } 36003d0407baSopenharmony_ci } else { 36013d0407baSopenharmony_ci if (copy_to_user(uinsns, prog->bpf_func, ulen)) { 36023d0407baSopenharmony_ci return -EFAULT; 36033d0407baSopenharmony_ci } 36043d0407baSopenharmony_ci } 36053d0407baSopenharmony_ci } else { 36063d0407baSopenharmony_ci info.jited_prog_insns = 0; 36073d0407baSopenharmony_ci } 36083d0407baSopenharmony_ci } 36093d0407baSopenharmony_ci 36103d0407baSopenharmony_ci ulen = info.nr_jited_ksyms; 36113d0407baSopenharmony_ci info.nr_jited_ksyms = prog->aux->func_cnt ?: 1; 36123d0407baSopenharmony_ci if (ulen) { 36133d0407baSopenharmony_ci if (bpf_dump_raw_ok(file->f_cred)) { 36143d0407baSopenharmony_ci unsigned long ksym_addr; 36153d0407baSopenharmony_ci u64 __user *user_ksyms; 36163d0407baSopenharmony_ci u32 i; 36173d0407baSopenharmony_ci 36183d0407baSopenharmony_ci /* copy the address of the kernel symbol 36193d0407baSopenharmony_ci * corresponding to each function 36203d0407baSopenharmony_ci */ 36213d0407baSopenharmony_ci ulen = min_t(u32, info.nr_jited_ksyms, ulen); 36223d0407baSopenharmony_ci user_ksyms = u64_to_user_ptr(info.jited_ksyms); 36233d0407baSopenharmony_ci if (prog->aux->func_cnt) { 36243d0407baSopenharmony_ci for (i = 0; i < ulen; i++) { 36253d0407baSopenharmony_ci ksym_addr = (unsigned long)prog->aux->func[i]->bpf_func; 36263d0407baSopenharmony_ci if (put_user((u64)ksym_addr, &user_ksyms[i])) { 36273d0407baSopenharmony_ci return -EFAULT; 36283d0407baSopenharmony_ci } 36293d0407baSopenharmony_ci } 36303d0407baSopenharmony_ci } else { 36313d0407baSopenharmony_ci ksym_addr = (unsigned long)prog->bpf_func; 36323d0407baSopenharmony_ci if (put_user((u64)ksym_addr, &user_ksyms[0])) { 36333d0407baSopenharmony_ci return -EFAULT; 36343d0407baSopenharmony_ci } 36353d0407baSopenharmony_ci } 36363d0407baSopenharmony_ci } else { 36373d0407baSopenharmony_ci info.jited_ksyms = 0; 36383d0407baSopenharmony_ci } 36393d0407baSopenharmony_ci } 36403d0407baSopenharmony_ci 36413d0407baSopenharmony_ci ulen = info.nr_jited_func_lens; 36423d0407baSopenharmony_ci info.nr_jited_func_lens = prog->aux->func_cnt ?: 1; 36433d0407baSopenharmony_ci if (ulen) { 36443d0407baSopenharmony_ci if (bpf_dump_raw_ok(file->f_cred)) { 36453d0407baSopenharmony_ci u32 __user *user_lens; 36463d0407baSopenharmony_ci u32 func_len, i; 36473d0407baSopenharmony_ci 36483d0407baSopenharmony_ci /* copy the JITed image lengths for each function */ 36493d0407baSopenharmony_ci ulen = min_t(u32, info.nr_jited_func_lens, ulen); 36503d0407baSopenharmony_ci user_lens = u64_to_user_ptr(info.jited_func_lens); 36513d0407baSopenharmony_ci if (prog->aux->func_cnt) { 36523d0407baSopenharmony_ci for (i = 0; i < ulen; i++) { 36533d0407baSopenharmony_ci func_len = prog->aux->func[i]->jited_len; 36543d0407baSopenharmony_ci if (put_user(func_len, &user_lens[i])) { 36553d0407baSopenharmony_ci return -EFAULT; 36563d0407baSopenharmony_ci } 36573d0407baSopenharmony_ci } 36583d0407baSopenharmony_ci } else { 36593d0407baSopenharmony_ci func_len = prog->jited_len; 36603d0407baSopenharmony_ci if (put_user(func_len, &user_lens[0])) { 36613d0407baSopenharmony_ci return -EFAULT; 36623d0407baSopenharmony_ci } 36633d0407baSopenharmony_ci } 36643d0407baSopenharmony_ci } else { 36653d0407baSopenharmony_ci info.jited_func_lens = 0; 36663d0407baSopenharmony_ci } 36673d0407baSopenharmony_ci } 36683d0407baSopenharmony_ci 36693d0407baSopenharmony_ci if (prog->aux->btf) { 36703d0407baSopenharmony_ci info.btf_id = btf_id(prog->aux->btf); 36713d0407baSopenharmony_ci } 36723d0407baSopenharmony_ci 36733d0407baSopenharmony_ci ulen = info.nr_func_info; 36743d0407baSopenharmony_ci info.nr_func_info = prog->aux->func_info_cnt; 36753d0407baSopenharmony_ci if (info.nr_func_info && ulen) { 36763d0407baSopenharmony_ci char __user *user_finfo; 36773d0407baSopenharmony_ci 36783d0407baSopenharmony_ci user_finfo = u64_to_user_ptr(info.func_info); 36793d0407baSopenharmony_ci ulen = min_t(u32, info.nr_func_info, ulen); 36803d0407baSopenharmony_ci if (copy_to_user(user_finfo, prog->aux->func_info, info.func_info_rec_size * ulen)) { 36813d0407baSopenharmony_ci return -EFAULT; 36823d0407baSopenharmony_ci } 36833d0407baSopenharmony_ci } 36843d0407baSopenharmony_ci 36853d0407baSopenharmony_ci ulen = info.nr_line_info; 36863d0407baSopenharmony_ci info.nr_line_info = prog->aux->nr_linfo; 36873d0407baSopenharmony_ci if (info.nr_line_info && ulen) { 36883d0407baSopenharmony_ci __u8 __user *user_linfo; 36893d0407baSopenharmony_ci 36903d0407baSopenharmony_ci user_linfo = u64_to_user_ptr(info.line_info); 36913d0407baSopenharmony_ci ulen = min_t(u32, info.nr_line_info, ulen); 36923d0407baSopenharmony_ci if (copy_to_user(user_linfo, prog->aux->linfo, info.line_info_rec_size * ulen)) { 36933d0407baSopenharmony_ci return -EFAULT; 36943d0407baSopenharmony_ci } 36953d0407baSopenharmony_ci } 36963d0407baSopenharmony_ci 36973d0407baSopenharmony_ci ulen = info.nr_jited_line_info; 36983d0407baSopenharmony_ci if (prog->aux->jited_linfo) { 36993d0407baSopenharmony_ci info.nr_jited_line_info = prog->aux->nr_linfo; 37003d0407baSopenharmony_ci } else { 37013d0407baSopenharmony_ci info.nr_jited_line_info = 0; 37023d0407baSopenharmony_ci } 37033d0407baSopenharmony_ci if (info.nr_jited_line_info && ulen) { 37043d0407baSopenharmony_ci if (bpf_dump_raw_ok(file->f_cred)) { 37053d0407baSopenharmony_ci __u64 __user *user_linfo; 37063d0407baSopenharmony_ci u32 i; 37073d0407baSopenharmony_ci 37083d0407baSopenharmony_ci user_linfo = u64_to_user_ptr(info.jited_line_info); 37093d0407baSopenharmony_ci ulen = min_t(u32, info.nr_jited_line_info, ulen); 37103d0407baSopenharmony_ci for (i = 0; i < ulen; i++) { 37113d0407baSopenharmony_ci if (put_user((__u64)(long)prog->aux->jited_linfo[i], &user_linfo[i])) { 37123d0407baSopenharmony_ci return -EFAULT; 37133d0407baSopenharmony_ci } 37143d0407baSopenharmony_ci } 37153d0407baSopenharmony_ci } else { 37163d0407baSopenharmony_ci info.jited_line_info = 0; 37173d0407baSopenharmony_ci } 37183d0407baSopenharmony_ci } 37193d0407baSopenharmony_ci 37203d0407baSopenharmony_ci ulen = info.nr_prog_tags; 37213d0407baSopenharmony_ci info.nr_prog_tags = prog->aux->func_cnt ?: 1; 37223d0407baSopenharmony_ci if (ulen) { 37233d0407baSopenharmony_ci __u8 __user(*user_prog_tags)[BPF_TAG_SIZE]; 37243d0407baSopenharmony_ci u32 i; 37253d0407baSopenharmony_ci 37263d0407baSopenharmony_ci user_prog_tags = u64_to_user_ptr(info.prog_tags); 37273d0407baSopenharmony_ci ulen = min_t(u32, info.nr_prog_tags, ulen); 37283d0407baSopenharmony_ci if (prog->aux->func_cnt) { 37293d0407baSopenharmony_ci for (i = 0; i < ulen; i++) { 37303d0407baSopenharmony_ci if (copy_to_user(user_prog_tags[i], prog->aux->func[i]->tag, BPF_TAG_SIZE)) { 37313d0407baSopenharmony_ci return -EFAULT; 37323d0407baSopenharmony_ci } 37333d0407baSopenharmony_ci } 37343d0407baSopenharmony_ci } else { 37353d0407baSopenharmony_ci if (copy_to_user(user_prog_tags[0], prog->tag, BPF_TAG_SIZE)) { 37363d0407baSopenharmony_ci return -EFAULT; 37373d0407baSopenharmony_ci } 37383d0407baSopenharmony_ci } 37393d0407baSopenharmony_ci } 37403d0407baSopenharmony_ci 37413d0407baSopenharmony_cidone: 37423d0407baSopenharmony_ci if (copy_to_user(uinfo, &info, info_len) || put_user(info_len, &uattr->info.info_len)) { 37433d0407baSopenharmony_ci return -EFAULT; 37443d0407baSopenharmony_ci } 37453d0407baSopenharmony_ci 37463d0407baSopenharmony_ci return 0; 37473d0407baSopenharmony_ci} 37483d0407baSopenharmony_ci 37493d0407baSopenharmony_cistatic int bpf_map_get_info_by_fd(struct file *file, struct bpf_map *map, const union bpf_attr *attr, 37503d0407baSopenharmony_ci union bpf_attr __user *uattr) 37513d0407baSopenharmony_ci{ 37523d0407baSopenharmony_ci struct bpf_map_info __user *uinfo = u64_to_user_ptr(attr->info.info); 37533d0407baSopenharmony_ci struct bpf_map_info info; 37543d0407baSopenharmony_ci u32 info_len = attr->info.info_len; 37553d0407baSopenharmony_ci int err; 37563d0407baSopenharmony_ci 37573d0407baSopenharmony_ci err = bpf_check_uarg_tail_zero(uinfo, sizeof(info), info_len); 37583d0407baSopenharmony_ci if (err) { 37593d0407baSopenharmony_ci return err; 37603d0407baSopenharmony_ci } 37613d0407baSopenharmony_ci info_len = min_t(u32, sizeof(info), info_len); 37623d0407baSopenharmony_ci 37633d0407baSopenharmony_ci memset(&info, 0, sizeof(info)); 37643d0407baSopenharmony_ci info.type = map->map_type; 37653d0407baSopenharmony_ci info.id = map->id; 37663d0407baSopenharmony_ci info.key_size = map->key_size; 37673d0407baSopenharmony_ci info.value_size = map->value_size; 37683d0407baSopenharmony_ci info.max_entries = map->max_entries; 37693d0407baSopenharmony_ci info.map_flags = map->map_flags; 37703d0407baSopenharmony_ci memcpy(info.name, map->name, sizeof(map->name)); 37713d0407baSopenharmony_ci 37723d0407baSopenharmony_ci if (map->btf) { 37733d0407baSopenharmony_ci info.btf_id = btf_id(map->btf); 37743d0407baSopenharmony_ci info.btf_key_type_id = map->btf_key_type_id; 37753d0407baSopenharmony_ci info.btf_value_type_id = map->btf_value_type_id; 37763d0407baSopenharmony_ci } 37773d0407baSopenharmony_ci info.btf_vmlinux_value_type_id = map->btf_vmlinux_value_type_id; 37783d0407baSopenharmony_ci 37793d0407baSopenharmony_ci if (bpf_map_is_dev_bound(map)) { 37803d0407baSopenharmony_ci err = bpf_map_offload_info_fill(&info, map); 37813d0407baSopenharmony_ci if (err) { 37823d0407baSopenharmony_ci return err; 37833d0407baSopenharmony_ci } 37843d0407baSopenharmony_ci } 37853d0407baSopenharmony_ci 37863d0407baSopenharmony_ci if (copy_to_user(uinfo, &info, info_len) || put_user(info_len, &uattr->info.info_len)) { 37873d0407baSopenharmony_ci return -EFAULT; 37883d0407baSopenharmony_ci } 37893d0407baSopenharmony_ci 37903d0407baSopenharmony_ci return 0; 37913d0407baSopenharmony_ci} 37923d0407baSopenharmony_ci 37933d0407baSopenharmony_cistatic int bpf_btf_get_info_by_fd(struct file *file, struct btf *btf, const union bpf_attr *attr, 37943d0407baSopenharmony_ci union bpf_attr __user *uattr) 37953d0407baSopenharmony_ci{ 37963d0407baSopenharmony_ci struct bpf_btf_info __user *uinfo = u64_to_user_ptr(attr->info.info); 37973d0407baSopenharmony_ci u32 info_len = attr->info.info_len; 37983d0407baSopenharmony_ci int err; 37993d0407baSopenharmony_ci 38003d0407baSopenharmony_ci err = bpf_check_uarg_tail_zero(uinfo, sizeof(*uinfo), info_len); 38013d0407baSopenharmony_ci if (err) { 38023d0407baSopenharmony_ci return err; 38033d0407baSopenharmony_ci } 38043d0407baSopenharmony_ci 38053d0407baSopenharmony_ci return btf_get_info_by_fd(btf, attr, uattr); 38063d0407baSopenharmony_ci} 38073d0407baSopenharmony_ci 38083d0407baSopenharmony_cistatic int bpf_link_get_info_by_fd(struct file *file, struct bpf_link *link, const union bpf_attr *attr, 38093d0407baSopenharmony_ci union bpf_attr __user *uattr) 38103d0407baSopenharmony_ci{ 38113d0407baSopenharmony_ci struct bpf_link_info __user *uinfo = u64_to_user_ptr(attr->info.info); 38123d0407baSopenharmony_ci struct bpf_link_info info; 38133d0407baSopenharmony_ci u32 info_len = attr->info.info_len; 38143d0407baSopenharmony_ci int err; 38153d0407baSopenharmony_ci 38163d0407baSopenharmony_ci err = bpf_check_uarg_tail_zero(uinfo, sizeof(info), info_len); 38173d0407baSopenharmony_ci if (err) { 38183d0407baSopenharmony_ci return err; 38193d0407baSopenharmony_ci } 38203d0407baSopenharmony_ci info_len = min_t(u32, sizeof(info), info_len); 38213d0407baSopenharmony_ci 38223d0407baSopenharmony_ci memset(&info, 0, sizeof(info)); 38233d0407baSopenharmony_ci if (copy_from_user(&info, uinfo, info_len)) { 38243d0407baSopenharmony_ci return -EFAULT; 38253d0407baSopenharmony_ci } 38263d0407baSopenharmony_ci 38273d0407baSopenharmony_ci info.type = link->type; 38283d0407baSopenharmony_ci info.id = link->id; 38293d0407baSopenharmony_ci info.prog_id = link->prog->aux->id; 38303d0407baSopenharmony_ci 38313d0407baSopenharmony_ci if (link->ops->fill_link_info) { 38323d0407baSopenharmony_ci err = link->ops->fill_link_info(link, &info); 38333d0407baSopenharmony_ci if (err) { 38343d0407baSopenharmony_ci return err; 38353d0407baSopenharmony_ci } 38363d0407baSopenharmony_ci } 38373d0407baSopenharmony_ci 38383d0407baSopenharmony_ci if (copy_to_user(uinfo, &info, info_len) || put_user(info_len, &uattr->info.info_len)) { 38393d0407baSopenharmony_ci return -EFAULT; 38403d0407baSopenharmony_ci } 38413d0407baSopenharmony_ci 38423d0407baSopenharmony_ci return 0; 38433d0407baSopenharmony_ci} 38443d0407baSopenharmony_ci 38453d0407baSopenharmony_ci#define BPF_OBJ_GET_INFO_BY_FD_LAST_FIELD info.info 38463d0407baSopenharmony_ci 38473d0407baSopenharmony_cistatic int bpf_obj_get_info_by_fd(const union bpf_attr *attr, union bpf_attr __user *uattr) 38483d0407baSopenharmony_ci{ 38493d0407baSopenharmony_ci int ufd = attr->info.bpf_fd; 38503d0407baSopenharmony_ci struct fd f; 38513d0407baSopenharmony_ci int err; 38523d0407baSopenharmony_ci 38533d0407baSopenharmony_ci if (CHECK_ATTR(BPF_OBJ_GET_INFO_BY_FD)) { 38543d0407baSopenharmony_ci return -EINVAL; 38553d0407baSopenharmony_ci } 38563d0407baSopenharmony_ci 38573d0407baSopenharmony_ci f = fdget(ufd); 38583d0407baSopenharmony_ci if (!f.file) { 38593d0407baSopenharmony_ci return -EBADFD; 38603d0407baSopenharmony_ci } 38613d0407baSopenharmony_ci 38623d0407baSopenharmony_ci if (f.file->f_op == &bpf_prog_fops) { 38633d0407baSopenharmony_ci err = bpf_prog_get_info_by_fd(f.file, f.file->private_data, attr, uattr); 38643d0407baSopenharmony_ci } else if (f.file->f_op == &bpf_map_fops) { 38653d0407baSopenharmony_ci err = bpf_map_get_info_by_fd(f.file, f.file->private_data, attr, uattr); 38663d0407baSopenharmony_ci } else if (f.file->f_op == &btf_fops) { 38673d0407baSopenharmony_ci err = bpf_btf_get_info_by_fd(f.file, f.file->private_data, attr, uattr); 38683d0407baSopenharmony_ci } else if (f.file->f_op == &bpf_link_fops) { 38693d0407baSopenharmony_ci err = bpf_link_get_info_by_fd(f.file, f.file->private_data, attr, uattr); 38703d0407baSopenharmony_ci } else { 38713d0407baSopenharmony_ci err = -EINVAL; 38723d0407baSopenharmony_ci } 38733d0407baSopenharmony_ci 38743d0407baSopenharmony_ci fdput(f); 38753d0407baSopenharmony_ci return err; 38763d0407baSopenharmony_ci} 38773d0407baSopenharmony_ci 38783d0407baSopenharmony_ci#define BPF_BTF_LOAD_LAST_FIELD btf_log_level 38793d0407baSopenharmony_ci 38803d0407baSopenharmony_cistatic int bpf_btf_load(const union bpf_attr *attr) 38813d0407baSopenharmony_ci{ 38823d0407baSopenharmony_ci if (CHECK_ATTR(BPF_BTF_LOAD)) { 38833d0407baSopenharmony_ci return -EINVAL; 38843d0407baSopenharmony_ci } 38853d0407baSopenharmony_ci 38863d0407baSopenharmony_ci if (!bpf_capable()) { 38873d0407baSopenharmony_ci return -EPERM; 38883d0407baSopenharmony_ci } 38893d0407baSopenharmony_ci 38903d0407baSopenharmony_ci return btf_new_fd(attr); 38913d0407baSopenharmony_ci} 38923d0407baSopenharmony_ci 38933d0407baSopenharmony_ci#define BPF_BTF_GET_FD_BY_ID_LAST_FIELD btf_id 38943d0407baSopenharmony_ci 38953d0407baSopenharmony_cistatic int bpf_btf_get_fd_by_id(const union bpf_attr *attr) 38963d0407baSopenharmony_ci{ 38973d0407baSopenharmony_ci if (CHECK_ATTR(BPF_BTF_GET_FD_BY_ID)) { 38983d0407baSopenharmony_ci return -EINVAL; 38993d0407baSopenharmony_ci } 39003d0407baSopenharmony_ci 39013d0407baSopenharmony_ci if (!capable(CAP_SYS_ADMIN)) { 39023d0407baSopenharmony_ci return -EPERM; 39033d0407baSopenharmony_ci } 39043d0407baSopenharmony_ci 39053d0407baSopenharmony_ci return btf_get_fd_by_id(attr->btf_id); 39063d0407baSopenharmony_ci} 39073d0407baSopenharmony_ci 39083d0407baSopenharmony_cistatic int bpf_task_fd_query_copy(const union bpf_attr *attr, union bpf_attr __user *uattr, u32 prog_id, u32 fd_type, 39093d0407baSopenharmony_ci const char *buf, u64 probe_offset, u64 probe_addr) 39103d0407baSopenharmony_ci{ 39113d0407baSopenharmony_ci char __user *ubuf = u64_to_user_ptr(attr->task_fd_query.buf); 39123d0407baSopenharmony_ci u32 len = buf ? strlen(buf) : 0, input_len; 39133d0407baSopenharmony_ci int err = 0; 39143d0407baSopenharmony_ci 39153d0407baSopenharmony_ci if (put_user(len, &uattr->task_fd_query.buf_len)) { 39163d0407baSopenharmony_ci return -EFAULT; 39173d0407baSopenharmony_ci } 39183d0407baSopenharmony_ci input_len = attr->task_fd_query.buf_len; 39193d0407baSopenharmony_ci if (input_len && ubuf) { 39203d0407baSopenharmony_ci if (!len) { 39213d0407baSopenharmony_ci /* nothing to copy, just make ubuf NULL terminated */ 39223d0407baSopenharmony_ci char zero = '\0'; 39233d0407baSopenharmony_ci 39243d0407baSopenharmony_ci if (put_user(zero, ubuf)) { 39253d0407baSopenharmony_ci return -EFAULT; 39263d0407baSopenharmony_ci } 39273d0407baSopenharmony_ci } else if (input_len >= len + 1) { 39283d0407baSopenharmony_ci /* ubuf can hold the string with NULL terminator */ 39293d0407baSopenharmony_ci if (copy_to_user(ubuf, buf, len + 1)) { 39303d0407baSopenharmony_ci return -EFAULT; 39313d0407baSopenharmony_ci } 39323d0407baSopenharmony_ci } else { 39333d0407baSopenharmony_ci /* ubuf cannot hold the string with NULL terminator, 39343d0407baSopenharmony_ci * do a partial copy with NULL terminator. 39353d0407baSopenharmony_ci */ 39363d0407baSopenharmony_ci char zero = '\0'; 39373d0407baSopenharmony_ci 39383d0407baSopenharmony_ci err = -ENOSPC; 39393d0407baSopenharmony_ci if (copy_to_user(ubuf, buf, input_len - 1)) { 39403d0407baSopenharmony_ci return -EFAULT; 39413d0407baSopenharmony_ci } 39423d0407baSopenharmony_ci if (put_user(zero, ubuf + input_len - 1)) { 39433d0407baSopenharmony_ci return -EFAULT; 39443d0407baSopenharmony_ci } 39453d0407baSopenharmony_ci } 39463d0407baSopenharmony_ci } 39473d0407baSopenharmony_ci 39483d0407baSopenharmony_ci if (put_user(prog_id, &uattr->task_fd_query.prog_id) || put_user(fd_type, &uattr->task_fd_query.fd_type) || 39493d0407baSopenharmony_ci put_user(probe_offset, &uattr->task_fd_query.probe_offset) || 39503d0407baSopenharmony_ci put_user(probe_addr, &uattr->task_fd_query.probe_addr)) { 39513d0407baSopenharmony_ci return -EFAULT; 39523d0407baSopenharmony_ci } 39533d0407baSopenharmony_ci 39543d0407baSopenharmony_ci return err; 39553d0407baSopenharmony_ci} 39563d0407baSopenharmony_ci 39573d0407baSopenharmony_ci#define BPF_TASK_FD_QUERY_LAST_FIELD task_fd_query.probe_addr 39583d0407baSopenharmony_ci 39593d0407baSopenharmony_cistatic int bpf_task_fd_query(const union bpf_attr *attr, union bpf_attr __user *uattr) 39603d0407baSopenharmony_ci{ 39613d0407baSopenharmony_ci pid_t pid = attr->task_fd_query.pid; 39623d0407baSopenharmony_ci u32 fd = attr->task_fd_query.fd; 39633d0407baSopenharmony_ci const struct perf_event *event; 39643d0407baSopenharmony_ci struct files_struct *files; 39653d0407baSopenharmony_ci struct task_struct *task; 39663d0407baSopenharmony_ci struct file *file; 39673d0407baSopenharmony_ci int err; 39683d0407baSopenharmony_ci 39693d0407baSopenharmony_ci if (CHECK_ATTR(BPF_TASK_FD_QUERY)) { 39703d0407baSopenharmony_ci return -EINVAL; 39713d0407baSopenharmony_ci } 39723d0407baSopenharmony_ci 39733d0407baSopenharmony_ci if (!capable(CAP_SYS_ADMIN)) { 39743d0407baSopenharmony_ci return -EPERM; 39753d0407baSopenharmony_ci } 39763d0407baSopenharmony_ci 39773d0407baSopenharmony_ci if (attr->task_fd_query.flags != 0) { 39783d0407baSopenharmony_ci return -EINVAL; 39793d0407baSopenharmony_ci } 39803d0407baSopenharmony_ci 39813d0407baSopenharmony_ci task = get_pid_task(find_vpid(pid), PIDTYPE_PID); 39823d0407baSopenharmony_ci if (!task) { 39833d0407baSopenharmony_ci return -ENOENT; 39843d0407baSopenharmony_ci } 39853d0407baSopenharmony_ci 39863d0407baSopenharmony_ci files = get_files_struct(task); 39873d0407baSopenharmony_ci put_task_struct(task); 39883d0407baSopenharmony_ci if (!files) { 39893d0407baSopenharmony_ci return -ENOENT; 39903d0407baSopenharmony_ci } 39913d0407baSopenharmony_ci 39923d0407baSopenharmony_ci err = 0; 39933d0407baSopenharmony_ci spin_lock(&files->file_lock); 39943d0407baSopenharmony_ci file = fcheck_files(files, fd); 39953d0407baSopenharmony_ci if (!file) { 39963d0407baSopenharmony_ci err = -EBADF; 39973d0407baSopenharmony_ci } else { 39983d0407baSopenharmony_ci get_file(file); 39993d0407baSopenharmony_ci } 40003d0407baSopenharmony_ci spin_unlock(&files->file_lock); 40013d0407baSopenharmony_ci put_files_struct(files); 40023d0407baSopenharmony_ci 40033d0407baSopenharmony_ci if (err) { 40043d0407baSopenharmony_ci goto out; 40053d0407baSopenharmony_ci } 40063d0407baSopenharmony_ci 40073d0407baSopenharmony_ci if (file->f_op == &bpf_link_fops) { 40083d0407baSopenharmony_ci struct bpf_link *link = file->private_data; 40093d0407baSopenharmony_ci 40103d0407baSopenharmony_ci if (link->ops == &bpf_raw_tp_link_lops) { 40113d0407baSopenharmony_ci struct bpf_raw_tp_link *raw_tp = container_of(link, struct bpf_raw_tp_link, link); 40123d0407baSopenharmony_ci struct bpf_raw_event_map *btp = raw_tp->btp; 40133d0407baSopenharmony_ci 40143d0407baSopenharmony_ci err = bpf_task_fd_query_copy(attr, uattr, raw_tp->link.prog->aux->id, BPF_FD_TYPE_RAW_TRACEPOINT, 40153d0407baSopenharmony_ci btp->tp->name, 0, 0); 40163d0407baSopenharmony_ci goto put_file; 40173d0407baSopenharmony_ci } 40183d0407baSopenharmony_ci goto out_not_supp; 40193d0407baSopenharmony_ci } 40203d0407baSopenharmony_ci 40213d0407baSopenharmony_ci event = perf_get_event(file); 40223d0407baSopenharmony_ci if (!IS_ERR(event)) { 40233d0407baSopenharmony_ci u64 probe_offset, probe_addr; 40243d0407baSopenharmony_ci u32 prog_id, fd_type; 40253d0407baSopenharmony_ci const char *buf; 40263d0407baSopenharmony_ci 40273d0407baSopenharmony_ci err = bpf_get_perf_event_info(event, &prog_id, &fd_type, &buf, &probe_offset, &probe_addr); 40283d0407baSopenharmony_ci if (!err) { 40293d0407baSopenharmony_ci err = bpf_task_fd_query_copy(attr, uattr, prog_id, fd_type, buf, probe_offset, probe_addr); 40303d0407baSopenharmony_ci } 40313d0407baSopenharmony_ci goto put_file; 40323d0407baSopenharmony_ci } 40333d0407baSopenharmony_ci 40343d0407baSopenharmony_ciout_not_supp: 40353d0407baSopenharmony_ci err = -ENOTSUPP; 40363d0407baSopenharmony_ciput_file: 40373d0407baSopenharmony_ci fput(file); 40383d0407baSopenharmony_ciout: 40393d0407baSopenharmony_ci return err; 40403d0407baSopenharmony_ci} 40413d0407baSopenharmony_ci 40423d0407baSopenharmony_ci#define BPF_MAP_BATCH_LAST_FIELD batch.flags 40433d0407baSopenharmony_ci 40443d0407baSopenharmony_ci#define BPF_DO_BATCH(fn) \ 40453d0407baSopenharmony_ci do { \ 40463d0407baSopenharmony_ci if (!(fn)) { \ 40473d0407baSopenharmony_ci err = -ENOTSUPP; \ 40483d0407baSopenharmony_ci goto err_put; \ 40493d0407baSopenharmony_ci } \ 40503d0407baSopenharmony_ci err = fn(map, attr, uattr); \ 40513d0407baSopenharmony_ci } while (0) 40523d0407baSopenharmony_ci 40533d0407baSopenharmony_cistatic int bpf_map_do_batch(const union bpf_attr *attr, union bpf_attr __user *uattr, int cmd) 40543d0407baSopenharmony_ci{ 40553d0407baSopenharmony_ci struct bpf_map *map; 40563d0407baSopenharmony_ci int err, ufd; 40573d0407baSopenharmony_ci struct fd f; 40583d0407baSopenharmony_ci 40593d0407baSopenharmony_ci if (CHECK_ATTR(BPF_MAP_BATCH)) { 40603d0407baSopenharmony_ci return -EINVAL; 40613d0407baSopenharmony_ci } 40623d0407baSopenharmony_ci 40633d0407baSopenharmony_ci ufd = attr->batch.map_fd; 40643d0407baSopenharmony_ci f = fdget(ufd); 40653d0407baSopenharmony_ci map = __bpf_map_get(f); 40663d0407baSopenharmony_ci if (IS_ERR(map)) { 40673d0407baSopenharmony_ci return PTR_ERR(map); 40683d0407baSopenharmony_ci } 40693d0407baSopenharmony_ci 40703d0407baSopenharmony_ci if ((cmd == BPF_MAP_LOOKUP_BATCH || cmd == BPF_MAP_LOOKUP_AND_DELETE_BATCH) && 40713d0407baSopenharmony_ci !(map_get_sys_perms(map, f) & FMODE_CAN_READ)) { 40723d0407baSopenharmony_ci err = -EPERM; 40733d0407baSopenharmony_ci goto err_put; 40743d0407baSopenharmony_ci } 40753d0407baSopenharmony_ci 40763d0407baSopenharmony_ci if (cmd != BPF_MAP_LOOKUP_BATCH && !(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) { 40773d0407baSopenharmony_ci err = -EPERM; 40783d0407baSopenharmony_ci goto err_put; 40793d0407baSopenharmony_ci } 40803d0407baSopenharmony_ci 40813d0407baSopenharmony_ci if (cmd == BPF_MAP_LOOKUP_BATCH) { 40823d0407baSopenharmony_ci BPF_DO_BATCH(map->ops->map_lookup_batch); 40833d0407baSopenharmony_ci } else if (cmd == BPF_MAP_LOOKUP_AND_DELETE_BATCH) { 40843d0407baSopenharmony_ci BPF_DO_BATCH(map->ops->map_lookup_and_delete_batch); 40853d0407baSopenharmony_ci } else if (cmd == BPF_MAP_UPDATE_BATCH) { 40863d0407baSopenharmony_ci BPF_DO_BATCH(map->ops->map_update_batch); 40873d0407baSopenharmony_ci } else { 40883d0407baSopenharmony_ci BPF_DO_BATCH(map->ops->map_delete_batch); 40893d0407baSopenharmony_ci } 40903d0407baSopenharmony_ci 40913d0407baSopenharmony_cierr_put: 40923d0407baSopenharmony_ci fdput(f); 40933d0407baSopenharmony_ci return err; 40943d0407baSopenharmony_ci} 40953d0407baSopenharmony_ci 40963d0407baSopenharmony_cistatic int tracing_bpf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog) 40973d0407baSopenharmony_ci{ 40983d0407baSopenharmony_ci if (attr->link_create.attach_type != prog->expected_attach_type) { 40993d0407baSopenharmony_ci return -EINVAL; 41003d0407baSopenharmony_ci } 41013d0407baSopenharmony_ci 41023d0407baSopenharmony_ci if (prog->expected_attach_type == BPF_TRACE_ITER) { 41033d0407baSopenharmony_ci return bpf_iter_link_attach(attr, prog); 41043d0407baSopenharmony_ci } else if (prog->type == BPF_PROG_TYPE_EXT) { 41053d0407baSopenharmony_ci return bpf_tracing_prog_attach(prog, attr->link_create.target_fd, attr->link_create.target_btf_id); 41063d0407baSopenharmony_ci } 41073d0407baSopenharmony_ci return -EINVAL; 41083d0407baSopenharmony_ci} 41093d0407baSopenharmony_ci 41103d0407baSopenharmony_ci#define BPF_LINK_CREATE_LAST_FIELD link_create.iter_info_len 41113d0407baSopenharmony_cistatic int link_create(union bpf_attr *attr) 41123d0407baSopenharmony_ci{ 41133d0407baSopenharmony_ci enum bpf_prog_type ptype; 41143d0407baSopenharmony_ci struct bpf_prog *prog; 41153d0407baSopenharmony_ci int ret; 41163d0407baSopenharmony_ci 41173d0407baSopenharmony_ci if (CHECK_ATTR(BPF_LINK_CREATE)) { 41183d0407baSopenharmony_ci return -EINVAL; 41193d0407baSopenharmony_ci } 41203d0407baSopenharmony_ci 41213d0407baSopenharmony_ci prog = bpf_prog_get(attr->link_create.prog_fd); 41223d0407baSopenharmony_ci if (IS_ERR(prog)) { 41233d0407baSopenharmony_ci return PTR_ERR(prog); 41243d0407baSopenharmony_ci } 41253d0407baSopenharmony_ci 41263d0407baSopenharmony_ci ret = bpf_prog_attach_check_attach_type(prog, attr->link_create.attach_type); 41273d0407baSopenharmony_ci if (ret) { 41283d0407baSopenharmony_ci goto out; 41293d0407baSopenharmony_ci } 41303d0407baSopenharmony_ci 41313d0407baSopenharmony_ci if (prog->type == BPF_PROG_TYPE_EXT) { 41323d0407baSopenharmony_ci ret = tracing_bpf_link_attach(attr, prog); 41333d0407baSopenharmony_ci goto out; 41343d0407baSopenharmony_ci } 41353d0407baSopenharmony_ci 41363d0407baSopenharmony_ci ptype = attach_type_to_prog_type(attr->link_create.attach_type); 41373d0407baSopenharmony_ci if (ptype == BPF_PROG_TYPE_UNSPEC || ptype != prog->type) { 41383d0407baSopenharmony_ci ret = -EINVAL; 41393d0407baSopenharmony_ci goto out; 41403d0407baSopenharmony_ci } 41413d0407baSopenharmony_ci 41423d0407baSopenharmony_ci switch (ptype) { 41433d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SKB: 41443d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SOCK: 41453d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: 41463d0407baSopenharmony_ci case BPF_PROG_TYPE_SOCK_OPS: 41473d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_DEVICE: 41483d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SYSCTL: 41493d0407baSopenharmony_ci case BPF_PROG_TYPE_CGROUP_SOCKOPT: 41503d0407baSopenharmony_ci ret = cgroup_bpf_link_attach(attr, prog); 41513d0407baSopenharmony_ci break; 41523d0407baSopenharmony_ci case BPF_PROG_TYPE_TRACING: 41533d0407baSopenharmony_ci ret = tracing_bpf_link_attach(attr, prog); 41543d0407baSopenharmony_ci break; 41553d0407baSopenharmony_ci case BPF_PROG_TYPE_FLOW_DISSECTOR: 41563d0407baSopenharmony_ci case BPF_PROG_TYPE_SK_LOOKUP: 41573d0407baSopenharmony_ci ret = netns_bpf_link_create(attr, prog); 41583d0407baSopenharmony_ci break; 41593d0407baSopenharmony_ci#ifdef CONFIG_NET 41603d0407baSopenharmony_ci case BPF_PROG_TYPE_XDP: 41613d0407baSopenharmony_ci ret = bpf_xdp_link_attach(attr, prog); 41623d0407baSopenharmony_ci break; 41633d0407baSopenharmony_ci#endif 41643d0407baSopenharmony_ci default: 41653d0407baSopenharmony_ci ret = -EINVAL; 41663d0407baSopenharmony_ci } 41673d0407baSopenharmony_ci 41683d0407baSopenharmony_ciout: 41693d0407baSopenharmony_ci if (ret < 0) { 41703d0407baSopenharmony_ci bpf_prog_put(prog); 41713d0407baSopenharmony_ci } 41723d0407baSopenharmony_ci return ret; 41733d0407baSopenharmony_ci} 41743d0407baSopenharmony_ci 41753d0407baSopenharmony_ci#define BPF_LINK_UPDATE_LAST_FIELD link_update.old_prog_fd 41763d0407baSopenharmony_ci 41773d0407baSopenharmony_cistatic int link_update(union bpf_attr *attr) 41783d0407baSopenharmony_ci{ 41793d0407baSopenharmony_ci struct bpf_prog *old_prog = NULL, *new_prog; 41803d0407baSopenharmony_ci struct bpf_link *link; 41813d0407baSopenharmony_ci u32 flags; 41823d0407baSopenharmony_ci int ret; 41833d0407baSopenharmony_ci 41843d0407baSopenharmony_ci if (CHECK_ATTR(BPF_LINK_UPDATE)) { 41853d0407baSopenharmony_ci return -EINVAL; 41863d0407baSopenharmony_ci } 41873d0407baSopenharmony_ci 41883d0407baSopenharmony_ci flags = attr->link_update.flags; 41893d0407baSopenharmony_ci if (flags & ~BPF_F_REPLACE) { 41903d0407baSopenharmony_ci return -EINVAL; 41913d0407baSopenharmony_ci } 41923d0407baSopenharmony_ci 41933d0407baSopenharmony_ci link = bpf_link_get_from_fd(attr->link_update.link_fd); 41943d0407baSopenharmony_ci if (IS_ERR(link)) { 41953d0407baSopenharmony_ci return PTR_ERR(link); 41963d0407baSopenharmony_ci } 41973d0407baSopenharmony_ci 41983d0407baSopenharmony_ci new_prog = bpf_prog_get(attr->link_update.new_prog_fd); 41993d0407baSopenharmony_ci if (IS_ERR(new_prog)) { 42003d0407baSopenharmony_ci ret = PTR_ERR(new_prog); 42013d0407baSopenharmony_ci goto out_put_link; 42023d0407baSopenharmony_ci } 42033d0407baSopenharmony_ci 42043d0407baSopenharmony_ci if (flags & BPF_F_REPLACE) { 42053d0407baSopenharmony_ci old_prog = bpf_prog_get(attr->link_update.old_prog_fd); 42063d0407baSopenharmony_ci if (IS_ERR(old_prog)) { 42073d0407baSopenharmony_ci ret = PTR_ERR(old_prog); 42083d0407baSopenharmony_ci old_prog = NULL; 42093d0407baSopenharmony_ci goto out_put_progs; 42103d0407baSopenharmony_ci } 42113d0407baSopenharmony_ci } else if (attr->link_update.old_prog_fd) { 42123d0407baSopenharmony_ci ret = -EINVAL; 42133d0407baSopenharmony_ci goto out_put_progs; 42143d0407baSopenharmony_ci } 42153d0407baSopenharmony_ci 42163d0407baSopenharmony_ci if (link->ops->update_prog) { 42173d0407baSopenharmony_ci ret = link->ops->update_prog(link, new_prog, old_prog); 42183d0407baSopenharmony_ci } else { 42193d0407baSopenharmony_ci ret = -EINVAL; 42203d0407baSopenharmony_ci } 42213d0407baSopenharmony_ci 42223d0407baSopenharmony_ciout_put_progs: 42233d0407baSopenharmony_ci if (old_prog) { 42243d0407baSopenharmony_ci bpf_prog_put(old_prog); 42253d0407baSopenharmony_ci } 42263d0407baSopenharmony_ci if (ret) { 42273d0407baSopenharmony_ci bpf_prog_put(new_prog); 42283d0407baSopenharmony_ci } 42293d0407baSopenharmony_ciout_put_link: 42303d0407baSopenharmony_ci bpf_link_put(link); 42313d0407baSopenharmony_ci return ret; 42323d0407baSopenharmony_ci} 42333d0407baSopenharmony_ci 42343d0407baSopenharmony_ci#define BPF_LINK_DETACH_LAST_FIELD link_detach.link_fd 42353d0407baSopenharmony_ci 42363d0407baSopenharmony_cistatic int link_detach(union bpf_attr *attr) 42373d0407baSopenharmony_ci{ 42383d0407baSopenharmony_ci struct bpf_link *link; 42393d0407baSopenharmony_ci int ret; 42403d0407baSopenharmony_ci 42413d0407baSopenharmony_ci if (CHECK_ATTR(BPF_LINK_DETACH)) { 42423d0407baSopenharmony_ci return -EINVAL; 42433d0407baSopenharmony_ci } 42443d0407baSopenharmony_ci 42453d0407baSopenharmony_ci link = bpf_link_get_from_fd(attr->link_detach.link_fd); 42463d0407baSopenharmony_ci if (IS_ERR(link)) { 42473d0407baSopenharmony_ci return PTR_ERR(link); 42483d0407baSopenharmony_ci } 42493d0407baSopenharmony_ci 42503d0407baSopenharmony_ci if (link->ops->detach) { 42513d0407baSopenharmony_ci ret = link->ops->detach(link); 42523d0407baSopenharmony_ci } else { 42533d0407baSopenharmony_ci ret = -EOPNOTSUPP; 42543d0407baSopenharmony_ci } 42553d0407baSopenharmony_ci 42563d0407baSopenharmony_ci bpf_link_put(link); 42573d0407baSopenharmony_ci return ret; 42583d0407baSopenharmony_ci} 42593d0407baSopenharmony_ci 42603d0407baSopenharmony_cistatic struct bpf_link *bpf_link_inc_not_zero(struct bpf_link *link) 42613d0407baSopenharmony_ci{ 42623d0407baSopenharmony_ci return atomic64_fetch_add_unless(&link->refcnt, 1, 0) ? link : ERR_PTR(-ENOENT); 42633d0407baSopenharmony_ci} 42643d0407baSopenharmony_ci 42653d0407baSopenharmony_cistruct bpf_link *bpf_link_by_id(u32 id) 42663d0407baSopenharmony_ci{ 42673d0407baSopenharmony_ci struct bpf_link *link; 42683d0407baSopenharmony_ci 42693d0407baSopenharmony_ci if (!id) { 42703d0407baSopenharmony_ci return ERR_PTR(-ENOENT); 42713d0407baSopenharmony_ci } 42723d0407baSopenharmony_ci 42733d0407baSopenharmony_ci spin_lock_bh(&link_idr_lock); 42743d0407baSopenharmony_ci /* before link is "settled", ID is 0, pretend it doesn't exist yet */ 42753d0407baSopenharmony_ci link = idr_find(&link_idr, id); 42763d0407baSopenharmony_ci if (link) { 42773d0407baSopenharmony_ci if (link->id) { 42783d0407baSopenharmony_ci link = bpf_link_inc_not_zero(link); 42793d0407baSopenharmony_ci } else { 42803d0407baSopenharmony_ci link = ERR_PTR(-EAGAIN); 42813d0407baSopenharmony_ci } 42823d0407baSopenharmony_ci } else { 42833d0407baSopenharmony_ci link = ERR_PTR(-ENOENT); 42843d0407baSopenharmony_ci } 42853d0407baSopenharmony_ci spin_unlock_bh(&link_idr_lock); 42863d0407baSopenharmony_ci return link; 42873d0407baSopenharmony_ci} 42883d0407baSopenharmony_ci 42893d0407baSopenharmony_ci#define BPF_LINK_GET_FD_BY_ID_LAST_FIELD link_id 42903d0407baSopenharmony_ci 42913d0407baSopenharmony_cistatic int bpf_link_get_fd_by_id(const union bpf_attr *attr) 42923d0407baSopenharmony_ci{ 42933d0407baSopenharmony_ci struct bpf_link *link; 42943d0407baSopenharmony_ci u32 id = attr->link_id; 42953d0407baSopenharmony_ci int fd; 42963d0407baSopenharmony_ci 42973d0407baSopenharmony_ci if (CHECK_ATTR(BPF_LINK_GET_FD_BY_ID)) { 42983d0407baSopenharmony_ci return -EINVAL; 42993d0407baSopenharmony_ci } 43003d0407baSopenharmony_ci 43013d0407baSopenharmony_ci if (!capable(CAP_SYS_ADMIN)) { 43023d0407baSopenharmony_ci return -EPERM; 43033d0407baSopenharmony_ci } 43043d0407baSopenharmony_ci 43053d0407baSopenharmony_ci link = bpf_link_by_id(id); 43063d0407baSopenharmony_ci if (IS_ERR(link)) { 43073d0407baSopenharmony_ci return PTR_ERR(link); 43083d0407baSopenharmony_ci } 43093d0407baSopenharmony_ci 43103d0407baSopenharmony_ci fd = bpf_link_new_fd(link); 43113d0407baSopenharmony_ci if (fd < 0) { 43123d0407baSopenharmony_ci bpf_link_put(link); 43133d0407baSopenharmony_ci } 43143d0407baSopenharmony_ci 43153d0407baSopenharmony_ci return fd; 43163d0407baSopenharmony_ci} 43173d0407baSopenharmony_ci 43183d0407baSopenharmony_ciDEFINE_MUTEX(bpf_stats_enabled_mutex); 43193d0407baSopenharmony_ci 43203d0407baSopenharmony_cistatic int bpf_stats_release(struct inode *inode, struct file *file) 43213d0407baSopenharmony_ci{ 43223d0407baSopenharmony_ci mutex_lock(&bpf_stats_enabled_mutex); 43233d0407baSopenharmony_ci static_key_slow_dec(&bpf_stats_enabled_key.key); 43243d0407baSopenharmony_ci mutex_unlock(&bpf_stats_enabled_mutex); 43253d0407baSopenharmony_ci return 0; 43263d0407baSopenharmony_ci} 43273d0407baSopenharmony_ci 43283d0407baSopenharmony_cistatic const struct file_operations bpf_stats_fops = { 43293d0407baSopenharmony_ci .release = bpf_stats_release, 43303d0407baSopenharmony_ci}; 43313d0407baSopenharmony_ci 43323d0407baSopenharmony_cistatic int bpf_enable_runtime_stats(void) 43333d0407baSopenharmony_ci{ 43343d0407baSopenharmony_ci int fd; 43353d0407baSopenharmony_ci 43363d0407baSopenharmony_ci mutex_lock(&bpf_stats_enabled_mutex); 43373d0407baSopenharmony_ci 43383d0407baSopenharmony_ci /* Set a very high limit to avoid overflow */ 43393d0407baSopenharmony_ci if (static_key_count(&bpf_stats_enabled_key.key) > INT_MAX / 0x2) { 43403d0407baSopenharmony_ci mutex_unlock(&bpf_stats_enabled_mutex); 43413d0407baSopenharmony_ci return -EBUSY; 43423d0407baSopenharmony_ci } 43433d0407baSopenharmony_ci 43443d0407baSopenharmony_ci fd = anon_inode_getfd("bpf-stats", &bpf_stats_fops, NULL, O_CLOEXEC); 43453d0407baSopenharmony_ci if (fd >= 0) { 43463d0407baSopenharmony_ci static_key_slow_inc(&bpf_stats_enabled_key.key); 43473d0407baSopenharmony_ci } 43483d0407baSopenharmony_ci 43493d0407baSopenharmony_ci mutex_unlock(&bpf_stats_enabled_mutex); 43503d0407baSopenharmony_ci return fd; 43513d0407baSopenharmony_ci} 43523d0407baSopenharmony_ci 43533d0407baSopenharmony_ci#define BPF_ENABLE_STATS_LAST_FIELD enable_stats.type 43543d0407baSopenharmony_ci 43553d0407baSopenharmony_cistatic int bpf_enable_stats(union bpf_attr *attr) 43563d0407baSopenharmony_ci{ 43573d0407baSopenharmony_ci if (CHECK_ATTR(BPF_ENABLE_STATS)) { 43583d0407baSopenharmony_ci return -EINVAL; 43593d0407baSopenharmony_ci } 43603d0407baSopenharmony_ci 43613d0407baSopenharmony_ci if (!capable(CAP_SYS_ADMIN)) { 43623d0407baSopenharmony_ci return -EPERM; 43633d0407baSopenharmony_ci } 43643d0407baSopenharmony_ci 43653d0407baSopenharmony_ci switch (attr->enable_stats.type) { 43663d0407baSopenharmony_ci case BPF_STATS_RUN_TIME: 43673d0407baSopenharmony_ci return bpf_enable_runtime_stats(); 43683d0407baSopenharmony_ci default: 43693d0407baSopenharmony_ci break; 43703d0407baSopenharmony_ci } 43713d0407baSopenharmony_ci return -EINVAL; 43723d0407baSopenharmony_ci} 43733d0407baSopenharmony_ci 43743d0407baSopenharmony_ci#define BPF_ITER_CREATE_LAST_FIELD iter_create.flags 43753d0407baSopenharmony_ci 43763d0407baSopenharmony_cistatic int bpf_iter_create(union bpf_attr *attr) 43773d0407baSopenharmony_ci{ 43783d0407baSopenharmony_ci struct bpf_link *link; 43793d0407baSopenharmony_ci int err; 43803d0407baSopenharmony_ci 43813d0407baSopenharmony_ci if (CHECK_ATTR(BPF_ITER_CREATE)) { 43823d0407baSopenharmony_ci return -EINVAL; 43833d0407baSopenharmony_ci } 43843d0407baSopenharmony_ci 43853d0407baSopenharmony_ci if (attr->iter_create.flags) { 43863d0407baSopenharmony_ci return -EINVAL; 43873d0407baSopenharmony_ci } 43883d0407baSopenharmony_ci 43893d0407baSopenharmony_ci link = bpf_link_get_from_fd(attr->iter_create.link_fd); 43903d0407baSopenharmony_ci if (IS_ERR(link)) { 43913d0407baSopenharmony_ci return PTR_ERR(link); 43923d0407baSopenharmony_ci } 43933d0407baSopenharmony_ci 43943d0407baSopenharmony_ci err = bpf_iter_new_fd(link); 43953d0407baSopenharmony_ci bpf_link_put(link); 43963d0407baSopenharmony_ci 43973d0407baSopenharmony_ci return err; 43983d0407baSopenharmony_ci} 43993d0407baSopenharmony_ci 44003d0407baSopenharmony_ci#define BPF_PROG_BIND_MAP_LAST_FIELD prog_bind_map.flags 44013d0407baSopenharmony_ci 44023d0407baSopenharmony_cistatic int bpf_prog_bind_map(union bpf_attr *attr) 44033d0407baSopenharmony_ci{ 44043d0407baSopenharmony_ci struct bpf_prog *prog; 44053d0407baSopenharmony_ci struct bpf_map *map; 44063d0407baSopenharmony_ci struct bpf_map **used_maps_old, **used_maps_new; 44073d0407baSopenharmony_ci int i, ret = 0; 44083d0407baSopenharmony_ci 44093d0407baSopenharmony_ci if (CHECK_ATTR(BPF_PROG_BIND_MAP)) { 44103d0407baSopenharmony_ci return -EINVAL; 44113d0407baSopenharmony_ci } 44123d0407baSopenharmony_ci 44133d0407baSopenharmony_ci if (attr->prog_bind_map.flags) { 44143d0407baSopenharmony_ci return -EINVAL; 44153d0407baSopenharmony_ci } 44163d0407baSopenharmony_ci 44173d0407baSopenharmony_ci prog = bpf_prog_get(attr->prog_bind_map.prog_fd); 44183d0407baSopenharmony_ci if (IS_ERR(prog)) { 44193d0407baSopenharmony_ci return PTR_ERR(prog); 44203d0407baSopenharmony_ci } 44213d0407baSopenharmony_ci 44223d0407baSopenharmony_ci map = bpf_map_get(attr->prog_bind_map.map_fd); 44233d0407baSopenharmony_ci if (IS_ERR(map)) { 44243d0407baSopenharmony_ci ret = PTR_ERR(map); 44253d0407baSopenharmony_ci goto out_prog_put; 44263d0407baSopenharmony_ci } 44273d0407baSopenharmony_ci 44283d0407baSopenharmony_ci mutex_lock(&prog->aux->used_maps_mutex); 44293d0407baSopenharmony_ci 44303d0407baSopenharmony_ci used_maps_old = prog->aux->used_maps; 44313d0407baSopenharmony_ci 44323d0407baSopenharmony_ci for (i = 0; i < prog->aux->used_map_cnt; i++) { 44333d0407baSopenharmony_ci if (used_maps_old[i] == map) { 44343d0407baSopenharmony_ci bpf_map_put(map); 44353d0407baSopenharmony_ci goto out_unlock; 44363d0407baSopenharmony_ci } 44373d0407baSopenharmony_ci } 44383d0407baSopenharmony_ci 44393d0407baSopenharmony_ci used_maps_new = kmalloc_array(prog->aux->used_map_cnt + 1, sizeof(used_maps_new[0]), GFP_KERNEL); 44403d0407baSopenharmony_ci if (!used_maps_new) { 44413d0407baSopenharmony_ci ret = -ENOMEM; 44423d0407baSopenharmony_ci goto out_unlock; 44433d0407baSopenharmony_ci } 44443d0407baSopenharmony_ci 44453d0407baSopenharmony_ci memcpy(used_maps_new, used_maps_old, sizeof(used_maps_old[0]) * prog->aux->used_map_cnt); 44463d0407baSopenharmony_ci used_maps_new[prog->aux->used_map_cnt] = map; 44473d0407baSopenharmony_ci 44483d0407baSopenharmony_ci prog->aux->used_map_cnt++; 44493d0407baSopenharmony_ci prog->aux->used_maps = used_maps_new; 44503d0407baSopenharmony_ci 44513d0407baSopenharmony_ci kfree(used_maps_old); 44523d0407baSopenharmony_ci 44533d0407baSopenharmony_ciout_unlock: 44543d0407baSopenharmony_ci mutex_unlock(&prog->aux->used_maps_mutex); 44553d0407baSopenharmony_ci 44563d0407baSopenharmony_ci if (ret) { 44573d0407baSopenharmony_ci bpf_map_put(map); 44583d0407baSopenharmony_ci } 44593d0407baSopenharmony_ciout_prog_put: 44603d0407baSopenharmony_ci bpf_prog_put(prog); 44613d0407baSopenharmony_ci return ret; 44623d0407baSopenharmony_ci} 44633d0407baSopenharmony_ci 44643d0407baSopenharmony_ciSYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size) 44653d0407baSopenharmony_ci{ 44663d0407baSopenharmony_ci union bpf_attr attr; 44673d0407baSopenharmony_ci int err; 44683d0407baSopenharmony_ci 44693d0407baSopenharmony_ci if (sysctl_unprivileged_bpf_disabled && !bpf_capable()) { 44703d0407baSopenharmony_ci return -EPERM; 44713d0407baSopenharmony_ci } 44723d0407baSopenharmony_ci 44733d0407baSopenharmony_ci err = bpf_check_uarg_tail_zero(uattr, sizeof(attr), size); 44743d0407baSopenharmony_ci if (err) { 44753d0407baSopenharmony_ci return err; 44763d0407baSopenharmony_ci } 44773d0407baSopenharmony_ci size = min_t(u32, size, sizeof(attr)); 44783d0407baSopenharmony_ci 44793d0407baSopenharmony_ci /* copy attributes from user space, may be less than sizeof(bpf_attr) */ 44803d0407baSopenharmony_ci memset(&attr, 0, sizeof(attr)); 44813d0407baSopenharmony_ci if (copy_from_user(&attr, uattr, size) != 0) { 44823d0407baSopenharmony_ci return -EFAULT; 44833d0407baSopenharmony_ci } 44843d0407baSopenharmony_ci 44853d0407baSopenharmony_ci err = security_bpf(cmd, &attr, size); 44863d0407baSopenharmony_ci if (err < 0) { 44873d0407baSopenharmony_ci return err; 44883d0407baSopenharmony_ci } 44893d0407baSopenharmony_ci 44903d0407baSopenharmony_ci switch (cmd) { 44913d0407baSopenharmony_ci case BPF_MAP_CREATE: 44923d0407baSopenharmony_ci err = map_create(&attr); 44933d0407baSopenharmony_ci break; 44943d0407baSopenharmony_ci case BPF_MAP_LOOKUP_ELEM: 44953d0407baSopenharmony_ci err = map_lookup_elem(&attr); 44963d0407baSopenharmony_ci break; 44973d0407baSopenharmony_ci case BPF_MAP_UPDATE_ELEM: 44983d0407baSopenharmony_ci err = map_update_elem(&attr); 44993d0407baSopenharmony_ci break; 45003d0407baSopenharmony_ci case BPF_MAP_DELETE_ELEM: 45013d0407baSopenharmony_ci err = map_delete_elem(&attr); 45023d0407baSopenharmony_ci break; 45033d0407baSopenharmony_ci case BPF_MAP_GET_NEXT_KEY: 45043d0407baSopenharmony_ci err = map_get_next_key(&attr); 45053d0407baSopenharmony_ci break; 45063d0407baSopenharmony_ci case BPF_MAP_FREEZE: 45073d0407baSopenharmony_ci err = map_freeze(&attr); 45083d0407baSopenharmony_ci break; 45093d0407baSopenharmony_ci case BPF_PROG_LOAD: 45103d0407baSopenharmony_ci err = bpf_prog_load(&attr, uattr); 45113d0407baSopenharmony_ci break; 45123d0407baSopenharmony_ci case BPF_OBJ_PIN: 45133d0407baSopenharmony_ci err = bpf_obj_pin(&attr); 45143d0407baSopenharmony_ci break; 45153d0407baSopenharmony_ci case BPF_OBJ_GET: 45163d0407baSopenharmony_ci err = bpf_obj_get(&attr); 45173d0407baSopenharmony_ci break; 45183d0407baSopenharmony_ci case BPF_PROG_ATTACH: 45193d0407baSopenharmony_ci err = bpf_prog_attach(&attr); 45203d0407baSopenharmony_ci break; 45213d0407baSopenharmony_ci case BPF_PROG_DETACH: 45223d0407baSopenharmony_ci err = bpf_prog_detach(&attr); 45233d0407baSopenharmony_ci break; 45243d0407baSopenharmony_ci case BPF_PROG_QUERY: 45253d0407baSopenharmony_ci err = bpf_prog_query(&attr, uattr); 45263d0407baSopenharmony_ci break; 45273d0407baSopenharmony_ci case BPF_PROG_TEST_RUN: 45283d0407baSopenharmony_ci err = bpf_prog_test_run(&attr, uattr); 45293d0407baSopenharmony_ci break; 45303d0407baSopenharmony_ci case BPF_PROG_GET_NEXT_ID: 45313d0407baSopenharmony_ci err = bpf_obj_get_next_id(&attr, uattr, &prog_idr, &prog_idr_lock); 45323d0407baSopenharmony_ci break; 45333d0407baSopenharmony_ci case BPF_MAP_GET_NEXT_ID: 45343d0407baSopenharmony_ci err = bpf_obj_get_next_id(&attr, uattr, &map_idr, &map_idr_lock); 45353d0407baSopenharmony_ci break; 45363d0407baSopenharmony_ci case BPF_BTF_GET_NEXT_ID: 45373d0407baSopenharmony_ci err = bpf_obj_get_next_id(&attr, uattr, &btf_idr, &btf_idr_lock); 45383d0407baSopenharmony_ci break; 45393d0407baSopenharmony_ci case BPF_PROG_GET_FD_BY_ID: 45403d0407baSopenharmony_ci err = bpf_prog_get_fd_by_id(&attr); 45413d0407baSopenharmony_ci break; 45423d0407baSopenharmony_ci case BPF_MAP_GET_FD_BY_ID: 45433d0407baSopenharmony_ci err = bpf_map_get_fd_by_id(&attr); 45443d0407baSopenharmony_ci break; 45453d0407baSopenharmony_ci case BPF_OBJ_GET_INFO_BY_FD: 45463d0407baSopenharmony_ci err = bpf_obj_get_info_by_fd(&attr, uattr); 45473d0407baSopenharmony_ci break; 45483d0407baSopenharmony_ci case BPF_RAW_TRACEPOINT_OPEN: 45493d0407baSopenharmony_ci err = bpf_raw_tracepoint_open(&attr); 45503d0407baSopenharmony_ci break; 45513d0407baSopenharmony_ci case BPF_BTF_LOAD: 45523d0407baSopenharmony_ci err = bpf_btf_load(&attr); 45533d0407baSopenharmony_ci break; 45543d0407baSopenharmony_ci case BPF_BTF_GET_FD_BY_ID: 45553d0407baSopenharmony_ci err = bpf_btf_get_fd_by_id(&attr); 45563d0407baSopenharmony_ci break; 45573d0407baSopenharmony_ci case BPF_TASK_FD_QUERY: 45583d0407baSopenharmony_ci err = bpf_task_fd_query(&attr, uattr); 45593d0407baSopenharmony_ci break; 45603d0407baSopenharmony_ci case BPF_MAP_LOOKUP_AND_DELETE_ELEM: 45613d0407baSopenharmony_ci err = map_lookup_and_delete_elem(&attr); 45623d0407baSopenharmony_ci break; 45633d0407baSopenharmony_ci case BPF_MAP_LOOKUP_BATCH: 45643d0407baSopenharmony_ci err = bpf_map_do_batch(&attr, uattr, BPF_MAP_LOOKUP_BATCH); 45653d0407baSopenharmony_ci break; 45663d0407baSopenharmony_ci case BPF_MAP_LOOKUP_AND_DELETE_BATCH: 45673d0407baSopenharmony_ci err = bpf_map_do_batch(&attr, uattr, BPF_MAP_LOOKUP_AND_DELETE_BATCH); 45683d0407baSopenharmony_ci break; 45693d0407baSopenharmony_ci case BPF_MAP_UPDATE_BATCH: 45703d0407baSopenharmony_ci err = bpf_map_do_batch(&attr, uattr, BPF_MAP_UPDATE_BATCH); 45713d0407baSopenharmony_ci break; 45723d0407baSopenharmony_ci case BPF_MAP_DELETE_BATCH: 45733d0407baSopenharmony_ci err = bpf_map_do_batch(&attr, uattr, BPF_MAP_DELETE_BATCH); 45743d0407baSopenharmony_ci break; 45753d0407baSopenharmony_ci case BPF_LINK_CREATE: 45763d0407baSopenharmony_ci err = link_create(&attr); 45773d0407baSopenharmony_ci break; 45783d0407baSopenharmony_ci case BPF_LINK_UPDATE: 45793d0407baSopenharmony_ci err = link_update(&attr); 45803d0407baSopenharmony_ci break; 45813d0407baSopenharmony_ci case BPF_LINK_GET_FD_BY_ID: 45823d0407baSopenharmony_ci err = bpf_link_get_fd_by_id(&attr); 45833d0407baSopenharmony_ci break; 45843d0407baSopenharmony_ci case BPF_LINK_GET_NEXT_ID: 45853d0407baSopenharmony_ci err = bpf_obj_get_next_id(&attr, uattr, &link_idr, &link_idr_lock); 45863d0407baSopenharmony_ci break; 45873d0407baSopenharmony_ci case BPF_ENABLE_STATS: 45883d0407baSopenharmony_ci err = bpf_enable_stats(&attr); 45893d0407baSopenharmony_ci break; 45903d0407baSopenharmony_ci case BPF_ITER_CREATE: 45913d0407baSopenharmony_ci err = bpf_iter_create(&attr); 45923d0407baSopenharmony_ci break; 45933d0407baSopenharmony_ci case BPF_LINK_DETACH: 45943d0407baSopenharmony_ci err = link_detach(&attr); 45953d0407baSopenharmony_ci break; 45963d0407baSopenharmony_ci case BPF_PROG_BIND_MAP: 45973d0407baSopenharmony_ci err = bpf_prog_bind_map(&attr); 45983d0407baSopenharmony_ci break; 45993d0407baSopenharmony_ci default: 46003d0407baSopenharmony_ci err = -EINVAL; 46013d0407baSopenharmony_ci break; 46023d0407baSopenharmony_ci } 46033d0407baSopenharmony_ci 46043d0407baSopenharmony_ci return err; 46053d0407baSopenharmony_ci} 4606