15b497af4SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2d0003ec0SAlexei Starovoitov /* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com 3d0003ec0SAlexei Starovoitov */ 4d0003ec0SAlexei Starovoitov #include <linux/bpf.h> 5aef2fedaSJakub Kicinski #include <linux/bpf-cgroup.h> 6d0003ec0SAlexei Starovoitov #include <linux/rcupdate.h> 703e69b50SDaniel Borkmann #include <linux/random.h> 8c04167ceSDaniel Borkmann #include <linux/smp.h> 92d0e30c3SDaniel Borkmann #include <linux/topology.h> 1017ca8cbfSDaniel Borkmann #include <linux/ktime.h> 11ffeedafbSAlexei Starovoitov #include <linux/sched.h> 12ffeedafbSAlexei Starovoitov #include <linux/uidgid.h> 13f3694e00SDaniel Borkmann #include <linux/filter.h> 14d7a4cb9bSAndrey Ignatov #include <linux/ctype.h> 155576b991SMartin KaFai Lau #include <linux/jiffies.h> 16b4490c5cSCarlos Neira #include <linux/pid_namespace.h> 17b4490c5cSCarlos Neira #include <linux/proc_ns.h> 18ff40e510SDaniel Borkmann #include <linux/security.h> 19d7a4cb9bSAndrey Ignatov 20d7a4cb9bSAndrey Ignatov #include "../../lib/kstrtox.h" 21d0003ec0SAlexei Starovoitov 22d0003ec0SAlexei Starovoitov /* If kernel subsystem is allowing eBPF programs to call this function, 23d0003ec0SAlexei Starovoitov * inside its own verifier_ops->get_func_proto() callback it should return 24d0003ec0SAlexei Starovoitov * bpf_map_lookup_elem_proto, so that verifier can properly check the arguments 25d0003ec0SAlexei Starovoitov * 26d0003ec0SAlexei Starovoitov * Different map implementations will rely on rcu in map methods 27d0003ec0SAlexei Starovoitov * lookup/update/delete, therefore eBPF programs must run under rcu lock 28d0003ec0SAlexei Starovoitov * if program is allowed to access maps, so check rcu_read_lock_held in 29d0003ec0SAlexei Starovoitov * all three functions. 30d0003ec0SAlexei Starovoitov */ 31f3694e00SDaniel Borkmann BPF_CALL_2(bpf_map_lookup_elem, struct bpf_map *, map, void *, key) 32d0003ec0SAlexei Starovoitov { 33694cea39SToke Høiland-Jørgensen WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_bh_held()); 34f3694e00SDaniel Borkmann return (unsigned long) map->ops->map_lookup_elem(map, key); 35d0003ec0SAlexei Starovoitov } 36d0003ec0SAlexei Starovoitov 37a2c83fffSDaniel Borkmann const struct bpf_func_proto bpf_map_lookup_elem_proto = { 38d0003ec0SAlexei Starovoitov .func = bpf_map_lookup_elem, 39d0003ec0SAlexei Starovoitov .gpl_only = false, 4036bbef52SDaniel Borkmann .pkt_access = true, 41d0003ec0SAlexei Starovoitov .ret_type = RET_PTR_TO_MAP_VALUE_OR_NULL, 42d0003ec0SAlexei Starovoitov .arg1_type = ARG_CONST_MAP_PTR, 43d0003ec0SAlexei Starovoitov .arg2_type = ARG_PTR_TO_MAP_KEY, 44d0003ec0SAlexei Starovoitov }; 45d0003ec0SAlexei Starovoitov 46f3694e00SDaniel Borkmann BPF_CALL_4(bpf_map_update_elem, struct bpf_map *, map, void *, key, 47f3694e00SDaniel Borkmann void *, value, u64, flags) 48d0003ec0SAlexei Starovoitov { 49694cea39SToke Høiland-Jørgensen WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_bh_held()); 50f3694e00SDaniel Borkmann return map->ops->map_update_elem(map, key, value, flags); 51d0003ec0SAlexei Starovoitov } 52d0003ec0SAlexei Starovoitov 53a2c83fffSDaniel Borkmann const struct bpf_func_proto bpf_map_update_elem_proto = { 54d0003ec0SAlexei Starovoitov .func = bpf_map_update_elem, 55d0003ec0SAlexei Starovoitov .gpl_only = false, 5636bbef52SDaniel Borkmann .pkt_access = true, 57d0003ec0SAlexei Starovoitov .ret_type = RET_INTEGER, 58d0003ec0SAlexei Starovoitov .arg1_type = ARG_CONST_MAP_PTR, 59d0003ec0SAlexei Starovoitov .arg2_type = ARG_PTR_TO_MAP_KEY, 60d0003ec0SAlexei Starovoitov .arg3_type = ARG_PTR_TO_MAP_VALUE, 61d0003ec0SAlexei Starovoitov .arg4_type = ARG_ANYTHING, 62d0003ec0SAlexei Starovoitov }; 63d0003ec0SAlexei Starovoitov 64f3694e00SDaniel Borkmann BPF_CALL_2(bpf_map_delete_elem, struct bpf_map *, map, void *, key) 65d0003ec0SAlexei Starovoitov { 66694cea39SToke Høiland-Jørgensen WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_bh_held()); 67d0003ec0SAlexei Starovoitov return map->ops->map_delete_elem(map, key); 68d0003ec0SAlexei Starovoitov } 69d0003ec0SAlexei Starovoitov 70a2c83fffSDaniel Borkmann const struct bpf_func_proto bpf_map_delete_elem_proto = { 71d0003ec0SAlexei Starovoitov .func = bpf_map_delete_elem, 72d0003ec0SAlexei Starovoitov .gpl_only = false, 7336bbef52SDaniel Borkmann .pkt_access = true, 74d0003ec0SAlexei Starovoitov .ret_type = RET_INTEGER, 75d0003ec0SAlexei Starovoitov .arg1_type = ARG_CONST_MAP_PTR, 76d0003ec0SAlexei Starovoitov .arg2_type = ARG_PTR_TO_MAP_KEY, 77d0003ec0SAlexei Starovoitov }; 7803e69b50SDaniel Borkmann 79f1a2e44aSMauricio Vasquez B BPF_CALL_3(bpf_map_push_elem, struct bpf_map *, map, void *, value, u64, flags) 80f1a2e44aSMauricio Vasquez B { 81f1a2e44aSMauricio Vasquez B return map->ops->map_push_elem(map, value, flags); 82f1a2e44aSMauricio Vasquez B } 83f1a2e44aSMauricio Vasquez B 84f1a2e44aSMauricio Vasquez B const struct bpf_func_proto bpf_map_push_elem_proto = { 85f1a2e44aSMauricio Vasquez B .func = bpf_map_push_elem, 86f1a2e44aSMauricio Vasquez B .gpl_only = false, 87f1a2e44aSMauricio Vasquez B .pkt_access = true, 88f1a2e44aSMauricio Vasquez B .ret_type = RET_INTEGER, 89f1a2e44aSMauricio Vasquez B .arg1_type = ARG_CONST_MAP_PTR, 90f1a2e44aSMauricio Vasquez B .arg2_type = ARG_PTR_TO_MAP_VALUE, 91f1a2e44aSMauricio Vasquez B .arg3_type = ARG_ANYTHING, 92f1a2e44aSMauricio Vasquez B }; 93f1a2e44aSMauricio Vasquez B 94f1a2e44aSMauricio Vasquez B BPF_CALL_2(bpf_map_pop_elem, struct bpf_map *, map, void *, value) 95f1a2e44aSMauricio Vasquez B { 96f1a2e44aSMauricio Vasquez B return map->ops->map_pop_elem(map, value); 97f1a2e44aSMauricio Vasquez B } 98f1a2e44aSMauricio Vasquez B 99f1a2e44aSMauricio Vasquez B const struct bpf_func_proto bpf_map_pop_elem_proto = { 100f1a2e44aSMauricio Vasquez B .func = bpf_map_pop_elem, 101f1a2e44aSMauricio Vasquez B .gpl_only = false, 102f1a2e44aSMauricio Vasquez B .ret_type = RET_INTEGER, 103f1a2e44aSMauricio Vasquez B .arg1_type = ARG_CONST_MAP_PTR, 104f1a2e44aSMauricio Vasquez B .arg2_type = ARG_PTR_TO_UNINIT_MAP_VALUE, 105f1a2e44aSMauricio Vasquez B }; 106f1a2e44aSMauricio Vasquez B 107f1a2e44aSMauricio Vasquez B BPF_CALL_2(bpf_map_peek_elem, struct bpf_map *, map, void *, value) 108f1a2e44aSMauricio Vasquez B { 109f1a2e44aSMauricio Vasquez B return map->ops->map_peek_elem(map, value); 110f1a2e44aSMauricio Vasquez B } 111f1a2e44aSMauricio Vasquez B 112f1a2e44aSMauricio Vasquez B const struct bpf_func_proto bpf_map_peek_elem_proto = { 113301a33d5SMircea Cirjaliu .func = bpf_map_peek_elem, 114f1a2e44aSMauricio Vasquez B .gpl_only = false, 115f1a2e44aSMauricio Vasquez B .ret_type = RET_INTEGER, 116f1a2e44aSMauricio Vasquez B .arg1_type = ARG_CONST_MAP_PTR, 117f1a2e44aSMauricio Vasquez B .arg2_type = ARG_PTR_TO_UNINIT_MAP_VALUE, 118f1a2e44aSMauricio Vasquez B }; 119f1a2e44aSMauricio Vasquez B 12003e69b50SDaniel Borkmann const struct bpf_func_proto bpf_get_prandom_u32_proto = { 1213ad00405SDaniel Borkmann .func = bpf_user_rnd_u32, 12203e69b50SDaniel Borkmann .gpl_only = false, 12303e69b50SDaniel Borkmann .ret_type = RET_INTEGER, 12403e69b50SDaniel Borkmann }; 125c04167ceSDaniel Borkmann 126f3694e00SDaniel Borkmann BPF_CALL_0(bpf_get_smp_processor_id) 127c04167ceSDaniel Borkmann { 12880b48c44SDaniel Borkmann return smp_processor_id(); 129c04167ceSDaniel Borkmann } 130c04167ceSDaniel Borkmann 131c04167ceSDaniel Borkmann const struct bpf_func_proto bpf_get_smp_processor_id_proto = { 132c04167ceSDaniel Borkmann .func = bpf_get_smp_processor_id, 133c04167ceSDaniel Borkmann .gpl_only = false, 134c04167ceSDaniel Borkmann .ret_type = RET_INTEGER, 135c04167ceSDaniel Borkmann }; 13617ca8cbfSDaniel Borkmann 1372d0e30c3SDaniel Borkmann BPF_CALL_0(bpf_get_numa_node_id) 1382d0e30c3SDaniel Borkmann { 1392d0e30c3SDaniel Borkmann return numa_node_id(); 1402d0e30c3SDaniel Borkmann } 1412d0e30c3SDaniel Borkmann 1422d0e30c3SDaniel Borkmann const struct bpf_func_proto bpf_get_numa_node_id_proto = { 1432d0e30c3SDaniel Borkmann .func = bpf_get_numa_node_id, 1442d0e30c3SDaniel Borkmann .gpl_only = false, 1452d0e30c3SDaniel Borkmann .ret_type = RET_INTEGER, 1462d0e30c3SDaniel Borkmann }; 1472d0e30c3SDaniel Borkmann 148f3694e00SDaniel Borkmann BPF_CALL_0(bpf_ktime_get_ns) 14917ca8cbfSDaniel Borkmann { 15017ca8cbfSDaniel Borkmann /* NMI safe access to clock monotonic */ 15117ca8cbfSDaniel Borkmann return ktime_get_mono_fast_ns(); 15217ca8cbfSDaniel Borkmann } 15317ca8cbfSDaniel Borkmann 15417ca8cbfSDaniel Borkmann const struct bpf_func_proto bpf_ktime_get_ns_proto = { 15517ca8cbfSDaniel Borkmann .func = bpf_ktime_get_ns, 156082b57e3SMaciej Żenczykowski .gpl_only = false, 15717ca8cbfSDaniel Borkmann .ret_type = RET_INTEGER, 15817ca8cbfSDaniel Borkmann }; 159ffeedafbSAlexei Starovoitov 16071d19214SMaciej Żenczykowski BPF_CALL_0(bpf_ktime_get_boot_ns) 16171d19214SMaciej Żenczykowski { 16271d19214SMaciej Żenczykowski /* NMI safe access to clock boottime */ 16371d19214SMaciej Żenczykowski return ktime_get_boot_fast_ns(); 16471d19214SMaciej Żenczykowski } 16571d19214SMaciej Żenczykowski 16671d19214SMaciej Żenczykowski const struct bpf_func_proto bpf_ktime_get_boot_ns_proto = { 16771d19214SMaciej Żenczykowski .func = bpf_ktime_get_boot_ns, 16871d19214SMaciej Żenczykowski .gpl_only = false, 16971d19214SMaciej Żenczykowski .ret_type = RET_INTEGER, 17071d19214SMaciej Żenczykowski }; 17171d19214SMaciej Żenczykowski 172d0551261SDmitrii Banshchikov BPF_CALL_0(bpf_ktime_get_coarse_ns) 173d0551261SDmitrii Banshchikov { 174d0551261SDmitrii Banshchikov return ktime_get_coarse_ns(); 175d0551261SDmitrii Banshchikov } 176d0551261SDmitrii Banshchikov 177d0551261SDmitrii Banshchikov const struct bpf_func_proto bpf_ktime_get_coarse_ns_proto = { 178d0551261SDmitrii Banshchikov .func = bpf_ktime_get_coarse_ns, 179d0551261SDmitrii Banshchikov .gpl_only = false, 180d0551261SDmitrii Banshchikov .ret_type = RET_INTEGER, 181d0551261SDmitrii Banshchikov }; 182d0551261SDmitrii Banshchikov 183f3694e00SDaniel Borkmann BPF_CALL_0(bpf_get_current_pid_tgid) 184ffeedafbSAlexei Starovoitov { 185ffeedafbSAlexei Starovoitov struct task_struct *task = current; 186ffeedafbSAlexei Starovoitov 1876088b582SDaniel Borkmann if (unlikely(!task)) 188ffeedafbSAlexei Starovoitov return -EINVAL; 189ffeedafbSAlexei Starovoitov 190ffeedafbSAlexei Starovoitov return (u64) task->tgid << 32 | task->pid; 191ffeedafbSAlexei Starovoitov } 192ffeedafbSAlexei Starovoitov 193ffeedafbSAlexei Starovoitov const struct bpf_func_proto bpf_get_current_pid_tgid_proto = { 194ffeedafbSAlexei Starovoitov .func = bpf_get_current_pid_tgid, 195ffeedafbSAlexei Starovoitov .gpl_only = false, 196ffeedafbSAlexei Starovoitov .ret_type = RET_INTEGER, 197ffeedafbSAlexei Starovoitov }; 198ffeedafbSAlexei Starovoitov 199f3694e00SDaniel Borkmann BPF_CALL_0(bpf_get_current_uid_gid) 200ffeedafbSAlexei Starovoitov { 201ffeedafbSAlexei Starovoitov struct task_struct *task = current; 202ffeedafbSAlexei Starovoitov kuid_t uid; 203ffeedafbSAlexei Starovoitov kgid_t gid; 204ffeedafbSAlexei Starovoitov 2056088b582SDaniel Borkmann if (unlikely(!task)) 206ffeedafbSAlexei Starovoitov return -EINVAL; 207ffeedafbSAlexei Starovoitov 208ffeedafbSAlexei Starovoitov current_uid_gid(&uid, &gid); 209ffeedafbSAlexei Starovoitov return (u64) from_kgid(&init_user_ns, gid) << 32 | 210ffeedafbSAlexei Starovoitov from_kuid(&init_user_ns, uid); 211ffeedafbSAlexei Starovoitov } 212ffeedafbSAlexei Starovoitov 213ffeedafbSAlexei Starovoitov const struct bpf_func_proto bpf_get_current_uid_gid_proto = { 214ffeedafbSAlexei Starovoitov .func = bpf_get_current_uid_gid, 215ffeedafbSAlexei Starovoitov .gpl_only = false, 216ffeedafbSAlexei Starovoitov .ret_type = RET_INTEGER, 217ffeedafbSAlexei Starovoitov }; 218ffeedafbSAlexei Starovoitov 219f3694e00SDaniel Borkmann BPF_CALL_2(bpf_get_current_comm, char *, buf, u32, size) 220ffeedafbSAlexei Starovoitov { 221ffeedafbSAlexei Starovoitov struct task_struct *task = current; 222ffeedafbSAlexei Starovoitov 223074f528eSDaniel Borkmann if (unlikely(!task)) 224074f528eSDaniel Borkmann goto err_clear; 225ffeedafbSAlexei Starovoitov 226074f528eSDaniel Borkmann strncpy(buf, task->comm, size); 227074f528eSDaniel Borkmann 228074f528eSDaniel Borkmann /* Verifier guarantees that size > 0. For task->comm exceeding 229074f528eSDaniel Borkmann * size, guarantee that buf is %NUL-terminated. Unconditionally 230074f528eSDaniel Borkmann * done here to save the size test. 231074f528eSDaniel Borkmann */ 232074f528eSDaniel Borkmann buf[size - 1] = 0; 233ffeedafbSAlexei Starovoitov return 0; 234074f528eSDaniel Borkmann err_clear: 235074f528eSDaniel Borkmann memset(buf, 0, size); 236074f528eSDaniel Borkmann return -EINVAL; 237ffeedafbSAlexei Starovoitov } 238ffeedafbSAlexei Starovoitov 239ffeedafbSAlexei Starovoitov const struct bpf_func_proto bpf_get_current_comm_proto = { 240ffeedafbSAlexei Starovoitov .func = bpf_get_current_comm, 241ffeedafbSAlexei Starovoitov .gpl_only = false, 242ffeedafbSAlexei Starovoitov .ret_type = RET_INTEGER, 24339f19ebbSAlexei Starovoitov .arg1_type = ARG_PTR_TO_UNINIT_MEM, 24439f19ebbSAlexei Starovoitov .arg2_type = ARG_CONST_SIZE, 245ffeedafbSAlexei Starovoitov }; 246bf6fa2c8SYonghong Song 247d83525caSAlexei Starovoitov #if defined(CONFIG_QUEUED_SPINLOCKS) || defined(CONFIG_BPF_ARCH_SPINLOCK) 248d83525caSAlexei Starovoitov 249d83525caSAlexei Starovoitov static inline void __bpf_spin_lock(struct bpf_spin_lock *lock) 250d83525caSAlexei Starovoitov { 251d83525caSAlexei Starovoitov arch_spinlock_t *l = (void *)lock; 252d83525caSAlexei Starovoitov union { 253d83525caSAlexei Starovoitov __u32 val; 254d83525caSAlexei Starovoitov arch_spinlock_t lock; 255d83525caSAlexei Starovoitov } u = { .lock = __ARCH_SPIN_LOCK_UNLOCKED }; 256d83525caSAlexei Starovoitov 257d83525caSAlexei Starovoitov compiletime_assert(u.val == 0, "__ARCH_SPIN_LOCK_UNLOCKED not 0"); 258d83525caSAlexei Starovoitov BUILD_BUG_ON(sizeof(*l) != sizeof(__u32)); 259d83525caSAlexei Starovoitov BUILD_BUG_ON(sizeof(*lock) != sizeof(__u32)); 260d83525caSAlexei Starovoitov arch_spin_lock(l); 261d83525caSAlexei Starovoitov } 262d83525caSAlexei Starovoitov 263d83525caSAlexei Starovoitov static inline void __bpf_spin_unlock(struct bpf_spin_lock *lock) 264d83525caSAlexei Starovoitov { 265d83525caSAlexei Starovoitov arch_spinlock_t *l = (void *)lock; 266d83525caSAlexei Starovoitov 267d83525caSAlexei Starovoitov arch_spin_unlock(l); 268d83525caSAlexei Starovoitov } 269d83525caSAlexei Starovoitov 270d83525caSAlexei Starovoitov #else 271d83525caSAlexei Starovoitov 272d83525caSAlexei Starovoitov static inline void __bpf_spin_lock(struct bpf_spin_lock *lock) 273d83525caSAlexei Starovoitov { 274d83525caSAlexei Starovoitov atomic_t *l = (void *)lock; 275d83525caSAlexei Starovoitov 276d83525caSAlexei Starovoitov BUILD_BUG_ON(sizeof(*l) != sizeof(*lock)); 277d83525caSAlexei Starovoitov do { 278d83525caSAlexei Starovoitov atomic_cond_read_relaxed(l, !VAL); 279d83525caSAlexei Starovoitov } while (atomic_xchg(l, 1)); 280d83525caSAlexei Starovoitov } 281d83525caSAlexei Starovoitov 282d83525caSAlexei Starovoitov static inline void __bpf_spin_unlock(struct bpf_spin_lock *lock) 283d83525caSAlexei Starovoitov { 284d83525caSAlexei Starovoitov atomic_t *l = (void *)lock; 285d83525caSAlexei Starovoitov 286d83525caSAlexei Starovoitov atomic_set_release(l, 0); 287d83525caSAlexei Starovoitov } 288d83525caSAlexei Starovoitov 289d83525caSAlexei Starovoitov #endif 290d83525caSAlexei Starovoitov 291d83525caSAlexei Starovoitov static DEFINE_PER_CPU(unsigned long, irqsave_flags); 292d83525caSAlexei Starovoitov 293c1b3fed3SAlexei Starovoitov static inline void __bpf_spin_lock_irqsave(struct bpf_spin_lock *lock) 294d83525caSAlexei Starovoitov { 295d83525caSAlexei Starovoitov unsigned long flags; 296d83525caSAlexei Starovoitov 297d83525caSAlexei Starovoitov local_irq_save(flags); 298d83525caSAlexei Starovoitov __bpf_spin_lock(lock); 299d83525caSAlexei Starovoitov __this_cpu_write(irqsave_flags, flags); 300c1b3fed3SAlexei Starovoitov } 301c1b3fed3SAlexei Starovoitov 302c1b3fed3SAlexei Starovoitov notrace BPF_CALL_1(bpf_spin_lock, struct bpf_spin_lock *, lock) 303c1b3fed3SAlexei Starovoitov { 304c1b3fed3SAlexei Starovoitov __bpf_spin_lock_irqsave(lock); 305d83525caSAlexei Starovoitov return 0; 306d83525caSAlexei Starovoitov } 307d83525caSAlexei Starovoitov 308d83525caSAlexei Starovoitov const struct bpf_func_proto bpf_spin_lock_proto = { 309d83525caSAlexei Starovoitov .func = bpf_spin_lock, 310d83525caSAlexei Starovoitov .gpl_only = false, 311d83525caSAlexei Starovoitov .ret_type = RET_VOID, 312d83525caSAlexei Starovoitov .arg1_type = ARG_PTR_TO_SPIN_LOCK, 313d83525caSAlexei Starovoitov }; 314d83525caSAlexei Starovoitov 315c1b3fed3SAlexei Starovoitov static inline void __bpf_spin_unlock_irqrestore(struct bpf_spin_lock *lock) 316d83525caSAlexei Starovoitov { 317d83525caSAlexei Starovoitov unsigned long flags; 318d83525caSAlexei Starovoitov 319d83525caSAlexei Starovoitov flags = __this_cpu_read(irqsave_flags); 320d83525caSAlexei Starovoitov __bpf_spin_unlock(lock); 321d83525caSAlexei Starovoitov local_irq_restore(flags); 322c1b3fed3SAlexei Starovoitov } 323c1b3fed3SAlexei Starovoitov 324c1b3fed3SAlexei Starovoitov notrace BPF_CALL_1(bpf_spin_unlock, struct bpf_spin_lock *, lock) 325c1b3fed3SAlexei Starovoitov { 326c1b3fed3SAlexei Starovoitov __bpf_spin_unlock_irqrestore(lock); 327d83525caSAlexei Starovoitov return 0; 328d83525caSAlexei Starovoitov } 329d83525caSAlexei Starovoitov 330d83525caSAlexei Starovoitov const struct bpf_func_proto bpf_spin_unlock_proto = { 331d83525caSAlexei Starovoitov .func = bpf_spin_unlock, 332d83525caSAlexei Starovoitov .gpl_only = false, 333d83525caSAlexei Starovoitov .ret_type = RET_VOID, 334d83525caSAlexei Starovoitov .arg1_type = ARG_PTR_TO_SPIN_LOCK, 335d83525caSAlexei Starovoitov }; 336d83525caSAlexei Starovoitov 33796049f3aSAlexei Starovoitov void copy_map_value_locked(struct bpf_map *map, void *dst, void *src, 33896049f3aSAlexei Starovoitov bool lock_src) 33996049f3aSAlexei Starovoitov { 34096049f3aSAlexei Starovoitov struct bpf_spin_lock *lock; 34196049f3aSAlexei Starovoitov 34296049f3aSAlexei Starovoitov if (lock_src) 34396049f3aSAlexei Starovoitov lock = src + map->spin_lock_off; 34496049f3aSAlexei Starovoitov else 34596049f3aSAlexei Starovoitov lock = dst + map->spin_lock_off; 34696049f3aSAlexei Starovoitov preempt_disable(); 347c1b3fed3SAlexei Starovoitov __bpf_spin_lock_irqsave(lock); 34896049f3aSAlexei Starovoitov copy_map_value(map, dst, src); 349c1b3fed3SAlexei Starovoitov __bpf_spin_unlock_irqrestore(lock); 35096049f3aSAlexei Starovoitov preempt_enable(); 35196049f3aSAlexei Starovoitov } 35296049f3aSAlexei Starovoitov 3535576b991SMartin KaFai Lau BPF_CALL_0(bpf_jiffies64) 3545576b991SMartin KaFai Lau { 3555576b991SMartin KaFai Lau return get_jiffies_64(); 3565576b991SMartin KaFai Lau } 3575576b991SMartin KaFai Lau 3585576b991SMartin KaFai Lau const struct bpf_func_proto bpf_jiffies64_proto = { 3595576b991SMartin KaFai Lau .func = bpf_jiffies64, 3605576b991SMartin KaFai Lau .gpl_only = false, 3615576b991SMartin KaFai Lau .ret_type = RET_INTEGER, 3625576b991SMartin KaFai Lau }; 3635576b991SMartin KaFai Lau 364bf6fa2c8SYonghong Song #ifdef CONFIG_CGROUPS 365bf6fa2c8SYonghong Song BPF_CALL_0(bpf_get_current_cgroup_id) 366bf6fa2c8SYonghong Song { 3672d3a1e36SYonghong Song struct cgroup *cgrp; 3682d3a1e36SYonghong Song u64 cgrp_id; 369bf6fa2c8SYonghong Song 3702d3a1e36SYonghong Song rcu_read_lock(); 3712d3a1e36SYonghong Song cgrp = task_dfl_cgroup(current); 3722d3a1e36SYonghong Song cgrp_id = cgroup_id(cgrp); 3732d3a1e36SYonghong Song rcu_read_unlock(); 3742d3a1e36SYonghong Song 3752d3a1e36SYonghong Song return cgrp_id; 376bf6fa2c8SYonghong Song } 377bf6fa2c8SYonghong Song 378bf6fa2c8SYonghong Song const struct bpf_func_proto bpf_get_current_cgroup_id_proto = { 379bf6fa2c8SYonghong Song .func = bpf_get_current_cgroup_id, 380bf6fa2c8SYonghong Song .gpl_only = false, 381bf6fa2c8SYonghong Song .ret_type = RET_INTEGER, 382bf6fa2c8SYonghong Song }; 383cd339431SRoman Gushchin 3840f09abd1SDaniel Borkmann BPF_CALL_1(bpf_get_current_ancestor_cgroup_id, int, ancestor_level) 3850f09abd1SDaniel Borkmann { 3862d3a1e36SYonghong Song struct cgroup *cgrp; 3870f09abd1SDaniel Borkmann struct cgroup *ancestor; 3882d3a1e36SYonghong Song u64 cgrp_id; 3890f09abd1SDaniel Borkmann 3902d3a1e36SYonghong Song rcu_read_lock(); 3912d3a1e36SYonghong Song cgrp = task_dfl_cgroup(current); 3920f09abd1SDaniel Borkmann ancestor = cgroup_ancestor(cgrp, ancestor_level); 3932d3a1e36SYonghong Song cgrp_id = ancestor ? cgroup_id(ancestor) : 0; 3942d3a1e36SYonghong Song rcu_read_unlock(); 3952d3a1e36SYonghong Song 3962d3a1e36SYonghong Song return cgrp_id; 3970f09abd1SDaniel Borkmann } 3980f09abd1SDaniel Borkmann 3990f09abd1SDaniel Borkmann const struct bpf_func_proto bpf_get_current_ancestor_cgroup_id_proto = { 4000f09abd1SDaniel Borkmann .func = bpf_get_current_ancestor_cgroup_id, 4010f09abd1SDaniel Borkmann .gpl_only = false, 4020f09abd1SDaniel Borkmann .ret_type = RET_INTEGER, 4030f09abd1SDaniel Borkmann .arg1_type = ARG_ANYTHING, 4040f09abd1SDaniel Borkmann }; 4050f09abd1SDaniel Borkmann 4068bad74f9SRoman Gushchin #ifdef CONFIG_CGROUP_BPF 407cd339431SRoman Gushchin 408cd339431SRoman Gushchin BPF_CALL_2(bpf_get_local_storage, struct bpf_map *, map, u64, flags) 409cd339431SRoman Gushchin { 4108bad74f9SRoman Gushchin /* flags argument is not used now, 4118bad74f9SRoman Gushchin * but provides an ability to extend the API. 4128bad74f9SRoman Gushchin * verifier checks that its value is correct. 413cd339431SRoman Gushchin */ 4148bad74f9SRoman Gushchin enum bpf_cgroup_storage_type stype = cgroup_storage_type(map); 415c7603cfaSAndrii Nakryiko struct bpf_cgroup_storage *storage; 416c7603cfaSAndrii Nakryiko struct bpf_cg_run_ctx *ctx; 417b741f163SRoman Gushchin void *ptr; 4188bad74f9SRoman Gushchin 419c7603cfaSAndrii Nakryiko /* get current cgroup storage from BPF run context */ 420c7603cfaSAndrii Nakryiko ctx = container_of(current->bpf_ctx, struct bpf_cg_run_ctx, run_ctx); 421c7603cfaSAndrii Nakryiko storage = ctx->prog_item->cgroup_storage[stype]; 422f294b37eSRoman Gushchin 423b741f163SRoman Gushchin if (stype == BPF_CGROUP_STORAGE_SHARED) 424b741f163SRoman Gushchin ptr = &READ_ONCE(storage->buf)->data[0]; 425b741f163SRoman Gushchin else 426b741f163SRoman Gushchin ptr = this_cpu_ptr(storage->percpu_buf); 427b741f163SRoman Gushchin 428b741f163SRoman Gushchin return (unsigned long)ptr; 429cd339431SRoman Gushchin } 430cd339431SRoman Gushchin 431cd339431SRoman Gushchin const struct bpf_func_proto bpf_get_local_storage_proto = { 432cd339431SRoman Gushchin .func = bpf_get_local_storage, 433cd339431SRoman Gushchin .gpl_only = false, 434cd339431SRoman Gushchin .ret_type = RET_PTR_TO_MAP_VALUE, 435cd339431SRoman Gushchin .arg1_type = ARG_CONST_MAP_PTR, 436cd339431SRoman Gushchin .arg2_type = ARG_ANYTHING, 437cd339431SRoman Gushchin }; 438bf6fa2c8SYonghong Song #endif 439d7a4cb9bSAndrey Ignatov 440d7a4cb9bSAndrey Ignatov #define BPF_STRTOX_BASE_MASK 0x1F 441d7a4cb9bSAndrey Ignatov 442d7a4cb9bSAndrey Ignatov static int __bpf_strtoull(const char *buf, size_t buf_len, u64 flags, 443d7a4cb9bSAndrey Ignatov unsigned long long *res, bool *is_negative) 444d7a4cb9bSAndrey Ignatov { 445d7a4cb9bSAndrey Ignatov unsigned int base = flags & BPF_STRTOX_BASE_MASK; 446d7a4cb9bSAndrey Ignatov const char *cur_buf = buf; 447d7a4cb9bSAndrey Ignatov size_t cur_len = buf_len; 448d7a4cb9bSAndrey Ignatov unsigned int consumed; 449d7a4cb9bSAndrey Ignatov size_t val_len; 450d7a4cb9bSAndrey Ignatov char str[64]; 451d7a4cb9bSAndrey Ignatov 452d7a4cb9bSAndrey Ignatov if (!buf || !buf_len || !res || !is_negative) 453d7a4cb9bSAndrey Ignatov return -EINVAL; 454d7a4cb9bSAndrey Ignatov 455d7a4cb9bSAndrey Ignatov if (base != 0 && base != 8 && base != 10 && base != 16) 456d7a4cb9bSAndrey Ignatov return -EINVAL; 457d7a4cb9bSAndrey Ignatov 458d7a4cb9bSAndrey Ignatov if (flags & ~BPF_STRTOX_BASE_MASK) 459d7a4cb9bSAndrey Ignatov return -EINVAL; 460d7a4cb9bSAndrey Ignatov 461d7a4cb9bSAndrey Ignatov while (cur_buf < buf + buf_len && isspace(*cur_buf)) 462d7a4cb9bSAndrey Ignatov ++cur_buf; 463d7a4cb9bSAndrey Ignatov 464d7a4cb9bSAndrey Ignatov *is_negative = (cur_buf < buf + buf_len && *cur_buf == '-'); 465d7a4cb9bSAndrey Ignatov if (*is_negative) 466d7a4cb9bSAndrey Ignatov ++cur_buf; 467d7a4cb9bSAndrey Ignatov 468d7a4cb9bSAndrey Ignatov consumed = cur_buf - buf; 469d7a4cb9bSAndrey Ignatov cur_len -= consumed; 470d7a4cb9bSAndrey Ignatov if (!cur_len) 471d7a4cb9bSAndrey Ignatov return -EINVAL; 472d7a4cb9bSAndrey Ignatov 473d7a4cb9bSAndrey Ignatov cur_len = min(cur_len, sizeof(str) - 1); 474d7a4cb9bSAndrey Ignatov memcpy(str, cur_buf, cur_len); 475d7a4cb9bSAndrey Ignatov str[cur_len] = '\0'; 476d7a4cb9bSAndrey Ignatov cur_buf = str; 477d7a4cb9bSAndrey Ignatov 478d7a4cb9bSAndrey Ignatov cur_buf = _parse_integer_fixup_radix(cur_buf, &base); 479d7a4cb9bSAndrey Ignatov val_len = _parse_integer(cur_buf, base, res); 480d7a4cb9bSAndrey Ignatov 481d7a4cb9bSAndrey Ignatov if (val_len & KSTRTOX_OVERFLOW) 482d7a4cb9bSAndrey Ignatov return -ERANGE; 483d7a4cb9bSAndrey Ignatov 484d7a4cb9bSAndrey Ignatov if (val_len == 0) 485d7a4cb9bSAndrey Ignatov return -EINVAL; 486d7a4cb9bSAndrey Ignatov 487d7a4cb9bSAndrey Ignatov cur_buf += val_len; 488d7a4cb9bSAndrey Ignatov consumed += cur_buf - str; 489d7a4cb9bSAndrey Ignatov 490d7a4cb9bSAndrey Ignatov return consumed; 491d7a4cb9bSAndrey Ignatov } 492d7a4cb9bSAndrey Ignatov 493d7a4cb9bSAndrey Ignatov static int __bpf_strtoll(const char *buf, size_t buf_len, u64 flags, 494d7a4cb9bSAndrey Ignatov long long *res) 495d7a4cb9bSAndrey Ignatov { 496d7a4cb9bSAndrey Ignatov unsigned long long _res; 497d7a4cb9bSAndrey Ignatov bool is_negative; 498d7a4cb9bSAndrey Ignatov int err; 499d7a4cb9bSAndrey Ignatov 500d7a4cb9bSAndrey Ignatov err = __bpf_strtoull(buf, buf_len, flags, &_res, &is_negative); 501d7a4cb9bSAndrey Ignatov if (err < 0) 502d7a4cb9bSAndrey Ignatov return err; 503d7a4cb9bSAndrey Ignatov if (is_negative) { 504d7a4cb9bSAndrey Ignatov if ((long long)-_res > 0) 505d7a4cb9bSAndrey Ignatov return -ERANGE; 506d7a4cb9bSAndrey Ignatov *res = -_res; 507d7a4cb9bSAndrey Ignatov } else { 508d7a4cb9bSAndrey Ignatov if ((long long)_res < 0) 509d7a4cb9bSAndrey Ignatov return -ERANGE; 510d7a4cb9bSAndrey Ignatov *res = _res; 511d7a4cb9bSAndrey Ignatov } 512d7a4cb9bSAndrey Ignatov return err; 513d7a4cb9bSAndrey Ignatov } 514d7a4cb9bSAndrey Ignatov 515d7a4cb9bSAndrey Ignatov BPF_CALL_4(bpf_strtol, const char *, buf, size_t, buf_len, u64, flags, 516d7a4cb9bSAndrey Ignatov long *, res) 517d7a4cb9bSAndrey Ignatov { 518d7a4cb9bSAndrey Ignatov long long _res; 519d7a4cb9bSAndrey Ignatov int err; 520d7a4cb9bSAndrey Ignatov 521d7a4cb9bSAndrey Ignatov err = __bpf_strtoll(buf, buf_len, flags, &_res); 522d7a4cb9bSAndrey Ignatov if (err < 0) 523d7a4cb9bSAndrey Ignatov return err; 524d7a4cb9bSAndrey Ignatov if (_res != (long)_res) 525d7a4cb9bSAndrey Ignatov return -ERANGE; 526d7a4cb9bSAndrey Ignatov *res = _res; 527d7a4cb9bSAndrey Ignatov return err; 528d7a4cb9bSAndrey Ignatov } 529d7a4cb9bSAndrey Ignatov 530d7a4cb9bSAndrey Ignatov const struct bpf_func_proto bpf_strtol_proto = { 531d7a4cb9bSAndrey Ignatov .func = bpf_strtol, 532d7a4cb9bSAndrey Ignatov .gpl_only = false, 533d7a4cb9bSAndrey Ignatov .ret_type = RET_INTEGER, 534d7a4cb9bSAndrey Ignatov .arg1_type = ARG_PTR_TO_MEM, 535d7a4cb9bSAndrey Ignatov .arg2_type = ARG_CONST_SIZE, 536d7a4cb9bSAndrey Ignatov .arg3_type = ARG_ANYTHING, 537d7a4cb9bSAndrey Ignatov .arg4_type = ARG_PTR_TO_LONG, 538d7a4cb9bSAndrey Ignatov }; 539d7a4cb9bSAndrey Ignatov 540d7a4cb9bSAndrey Ignatov BPF_CALL_4(bpf_strtoul, const char *, buf, size_t, buf_len, u64, flags, 541d7a4cb9bSAndrey Ignatov unsigned long *, res) 542d7a4cb9bSAndrey Ignatov { 543d7a4cb9bSAndrey Ignatov unsigned long long _res; 544d7a4cb9bSAndrey Ignatov bool is_negative; 545d7a4cb9bSAndrey Ignatov int err; 546d7a4cb9bSAndrey Ignatov 547d7a4cb9bSAndrey Ignatov err = __bpf_strtoull(buf, buf_len, flags, &_res, &is_negative); 548d7a4cb9bSAndrey Ignatov if (err < 0) 549d7a4cb9bSAndrey Ignatov return err; 550d7a4cb9bSAndrey Ignatov if (is_negative) 551d7a4cb9bSAndrey Ignatov return -EINVAL; 552d7a4cb9bSAndrey Ignatov if (_res != (unsigned long)_res) 553d7a4cb9bSAndrey Ignatov return -ERANGE; 554d7a4cb9bSAndrey Ignatov *res = _res; 555d7a4cb9bSAndrey Ignatov return err; 556d7a4cb9bSAndrey Ignatov } 557d7a4cb9bSAndrey Ignatov 558d7a4cb9bSAndrey Ignatov const struct bpf_func_proto bpf_strtoul_proto = { 559d7a4cb9bSAndrey Ignatov .func = bpf_strtoul, 560d7a4cb9bSAndrey Ignatov .gpl_only = false, 561d7a4cb9bSAndrey Ignatov .ret_type = RET_INTEGER, 562d7a4cb9bSAndrey Ignatov .arg1_type = ARG_PTR_TO_MEM, 563d7a4cb9bSAndrey Ignatov .arg2_type = ARG_CONST_SIZE, 564d7a4cb9bSAndrey Ignatov .arg3_type = ARG_ANYTHING, 565d7a4cb9bSAndrey Ignatov .arg4_type = ARG_PTR_TO_LONG, 566d7a4cb9bSAndrey Ignatov }; 5678bad74f9SRoman Gushchin #endif 568b4490c5cSCarlos Neira 569c5fb1993SHou Tao BPF_CALL_3(bpf_strncmp, const char *, s1, u32, s1_sz, const char *, s2) 570c5fb1993SHou Tao { 571c5fb1993SHou Tao return strncmp(s1, s2, s1_sz); 572c5fb1993SHou Tao } 573c5fb1993SHou Tao 574c5fb1993SHou Tao const struct bpf_func_proto bpf_strncmp_proto = { 575c5fb1993SHou Tao .func = bpf_strncmp, 576c5fb1993SHou Tao .gpl_only = false, 577c5fb1993SHou Tao .ret_type = RET_INTEGER, 578c5fb1993SHou Tao .arg1_type = ARG_PTR_TO_MEM, 579c5fb1993SHou Tao .arg2_type = ARG_CONST_SIZE, 580c5fb1993SHou Tao .arg3_type = ARG_PTR_TO_CONST_STR, 581c5fb1993SHou Tao }; 582c5fb1993SHou Tao 583b4490c5cSCarlos Neira BPF_CALL_4(bpf_get_ns_current_pid_tgid, u64, dev, u64, ino, 584b4490c5cSCarlos Neira struct bpf_pidns_info *, nsdata, u32, size) 585b4490c5cSCarlos Neira { 586b4490c5cSCarlos Neira struct task_struct *task = current; 587b4490c5cSCarlos Neira struct pid_namespace *pidns; 588b4490c5cSCarlos Neira int err = -EINVAL; 589b4490c5cSCarlos Neira 590b4490c5cSCarlos Neira if (unlikely(size != sizeof(struct bpf_pidns_info))) 591b4490c5cSCarlos Neira goto clear; 592b4490c5cSCarlos Neira 593b4490c5cSCarlos Neira if (unlikely((u64)(dev_t)dev != dev)) 594b4490c5cSCarlos Neira goto clear; 595b4490c5cSCarlos Neira 596b4490c5cSCarlos Neira if (unlikely(!task)) 597b4490c5cSCarlos Neira goto clear; 598b4490c5cSCarlos Neira 599b4490c5cSCarlos Neira pidns = task_active_pid_ns(task); 600b4490c5cSCarlos Neira if (unlikely(!pidns)) { 601b4490c5cSCarlos Neira err = -ENOENT; 602b4490c5cSCarlos Neira goto clear; 603b4490c5cSCarlos Neira } 604b4490c5cSCarlos Neira 605b4490c5cSCarlos Neira if (!ns_match(&pidns->ns, (dev_t)dev, ino)) 606b4490c5cSCarlos Neira goto clear; 607b4490c5cSCarlos Neira 608b4490c5cSCarlos Neira nsdata->pid = task_pid_nr_ns(task, pidns); 609b4490c5cSCarlos Neira nsdata->tgid = task_tgid_nr_ns(task, pidns); 610b4490c5cSCarlos Neira return 0; 611b4490c5cSCarlos Neira clear: 612b4490c5cSCarlos Neira memset((void *)nsdata, 0, (size_t) size); 613b4490c5cSCarlos Neira return err; 614b4490c5cSCarlos Neira } 615b4490c5cSCarlos Neira 616b4490c5cSCarlos Neira const struct bpf_func_proto bpf_get_ns_current_pid_tgid_proto = { 617b4490c5cSCarlos Neira .func = bpf_get_ns_current_pid_tgid, 618b4490c5cSCarlos Neira .gpl_only = false, 619b4490c5cSCarlos Neira .ret_type = RET_INTEGER, 620b4490c5cSCarlos Neira .arg1_type = ARG_ANYTHING, 621b4490c5cSCarlos Neira .arg2_type = ARG_ANYTHING, 622b4490c5cSCarlos Neira .arg3_type = ARG_PTR_TO_UNINIT_MEM, 623b4490c5cSCarlos Neira .arg4_type = ARG_CONST_SIZE, 624b4490c5cSCarlos Neira }; 6256890896bSStanislav Fomichev 6266890896bSStanislav Fomichev static const struct bpf_func_proto bpf_get_raw_smp_processor_id_proto = { 6276890896bSStanislav Fomichev .func = bpf_get_raw_cpu_id, 6286890896bSStanislav Fomichev .gpl_only = false, 6296890896bSStanislav Fomichev .ret_type = RET_INTEGER, 6306890896bSStanislav Fomichev }; 6316890896bSStanislav Fomichev 6326890896bSStanislav Fomichev BPF_CALL_5(bpf_event_output_data, void *, ctx, struct bpf_map *, map, 6336890896bSStanislav Fomichev u64, flags, void *, data, u64, size) 6346890896bSStanislav Fomichev { 6356890896bSStanislav Fomichev if (unlikely(flags & ~(BPF_F_INDEX_MASK))) 6366890896bSStanislav Fomichev return -EINVAL; 6376890896bSStanislav Fomichev 6386890896bSStanislav Fomichev return bpf_event_output(map, flags, data, size, NULL, 0, NULL); 6396890896bSStanislav Fomichev } 6406890896bSStanislav Fomichev 6416890896bSStanislav Fomichev const struct bpf_func_proto bpf_event_output_data_proto = { 6426890896bSStanislav Fomichev .func = bpf_event_output_data, 6436890896bSStanislav Fomichev .gpl_only = true, 6446890896bSStanislav Fomichev .ret_type = RET_INTEGER, 6456890896bSStanislav Fomichev .arg1_type = ARG_PTR_TO_CTX, 6466890896bSStanislav Fomichev .arg2_type = ARG_CONST_MAP_PTR, 6476890896bSStanislav Fomichev .arg3_type = ARG_ANYTHING, 6486890896bSStanislav Fomichev .arg4_type = ARG_PTR_TO_MEM, 6496890896bSStanislav Fomichev .arg5_type = ARG_CONST_SIZE_OR_ZERO, 6506890896bSStanislav Fomichev }; 6516890896bSStanislav Fomichev 65207be4c4aSAlexei Starovoitov BPF_CALL_3(bpf_copy_from_user, void *, dst, u32, size, 65307be4c4aSAlexei Starovoitov const void __user *, user_ptr) 65407be4c4aSAlexei Starovoitov { 65507be4c4aSAlexei Starovoitov int ret = copy_from_user(dst, user_ptr, size); 65607be4c4aSAlexei Starovoitov 65707be4c4aSAlexei Starovoitov if (unlikely(ret)) { 65807be4c4aSAlexei Starovoitov memset(dst, 0, size); 65907be4c4aSAlexei Starovoitov ret = -EFAULT; 66007be4c4aSAlexei Starovoitov } 66107be4c4aSAlexei Starovoitov 66207be4c4aSAlexei Starovoitov return ret; 66307be4c4aSAlexei Starovoitov } 66407be4c4aSAlexei Starovoitov 66507be4c4aSAlexei Starovoitov const struct bpf_func_proto bpf_copy_from_user_proto = { 66607be4c4aSAlexei Starovoitov .func = bpf_copy_from_user, 66707be4c4aSAlexei Starovoitov .gpl_only = false, 66807be4c4aSAlexei Starovoitov .ret_type = RET_INTEGER, 66907be4c4aSAlexei Starovoitov .arg1_type = ARG_PTR_TO_UNINIT_MEM, 67007be4c4aSAlexei Starovoitov .arg2_type = ARG_CONST_SIZE_OR_ZERO, 67107be4c4aSAlexei Starovoitov .arg3_type = ARG_ANYTHING, 67207be4c4aSAlexei Starovoitov }; 67307be4c4aSAlexei Starovoitov 674eaa6bcb7SHao Luo BPF_CALL_2(bpf_per_cpu_ptr, const void *, ptr, u32, cpu) 675eaa6bcb7SHao Luo { 676eaa6bcb7SHao Luo if (cpu >= nr_cpu_ids) 677eaa6bcb7SHao Luo return (unsigned long)NULL; 678eaa6bcb7SHao Luo 679eaa6bcb7SHao Luo return (unsigned long)per_cpu_ptr((const void __percpu *)ptr, cpu); 680eaa6bcb7SHao Luo } 681eaa6bcb7SHao Luo 682eaa6bcb7SHao Luo const struct bpf_func_proto bpf_per_cpu_ptr_proto = { 683eaa6bcb7SHao Luo .func = bpf_per_cpu_ptr, 684eaa6bcb7SHao Luo .gpl_only = false, 685*34d3a78cSHao Luo .ret_type = RET_PTR_TO_MEM_OR_BTF_ID | PTR_MAYBE_NULL | MEM_RDONLY, 686eaa6bcb7SHao Luo .arg1_type = ARG_PTR_TO_PERCPU_BTF_ID, 687eaa6bcb7SHao Luo .arg2_type = ARG_ANYTHING, 688eaa6bcb7SHao Luo }; 689eaa6bcb7SHao Luo 69063d9b80dSHao Luo BPF_CALL_1(bpf_this_cpu_ptr, const void *, percpu_ptr) 69163d9b80dSHao Luo { 69263d9b80dSHao Luo return (unsigned long)this_cpu_ptr((const void __percpu *)percpu_ptr); 69363d9b80dSHao Luo } 69463d9b80dSHao Luo 69563d9b80dSHao Luo const struct bpf_func_proto bpf_this_cpu_ptr_proto = { 69663d9b80dSHao Luo .func = bpf_this_cpu_ptr, 69763d9b80dSHao Luo .gpl_only = false, 698*34d3a78cSHao Luo .ret_type = RET_PTR_TO_MEM_OR_BTF_ID | MEM_RDONLY, 69963d9b80dSHao Luo .arg1_type = ARG_PTR_TO_PERCPU_BTF_ID, 70063d9b80dSHao Luo }; 70163d9b80dSHao Luo 702d9c9e4dbSFlorent Revest static int bpf_trace_copy_string(char *buf, void *unsafe_ptr, char fmt_ptype, 703d9c9e4dbSFlorent Revest size_t bufsz) 704d9c9e4dbSFlorent Revest { 705d9c9e4dbSFlorent Revest void __user *user_ptr = (__force void __user *)unsafe_ptr; 706d9c9e4dbSFlorent Revest 707d9c9e4dbSFlorent Revest buf[0] = 0; 708d9c9e4dbSFlorent Revest 709d9c9e4dbSFlorent Revest switch (fmt_ptype) { 710d9c9e4dbSFlorent Revest case 's': 711d9c9e4dbSFlorent Revest #ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE 712d9c9e4dbSFlorent Revest if ((unsigned long)unsafe_ptr < TASK_SIZE) 713d9c9e4dbSFlorent Revest return strncpy_from_user_nofault(buf, user_ptr, bufsz); 714d9c9e4dbSFlorent Revest fallthrough; 715d9c9e4dbSFlorent Revest #endif 716d9c9e4dbSFlorent Revest case 'k': 717d9c9e4dbSFlorent Revest return strncpy_from_kernel_nofault(buf, unsafe_ptr, bufsz); 718d9c9e4dbSFlorent Revest case 'u': 719d9c9e4dbSFlorent Revest return strncpy_from_user_nofault(buf, user_ptr, bufsz); 720d9c9e4dbSFlorent Revest } 721d9c9e4dbSFlorent Revest 722d9c9e4dbSFlorent Revest return -EINVAL; 723d9c9e4dbSFlorent Revest } 724d9c9e4dbSFlorent Revest 7258afcc19fSFlorent Revest /* Per-cpu temp buffers used by printf-like helpers to store the bprintf binary 7268afcc19fSFlorent Revest * arguments representation. 727d9c9e4dbSFlorent Revest */ 7288afcc19fSFlorent Revest #define MAX_BPRINTF_BUF_LEN 512 729d9c9e4dbSFlorent Revest 730e2d5b2bbSFlorent Revest /* Support executing three nested bprintf helper calls on a given CPU */ 7310af02eb2SFlorent Revest #define MAX_BPRINTF_NEST_LEVEL 3 732e2d5b2bbSFlorent Revest struct bpf_bprintf_buffers { 7330af02eb2SFlorent Revest char tmp_bufs[MAX_BPRINTF_NEST_LEVEL][MAX_BPRINTF_BUF_LEN]; 734d9c9e4dbSFlorent Revest }; 735e2d5b2bbSFlorent Revest static DEFINE_PER_CPU(struct bpf_bprintf_buffers, bpf_bprintf_bufs); 736e2d5b2bbSFlorent Revest static DEFINE_PER_CPU(int, bpf_bprintf_nest_level); 737d9c9e4dbSFlorent Revest 738d9c9e4dbSFlorent Revest static int try_get_fmt_tmp_buf(char **tmp_buf) 739d9c9e4dbSFlorent Revest { 740e2d5b2bbSFlorent Revest struct bpf_bprintf_buffers *bufs; 741e2d5b2bbSFlorent Revest int nest_level; 742d9c9e4dbSFlorent Revest 743d9c9e4dbSFlorent Revest preempt_disable(); 744e2d5b2bbSFlorent Revest nest_level = this_cpu_inc_return(bpf_bprintf_nest_level); 7450af02eb2SFlorent Revest if (WARN_ON_ONCE(nest_level > MAX_BPRINTF_NEST_LEVEL)) { 746e2d5b2bbSFlorent Revest this_cpu_dec(bpf_bprintf_nest_level); 747d9c9e4dbSFlorent Revest preempt_enable(); 748d9c9e4dbSFlorent Revest return -EBUSY; 749d9c9e4dbSFlorent Revest } 750e2d5b2bbSFlorent Revest bufs = this_cpu_ptr(&bpf_bprintf_bufs); 751e2d5b2bbSFlorent Revest *tmp_buf = bufs->tmp_bufs[nest_level - 1]; 752d9c9e4dbSFlorent Revest 753d9c9e4dbSFlorent Revest return 0; 754d9c9e4dbSFlorent Revest } 755d9c9e4dbSFlorent Revest 75648cac3f4SFlorent Revest void bpf_bprintf_cleanup(void) 757d9c9e4dbSFlorent Revest { 758e2d5b2bbSFlorent Revest if (this_cpu_read(bpf_bprintf_nest_level)) { 759e2d5b2bbSFlorent Revest this_cpu_dec(bpf_bprintf_nest_level); 760d9c9e4dbSFlorent Revest preempt_enable(); 761d9c9e4dbSFlorent Revest } 762d9c9e4dbSFlorent Revest } 763d9c9e4dbSFlorent Revest 764d9c9e4dbSFlorent Revest /* 76548cac3f4SFlorent Revest * bpf_bprintf_prepare - Generic pass on format strings for bprintf-like helpers 766d9c9e4dbSFlorent Revest * 767d9c9e4dbSFlorent Revest * Returns a negative value if fmt is an invalid format string or 0 otherwise. 768d9c9e4dbSFlorent Revest * 769d9c9e4dbSFlorent Revest * This can be used in two ways: 77048cac3f4SFlorent Revest * - Format string verification only: when bin_args is NULL 771d9c9e4dbSFlorent Revest * - Arguments preparation: in addition to the above verification, it writes in 77248cac3f4SFlorent Revest * bin_args a binary representation of arguments usable by bstr_printf where 77348cac3f4SFlorent Revest * pointers from BPF have been sanitized. 774d9c9e4dbSFlorent Revest * 775d9c9e4dbSFlorent Revest * In argument preparation mode, if 0 is returned, safe temporary buffers are 77648cac3f4SFlorent Revest * allocated and bpf_bprintf_cleanup should be called to free them after use. 777d9c9e4dbSFlorent Revest */ 77848cac3f4SFlorent Revest int bpf_bprintf_prepare(char *fmt, u32 fmt_size, const u64 *raw_args, 77948cac3f4SFlorent Revest u32 **bin_args, u32 num_args) 780d9c9e4dbSFlorent Revest { 78148cac3f4SFlorent Revest char *unsafe_ptr = NULL, *tmp_buf = NULL, *tmp_buf_end, *fmt_end; 78248cac3f4SFlorent Revest size_t sizeof_cur_arg, sizeof_cur_ip; 78348cac3f4SFlorent Revest int err, i, num_spec = 0; 784d9c9e4dbSFlorent Revest u64 cur_arg; 78548cac3f4SFlorent Revest char fmt_ptype, cur_ip[16], ip_spec[] = "%pXX"; 786d9c9e4dbSFlorent Revest 787d9c9e4dbSFlorent Revest fmt_end = strnchr(fmt, fmt_size, 0); 788d9c9e4dbSFlorent Revest if (!fmt_end) 789d9c9e4dbSFlorent Revest return -EINVAL; 790d9c9e4dbSFlorent Revest fmt_size = fmt_end - fmt; 791d9c9e4dbSFlorent Revest 79248cac3f4SFlorent Revest if (bin_args) { 79348cac3f4SFlorent Revest if (num_args && try_get_fmt_tmp_buf(&tmp_buf)) 79448cac3f4SFlorent Revest return -EBUSY; 79548cac3f4SFlorent Revest 7968afcc19fSFlorent Revest tmp_buf_end = tmp_buf + MAX_BPRINTF_BUF_LEN; 79748cac3f4SFlorent Revest *bin_args = (u32 *)tmp_buf; 79848cac3f4SFlorent Revest } 79948cac3f4SFlorent Revest 800d9c9e4dbSFlorent Revest for (i = 0; i < fmt_size; i++) { 801d9c9e4dbSFlorent Revest if ((!isprint(fmt[i]) && !isspace(fmt[i])) || !isascii(fmt[i])) { 802d9c9e4dbSFlorent Revest err = -EINVAL; 80348cac3f4SFlorent Revest goto out; 804d9c9e4dbSFlorent Revest } 805d9c9e4dbSFlorent Revest 806d9c9e4dbSFlorent Revest if (fmt[i] != '%') 807d9c9e4dbSFlorent Revest continue; 808d9c9e4dbSFlorent Revest 809d9c9e4dbSFlorent Revest if (fmt[i + 1] == '%') { 810d9c9e4dbSFlorent Revest i++; 811d9c9e4dbSFlorent Revest continue; 812d9c9e4dbSFlorent Revest } 813d9c9e4dbSFlorent Revest 814d9c9e4dbSFlorent Revest if (num_spec >= num_args) { 815d9c9e4dbSFlorent Revest err = -EINVAL; 81648cac3f4SFlorent Revest goto out; 817d9c9e4dbSFlorent Revest } 818d9c9e4dbSFlorent Revest 819d9c9e4dbSFlorent Revest /* The string is zero-terminated so if fmt[i] != 0, we can 820d9c9e4dbSFlorent Revest * always access fmt[i + 1], in the worst case it will be a 0 821d9c9e4dbSFlorent Revest */ 822d9c9e4dbSFlorent Revest i++; 823d9c9e4dbSFlorent Revest 824d9c9e4dbSFlorent Revest /* skip optional "[0 +-][num]" width formatting field */ 825d9c9e4dbSFlorent Revest while (fmt[i] == '0' || fmt[i] == '+' || fmt[i] == '-' || 826d9c9e4dbSFlorent Revest fmt[i] == ' ') 827d9c9e4dbSFlorent Revest i++; 828d9c9e4dbSFlorent Revest if (fmt[i] >= '1' && fmt[i] <= '9') { 829d9c9e4dbSFlorent Revest i++; 830d9c9e4dbSFlorent Revest while (fmt[i] >= '0' && fmt[i] <= '9') 831d9c9e4dbSFlorent Revest i++; 832d9c9e4dbSFlorent Revest } 833d9c9e4dbSFlorent Revest 834d9c9e4dbSFlorent Revest if (fmt[i] == 'p') { 83548cac3f4SFlorent Revest sizeof_cur_arg = sizeof(long); 836d9c9e4dbSFlorent Revest 837d9c9e4dbSFlorent Revest if ((fmt[i + 1] == 'k' || fmt[i + 1] == 'u') && 838d9c9e4dbSFlorent Revest fmt[i + 2] == 's') { 839d9c9e4dbSFlorent Revest fmt_ptype = fmt[i + 1]; 840d9c9e4dbSFlorent Revest i += 2; 841d9c9e4dbSFlorent Revest goto fmt_str; 842d9c9e4dbSFlorent Revest } 843d9c9e4dbSFlorent Revest 844d9c9e4dbSFlorent Revest if (fmt[i + 1] == 0 || isspace(fmt[i + 1]) || 845d9c9e4dbSFlorent Revest ispunct(fmt[i + 1]) || fmt[i + 1] == 'K' || 84648cac3f4SFlorent Revest fmt[i + 1] == 'x' || fmt[i + 1] == 's' || 84748cac3f4SFlorent Revest fmt[i + 1] == 'S') { 848d9c9e4dbSFlorent Revest /* just kernel pointers */ 84948cac3f4SFlorent Revest if (tmp_buf) 850d9c9e4dbSFlorent Revest cur_arg = raw_args[num_spec]; 85148cac3f4SFlorent Revest i++; 85248cac3f4SFlorent Revest goto nocopy_fmt; 85348cac3f4SFlorent Revest } 85448cac3f4SFlorent Revest 85548cac3f4SFlorent Revest if (fmt[i + 1] == 'B') { 85648cac3f4SFlorent Revest if (tmp_buf) { 85748cac3f4SFlorent Revest err = snprintf(tmp_buf, 85848cac3f4SFlorent Revest (tmp_buf_end - tmp_buf), 85948cac3f4SFlorent Revest "%pB", 86048cac3f4SFlorent Revest (void *)(long)raw_args[num_spec]); 86148cac3f4SFlorent Revest tmp_buf += (err + 1); 86248cac3f4SFlorent Revest } 86348cac3f4SFlorent Revest 86448cac3f4SFlorent Revest i++; 86548cac3f4SFlorent Revest num_spec++; 86648cac3f4SFlorent Revest continue; 867d9c9e4dbSFlorent Revest } 868d9c9e4dbSFlorent Revest 869d9c9e4dbSFlorent Revest /* only support "%pI4", "%pi4", "%pI6" and "%pi6". */ 870d9c9e4dbSFlorent Revest if ((fmt[i + 1] != 'i' && fmt[i + 1] != 'I') || 871d9c9e4dbSFlorent Revest (fmt[i + 2] != '4' && fmt[i + 2] != '6')) { 872d9c9e4dbSFlorent Revest err = -EINVAL; 873d9c9e4dbSFlorent Revest goto out; 874d9c9e4dbSFlorent Revest } 875d9c9e4dbSFlorent Revest 87648cac3f4SFlorent Revest i += 2; 87748cac3f4SFlorent Revest if (!tmp_buf) 87848cac3f4SFlorent Revest goto nocopy_fmt; 87948cac3f4SFlorent Revest 88048cac3f4SFlorent Revest sizeof_cur_ip = (fmt[i] == '4') ? 4 : 16; 88148cac3f4SFlorent Revest if (tmp_buf_end - tmp_buf < sizeof_cur_ip) { 882d9c9e4dbSFlorent Revest err = -ENOSPC; 88348cac3f4SFlorent Revest goto out; 884d9c9e4dbSFlorent Revest } 885d9c9e4dbSFlorent Revest 886d9c9e4dbSFlorent Revest unsafe_ptr = (char *)(long)raw_args[num_spec]; 88748cac3f4SFlorent Revest err = copy_from_kernel_nofault(cur_ip, unsafe_ptr, 88848cac3f4SFlorent Revest sizeof_cur_ip); 889d9c9e4dbSFlorent Revest if (err < 0) 89048cac3f4SFlorent Revest memset(cur_ip, 0, sizeof_cur_ip); 891d9c9e4dbSFlorent Revest 89248cac3f4SFlorent Revest /* hack: bstr_printf expects IP addresses to be 89348cac3f4SFlorent Revest * pre-formatted as strings, ironically, the easiest way 89448cac3f4SFlorent Revest * to do that is to call snprintf. 89548cac3f4SFlorent Revest */ 89648cac3f4SFlorent Revest ip_spec[2] = fmt[i - 1]; 89748cac3f4SFlorent Revest ip_spec[3] = fmt[i]; 89848cac3f4SFlorent Revest err = snprintf(tmp_buf, tmp_buf_end - tmp_buf, 89948cac3f4SFlorent Revest ip_spec, &cur_ip); 90048cac3f4SFlorent Revest 90148cac3f4SFlorent Revest tmp_buf += err + 1; 90248cac3f4SFlorent Revest num_spec++; 90348cac3f4SFlorent Revest 90448cac3f4SFlorent Revest continue; 905d9c9e4dbSFlorent Revest } else if (fmt[i] == 's') { 906d9c9e4dbSFlorent Revest fmt_ptype = fmt[i]; 907d9c9e4dbSFlorent Revest fmt_str: 908d9c9e4dbSFlorent Revest if (fmt[i + 1] != 0 && 909d9c9e4dbSFlorent Revest !isspace(fmt[i + 1]) && 910d9c9e4dbSFlorent Revest !ispunct(fmt[i + 1])) { 911d9c9e4dbSFlorent Revest err = -EINVAL; 912d9c9e4dbSFlorent Revest goto out; 913d9c9e4dbSFlorent Revest } 914d9c9e4dbSFlorent Revest 91548cac3f4SFlorent Revest if (!tmp_buf) 91648cac3f4SFlorent Revest goto nocopy_fmt; 91748cac3f4SFlorent Revest 91848cac3f4SFlorent Revest if (tmp_buf_end == tmp_buf) { 919d9c9e4dbSFlorent Revest err = -ENOSPC; 92048cac3f4SFlorent Revest goto out; 921d9c9e4dbSFlorent Revest } 922d9c9e4dbSFlorent Revest 923d9c9e4dbSFlorent Revest unsafe_ptr = (char *)(long)raw_args[num_spec]; 924d9c9e4dbSFlorent Revest err = bpf_trace_copy_string(tmp_buf, unsafe_ptr, 92548cac3f4SFlorent Revest fmt_ptype, 92648cac3f4SFlorent Revest tmp_buf_end - tmp_buf); 927d9c9e4dbSFlorent Revest if (err < 0) { 928d9c9e4dbSFlorent Revest tmp_buf[0] = '\0'; 929d9c9e4dbSFlorent Revest err = 1; 930d9c9e4dbSFlorent Revest } 931d9c9e4dbSFlorent Revest 932d9c9e4dbSFlorent Revest tmp_buf += err; 93348cac3f4SFlorent Revest num_spec++; 934d9c9e4dbSFlorent Revest 93548cac3f4SFlorent Revest continue; 9363478cfcfSKuniyuki Iwashima } else if (fmt[i] == 'c') { 9373478cfcfSKuniyuki Iwashima if (!tmp_buf) 9383478cfcfSKuniyuki Iwashima goto nocopy_fmt; 9393478cfcfSKuniyuki Iwashima 9403478cfcfSKuniyuki Iwashima if (tmp_buf_end == tmp_buf) { 9413478cfcfSKuniyuki Iwashima err = -ENOSPC; 9423478cfcfSKuniyuki Iwashima goto out; 9433478cfcfSKuniyuki Iwashima } 9443478cfcfSKuniyuki Iwashima 9453478cfcfSKuniyuki Iwashima *tmp_buf = raw_args[num_spec]; 9463478cfcfSKuniyuki Iwashima tmp_buf++; 9473478cfcfSKuniyuki Iwashima num_spec++; 9483478cfcfSKuniyuki Iwashima 9493478cfcfSKuniyuki Iwashima continue; 950d9c9e4dbSFlorent Revest } 951d9c9e4dbSFlorent Revest 95248cac3f4SFlorent Revest sizeof_cur_arg = sizeof(int); 953d9c9e4dbSFlorent Revest 954d9c9e4dbSFlorent Revest if (fmt[i] == 'l') { 95548cac3f4SFlorent Revest sizeof_cur_arg = sizeof(long); 956d9c9e4dbSFlorent Revest i++; 957d9c9e4dbSFlorent Revest } 958d9c9e4dbSFlorent Revest if (fmt[i] == 'l') { 95948cac3f4SFlorent Revest sizeof_cur_arg = sizeof(long long); 960d9c9e4dbSFlorent Revest i++; 961d9c9e4dbSFlorent Revest } 962d9c9e4dbSFlorent Revest 963d9c9e4dbSFlorent Revest if (fmt[i] != 'i' && fmt[i] != 'd' && fmt[i] != 'u' && 964d9c9e4dbSFlorent Revest fmt[i] != 'x' && fmt[i] != 'X') { 965d9c9e4dbSFlorent Revest err = -EINVAL; 96648cac3f4SFlorent Revest goto out; 967d9c9e4dbSFlorent Revest } 968d9c9e4dbSFlorent Revest 96948cac3f4SFlorent Revest if (tmp_buf) 970d9c9e4dbSFlorent Revest cur_arg = raw_args[num_spec]; 97148cac3f4SFlorent Revest nocopy_fmt: 97248cac3f4SFlorent Revest if (tmp_buf) { 97348cac3f4SFlorent Revest tmp_buf = PTR_ALIGN(tmp_buf, sizeof(u32)); 97448cac3f4SFlorent Revest if (tmp_buf_end - tmp_buf < sizeof_cur_arg) { 97548cac3f4SFlorent Revest err = -ENOSPC; 97648cac3f4SFlorent Revest goto out; 97748cac3f4SFlorent Revest } 97848cac3f4SFlorent Revest 97948cac3f4SFlorent Revest if (sizeof_cur_arg == 8) { 98048cac3f4SFlorent Revest *(u32 *)tmp_buf = *(u32 *)&cur_arg; 98148cac3f4SFlorent Revest *(u32 *)(tmp_buf + 4) = *((u32 *)&cur_arg + 1); 98248cac3f4SFlorent Revest } else { 98348cac3f4SFlorent Revest *(u32 *)tmp_buf = (u32)(long)cur_arg; 98448cac3f4SFlorent Revest } 98548cac3f4SFlorent Revest tmp_buf += sizeof_cur_arg; 986d9c9e4dbSFlorent Revest } 987d9c9e4dbSFlorent Revest num_spec++; 988d9c9e4dbSFlorent Revest } 989d9c9e4dbSFlorent Revest 990d9c9e4dbSFlorent Revest err = 0; 991d9c9e4dbSFlorent Revest out: 99248cac3f4SFlorent Revest if (err) 99348cac3f4SFlorent Revest bpf_bprintf_cleanup(); 994d9c9e4dbSFlorent Revest return err; 995d9c9e4dbSFlorent Revest } 996d9c9e4dbSFlorent Revest 9977b15523aSFlorent Revest BPF_CALL_5(bpf_snprintf, char *, str, u32, str_size, char *, fmt, 9987b15523aSFlorent Revest const void *, data, u32, data_len) 9997b15523aSFlorent Revest { 10007b15523aSFlorent Revest int err, num_args; 100148cac3f4SFlorent Revest u32 *bin_args; 10027b15523aSFlorent Revest 1003335ff499SDave Marchevsky if (data_len % 8 || data_len > MAX_BPRINTF_VARARGS * 8 || 10047b15523aSFlorent Revest (data_len && !data)) 10057b15523aSFlorent Revest return -EINVAL; 10067b15523aSFlorent Revest num_args = data_len / 8; 10077b15523aSFlorent Revest 10087b15523aSFlorent Revest /* ARG_PTR_TO_CONST_STR guarantees that fmt is zero-terminated so we 10097b15523aSFlorent Revest * can safely give an unbounded size. 10107b15523aSFlorent Revest */ 101148cac3f4SFlorent Revest err = bpf_bprintf_prepare(fmt, UINT_MAX, data, &bin_args, num_args); 10127b15523aSFlorent Revest if (err < 0) 10137b15523aSFlorent Revest return err; 10147b15523aSFlorent Revest 101548cac3f4SFlorent Revest err = bstr_printf(str, str_size, fmt, bin_args); 10167b15523aSFlorent Revest 101748cac3f4SFlorent Revest bpf_bprintf_cleanup(); 10187b15523aSFlorent Revest 10197b15523aSFlorent Revest return err + 1; 10207b15523aSFlorent Revest } 10217b15523aSFlorent Revest 10227b15523aSFlorent Revest const struct bpf_func_proto bpf_snprintf_proto = { 10237b15523aSFlorent Revest .func = bpf_snprintf, 10247b15523aSFlorent Revest .gpl_only = true, 10257b15523aSFlorent Revest .ret_type = RET_INTEGER, 10267b15523aSFlorent Revest .arg1_type = ARG_PTR_TO_MEM_OR_NULL, 10277b15523aSFlorent Revest .arg2_type = ARG_CONST_SIZE_OR_ZERO, 10287b15523aSFlorent Revest .arg3_type = ARG_PTR_TO_CONST_STR, 10297b15523aSFlorent Revest .arg4_type = ARG_PTR_TO_MEM_OR_NULL, 10307b15523aSFlorent Revest .arg5_type = ARG_CONST_SIZE_OR_ZERO, 10317b15523aSFlorent Revest }; 10327b15523aSFlorent Revest 1033b00628b1SAlexei Starovoitov /* BPF map elements can contain 'struct bpf_timer'. 1034b00628b1SAlexei Starovoitov * Such map owns all of its BPF timers. 1035b00628b1SAlexei Starovoitov * 'struct bpf_timer' is allocated as part of map element allocation 1036b00628b1SAlexei Starovoitov * and it's zero initialized. 1037b00628b1SAlexei Starovoitov * That space is used to keep 'struct bpf_timer_kern'. 1038b00628b1SAlexei Starovoitov * bpf_timer_init() allocates 'struct bpf_hrtimer', inits hrtimer, and 1039b00628b1SAlexei Starovoitov * remembers 'struct bpf_map *' pointer it's part of. 1040b00628b1SAlexei Starovoitov * bpf_timer_set_callback() increments prog refcnt and assign bpf callback_fn. 1041b00628b1SAlexei Starovoitov * bpf_timer_start() arms the timer. 1042b00628b1SAlexei Starovoitov * If user space reference to a map goes to zero at this point 1043b00628b1SAlexei Starovoitov * ops->map_release_uref callback is responsible for cancelling the timers, 1044b00628b1SAlexei Starovoitov * freeing their memory, and decrementing prog's refcnts. 1045b00628b1SAlexei Starovoitov * bpf_timer_cancel() cancels the timer and decrements prog's refcnt. 1046b00628b1SAlexei Starovoitov * Inner maps can contain bpf timers as well. ops->map_release_uref is 1047b00628b1SAlexei Starovoitov * freeing the timers when inner map is replaced or deleted by user space. 1048b00628b1SAlexei Starovoitov */ 1049b00628b1SAlexei Starovoitov struct bpf_hrtimer { 1050b00628b1SAlexei Starovoitov struct hrtimer timer; 1051b00628b1SAlexei Starovoitov struct bpf_map *map; 1052b00628b1SAlexei Starovoitov struct bpf_prog *prog; 1053b00628b1SAlexei Starovoitov void __rcu *callback_fn; 1054b00628b1SAlexei Starovoitov void *value; 1055b00628b1SAlexei Starovoitov }; 1056b00628b1SAlexei Starovoitov 1057b00628b1SAlexei Starovoitov /* the actual struct hidden inside uapi struct bpf_timer */ 1058b00628b1SAlexei Starovoitov struct bpf_timer_kern { 1059b00628b1SAlexei Starovoitov struct bpf_hrtimer *timer; 1060b00628b1SAlexei Starovoitov /* bpf_spin_lock is used here instead of spinlock_t to make 1061b00628b1SAlexei Starovoitov * sure that it always fits into space resereved by struct bpf_timer 1062b00628b1SAlexei Starovoitov * regardless of LOCKDEP and spinlock debug flags. 1063b00628b1SAlexei Starovoitov */ 1064b00628b1SAlexei Starovoitov struct bpf_spin_lock lock; 1065b00628b1SAlexei Starovoitov } __attribute__((aligned(8))); 1066b00628b1SAlexei Starovoitov 1067b00628b1SAlexei Starovoitov static DEFINE_PER_CPU(struct bpf_hrtimer *, hrtimer_running); 1068b00628b1SAlexei Starovoitov 1069b00628b1SAlexei Starovoitov static enum hrtimer_restart bpf_timer_cb(struct hrtimer *hrtimer) 1070b00628b1SAlexei Starovoitov { 1071b00628b1SAlexei Starovoitov struct bpf_hrtimer *t = container_of(hrtimer, struct bpf_hrtimer, timer); 1072b00628b1SAlexei Starovoitov struct bpf_map *map = t->map; 1073b00628b1SAlexei Starovoitov void *value = t->value; 1074102acbacSKees Cook bpf_callback_t callback_fn; 1075b00628b1SAlexei Starovoitov void *key; 1076b00628b1SAlexei Starovoitov u32 idx; 1077b00628b1SAlexei Starovoitov 1078b00628b1SAlexei Starovoitov callback_fn = rcu_dereference_check(t->callback_fn, rcu_read_lock_bh_held()); 1079b00628b1SAlexei Starovoitov if (!callback_fn) 1080b00628b1SAlexei Starovoitov goto out; 1081b00628b1SAlexei Starovoitov 1082b00628b1SAlexei Starovoitov /* bpf_timer_cb() runs in hrtimer_run_softirq. It doesn't migrate and 1083b00628b1SAlexei Starovoitov * cannot be preempted by another bpf_timer_cb() on the same cpu. 1084b00628b1SAlexei Starovoitov * Remember the timer this callback is servicing to prevent 1085b00628b1SAlexei Starovoitov * deadlock if callback_fn() calls bpf_timer_cancel() or 1086b00628b1SAlexei Starovoitov * bpf_map_delete_elem() on the same timer. 1087b00628b1SAlexei Starovoitov */ 1088b00628b1SAlexei Starovoitov this_cpu_write(hrtimer_running, t); 1089b00628b1SAlexei Starovoitov if (map->map_type == BPF_MAP_TYPE_ARRAY) { 1090b00628b1SAlexei Starovoitov struct bpf_array *array = container_of(map, struct bpf_array, map); 1091b00628b1SAlexei Starovoitov 1092b00628b1SAlexei Starovoitov /* compute the key */ 1093b00628b1SAlexei Starovoitov idx = ((char *)value - array->value) / array->elem_size; 1094b00628b1SAlexei Starovoitov key = &idx; 1095b00628b1SAlexei Starovoitov } else { /* hash or lru */ 1096b00628b1SAlexei Starovoitov key = value - round_up(map->key_size, 8); 1097b00628b1SAlexei Starovoitov } 1098b00628b1SAlexei Starovoitov 1099102acbacSKees Cook callback_fn((u64)(long)map, (u64)(long)key, (u64)(long)value, 0, 0); 1100bfc6bb74SAlexei Starovoitov /* The verifier checked that return value is zero. */ 1101b00628b1SAlexei Starovoitov 1102b00628b1SAlexei Starovoitov this_cpu_write(hrtimer_running, NULL); 1103b00628b1SAlexei Starovoitov out: 1104b00628b1SAlexei Starovoitov return HRTIMER_NORESTART; 1105b00628b1SAlexei Starovoitov } 1106b00628b1SAlexei Starovoitov 1107b00628b1SAlexei Starovoitov BPF_CALL_3(bpf_timer_init, struct bpf_timer_kern *, timer, struct bpf_map *, map, 1108b00628b1SAlexei Starovoitov u64, flags) 1109b00628b1SAlexei Starovoitov { 1110b00628b1SAlexei Starovoitov clockid_t clockid = flags & (MAX_CLOCKS - 1); 1111b00628b1SAlexei Starovoitov struct bpf_hrtimer *t; 1112b00628b1SAlexei Starovoitov int ret = 0; 1113b00628b1SAlexei Starovoitov 1114b00628b1SAlexei Starovoitov BUILD_BUG_ON(MAX_CLOCKS != 16); 1115b00628b1SAlexei Starovoitov BUILD_BUG_ON(sizeof(struct bpf_timer_kern) > sizeof(struct bpf_timer)); 1116b00628b1SAlexei Starovoitov BUILD_BUG_ON(__alignof__(struct bpf_timer_kern) != __alignof__(struct bpf_timer)); 1117b00628b1SAlexei Starovoitov 1118b00628b1SAlexei Starovoitov if (in_nmi()) 1119b00628b1SAlexei Starovoitov return -EOPNOTSUPP; 1120b00628b1SAlexei Starovoitov 1121b00628b1SAlexei Starovoitov if (flags >= MAX_CLOCKS || 1122b00628b1SAlexei Starovoitov /* similar to timerfd except _ALARM variants are not supported */ 1123b00628b1SAlexei Starovoitov (clockid != CLOCK_MONOTONIC && 1124b00628b1SAlexei Starovoitov clockid != CLOCK_REALTIME && 1125b00628b1SAlexei Starovoitov clockid != CLOCK_BOOTTIME)) 1126b00628b1SAlexei Starovoitov return -EINVAL; 1127b00628b1SAlexei Starovoitov __bpf_spin_lock_irqsave(&timer->lock); 1128b00628b1SAlexei Starovoitov t = timer->timer; 1129b00628b1SAlexei Starovoitov if (t) { 1130b00628b1SAlexei Starovoitov ret = -EBUSY; 1131b00628b1SAlexei Starovoitov goto out; 1132b00628b1SAlexei Starovoitov } 1133b00628b1SAlexei Starovoitov if (!atomic64_read(&map->usercnt)) { 1134b00628b1SAlexei Starovoitov /* maps with timers must be either held by user space 1135b00628b1SAlexei Starovoitov * or pinned in bpffs. 1136b00628b1SAlexei Starovoitov */ 1137b00628b1SAlexei Starovoitov ret = -EPERM; 1138b00628b1SAlexei Starovoitov goto out; 1139b00628b1SAlexei Starovoitov } 1140b00628b1SAlexei Starovoitov /* allocate hrtimer via map_kmalloc to use memcg accounting */ 1141b00628b1SAlexei Starovoitov t = bpf_map_kmalloc_node(map, sizeof(*t), GFP_ATOMIC, map->numa_node); 1142b00628b1SAlexei Starovoitov if (!t) { 1143b00628b1SAlexei Starovoitov ret = -ENOMEM; 1144b00628b1SAlexei Starovoitov goto out; 1145b00628b1SAlexei Starovoitov } 1146b00628b1SAlexei Starovoitov t->value = (void *)timer - map->timer_off; 1147b00628b1SAlexei Starovoitov t->map = map; 1148b00628b1SAlexei Starovoitov t->prog = NULL; 1149b00628b1SAlexei Starovoitov rcu_assign_pointer(t->callback_fn, NULL); 1150b00628b1SAlexei Starovoitov hrtimer_init(&t->timer, clockid, HRTIMER_MODE_REL_SOFT); 1151b00628b1SAlexei Starovoitov t->timer.function = bpf_timer_cb; 1152b00628b1SAlexei Starovoitov timer->timer = t; 1153b00628b1SAlexei Starovoitov out: 1154b00628b1SAlexei Starovoitov __bpf_spin_unlock_irqrestore(&timer->lock); 1155b00628b1SAlexei Starovoitov return ret; 1156b00628b1SAlexei Starovoitov } 1157b00628b1SAlexei Starovoitov 1158b00628b1SAlexei Starovoitov static const struct bpf_func_proto bpf_timer_init_proto = { 1159b00628b1SAlexei Starovoitov .func = bpf_timer_init, 1160b00628b1SAlexei Starovoitov .gpl_only = true, 1161b00628b1SAlexei Starovoitov .ret_type = RET_INTEGER, 1162b00628b1SAlexei Starovoitov .arg1_type = ARG_PTR_TO_TIMER, 1163b00628b1SAlexei Starovoitov .arg2_type = ARG_CONST_MAP_PTR, 1164b00628b1SAlexei Starovoitov .arg3_type = ARG_ANYTHING, 1165b00628b1SAlexei Starovoitov }; 1166b00628b1SAlexei Starovoitov 1167b00628b1SAlexei Starovoitov BPF_CALL_3(bpf_timer_set_callback, struct bpf_timer_kern *, timer, void *, callback_fn, 1168b00628b1SAlexei Starovoitov struct bpf_prog_aux *, aux) 1169b00628b1SAlexei Starovoitov { 1170b00628b1SAlexei Starovoitov struct bpf_prog *prev, *prog = aux->prog; 1171b00628b1SAlexei Starovoitov struct bpf_hrtimer *t; 1172b00628b1SAlexei Starovoitov int ret = 0; 1173b00628b1SAlexei Starovoitov 1174b00628b1SAlexei Starovoitov if (in_nmi()) 1175b00628b1SAlexei Starovoitov return -EOPNOTSUPP; 1176b00628b1SAlexei Starovoitov __bpf_spin_lock_irqsave(&timer->lock); 1177b00628b1SAlexei Starovoitov t = timer->timer; 1178b00628b1SAlexei Starovoitov if (!t) { 1179b00628b1SAlexei Starovoitov ret = -EINVAL; 1180b00628b1SAlexei Starovoitov goto out; 1181b00628b1SAlexei Starovoitov } 1182b00628b1SAlexei Starovoitov if (!atomic64_read(&t->map->usercnt)) { 1183b00628b1SAlexei Starovoitov /* maps with timers must be either held by user space 1184b00628b1SAlexei Starovoitov * or pinned in bpffs. Otherwise timer might still be 1185b00628b1SAlexei Starovoitov * running even when bpf prog is detached and user space 1186b00628b1SAlexei Starovoitov * is gone, since map_release_uref won't ever be called. 1187b00628b1SAlexei Starovoitov */ 1188b00628b1SAlexei Starovoitov ret = -EPERM; 1189b00628b1SAlexei Starovoitov goto out; 1190b00628b1SAlexei Starovoitov } 1191b00628b1SAlexei Starovoitov prev = t->prog; 1192b00628b1SAlexei Starovoitov if (prev != prog) { 1193b00628b1SAlexei Starovoitov /* Bump prog refcnt once. Every bpf_timer_set_callback() 1194b00628b1SAlexei Starovoitov * can pick different callback_fn-s within the same prog. 1195b00628b1SAlexei Starovoitov */ 1196b00628b1SAlexei Starovoitov prog = bpf_prog_inc_not_zero(prog); 1197b00628b1SAlexei Starovoitov if (IS_ERR(prog)) { 1198b00628b1SAlexei Starovoitov ret = PTR_ERR(prog); 1199b00628b1SAlexei Starovoitov goto out; 1200b00628b1SAlexei Starovoitov } 1201b00628b1SAlexei Starovoitov if (prev) 1202b00628b1SAlexei Starovoitov /* Drop prev prog refcnt when swapping with new prog */ 1203b00628b1SAlexei Starovoitov bpf_prog_put(prev); 1204b00628b1SAlexei Starovoitov t->prog = prog; 1205b00628b1SAlexei Starovoitov } 1206b00628b1SAlexei Starovoitov rcu_assign_pointer(t->callback_fn, callback_fn); 1207b00628b1SAlexei Starovoitov out: 1208b00628b1SAlexei Starovoitov __bpf_spin_unlock_irqrestore(&timer->lock); 1209b00628b1SAlexei Starovoitov return ret; 1210b00628b1SAlexei Starovoitov } 1211b00628b1SAlexei Starovoitov 1212b00628b1SAlexei Starovoitov static const struct bpf_func_proto bpf_timer_set_callback_proto = { 1213b00628b1SAlexei Starovoitov .func = bpf_timer_set_callback, 1214b00628b1SAlexei Starovoitov .gpl_only = true, 1215b00628b1SAlexei Starovoitov .ret_type = RET_INTEGER, 1216b00628b1SAlexei Starovoitov .arg1_type = ARG_PTR_TO_TIMER, 1217b00628b1SAlexei Starovoitov .arg2_type = ARG_PTR_TO_FUNC, 1218b00628b1SAlexei Starovoitov }; 1219b00628b1SAlexei Starovoitov 1220b00628b1SAlexei Starovoitov BPF_CALL_3(bpf_timer_start, struct bpf_timer_kern *, timer, u64, nsecs, u64, flags) 1221b00628b1SAlexei Starovoitov { 1222b00628b1SAlexei Starovoitov struct bpf_hrtimer *t; 1223b00628b1SAlexei Starovoitov int ret = 0; 1224b00628b1SAlexei Starovoitov 1225b00628b1SAlexei Starovoitov if (in_nmi()) 1226b00628b1SAlexei Starovoitov return -EOPNOTSUPP; 1227b00628b1SAlexei Starovoitov if (flags) 1228b00628b1SAlexei Starovoitov return -EINVAL; 1229b00628b1SAlexei Starovoitov __bpf_spin_lock_irqsave(&timer->lock); 1230b00628b1SAlexei Starovoitov t = timer->timer; 1231b00628b1SAlexei Starovoitov if (!t || !t->prog) { 1232b00628b1SAlexei Starovoitov ret = -EINVAL; 1233b00628b1SAlexei Starovoitov goto out; 1234b00628b1SAlexei Starovoitov } 1235b00628b1SAlexei Starovoitov hrtimer_start(&t->timer, ns_to_ktime(nsecs), HRTIMER_MODE_REL_SOFT); 1236b00628b1SAlexei Starovoitov out: 1237b00628b1SAlexei Starovoitov __bpf_spin_unlock_irqrestore(&timer->lock); 1238b00628b1SAlexei Starovoitov return ret; 1239b00628b1SAlexei Starovoitov } 1240b00628b1SAlexei Starovoitov 1241b00628b1SAlexei Starovoitov static const struct bpf_func_proto bpf_timer_start_proto = { 1242b00628b1SAlexei Starovoitov .func = bpf_timer_start, 1243b00628b1SAlexei Starovoitov .gpl_only = true, 1244b00628b1SAlexei Starovoitov .ret_type = RET_INTEGER, 1245b00628b1SAlexei Starovoitov .arg1_type = ARG_PTR_TO_TIMER, 1246b00628b1SAlexei Starovoitov .arg2_type = ARG_ANYTHING, 1247b00628b1SAlexei Starovoitov .arg3_type = ARG_ANYTHING, 1248b00628b1SAlexei Starovoitov }; 1249b00628b1SAlexei Starovoitov 1250b00628b1SAlexei Starovoitov static void drop_prog_refcnt(struct bpf_hrtimer *t) 1251b00628b1SAlexei Starovoitov { 1252b00628b1SAlexei Starovoitov struct bpf_prog *prog = t->prog; 1253b00628b1SAlexei Starovoitov 1254b00628b1SAlexei Starovoitov if (prog) { 1255b00628b1SAlexei Starovoitov bpf_prog_put(prog); 1256b00628b1SAlexei Starovoitov t->prog = NULL; 1257b00628b1SAlexei Starovoitov rcu_assign_pointer(t->callback_fn, NULL); 1258b00628b1SAlexei Starovoitov } 1259b00628b1SAlexei Starovoitov } 1260b00628b1SAlexei Starovoitov 1261b00628b1SAlexei Starovoitov BPF_CALL_1(bpf_timer_cancel, struct bpf_timer_kern *, timer) 1262b00628b1SAlexei Starovoitov { 1263b00628b1SAlexei Starovoitov struct bpf_hrtimer *t; 1264b00628b1SAlexei Starovoitov int ret = 0; 1265b00628b1SAlexei Starovoitov 1266b00628b1SAlexei Starovoitov if (in_nmi()) 1267b00628b1SAlexei Starovoitov return -EOPNOTSUPP; 1268b00628b1SAlexei Starovoitov __bpf_spin_lock_irqsave(&timer->lock); 1269b00628b1SAlexei Starovoitov t = timer->timer; 1270b00628b1SAlexei Starovoitov if (!t) { 1271b00628b1SAlexei Starovoitov ret = -EINVAL; 1272b00628b1SAlexei Starovoitov goto out; 1273b00628b1SAlexei Starovoitov } 1274b00628b1SAlexei Starovoitov if (this_cpu_read(hrtimer_running) == t) { 1275b00628b1SAlexei Starovoitov /* If bpf callback_fn is trying to bpf_timer_cancel() 1276b00628b1SAlexei Starovoitov * its own timer the hrtimer_cancel() will deadlock 1277b00628b1SAlexei Starovoitov * since it waits for callback_fn to finish 1278b00628b1SAlexei Starovoitov */ 1279b00628b1SAlexei Starovoitov ret = -EDEADLK; 1280b00628b1SAlexei Starovoitov goto out; 1281b00628b1SAlexei Starovoitov } 1282b00628b1SAlexei Starovoitov drop_prog_refcnt(t); 1283b00628b1SAlexei Starovoitov out: 1284b00628b1SAlexei Starovoitov __bpf_spin_unlock_irqrestore(&timer->lock); 1285b00628b1SAlexei Starovoitov /* Cancel the timer and wait for associated callback to finish 1286b00628b1SAlexei Starovoitov * if it was running. 1287b00628b1SAlexei Starovoitov */ 1288b00628b1SAlexei Starovoitov ret = ret ?: hrtimer_cancel(&t->timer); 1289b00628b1SAlexei Starovoitov return ret; 1290b00628b1SAlexei Starovoitov } 1291b00628b1SAlexei Starovoitov 1292b00628b1SAlexei Starovoitov static const struct bpf_func_proto bpf_timer_cancel_proto = { 1293b00628b1SAlexei Starovoitov .func = bpf_timer_cancel, 1294b00628b1SAlexei Starovoitov .gpl_only = true, 1295b00628b1SAlexei Starovoitov .ret_type = RET_INTEGER, 1296b00628b1SAlexei Starovoitov .arg1_type = ARG_PTR_TO_TIMER, 1297b00628b1SAlexei Starovoitov }; 1298b00628b1SAlexei Starovoitov 1299b00628b1SAlexei Starovoitov /* This function is called by map_delete/update_elem for individual element and 1300b00628b1SAlexei Starovoitov * by ops->map_release_uref when the user space reference to a map reaches zero. 1301b00628b1SAlexei Starovoitov */ 1302b00628b1SAlexei Starovoitov void bpf_timer_cancel_and_free(void *val) 1303b00628b1SAlexei Starovoitov { 1304b00628b1SAlexei Starovoitov struct bpf_timer_kern *timer = val; 1305b00628b1SAlexei Starovoitov struct bpf_hrtimer *t; 1306b00628b1SAlexei Starovoitov 1307b00628b1SAlexei Starovoitov /* Performance optimization: read timer->timer without lock first. */ 1308b00628b1SAlexei Starovoitov if (!READ_ONCE(timer->timer)) 1309b00628b1SAlexei Starovoitov return; 1310b00628b1SAlexei Starovoitov 1311b00628b1SAlexei Starovoitov __bpf_spin_lock_irqsave(&timer->lock); 1312b00628b1SAlexei Starovoitov /* re-read it under lock */ 1313b00628b1SAlexei Starovoitov t = timer->timer; 1314b00628b1SAlexei Starovoitov if (!t) 1315b00628b1SAlexei Starovoitov goto out; 1316b00628b1SAlexei Starovoitov drop_prog_refcnt(t); 1317b00628b1SAlexei Starovoitov /* The subsequent bpf_timer_start/cancel() helpers won't be able to use 1318b00628b1SAlexei Starovoitov * this timer, since it won't be initialized. 1319b00628b1SAlexei Starovoitov */ 1320b00628b1SAlexei Starovoitov timer->timer = NULL; 1321b00628b1SAlexei Starovoitov out: 1322b00628b1SAlexei Starovoitov __bpf_spin_unlock_irqrestore(&timer->lock); 1323b00628b1SAlexei Starovoitov if (!t) 1324b00628b1SAlexei Starovoitov return; 1325b00628b1SAlexei Starovoitov /* Cancel the timer and wait for callback to complete if it was running. 1326b00628b1SAlexei Starovoitov * If hrtimer_cancel() can be safely called it's safe to call kfree(t) 1327b00628b1SAlexei Starovoitov * right after for both preallocated and non-preallocated maps. 1328b00628b1SAlexei Starovoitov * The timer->timer = NULL was already done and no code path can 1329b00628b1SAlexei Starovoitov * see address 't' anymore. 1330b00628b1SAlexei Starovoitov * 1331b00628b1SAlexei Starovoitov * Check that bpf_map_delete/update_elem() wasn't called from timer 1332b00628b1SAlexei Starovoitov * callback_fn. In such case don't call hrtimer_cancel() (since it will 1333b00628b1SAlexei Starovoitov * deadlock) and don't call hrtimer_try_to_cancel() (since it will just 1334b00628b1SAlexei Starovoitov * return -1). Though callback_fn is still running on this cpu it's 1335b00628b1SAlexei Starovoitov * safe to do kfree(t) because bpf_timer_cb() read everything it needed 1336b00628b1SAlexei Starovoitov * from 't'. The bpf subprog callback_fn won't be able to access 't', 1337b00628b1SAlexei Starovoitov * since timer->timer = NULL was already done. The timer will be 1338b00628b1SAlexei Starovoitov * effectively cancelled because bpf_timer_cb() will return 1339b00628b1SAlexei Starovoitov * HRTIMER_NORESTART. 1340b00628b1SAlexei Starovoitov */ 1341b00628b1SAlexei Starovoitov if (this_cpu_read(hrtimer_running) != t) 1342b00628b1SAlexei Starovoitov hrtimer_cancel(&t->timer); 1343b00628b1SAlexei Starovoitov kfree(t); 1344b00628b1SAlexei Starovoitov } 1345b00628b1SAlexei Starovoitov 1346f470378cSJohn Fastabend const struct bpf_func_proto bpf_get_current_task_proto __weak; 1347a396eda5SDaniel Xu const struct bpf_func_proto bpf_get_current_task_btf_proto __weak; 1348f470378cSJohn Fastabend const struct bpf_func_proto bpf_probe_read_user_proto __weak; 1349f470378cSJohn Fastabend const struct bpf_func_proto bpf_probe_read_user_str_proto __weak; 1350f470378cSJohn Fastabend const struct bpf_func_proto bpf_probe_read_kernel_proto __weak; 1351f470378cSJohn Fastabend const struct bpf_func_proto bpf_probe_read_kernel_str_proto __weak; 1352dd6e10fbSDaniel Xu const struct bpf_func_proto bpf_task_pt_regs_proto __weak; 1353f470378cSJohn Fastabend 13546890896bSStanislav Fomichev const struct bpf_func_proto * 13556890896bSStanislav Fomichev bpf_base_func_proto(enum bpf_func_id func_id) 13566890896bSStanislav Fomichev { 13576890896bSStanislav Fomichev switch (func_id) { 13586890896bSStanislav Fomichev case BPF_FUNC_map_lookup_elem: 13596890896bSStanislav Fomichev return &bpf_map_lookup_elem_proto; 13606890896bSStanislav Fomichev case BPF_FUNC_map_update_elem: 13616890896bSStanislav Fomichev return &bpf_map_update_elem_proto; 13626890896bSStanislav Fomichev case BPF_FUNC_map_delete_elem: 13636890896bSStanislav Fomichev return &bpf_map_delete_elem_proto; 13646890896bSStanislav Fomichev case BPF_FUNC_map_push_elem: 13656890896bSStanislav Fomichev return &bpf_map_push_elem_proto; 13666890896bSStanislav Fomichev case BPF_FUNC_map_pop_elem: 13676890896bSStanislav Fomichev return &bpf_map_pop_elem_proto; 13686890896bSStanislav Fomichev case BPF_FUNC_map_peek_elem: 13696890896bSStanislav Fomichev return &bpf_map_peek_elem_proto; 13706890896bSStanislav Fomichev case BPF_FUNC_get_prandom_u32: 13716890896bSStanislav Fomichev return &bpf_get_prandom_u32_proto; 13726890896bSStanislav Fomichev case BPF_FUNC_get_smp_processor_id: 13736890896bSStanislav Fomichev return &bpf_get_raw_smp_processor_id_proto; 13746890896bSStanislav Fomichev case BPF_FUNC_get_numa_node_id: 13756890896bSStanislav Fomichev return &bpf_get_numa_node_id_proto; 13766890896bSStanislav Fomichev case BPF_FUNC_tail_call: 13776890896bSStanislav Fomichev return &bpf_tail_call_proto; 13786890896bSStanislav Fomichev case BPF_FUNC_ktime_get_ns: 13796890896bSStanislav Fomichev return &bpf_ktime_get_ns_proto; 138071d19214SMaciej Żenczykowski case BPF_FUNC_ktime_get_boot_ns: 138171d19214SMaciej Żenczykowski return &bpf_ktime_get_boot_ns_proto; 1382457f4436SAndrii Nakryiko case BPF_FUNC_ringbuf_output: 1383457f4436SAndrii Nakryiko return &bpf_ringbuf_output_proto; 1384457f4436SAndrii Nakryiko case BPF_FUNC_ringbuf_reserve: 1385457f4436SAndrii Nakryiko return &bpf_ringbuf_reserve_proto; 1386457f4436SAndrii Nakryiko case BPF_FUNC_ringbuf_submit: 1387457f4436SAndrii Nakryiko return &bpf_ringbuf_submit_proto; 1388457f4436SAndrii Nakryiko case BPF_FUNC_ringbuf_discard: 1389457f4436SAndrii Nakryiko return &bpf_ringbuf_discard_proto; 1390457f4436SAndrii Nakryiko case BPF_FUNC_ringbuf_query: 1391457f4436SAndrii Nakryiko return &bpf_ringbuf_query_proto; 139269c087baSYonghong Song case BPF_FUNC_for_each_map_elem: 139369c087baSYonghong Song return &bpf_for_each_map_elem_proto; 1394e6f2dd0fSJoanne Koong case BPF_FUNC_loop: 1395e6f2dd0fSJoanne Koong return &bpf_loop_proto; 1396c5fb1993SHou Tao case BPF_FUNC_strncmp: 1397c5fb1993SHou Tao return &bpf_strncmp_proto; 13986890896bSStanislav Fomichev default: 13996890896bSStanislav Fomichev break; 14006890896bSStanislav Fomichev } 14016890896bSStanislav Fomichev 14022c78ee89SAlexei Starovoitov if (!bpf_capable()) 14036890896bSStanislav Fomichev return NULL; 14046890896bSStanislav Fomichev 14056890896bSStanislav Fomichev switch (func_id) { 14066890896bSStanislav Fomichev case BPF_FUNC_spin_lock: 14076890896bSStanislav Fomichev return &bpf_spin_lock_proto; 14086890896bSStanislav Fomichev case BPF_FUNC_spin_unlock: 14096890896bSStanislav Fomichev return &bpf_spin_unlock_proto; 14106890896bSStanislav Fomichev case BPF_FUNC_jiffies64: 14116890896bSStanislav Fomichev return &bpf_jiffies64_proto; 1412b7906b70SAndrii Nakryiko case BPF_FUNC_per_cpu_ptr: 1413eaa6bcb7SHao Luo return &bpf_per_cpu_ptr_proto; 1414b7906b70SAndrii Nakryiko case BPF_FUNC_this_cpu_ptr: 141563d9b80dSHao Luo return &bpf_this_cpu_ptr_proto; 1416b00628b1SAlexei Starovoitov case BPF_FUNC_timer_init: 1417b00628b1SAlexei Starovoitov return &bpf_timer_init_proto; 1418b00628b1SAlexei Starovoitov case BPF_FUNC_timer_set_callback: 1419b00628b1SAlexei Starovoitov return &bpf_timer_set_callback_proto; 1420b00628b1SAlexei Starovoitov case BPF_FUNC_timer_start: 1421b00628b1SAlexei Starovoitov return &bpf_timer_start_proto; 1422b00628b1SAlexei Starovoitov case BPF_FUNC_timer_cancel: 1423b00628b1SAlexei Starovoitov return &bpf_timer_cancel_proto; 14246890896bSStanislav Fomichev default: 1425f470378cSJohn Fastabend break; 1426f470378cSJohn Fastabend } 1427f470378cSJohn Fastabend 1428f470378cSJohn Fastabend if (!perfmon_capable()) 1429f470378cSJohn Fastabend return NULL; 1430f470378cSJohn Fastabend 1431f470378cSJohn Fastabend switch (func_id) { 143261ca36c8STobias Klauser case BPF_FUNC_trace_printk: 143361ca36c8STobias Klauser return bpf_get_trace_printk_proto(); 1434f470378cSJohn Fastabend case BPF_FUNC_get_current_task: 1435f470378cSJohn Fastabend return &bpf_get_current_task_proto; 1436a396eda5SDaniel Xu case BPF_FUNC_get_current_task_btf: 1437a396eda5SDaniel Xu return &bpf_get_current_task_btf_proto; 1438f470378cSJohn Fastabend case BPF_FUNC_probe_read_user: 1439f470378cSJohn Fastabend return &bpf_probe_read_user_proto; 1440f470378cSJohn Fastabend case BPF_FUNC_probe_read_kernel: 144171330842SDaniel Borkmann return security_locked_down(LOCKDOWN_BPF_READ_KERNEL) < 0 ? 1442ff40e510SDaniel Borkmann NULL : &bpf_probe_read_kernel_proto; 1443f470378cSJohn Fastabend case BPF_FUNC_probe_read_user_str: 1444f470378cSJohn Fastabend return &bpf_probe_read_user_str_proto; 1445f470378cSJohn Fastabend case BPF_FUNC_probe_read_kernel_str: 144671330842SDaniel Borkmann return security_locked_down(LOCKDOWN_BPF_READ_KERNEL) < 0 ? 1447ff40e510SDaniel Borkmann NULL : &bpf_probe_read_kernel_str_proto; 144861ca36c8STobias Klauser case BPF_FUNC_snprintf_btf: 144961ca36c8STobias Klauser return &bpf_snprintf_btf_proto; 14507b15523aSFlorent Revest case BPF_FUNC_snprintf: 14517b15523aSFlorent Revest return &bpf_snprintf_proto; 1452dd6e10fbSDaniel Xu case BPF_FUNC_task_pt_regs: 1453dd6e10fbSDaniel Xu return &bpf_task_pt_regs_proto; 145410aceb62SDave Marchevsky case BPF_FUNC_trace_vprintk: 145510aceb62SDave Marchevsky return bpf_get_trace_vprintk_proto(); 1456f470378cSJohn Fastabend default: 14576890896bSStanislav Fomichev return NULL; 14586890896bSStanislav Fomichev } 14596890896bSStanislav Fomichev } 1460