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