18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (c) 2011-2015 PLUMgrid, http://plumgrid.com 38c2ecf20Sopenharmony_ci * Copyright (c) 2016 Facebook 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci#include <linux/kernel.h> 68c2ecf20Sopenharmony_ci#include <linux/types.h> 78c2ecf20Sopenharmony_ci#include <linux/slab.h> 88c2ecf20Sopenharmony_ci#include <linux/bpf.h> 98c2ecf20Sopenharmony_ci#include <linux/bpf_perf_event.h> 108c2ecf20Sopenharmony_ci#include <linux/btf.h> 118c2ecf20Sopenharmony_ci#include <linux/filter.h> 128c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 138c2ecf20Sopenharmony_ci#include <linux/ctype.h> 148c2ecf20Sopenharmony_ci#include <linux/kprobes.h> 158c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 168c2ecf20Sopenharmony_ci#include <linux/syscalls.h> 178c2ecf20Sopenharmony_ci#include <linux/error-injection.h> 188c2ecf20Sopenharmony_ci#include <linux/btf_ids.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <uapi/linux/bpf.h> 218c2ecf20Sopenharmony_ci#include <uapi/linux/btf.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <asm/tlb.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "trace_probe.h" 268c2ecf20Sopenharmony_ci#include "trace.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define CREATE_TRACE_POINTS 298c2ecf20Sopenharmony_ci#include "bpf_trace.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define bpf_event_rcu_dereference(p) \ 328c2ecf20Sopenharmony_ci rcu_dereference_protected(p, lockdep_is_held(&bpf_event_mutex)) 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#ifdef CONFIG_MODULES 358c2ecf20Sopenharmony_cistruct bpf_trace_module { 368c2ecf20Sopenharmony_ci struct module *module; 378c2ecf20Sopenharmony_ci struct list_head list; 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic LIST_HEAD(bpf_trace_modules); 418c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(bpf_module_mutex); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic struct bpf_raw_event_map *bpf_get_raw_tracepoint_module(const char *name) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct bpf_raw_event_map *btp, *ret = NULL; 468c2ecf20Sopenharmony_ci struct bpf_trace_module *btm; 478c2ecf20Sopenharmony_ci unsigned int i; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci mutex_lock(&bpf_module_mutex); 508c2ecf20Sopenharmony_ci list_for_each_entry(btm, &bpf_trace_modules, list) { 518c2ecf20Sopenharmony_ci for (i = 0; i < btm->module->num_bpf_raw_events; ++i) { 528c2ecf20Sopenharmony_ci btp = &btm->module->bpf_raw_events[i]; 538c2ecf20Sopenharmony_ci if (!strcmp(btp->tp->name, name)) { 548c2ecf20Sopenharmony_ci if (try_module_get(btm->module)) 558c2ecf20Sopenharmony_ci ret = btp; 568c2ecf20Sopenharmony_ci goto out; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ciout: 618c2ecf20Sopenharmony_ci mutex_unlock(&bpf_module_mutex); 628c2ecf20Sopenharmony_ci return ret; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci#else 658c2ecf20Sopenharmony_cistatic struct bpf_raw_event_map *bpf_get_raw_tracepoint_module(const char *name) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci return NULL; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci#endif /* CONFIG_MODULES */ 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ciu64 bpf_get_stackid(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); 728c2ecf20Sopenharmony_ciu64 bpf_get_stack(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic int bpf_btf_printf_prepare(struct btf_ptr *ptr, u32 btf_ptr_size, 758c2ecf20Sopenharmony_ci u64 flags, const struct btf **btf, 768c2ecf20Sopenharmony_ci s32 *btf_id); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/** 798c2ecf20Sopenharmony_ci * trace_call_bpf - invoke BPF program 808c2ecf20Sopenharmony_ci * @call: tracepoint event 818c2ecf20Sopenharmony_ci * @ctx: opaque context pointer 828c2ecf20Sopenharmony_ci * 838c2ecf20Sopenharmony_ci * kprobe handlers execute BPF programs via this helper. 848c2ecf20Sopenharmony_ci * Can be used from static tracepoints in the future. 858c2ecf20Sopenharmony_ci * 868c2ecf20Sopenharmony_ci * Return: BPF programs always return an integer which is interpreted by 878c2ecf20Sopenharmony_ci * kprobe handler as: 888c2ecf20Sopenharmony_ci * 0 - return from kprobe (event is filtered out) 898c2ecf20Sopenharmony_ci * 1 - store kprobe event into ring buffer 908c2ecf20Sopenharmony_ci * Other values are reserved and currently alias to 1 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_ciunsigned int trace_call_bpf(struct trace_event_call *call, void *ctx) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci unsigned int ret; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci cant_sleep(); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (unlikely(__this_cpu_inc_return(bpf_prog_active) != 1)) { 998c2ecf20Sopenharmony_ci /* 1008c2ecf20Sopenharmony_ci * since some bpf program is already running on this cpu, 1018c2ecf20Sopenharmony_ci * don't call into another bpf program (same or different) 1028c2ecf20Sopenharmony_ci * and don't send kprobe event into ring-buffer, 1038c2ecf20Sopenharmony_ci * so return zero here 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_ci ret = 0; 1068c2ecf20Sopenharmony_ci goto out; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* 1108c2ecf20Sopenharmony_ci * Instead of moving rcu_read_lock/rcu_dereference/rcu_read_unlock 1118c2ecf20Sopenharmony_ci * to all call sites, we did a bpf_prog_array_valid() there to check 1128c2ecf20Sopenharmony_ci * whether call->prog_array is empty or not, which is 1138c2ecf20Sopenharmony_ci * a heurisitc to speed up execution. 1148c2ecf20Sopenharmony_ci * 1158c2ecf20Sopenharmony_ci * If bpf_prog_array_valid() fetched prog_array was 1168c2ecf20Sopenharmony_ci * non-NULL, we go into trace_call_bpf() and do the actual 1178c2ecf20Sopenharmony_ci * proper rcu_dereference() under RCU lock. 1188c2ecf20Sopenharmony_ci * If it turns out that prog_array is NULL then, we bail out. 1198c2ecf20Sopenharmony_ci * For the opposite, if the bpf_prog_array_valid() fetched pointer 1208c2ecf20Sopenharmony_ci * was NULL, you'll skip the prog_array with the risk of missing 1218c2ecf20Sopenharmony_ci * out of events when it was updated in between this and the 1228c2ecf20Sopenharmony_ci * rcu_dereference() which is accepted risk. 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_ci ret = BPF_PROG_RUN_ARRAY_CHECK(call->prog_array, ctx, BPF_PROG_RUN); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci out: 1278c2ecf20Sopenharmony_ci __this_cpu_dec(bpf_prog_active); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci return ret; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci#ifdef CONFIG_BPF_KPROBE_OVERRIDE 1338c2ecf20Sopenharmony_ciBPF_CALL_2(bpf_override_return, struct pt_regs *, regs, unsigned long, rc) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci regs_set_return_value(regs, rc); 1368c2ecf20Sopenharmony_ci override_function_with_return(regs); 1378c2ecf20Sopenharmony_ci return 0; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic const struct bpf_func_proto bpf_override_return_proto = { 1418c2ecf20Sopenharmony_ci .func = bpf_override_return, 1428c2ecf20Sopenharmony_ci .gpl_only = true, 1438c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 1448c2ecf20Sopenharmony_ci .arg1_type = ARG_PTR_TO_CTX, 1458c2ecf20Sopenharmony_ci .arg2_type = ARG_ANYTHING, 1468c2ecf20Sopenharmony_ci}; 1478c2ecf20Sopenharmony_ci#endif 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic __always_inline int 1508c2ecf20Sopenharmony_cibpf_probe_read_user_common(void *dst, u32 size, const void __user *unsafe_ptr) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci int ret; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci ret = copy_from_user_nofault(dst, unsafe_ptr, size); 1558c2ecf20Sopenharmony_ci if (unlikely(ret < 0)) 1568c2ecf20Sopenharmony_ci memset(dst, 0, size); 1578c2ecf20Sopenharmony_ci return ret; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ciBPF_CALL_3(bpf_probe_read_user, void *, dst, u32, size, 1618c2ecf20Sopenharmony_ci const void __user *, unsafe_ptr) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci return bpf_probe_read_user_common(dst, size, unsafe_ptr); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ciconst struct bpf_func_proto bpf_probe_read_user_proto = { 1678c2ecf20Sopenharmony_ci .func = bpf_probe_read_user, 1688c2ecf20Sopenharmony_ci .gpl_only = true, 1698c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 1708c2ecf20Sopenharmony_ci .arg1_type = ARG_PTR_TO_UNINIT_MEM, 1718c2ecf20Sopenharmony_ci .arg2_type = ARG_CONST_SIZE_OR_ZERO, 1728c2ecf20Sopenharmony_ci .arg3_type = ARG_ANYTHING, 1738c2ecf20Sopenharmony_ci}; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic __always_inline int 1768c2ecf20Sopenharmony_cibpf_probe_read_user_str_common(void *dst, u32 size, 1778c2ecf20Sopenharmony_ci const void __user *unsafe_ptr) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci int ret; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci /* 1828c2ecf20Sopenharmony_ci * NB: We rely on strncpy_from_user() not copying junk past the NUL 1838c2ecf20Sopenharmony_ci * terminator into `dst`. 1848c2ecf20Sopenharmony_ci * 1858c2ecf20Sopenharmony_ci * strncpy_from_user() does long-sized strides in the fast path. If the 1868c2ecf20Sopenharmony_ci * strncpy does not mask out the bytes after the NUL in `unsafe_ptr`, 1878c2ecf20Sopenharmony_ci * then there could be junk after the NUL in `dst`. If user takes `dst` 1888c2ecf20Sopenharmony_ci * and keys a hash map with it, then semantically identical strings can 1898c2ecf20Sopenharmony_ci * occupy multiple entries in the map. 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_ci ret = strncpy_from_user_nofault(dst, unsafe_ptr, size); 1928c2ecf20Sopenharmony_ci if (unlikely(ret < 0)) 1938c2ecf20Sopenharmony_ci memset(dst, 0, size); 1948c2ecf20Sopenharmony_ci return ret; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ciBPF_CALL_3(bpf_probe_read_user_str, void *, dst, u32, size, 1988c2ecf20Sopenharmony_ci const void __user *, unsafe_ptr) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci return bpf_probe_read_user_str_common(dst, size, unsafe_ptr); 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ciconst struct bpf_func_proto bpf_probe_read_user_str_proto = { 2048c2ecf20Sopenharmony_ci .func = bpf_probe_read_user_str, 2058c2ecf20Sopenharmony_ci .gpl_only = true, 2068c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 2078c2ecf20Sopenharmony_ci .arg1_type = ARG_PTR_TO_UNINIT_MEM, 2088c2ecf20Sopenharmony_ci .arg2_type = ARG_CONST_SIZE_OR_ZERO, 2098c2ecf20Sopenharmony_ci .arg3_type = ARG_ANYTHING, 2108c2ecf20Sopenharmony_ci}; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic __always_inline int 2138c2ecf20Sopenharmony_cibpf_probe_read_kernel_common(void *dst, u32 size, const void *unsafe_ptr) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci int ret; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci ret = copy_from_kernel_nofault(dst, unsafe_ptr, size); 2188c2ecf20Sopenharmony_ci if (unlikely(ret < 0)) 2198c2ecf20Sopenharmony_ci memset(dst, 0, size); 2208c2ecf20Sopenharmony_ci return ret; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ciBPF_CALL_3(bpf_probe_read_kernel, void *, dst, u32, size, 2248c2ecf20Sopenharmony_ci const void *, unsafe_ptr) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci return bpf_probe_read_kernel_common(dst, size, unsafe_ptr); 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ciconst struct bpf_func_proto bpf_probe_read_kernel_proto = { 2308c2ecf20Sopenharmony_ci .func = bpf_probe_read_kernel, 2318c2ecf20Sopenharmony_ci .gpl_only = true, 2328c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 2338c2ecf20Sopenharmony_ci .arg1_type = ARG_PTR_TO_UNINIT_MEM, 2348c2ecf20Sopenharmony_ci .arg2_type = ARG_CONST_SIZE_OR_ZERO, 2358c2ecf20Sopenharmony_ci .arg3_type = ARG_ANYTHING, 2368c2ecf20Sopenharmony_ci}; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic __always_inline int 2398c2ecf20Sopenharmony_cibpf_probe_read_kernel_str_common(void *dst, u32 size, const void *unsafe_ptr) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci int ret; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* 2448c2ecf20Sopenharmony_ci * The strncpy_from_kernel_nofault() call will likely not fill the 2458c2ecf20Sopenharmony_ci * entire buffer, but that's okay in this circumstance as we're probing 2468c2ecf20Sopenharmony_ci * arbitrary memory anyway similar to bpf_probe_read_*() and might 2478c2ecf20Sopenharmony_ci * as well probe the stack. Thus, memory is explicitly cleared 2488c2ecf20Sopenharmony_ci * only in error case, so that improper users ignoring return 2498c2ecf20Sopenharmony_ci * code altogether don't copy garbage; otherwise length of string 2508c2ecf20Sopenharmony_ci * is returned that can be used for bpf_perf_event_output() et al. 2518c2ecf20Sopenharmony_ci */ 2528c2ecf20Sopenharmony_ci ret = strncpy_from_kernel_nofault(dst, unsafe_ptr, size); 2538c2ecf20Sopenharmony_ci if (unlikely(ret < 0)) 2548c2ecf20Sopenharmony_ci memset(dst, 0, size); 2558c2ecf20Sopenharmony_ci return ret; 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ciBPF_CALL_3(bpf_probe_read_kernel_str, void *, dst, u32, size, 2598c2ecf20Sopenharmony_ci const void *, unsafe_ptr) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci return bpf_probe_read_kernel_str_common(dst, size, unsafe_ptr); 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ciconst struct bpf_func_proto bpf_probe_read_kernel_str_proto = { 2658c2ecf20Sopenharmony_ci .func = bpf_probe_read_kernel_str, 2668c2ecf20Sopenharmony_ci .gpl_only = true, 2678c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 2688c2ecf20Sopenharmony_ci .arg1_type = ARG_PTR_TO_UNINIT_MEM, 2698c2ecf20Sopenharmony_ci .arg2_type = ARG_CONST_SIZE_OR_ZERO, 2708c2ecf20Sopenharmony_ci .arg3_type = ARG_ANYTHING, 2718c2ecf20Sopenharmony_ci}; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE 2748c2ecf20Sopenharmony_ciBPF_CALL_3(bpf_probe_read_compat, void *, dst, u32, size, 2758c2ecf20Sopenharmony_ci const void *, unsafe_ptr) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci if ((unsigned long)unsafe_ptr < TASK_SIZE) { 2788c2ecf20Sopenharmony_ci return bpf_probe_read_user_common(dst, size, 2798c2ecf20Sopenharmony_ci (__force void __user *)unsafe_ptr); 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci return bpf_probe_read_kernel_common(dst, size, unsafe_ptr); 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic const struct bpf_func_proto bpf_probe_read_compat_proto = { 2858c2ecf20Sopenharmony_ci .func = bpf_probe_read_compat, 2868c2ecf20Sopenharmony_ci .gpl_only = true, 2878c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 2888c2ecf20Sopenharmony_ci .arg1_type = ARG_PTR_TO_UNINIT_MEM, 2898c2ecf20Sopenharmony_ci .arg2_type = ARG_CONST_SIZE_OR_ZERO, 2908c2ecf20Sopenharmony_ci .arg3_type = ARG_ANYTHING, 2918c2ecf20Sopenharmony_ci}; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ciBPF_CALL_3(bpf_probe_read_compat_str, void *, dst, u32, size, 2948c2ecf20Sopenharmony_ci const void *, unsafe_ptr) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci if ((unsigned long)unsafe_ptr < TASK_SIZE) { 2978c2ecf20Sopenharmony_ci return bpf_probe_read_user_str_common(dst, size, 2988c2ecf20Sopenharmony_ci (__force void __user *)unsafe_ptr); 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci return bpf_probe_read_kernel_str_common(dst, size, unsafe_ptr); 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic const struct bpf_func_proto bpf_probe_read_compat_str_proto = { 3048c2ecf20Sopenharmony_ci .func = bpf_probe_read_compat_str, 3058c2ecf20Sopenharmony_ci .gpl_only = true, 3068c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 3078c2ecf20Sopenharmony_ci .arg1_type = ARG_PTR_TO_UNINIT_MEM, 3088c2ecf20Sopenharmony_ci .arg2_type = ARG_CONST_SIZE_OR_ZERO, 3098c2ecf20Sopenharmony_ci .arg3_type = ARG_ANYTHING, 3108c2ecf20Sopenharmony_ci}; 3118c2ecf20Sopenharmony_ci#endif /* CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE */ 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ciBPF_CALL_3(bpf_probe_write_user, void __user *, unsafe_ptr, const void *, src, 3148c2ecf20Sopenharmony_ci u32, size) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci /* 3178c2ecf20Sopenharmony_ci * Ensure we're in user context which is safe for the helper to 3188c2ecf20Sopenharmony_ci * run. This helper has no business in a kthread. 3198c2ecf20Sopenharmony_ci * 3208c2ecf20Sopenharmony_ci * access_ok() should prevent writing to non-user memory, but in 3218c2ecf20Sopenharmony_ci * some situations (nommu, temporary switch, etc) access_ok() does 3228c2ecf20Sopenharmony_ci * not provide enough validation, hence the check on KERNEL_DS. 3238c2ecf20Sopenharmony_ci * 3248c2ecf20Sopenharmony_ci * nmi_uaccess_okay() ensures the probe is not run in an interim 3258c2ecf20Sopenharmony_ci * state, when the task or mm are switched. This is specifically 3268c2ecf20Sopenharmony_ci * required to prevent the use of temporary mm. 3278c2ecf20Sopenharmony_ci */ 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (unlikely(in_interrupt() || 3308c2ecf20Sopenharmony_ci current->flags & (PF_KTHREAD | PF_EXITING))) 3318c2ecf20Sopenharmony_ci return -EPERM; 3328c2ecf20Sopenharmony_ci if (unlikely(uaccess_kernel())) 3338c2ecf20Sopenharmony_ci return -EPERM; 3348c2ecf20Sopenharmony_ci if (unlikely(!nmi_uaccess_okay())) 3358c2ecf20Sopenharmony_ci return -EPERM; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci return copy_to_user_nofault(unsafe_ptr, src, size); 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic const struct bpf_func_proto bpf_probe_write_user_proto = { 3418c2ecf20Sopenharmony_ci .func = bpf_probe_write_user, 3428c2ecf20Sopenharmony_ci .gpl_only = true, 3438c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 3448c2ecf20Sopenharmony_ci .arg1_type = ARG_ANYTHING, 3458c2ecf20Sopenharmony_ci .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 3468c2ecf20Sopenharmony_ci .arg3_type = ARG_CONST_SIZE, 3478c2ecf20Sopenharmony_ci}; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic const struct bpf_func_proto *bpf_get_probe_write_proto(void) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 3528c2ecf20Sopenharmony_ci return NULL; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci pr_warn_ratelimited("%s[%d] is installing a program with bpf_probe_write_user helper that may corrupt user memory!", 3558c2ecf20Sopenharmony_ci current->comm, task_pid_nr(current)); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci return &bpf_probe_write_user_proto; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic void bpf_trace_copy_string(char *buf, void *unsafe_ptr, char fmt_ptype, 3618c2ecf20Sopenharmony_ci size_t bufsz) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci void __user *user_ptr = (__force void __user *)unsafe_ptr; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci buf[0] = 0; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci switch (fmt_ptype) { 3688c2ecf20Sopenharmony_ci case 's': 3698c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE 3708c2ecf20Sopenharmony_ci if ((unsigned long)unsafe_ptr < TASK_SIZE) { 3718c2ecf20Sopenharmony_ci strncpy_from_user_nofault(buf, user_ptr, bufsz); 3728c2ecf20Sopenharmony_ci break; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci fallthrough; 3758c2ecf20Sopenharmony_ci#endif 3768c2ecf20Sopenharmony_ci case 'k': 3778c2ecf20Sopenharmony_ci strncpy_from_kernel_nofault(buf, unsafe_ptr, bufsz); 3788c2ecf20Sopenharmony_ci break; 3798c2ecf20Sopenharmony_ci case 'u': 3808c2ecf20Sopenharmony_ci strncpy_from_user_nofault(buf, user_ptr, bufsz); 3818c2ecf20Sopenharmony_ci break; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic DEFINE_RAW_SPINLOCK(trace_printk_lock); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci#define BPF_TRACE_PRINTK_SIZE 1024 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic __printf(1, 0) int bpf_do_trace_printk(const char *fmt, ...) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci static char buf[BPF_TRACE_PRINTK_SIZE]; 3928c2ecf20Sopenharmony_ci unsigned long flags; 3938c2ecf20Sopenharmony_ci va_list ap; 3948c2ecf20Sopenharmony_ci int ret; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&trace_printk_lock, flags); 3978c2ecf20Sopenharmony_ci va_start(ap, fmt); 3988c2ecf20Sopenharmony_ci ret = vsnprintf(buf, sizeof(buf), fmt, ap); 3998c2ecf20Sopenharmony_ci va_end(ap); 4008c2ecf20Sopenharmony_ci /* vsnprintf() will not append null for zero-length strings */ 4018c2ecf20Sopenharmony_ci if (ret == 0) 4028c2ecf20Sopenharmony_ci buf[0] = '\0'; 4038c2ecf20Sopenharmony_ci trace_bpf_trace_printk(buf); 4048c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&trace_printk_lock, flags); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci return ret; 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci/* 4108c2ecf20Sopenharmony_ci * Only limited trace_printk() conversion specifiers allowed: 4118c2ecf20Sopenharmony_ci * %d %i %u %x %ld %li %lu %lx %lld %lli %llu %llx %p %pB %pks %pus %s 4128c2ecf20Sopenharmony_ci */ 4138c2ecf20Sopenharmony_ciBPF_CALL_5(bpf_trace_printk, char *, fmt, u32, fmt_size, u64, arg1, 4148c2ecf20Sopenharmony_ci u64, arg2, u64, arg3) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci int i, mod[3] = {}, fmt_cnt = 0; 4178c2ecf20Sopenharmony_ci char buf[64], fmt_ptype; 4188c2ecf20Sopenharmony_ci void *unsafe_ptr = NULL; 4198c2ecf20Sopenharmony_ci bool str_seen = false; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci /* 4228c2ecf20Sopenharmony_ci * bpf_check()->check_func_arg()->check_stack_boundary() 4238c2ecf20Sopenharmony_ci * guarantees that fmt points to bpf program stack, 4248c2ecf20Sopenharmony_ci * fmt_size bytes of it were initialized and fmt_size > 0 4258c2ecf20Sopenharmony_ci */ 4268c2ecf20Sopenharmony_ci if (fmt[--fmt_size] != 0) 4278c2ecf20Sopenharmony_ci return -EINVAL; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci /* check format string for allowed specifiers */ 4308c2ecf20Sopenharmony_ci for (i = 0; i < fmt_size; i++) { 4318c2ecf20Sopenharmony_ci if ((!isprint(fmt[i]) && !isspace(fmt[i])) || !isascii(fmt[i])) 4328c2ecf20Sopenharmony_ci return -EINVAL; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (fmt[i] != '%') 4358c2ecf20Sopenharmony_ci continue; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (fmt_cnt >= 3) 4388c2ecf20Sopenharmony_ci return -EINVAL; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci /* fmt[i] != 0 && fmt[last] == 0, so we can access fmt[i + 1] */ 4418c2ecf20Sopenharmony_ci i++; 4428c2ecf20Sopenharmony_ci if (fmt[i] == 'l') { 4438c2ecf20Sopenharmony_ci mod[fmt_cnt]++; 4448c2ecf20Sopenharmony_ci i++; 4458c2ecf20Sopenharmony_ci } else if (fmt[i] == 'p') { 4468c2ecf20Sopenharmony_ci mod[fmt_cnt]++; 4478c2ecf20Sopenharmony_ci if ((fmt[i + 1] == 'k' || 4488c2ecf20Sopenharmony_ci fmt[i + 1] == 'u') && 4498c2ecf20Sopenharmony_ci fmt[i + 2] == 's') { 4508c2ecf20Sopenharmony_ci fmt_ptype = fmt[i + 1]; 4518c2ecf20Sopenharmony_ci i += 2; 4528c2ecf20Sopenharmony_ci goto fmt_str; 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (fmt[i + 1] == 'B') { 4568c2ecf20Sopenharmony_ci i++; 4578c2ecf20Sopenharmony_ci goto fmt_next; 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci /* disallow any further format extensions */ 4618c2ecf20Sopenharmony_ci if (fmt[i + 1] != 0 && 4628c2ecf20Sopenharmony_ci !isspace(fmt[i + 1]) && 4638c2ecf20Sopenharmony_ci !ispunct(fmt[i + 1])) 4648c2ecf20Sopenharmony_ci return -EINVAL; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci goto fmt_next; 4678c2ecf20Sopenharmony_ci } else if (fmt[i] == 's') { 4688c2ecf20Sopenharmony_ci mod[fmt_cnt]++; 4698c2ecf20Sopenharmony_ci fmt_ptype = fmt[i]; 4708c2ecf20Sopenharmony_cifmt_str: 4718c2ecf20Sopenharmony_ci if (str_seen) 4728c2ecf20Sopenharmony_ci /* allow only one '%s' per fmt string */ 4738c2ecf20Sopenharmony_ci return -EINVAL; 4748c2ecf20Sopenharmony_ci str_seen = true; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci if (fmt[i + 1] != 0 && 4778c2ecf20Sopenharmony_ci !isspace(fmt[i + 1]) && 4788c2ecf20Sopenharmony_ci !ispunct(fmt[i + 1])) 4798c2ecf20Sopenharmony_ci return -EINVAL; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci switch (fmt_cnt) { 4828c2ecf20Sopenharmony_ci case 0: 4838c2ecf20Sopenharmony_ci unsafe_ptr = (void *)(long)arg1; 4848c2ecf20Sopenharmony_ci arg1 = (long)buf; 4858c2ecf20Sopenharmony_ci break; 4868c2ecf20Sopenharmony_ci case 1: 4878c2ecf20Sopenharmony_ci unsafe_ptr = (void *)(long)arg2; 4888c2ecf20Sopenharmony_ci arg2 = (long)buf; 4898c2ecf20Sopenharmony_ci break; 4908c2ecf20Sopenharmony_ci case 2: 4918c2ecf20Sopenharmony_ci unsafe_ptr = (void *)(long)arg3; 4928c2ecf20Sopenharmony_ci arg3 = (long)buf; 4938c2ecf20Sopenharmony_ci break; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci bpf_trace_copy_string(buf, unsafe_ptr, fmt_ptype, 4978c2ecf20Sopenharmony_ci sizeof(buf)); 4988c2ecf20Sopenharmony_ci goto fmt_next; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci if (fmt[i] == 'l') { 5028c2ecf20Sopenharmony_ci mod[fmt_cnt]++; 5038c2ecf20Sopenharmony_ci i++; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci if (fmt[i] != 'i' && fmt[i] != 'd' && 5078c2ecf20Sopenharmony_ci fmt[i] != 'u' && fmt[i] != 'x') 5088c2ecf20Sopenharmony_ci return -EINVAL; 5098c2ecf20Sopenharmony_cifmt_next: 5108c2ecf20Sopenharmony_ci fmt_cnt++; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci/* Horrid workaround for getting va_list handling working with different 5148c2ecf20Sopenharmony_ci * argument type combinations generically for 32 and 64 bit archs. 5158c2ecf20Sopenharmony_ci */ 5168c2ecf20Sopenharmony_ci#define __BPF_TP_EMIT() __BPF_ARG3_TP() 5178c2ecf20Sopenharmony_ci#define __BPF_TP(...) \ 5188c2ecf20Sopenharmony_ci bpf_do_trace_printk(fmt, ##__VA_ARGS__) 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci#define __BPF_ARG1_TP(...) \ 5218c2ecf20Sopenharmony_ci ((mod[0] == 2 || (mod[0] == 1 && __BITS_PER_LONG == 64)) \ 5228c2ecf20Sopenharmony_ci ? __BPF_TP(arg1, ##__VA_ARGS__) \ 5238c2ecf20Sopenharmony_ci : ((mod[0] == 1 || (mod[0] == 0 && __BITS_PER_LONG == 32)) \ 5248c2ecf20Sopenharmony_ci ? __BPF_TP((long)arg1, ##__VA_ARGS__) \ 5258c2ecf20Sopenharmony_ci : __BPF_TP((u32)arg1, ##__VA_ARGS__))) 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci#define __BPF_ARG2_TP(...) \ 5288c2ecf20Sopenharmony_ci ((mod[1] == 2 || (mod[1] == 1 && __BITS_PER_LONG == 64)) \ 5298c2ecf20Sopenharmony_ci ? __BPF_ARG1_TP(arg2, ##__VA_ARGS__) \ 5308c2ecf20Sopenharmony_ci : ((mod[1] == 1 || (mod[1] == 0 && __BITS_PER_LONG == 32)) \ 5318c2ecf20Sopenharmony_ci ? __BPF_ARG1_TP((long)arg2, ##__VA_ARGS__) \ 5328c2ecf20Sopenharmony_ci : __BPF_ARG1_TP((u32)arg2, ##__VA_ARGS__))) 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci#define __BPF_ARG3_TP(...) \ 5358c2ecf20Sopenharmony_ci ((mod[2] == 2 || (mod[2] == 1 && __BITS_PER_LONG == 64)) \ 5368c2ecf20Sopenharmony_ci ? __BPF_ARG2_TP(arg3, ##__VA_ARGS__) \ 5378c2ecf20Sopenharmony_ci : ((mod[2] == 1 || (mod[2] == 0 && __BITS_PER_LONG == 32)) \ 5388c2ecf20Sopenharmony_ci ? __BPF_ARG2_TP((long)arg3, ##__VA_ARGS__) \ 5398c2ecf20Sopenharmony_ci : __BPF_ARG2_TP((u32)arg3, ##__VA_ARGS__))) 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci return __BPF_TP_EMIT(); 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cistatic const struct bpf_func_proto bpf_trace_printk_proto = { 5458c2ecf20Sopenharmony_ci .func = bpf_trace_printk, 5468c2ecf20Sopenharmony_ci .gpl_only = true, 5478c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 5488c2ecf20Sopenharmony_ci .arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY, 5498c2ecf20Sopenharmony_ci .arg2_type = ARG_CONST_SIZE, 5508c2ecf20Sopenharmony_ci}; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ciconst struct bpf_func_proto *bpf_get_trace_printk_proto(void) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci /* 5558c2ecf20Sopenharmony_ci * This program might be calling bpf_trace_printk, 5568c2ecf20Sopenharmony_ci * so enable the associated bpf_trace/bpf_trace_printk event. 5578c2ecf20Sopenharmony_ci * Repeat this each time as it is possible a user has 5588c2ecf20Sopenharmony_ci * disabled bpf_trace_printk events. By loading a program 5598c2ecf20Sopenharmony_ci * calling bpf_trace_printk() however the user has expressed 5608c2ecf20Sopenharmony_ci * the intent to see such events. 5618c2ecf20Sopenharmony_ci */ 5628c2ecf20Sopenharmony_ci if (trace_set_clr_event("bpf_trace", "bpf_trace_printk", 1)) 5638c2ecf20Sopenharmony_ci pr_warn_ratelimited("could not enable bpf_trace_printk events"); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci return &bpf_trace_printk_proto; 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci#define MAX_SEQ_PRINTF_VARARGS 12 5698c2ecf20Sopenharmony_ci#define MAX_SEQ_PRINTF_MAX_MEMCPY 6 5708c2ecf20Sopenharmony_ci#define MAX_SEQ_PRINTF_STR_LEN 128 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistruct bpf_seq_printf_buf { 5738c2ecf20Sopenharmony_ci char buf[MAX_SEQ_PRINTF_MAX_MEMCPY][MAX_SEQ_PRINTF_STR_LEN]; 5748c2ecf20Sopenharmony_ci}; 5758c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct bpf_seq_printf_buf, bpf_seq_printf_buf); 5768c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(int, bpf_seq_printf_buf_used); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ciBPF_CALL_5(bpf_seq_printf, struct seq_file *, m, char *, fmt, u32, fmt_size, 5798c2ecf20Sopenharmony_ci const void *, data, u32, data_len) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci int err = -EINVAL, fmt_cnt = 0, memcpy_cnt = 0; 5828c2ecf20Sopenharmony_ci int i, buf_used, copy_size, num_args; 5838c2ecf20Sopenharmony_ci u64 params[MAX_SEQ_PRINTF_VARARGS]; 5848c2ecf20Sopenharmony_ci struct bpf_seq_printf_buf *bufs; 5858c2ecf20Sopenharmony_ci const u64 *args = data; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci buf_used = this_cpu_inc_return(bpf_seq_printf_buf_used); 5888c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(buf_used > 1)) { 5898c2ecf20Sopenharmony_ci err = -EBUSY; 5908c2ecf20Sopenharmony_ci goto out; 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci bufs = this_cpu_ptr(&bpf_seq_printf_buf); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci /* 5968c2ecf20Sopenharmony_ci * bpf_check()->check_func_arg()->check_stack_boundary() 5978c2ecf20Sopenharmony_ci * guarantees that fmt points to bpf program stack, 5988c2ecf20Sopenharmony_ci * fmt_size bytes of it were initialized and fmt_size > 0 5998c2ecf20Sopenharmony_ci */ 6008c2ecf20Sopenharmony_ci if (fmt[--fmt_size] != 0) 6018c2ecf20Sopenharmony_ci goto out; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci if (data_len & 7) 6048c2ecf20Sopenharmony_ci goto out; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci for (i = 0; i < fmt_size; i++) { 6078c2ecf20Sopenharmony_ci if (fmt[i] == '%') { 6088c2ecf20Sopenharmony_ci if (fmt[i + 1] == '%') 6098c2ecf20Sopenharmony_ci i++; 6108c2ecf20Sopenharmony_ci else if (!data || !data_len) 6118c2ecf20Sopenharmony_ci goto out; 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci num_args = data_len / 8; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci /* check format string for allowed specifiers */ 6188c2ecf20Sopenharmony_ci for (i = 0; i < fmt_size; i++) { 6198c2ecf20Sopenharmony_ci /* only printable ascii for now. */ 6208c2ecf20Sopenharmony_ci if ((!isprint(fmt[i]) && !isspace(fmt[i])) || !isascii(fmt[i])) { 6218c2ecf20Sopenharmony_ci err = -EINVAL; 6228c2ecf20Sopenharmony_ci goto out; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if (fmt[i] != '%') 6268c2ecf20Sopenharmony_ci continue; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci if (fmt[i + 1] == '%') { 6298c2ecf20Sopenharmony_ci i++; 6308c2ecf20Sopenharmony_ci continue; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci if (fmt_cnt >= MAX_SEQ_PRINTF_VARARGS) { 6348c2ecf20Sopenharmony_ci err = -E2BIG; 6358c2ecf20Sopenharmony_ci goto out; 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci if (fmt_cnt >= num_args) { 6398c2ecf20Sopenharmony_ci err = -EINVAL; 6408c2ecf20Sopenharmony_ci goto out; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci /* fmt[i] != 0 && fmt[last] == 0, so we can access fmt[i + 1] */ 6448c2ecf20Sopenharmony_ci i++; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci /* skip optional "[0 +-][num]" width formating field */ 6478c2ecf20Sopenharmony_ci while (fmt[i] == '0' || fmt[i] == '+' || fmt[i] == '-' || 6488c2ecf20Sopenharmony_ci fmt[i] == ' ') 6498c2ecf20Sopenharmony_ci i++; 6508c2ecf20Sopenharmony_ci if (fmt[i] >= '1' && fmt[i] <= '9') { 6518c2ecf20Sopenharmony_ci i++; 6528c2ecf20Sopenharmony_ci while (fmt[i] >= '0' && fmt[i] <= '9') 6538c2ecf20Sopenharmony_ci i++; 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci if (fmt[i] == 's') { 6578c2ecf20Sopenharmony_ci void *unsafe_ptr; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci /* try our best to copy */ 6608c2ecf20Sopenharmony_ci if (memcpy_cnt >= MAX_SEQ_PRINTF_MAX_MEMCPY) { 6618c2ecf20Sopenharmony_ci err = -E2BIG; 6628c2ecf20Sopenharmony_ci goto out; 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci unsafe_ptr = (void *)(long)args[fmt_cnt]; 6668c2ecf20Sopenharmony_ci err = strncpy_from_kernel_nofault(bufs->buf[memcpy_cnt], 6678c2ecf20Sopenharmony_ci unsafe_ptr, MAX_SEQ_PRINTF_STR_LEN); 6688c2ecf20Sopenharmony_ci if (err < 0) 6698c2ecf20Sopenharmony_ci bufs->buf[memcpy_cnt][0] = '\0'; 6708c2ecf20Sopenharmony_ci params[fmt_cnt] = (u64)(long)bufs->buf[memcpy_cnt]; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci fmt_cnt++; 6738c2ecf20Sopenharmony_ci memcpy_cnt++; 6748c2ecf20Sopenharmony_ci continue; 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci if (fmt[i] == 'p') { 6788c2ecf20Sopenharmony_ci if (fmt[i + 1] == 0 || 6798c2ecf20Sopenharmony_ci fmt[i + 1] == 'K' || 6808c2ecf20Sopenharmony_ci fmt[i + 1] == 'x' || 6818c2ecf20Sopenharmony_ci fmt[i + 1] == 'B') { 6828c2ecf20Sopenharmony_ci /* just kernel pointers */ 6838c2ecf20Sopenharmony_ci params[fmt_cnt] = args[fmt_cnt]; 6848c2ecf20Sopenharmony_ci fmt_cnt++; 6858c2ecf20Sopenharmony_ci continue; 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci /* only support "%pI4", "%pi4", "%pI6" and "%pi6". */ 6898c2ecf20Sopenharmony_ci if (fmt[i + 1] != 'i' && fmt[i + 1] != 'I') { 6908c2ecf20Sopenharmony_ci err = -EINVAL; 6918c2ecf20Sopenharmony_ci goto out; 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci if (fmt[i + 2] != '4' && fmt[i + 2] != '6') { 6948c2ecf20Sopenharmony_ci err = -EINVAL; 6958c2ecf20Sopenharmony_ci goto out; 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci if (memcpy_cnt >= MAX_SEQ_PRINTF_MAX_MEMCPY) { 6998c2ecf20Sopenharmony_ci err = -E2BIG; 7008c2ecf20Sopenharmony_ci goto out; 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci copy_size = (fmt[i + 2] == '4') ? 4 : 16; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci err = copy_from_kernel_nofault(bufs->buf[memcpy_cnt], 7078c2ecf20Sopenharmony_ci (void *) (long) args[fmt_cnt], 7088c2ecf20Sopenharmony_ci copy_size); 7098c2ecf20Sopenharmony_ci if (err < 0) 7108c2ecf20Sopenharmony_ci memset(bufs->buf[memcpy_cnt], 0, copy_size); 7118c2ecf20Sopenharmony_ci params[fmt_cnt] = (u64)(long)bufs->buf[memcpy_cnt]; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci i += 2; 7148c2ecf20Sopenharmony_ci fmt_cnt++; 7158c2ecf20Sopenharmony_ci memcpy_cnt++; 7168c2ecf20Sopenharmony_ci continue; 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci if (fmt[i] == 'l') { 7208c2ecf20Sopenharmony_ci i++; 7218c2ecf20Sopenharmony_ci if (fmt[i] == 'l') 7228c2ecf20Sopenharmony_ci i++; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci if (fmt[i] != 'i' && fmt[i] != 'd' && 7268c2ecf20Sopenharmony_ci fmt[i] != 'u' && fmt[i] != 'x' && 7278c2ecf20Sopenharmony_ci fmt[i] != 'X') { 7288c2ecf20Sopenharmony_ci err = -EINVAL; 7298c2ecf20Sopenharmony_ci goto out; 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci params[fmt_cnt] = args[fmt_cnt]; 7338c2ecf20Sopenharmony_ci fmt_cnt++; 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci /* Maximumly we can have MAX_SEQ_PRINTF_VARARGS parameter, just give 7378c2ecf20Sopenharmony_ci * all of them to seq_printf(). 7388c2ecf20Sopenharmony_ci */ 7398c2ecf20Sopenharmony_ci seq_printf(m, fmt, params[0], params[1], params[2], params[3], 7408c2ecf20Sopenharmony_ci params[4], params[5], params[6], params[7], params[8], 7418c2ecf20Sopenharmony_ci params[9], params[10], params[11]); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci err = seq_has_overflowed(m) ? -EOVERFLOW : 0; 7448c2ecf20Sopenharmony_ciout: 7458c2ecf20Sopenharmony_ci this_cpu_dec(bpf_seq_printf_buf_used); 7468c2ecf20Sopenharmony_ci return err; 7478c2ecf20Sopenharmony_ci} 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ciBTF_ID_LIST_SINGLE(btf_seq_file_ids, struct, seq_file) 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic const struct bpf_func_proto bpf_seq_printf_proto = { 7528c2ecf20Sopenharmony_ci .func = bpf_seq_printf, 7538c2ecf20Sopenharmony_ci .gpl_only = true, 7548c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 7558c2ecf20Sopenharmony_ci .arg1_type = ARG_PTR_TO_BTF_ID, 7568c2ecf20Sopenharmony_ci .arg1_btf_id = &btf_seq_file_ids[0], 7578c2ecf20Sopenharmony_ci .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 7588c2ecf20Sopenharmony_ci .arg3_type = ARG_CONST_SIZE, 7598c2ecf20Sopenharmony_ci .arg4_type = ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY, 7608c2ecf20Sopenharmony_ci .arg5_type = ARG_CONST_SIZE_OR_ZERO, 7618c2ecf20Sopenharmony_ci}; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ciBPF_CALL_3(bpf_seq_write, struct seq_file *, m, const void *, data, u32, len) 7648c2ecf20Sopenharmony_ci{ 7658c2ecf20Sopenharmony_ci return seq_write(m, data, len) ? -EOVERFLOW : 0; 7668c2ecf20Sopenharmony_ci} 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_cistatic const struct bpf_func_proto bpf_seq_write_proto = { 7698c2ecf20Sopenharmony_ci .func = bpf_seq_write, 7708c2ecf20Sopenharmony_ci .gpl_only = true, 7718c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 7728c2ecf20Sopenharmony_ci .arg1_type = ARG_PTR_TO_BTF_ID, 7738c2ecf20Sopenharmony_ci .arg1_btf_id = &btf_seq_file_ids[0], 7748c2ecf20Sopenharmony_ci .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 7758c2ecf20Sopenharmony_ci .arg3_type = ARG_CONST_SIZE_OR_ZERO, 7768c2ecf20Sopenharmony_ci}; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ciBPF_CALL_4(bpf_seq_printf_btf, struct seq_file *, m, struct btf_ptr *, ptr, 7798c2ecf20Sopenharmony_ci u32, btf_ptr_size, u64, flags) 7808c2ecf20Sopenharmony_ci{ 7818c2ecf20Sopenharmony_ci const struct btf *btf; 7828c2ecf20Sopenharmony_ci s32 btf_id; 7838c2ecf20Sopenharmony_ci int ret; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci ret = bpf_btf_printf_prepare(ptr, btf_ptr_size, flags, &btf, &btf_id); 7868c2ecf20Sopenharmony_ci if (ret) 7878c2ecf20Sopenharmony_ci return ret; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci return btf_type_seq_show_flags(btf, btf_id, ptr->ptr, m, flags); 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_cistatic const struct bpf_func_proto bpf_seq_printf_btf_proto = { 7938c2ecf20Sopenharmony_ci .func = bpf_seq_printf_btf, 7948c2ecf20Sopenharmony_ci .gpl_only = true, 7958c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 7968c2ecf20Sopenharmony_ci .arg1_type = ARG_PTR_TO_BTF_ID, 7978c2ecf20Sopenharmony_ci .arg1_btf_id = &btf_seq_file_ids[0], 7988c2ecf20Sopenharmony_ci .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 7998c2ecf20Sopenharmony_ci .arg3_type = ARG_CONST_SIZE_OR_ZERO, 8008c2ecf20Sopenharmony_ci .arg4_type = ARG_ANYTHING, 8018c2ecf20Sopenharmony_ci}; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_cistatic __always_inline int 8048c2ecf20Sopenharmony_ciget_map_perf_counter(struct bpf_map *map, u64 flags, 8058c2ecf20Sopenharmony_ci u64 *value, u64 *enabled, u64 *running) 8068c2ecf20Sopenharmony_ci{ 8078c2ecf20Sopenharmony_ci struct bpf_array *array = container_of(map, struct bpf_array, map); 8088c2ecf20Sopenharmony_ci unsigned int cpu = smp_processor_id(); 8098c2ecf20Sopenharmony_ci u64 index = flags & BPF_F_INDEX_MASK; 8108c2ecf20Sopenharmony_ci struct bpf_event_entry *ee; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci if (unlikely(flags & ~(BPF_F_INDEX_MASK))) 8138c2ecf20Sopenharmony_ci return -EINVAL; 8148c2ecf20Sopenharmony_ci if (index == BPF_F_CURRENT_CPU) 8158c2ecf20Sopenharmony_ci index = cpu; 8168c2ecf20Sopenharmony_ci if (unlikely(index >= array->map.max_entries)) 8178c2ecf20Sopenharmony_ci return -E2BIG; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci ee = READ_ONCE(array->ptrs[index]); 8208c2ecf20Sopenharmony_ci if (!ee) 8218c2ecf20Sopenharmony_ci return -ENOENT; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci return perf_event_read_local(ee->event, value, enabled, running); 8248c2ecf20Sopenharmony_ci} 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ciBPF_CALL_2(bpf_perf_event_read, struct bpf_map *, map, u64, flags) 8278c2ecf20Sopenharmony_ci{ 8288c2ecf20Sopenharmony_ci u64 value = 0; 8298c2ecf20Sopenharmony_ci int err; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci err = get_map_perf_counter(map, flags, &value, NULL, NULL); 8328c2ecf20Sopenharmony_ci /* 8338c2ecf20Sopenharmony_ci * this api is ugly since we miss [-22..-2] range of valid 8348c2ecf20Sopenharmony_ci * counter values, but that's uapi 8358c2ecf20Sopenharmony_ci */ 8368c2ecf20Sopenharmony_ci if (err) 8378c2ecf20Sopenharmony_ci return err; 8388c2ecf20Sopenharmony_ci return value; 8398c2ecf20Sopenharmony_ci} 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_cistatic const struct bpf_func_proto bpf_perf_event_read_proto = { 8428c2ecf20Sopenharmony_ci .func = bpf_perf_event_read, 8438c2ecf20Sopenharmony_ci .gpl_only = true, 8448c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 8458c2ecf20Sopenharmony_ci .arg1_type = ARG_CONST_MAP_PTR, 8468c2ecf20Sopenharmony_ci .arg2_type = ARG_ANYTHING, 8478c2ecf20Sopenharmony_ci}; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ciBPF_CALL_4(bpf_perf_event_read_value, struct bpf_map *, map, u64, flags, 8508c2ecf20Sopenharmony_ci struct bpf_perf_event_value *, buf, u32, size) 8518c2ecf20Sopenharmony_ci{ 8528c2ecf20Sopenharmony_ci int err = -EINVAL; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci if (unlikely(size != sizeof(struct bpf_perf_event_value))) 8558c2ecf20Sopenharmony_ci goto clear; 8568c2ecf20Sopenharmony_ci err = get_map_perf_counter(map, flags, &buf->counter, &buf->enabled, 8578c2ecf20Sopenharmony_ci &buf->running); 8588c2ecf20Sopenharmony_ci if (unlikely(err)) 8598c2ecf20Sopenharmony_ci goto clear; 8608c2ecf20Sopenharmony_ci return 0; 8618c2ecf20Sopenharmony_ciclear: 8628c2ecf20Sopenharmony_ci memset(buf, 0, size); 8638c2ecf20Sopenharmony_ci return err; 8648c2ecf20Sopenharmony_ci} 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_cistatic const struct bpf_func_proto bpf_perf_event_read_value_proto = { 8678c2ecf20Sopenharmony_ci .func = bpf_perf_event_read_value, 8688c2ecf20Sopenharmony_ci .gpl_only = true, 8698c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 8708c2ecf20Sopenharmony_ci .arg1_type = ARG_CONST_MAP_PTR, 8718c2ecf20Sopenharmony_ci .arg2_type = ARG_ANYTHING, 8728c2ecf20Sopenharmony_ci .arg3_type = ARG_PTR_TO_UNINIT_MEM, 8738c2ecf20Sopenharmony_ci .arg4_type = ARG_CONST_SIZE, 8748c2ecf20Sopenharmony_ci}; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_cistatic __always_inline u64 8778c2ecf20Sopenharmony_ci__bpf_perf_event_output(struct pt_regs *regs, struct bpf_map *map, 8788c2ecf20Sopenharmony_ci u64 flags, struct perf_sample_data *sd) 8798c2ecf20Sopenharmony_ci{ 8808c2ecf20Sopenharmony_ci struct bpf_array *array = container_of(map, struct bpf_array, map); 8818c2ecf20Sopenharmony_ci unsigned int cpu = smp_processor_id(); 8828c2ecf20Sopenharmony_ci u64 index = flags & BPF_F_INDEX_MASK; 8838c2ecf20Sopenharmony_ci struct bpf_event_entry *ee; 8848c2ecf20Sopenharmony_ci struct perf_event *event; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci if (index == BPF_F_CURRENT_CPU) 8878c2ecf20Sopenharmony_ci index = cpu; 8888c2ecf20Sopenharmony_ci if (unlikely(index >= array->map.max_entries)) 8898c2ecf20Sopenharmony_ci return -E2BIG; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci ee = READ_ONCE(array->ptrs[index]); 8928c2ecf20Sopenharmony_ci if (!ee) 8938c2ecf20Sopenharmony_ci return -ENOENT; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci event = ee->event; 8968c2ecf20Sopenharmony_ci if (unlikely(event->attr.type != PERF_TYPE_SOFTWARE || 8978c2ecf20Sopenharmony_ci event->attr.config != PERF_COUNT_SW_BPF_OUTPUT)) 8988c2ecf20Sopenharmony_ci return -EINVAL; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci if (unlikely(event->oncpu != cpu)) 9018c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci return perf_event_output(event, sd, regs); 9048c2ecf20Sopenharmony_ci} 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci/* 9078c2ecf20Sopenharmony_ci * Support executing tracepoints in normal, irq, and nmi context that each call 9088c2ecf20Sopenharmony_ci * bpf_perf_event_output 9098c2ecf20Sopenharmony_ci */ 9108c2ecf20Sopenharmony_cistruct bpf_trace_sample_data { 9118c2ecf20Sopenharmony_ci struct perf_sample_data sds[3]; 9128c2ecf20Sopenharmony_ci}; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct bpf_trace_sample_data, bpf_trace_sds); 9158c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(int, bpf_trace_nest_level); 9168c2ecf20Sopenharmony_ciBPF_CALL_5(bpf_perf_event_output, struct pt_regs *, regs, struct bpf_map *, map, 9178c2ecf20Sopenharmony_ci u64, flags, void *, data, u64, size) 9188c2ecf20Sopenharmony_ci{ 9198c2ecf20Sopenharmony_ci struct bpf_trace_sample_data *sds = this_cpu_ptr(&bpf_trace_sds); 9208c2ecf20Sopenharmony_ci int nest_level = this_cpu_inc_return(bpf_trace_nest_level); 9218c2ecf20Sopenharmony_ci struct perf_raw_record raw = { 9228c2ecf20Sopenharmony_ci .frag = { 9238c2ecf20Sopenharmony_ci .size = size, 9248c2ecf20Sopenharmony_ci .data = data, 9258c2ecf20Sopenharmony_ci }, 9268c2ecf20Sopenharmony_ci }; 9278c2ecf20Sopenharmony_ci struct perf_sample_data *sd; 9288c2ecf20Sopenharmony_ci int err; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(nest_level > ARRAY_SIZE(sds->sds))) { 9318c2ecf20Sopenharmony_ci err = -EBUSY; 9328c2ecf20Sopenharmony_ci goto out; 9338c2ecf20Sopenharmony_ci } 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci sd = &sds->sds[nest_level - 1]; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci if (unlikely(flags & ~(BPF_F_INDEX_MASK))) { 9388c2ecf20Sopenharmony_ci err = -EINVAL; 9398c2ecf20Sopenharmony_ci goto out; 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci perf_sample_data_init(sd, 0, 0); 9438c2ecf20Sopenharmony_ci sd->raw = &raw; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci err = __bpf_perf_event_output(regs, map, flags, sd); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ciout: 9488c2ecf20Sopenharmony_ci this_cpu_dec(bpf_trace_nest_level); 9498c2ecf20Sopenharmony_ci return err; 9508c2ecf20Sopenharmony_ci} 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_cistatic const struct bpf_func_proto bpf_perf_event_output_proto = { 9538c2ecf20Sopenharmony_ci .func = bpf_perf_event_output, 9548c2ecf20Sopenharmony_ci .gpl_only = true, 9558c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 9568c2ecf20Sopenharmony_ci .arg1_type = ARG_PTR_TO_CTX, 9578c2ecf20Sopenharmony_ci .arg2_type = ARG_CONST_MAP_PTR, 9588c2ecf20Sopenharmony_ci .arg3_type = ARG_ANYTHING, 9598c2ecf20Sopenharmony_ci .arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY, 9608c2ecf20Sopenharmony_ci .arg5_type = ARG_CONST_SIZE_OR_ZERO, 9618c2ecf20Sopenharmony_ci}; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(int, bpf_event_output_nest_level); 9648c2ecf20Sopenharmony_cistruct bpf_nested_pt_regs { 9658c2ecf20Sopenharmony_ci struct pt_regs regs[3]; 9668c2ecf20Sopenharmony_ci}; 9678c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct bpf_nested_pt_regs, bpf_pt_regs); 9688c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct bpf_trace_sample_data, bpf_misc_sds); 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ciu64 bpf_event_output(struct bpf_map *map, u64 flags, void *meta, u64 meta_size, 9718c2ecf20Sopenharmony_ci void *ctx, u64 ctx_size, bpf_ctx_copy_t ctx_copy) 9728c2ecf20Sopenharmony_ci{ 9738c2ecf20Sopenharmony_ci struct perf_raw_frag frag = { 9748c2ecf20Sopenharmony_ci .copy = ctx_copy, 9758c2ecf20Sopenharmony_ci .size = ctx_size, 9768c2ecf20Sopenharmony_ci .data = ctx, 9778c2ecf20Sopenharmony_ci }; 9788c2ecf20Sopenharmony_ci struct perf_raw_record raw = { 9798c2ecf20Sopenharmony_ci .frag = { 9808c2ecf20Sopenharmony_ci { 9818c2ecf20Sopenharmony_ci .next = ctx_size ? &frag : NULL, 9828c2ecf20Sopenharmony_ci }, 9838c2ecf20Sopenharmony_ci .size = meta_size, 9848c2ecf20Sopenharmony_ci .data = meta, 9858c2ecf20Sopenharmony_ci }, 9868c2ecf20Sopenharmony_ci }; 9878c2ecf20Sopenharmony_ci struct perf_sample_data *sd; 9888c2ecf20Sopenharmony_ci struct pt_regs *regs; 9898c2ecf20Sopenharmony_ci int nest_level; 9908c2ecf20Sopenharmony_ci u64 ret; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci preempt_disable(); 9938c2ecf20Sopenharmony_ci nest_level = this_cpu_inc_return(bpf_event_output_nest_level); 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(nest_level > ARRAY_SIZE(bpf_misc_sds.sds))) { 9968c2ecf20Sopenharmony_ci ret = -EBUSY; 9978c2ecf20Sopenharmony_ci goto out; 9988c2ecf20Sopenharmony_ci } 9998c2ecf20Sopenharmony_ci sd = this_cpu_ptr(&bpf_misc_sds.sds[nest_level - 1]); 10008c2ecf20Sopenharmony_ci regs = this_cpu_ptr(&bpf_pt_regs.regs[nest_level - 1]); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci perf_fetch_caller_regs(regs); 10038c2ecf20Sopenharmony_ci perf_sample_data_init(sd, 0, 0); 10048c2ecf20Sopenharmony_ci sd->raw = &raw; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci ret = __bpf_perf_event_output(regs, map, flags, sd); 10078c2ecf20Sopenharmony_ciout: 10088c2ecf20Sopenharmony_ci this_cpu_dec(bpf_event_output_nest_level); 10098c2ecf20Sopenharmony_ci preempt_enable(); 10108c2ecf20Sopenharmony_ci return ret; 10118c2ecf20Sopenharmony_ci} 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ciBPF_CALL_0(bpf_get_current_task) 10148c2ecf20Sopenharmony_ci{ 10158c2ecf20Sopenharmony_ci return (long) current; 10168c2ecf20Sopenharmony_ci} 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ciconst struct bpf_func_proto bpf_get_current_task_proto = { 10198c2ecf20Sopenharmony_ci .func = bpf_get_current_task, 10208c2ecf20Sopenharmony_ci .gpl_only = true, 10218c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 10228c2ecf20Sopenharmony_ci}; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ciBPF_CALL_2(bpf_current_task_under_cgroup, struct bpf_map *, map, u32, idx) 10258c2ecf20Sopenharmony_ci{ 10268c2ecf20Sopenharmony_ci struct bpf_array *array = container_of(map, struct bpf_array, map); 10278c2ecf20Sopenharmony_ci struct cgroup *cgrp; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci if (unlikely(idx >= array->map.max_entries)) 10308c2ecf20Sopenharmony_ci return -E2BIG; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci cgrp = READ_ONCE(array->ptrs[idx]); 10338c2ecf20Sopenharmony_ci if (unlikely(!cgrp)) 10348c2ecf20Sopenharmony_ci return -EAGAIN; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci return task_under_cgroup_hierarchy(current, cgrp); 10378c2ecf20Sopenharmony_ci} 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_cistatic const struct bpf_func_proto bpf_current_task_under_cgroup_proto = { 10408c2ecf20Sopenharmony_ci .func = bpf_current_task_under_cgroup, 10418c2ecf20Sopenharmony_ci .gpl_only = false, 10428c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 10438c2ecf20Sopenharmony_ci .arg1_type = ARG_CONST_MAP_PTR, 10448c2ecf20Sopenharmony_ci .arg2_type = ARG_ANYTHING, 10458c2ecf20Sopenharmony_ci}; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_cistruct send_signal_irq_work { 10488c2ecf20Sopenharmony_ci struct irq_work irq_work; 10498c2ecf20Sopenharmony_ci struct task_struct *task; 10508c2ecf20Sopenharmony_ci u32 sig; 10518c2ecf20Sopenharmony_ci enum pid_type type; 10528c2ecf20Sopenharmony_ci}; 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct send_signal_irq_work, send_signal_work); 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_cistatic void do_bpf_send_signal(struct irq_work *entry) 10578c2ecf20Sopenharmony_ci{ 10588c2ecf20Sopenharmony_ci struct send_signal_irq_work *work; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci work = container_of(entry, struct send_signal_irq_work, irq_work); 10618c2ecf20Sopenharmony_ci group_send_sig_info(work->sig, SEND_SIG_PRIV, work->task, work->type); 10628c2ecf20Sopenharmony_ci put_task_struct(work->task); 10638c2ecf20Sopenharmony_ci} 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_cistatic int bpf_send_signal_common(u32 sig, enum pid_type type) 10668c2ecf20Sopenharmony_ci{ 10678c2ecf20Sopenharmony_ci struct send_signal_irq_work *work = NULL; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci /* Similar to bpf_probe_write_user, task needs to be 10708c2ecf20Sopenharmony_ci * in a sound condition and kernel memory access be 10718c2ecf20Sopenharmony_ci * permitted in order to send signal to the current 10728c2ecf20Sopenharmony_ci * task. 10738c2ecf20Sopenharmony_ci */ 10748c2ecf20Sopenharmony_ci if (unlikely(current->flags & (PF_KTHREAD | PF_EXITING))) 10758c2ecf20Sopenharmony_ci return -EPERM; 10768c2ecf20Sopenharmony_ci if (unlikely(uaccess_kernel())) 10778c2ecf20Sopenharmony_ci return -EPERM; 10788c2ecf20Sopenharmony_ci if (unlikely(!nmi_uaccess_okay())) 10798c2ecf20Sopenharmony_ci return -EPERM; 10808c2ecf20Sopenharmony_ci /* Task should not be pid=1 to avoid kernel panic. */ 10818c2ecf20Sopenharmony_ci if (unlikely(is_global_init(current))) 10828c2ecf20Sopenharmony_ci return -EPERM; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci if (irqs_disabled()) { 10858c2ecf20Sopenharmony_ci /* Do an early check on signal validity. Otherwise, 10868c2ecf20Sopenharmony_ci * the error is lost in deferred irq_work. 10878c2ecf20Sopenharmony_ci */ 10888c2ecf20Sopenharmony_ci if (unlikely(!valid_signal(sig))) 10898c2ecf20Sopenharmony_ci return -EINVAL; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci work = this_cpu_ptr(&send_signal_work); 10928c2ecf20Sopenharmony_ci if (atomic_read(&work->irq_work.flags) & IRQ_WORK_BUSY) 10938c2ecf20Sopenharmony_ci return -EBUSY; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci /* Add the current task, which is the target of sending signal, 10968c2ecf20Sopenharmony_ci * to the irq_work. The current task may change when queued 10978c2ecf20Sopenharmony_ci * irq works get executed. 10988c2ecf20Sopenharmony_ci */ 10998c2ecf20Sopenharmony_ci work->task = get_task_struct(current); 11008c2ecf20Sopenharmony_ci work->sig = sig; 11018c2ecf20Sopenharmony_ci work->type = type; 11028c2ecf20Sopenharmony_ci irq_work_queue(&work->irq_work); 11038c2ecf20Sopenharmony_ci return 0; 11048c2ecf20Sopenharmony_ci } 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci return group_send_sig_info(sig, SEND_SIG_PRIV, current, type); 11078c2ecf20Sopenharmony_ci} 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ciBPF_CALL_1(bpf_send_signal, u32, sig) 11108c2ecf20Sopenharmony_ci{ 11118c2ecf20Sopenharmony_ci return bpf_send_signal_common(sig, PIDTYPE_TGID); 11128c2ecf20Sopenharmony_ci} 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_cistatic const struct bpf_func_proto bpf_send_signal_proto = { 11158c2ecf20Sopenharmony_ci .func = bpf_send_signal, 11168c2ecf20Sopenharmony_ci .gpl_only = false, 11178c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 11188c2ecf20Sopenharmony_ci .arg1_type = ARG_ANYTHING, 11198c2ecf20Sopenharmony_ci}; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ciBPF_CALL_1(bpf_send_signal_thread, u32, sig) 11228c2ecf20Sopenharmony_ci{ 11238c2ecf20Sopenharmony_ci return bpf_send_signal_common(sig, PIDTYPE_PID); 11248c2ecf20Sopenharmony_ci} 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_cistatic const struct bpf_func_proto bpf_send_signal_thread_proto = { 11278c2ecf20Sopenharmony_ci .func = bpf_send_signal_thread, 11288c2ecf20Sopenharmony_ci .gpl_only = false, 11298c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 11308c2ecf20Sopenharmony_ci .arg1_type = ARG_ANYTHING, 11318c2ecf20Sopenharmony_ci}; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ciBPF_CALL_3(bpf_d_path, struct path *, path, char *, buf, u32, sz) 11348c2ecf20Sopenharmony_ci{ 11358c2ecf20Sopenharmony_ci struct path copy; 11368c2ecf20Sopenharmony_ci long len; 11378c2ecf20Sopenharmony_ci char *p; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci if (!sz) 11408c2ecf20Sopenharmony_ci return 0; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci /* 11438c2ecf20Sopenharmony_ci * The path pointer is verified as trusted and safe to use, 11448c2ecf20Sopenharmony_ci * but let's double check it's valid anyway to workaround 11458c2ecf20Sopenharmony_ci * potentially broken verifier. 11468c2ecf20Sopenharmony_ci */ 11478c2ecf20Sopenharmony_ci len = copy_from_kernel_nofault(©, path, sizeof(*path)); 11488c2ecf20Sopenharmony_ci if (len < 0) 11498c2ecf20Sopenharmony_ci return len; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci p = d_path(©, buf, sz); 11528c2ecf20Sopenharmony_ci if (IS_ERR(p)) { 11538c2ecf20Sopenharmony_ci len = PTR_ERR(p); 11548c2ecf20Sopenharmony_ci } else { 11558c2ecf20Sopenharmony_ci len = buf + sz - p; 11568c2ecf20Sopenharmony_ci memmove(buf, p, len); 11578c2ecf20Sopenharmony_ci } 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci return len; 11608c2ecf20Sopenharmony_ci} 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ciBTF_SET_START(btf_allowlist_d_path) 11638c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY 11648c2ecf20Sopenharmony_ciBTF_ID(func, security_file_permission) 11658c2ecf20Sopenharmony_ciBTF_ID(func, security_inode_getattr) 11668c2ecf20Sopenharmony_ciBTF_ID(func, security_file_open) 11678c2ecf20Sopenharmony_ci#endif 11688c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_PATH 11698c2ecf20Sopenharmony_ciBTF_ID(func, security_path_truncate) 11708c2ecf20Sopenharmony_ci#endif 11718c2ecf20Sopenharmony_ciBTF_ID(func, vfs_truncate) 11728c2ecf20Sopenharmony_ciBTF_ID(func, vfs_fallocate) 11738c2ecf20Sopenharmony_ciBTF_ID(func, dentry_open) 11748c2ecf20Sopenharmony_ciBTF_ID(func, vfs_getattr) 11758c2ecf20Sopenharmony_ciBTF_ID(func, filp_close) 11768c2ecf20Sopenharmony_ciBTF_SET_END(btf_allowlist_d_path) 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_cistatic bool bpf_d_path_allowed(const struct bpf_prog *prog) 11798c2ecf20Sopenharmony_ci{ 11808c2ecf20Sopenharmony_ci return btf_id_set_contains(&btf_allowlist_d_path, prog->aux->attach_btf_id); 11818c2ecf20Sopenharmony_ci} 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ciBTF_ID_LIST_SINGLE(bpf_d_path_btf_ids, struct, path) 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_cistatic const struct bpf_func_proto bpf_d_path_proto = { 11868c2ecf20Sopenharmony_ci .func = bpf_d_path, 11878c2ecf20Sopenharmony_ci .gpl_only = false, 11888c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 11898c2ecf20Sopenharmony_ci .arg1_type = ARG_PTR_TO_BTF_ID, 11908c2ecf20Sopenharmony_ci .arg1_btf_id = &bpf_d_path_btf_ids[0], 11918c2ecf20Sopenharmony_ci .arg2_type = ARG_PTR_TO_MEM, 11928c2ecf20Sopenharmony_ci .arg3_type = ARG_CONST_SIZE_OR_ZERO, 11938c2ecf20Sopenharmony_ci .allowed = bpf_d_path_allowed, 11948c2ecf20Sopenharmony_ci}; 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci#define BTF_F_ALL (BTF_F_COMPACT | BTF_F_NONAME | \ 11978c2ecf20Sopenharmony_ci BTF_F_PTR_RAW | BTF_F_ZERO) 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_cistatic int bpf_btf_printf_prepare(struct btf_ptr *ptr, u32 btf_ptr_size, 12008c2ecf20Sopenharmony_ci u64 flags, const struct btf **btf, 12018c2ecf20Sopenharmony_ci s32 *btf_id) 12028c2ecf20Sopenharmony_ci{ 12038c2ecf20Sopenharmony_ci const struct btf_type *t; 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci if (unlikely(flags & ~(BTF_F_ALL))) 12068c2ecf20Sopenharmony_ci return -EINVAL; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci if (btf_ptr_size != sizeof(struct btf_ptr)) 12098c2ecf20Sopenharmony_ci return -EINVAL; 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci *btf = bpf_get_btf_vmlinux(); 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(*btf)) 12148c2ecf20Sopenharmony_ci return IS_ERR(*btf) ? PTR_ERR(*btf) : -EINVAL; 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci if (ptr->type_id > 0) 12178c2ecf20Sopenharmony_ci *btf_id = ptr->type_id; 12188c2ecf20Sopenharmony_ci else 12198c2ecf20Sopenharmony_ci return -EINVAL; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci if (*btf_id > 0) 12228c2ecf20Sopenharmony_ci t = btf_type_by_id(*btf, *btf_id); 12238c2ecf20Sopenharmony_ci if (*btf_id <= 0 || !t) 12248c2ecf20Sopenharmony_ci return -ENOENT; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci return 0; 12278c2ecf20Sopenharmony_ci} 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ciBPF_CALL_5(bpf_snprintf_btf, char *, str, u32, str_size, struct btf_ptr *, ptr, 12308c2ecf20Sopenharmony_ci u32, btf_ptr_size, u64, flags) 12318c2ecf20Sopenharmony_ci{ 12328c2ecf20Sopenharmony_ci const struct btf *btf; 12338c2ecf20Sopenharmony_ci s32 btf_id; 12348c2ecf20Sopenharmony_ci int ret; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci ret = bpf_btf_printf_prepare(ptr, btf_ptr_size, flags, &btf, &btf_id); 12378c2ecf20Sopenharmony_ci if (ret) 12388c2ecf20Sopenharmony_ci return ret; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci return btf_type_snprintf_show(btf, btf_id, ptr->ptr, str, str_size, 12418c2ecf20Sopenharmony_ci flags); 12428c2ecf20Sopenharmony_ci} 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ciconst struct bpf_func_proto bpf_snprintf_btf_proto = { 12458c2ecf20Sopenharmony_ci .func = bpf_snprintf_btf, 12468c2ecf20Sopenharmony_ci .gpl_only = false, 12478c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 12488c2ecf20Sopenharmony_ci .arg1_type = ARG_PTR_TO_MEM, 12498c2ecf20Sopenharmony_ci .arg2_type = ARG_CONST_SIZE, 12508c2ecf20Sopenharmony_ci .arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY, 12518c2ecf20Sopenharmony_ci .arg4_type = ARG_CONST_SIZE, 12528c2ecf20Sopenharmony_ci .arg5_type = ARG_ANYTHING, 12538c2ecf20Sopenharmony_ci}; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ciconst struct bpf_func_proto * 12568c2ecf20Sopenharmony_cibpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) 12578c2ecf20Sopenharmony_ci{ 12588c2ecf20Sopenharmony_ci switch (func_id) { 12598c2ecf20Sopenharmony_ci case BPF_FUNC_map_lookup_elem: 12608c2ecf20Sopenharmony_ci return &bpf_map_lookup_elem_proto; 12618c2ecf20Sopenharmony_ci case BPF_FUNC_map_update_elem: 12628c2ecf20Sopenharmony_ci return &bpf_map_update_elem_proto; 12638c2ecf20Sopenharmony_ci case BPF_FUNC_map_delete_elem: 12648c2ecf20Sopenharmony_ci return &bpf_map_delete_elem_proto; 12658c2ecf20Sopenharmony_ci case BPF_FUNC_map_push_elem: 12668c2ecf20Sopenharmony_ci return &bpf_map_push_elem_proto; 12678c2ecf20Sopenharmony_ci case BPF_FUNC_map_pop_elem: 12688c2ecf20Sopenharmony_ci return &bpf_map_pop_elem_proto; 12698c2ecf20Sopenharmony_ci case BPF_FUNC_map_peek_elem: 12708c2ecf20Sopenharmony_ci return &bpf_map_peek_elem_proto; 12718c2ecf20Sopenharmony_ci case BPF_FUNC_ktime_get_ns: 12728c2ecf20Sopenharmony_ci return &bpf_ktime_get_ns_proto; 12738c2ecf20Sopenharmony_ci case BPF_FUNC_ktime_get_boot_ns: 12748c2ecf20Sopenharmony_ci return &bpf_ktime_get_boot_ns_proto; 12758c2ecf20Sopenharmony_ci case BPF_FUNC_tail_call: 12768c2ecf20Sopenharmony_ci return &bpf_tail_call_proto; 12778c2ecf20Sopenharmony_ci case BPF_FUNC_get_current_pid_tgid: 12788c2ecf20Sopenharmony_ci return &bpf_get_current_pid_tgid_proto; 12798c2ecf20Sopenharmony_ci case BPF_FUNC_get_current_task: 12808c2ecf20Sopenharmony_ci return &bpf_get_current_task_proto; 12818c2ecf20Sopenharmony_ci case BPF_FUNC_get_current_uid_gid: 12828c2ecf20Sopenharmony_ci return &bpf_get_current_uid_gid_proto; 12838c2ecf20Sopenharmony_ci case BPF_FUNC_get_current_comm: 12848c2ecf20Sopenharmony_ci return &bpf_get_current_comm_proto; 12858c2ecf20Sopenharmony_ci case BPF_FUNC_trace_printk: 12868c2ecf20Sopenharmony_ci return bpf_get_trace_printk_proto(); 12878c2ecf20Sopenharmony_ci case BPF_FUNC_get_smp_processor_id: 12888c2ecf20Sopenharmony_ci return &bpf_get_smp_processor_id_proto; 12898c2ecf20Sopenharmony_ci case BPF_FUNC_get_numa_node_id: 12908c2ecf20Sopenharmony_ci return &bpf_get_numa_node_id_proto; 12918c2ecf20Sopenharmony_ci case BPF_FUNC_perf_event_read: 12928c2ecf20Sopenharmony_ci return &bpf_perf_event_read_proto; 12938c2ecf20Sopenharmony_ci case BPF_FUNC_current_task_under_cgroup: 12948c2ecf20Sopenharmony_ci return &bpf_current_task_under_cgroup_proto; 12958c2ecf20Sopenharmony_ci case BPF_FUNC_get_prandom_u32: 12968c2ecf20Sopenharmony_ci return &bpf_get_prandom_u32_proto; 12978c2ecf20Sopenharmony_ci case BPF_FUNC_probe_write_user: 12988c2ecf20Sopenharmony_ci return security_locked_down(LOCKDOWN_BPF_WRITE_USER) < 0 ? 12998c2ecf20Sopenharmony_ci NULL : bpf_get_probe_write_proto(); 13008c2ecf20Sopenharmony_ci case BPF_FUNC_probe_read_user: 13018c2ecf20Sopenharmony_ci return &bpf_probe_read_user_proto; 13028c2ecf20Sopenharmony_ci case BPF_FUNC_probe_read_kernel: 13038c2ecf20Sopenharmony_ci return security_locked_down(LOCKDOWN_BPF_READ) < 0 ? 13048c2ecf20Sopenharmony_ci NULL : &bpf_probe_read_kernel_proto; 13058c2ecf20Sopenharmony_ci case BPF_FUNC_probe_read_user_str: 13068c2ecf20Sopenharmony_ci return &bpf_probe_read_user_str_proto; 13078c2ecf20Sopenharmony_ci case BPF_FUNC_probe_read_kernel_str: 13088c2ecf20Sopenharmony_ci return security_locked_down(LOCKDOWN_BPF_READ) < 0 ? 13098c2ecf20Sopenharmony_ci NULL : &bpf_probe_read_kernel_str_proto; 13108c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE 13118c2ecf20Sopenharmony_ci case BPF_FUNC_probe_read: 13128c2ecf20Sopenharmony_ci return security_locked_down(LOCKDOWN_BPF_READ) < 0 ? 13138c2ecf20Sopenharmony_ci NULL : &bpf_probe_read_compat_proto; 13148c2ecf20Sopenharmony_ci case BPF_FUNC_probe_read_str: 13158c2ecf20Sopenharmony_ci return security_locked_down(LOCKDOWN_BPF_READ) < 0 ? 13168c2ecf20Sopenharmony_ci NULL : &bpf_probe_read_compat_str_proto; 13178c2ecf20Sopenharmony_ci#endif 13188c2ecf20Sopenharmony_ci#ifdef CONFIG_CGROUPS 13198c2ecf20Sopenharmony_ci case BPF_FUNC_get_current_cgroup_id: 13208c2ecf20Sopenharmony_ci return &bpf_get_current_cgroup_id_proto; 13218c2ecf20Sopenharmony_ci#endif 13228c2ecf20Sopenharmony_ci case BPF_FUNC_send_signal: 13238c2ecf20Sopenharmony_ci return &bpf_send_signal_proto; 13248c2ecf20Sopenharmony_ci case BPF_FUNC_send_signal_thread: 13258c2ecf20Sopenharmony_ci return &bpf_send_signal_thread_proto; 13268c2ecf20Sopenharmony_ci case BPF_FUNC_perf_event_read_value: 13278c2ecf20Sopenharmony_ci return &bpf_perf_event_read_value_proto; 13288c2ecf20Sopenharmony_ci case BPF_FUNC_get_ns_current_pid_tgid: 13298c2ecf20Sopenharmony_ci return &bpf_get_ns_current_pid_tgid_proto; 13308c2ecf20Sopenharmony_ci case BPF_FUNC_ringbuf_output: 13318c2ecf20Sopenharmony_ci return &bpf_ringbuf_output_proto; 13328c2ecf20Sopenharmony_ci case BPF_FUNC_ringbuf_reserve: 13338c2ecf20Sopenharmony_ci return &bpf_ringbuf_reserve_proto; 13348c2ecf20Sopenharmony_ci case BPF_FUNC_ringbuf_submit: 13358c2ecf20Sopenharmony_ci return &bpf_ringbuf_submit_proto; 13368c2ecf20Sopenharmony_ci case BPF_FUNC_ringbuf_discard: 13378c2ecf20Sopenharmony_ci return &bpf_ringbuf_discard_proto; 13388c2ecf20Sopenharmony_ci case BPF_FUNC_ringbuf_query: 13398c2ecf20Sopenharmony_ci return &bpf_ringbuf_query_proto; 13408c2ecf20Sopenharmony_ci case BPF_FUNC_jiffies64: 13418c2ecf20Sopenharmony_ci return &bpf_jiffies64_proto; 13428c2ecf20Sopenharmony_ci case BPF_FUNC_get_task_stack: 13438c2ecf20Sopenharmony_ci return &bpf_get_task_stack_proto; 13448c2ecf20Sopenharmony_ci case BPF_FUNC_copy_from_user: 13458c2ecf20Sopenharmony_ci return prog->aux->sleepable ? &bpf_copy_from_user_proto : NULL; 13468c2ecf20Sopenharmony_ci case BPF_FUNC_snprintf_btf: 13478c2ecf20Sopenharmony_ci return &bpf_snprintf_btf_proto; 13488c2ecf20Sopenharmony_ci case BPF_FUNC_per_cpu_ptr: 13498c2ecf20Sopenharmony_ci return &bpf_per_cpu_ptr_proto; 13508c2ecf20Sopenharmony_ci case BPF_FUNC_this_cpu_ptr: 13518c2ecf20Sopenharmony_ci return &bpf_this_cpu_ptr_proto; 13528c2ecf20Sopenharmony_ci default: 13538c2ecf20Sopenharmony_ci return NULL; 13548c2ecf20Sopenharmony_ci } 13558c2ecf20Sopenharmony_ci} 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_cistatic const struct bpf_func_proto * 13588c2ecf20Sopenharmony_cikprobe_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) 13598c2ecf20Sopenharmony_ci{ 13608c2ecf20Sopenharmony_ci switch (func_id) { 13618c2ecf20Sopenharmony_ci case BPF_FUNC_perf_event_output: 13628c2ecf20Sopenharmony_ci return &bpf_perf_event_output_proto; 13638c2ecf20Sopenharmony_ci case BPF_FUNC_get_stackid: 13648c2ecf20Sopenharmony_ci return &bpf_get_stackid_proto; 13658c2ecf20Sopenharmony_ci case BPF_FUNC_get_stack: 13668c2ecf20Sopenharmony_ci return &bpf_get_stack_proto; 13678c2ecf20Sopenharmony_ci#ifdef CONFIG_BPF_KPROBE_OVERRIDE 13688c2ecf20Sopenharmony_ci case BPF_FUNC_override_return: 13698c2ecf20Sopenharmony_ci return &bpf_override_return_proto; 13708c2ecf20Sopenharmony_ci#endif 13718c2ecf20Sopenharmony_ci default: 13728c2ecf20Sopenharmony_ci return bpf_tracing_func_proto(func_id, prog); 13738c2ecf20Sopenharmony_ci } 13748c2ecf20Sopenharmony_ci} 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci/* bpf+kprobe programs can access fields of 'struct pt_regs' */ 13778c2ecf20Sopenharmony_cistatic bool kprobe_prog_is_valid_access(int off, int size, enum bpf_access_type type, 13788c2ecf20Sopenharmony_ci const struct bpf_prog *prog, 13798c2ecf20Sopenharmony_ci struct bpf_insn_access_aux *info) 13808c2ecf20Sopenharmony_ci{ 13818c2ecf20Sopenharmony_ci if (off < 0 || off >= sizeof(struct pt_regs)) 13828c2ecf20Sopenharmony_ci return false; 13838c2ecf20Sopenharmony_ci if (type != BPF_READ) 13848c2ecf20Sopenharmony_ci return false; 13858c2ecf20Sopenharmony_ci if (off % size != 0) 13868c2ecf20Sopenharmony_ci return false; 13878c2ecf20Sopenharmony_ci /* 13888c2ecf20Sopenharmony_ci * Assertion for 32 bit to make sure last 8 byte access 13898c2ecf20Sopenharmony_ci * (BPF_DW) to the last 4 byte member is disallowed. 13908c2ecf20Sopenharmony_ci */ 13918c2ecf20Sopenharmony_ci if (off + size > sizeof(struct pt_regs)) 13928c2ecf20Sopenharmony_ci return false; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci return true; 13958c2ecf20Sopenharmony_ci} 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ciconst struct bpf_verifier_ops kprobe_verifier_ops = { 13988c2ecf20Sopenharmony_ci .get_func_proto = kprobe_prog_func_proto, 13998c2ecf20Sopenharmony_ci .is_valid_access = kprobe_prog_is_valid_access, 14008c2ecf20Sopenharmony_ci}; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ciconst struct bpf_prog_ops kprobe_prog_ops = { 14038c2ecf20Sopenharmony_ci}; 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ciBPF_CALL_5(bpf_perf_event_output_tp, void *, tp_buff, struct bpf_map *, map, 14068c2ecf20Sopenharmony_ci u64, flags, void *, data, u64, size) 14078c2ecf20Sopenharmony_ci{ 14088c2ecf20Sopenharmony_ci struct pt_regs *regs = *(struct pt_regs **)tp_buff; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci /* 14118c2ecf20Sopenharmony_ci * r1 points to perf tracepoint buffer where first 8 bytes are hidden 14128c2ecf20Sopenharmony_ci * from bpf program and contain a pointer to 'struct pt_regs'. Fetch it 14138c2ecf20Sopenharmony_ci * from there and call the same bpf_perf_event_output() helper inline. 14148c2ecf20Sopenharmony_ci */ 14158c2ecf20Sopenharmony_ci return ____bpf_perf_event_output(regs, map, flags, data, size); 14168c2ecf20Sopenharmony_ci} 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_cistatic const struct bpf_func_proto bpf_perf_event_output_proto_tp = { 14198c2ecf20Sopenharmony_ci .func = bpf_perf_event_output_tp, 14208c2ecf20Sopenharmony_ci .gpl_only = true, 14218c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 14228c2ecf20Sopenharmony_ci .arg1_type = ARG_PTR_TO_CTX, 14238c2ecf20Sopenharmony_ci .arg2_type = ARG_CONST_MAP_PTR, 14248c2ecf20Sopenharmony_ci .arg3_type = ARG_ANYTHING, 14258c2ecf20Sopenharmony_ci .arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY, 14268c2ecf20Sopenharmony_ci .arg5_type = ARG_CONST_SIZE_OR_ZERO, 14278c2ecf20Sopenharmony_ci}; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ciBPF_CALL_3(bpf_get_stackid_tp, void *, tp_buff, struct bpf_map *, map, 14308c2ecf20Sopenharmony_ci u64, flags) 14318c2ecf20Sopenharmony_ci{ 14328c2ecf20Sopenharmony_ci struct pt_regs *regs = *(struct pt_regs **)tp_buff; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci /* 14358c2ecf20Sopenharmony_ci * Same comment as in bpf_perf_event_output_tp(), only that this time 14368c2ecf20Sopenharmony_ci * the other helper's function body cannot be inlined due to being 14378c2ecf20Sopenharmony_ci * external, thus we need to call raw helper function. 14388c2ecf20Sopenharmony_ci */ 14398c2ecf20Sopenharmony_ci return bpf_get_stackid((unsigned long) regs, (unsigned long) map, 14408c2ecf20Sopenharmony_ci flags, 0, 0); 14418c2ecf20Sopenharmony_ci} 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_cistatic const struct bpf_func_proto bpf_get_stackid_proto_tp = { 14448c2ecf20Sopenharmony_ci .func = bpf_get_stackid_tp, 14458c2ecf20Sopenharmony_ci .gpl_only = true, 14468c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 14478c2ecf20Sopenharmony_ci .arg1_type = ARG_PTR_TO_CTX, 14488c2ecf20Sopenharmony_ci .arg2_type = ARG_CONST_MAP_PTR, 14498c2ecf20Sopenharmony_ci .arg3_type = ARG_ANYTHING, 14508c2ecf20Sopenharmony_ci}; 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ciBPF_CALL_4(bpf_get_stack_tp, void *, tp_buff, void *, buf, u32, size, 14538c2ecf20Sopenharmony_ci u64, flags) 14548c2ecf20Sopenharmony_ci{ 14558c2ecf20Sopenharmony_ci struct pt_regs *regs = *(struct pt_regs **)tp_buff; 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci return bpf_get_stack((unsigned long) regs, (unsigned long) buf, 14588c2ecf20Sopenharmony_ci (unsigned long) size, flags, 0); 14598c2ecf20Sopenharmony_ci} 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_cistatic const struct bpf_func_proto bpf_get_stack_proto_tp = { 14628c2ecf20Sopenharmony_ci .func = bpf_get_stack_tp, 14638c2ecf20Sopenharmony_ci .gpl_only = true, 14648c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 14658c2ecf20Sopenharmony_ci .arg1_type = ARG_PTR_TO_CTX, 14668c2ecf20Sopenharmony_ci .arg2_type = ARG_PTR_TO_UNINIT_MEM, 14678c2ecf20Sopenharmony_ci .arg3_type = ARG_CONST_SIZE_OR_ZERO, 14688c2ecf20Sopenharmony_ci .arg4_type = ARG_ANYTHING, 14698c2ecf20Sopenharmony_ci}; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_cistatic const struct bpf_func_proto * 14728c2ecf20Sopenharmony_citp_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) 14738c2ecf20Sopenharmony_ci{ 14748c2ecf20Sopenharmony_ci switch (func_id) { 14758c2ecf20Sopenharmony_ci case BPF_FUNC_perf_event_output: 14768c2ecf20Sopenharmony_ci return &bpf_perf_event_output_proto_tp; 14778c2ecf20Sopenharmony_ci case BPF_FUNC_get_stackid: 14788c2ecf20Sopenharmony_ci return &bpf_get_stackid_proto_tp; 14798c2ecf20Sopenharmony_ci case BPF_FUNC_get_stack: 14808c2ecf20Sopenharmony_ci return &bpf_get_stack_proto_tp; 14818c2ecf20Sopenharmony_ci default: 14828c2ecf20Sopenharmony_ci return bpf_tracing_func_proto(func_id, prog); 14838c2ecf20Sopenharmony_ci } 14848c2ecf20Sopenharmony_ci} 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_cistatic bool tp_prog_is_valid_access(int off, int size, enum bpf_access_type type, 14878c2ecf20Sopenharmony_ci const struct bpf_prog *prog, 14888c2ecf20Sopenharmony_ci struct bpf_insn_access_aux *info) 14898c2ecf20Sopenharmony_ci{ 14908c2ecf20Sopenharmony_ci if (off < sizeof(void *) || off >= PERF_MAX_TRACE_SIZE) 14918c2ecf20Sopenharmony_ci return false; 14928c2ecf20Sopenharmony_ci if (type != BPF_READ) 14938c2ecf20Sopenharmony_ci return false; 14948c2ecf20Sopenharmony_ci if (off % size != 0) 14958c2ecf20Sopenharmony_ci return false; 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci BUILD_BUG_ON(PERF_MAX_TRACE_SIZE % sizeof(__u64)); 14988c2ecf20Sopenharmony_ci return true; 14998c2ecf20Sopenharmony_ci} 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ciconst struct bpf_verifier_ops tracepoint_verifier_ops = { 15028c2ecf20Sopenharmony_ci .get_func_proto = tp_prog_func_proto, 15038c2ecf20Sopenharmony_ci .is_valid_access = tp_prog_is_valid_access, 15048c2ecf20Sopenharmony_ci}; 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ciconst struct bpf_prog_ops tracepoint_prog_ops = { 15078c2ecf20Sopenharmony_ci}; 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ciBPF_CALL_3(bpf_perf_prog_read_value, struct bpf_perf_event_data_kern *, ctx, 15108c2ecf20Sopenharmony_ci struct bpf_perf_event_value *, buf, u32, size) 15118c2ecf20Sopenharmony_ci{ 15128c2ecf20Sopenharmony_ci int err = -EINVAL; 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci if (unlikely(size != sizeof(struct bpf_perf_event_value))) 15158c2ecf20Sopenharmony_ci goto clear; 15168c2ecf20Sopenharmony_ci err = perf_event_read_local(ctx->event, &buf->counter, &buf->enabled, 15178c2ecf20Sopenharmony_ci &buf->running); 15188c2ecf20Sopenharmony_ci if (unlikely(err)) 15198c2ecf20Sopenharmony_ci goto clear; 15208c2ecf20Sopenharmony_ci return 0; 15218c2ecf20Sopenharmony_ciclear: 15228c2ecf20Sopenharmony_ci memset(buf, 0, size); 15238c2ecf20Sopenharmony_ci return err; 15248c2ecf20Sopenharmony_ci} 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_cistatic const struct bpf_func_proto bpf_perf_prog_read_value_proto = { 15278c2ecf20Sopenharmony_ci .func = bpf_perf_prog_read_value, 15288c2ecf20Sopenharmony_ci .gpl_only = true, 15298c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 15308c2ecf20Sopenharmony_ci .arg1_type = ARG_PTR_TO_CTX, 15318c2ecf20Sopenharmony_ci .arg2_type = ARG_PTR_TO_UNINIT_MEM, 15328c2ecf20Sopenharmony_ci .arg3_type = ARG_CONST_SIZE, 15338c2ecf20Sopenharmony_ci}; 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ciBPF_CALL_4(bpf_read_branch_records, struct bpf_perf_event_data_kern *, ctx, 15368c2ecf20Sopenharmony_ci void *, buf, u32, size, u64, flags) 15378c2ecf20Sopenharmony_ci{ 15388c2ecf20Sopenharmony_ci static const u32 br_entry_size = sizeof(struct perf_branch_entry); 15398c2ecf20Sopenharmony_ci struct perf_branch_stack *br_stack = ctx->data->br_stack; 15408c2ecf20Sopenharmony_ci u32 to_copy; 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci if (unlikely(flags & ~BPF_F_GET_BRANCH_RECORDS_SIZE)) 15438c2ecf20Sopenharmony_ci return -EINVAL; 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci if (unlikely(!br_stack)) 15468c2ecf20Sopenharmony_ci return -ENOENT; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci if (flags & BPF_F_GET_BRANCH_RECORDS_SIZE) 15498c2ecf20Sopenharmony_ci return br_stack->nr * br_entry_size; 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci if (!buf || (size % br_entry_size != 0)) 15528c2ecf20Sopenharmony_ci return -EINVAL; 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci to_copy = min_t(u32, br_stack->nr * br_entry_size, size); 15558c2ecf20Sopenharmony_ci memcpy(buf, br_stack->entries, to_copy); 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci return to_copy; 15588c2ecf20Sopenharmony_ci} 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_cistatic const struct bpf_func_proto bpf_read_branch_records_proto = { 15618c2ecf20Sopenharmony_ci .func = bpf_read_branch_records, 15628c2ecf20Sopenharmony_ci .gpl_only = true, 15638c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 15648c2ecf20Sopenharmony_ci .arg1_type = ARG_PTR_TO_CTX, 15658c2ecf20Sopenharmony_ci .arg2_type = ARG_PTR_TO_MEM_OR_NULL, 15668c2ecf20Sopenharmony_ci .arg3_type = ARG_CONST_SIZE_OR_ZERO, 15678c2ecf20Sopenharmony_ci .arg4_type = ARG_ANYTHING, 15688c2ecf20Sopenharmony_ci}; 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_cistatic const struct bpf_func_proto * 15718c2ecf20Sopenharmony_cipe_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) 15728c2ecf20Sopenharmony_ci{ 15738c2ecf20Sopenharmony_ci switch (func_id) { 15748c2ecf20Sopenharmony_ci case BPF_FUNC_perf_event_output: 15758c2ecf20Sopenharmony_ci return &bpf_perf_event_output_proto_tp; 15768c2ecf20Sopenharmony_ci case BPF_FUNC_get_stackid: 15778c2ecf20Sopenharmony_ci return &bpf_get_stackid_proto_pe; 15788c2ecf20Sopenharmony_ci case BPF_FUNC_get_stack: 15798c2ecf20Sopenharmony_ci return &bpf_get_stack_proto_pe; 15808c2ecf20Sopenharmony_ci case BPF_FUNC_perf_prog_read_value: 15818c2ecf20Sopenharmony_ci return &bpf_perf_prog_read_value_proto; 15828c2ecf20Sopenharmony_ci case BPF_FUNC_read_branch_records: 15838c2ecf20Sopenharmony_ci return &bpf_read_branch_records_proto; 15848c2ecf20Sopenharmony_ci default: 15858c2ecf20Sopenharmony_ci return bpf_tracing_func_proto(func_id, prog); 15868c2ecf20Sopenharmony_ci } 15878c2ecf20Sopenharmony_ci} 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci/* 15908c2ecf20Sopenharmony_ci * bpf_raw_tp_regs are separate from bpf_pt_regs used from skb/xdp 15918c2ecf20Sopenharmony_ci * to avoid potential recursive reuse issue when/if tracepoints are added 15928c2ecf20Sopenharmony_ci * inside bpf_*_event_output, bpf_get_stackid and/or bpf_get_stack. 15938c2ecf20Sopenharmony_ci * 15948c2ecf20Sopenharmony_ci * Since raw tracepoints run despite bpf_prog_active, support concurrent usage 15958c2ecf20Sopenharmony_ci * in normal, irq, and nmi context. 15968c2ecf20Sopenharmony_ci */ 15978c2ecf20Sopenharmony_cistruct bpf_raw_tp_regs { 15988c2ecf20Sopenharmony_ci struct pt_regs regs[3]; 15998c2ecf20Sopenharmony_ci}; 16008c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct bpf_raw_tp_regs, bpf_raw_tp_regs); 16018c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(int, bpf_raw_tp_nest_level); 16028c2ecf20Sopenharmony_cistatic struct pt_regs *get_bpf_raw_tp_regs(void) 16038c2ecf20Sopenharmony_ci{ 16048c2ecf20Sopenharmony_ci struct bpf_raw_tp_regs *tp_regs = this_cpu_ptr(&bpf_raw_tp_regs); 16058c2ecf20Sopenharmony_ci int nest_level = this_cpu_inc_return(bpf_raw_tp_nest_level); 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(nest_level > ARRAY_SIZE(tp_regs->regs))) { 16088c2ecf20Sopenharmony_ci this_cpu_dec(bpf_raw_tp_nest_level); 16098c2ecf20Sopenharmony_ci return ERR_PTR(-EBUSY); 16108c2ecf20Sopenharmony_ci } 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci return &tp_regs->regs[nest_level - 1]; 16138c2ecf20Sopenharmony_ci} 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_cistatic void put_bpf_raw_tp_regs(void) 16168c2ecf20Sopenharmony_ci{ 16178c2ecf20Sopenharmony_ci this_cpu_dec(bpf_raw_tp_nest_level); 16188c2ecf20Sopenharmony_ci} 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ciBPF_CALL_5(bpf_perf_event_output_raw_tp, struct bpf_raw_tracepoint_args *, args, 16218c2ecf20Sopenharmony_ci struct bpf_map *, map, u64, flags, void *, data, u64, size) 16228c2ecf20Sopenharmony_ci{ 16238c2ecf20Sopenharmony_ci struct pt_regs *regs = get_bpf_raw_tp_regs(); 16248c2ecf20Sopenharmony_ci int ret; 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci if (IS_ERR(regs)) 16278c2ecf20Sopenharmony_ci return PTR_ERR(regs); 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci perf_fetch_caller_regs(regs); 16308c2ecf20Sopenharmony_ci ret = ____bpf_perf_event_output(regs, map, flags, data, size); 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci put_bpf_raw_tp_regs(); 16338c2ecf20Sopenharmony_ci return ret; 16348c2ecf20Sopenharmony_ci} 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_cistatic const struct bpf_func_proto bpf_perf_event_output_proto_raw_tp = { 16378c2ecf20Sopenharmony_ci .func = bpf_perf_event_output_raw_tp, 16388c2ecf20Sopenharmony_ci .gpl_only = true, 16398c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 16408c2ecf20Sopenharmony_ci .arg1_type = ARG_PTR_TO_CTX, 16418c2ecf20Sopenharmony_ci .arg2_type = ARG_CONST_MAP_PTR, 16428c2ecf20Sopenharmony_ci .arg3_type = ARG_ANYTHING, 16438c2ecf20Sopenharmony_ci .arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY, 16448c2ecf20Sopenharmony_ci .arg5_type = ARG_CONST_SIZE_OR_ZERO, 16458c2ecf20Sopenharmony_ci}; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ciextern const struct bpf_func_proto bpf_skb_output_proto; 16488c2ecf20Sopenharmony_ciextern const struct bpf_func_proto bpf_xdp_output_proto; 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ciBPF_CALL_3(bpf_get_stackid_raw_tp, struct bpf_raw_tracepoint_args *, args, 16518c2ecf20Sopenharmony_ci struct bpf_map *, map, u64, flags) 16528c2ecf20Sopenharmony_ci{ 16538c2ecf20Sopenharmony_ci struct pt_regs *regs = get_bpf_raw_tp_regs(); 16548c2ecf20Sopenharmony_ci int ret; 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci if (IS_ERR(regs)) 16578c2ecf20Sopenharmony_ci return PTR_ERR(regs); 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci perf_fetch_caller_regs(regs); 16608c2ecf20Sopenharmony_ci /* similar to bpf_perf_event_output_tp, but pt_regs fetched differently */ 16618c2ecf20Sopenharmony_ci ret = bpf_get_stackid((unsigned long) regs, (unsigned long) map, 16628c2ecf20Sopenharmony_ci flags, 0, 0); 16638c2ecf20Sopenharmony_ci put_bpf_raw_tp_regs(); 16648c2ecf20Sopenharmony_ci return ret; 16658c2ecf20Sopenharmony_ci} 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_cistatic const struct bpf_func_proto bpf_get_stackid_proto_raw_tp = { 16688c2ecf20Sopenharmony_ci .func = bpf_get_stackid_raw_tp, 16698c2ecf20Sopenharmony_ci .gpl_only = true, 16708c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 16718c2ecf20Sopenharmony_ci .arg1_type = ARG_PTR_TO_CTX, 16728c2ecf20Sopenharmony_ci .arg2_type = ARG_CONST_MAP_PTR, 16738c2ecf20Sopenharmony_ci .arg3_type = ARG_ANYTHING, 16748c2ecf20Sopenharmony_ci}; 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ciBPF_CALL_4(bpf_get_stack_raw_tp, struct bpf_raw_tracepoint_args *, args, 16778c2ecf20Sopenharmony_ci void *, buf, u32, size, u64, flags) 16788c2ecf20Sopenharmony_ci{ 16798c2ecf20Sopenharmony_ci struct pt_regs *regs = get_bpf_raw_tp_regs(); 16808c2ecf20Sopenharmony_ci int ret; 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci if (IS_ERR(regs)) 16838c2ecf20Sopenharmony_ci return PTR_ERR(regs); 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci perf_fetch_caller_regs(regs); 16868c2ecf20Sopenharmony_ci ret = bpf_get_stack((unsigned long) regs, (unsigned long) buf, 16878c2ecf20Sopenharmony_ci (unsigned long) size, flags, 0); 16888c2ecf20Sopenharmony_ci put_bpf_raw_tp_regs(); 16898c2ecf20Sopenharmony_ci return ret; 16908c2ecf20Sopenharmony_ci} 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_cistatic const struct bpf_func_proto bpf_get_stack_proto_raw_tp = { 16938c2ecf20Sopenharmony_ci .func = bpf_get_stack_raw_tp, 16948c2ecf20Sopenharmony_ci .gpl_only = true, 16958c2ecf20Sopenharmony_ci .ret_type = RET_INTEGER, 16968c2ecf20Sopenharmony_ci .arg1_type = ARG_PTR_TO_CTX, 16978c2ecf20Sopenharmony_ci .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 16988c2ecf20Sopenharmony_ci .arg3_type = ARG_CONST_SIZE_OR_ZERO, 16998c2ecf20Sopenharmony_ci .arg4_type = ARG_ANYTHING, 17008c2ecf20Sopenharmony_ci}; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_cistatic const struct bpf_func_proto * 17038c2ecf20Sopenharmony_ciraw_tp_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) 17048c2ecf20Sopenharmony_ci{ 17058c2ecf20Sopenharmony_ci switch (func_id) { 17068c2ecf20Sopenharmony_ci case BPF_FUNC_perf_event_output: 17078c2ecf20Sopenharmony_ci return &bpf_perf_event_output_proto_raw_tp; 17088c2ecf20Sopenharmony_ci case BPF_FUNC_get_stackid: 17098c2ecf20Sopenharmony_ci return &bpf_get_stackid_proto_raw_tp; 17108c2ecf20Sopenharmony_ci case BPF_FUNC_get_stack: 17118c2ecf20Sopenharmony_ci return &bpf_get_stack_proto_raw_tp; 17128c2ecf20Sopenharmony_ci default: 17138c2ecf20Sopenharmony_ci return bpf_tracing_func_proto(func_id, prog); 17148c2ecf20Sopenharmony_ci } 17158c2ecf20Sopenharmony_ci} 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ciconst struct bpf_func_proto * 17188c2ecf20Sopenharmony_citracing_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) 17198c2ecf20Sopenharmony_ci{ 17208c2ecf20Sopenharmony_ci switch (func_id) { 17218c2ecf20Sopenharmony_ci#ifdef CONFIG_NET 17228c2ecf20Sopenharmony_ci case BPF_FUNC_skb_output: 17238c2ecf20Sopenharmony_ci return &bpf_skb_output_proto; 17248c2ecf20Sopenharmony_ci case BPF_FUNC_xdp_output: 17258c2ecf20Sopenharmony_ci return &bpf_xdp_output_proto; 17268c2ecf20Sopenharmony_ci case BPF_FUNC_skc_to_tcp6_sock: 17278c2ecf20Sopenharmony_ci return &bpf_skc_to_tcp6_sock_proto; 17288c2ecf20Sopenharmony_ci case BPF_FUNC_skc_to_tcp_sock: 17298c2ecf20Sopenharmony_ci return &bpf_skc_to_tcp_sock_proto; 17308c2ecf20Sopenharmony_ci case BPF_FUNC_skc_to_tcp_timewait_sock: 17318c2ecf20Sopenharmony_ci return &bpf_skc_to_tcp_timewait_sock_proto; 17328c2ecf20Sopenharmony_ci case BPF_FUNC_skc_to_tcp_request_sock: 17338c2ecf20Sopenharmony_ci return &bpf_skc_to_tcp_request_sock_proto; 17348c2ecf20Sopenharmony_ci case BPF_FUNC_skc_to_udp6_sock: 17358c2ecf20Sopenharmony_ci return &bpf_skc_to_udp6_sock_proto; 17368c2ecf20Sopenharmony_ci#endif 17378c2ecf20Sopenharmony_ci case BPF_FUNC_seq_printf: 17388c2ecf20Sopenharmony_ci return prog->expected_attach_type == BPF_TRACE_ITER ? 17398c2ecf20Sopenharmony_ci &bpf_seq_printf_proto : 17408c2ecf20Sopenharmony_ci NULL; 17418c2ecf20Sopenharmony_ci case BPF_FUNC_seq_write: 17428c2ecf20Sopenharmony_ci return prog->expected_attach_type == BPF_TRACE_ITER ? 17438c2ecf20Sopenharmony_ci &bpf_seq_write_proto : 17448c2ecf20Sopenharmony_ci NULL; 17458c2ecf20Sopenharmony_ci case BPF_FUNC_seq_printf_btf: 17468c2ecf20Sopenharmony_ci return prog->expected_attach_type == BPF_TRACE_ITER ? 17478c2ecf20Sopenharmony_ci &bpf_seq_printf_btf_proto : 17488c2ecf20Sopenharmony_ci NULL; 17498c2ecf20Sopenharmony_ci case BPF_FUNC_d_path: 17508c2ecf20Sopenharmony_ci return &bpf_d_path_proto; 17518c2ecf20Sopenharmony_ci default: 17528c2ecf20Sopenharmony_ci return raw_tp_prog_func_proto(func_id, prog); 17538c2ecf20Sopenharmony_ci } 17548c2ecf20Sopenharmony_ci} 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_cistatic bool raw_tp_prog_is_valid_access(int off, int size, 17578c2ecf20Sopenharmony_ci enum bpf_access_type type, 17588c2ecf20Sopenharmony_ci const struct bpf_prog *prog, 17598c2ecf20Sopenharmony_ci struct bpf_insn_access_aux *info) 17608c2ecf20Sopenharmony_ci{ 17618c2ecf20Sopenharmony_ci if (off < 0 || off >= sizeof(__u64) * MAX_BPF_FUNC_ARGS) 17628c2ecf20Sopenharmony_ci return false; 17638c2ecf20Sopenharmony_ci if (type != BPF_READ) 17648c2ecf20Sopenharmony_ci return false; 17658c2ecf20Sopenharmony_ci if (off % size != 0) 17668c2ecf20Sopenharmony_ci return false; 17678c2ecf20Sopenharmony_ci return true; 17688c2ecf20Sopenharmony_ci} 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_cistatic bool tracing_prog_is_valid_access(int off, int size, 17718c2ecf20Sopenharmony_ci enum bpf_access_type type, 17728c2ecf20Sopenharmony_ci const struct bpf_prog *prog, 17738c2ecf20Sopenharmony_ci struct bpf_insn_access_aux *info) 17748c2ecf20Sopenharmony_ci{ 17758c2ecf20Sopenharmony_ci if (off < 0 || off >= sizeof(__u64) * MAX_BPF_FUNC_ARGS) 17768c2ecf20Sopenharmony_ci return false; 17778c2ecf20Sopenharmony_ci if (type != BPF_READ) 17788c2ecf20Sopenharmony_ci return false; 17798c2ecf20Sopenharmony_ci if (off % size != 0) 17808c2ecf20Sopenharmony_ci return false; 17818c2ecf20Sopenharmony_ci return btf_ctx_access(off, size, type, prog, info); 17828c2ecf20Sopenharmony_ci} 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ciint __weak bpf_prog_test_run_tracing(struct bpf_prog *prog, 17858c2ecf20Sopenharmony_ci const union bpf_attr *kattr, 17868c2ecf20Sopenharmony_ci union bpf_attr __user *uattr) 17878c2ecf20Sopenharmony_ci{ 17888c2ecf20Sopenharmony_ci return -ENOTSUPP; 17898c2ecf20Sopenharmony_ci} 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ciconst struct bpf_verifier_ops raw_tracepoint_verifier_ops = { 17928c2ecf20Sopenharmony_ci .get_func_proto = raw_tp_prog_func_proto, 17938c2ecf20Sopenharmony_ci .is_valid_access = raw_tp_prog_is_valid_access, 17948c2ecf20Sopenharmony_ci}; 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ciconst struct bpf_prog_ops raw_tracepoint_prog_ops = { 17978c2ecf20Sopenharmony_ci#ifdef CONFIG_NET 17988c2ecf20Sopenharmony_ci .test_run = bpf_prog_test_run_raw_tp, 17998c2ecf20Sopenharmony_ci#endif 18008c2ecf20Sopenharmony_ci}; 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ciconst struct bpf_verifier_ops tracing_verifier_ops = { 18038c2ecf20Sopenharmony_ci .get_func_proto = tracing_prog_func_proto, 18048c2ecf20Sopenharmony_ci .is_valid_access = tracing_prog_is_valid_access, 18058c2ecf20Sopenharmony_ci}; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ciconst struct bpf_prog_ops tracing_prog_ops = { 18088c2ecf20Sopenharmony_ci .test_run = bpf_prog_test_run_tracing, 18098c2ecf20Sopenharmony_ci}; 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_cistatic bool raw_tp_writable_prog_is_valid_access(int off, int size, 18128c2ecf20Sopenharmony_ci enum bpf_access_type type, 18138c2ecf20Sopenharmony_ci const struct bpf_prog *prog, 18148c2ecf20Sopenharmony_ci struct bpf_insn_access_aux *info) 18158c2ecf20Sopenharmony_ci{ 18168c2ecf20Sopenharmony_ci if (off == 0) { 18178c2ecf20Sopenharmony_ci if (size != sizeof(u64) || type != BPF_READ) 18188c2ecf20Sopenharmony_ci return false; 18198c2ecf20Sopenharmony_ci info->reg_type = PTR_TO_TP_BUFFER; 18208c2ecf20Sopenharmony_ci } 18218c2ecf20Sopenharmony_ci return raw_tp_prog_is_valid_access(off, size, type, prog, info); 18228c2ecf20Sopenharmony_ci} 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ciconst struct bpf_verifier_ops raw_tracepoint_writable_verifier_ops = { 18258c2ecf20Sopenharmony_ci .get_func_proto = raw_tp_prog_func_proto, 18268c2ecf20Sopenharmony_ci .is_valid_access = raw_tp_writable_prog_is_valid_access, 18278c2ecf20Sopenharmony_ci}; 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ciconst struct bpf_prog_ops raw_tracepoint_writable_prog_ops = { 18308c2ecf20Sopenharmony_ci}; 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_cistatic bool pe_prog_is_valid_access(int off, int size, enum bpf_access_type type, 18338c2ecf20Sopenharmony_ci const struct bpf_prog *prog, 18348c2ecf20Sopenharmony_ci struct bpf_insn_access_aux *info) 18358c2ecf20Sopenharmony_ci{ 18368c2ecf20Sopenharmony_ci const int size_u64 = sizeof(u64); 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci if (off < 0 || off >= sizeof(struct bpf_perf_event_data)) 18398c2ecf20Sopenharmony_ci return false; 18408c2ecf20Sopenharmony_ci if (type != BPF_READ) 18418c2ecf20Sopenharmony_ci return false; 18428c2ecf20Sopenharmony_ci if (off % size != 0) { 18438c2ecf20Sopenharmony_ci if (sizeof(unsigned long) != 4) 18448c2ecf20Sopenharmony_ci return false; 18458c2ecf20Sopenharmony_ci if (size != 8) 18468c2ecf20Sopenharmony_ci return false; 18478c2ecf20Sopenharmony_ci if (off % size != 4) 18488c2ecf20Sopenharmony_ci return false; 18498c2ecf20Sopenharmony_ci } 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci switch (off) { 18528c2ecf20Sopenharmony_ci case bpf_ctx_range(struct bpf_perf_event_data, sample_period): 18538c2ecf20Sopenharmony_ci bpf_ctx_record_field_size(info, size_u64); 18548c2ecf20Sopenharmony_ci if (!bpf_ctx_narrow_access_ok(off, size, size_u64)) 18558c2ecf20Sopenharmony_ci return false; 18568c2ecf20Sopenharmony_ci break; 18578c2ecf20Sopenharmony_ci case bpf_ctx_range(struct bpf_perf_event_data, addr): 18588c2ecf20Sopenharmony_ci bpf_ctx_record_field_size(info, size_u64); 18598c2ecf20Sopenharmony_ci if (!bpf_ctx_narrow_access_ok(off, size, size_u64)) 18608c2ecf20Sopenharmony_ci return false; 18618c2ecf20Sopenharmony_ci break; 18628c2ecf20Sopenharmony_ci default: 18638c2ecf20Sopenharmony_ci if (size != sizeof(long)) 18648c2ecf20Sopenharmony_ci return false; 18658c2ecf20Sopenharmony_ci } 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci return true; 18688c2ecf20Sopenharmony_ci} 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_cistatic u32 pe_prog_convert_ctx_access(enum bpf_access_type type, 18718c2ecf20Sopenharmony_ci const struct bpf_insn *si, 18728c2ecf20Sopenharmony_ci struct bpf_insn *insn_buf, 18738c2ecf20Sopenharmony_ci struct bpf_prog *prog, u32 *target_size) 18748c2ecf20Sopenharmony_ci{ 18758c2ecf20Sopenharmony_ci struct bpf_insn *insn = insn_buf; 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci switch (si->off) { 18788c2ecf20Sopenharmony_ci case offsetof(struct bpf_perf_event_data, sample_period): 18798c2ecf20Sopenharmony_ci *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct bpf_perf_event_data_kern, 18808c2ecf20Sopenharmony_ci data), si->dst_reg, si->src_reg, 18818c2ecf20Sopenharmony_ci offsetof(struct bpf_perf_event_data_kern, data)); 18828c2ecf20Sopenharmony_ci *insn++ = BPF_LDX_MEM(BPF_DW, si->dst_reg, si->dst_reg, 18838c2ecf20Sopenharmony_ci bpf_target_off(struct perf_sample_data, period, 8, 18848c2ecf20Sopenharmony_ci target_size)); 18858c2ecf20Sopenharmony_ci break; 18868c2ecf20Sopenharmony_ci case offsetof(struct bpf_perf_event_data, addr): 18878c2ecf20Sopenharmony_ci *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct bpf_perf_event_data_kern, 18888c2ecf20Sopenharmony_ci data), si->dst_reg, si->src_reg, 18898c2ecf20Sopenharmony_ci offsetof(struct bpf_perf_event_data_kern, data)); 18908c2ecf20Sopenharmony_ci *insn++ = BPF_LDX_MEM(BPF_DW, si->dst_reg, si->dst_reg, 18918c2ecf20Sopenharmony_ci bpf_target_off(struct perf_sample_data, addr, 8, 18928c2ecf20Sopenharmony_ci target_size)); 18938c2ecf20Sopenharmony_ci break; 18948c2ecf20Sopenharmony_ci default: 18958c2ecf20Sopenharmony_ci *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct bpf_perf_event_data_kern, 18968c2ecf20Sopenharmony_ci regs), si->dst_reg, si->src_reg, 18978c2ecf20Sopenharmony_ci offsetof(struct bpf_perf_event_data_kern, regs)); 18988c2ecf20Sopenharmony_ci *insn++ = BPF_LDX_MEM(BPF_SIZEOF(long), si->dst_reg, si->dst_reg, 18998c2ecf20Sopenharmony_ci si->off); 19008c2ecf20Sopenharmony_ci break; 19018c2ecf20Sopenharmony_ci } 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci return insn - insn_buf; 19048c2ecf20Sopenharmony_ci} 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ciconst struct bpf_verifier_ops perf_event_verifier_ops = { 19078c2ecf20Sopenharmony_ci .get_func_proto = pe_prog_func_proto, 19088c2ecf20Sopenharmony_ci .is_valid_access = pe_prog_is_valid_access, 19098c2ecf20Sopenharmony_ci .convert_ctx_access = pe_prog_convert_ctx_access, 19108c2ecf20Sopenharmony_ci}; 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ciconst struct bpf_prog_ops perf_event_prog_ops = { 19138c2ecf20Sopenharmony_ci}; 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(bpf_event_mutex); 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci#define BPF_TRACE_MAX_PROGS 64 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ciint perf_event_attach_bpf_prog(struct perf_event *event, 19208c2ecf20Sopenharmony_ci struct bpf_prog *prog) 19218c2ecf20Sopenharmony_ci{ 19228c2ecf20Sopenharmony_ci struct bpf_prog_array *old_array; 19238c2ecf20Sopenharmony_ci struct bpf_prog_array *new_array; 19248c2ecf20Sopenharmony_ci int ret = -EEXIST; 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci /* 19278c2ecf20Sopenharmony_ci * Kprobe override only works if they are on the function entry, 19288c2ecf20Sopenharmony_ci * and only if they are on the opt-in list. 19298c2ecf20Sopenharmony_ci */ 19308c2ecf20Sopenharmony_ci if (prog->kprobe_override && 19318c2ecf20Sopenharmony_ci (!trace_kprobe_on_func_entry(event->tp_event) || 19328c2ecf20Sopenharmony_ci !trace_kprobe_error_injectable(event->tp_event))) 19338c2ecf20Sopenharmony_ci return -EINVAL; 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci mutex_lock(&bpf_event_mutex); 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci if (event->prog) 19388c2ecf20Sopenharmony_ci goto unlock; 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci old_array = bpf_event_rcu_dereference(event->tp_event->prog_array); 19418c2ecf20Sopenharmony_ci if (old_array && 19428c2ecf20Sopenharmony_ci bpf_prog_array_length(old_array) >= BPF_TRACE_MAX_PROGS) { 19438c2ecf20Sopenharmony_ci ret = -E2BIG; 19448c2ecf20Sopenharmony_ci goto unlock; 19458c2ecf20Sopenharmony_ci } 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci ret = bpf_prog_array_copy(old_array, NULL, prog, &new_array); 19488c2ecf20Sopenharmony_ci if (ret < 0) 19498c2ecf20Sopenharmony_ci goto unlock; 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci /* set the new array to event->tp_event and set event->prog */ 19528c2ecf20Sopenharmony_ci event->prog = prog; 19538c2ecf20Sopenharmony_ci rcu_assign_pointer(event->tp_event->prog_array, new_array); 19548c2ecf20Sopenharmony_ci bpf_prog_array_free(old_array); 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_ciunlock: 19578c2ecf20Sopenharmony_ci mutex_unlock(&bpf_event_mutex); 19588c2ecf20Sopenharmony_ci return ret; 19598c2ecf20Sopenharmony_ci} 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_civoid perf_event_detach_bpf_prog(struct perf_event *event) 19628c2ecf20Sopenharmony_ci{ 19638c2ecf20Sopenharmony_ci struct bpf_prog_array *old_array; 19648c2ecf20Sopenharmony_ci struct bpf_prog_array *new_array; 19658c2ecf20Sopenharmony_ci int ret; 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci mutex_lock(&bpf_event_mutex); 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci if (!event->prog) 19708c2ecf20Sopenharmony_ci goto unlock; 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci old_array = bpf_event_rcu_dereference(event->tp_event->prog_array); 19738c2ecf20Sopenharmony_ci ret = bpf_prog_array_copy(old_array, event->prog, NULL, &new_array); 19748c2ecf20Sopenharmony_ci if (ret == -ENOENT) 19758c2ecf20Sopenharmony_ci goto unlock; 19768c2ecf20Sopenharmony_ci if (ret < 0) { 19778c2ecf20Sopenharmony_ci bpf_prog_array_delete_safe(old_array, event->prog); 19788c2ecf20Sopenharmony_ci } else { 19798c2ecf20Sopenharmony_ci rcu_assign_pointer(event->tp_event->prog_array, new_array); 19808c2ecf20Sopenharmony_ci bpf_prog_array_free(old_array); 19818c2ecf20Sopenharmony_ci } 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci bpf_prog_put(event->prog); 19848c2ecf20Sopenharmony_ci event->prog = NULL; 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ciunlock: 19878c2ecf20Sopenharmony_ci mutex_unlock(&bpf_event_mutex); 19888c2ecf20Sopenharmony_ci} 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ciint perf_event_query_prog_array(struct perf_event *event, void __user *info) 19918c2ecf20Sopenharmony_ci{ 19928c2ecf20Sopenharmony_ci struct perf_event_query_bpf __user *uquery = info; 19938c2ecf20Sopenharmony_ci struct perf_event_query_bpf query = {}; 19948c2ecf20Sopenharmony_ci struct bpf_prog_array *progs; 19958c2ecf20Sopenharmony_ci u32 *ids, prog_cnt, ids_len; 19968c2ecf20Sopenharmony_ci int ret; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci if (!perfmon_capable()) 19998c2ecf20Sopenharmony_ci return -EPERM; 20008c2ecf20Sopenharmony_ci if (event->attr.type != PERF_TYPE_TRACEPOINT) 20018c2ecf20Sopenharmony_ci return -EINVAL; 20028c2ecf20Sopenharmony_ci if (copy_from_user(&query, uquery, sizeof(query))) 20038c2ecf20Sopenharmony_ci return -EFAULT; 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci ids_len = query.ids_len; 20068c2ecf20Sopenharmony_ci if (ids_len > BPF_TRACE_MAX_PROGS) 20078c2ecf20Sopenharmony_ci return -E2BIG; 20088c2ecf20Sopenharmony_ci ids = kcalloc(ids_len, sizeof(u32), GFP_USER | __GFP_NOWARN); 20098c2ecf20Sopenharmony_ci if (!ids) 20108c2ecf20Sopenharmony_ci return -ENOMEM; 20118c2ecf20Sopenharmony_ci /* 20128c2ecf20Sopenharmony_ci * The above kcalloc returns ZERO_SIZE_PTR when ids_len = 0, which 20138c2ecf20Sopenharmony_ci * is required when user only wants to check for uquery->prog_cnt. 20148c2ecf20Sopenharmony_ci * There is no need to check for it since the case is handled 20158c2ecf20Sopenharmony_ci * gracefully in bpf_prog_array_copy_info. 20168c2ecf20Sopenharmony_ci */ 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci mutex_lock(&bpf_event_mutex); 20198c2ecf20Sopenharmony_ci progs = bpf_event_rcu_dereference(event->tp_event->prog_array); 20208c2ecf20Sopenharmony_ci ret = bpf_prog_array_copy_info(progs, ids, ids_len, &prog_cnt); 20218c2ecf20Sopenharmony_ci mutex_unlock(&bpf_event_mutex); 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_ci if (copy_to_user(&uquery->prog_cnt, &prog_cnt, sizeof(prog_cnt)) || 20248c2ecf20Sopenharmony_ci copy_to_user(uquery->ids, ids, ids_len * sizeof(u32))) 20258c2ecf20Sopenharmony_ci ret = -EFAULT; 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci kfree(ids); 20288c2ecf20Sopenharmony_ci return ret; 20298c2ecf20Sopenharmony_ci} 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ciextern struct bpf_raw_event_map __start__bpf_raw_tp[]; 20328c2ecf20Sopenharmony_ciextern struct bpf_raw_event_map __stop__bpf_raw_tp[]; 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_cistruct bpf_raw_event_map *bpf_get_raw_tracepoint(const char *name) 20358c2ecf20Sopenharmony_ci{ 20368c2ecf20Sopenharmony_ci struct bpf_raw_event_map *btp = __start__bpf_raw_tp; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci for (; btp < __stop__bpf_raw_tp; btp++) { 20398c2ecf20Sopenharmony_ci if (!strcmp(btp->tp->name, name)) 20408c2ecf20Sopenharmony_ci return btp; 20418c2ecf20Sopenharmony_ci } 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci return bpf_get_raw_tracepoint_module(name); 20448c2ecf20Sopenharmony_ci} 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_civoid bpf_put_raw_tracepoint(struct bpf_raw_event_map *btp) 20478c2ecf20Sopenharmony_ci{ 20488c2ecf20Sopenharmony_ci struct module *mod; 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci preempt_disable(); 20518c2ecf20Sopenharmony_ci mod = __module_address((unsigned long)btp); 20528c2ecf20Sopenharmony_ci module_put(mod); 20538c2ecf20Sopenharmony_ci preempt_enable(); 20548c2ecf20Sopenharmony_ci} 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_cistatic __always_inline 20578c2ecf20Sopenharmony_civoid __bpf_trace_run(struct bpf_prog *prog, u64 *args) 20588c2ecf20Sopenharmony_ci{ 20598c2ecf20Sopenharmony_ci cant_sleep(); 20608c2ecf20Sopenharmony_ci rcu_read_lock(); 20618c2ecf20Sopenharmony_ci (void) BPF_PROG_RUN(prog, args); 20628c2ecf20Sopenharmony_ci rcu_read_unlock(); 20638c2ecf20Sopenharmony_ci} 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci#define UNPACK(...) __VA_ARGS__ 20668c2ecf20Sopenharmony_ci#define REPEAT_1(FN, DL, X, ...) FN(X) 20678c2ecf20Sopenharmony_ci#define REPEAT_2(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_1(FN, DL, __VA_ARGS__) 20688c2ecf20Sopenharmony_ci#define REPEAT_3(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_2(FN, DL, __VA_ARGS__) 20698c2ecf20Sopenharmony_ci#define REPEAT_4(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_3(FN, DL, __VA_ARGS__) 20708c2ecf20Sopenharmony_ci#define REPEAT_5(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_4(FN, DL, __VA_ARGS__) 20718c2ecf20Sopenharmony_ci#define REPEAT_6(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_5(FN, DL, __VA_ARGS__) 20728c2ecf20Sopenharmony_ci#define REPEAT_7(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_6(FN, DL, __VA_ARGS__) 20738c2ecf20Sopenharmony_ci#define REPEAT_8(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_7(FN, DL, __VA_ARGS__) 20748c2ecf20Sopenharmony_ci#define REPEAT_9(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_8(FN, DL, __VA_ARGS__) 20758c2ecf20Sopenharmony_ci#define REPEAT_10(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_9(FN, DL, __VA_ARGS__) 20768c2ecf20Sopenharmony_ci#define REPEAT_11(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_10(FN, DL, __VA_ARGS__) 20778c2ecf20Sopenharmony_ci#define REPEAT_12(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_11(FN, DL, __VA_ARGS__) 20788c2ecf20Sopenharmony_ci#define REPEAT(X, FN, DL, ...) REPEAT_##X(FN, DL, __VA_ARGS__) 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci#define SARG(X) u64 arg##X 20818c2ecf20Sopenharmony_ci#define COPY(X) args[X] = arg##X 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_ci#define __DL_COM (,) 20848c2ecf20Sopenharmony_ci#define __DL_SEM (;) 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci#define __SEQ_0_11 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci#define BPF_TRACE_DEFN_x(x) \ 20898c2ecf20Sopenharmony_ci void bpf_trace_run##x(struct bpf_prog *prog, \ 20908c2ecf20Sopenharmony_ci REPEAT(x, SARG, __DL_COM, __SEQ_0_11)) \ 20918c2ecf20Sopenharmony_ci { \ 20928c2ecf20Sopenharmony_ci u64 args[x]; \ 20938c2ecf20Sopenharmony_ci REPEAT(x, COPY, __DL_SEM, __SEQ_0_11); \ 20948c2ecf20Sopenharmony_ci __bpf_trace_run(prog, args); \ 20958c2ecf20Sopenharmony_ci } \ 20968c2ecf20Sopenharmony_ci EXPORT_SYMBOL_GPL(bpf_trace_run##x) 20978c2ecf20Sopenharmony_ciBPF_TRACE_DEFN_x(1); 20988c2ecf20Sopenharmony_ciBPF_TRACE_DEFN_x(2); 20998c2ecf20Sopenharmony_ciBPF_TRACE_DEFN_x(3); 21008c2ecf20Sopenharmony_ciBPF_TRACE_DEFN_x(4); 21018c2ecf20Sopenharmony_ciBPF_TRACE_DEFN_x(5); 21028c2ecf20Sopenharmony_ciBPF_TRACE_DEFN_x(6); 21038c2ecf20Sopenharmony_ciBPF_TRACE_DEFN_x(7); 21048c2ecf20Sopenharmony_ciBPF_TRACE_DEFN_x(8); 21058c2ecf20Sopenharmony_ciBPF_TRACE_DEFN_x(9); 21068c2ecf20Sopenharmony_ciBPF_TRACE_DEFN_x(10); 21078c2ecf20Sopenharmony_ciBPF_TRACE_DEFN_x(11); 21088c2ecf20Sopenharmony_ciBPF_TRACE_DEFN_x(12); 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_cistatic int __bpf_probe_register(struct bpf_raw_event_map *btp, struct bpf_prog *prog) 21118c2ecf20Sopenharmony_ci{ 21128c2ecf20Sopenharmony_ci struct tracepoint *tp = btp->tp; 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ci /* 21158c2ecf20Sopenharmony_ci * check that program doesn't access arguments beyond what's 21168c2ecf20Sopenharmony_ci * available in this tracepoint 21178c2ecf20Sopenharmony_ci */ 21188c2ecf20Sopenharmony_ci if (prog->aux->max_ctx_offset > btp->num_args * sizeof(u64)) 21198c2ecf20Sopenharmony_ci return -EINVAL; 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci if (prog->aux->max_tp_access > btp->writable_size) 21228c2ecf20Sopenharmony_ci return -EINVAL; 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_ci return tracepoint_probe_register_may_exist(tp, (void *)btp->bpf_func, 21258c2ecf20Sopenharmony_ci prog); 21268c2ecf20Sopenharmony_ci} 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ciint bpf_probe_register(struct bpf_raw_event_map *btp, struct bpf_prog *prog) 21298c2ecf20Sopenharmony_ci{ 21308c2ecf20Sopenharmony_ci return __bpf_probe_register(btp, prog); 21318c2ecf20Sopenharmony_ci} 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ciint bpf_probe_unregister(struct bpf_raw_event_map *btp, struct bpf_prog *prog) 21348c2ecf20Sopenharmony_ci{ 21358c2ecf20Sopenharmony_ci return tracepoint_probe_unregister(btp->tp, (void *)btp->bpf_func, prog); 21368c2ecf20Sopenharmony_ci} 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ciint bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id, 21398c2ecf20Sopenharmony_ci u32 *fd_type, const char **buf, 21408c2ecf20Sopenharmony_ci u64 *probe_offset, u64 *probe_addr) 21418c2ecf20Sopenharmony_ci{ 21428c2ecf20Sopenharmony_ci bool is_tracepoint, is_syscall_tp; 21438c2ecf20Sopenharmony_ci struct bpf_prog *prog; 21448c2ecf20Sopenharmony_ci int flags, err = 0; 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_ci prog = event->prog; 21478c2ecf20Sopenharmony_ci if (!prog) 21488c2ecf20Sopenharmony_ci return -ENOENT; 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci /* not supporting BPF_PROG_TYPE_PERF_EVENT yet */ 21518c2ecf20Sopenharmony_ci if (prog->type == BPF_PROG_TYPE_PERF_EVENT) 21528c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci *prog_id = prog->aux->id; 21558c2ecf20Sopenharmony_ci flags = event->tp_event->flags; 21568c2ecf20Sopenharmony_ci is_tracepoint = flags & TRACE_EVENT_FL_TRACEPOINT; 21578c2ecf20Sopenharmony_ci is_syscall_tp = is_syscall_trace_event(event->tp_event); 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci if (is_tracepoint || is_syscall_tp) { 21608c2ecf20Sopenharmony_ci *buf = is_tracepoint ? event->tp_event->tp->name 21618c2ecf20Sopenharmony_ci : event->tp_event->name; 21628c2ecf20Sopenharmony_ci *fd_type = BPF_FD_TYPE_TRACEPOINT; 21638c2ecf20Sopenharmony_ci *probe_offset = 0x0; 21648c2ecf20Sopenharmony_ci *probe_addr = 0x0; 21658c2ecf20Sopenharmony_ci } else { 21668c2ecf20Sopenharmony_ci /* kprobe/uprobe */ 21678c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 21688c2ecf20Sopenharmony_ci#ifdef CONFIG_KPROBE_EVENTS 21698c2ecf20Sopenharmony_ci if (flags & TRACE_EVENT_FL_KPROBE) 21708c2ecf20Sopenharmony_ci err = bpf_get_kprobe_info(event, fd_type, buf, 21718c2ecf20Sopenharmony_ci probe_offset, probe_addr, 21728c2ecf20Sopenharmony_ci event->attr.type == PERF_TYPE_TRACEPOINT); 21738c2ecf20Sopenharmony_ci#endif 21748c2ecf20Sopenharmony_ci#ifdef CONFIG_UPROBE_EVENTS 21758c2ecf20Sopenharmony_ci if (flags & TRACE_EVENT_FL_UPROBE) 21768c2ecf20Sopenharmony_ci err = bpf_get_uprobe_info(event, fd_type, buf, 21778c2ecf20Sopenharmony_ci probe_offset, probe_addr, 21788c2ecf20Sopenharmony_ci event->attr.type == PERF_TYPE_TRACEPOINT); 21798c2ecf20Sopenharmony_ci#endif 21808c2ecf20Sopenharmony_ci } 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci return err; 21838c2ecf20Sopenharmony_ci} 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_cistatic int __init send_signal_irq_work_init(void) 21868c2ecf20Sopenharmony_ci{ 21878c2ecf20Sopenharmony_ci int cpu; 21888c2ecf20Sopenharmony_ci struct send_signal_irq_work *work; 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) { 21918c2ecf20Sopenharmony_ci work = per_cpu_ptr(&send_signal_work, cpu); 21928c2ecf20Sopenharmony_ci init_irq_work(&work->irq_work, do_bpf_send_signal); 21938c2ecf20Sopenharmony_ci } 21948c2ecf20Sopenharmony_ci return 0; 21958c2ecf20Sopenharmony_ci} 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_cisubsys_initcall(send_signal_irq_work_init); 21988c2ecf20Sopenharmony_ci 21998c2ecf20Sopenharmony_ci#ifdef CONFIG_MODULES 22008c2ecf20Sopenharmony_cistatic int bpf_event_notify(struct notifier_block *nb, unsigned long op, 22018c2ecf20Sopenharmony_ci void *module) 22028c2ecf20Sopenharmony_ci{ 22038c2ecf20Sopenharmony_ci struct bpf_trace_module *btm, *tmp; 22048c2ecf20Sopenharmony_ci struct module *mod = module; 22058c2ecf20Sopenharmony_ci int ret = 0; 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_ci if (mod->num_bpf_raw_events == 0 || 22088c2ecf20Sopenharmony_ci (op != MODULE_STATE_COMING && op != MODULE_STATE_GOING)) 22098c2ecf20Sopenharmony_ci goto out; 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_ci mutex_lock(&bpf_module_mutex); 22128c2ecf20Sopenharmony_ci 22138c2ecf20Sopenharmony_ci switch (op) { 22148c2ecf20Sopenharmony_ci case MODULE_STATE_COMING: 22158c2ecf20Sopenharmony_ci btm = kzalloc(sizeof(*btm), GFP_KERNEL); 22168c2ecf20Sopenharmony_ci if (btm) { 22178c2ecf20Sopenharmony_ci btm->module = module; 22188c2ecf20Sopenharmony_ci list_add(&btm->list, &bpf_trace_modules); 22198c2ecf20Sopenharmony_ci } else { 22208c2ecf20Sopenharmony_ci ret = -ENOMEM; 22218c2ecf20Sopenharmony_ci } 22228c2ecf20Sopenharmony_ci break; 22238c2ecf20Sopenharmony_ci case MODULE_STATE_GOING: 22248c2ecf20Sopenharmony_ci list_for_each_entry_safe(btm, tmp, &bpf_trace_modules, list) { 22258c2ecf20Sopenharmony_ci if (btm->module == module) { 22268c2ecf20Sopenharmony_ci list_del(&btm->list); 22278c2ecf20Sopenharmony_ci kfree(btm); 22288c2ecf20Sopenharmony_ci break; 22298c2ecf20Sopenharmony_ci } 22308c2ecf20Sopenharmony_ci } 22318c2ecf20Sopenharmony_ci break; 22328c2ecf20Sopenharmony_ci } 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_ci mutex_unlock(&bpf_module_mutex); 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ciout: 22378c2ecf20Sopenharmony_ci return notifier_from_errno(ret); 22388c2ecf20Sopenharmony_ci} 22398c2ecf20Sopenharmony_ci 22408c2ecf20Sopenharmony_cistatic struct notifier_block bpf_module_nb = { 22418c2ecf20Sopenharmony_ci .notifier_call = bpf_event_notify, 22428c2ecf20Sopenharmony_ci}; 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_cistatic int __init bpf_event_init(void) 22458c2ecf20Sopenharmony_ci{ 22468c2ecf20Sopenharmony_ci register_module_notifier(&bpf_module_nb); 22478c2ecf20Sopenharmony_ci return 0; 22488c2ecf20Sopenharmony_ci} 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_cifs_initcall(bpf_event_init); 22518c2ecf20Sopenharmony_ci#endif /* CONFIG_MODULES */ 2252