199c55f7dSAlexei Starovoitov /* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com 299c55f7dSAlexei Starovoitov * 399c55f7dSAlexei Starovoitov * This program is free software; you can redistribute it and/or 499c55f7dSAlexei Starovoitov * modify it under the terms of version 2 of the GNU General Public 599c55f7dSAlexei Starovoitov * License as published by the Free Software Foundation. 699c55f7dSAlexei Starovoitov * 799c55f7dSAlexei Starovoitov * This program is distributed in the hope that it will be useful, but 899c55f7dSAlexei Starovoitov * WITHOUT ANY WARRANTY; without even the implied warranty of 999c55f7dSAlexei Starovoitov * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1099c55f7dSAlexei Starovoitov * General Public License for more details. 1199c55f7dSAlexei Starovoitov */ 1299c55f7dSAlexei Starovoitov #include <linux/bpf.h> 13a67edbf4SDaniel Borkmann #include <linux/bpf_trace.h> 1499c55f7dSAlexei Starovoitov #include <linux/syscalls.h> 1599c55f7dSAlexei Starovoitov #include <linux/slab.h> 163f07c014SIngo Molnar #include <linux/sched/signal.h> 17d407bd25SDaniel Borkmann #include <linux/vmalloc.h> 18d407bd25SDaniel Borkmann #include <linux/mmzone.h> 1999c55f7dSAlexei Starovoitov #include <linux/anon_inodes.h> 20db20fd2bSAlexei Starovoitov #include <linux/file.h> 2109756af4SAlexei Starovoitov #include <linux/license.h> 2209756af4SAlexei Starovoitov #include <linux/filter.h> 232541517cSAlexei Starovoitov #include <linux/version.h> 24535e7b4bSMickaël Salaün #include <linux/kernel.h> 25dc4bb0e2SMartin KaFai Lau #include <linux/idr.h> 26cb4d2b3fSMartin KaFai Lau #include <linux/cred.h> 27cb4d2b3fSMartin KaFai Lau #include <linux/timekeeping.h> 28cb4d2b3fSMartin KaFai Lau #include <linux/ctype.h> 2999c55f7dSAlexei Starovoitov 3014dc6f04SMartin KaFai Lau #define IS_FD_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PROG_ARRAY || \ 3114dc6f04SMartin KaFai Lau (map)->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || \ 3214dc6f04SMartin KaFai Lau (map)->map_type == BPF_MAP_TYPE_CGROUP_ARRAY || \ 3314dc6f04SMartin KaFai Lau (map)->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS) 3414dc6f04SMartin KaFai Lau #define IS_FD_HASH(map) ((map)->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) 3514dc6f04SMartin KaFai Lau #define IS_FD_MAP(map) (IS_FD_ARRAY(map) || IS_FD_HASH(map)) 3614dc6f04SMartin KaFai Lau 376e71b04aSChenbo Feng #define BPF_OBJ_FLAG_MASK (BPF_F_RDONLY | BPF_F_WRONLY) 386e71b04aSChenbo Feng 39b121d1e7SAlexei Starovoitov DEFINE_PER_CPU(int, bpf_prog_active); 40dc4bb0e2SMartin KaFai Lau static DEFINE_IDR(prog_idr); 41dc4bb0e2SMartin KaFai Lau static DEFINE_SPINLOCK(prog_idr_lock); 42f3f1c054SMartin KaFai Lau static DEFINE_IDR(map_idr); 43f3f1c054SMartin KaFai Lau static DEFINE_SPINLOCK(map_idr_lock); 44b121d1e7SAlexei Starovoitov 451be7f75dSAlexei Starovoitov int sysctl_unprivileged_bpf_disabled __read_mostly; 461be7f75dSAlexei Starovoitov 4740077e0cSJohannes Berg static const struct bpf_map_ops * const bpf_map_types[] = { 4840077e0cSJohannes Berg #define BPF_PROG_TYPE(_id, _ops) 4940077e0cSJohannes Berg #define BPF_MAP_TYPE(_id, _ops) \ 5040077e0cSJohannes Berg [_id] = &_ops, 5140077e0cSJohannes Berg #include <linux/bpf_types.h> 5240077e0cSJohannes Berg #undef BPF_PROG_TYPE 5340077e0cSJohannes Berg #undef BPF_MAP_TYPE 5440077e0cSJohannes Berg }; 5599c55f7dSAlexei Starovoitov 56752ba56fSMickaël Salaün /* 57752ba56fSMickaël Salaün * If we're handed a bigger struct than we know of, ensure all the unknown bits 58752ba56fSMickaël Salaün * are 0 - i.e. new user-space does not rely on any kernel feature extensions 59752ba56fSMickaël Salaün * we don't know about yet. 60752ba56fSMickaël Salaün * 61752ba56fSMickaël Salaün * There is a ToCToU between this function call and the following 62752ba56fSMickaël Salaün * copy_from_user() call. However, this is not a concern since this function is 63752ba56fSMickaël Salaün * meant to be a future-proofing of bits. 64752ba56fSMickaël Salaün */ 6558291a74SMickaël Salaün static int check_uarg_tail_zero(void __user *uaddr, 6658291a74SMickaël Salaün size_t expected_size, 6758291a74SMickaël Salaün size_t actual_size) 6858291a74SMickaël Salaün { 6958291a74SMickaël Salaün unsigned char __user *addr; 7058291a74SMickaël Salaün unsigned char __user *end; 7158291a74SMickaël Salaün unsigned char val; 7258291a74SMickaël Salaün int err; 7358291a74SMickaël Salaün 74752ba56fSMickaël Salaün if (unlikely(actual_size > PAGE_SIZE)) /* silly large */ 75752ba56fSMickaël Salaün return -E2BIG; 76752ba56fSMickaël Salaün 77752ba56fSMickaël Salaün if (unlikely(!access_ok(VERIFY_READ, uaddr, actual_size))) 78752ba56fSMickaël Salaün return -EFAULT; 79752ba56fSMickaël Salaün 8058291a74SMickaël Salaün if (actual_size <= expected_size) 8158291a74SMickaël Salaün return 0; 8258291a74SMickaël Salaün 8358291a74SMickaël Salaün addr = uaddr + expected_size; 8458291a74SMickaël Salaün end = uaddr + actual_size; 8558291a74SMickaël Salaün 8658291a74SMickaël Salaün for (; addr < end; addr++) { 8758291a74SMickaël Salaün err = get_user(val, addr); 8858291a74SMickaël Salaün if (err) 8958291a74SMickaël Salaün return err; 9058291a74SMickaël Salaün if (val) 9158291a74SMickaël Salaün return -E2BIG; 9258291a74SMickaël Salaün } 9358291a74SMickaël Salaün 9458291a74SMickaël Salaün return 0; 9558291a74SMickaël Salaün } 9658291a74SMickaël Salaün 97a3884572SJakub Kicinski const struct bpf_map_ops bpf_map_offload_ops = { 98a3884572SJakub Kicinski .map_alloc = bpf_map_offload_map_alloc, 99a3884572SJakub Kicinski .map_free = bpf_map_offload_map_free, 100a3884572SJakub Kicinski }; 101a3884572SJakub Kicinski 10299c55f7dSAlexei Starovoitov static struct bpf_map *find_and_alloc_map(union bpf_attr *attr) 10399c55f7dSAlexei Starovoitov { 1041110f3a9SJakub Kicinski const struct bpf_map_ops *ops; 10599c55f7dSAlexei Starovoitov struct bpf_map *map; 1061110f3a9SJakub Kicinski int err; 10799c55f7dSAlexei Starovoitov 1081110f3a9SJakub Kicinski if (attr->map_type >= ARRAY_SIZE(bpf_map_types)) 1091110f3a9SJakub Kicinski return ERR_PTR(-EINVAL); 1101110f3a9SJakub Kicinski ops = bpf_map_types[attr->map_type]; 1111110f3a9SJakub Kicinski if (!ops) 11240077e0cSJohannes Berg return ERR_PTR(-EINVAL); 11340077e0cSJohannes Berg 1141110f3a9SJakub Kicinski if (ops->map_alloc_check) { 1151110f3a9SJakub Kicinski err = ops->map_alloc_check(attr); 1161110f3a9SJakub Kicinski if (err) 1171110f3a9SJakub Kicinski return ERR_PTR(err); 1181110f3a9SJakub Kicinski } 119a3884572SJakub Kicinski if (attr->map_ifindex) 120a3884572SJakub Kicinski ops = &bpf_map_offload_ops; 1211110f3a9SJakub Kicinski map = ops->map_alloc(attr); 12299c55f7dSAlexei Starovoitov if (IS_ERR(map)) 12399c55f7dSAlexei Starovoitov return map; 1241110f3a9SJakub Kicinski map->ops = ops; 12599c55f7dSAlexei Starovoitov map->map_type = attr->map_type; 12699c55f7dSAlexei Starovoitov return map; 12799c55f7dSAlexei Starovoitov } 12899c55f7dSAlexei Starovoitov 12996eabe7aSMartin KaFai Lau void *bpf_map_area_alloc(size_t size, int numa_node) 130d407bd25SDaniel Borkmann { 131d407bd25SDaniel Borkmann /* We definitely need __GFP_NORETRY, so OOM killer doesn't 132d407bd25SDaniel Borkmann * trigger under memory pressure as we really just want to 133d407bd25SDaniel Borkmann * fail instead. 134d407bd25SDaniel Borkmann */ 135d407bd25SDaniel Borkmann const gfp_t flags = __GFP_NOWARN | __GFP_NORETRY | __GFP_ZERO; 136d407bd25SDaniel Borkmann void *area; 137d407bd25SDaniel Borkmann 138d407bd25SDaniel Borkmann if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) { 13996eabe7aSMartin KaFai Lau area = kmalloc_node(size, GFP_USER | flags, numa_node); 140d407bd25SDaniel Borkmann if (area != NULL) 141d407bd25SDaniel Borkmann return area; 142d407bd25SDaniel Borkmann } 143d407bd25SDaniel Borkmann 14496eabe7aSMartin KaFai Lau return __vmalloc_node_flags_caller(size, numa_node, GFP_KERNEL | flags, 14596eabe7aSMartin KaFai Lau __builtin_return_address(0)); 146d407bd25SDaniel Borkmann } 147d407bd25SDaniel Borkmann 148d407bd25SDaniel Borkmann void bpf_map_area_free(void *area) 149d407bd25SDaniel Borkmann { 150d407bd25SDaniel Borkmann kvfree(area); 151d407bd25SDaniel Borkmann } 152d407bd25SDaniel Borkmann 153bd475643SJakub Kicinski void bpf_map_init_from_attr(struct bpf_map *map, union bpf_attr *attr) 154bd475643SJakub Kicinski { 155bd475643SJakub Kicinski map->map_type = attr->map_type; 156bd475643SJakub Kicinski map->key_size = attr->key_size; 157bd475643SJakub Kicinski map->value_size = attr->value_size; 158bd475643SJakub Kicinski map->max_entries = attr->max_entries; 159bd475643SJakub Kicinski map->map_flags = attr->map_flags; 160bd475643SJakub Kicinski map->numa_node = bpf_map_attr_numa_node(attr); 161bd475643SJakub Kicinski } 162bd475643SJakub Kicinski 1636c905981SAlexei Starovoitov int bpf_map_precharge_memlock(u32 pages) 1646c905981SAlexei Starovoitov { 1656c905981SAlexei Starovoitov struct user_struct *user = get_current_user(); 1666c905981SAlexei Starovoitov unsigned long memlock_limit, cur; 1676c905981SAlexei Starovoitov 1686c905981SAlexei Starovoitov memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; 1696c905981SAlexei Starovoitov cur = atomic_long_read(&user->locked_vm); 1706c905981SAlexei Starovoitov free_uid(user); 1716c905981SAlexei Starovoitov if (cur + pages > memlock_limit) 1726c905981SAlexei Starovoitov return -EPERM; 1736c905981SAlexei Starovoitov return 0; 1746c905981SAlexei Starovoitov } 1756c905981SAlexei Starovoitov 176aaac3ba9SAlexei Starovoitov static int bpf_map_charge_memlock(struct bpf_map *map) 177aaac3ba9SAlexei Starovoitov { 178aaac3ba9SAlexei Starovoitov struct user_struct *user = get_current_user(); 179aaac3ba9SAlexei Starovoitov unsigned long memlock_limit; 180aaac3ba9SAlexei Starovoitov 181aaac3ba9SAlexei Starovoitov memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; 182aaac3ba9SAlexei Starovoitov 183aaac3ba9SAlexei Starovoitov atomic_long_add(map->pages, &user->locked_vm); 184aaac3ba9SAlexei Starovoitov 185aaac3ba9SAlexei Starovoitov if (atomic_long_read(&user->locked_vm) > memlock_limit) { 186aaac3ba9SAlexei Starovoitov atomic_long_sub(map->pages, &user->locked_vm); 187aaac3ba9SAlexei Starovoitov free_uid(user); 188aaac3ba9SAlexei Starovoitov return -EPERM; 189aaac3ba9SAlexei Starovoitov } 190aaac3ba9SAlexei Starovoitov map->user = user; 191aaac3ba9SAlexei Starovoitov return 0; 192aaac3ba9SAlexei Starovoitov } 193aaac3ba9SAlexei Starovoitov 194aaac3ba9SAlexei Starovoitov static void bpf_map_uncharge_memlock(struct bpf_map *map) 195aaac3ba9SAlexei Starovoitov { 196aaac3ba9SAlexei Starovoitov struct user_struct *user = map->user; 197aaac3ba9SAlexei Starovoitov 198aaac3ba9SAlexei Starovoitov atomic_long_sub(map->pages, &user->locked_vm); 199aaac3ba9SAlexei Starovoitov free_uid(user); 200aaac3ba9SAlexei Starovoitov } 201aaac3ba9SAlexei Starovoitov 202f3f1c054SMartin KaFai Lau static int bpf_map_alloc_id(struct bpf_map *map) 203f3f1c054SMartin KaFai Lau { 204f3f1c054SMartin KaFai Lau int id; 205f3f1c054SMartin KaFai Lau 206f3f1c054SMartin KaFai Lau spin_lock_bh(&map_idr_lock); 207f3f1c054SMartin KaFai Lau id = idr_alloc_cyclic(&map_idr, map, 1, INT_MAX, GFP_ATOMIC); 208f3f1c054SMartin KaFai Lau if (id > 0) 209f3f1c054SMartin KaFai Lau map->id = id; 210f3f1c054SMartin KaFai Lau spin_unlock_bh(&map_idr_lock); 211f3f1c054SMartin KaFai Lau 212f3f1c054SMartin KaFai Lau if (WARN_ON_ONCE(!id)) 213f3f1c054SMartin KaFai Lau return -ENOSPC; 214f3f1c054SMartin KaFai Lau 215f3f1c054SMartin KaFai Lau return id > 0 ? 0 : id; 216f3f1c054SMartin KaFai Lau } 217f3f1c054SMartin KaFai Lau 218a3884572SJakub Kicinski void bpf_map_free_id(struct bpf_map *map, bool do_idr_lock) 219f3f1c054SMartin KaFai Lau { 220930651a7SEric Dumazet unsigned long flags; 221930651a7SEric Dumazet 222a3884572SJakub Kicinski /* Offloaded maps are removed from the IDR store when their device 223a3884572SJakub Kicinski * disappears - even if someone holds an fd to them they are unusable, 224a3884572SJakub Kicinski * the memory is gone, all ops will fail; they are simply waiting for 225a3884572SJakub Kicinski * refcnt to drop to be freed. 226a3884572SJakub Kicinski */ 227a3884572SJakub Kicinski if (!map->id) 228a3884572SJakub Kicinski return; 229a3884572SJakub Kicinski 230bd5f5f4eSMartin KaFai Lau if (do_idr_lock) 231930651a7SEric Dumazet spin_lock_irqsave(&map_idr_lock, flags); 232bd5f5f4eSMartin KaFai Lau else 233bd5f5f4eSMartin KaFai Lau __acquire(&map_idr_lock); 234bd5f5f4eSMartin KaFai Lau 235f3f1c054SMartin KaFai Lau idr_remove(&map_idr, map->id); 236a3884572SJakub Kicinski map->id = 0; 237bd5f5f4eSMartin KaFai Lau 238bd5f5f4eSMartin KaFai Lau if (do_idr_lock) 239930651a7SEric Dumazet spin_unlock_irqrestore(&map_idr_lock, flags); 240bd5f5f4eSMartin KaFai Lau else 241bd5f5f4eSMartin KaFai Lau __release(&map_idr_lock); 242f3f1c054SMartin KaFai Lau } 243f3f1c054SMartin KaFai Lau 24499c55f7dSAlexei Starovoitov /* called from workqueue */ 24599c55f7dSAlexei Starovoitov static void bpf_map_free_deferred(struct work_struct *work) 24699c55f7dSAlexei Starovoitov { 24799c55f7dSAlexei Starovoitov struct bpf_map *map = container_of(work, struct bpf_map, work); 24899c55f7dSAlexei Starovoitov 249aaac3ba9SAlexei Starovoitov bpf_map_uncharge_memlock(map); 250afdb09c7SChenbo Feng security_bpf_map_free(map); 25199c55f7dSAlexei Starovoitov /* implementation dependent freeing */ 25299c55f7dSAlexei Starovoitov map->ops->map_free(map); 25399c55f7dSAlexei Starovoitov } 25499c55f7dSAlexei Starovoitov 255c9da161cSDaniel Borkmann static void bpf_map_put_uref(struct bpf_map *map) 256c9da161cSDaniel Borkmann { 257c9da161cSDaniel Borkmann if (atomic_dec_and_test(&map->usercnt)) { 258c9da161cSDaniel Borkmann if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY) 259c9da161cSDaniel Borkmann bpf_fd_array_map_clear(map); 260c9da161cSDaniel Borkmann } 261c9da161cSDaniel Borkmann } 262c9da161cSDaniel Borkmann 26399c55f7dSAlexei Starovoitov /* decrement map refcnt and schedule it for freeing via workqueue 26499c55f7dSAlexei Starovoitov * (unrelying map implementation ops->map_free() might sleep) 26599c55f7dSAlexei Starovoitov */ 266bd5f5f4eSMartin KaFai Lau static void __bpf_map_put(struct bpf_map *map, bool do_idr_lock) 26799c55f7dSAlexei Starovoitov { 26899c55f7dSAlexei Starovoitov if (atomic_dec_and_test(&map->refcnt)) { 26934ad5580SMartin KaFai Lau /* bpf_map_free_id() must be called first */ 270bd5f5f4eSMartin KaFai Lau bpf_map_free_id(map, do_idr_lock); 27199c55f7dSAlexei Starovoitov INIT_WORK(&map->work, bpf_map_free_deferred); 27299c55f7dSAlexei Starovoitov schedule_work(&map->work); 27399c55f7dSAlexei Starovoitov } 27499c55f7dSAlexei Starovoitov } 27599c55f7dSAlexei Starovoitov 276bd5f5f4eSMartin KaFai Lau void bpf_map_put(struct bpf_map *map) 277bd5f5f4eSMartin KaFai Lau { 278bd5f5f4eSMartin KaFai Lau __bpf_map_put(map, true); 279bd5f5f4eSMartin KaFai Lau } 280bd5f5f4eSMartin KaFai Lau 281c9da161cSDaniel Borkmann void bpf_map_put_with_uref(struct bpf_map *map) 282c9da161cSDaniel Borkmann { 283c9da161cSDaniel Borkmann bpf_map_put_uref(map); 284c9da161cSDaniel Borkmann bpf_map_put(map); 285c9da161cSDaniel Borkmann } 286c9da161cSDaniel Borkmann 28799c55f7dSAlexei Starovoitov static int bpf_map_release(struct inode *inode, struct file *filp) 28899c55f7dSAlexei Starovoitov { 28961d1b6a4SDaniel Borkmann struct bpf_map *map = filp->private_data; 29061d1b6a4SDaniel Borkmann 29161d1b6a4SDaniel Borkmann if (map->ops->map_release) 29261d1b6a4SDaniel Borkmann map->ops->map_release(map, filp); 29361d1b6a4SDaniel Borkmann 29461d1b6a4SDaniel Borkmann bpf_map_put_with_uref(map); 29599c55f7dSAlexei Starovoitov return 0; 29699c55f7dSAlexei Starovoitov } 29799c55f7dSAlexei Starovoitov 298f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS 299f99bf205SDaniel Borkmann static void bpf_map_show_fdinfo(struct seq_file *m, struct file *filp) 300f99bf205SDaniel Borkmann { 301f99bf205SDaniel Borkmann const struct bpf_map *map = filp->private_data; 30221116b70SDaniel Borkmann const struct bpf_array *array; 30321116b70SDaniel Borkmann u32 owner_prog_type = 0; 3049780c0abSDaniel Borkmann u32 owner_jited = 0; 30521116b70SDaniel Borkmann 30621116b70SDaniel Borkmann if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY) { 30721116b70SDaniel Borkmann array = container_of(map, struct bpf_array, map); 30821116b70SDaniel Borkmann owner_prog_type = array->owner_prog_type; 3099780c0abSDaniel Borkmann owner_jited = array->owner_jited; 31021116b70SDaniel Borkmann } 311f99bf205SDaniel Borkmann 312f99bf205SDaniel Borkmann seq_printf(m, 313f99bf205SDaniel Borkmann "map_type:\t%u\n" 314f99bf205SDaniel Borkmann "key_size:\t%u\n" 315f99bf205SDaniel Borkmann "value_size:\t%u\n" 316322cea2fSDaniel Borkmann "max_entries:\t%u\n" 31721116b70SDaniel Borkmann "map_flags:\t%#x\n" 31821116b70SDaniel Borkmann "memlock:\t%llu\n", 319f99bf205SDaniel Borkmann map->map_type, 320f99bf205SDaniel Borkmann map->key_size, 321f99bf205SDaniel Borkmann map->value_size, 322322cea2fSDaniel Borkmann map->max_entries, 32321116b70SDaniel Borkmann map->map_flags, 32421116b70SDaniel Borkmann map->pages * 1ULL << PAGE_SHIFT); 32521116b70SDaniel Borkmann 3269780c0abSDaniel Borkmann if (owner_prog_type) { 32721116b70SDaniel Borkmann seq_printf(m, "owner_prog_type:\t%u\n", 32821116b70SDaniel Borkmann owner_prog_type); 3299780c0abSDaniel Borkmann seq_printf(m, "owner_jited:\t%u\n", 3309780c0abSDaniel Borkmann owner_jited); 3319780c0abSDaniel Borkmann } 332f99bf205SDaniel Borkmann } 333f99bf205SDaniel Borkmann #endif 334f99bf205SDaniel Borkmann 3356e71b04aSChenbo Feng static ssize_t bpf_dummy_read(struct file *filp, char __user *buf, size_t siz, 3366e71b04aSChenbo Feng loff_t *ppos) 3376e71b04aSChenbo Feng { 3386e71b04aSChenbo Feng /* We need this handler such that alloc_file() enables 3396e71b04aSChenbo Feng * f_mode with FMODE_CAN_READ. 3406e71b04aSChenbo Feng */ 3416e71b04aSChenbo Feng return -EINVAL; 3426e71b04aSChenbo Feng } 3436e71b04aSChenbo Feng 3446e71b04aSChenbo Feng static ssize_t bpf_dummy_write(struct file *filp, const char __user *buf, 3456e71b04aSChenbo Feng size_t siz, loff_t *ppos) 3466e71b04aSChenbo Feng { 3476e71b04aSChenbo Feng /* We need this handler such that alloc_file() enables 3486e71b04aSChenbo Feng * f_mode with FMODE_CAN_WRITE. 3496e71b04aSChenbo Feng */ 3506e71b04aSChenbo Feng return -EINVAL; 3516e71b04aSChenbo Feng } 3526e71b04aSChenbo Feng 353f66e448cSChenbo Feng const struct file_operations bpf_map_fops = { 354f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS 355f99bf205SDaniel Borkmann .show_fdinfo = bpf_map_show_fdinfo, 356f99bf205SDaniel Borkmann #endif 35799c55f7dSAlexei Starovoitov .release = bpf_map_release, 3586e71b04aSChenbo Feng .read = bpf_dummy_read, 3596e71b04aSChenbo Feng .write = bpf_dummy_write, 36099c55f7dSAlexei Starovoitov }; 36199c55f7dSAlexei Starovoitov 3626e71b04aSChenbo Feng int bpf_map_new_fd(struct bpf_map *map, int flags) 363aa79781bSDaniel Borkmann { 364afdb09c7SChenbo Feng int ret; 365afdb09c7SChenbo Feng 366afdb09c7SChenbo Feng ret = security_bpf_map(map, OPEN_FMODE(flags)); 367afdb09c7SChenbo Feng if (ret < 0) 368afdb09c7SChenbo Feng return ret; 369afdb09c7SChenbo Feng 370aa79781bSDaniel Borkmann return anon_inode_getfd("bpf-map", &bpf_map_fops, map, 3716e71b04aSChenbo Feng flags | O_CLOEXEC); 3726e71b04aSChenbo Feng } 3736e71b04aSChenbo Feng 3746e71b04aSChenbo Feng int bpf_get_file_flag(int flags) 3756e71b04aSChenbo Feng { 3766e71b04aSChenbo Feng if ((flags & BPF_F_RDONLY) && (flags & BPF_F_WRONLY)) 3776e71b04aSChenbo Feng return -EINVAL; 3786e71b04aSChenbo Feng if (flags & BPF_F_RDONLY) 3796e71b04aSChenbo Feng return O_RDONLY; 3806e71b04aSChenbo Feng if (flags & BPF_F_WRONLY) 3816e71b04aSChenbo Feng return O_WRONLY; 3826e71b04aSChenbo Feng return O_RDWR; 383aa79781bSDaniel Borkmann } 384aa79781bSDaniel Borkmann 38599c55f7dSAlexei Starovoitov /* helper macro to check that unused fields 'union bpf_attr' are zero */ 38699c55f7dSAlexei Starovoitov #define CHECK_ATTR(CMD) \ 38799c55f7dSAlexei Starovoitov memchr_inv((void *) &attr->CMD##_LAST_FIELD + \ 38899c55f7dSAlexei Starovoitov sizeof(attr->CMD##_LAST_FIELD), 0, \ 38999c55f7dSAlexei Starovoitov sizeof(*attr) - \ 39099c55f7dSAlexei Starovoitov offsetof(union bpf_attr, CMD##_LAST_FIELD) - \ 39199c55f7dSAlexei Starovoitov sizeof(attr->CMD##_LAST_FIELD)) != NULL 39299c55f7dSAlexei Starovoitov 393cb4d2b3fSMartin KaFai Lau /* dst and src must have at least BPF_OBJ_NAME_LEN number of bytes. 394cb4d2b3fSMartin KaFai Lau * Return 0 on success and < 0 on error. 395cb4d2b3fSMartin KaFai Lau */ 396cb4d2b3fSMartin KaFai Lau static int bpf_obj_name_cpy(char *dst, const char *src) 397cb4d2b3fSMartin KaFai Lau { 398cb4d2b3fSMartin KaFai Lau const char *end = src + BPF_OBJ_NAME_LEN; 399cb4d2b3fSMartin KaFai Lau 400473d9734SMartin KaFai Lau memset(dst, 0, BPF_OBJ_NAME_LEN); 401473d9734SMartin KaFai Lau 402cb4d2b3fSMartin KaFai Lau /* Copy all isalnum() and '_' char */ 403cb4d2b3fSMartin KaFai Lau while (src < end && *src) { 404cb4d2b3fSMartin KaFai Lau if (!isalnum(*src) && *src != '_') 405cb4d2b3fSMartin KaFai Lau return -EINVAL; 406cb4d2b3fSMartin KaFai Lau *dst++ = *src++; 407cb4d2b3fSMartin KaFai Lau } 408cb4d2b3fSMartin KaFai Lau 409cb4d2b3fSMartin KaFai Lau /* No '\0' found in BPF_OBJ_NAME_LEN number of bytes */ 410cb4d2b3fSMartin KaFai Lau if (src == end) 411cb4d2b3fSMartin KaFai Lau return -EINVAL; 412cb4d2b3fSMartin KaFai Lau 413cb4d2b3fSMartin KaFai Lau return 0; 414cb4d2b3fSMartin KaFai Lau } 415cb4d2b3fSMartin KaFai Lau 416a3884572SJakub Kicinski #define BPF_MAP_CREATE_LAST_FIELD map_ifindex 41799c55f7dSAlexei Starovoitov /* called via syscall */ 41899c55f7dSAlexei Starovoitov static int map_create(union bpf_attr *attr) 41999c55f7dSAlexei Starovoitov { 42096eabe7aSMartin KaFai Lau int numa_node = bpf_map_attr_numa_node(attr); 42199c55f7dSAlexei Starovoitov struct bpf_map *map; 4226e71b04aSChenbo Feng int f_flags; 42399c55f7dSAlexei Starovoitov int err; 42499c55f7dSAlexei Starovoitov 42599c55f7dSAlexei Starovoitov err = CHECK_ATTR(BPF_MAP_CREATE); 42699c55f7dSAlexei Starovoitov if (err) 42799c55f7dSAlexei Starovoitov return -EINVAL; 42899c55f7dSAlexei Starovoitov 4296e71b04aSChenbo Feng f_flags = bpf_get_file_flag(attr->map_flags); 4306e71b04aSChenbo Feng if (f_flags < 0) 4316e71b04aSChenbo Feng return f_flags; 4326e71b04aSChenbo Feng 43396eabe7aSMartin KaFai Lau if (numa_node != NUMA_NO_NODE && 43496e5ae4eSEric Dumazet ((unsigned int)numa_node >= nr_node_ids || 43596e5ae4eSEric Dumazet !node_online(numa_node))) 43696eabe7aSMartin KaFai Lau return -EINVAL; 43796eabe7aSMartin KaFai Lau 43899c55f7dSAlexei Starovoitov /* find map type and init map: hashtable vs rbtree vs bloom vs ... */ 43999c55f7dSAlexei Starovoitov map = find_and_alloc_map(attr); 44099c55f7dSAlexei Starovoitov if (IS_ERR(map)) 44199c55f7dSAlexei Starovoitov return PTR_ERR(map); 44299c55f7dSAlexei Starovoitov 443ad5b177bSMartin KaFai Lau err = bpf_obj_name_cpy(map->name, attr->map_name); 444ad5b177bSMartin KaFai Lau if (err) 445ad5b177bSMartin KaFai Lau goto free_map_nouncharge; 446ad5b177bSMartin KaFai Lau 44799c55f7dSAlexei Starovoitov atomic_set(&map->refcnt, 1); 448c9da161cSDaniel Borkmann atomic_set(&map->usercnt, 1); 44999c55f7dSAlexei Starovoitov 450afdb09c7SChenbo Feng err = security_bpf_map_alloc(map); 451aaac3ba9SAlexei Starovoitov if (err) 45220b2b24fSDaniel Borkmann goto free_map_nouncharge; 453aaac3ba9SAlexei Starovoitov 454afdb09c7SChenbo Feng err = bpf_map_charge_memlock(map); 455afdb09c7SChenbo Feng if (err) 456afdb09c7SChenbo Feng goto free_map_sec; 457afdb09c7SChenbo Feng 458f3f1c054SMartin KaFai Lau err = bpf_map_alloc_id(map); 459f3f1c054SMartin KaFai Lau if (err) 460f3f1c054SMartin KaFai Lau goto free_map; 461f3f1c054SMartin KaFai Lau 4626e71b04aSChenbo Feng err = bpf_map_new_fd(map, f_flags); 463bd5f5f4eSMartin KaFai Lau if (err < 0) { 464bd5f5f4eSMartin KaFai Lau /* failed to allocate fd. 465bd5f5f4eSMartin KaFai Lau * bpf_map_put() is needed because the above 466bd5f5f4eSMartin KaFai Lau * bpf_map_alloc_id() has published the map 467bd5f5f4eSMartin KaFai Lau * to the userspace and the userspace may 468bd5f5f4eSMartin KaFai Lau * have refcnt-ed it through BPF_MAP_GET_FD_BY_ID. 469bd5f5f4eSMartin KaFai Lau */ 470bd5f5f4eSMartin KaFai Lau bpf_map_put(map); 471bd5f5f4eSMartin KaFai Lau return err; 472bd5f5f4eSMartin KaFai Lau } 47399c55f7dSAlexei Starovoitov 474a67edbf4SDaniel Borkmann trace_bpf_map_create(map, err); 47599c55f7dSAlexei Starovoitov return err; 47699c55f7dSAlexei Starovoitov 47799c55f7dSAlexei Starovoitov free_map: 47820b2b24fSDaniel Borkmann bpf_map_uncharge_memlock(map); 479afdb09c7SChenbo Feng free_map_sec: 480afdb09c7SChenbo Feng security_bpf_map_free(map); 48120b2b24fSDaniel Borkmann free_map_nouncharge: 48299c55f7dSAlexei Starovoitov map->ops->map_free(map); 48399c55f7dSAlexei Starovoitov return err; 48499c55f7dSAlexei Starovoitov } 48599c55f7dSAlexei Starovoitov 486db20fd2bSAlexei Starovoitov /* if error is returned, fd is released. 487db20fd2bSAlexei Starovoitov * On success caller should complete fd access with matching fdput() 488db20fd2bSAlexei Starovoitov */ 489c2101297SDaniel Borkmann struct bpf_map *__bpf_map_get(struct fd f) 490db20fd2bSAlexei Starovoitov { 491db20fd2bSAlexei Starovoitov if (!f.file) 492db20fd2bSAlexei Starovoitov return ERR_PTR(-EBADF); 493db20fd2bSAlexei Starovoitov if (f.file->f_op != &bpf_map_fops) { 494db20fd2bSAlexei Starovoitov fdput(f); 495db20fd2bSAlexei Starovoitov return ERR_PTR(-EINVAL); 496db20fd2bSAlexei Starovoitov } 497db20fd2bSAlexei Starovoitov 498c2101297SDaniel Borkmann return f.file->private_data; 499c2101297SDaniel Borkmann } 500c2101297SDaniel Borkmann 50192117d84SAlexei Starovoitov /* prog's and map's refcnt limit */ 50292117d84SAlexei Starovoitov #define BPF_MAX_REFCNT 32768 50392117d84SAlexei Starovoitov 50492117d84SAlexei Starovoitov struct bpf_map *bpf_map_inc(struct bpf_map *map, bool uref) 505c9da161cSDaniel Borkmann { 50692117d84SAlexei Starovoitov if (atomic_inc_return(&map->refcnt) > BPF_MAX_REFCNT) { 50792117d84SAlexei Starovoitov atomic_dec(&map->refcnt); 50892117d84SAlexei Starovoitov return ERR_PTR(-EBUSY); 50992117d84SAlexei Starovoitov } 510c9da161cSDaniel Borkmann if (uref) 511c9da161cSDaniel Borkmann atomic_inc(&map->usercnt); 51292117d84SAlexei Starovoitov return map; 513c9da161cSDaniel Borkmann } 514c9da161cSDaniel Borkmann 515c9da161cSDaniel Borkmann struct bpf_map *bpf_map_get_with_uref(u32 ufd) 516c2101297SDaniel Borkmann { 517c2101297SDaniel Borkmann struct fd f = fdget(ufd); 518c2101297SDaniel Borkmann struct bpf_map *map; 519c2101297SDaniel Borkmann 520c2101297SDaniel Borkmann map = __bpf_map_get(f); 521c2101297SDaniel Borkmann if (IS_ERR(map)) 522c2101297SDaniel Borkmann return map; 523c2101297SDaniel Borkmann 52492117d84SAlexei Starovoitov map = bpf_map_inc(map, true); 525c2101297SDaniel Borkmann fdput(f); 526db20fd2bSAlexei Starovoitov 527db20fd2bSAlexei Starovoitov return map; 528db20fd2bSAlexei Starovoitov } 529db20fd2bSAlexei Starovoitov 530bd5f5f4eSMartin KaFai Lau /* map_idr_lock should have been held */ 531bd5f5f4eSMartin KaFai Lau static struct bpf_map *bpf_map_inc_not_zero(struct bpf_map *map, 532bd5f5f4eSMartin KaFai Lau bool uref) 533bd5f5f4eSMartin KaFai Lau { 534bd5f5f4eSMartin KaFai Lau int refold; 535bd5f5f4eSMartin KaFai Lau 536bd5f5f4eSMartin KaFai Lau refold = __atomic_add_unless(&map->refcnt, 1, 0); 537bd5f5f4eSMartin KaFai Lau 538bd5f5f4eSMartin KaFai Lau if (refold >= BPF_MAX_REFCNT) { 539bd5f5f4eSMartin KaFai Lau __bpf_map_put(map, false); 540bd5f5f4eSMartin KaFai Lau return ERR_PTR(-EBUSY); 541bd5f5f4eSMartin KaFai Lau } 542bd5f5f4eSMartin KaFai Lau 543bd5f5f4eSMartin KaFai Lau if (!refold) 544bd5f5f4eSMartin KaFai Lau return ERR_PTR(-ENOENT); 545bd5f5f4eSMartin KaFai Lau 546bd5f5f4eSMartin KaFai Lau if (uref) 547bd5f5f4eSMartin KaFai Lau atomic_inc(&map->usercnt); 548bd5f5f4eSMartin KaFai Lau 549bd5f5f4eSMartin KaFai Lau return map; 550bd5f5f4eSMartin KaFai Lau } 551bd5f5f4eSMartin KaFai Lau 552b8cdc051SAlexei Starovoitov int __weak bpf_stackmap_copy(struct bpf_map *map, void *key, void *value) 553b8cdc051SAlexei Starovoitov { 554b8cdc051SAlexei Starovoitov return -ENOTSUPP; 555b8cdc051SAlexei Starovoitov } 556b8cdc051SAlexei Starovoitov 557db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */ 558db20fd2bSAlexei Starovoitov #define BPF_MAP_LOOKUP_ELEM_LAST_FIELD value 559db20fd2bSAlexei Starovoitov 560db20fd2bSAlexei Starovoitov static int map_lookup_elem(union bpf_attr *attr) 561db20fd2bSAlexei Starovoitov { 562535e7b4bSMickaël Salaün void __user *ukey = u64_to_user_ptr(attr->key); 563535e7b4bSMickaël Salaün void __user *uvalue = u64_to_user_ptr(attr->value); 564db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 565db20fd2bSAlexei Starovoitov struct bpf_map *map; 5668ebe667cSAlexei Starovoitov void *key, *value, *ptr; 56715a07b33SAlexei Starovoitov u32 value_size; 568592867bfSDaniel Borkmann struct fd f; 569db20fd2bSAlexei Starovoitov int err; 570db20fd2bSAlexei Starovoitov 571db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM)) 572db20fd2bSAlexei Starovoitov return -EINVAL; 573db20fd2bSAlexei Starovoitov 574592867bfSDaniel Borkmann f = fdget(ufd); 575c2101297SDaniel Borkmann map = __bpf_map_get(f); 576db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 577db20fd2bSAlexei Starovoitov return PTR_ERR(map); 578db20fd2bSAlexei Starovoitov 5796e71b04aSChenbo Feng if (!(f.file->f_mode & FMODE_CAN_READ)) { 5806e71b04aSChenbo Feng err = -EPERM; 5816e71b04aSChenbo Feng goto err_put; 5826e71b04aSChenbo Feng } 5836e71b04aSChenbo Feng 584e4448ed8SAl Viro key = memdup_user(ukey, map->key_size); 585e4448ed8SAl Viro if (IS_ERR(key)) { 586e4448ed8SAl Viro err = PTR_ERR(key); 587db20fd2bSAlexei Starovoitov goto err_put; 588e4448ed8SAl Viro } 589db20fd2bSAlexei Starovoitov 59015a07b33SAlexei Starovoitov if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 5918f844938SMartin KaFai Lau map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH || 59215a07b33SAlexei Starovoitov map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) 59315a07b33SAlexei Starovoitov value_size = round_up(map->value_size, 8) * num_possible_cpus(); 59414dc6f04SMartin KaFai Lau else if (IS_FD_MAP(map)) 59514dc6f04SMartin KaFai Lau value_size = sizeof(u32); 59615a07b33SAlexei Starovoitov else 59715a07b33SAlexei Starovoitov value_size = map->value_size; 59815a07b33SAlexei Starovoitov 5998ebe667cSAlexei Starovoitov err = -ENOMEM; 60015a07b33SAlexei Starovoitov value = kmalloc(value_size, GFP_USER | __GFP_NOWARN); 601db20fd2bSAlexei Starovoitov if (!value) 6028ebe667cSAlexei Starovoitov goto free_key; 6038ebe667cSAlexei Starovoitov 604a3884572SJakub Kicinski if (bpf_map_is_dev_bound(map)) { 605a3884572SJakub Kicinski err = bpf_map_offload_lookup_elem(map, key, value); 606a3884572SJakub Kicinski } else if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 6078f844938SMartin KaFai Lau map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) { 60815a07b33SAlexei Starovoitov err = bpf_percpu_hash_copy(map, key, value); 60915a07b33SAlexei Starovoitov } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) { 61015a07b33SAlexei Starovoitov err = bpf_percpu_array_copy(map, key, value); 611557c0c6eSAlexei Starovoitov } else if (map->map_type == BPF_MAP_TYPE_STACK_TRACE) { 612557c0c6eSAlexei Starovoitov err = bpf_stackmap_copy(map, key, value); 61314dc6f04SMartin KaFai Lau } else if (IS_FD_ARRAY(map)) { 61414dc6f04SMartin KaFai Lau err = bpf_fd_array_map_lookup_elem(map, key, value); 61514dc6f04SMartin KaFai Lau } else if (IS_FD_HASH(map)) { 61614dc6f04SMartin KaFai Lau err = bpf_fd_htab_map_lookup_elem(map, key, value); 61715a07b33SAlexei Starovoitov } else { 6188ebe667cSAlexei Starovoitov rcu_read_lock(); 6198ebe667cSAlexei Starovoitov ptr = map->ops->map_lookup_elem(map, key); 6208ebe667cSAlexei Starovoitov if (ptr) 62115a07b33SAlexei Starovoitov memcpy(value, ptr, value_size); 6228ebe667cSAlexei Starovoitov rcu_read_unlock(); 62315a07b33SAlexei Starovoitov err = ptr ? 0 : -ENOENT; 62415a07b33SAlexei Starovoitov } 6258ebe667cSAlexei Starovoitov 62615a07b33SAlexei Starovoitov if (err) 6278ebe667cSAlexei Starovoitov goto free_value; 628db20fd2bSAlexei Starovoitov 629db20fd2bSAlexei Starovoitov err = -EFAULT; 63015a07b33SAlexei Starovoitov if (copy_to_user(uvalue, value, value_size) != 0) 6318ebe667cSAlexei Starovoitov goto free_value; 632db20fd2bSAlexei Starovoitov 633a67edbf4SDaniel Borkmann trace_bpf_map_lookup_elem(map, ufd, key, value); 634db20fd2bSAlexei Starovoitov err = 0; 635db20fd2bSAlexei Starovoitov 6368ebe667cSAlexei Starovoitov free_value: 6378ebe667cSAlexei Starovoitov kfree(value); 638db20fd2bSAlexei Starovoitov free_key: 639db20fd2bSAlexei Starovoitov kfree(key); 640db20fd2bSAlexei Starovoitov err_put: 641db20fd2bSAlexei Starovoitov fdput(f); 642db20fd2bSAlexei Starovoitov return err; 643db20fd2bSAlexei Starovoitov } 644db20fd2bSAlexei Starovoitov 6453274f520SAlexei Starovoitov #define BPF_MAP_UPDATE_ELEM_LAST_FIELD flags 646db20fd2bSAlexei Starovoitov 647db20fd2bSAlexei Starovoitov static int map_update_elem(union bpf_attr *attr) 648db20fd2bSAlexei Starovoitov { 649535e7b4bSMickaël Salaün void __user *ukey = u64_to_user_ptr(attr->key); 650535e7b4bSMickaël Salaün void __user *uvalue = u64_to_user_ptr(attr->value); 651db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 652db20fd2bSAlexei Starovoitov struct bpf_map *map; 653db20fd2bSAlexei Starovoitov void *key, *value; 65415a07b33SAlexei Starovoitov u32 value_size; 655592867bfSDaniel Borkmann struct fd f; 656db20fd2bSAlexei Starovoitov int err; 657db20fd2bSAlexei Starovoitov 658db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_UPDATE_ELEM)) 659db20fd2bSAlexei Starovoitov return -EINVAL; 660db20fd2bSAlexei Starovoitov 661592867bfSDaniel Borkmann f = fdget(ufd); 662c2101297SDaniel Borkmann map = __bpf_map_get(f); 663db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 664db20fd2bSAlexei Starovoitov return PTR_ERR(map); 665db20fd2bSAlexei Starovoitov 6666e71b04aSChenbo Feng if (!(f.file->f_mode & FMODE_CAN_WRITE)) { 6676e71b04aSChenbo Feng err = -EPERM; 6686e71b04aSChenbo Feng goto err_put; 6696e71b04aSChenbo Feng } 6706e71b04aSChenbo Feng 671e4448ed8SAl Viro key = memdup_user(ukey, map->key_size); 672e4448ed8SAl Viro if (IS_ERR(key)) { 673e4448ed8SAl Viro err = PTR_ERR(key); 674db20fd2bSAlexei Starovoitov goto err_put; 675e4448ed8SAl Viro } 676db20fd2bSAlexei Starovoitov 67715a07b33SAlexei Starovoitov if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 6788f844938SMartin KaFai Lau map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH || 67915a07b33SAlexei Starovoitov map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) 68015a07b33SAlexei Starovoitov value_size = round_up(map->value_size, 8) * num_possible_cpus(); 68115a07b33SAlexei Starovoitov else 68215a07b33SAlexei Starovoitov value_size = map->value_size; 68315a07b33SAlexei Starovoitov 684db20fd2bSAlexei Starovoitov err = -ENOMEM; 68515a07b33SAlexei Starovoitov value = kmalloc(value_size, GFP_USER | __GFP_NOWARN); 686db20fd2bSAlexei Starovoitov if (!value) 687db20fd2bSAlexei Starovoitov goto free_key; 688db20fd2bSAlexei Starovoitov 689db20fd2bSAlexei Starovoitov err = -EFAULT; 69015a07b33SAlexei Starovoitov if (copy_from_user(value, uvalue, value_size) != 0) 691db20fd2bSAlexei Starovoitov goto free_value; 692db20fd2bSAlexei Starovoitov 6936710e112SJesper Dangaard Brouer /* Need to create a kthread, thus must support schedule */ 694a3884572SJakub Kicinski if (bpf_map_is_dev_bound(map)) { 695a3884572SJakub Kicinski err = bpf_map_offload_update_elem(map, key, value, attr->flags); 696a3884572SJakub Kicinski goto out; 697a3884572SJakub Kicinski } else if (map->map_type == BPF_MAP_TYPE_CPUMAP) { 6986710e112SJesper Dangaard Brouer err = map->ops->map_update_elem(map, key, value, attr->flags); 6996710e112SJesper Dangaard Brouer goto out; 7006710e112SJesper Dangaard Brouer } 7016710e112SJesper Dangaard Brouer 702b121d1e7SAlexei Starovoitov /* must increment bpf_prog_active to avoid kprobe+bpf triggering from 703b121d1e7SAlexei Starovoitov * inside bpf map update or delete otherwise deadlocks are possible 704b121d1e7SAlexei Starovoitov */ 705b121d1e7SAlexei Starovoitov preempt_disable(); 706b121d1e7SAlexei Starovoitov __this_cpu_inc(bpf_prog_active); 7078f844938SMartin KaFai Lau if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 7088f844938SMartin KaFai Lau map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) { 70915a07b33SAlexei Starovoitov err = bpf_percpu_hash_update(map, key, value, attr->flags); 71015a07b33SAlexei Starovoitov } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) { 71115a07b33SAlexei Starovoitov err = bpf_percpu_array_update(map, key, value, attr->flags); 7129c147b56SMickaël Salaün } else if (IS_FD_ARRAY(map)) { 713d056a788SDaniel Borkmann rcu_read_lock(); 714d056a788SDaniel Borkmann err = bpf_fd_array_map_update_elem(map, f.file, key, value, 715d056a788SDaniel Borkmann attr->flags); 716d056a788SDaniel Borkmann rcu_read_unlock(); 717bcc6b1b7SMartin KaFai Lau } else if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) { 718bcc6b1b7SMartin KaFai Lau rcu_read_lock(); 719bcc6b1b7SMartin KaFai Lau err = bpf_fd_htab_map_update_elem(map, f.file, key, value, 720bcc6b1b7SMartin KaFai Lau attr->flags); 721bcc6b1b7SMartin KaFai Lau rcu_read_unlock(); 72215a07b33SAlexei Starovoitov } else { 723db20fd2bSAlexei Starovoitov rcu_read_lock(); 7243274f520SAlexei Starovoitov err = map->ops->map_update_elem(map, key, value, attr->flags); 725db20fd2bSAlexei Starovoitov rcu_read_unlock(); 72615a07b33SAlexei Starovoitov } 727b121d1e7SAlexei Starovoitov __this_cpu_dec(bpf_prog_active); 728b121d1e7SAlexei Starovoitov preempt_enable(); 7296710e112SJesper Dangaard Brouer out: 730a67edbf4SDaniel Borkmann if (!err) 731a67edbf4SDaniel Borkmann trace_bpf_map_update_elem(map, ufd, key, value); 732db20fd2bSAlexei Starovoitov free_value: 733db20fd2bSAlexei Starovoitov kfree(value); 734db20fd2bSAlexei Starovoitov free_key: 735db20fd2bSAlexei Starovoitov kfree(key); 736db20fd2bSAlexei Starovoitov err_put: 737db20fd2bSAlexei Starovoitov fdput(f); 738db20fd2bSAlexei Starovoitov return err; 739db20fd2bSAlexei Starovoitov } 740db20fd2bSAlexei Starovoitov 741db20fd2bSAlexei Starovoitov #define BPF_MAP_DELETE_ELEM_LAST_FIELD key 742db20fd2bSAlexei Starovoitov 743db20fd2bSAlexei Starovoitov static int map_delete_elem(union bpf_attr *attr) 744db20fd2bSAlexei Starovoitov { 745535e7b4bSMickaël Salaün void __user *ukey = u64_to_user_ptr(attr->key); 746db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 747db20fd2bSAlexei Starovoitov struct bpf_map *map; 748592867bfSDaniel Borkmann struct fd f; 749db20fd2bSAlexei Starovoitov void *key; 750db20fd2bSAlexei Starovoitov int err; 751db20fd2bSAlexei Starovoitov 752db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_DELETE_ELEM)) 753db20fd2bSAlexei Starovoitov return -EINVAL; 754db20fd2bSAlexei Starovoitov 755592867bfSDaniel Borkmann f = fdget(ufd); 756c2101297SDaniel Borkmann map = __bpf_map_get(f); 757db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 758db20fd2bSAlexei Starovoitov return PTR_ERR(map); 759db20fd2bSAlexei Starovoitov 7606e71b04aSChenbo Feng if (!(f.file->f_mode & FMODE_CAN_WRITE)) { 7616e71b04aSChenbo Feng err = -EPERM; 7626e71b04aSChenbo Feng goto err_put; 7636e71b04aSChenbo Feng } 7646e71b04aSChenbo Feng 765e4448ed8SAl Viro key = memdup_user(ukey, map->key_size); 766e4448ed8SAl Viro if (IS_ERR(key)) { 767e4448ed8SAl Viro err = PTR_ERR(key); 768db20fd2bSAlexei Starovoitov goto err_put; 769e4448ed8SAl Viro } 770db20fd2bSAlexei Starovoitov 771a3884572SJakub Kicinski if (bpf_map_is_dev_bound(map)) { 772a3884572SJakub Kicinski err = bpf_map_offload_delete_elem(map, key); 773a3884572SJakub Kicinski goto out; 774a3884572SJakub Kicinski } 775a3884572SJakub Kicinski 776b121d1e7SAlexei Starovoitov preempt_disable(); 777b121d1e7SAlexei Starovoitov __this_cpu_inc(bpf_prog_active); 778db20fd2bSAlexei Starovoitov rcu_read_lock(); 779db20fd2bSAlexei Starovoitov err = map->ops->map_delete_elem(map, key); 780db20fd2bSAlexei Starovoitov rcu_read_unlock(); 781b121d1e7SAlexei Starovoitov __this_cpu_dec(bpf_prog_active); 782b121d1e7SAlexei Starovoitov preempt_enable(); 783a3884572SJakub Kicinski out: 784a67edbf4SDaniel Borkmann if (!err) 785a67edbf4SDaniel Borkmann trace_bpf_map_delete_elem(map, ufd, key); 786db20fd2bSAlexei Starovoitov kfree(key); 787db20fd2bSAlexei Starovoitov err_put: 788db20fd2bSAlexei Starovoitov fdput(f); 789db20fd2bSAlexei Starovoitov return err; 790db20fd2bSAlexei Starovoitov } 791db20fd2bSAlexei Starovoitov 792db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */ 793db20fd2bSAlexei Starovoitov #define BPF_MAP_GET_NEXT_KEY_LAST_FIELD next_key 794db20fd2bSAlexei Starovoitov 795db20fd2bSAlexei Starovoitov static int map_get_next_key(union bpf_attr *attr) 796db20fd2bSAlexei Starovoitov { 797535e7b4bSMickaël Salaün void __user *ukey = u64_to_user_ptr(attr->key); 798535e7b4bSMickaël Salaün void __user *unext_key = u64_to_user_ptr(attr->next_key); 799db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 800db20fd2bSAlexei Starovoitov struct bpf_map *map; 801db20fd2bSAlexei Starovoitov void *key, *next_key; 802592867bfSDaniel Borkmann struct fd f; 803db20fd2bSAlexei Starovoitov int err; 804db20fd2bSAlexei Starovoitov 805db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_GET_NEXT_KEY)) 806db20fd2bSAlexei Starovoitov return -EINVAL; 807db20fd2bSAlexei Starovoitov 808592867bfSDaniel Borkmann f = fdget(ufd); 809c2101297SDaniel Borkmann map = __bpf_map_get(f); 810db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 811db20fd2bSAlexei Starovoitov return PTR_ERR(map); 812db20fd2bSAlexei Starovoitov 8136e71b04aSChenbo Feng if (!(f.file->f_mode & FMODE_CAN_READ)) { 8146e71b04aSChenbo Feng err = -EPERM; 8156e71b04aSChenbo Feng goto err_put; 8166e71b04aSChenbo Feng } 8176e71b04aSChenbo Feng 8188fe45924STeng Qin if (ukey) { 819e4448ed8SAl Viro key = memdup_user(ukey, map->key_size); 820e4448ed8SAl Viro if (IS_ERR(key)) { 821e4448ed8SAl Viro err = PTR_ERR(key); 822db20fd2bSAlexei Starovoitov goto err_put; 823e4448ed8SAl Viro } 8248fe45924STeng Qin } else { 8258fe45924STeng Qin key = NULL; 8268fe45924STeng Qin } 827db20fd2bSAlexei Starovoitov 828db20fd2bSAlexei Starovoitov err = -ENOMEM; 829db20fd2bSAlexei Starovoitov next_key = kmalloc(map->key_size, GFP_USER); 830db20fd2bSAlexei Starovoitov if (!next_key) 831db20fd2bSAlexei Starovoitov goto free_key; 832db20fd2bSAlexei Starovoitov 833a3884572SJakub Kicinski if (bpf_map_is_dev_bound(map)) { 834a3884572SJakub Kicinski err = bpf_map_offload_get_next_key(map, key, next_key); 835a3884572SJakub Kicinski goto out; 836a3884572SJakub Kicinski } 837a3884572SJakub Kicinski 838db20fd2bSAlexei Starovoitov rcu_read_lock(); 839db20fd2bSAlexei Starovoitov err = map->ops->map_get_next_key(map, key, next_key); 840db20fd2bSAlexei Starovoitov rcu_read_unlock(); 841a3884572SJakub Kicinski out: 842db20fd2bSAlexei Starovoitov if (err) 843db20fd2bSAlexei Starovoitov goto free_next_key; 844db20fd2bSAlexei Starovoitov 845db20fd2bSAlexei Starovoitov err = -EFAULT; 846db20fd2bSAlexei Starovoitov if (copy_to_user(unext_key, next_key, map->key_size) != 0) 847db20fd2bSAlexei Starovoitov goto free_next_key; 848db20fd2bSAlexei Starovoitov 849a67edbf4SDaniel Borkmann trace_bpf_map_next_key(map, ufd, key, next_key); 850db20fd2bSAlexei Starovoitov err = 0; 851db20fd2bSAlexei Starovoitov 852db20fd2bSAlexei Starovoitov free_next_key: 853db20fd2bSAlexei Starovoitov kfree(next_key); 854db20fd2bSAlexei Starovoitov free_key: 855db20fd2bSAlexei Starovoitov kfree(key); 856db20fd2bSAlexei Starovoitov err_put: 857db20fd2bSAlexei Starovoitov fdput(f); 858db20fd2bSAlexei Starovoitov return err; 859db20fd2bSAlexei Starovoitov } 860db20fd2bSAlexei Starovoitov 8617de16e3aSJakub Kicinski static const struct bpf_prog_ops * const bpf_prog_types[] = { 8627de16e3aSJakub Kicinski #define BPF_PROG_TYPE(_id, _name) \ 8637de16e3aSJakub Kicinski [_id] = & _name ## _prog_ops, 8647de16e3aSJakub Kicinski #define BPF_MAP_TYPE(_id, _ops) 8657de16e3aSJakub Kicinski #include <linux/bpf_types.h> 8667de16e3aSJakub Kicinski #undef BPF_PROG_TYPE 8677de16e3aSJakub Kicinski #undef BPF_MAP_TYPE 8687de16e3aSJakub Kicinski }; 8697de16e3aSJakub Kicinski 87009756af4SAlexei Starovoitov static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog) 87109756af4SAlexei Starovoitov { 872be9370a7SJohannes Berg if (type >= ARRAY_SIZE(bpf_prog_types) || !bpf_prog_types[type]) 873be9370a7SJohannes Berg return -EINVAL; 87409756af4SAlexei Starovoitov 875ab3f0063SJakub Kicinski if (!bpf_prog_is_dev_bound(prog->aux)) 876be9370a7SJohannes Berg prog->aux->ops = bpf_prog_types[type]; 877ab3f0063SJakub Kicinski else 878ab3f0063SJakub Kicinski prog->aux->ops = &bpf_offload_prog_ops; 87924701eceSDaniel Borkmann prog->type = type; 88009756af4SAlexei Starovoitov return 0; 88109756af4SAlexei Starovoitov } 88209756af4SAlexei Starovoitov 88309756af4SAlexei Starovoitov /* drop refcnt on maps used by eBPF program and free auxilary data */ 88409756af4SAlexei Starovoitov static void free_used_maps(struct bpf_prog_aux *aux) 88509756af4SAlexei Starovoitov { 88609756af4SAlexei Starovoitov int i; 88709756af4SAlexei Starovoitov 88809756af4SAlexei Starovoitov for (i = 0; i < aux->used_map_cnt; i++) 88909756af4SAlexei Starovoitov bpf_map_put(aux->used_maps[i]); 89009756af4SAlexei Starovoitov 89109756af4SAlexei Starovoitov kfree(aux->used_maps); 89209756af4SAlexei Starovoitov } 89309756af4SAlexei Starovoitov 8945ccb071eSDaniel Borkmann int __bpf_prog_charge(struct user_struct *user, u32 pages) 8955ccb071eSDaniel Borkmann { 8965ccb071eSDaniel Borkmann unsigned long memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; 8975ccb071eSDaniel Borkmann unsigned long user_bufs; 8985ccb071eSDaniel Borkmann 8995ccb071eSDaniel Borkmann if (user) { 9005ccb071eSDaniel Borkmann user_bufs = atomic_long_add_return(pages, &user->locked_vm); 9015ccb071eSDaniel Borkmann if (user_bufs > memlock_limit) { 9025ccb071eSDaniel Borkmann atomic_long_sub(pages, &user->locked_vm); 9035ccb071eSDaniel Borkmann return -EPERM; 9045ccb071eSDaniel Borkmann } 9055ccb071eSDaniel Borkmann } 9065ccb071eSDaniel Borkmann 9075ccb071eSDaniel Borkmann return 0; 9085ccb071eSDaniel Borkmann } 9095ccb071eSDaniel Borkmann 9105ccb071eSDaniel Borkmann void __bpf_prog_uncharge(struct user_struct *user, u32 pages) 9115ccb071eSDaniel Borkmann { 9125ccb071eSDaniel Borkmann if (user) 9135ccb071eSDaniel Borkmann atomic_long_sub(pages, &user->locked_vm); 9145ccb071eSDaniel Borkmann } 9155ccb071eSDaniel Borkmann 916aaac3ba9SAlexei Starovoitov static int bpf_prog_charge_memlock(struct bpf_prog *prog) 917aaac3ba9SAlexei Starovoitov { 918aaac3ba9SAlexei Starovoitov struct user_struct *user = get_current_user(); 9195ccb071eSDaniel Borkmann int ret; 920aaac3ba9SAlexei Starovoitov 9215ccb071eSDaniel Borkmann ret = __bpf_prog_charge(user, prog->pages); 9225ccb071eSDaniel Borkmann if (ret) { 923aaac3ba9SAlexei Starovoitov free_uid(user); 9245ccb071eSDaniel Borkmann return ret; 925aaac3ba9SAlexei Starovoitov } 9265ccb071eSDaniel Borkmann 927aaac3ba9SAlexei Starovoitov prog->aux->user = user; 928aaac3ba9SAlexei Starovoitov return 0; 929aaac3ba9SAlexei Starovoitov } 930aaac3ba9SAlexei Starovoitov 931aaac3ba9SAlexei Starovoitov static void bpf_prog_uncharge_memlock(struct bpf_prog *prog) 932aaac3ba9SAlexei Starovoitov { 933aaac3ba9SAlexei Starovoitov struct user_struct *user = prog->aux->user; 934aaac3ba9SAlexei Starovoitov 9355ccb071eSDaniel Borkmann __bpf_prog_uncharge(user, prog->pages); 936aaac3ba9SAlexei Starovoitov free_uid(user); 937aaac3ba9SAlexei Starovoitov } 938aaac3ba9SAlexei Starovoitov 939dc4bb0e2SMartin KaFai Lau static int bpf_prog_alloc_id(struct bpf_prog *prog) 940dc4bb0e2SMartin KaFai Lau { 941dc4bb0e2SMartin KaFai Lau int id; 942dc4bb0e2SMartin KaFai Lau 943dc4bb0e2SMartin KaFai Lau spin_lock_bh(&prog_idr_lock); 944dc4bb0e2SMartin KaFai Lau id = idr_alloc_cyclic(&prog_idr, prog, 1, INT_MAX, GFP_ATOMIC); 945dc4bb0e2SMartin KaFai Lau if (id > 0) 946dc4bb0e2SMartin KaFai Lau prog->aux->id = id; 947dc4bb0e2SMartin KaFai Lau spin_unlock_bh(&prog_idr_lock); 948dc4bb0e2SMartin KaFai Lau 949dc4bb0e2SMartin KaFai Lau /* id is in [1, INT_MAX) */ 950dc4bb0e2SMartin KaFai Lau if (WARN_ON_ONCE(!id)) 951dc4bb0e2SMartin KaFai Lau return -ENOSPC; 952dc4bb0e2SMartin KaFai Lau 953dc4bb0e2SMartin KaFai Lau return id > 0 ? 0 : id; 954dc4bb0e2SMartin KaFai Lau } 955dc4bb0e2SMartin KaFai Lau 956ad8ad79fSJakub Kicinski void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock) 957dc4bb0e2SMartin KaFai Lau { 958ad8ad79fSJakub Kicinski /* cBPF to eBPF migrations are currently not in the idr store. 959ad8ad79fSJakub Kicinski * Offloaded programs are removed from the store when their device 960ad8ad79fSJakub Kicinski * disappears - even if someone grabs an fd to them they are unusable, 961ad8ad79fSJakub Kicinski * simply waiting for refcnt to drop to be freed. 962ad8ad79fSJakub Kicinski */ 963dc4bb0e2SMartin KaFai Lau if (!prog->aux->id) 964dc4bb0e2SMartin KaFai Lau return; 965dc4bb0e2SMartin KaFai Lau 966b16d9aa4SMartin KaFai Lau if (do_idr_lock) 967dc4bb0e2SMartin KaFai Lau spin_lock_bh(&prog_idr_lock); 968b16d9aa4SMartin KaFai Lau else 969b16d9aa4SMartin KaFai Lau __acquire(&prog_idr_lock); 970b16d9aa4SMartin KaFai Lau 971dc4bb0e2SMartin KaFai Lau idr_remove(&prog_idr, prog->aux->id); 972ad8ad79fSJakub Kicinski prog->aux->id = 0; 973b16d9aa4SMartin KaFai Lau 974b16d9aa4SMartin KaFai Lau if (do_idr_lock) 975dc4bb0e2SMartin KaFai Lau spin_unlock_bh(&prog_idr_lock); 976b16d9aa4SMartin KaFai Lau else 977b16d9aa4SMartin KaFai Lau __release(&prog_idr_lock); 978dc4bb0e2SMartin KaFai Lau } 979dc4bb0e2SMartin KaFai Lau 9801aacde3dSDaniel Borkmann static void __bpf_prog_put_rcu(struct rcu_head *rcu) 981abf2e7d6SAlexei Starovoitov { 982abf2e7d6SAlexei Starovoitov struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu); 983abf2e7d6SAlexei Starovoitov 984abf2e7d6SAlexei Starovoitov free_used_maps(aux); 985aaac3ba9SAlexei Starovoitov bpf_prog_uncharge_memlock(aux->prog); 986afdb09c7SChenbo Feng security_bpf_prog_free(aux); 987abf2e7d6SAlexei Starovoitov bpf_prog_free(aux->prog); 988abf2e7d6SAlexei Starovoitov } 989abf2e7d6SAlexei Starovoitov 990b16d9aa4SMartin KaFai Lau static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock) 99109756af4SAlexei Starovoitov { 992a67edbf4SDaniel Borkmann if (atomic_dec_and_test(&prog->aux->refcnt)) { 9934f74d809SDaniel Borkmann int i; 9944f74d809SDaniel Borkmann 995a67edbf4SDaniel Borkmann trace_bpf_prog_put_rcu(prog); 99634ad5580SMartin KaFai Lau /* bpf_prog_free_id() must be called first */ 997b16d9aa4SMartin KaFai Lau bpf_prog_free_id(prog, do_idr_lock); 9984f74d809SDaniel Borkmann 9994f74d809SDaniel Borkmann for (i = 0; i < prog->aux->func_cnt; i++) 10004f74d809SDaniel Borkmann bpf_prog_kallsyms_del(prog->aux->func[i]); 100174451e66SDaniel Borkmann bpf_prog_kallsyms_del(prog); 10024f74d809SDaniel Borkmann 10031aacde3dSDaniel Borkmann call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu); 100409756af4SAlexei Starovoitov } 1005a67edbf4SDaniel Borkmann } 1006b16d9aa4SMartin KaFai Lau 1007b16d9aa4SMartin KaFai Lau void bpf_prog_put(struct bpf_prog *prog) 1008b16d9aa4SMartin KaFai Lau { 1009b16d9aa4SMartin KaFai Lau __bpf_prog_put(prog, true); 1010b16d9aa4SMartin KaFai Lau } 1011e2e9b654SDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_put); 101209756af4SAlexei Starovoitov 101309756af4SAlexei Starovoitov static int bpf_prog_release(struct inode *inode, struct file *filp) 101409756af4SAlexei Starovoitov { 101509756af4SAlexei Starovoitov struct bpf_prog *prog = filp->private_data; 101609756af4SAlexei Starovoitov 10171aacde3dSDaniel Borkmann bpf_prog_put(prog); 101809756af4SAlexei Starovoitov return 0; 101909756af4SAlexei Starovoitov } 102009756af4SAlexei Starovoitov 10217bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS 10227bd509e3SDaniel Borkmann static void bpf_prog_show_fdinfo(struct seq_file *m, struct file *filp) 10237bd509e3SDaniel Borkmann { 10247bd509e3SDaniel Borkmann const struct bpf_prog *prog = filp->private_data; 1025f1f7714eSDaniel Borkmann char prog_tag[sizeof(prog->tag) * 2 + 1] = { }; 10267bd509e3SDaniel Borkmann 1027f1f7714eSDaniel Borkmann bin2hex(prog_tag, prog->tag, sizeof(prog->tag)); 10287bd509e3SDaniel Borkmann seq_printf(m, 10297bd509e3SDaniel Borkmann "prog_type:\t%u\n" 10307bd509e3SDaniel Borkmann "prog_jited:\t%u\n" 1031f1f7714eSDaniel Borkmann "prog_tag:\t%s\n" 10327bd509e3SDaniel Borkmann "memlock:\t%llu\n", 10337bd509e3SDaniel Borkmann prog->type, 10347bd509e3SDaniel Borkmann prog->jited, 1035f1f7714eSDaniel Borkmann prog_tag, 10367bd509e3SDaniel Borkmann prog->pages * 1ULL << PAGE_SHIFT); 10377bd509e3SDaniel Borkmann } 10387bd509e3SDaniel Borkmann #endif 10397bd509e3SDaniel Borkmann 1040f66e448cSChenbo Feng const struct file_operations bpf_prog_fops = { 10417bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS 10427bd509e3SDaniel Borkmann .show_fdinfo = bpf_prog_show_fdinfo, 10437bd509e3SDaniel Borkmann #endif 104409756af4SAlexei Starovoitov .release = bpf_prog_release, 10456e71b04aSChenbo Feng .read = bpf_dummy_read, 10466e71b04aSChenbo Feng .write = bpf_dummy_write, 104709756af4SAlexei Starovoitov }; 104809756af4SAlexei Starovoitov 1049b2197755SDaniel Borkmann int bpf_prog_new_fd(struct bpf_prog *prog) 1050aa79781bSDaniel Borkmann { 1051afdb09c7SChenbo Feng int ret; 1052afdb09c7SChenbo Feng 1053afdb09c7SChenbo Feng ret = security_bpf_prog(prog); 1054afdb09c7SChenbo Feng if (ret < 0) 1055afdb09c7SChenbo Feng return ret; 1056afdb09c7SChenbo Feng 1057aa79781bSDaniel Borkmann return anon_inode_getfd("bpf-prog", &bpf_prog_fops, prog, 1058aa79781bSDaniel Borkmann O_RDWR | O_CLOEXEC); 1059aa79781bSDaniel Borkmann } 1060aa79781bSDaniel Borkmann 1061113214beSDaniel Borkmann static struct bpf_prog *____bpf_prog_get(struct fd f) 106209756af4SAlexei Starovoitov { 106309756af4SAlexei Starovoitov if (!f.file) 106409756af4SAlexei Starovoitov return ERR_PTR(-EBADF); 106509756af4SAlexei Starovoitov if (f.file->f_op != &bpf_prog_fops) { 106609756af4SAlexei Starovoitov fdput(f); 106709756af4SAlexei Starovoitov return ERR_PTR(-EINVAL); 106809756af4SAlexei Starovoitov } 106909756af4SAlexei Starovoitov 1070c2101297SDaniel Borkmann return f.file->private_data; 107109756af4SAlexei Starovoitov } 107209756af4SAlexei Starovoitov 107359d3656dSBrenden Blanco struct bpf_prog *bpf_prog_add(struct bpf_prog *prog, int i) 107492117d84SAlexei Starovoitov { 107559d3656dSBrenden Blanco if (atomic_add_return(i, &prog->aux->refcnt) > BPF_MAX_REFCNT) { 107659d3656dSBrenden Blanco atomic_sub(i, &prog->aux->refcnt); 107792117d84SAlexei Starovoitov return ERR_PTR(-EBUSY); 107892117d84SAlexei Starovoitov } 107992117d84SAlexei Starovoitov return prog; 108092117d84SAlexei Starovoitov } 108159d3656dSBrenden Blanco EXPORT_SYMBOL_GPL(bpf_prog_add); 108259d3656dSBrenden Blanco 1083c540594fSDaniel Borkmann void bpf_prog_sub(struct bpf_prog *prog, int i) 1084c540594fSDaniel Borkmann { 1085c540594fSDaniel Borkmann /* Only to be used for undoing previous bpf_prog_add() in some 1086c540594fSDaniel Borkmann * error path. We still know that another entity in our call 1087c540594fSDaniel Borkmann * path holds a reference to the program, thus atomic_sub() can 1088c540594fSDaniel Borkmann * be safely used in such cases! 1089c540594fSDaniel Borkmann */ 1090c540594fSDaniel Borkmann WARN_ON(atomic_sub_return(i, &prog->aux->refcnt) == 0); 1091c540594fSDaniel Borkmann } 1092c540594fSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_sub); 1093c540594fSDaniel Borkmann 109459d3656dSBrenden Blanco struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog) 109559d3656dSBrenden Blanco { 109659d3656dSBrenden Blanco return bpf_prog_add(prog, 1); 109759d3656dSBrenden Blanco } 109897bc402dSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_inc); 109992117d84SAlexei Starovoitov 1100b16d9aa4SMartin KaFai Lau /* prog_idr_lock should have been held */ 1101a6f6df69SJohn Fastabend struct bpf_prog *bpf_prog_inc_not_zero(struct bpf_prog *prog) 1102b16d9aa4SMartin KaFai Lau { 1103b16d9aa4SMartin KaFai Lau int refold; 1104b16d9aa4SMartin KaFai Lau 1105b16d9aa4SMartin KaFai Lau refold = __atomic_add_unless(&prog->aux->refcnt, 1, 0); 1106b16d9aa4SMartin KaFai Lau 1107b16d9aa4SMartin KaFai Lau if (refold >= BPF_MAX_REFCNT) { 1108b16d9aa4SMartin KaFai Lau __bpf_prog_put(prog, false); 1109b16d9aa4SMartin KaFai Lau return ERR_PTR(-EBUSY); 1110b16d9aa4SMartin KaFai Lau } 1111b16d9aa4SMartin KaFai Lau 1112b16d9aa4SMartin KaFai Lau if (!refold) 1113b16d9aa4SMartin KaFai Lau return ERR_PTR(-ENOENT); 1114b16d9aa4SMartin KaFai Lau 1115b16d9aa4SMartin KaFai Lau return prog; 1116b16d9aa4SMartin KaFai Lau } 1117a6f6df69SJohn Fastabend EXPORT_SYMBOL_GPL(bpf_prog_inc_not_zero); 1118b16d9aa4SMartin KaFai Lau 1119040ee692SAl Viro bool bpf_prog_get_ok(struct bpf_prog *prog, 1120288b3de5SJakub Kicinski enum bpf_prog_type *attach_type, bool attach_drv) 1121248f346fSJakub Kicinski { 1122288b3de5SJakub Kicinski /* not an attachment, just a refcount inc, always allow */ 1123288b3de5SJakub Kicinski if (!attach_type) 1124288b3de5SJakub Kicinski return true; 1125248f346fSJakub Kicinski 1126248f346fSJakub Kicinski if (prog->type != *attach_type) 1127248f346fSJakub Kicinski return false; 1128288b3de5SJakub Kicinski if (bpf_prog_is_dev_bound(prog->aux) && !attach_drv) 1129248f346fSJakub Kicinski return false; 1130248f346fSJakub Kicinski 1131248f346fSJakub Kicinski return true; 1132248f346fSJakub Kicinski } 1133248f346fSJakub Kicinski 1134248f346fSJakub Kicinski static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *attach_type, 1135288b3de5SJakub Kicinski bool attach_drv) 113609756af4SAlexei Starovoitov { 113709756af4SAlexei Starovoitov struct fd f = fdget(ufd); 113809756af4SAlexei Starovoitov struct bpf_prog *prog; 113909756af4SAlexei Starovoitov 1140113214beSDaniel Borkmann prog = ____bpf_prog_get(f); 114109756af4SAlexei Starovoitov if (IS_ERR(prog)) 114209756af4SAlexei Starovoitov return prog; 1143288b3de5SJakub Kicinski if (!bpf_prog_get_ok(prog, attach_type, attach_drv)) { 1144113214beSDaniel Borkmann prog = ERR_PTR(-EINVAL); 1145113214beSDaniel Borkmann goto out; 1146113214beSDaniel Borkmann } 114709756af4SAlexei Starovoitov 114892117d84SAlexei Starovoitov prog = bpf_prog_inc(prog); 1149113214beSDaniel Borkmann out: 115009756af4SAlexei Starovoitov fdput(f); 115109756af4SAlexei Starovoitov return prog; 115209756af4SAlexei Starovoitov } 1153113214beSDaniel Borkmann 1154113214beSDaniel Borkmann struct bpf_prog *bpf_prog_get(u32 ufd) 1155113214beSDaniel Borkmann { 1156288b3de5SJakub Kicinski return __bpf_prog_get(ufd, NULL, false); 1157113214beSDaniel Borkmann } 1158113214beSDaniel Borkmann 1159248f346fSJakub Kicinski struct bpf_prog *bpf_prog_get_type_dev(u32 ufd, enum bpf_prog_type type, 1160288b3de5SJakub Kicinski bool attach_drv) 1161248f346fSJakub Kicinski { 1162288b3de5SJakub Kicinski struct bpf_prog *prog = __bpf_prog_get(ufd, &type, attach_drv); 1163248f346fSJakub Kicinski 1164248f346fSJakub Kicinski if (!IS_ERR(prog)) 1165248f346fSJakub Kicinski trace_bpf_prog_get_type(prog); 1166248f346fSJakub Kicinski return prog; 1167248f346fSJakub Kicinski } 11686c8dfe21SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_prog_get_type_dev); 1169248f346fSJakub Kicinski 117009756af4SAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */ 11711f6f4cb7SJakub Kicinski #define BPF_PROG_LOAD_LAST_FIELD prog_ifindex 117209756af4SAlexei Starovoitov 117309756af4SAlexei Starovoitov static int bpf_prog_load(union bpf_attr *attr) 117409756af4SAlexei Starovoitov { 117509756af4SAlexei Starovoitov enum bpf_prog_type type = attr->prog_type; 117609756af4SAlexei Starovoitov struct bpf_prog *prog; 117709756af4SAlexei Starovoitov int err; 117809756af4SAlexei Starovoitov char license[128]; 117909756af4SAlexei Starovoitov bool is_gpl; 118009756af4SAlexei Starovoitov 118109756af4SAlexei Starovoitov if (CHECK_ATTR(BPF_PROG_LOAD)) 118209756af4SAlexei Starovoitov return -EINVAL; 118309756af4SAlexei Starovoitov 1184e07b98d9SDavid S. Miller if (attr->prog_flags & ~BPF_F_STRICT_ALIGNMENT) 1185e07b98d9SDavid S. Miller return -EINVAL; 1186e07b98d9SDavid S. Miller 118709756af4SAlexei Starovoitov /* copy eBPF program license from user space */ 1188535e7b4bSMickaël Salaün if (strncpy_from_user(license, u64_to_user_ptr(attr->license), 118909756af4SAlexei Starovoitov sizeof(license) - 1) < 0) 119009756af4SAlexei Starovoitov return -EFAULT; 119109756af4SAlexei Starovoitov license[sizeof(license) - 1] = 0; 119209756af4SAlexei Starovoitov 119309756af4SAlexei Starovoitov /* eBPF programs must be GPL compatible to use GPL-ed functions */ 119409756af4SAlexei Starovoitov is_gpl = license_is_gpl_compatible(license); 119509756af4SAlexei Starovoitov 1196ef0915caSDaniel Borkmann if (attr->insn_cnt == 0 || attr->insn_cnt > BPF_MAXINSNS) 1197ef0915caSDaniel Borkmann return -E2BIG; 119809756af4SAlexei Starovoitov 11992541517cSAlexei Starovoitov if (type == BPF_PROG_TYPE_KPROBE && 12002541517cSAlexei Starovoitov attr->kern_version != LINUX_VERSION_CODE) 12012541517cSAlexei Starovoitov return -EINVAL; 12022541517cSAlexei Starovoitov 120380b7d819SChenbo Feng if (type != BPF_PROG_TYPE_SOCKET_FILTER && 120480b7d819SChenbo Feng type != BPF_PROG_TYPE_CGROUP_SKB && 120580b7d819SChenbo Feng !capable(CAP_SYS_ADMIN)) 12061be7f75dSAlexei Starovoitov return -EPERM; 12071be7f75dSAlexei Starovoitov 120809756af4SAlexei Starovoitov /* plain bpf_prog allocation */ 120909756af4SAlexei Starovoitov prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER); 121009756af4SAlexei Starovoitov if (!prog) 121109756af4SAlexei Starovoitov return -ENOMEM; 121209756af4SAlexei Starovoitov 12139a18eedbSJakub Kicinski prog->aux->offload_requested = !!attr->prog_ifindex; 12149a18eedbSJakub Kicinski 1215afdb09c7SChenbo Feng err = security_bpf_prog_alloc(prog->aux); 1216aaac3ba9SAlexei Starovoitov if (err) 1217aaac3ba9SAlexei Starovoitov goto free_prog_nouncharge; 1218aaac3ba9SAlexei Starovoitov 1219afdb09c7SChenbo Feng err = bpf_prog_charge_memlock(prog); 1220afdb09c7SChenbo Feng if (err) 1221afdb09c7SChenbo Feng goto free_prog_sec; 1222afdb09c7SChenbo Feng 122309756af4SAlexei Starovoitov prog->len = attr->insn_cnt; 122409756af4SAlexei Starovoitov 122509756af4SAlexei Starovoitov err = -EFAULT; 1226535e7b4bSMickaël Salaün if (copy_from_user(prog->insns, u64_to_user_ptr(attr->insns), 1227aafe6ae9SDaniel Borkmann bpf_prog_insn_size(prog)) != 0) 122809756af4SAlexei Starovoitov goto free_prog; 122909756af4SAlexei Starovoitov 123009756af4SAlexei Starovoitov prog->orig_prog = NULL; 1231a91263d5SDaniel Borkmann prog->jited = 0; 123209756af4SAlexei Starovoitov 123309756af4SAlexei Starovoitov atomic_set(&prog->aux->refcnt, 1); 1234a91263d5SDaniel Borkmann prog->gpl_compatible = is_gpl ? 1 : 0; 123509756af4SAlexei Starovoitov 12369a18eedbSJakub Kicinski if (bpf_prog_is_dev_bound(prog->aux)) { 1237ab3f0063SJakub Kicinski err = bpf_prog_offload_init(prog, attr); 1238ab3f0063SJakub Kicinski if (err) 1239ab3f0063SJakub Kicinski goto free_prog; 1240ab3f0063SJakub Kicinski } 1241ab3f0063SJakub Kicinski 124209756af4SAlexei Starovoitov /* find program type: socket_filter vs tracing_filter */ 124309756af4SAlexei Starovoitov err = find_prog_type(type, prog); 124409756af4SAlexei Starovoitov if (err < 0) 124509756af4SAlexei Starovoitov goto free_prog; 124609756af4SAlexei Starovoitov 1247cb4d2b3fSMartin KaFai Lau prog->aux->load_time = ktime_get_boot_ns(); 1248cb4d2b3fSMartin KaFai Lau err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name); 1249cb4d2b3fSMartin KaFai Lau if (err) 1250cb4d2b3fSMartin KaFai Lau goto free_prog; 1251cb4d2b3fSMartin KaFai Lau 125209756af4SAlexei Starovoitov /* run eBPF verifier */ 12539bac3d6dSAlexei Starovoitov err = bpf_check(&prog, attr); 125409756af4SAlexei Starovoitov if (err < 0) 125509756af4SAlexei Starovoitov goto free_used_maps; 125609756af4SAlexei Starovoitov 125709756af4SAlexei Starovoitov /* eBPF program is ready to be JITed */ 12581c2a088aSAlexei Starovoitov if (!prog->bpf_func) 1259d1c55ab5SDaniel Borkmann prog = bpf_prog_select_runtime(prog, &err); 126004fd61abSAlexei Starovoitov if (err < 0) 126104fd61abSAlexei Starovoitov goto free_used_maps; 126209756af4SAlexei Starovoitov 1263dc4bb0e2SMartin KaFai Lau err = bpf_prog_alloc_id(prog); 1264dc4bb0e2SMartin KaFai Lau if (err) 1265dc4bb0e2SMartin KaFai Lau goto free_used_maps; 1266dc4bb0e2SMartin KaFai Lau 1267aa79781bSDaniel Borkmann err = bpf_prog_new_fd(prog); 1268b16d9aa4SMartin KaFai Lau if (err < 0) { 1269b16d9aa4SMartin KaFai Lau /* failed to allocate fd. 1270b16d9aa4SMartin KaFai Lau * bpf_prog_put() is needed because the above 1271b16d9aa4SMartin KaFai Lau * bpf_prog_alloc_id() has published the prog 1272b16d9aa4SMartin KaFai Lau * to the userspace and the userspace may 1273b16d9aa4SMartin KaFai Lau * have refcnt-ed it through BPF_PROG_GET_FD_BY_ID. 1274b16d9aa4SMartin KaFai Lau */ 1275b16d9aa4SMartin KaFai Lau bpf_prog_put(prog); 1276b16d9aa4SMartin KaFai Lau return err; 1277b16d9aa4SMartin KaFai Lau } 127809756af4SAlexei Starovoitov 127974451e66SDaniel Borkmann bpf_prog_kallsyms_add(prog); 1280a67edbf4SDaniel Borkmann trace_bpf_prog_load(prog, err); 128109756af4SAlexei Starovoitov return err; 128209756af4SAlexei Starovoitov 128309756af4SAlexei Starovoitov free_used_maps: 128409756af4SAlexei Starovoitov free_used_maps(prog->aux); 128509756af4SAlexei Starovoitov free_prog: 1286aaac3ba9SAlexei Starovoitov bpf_prog_uncharge_memlock(prog); 1287afdb09c7SChenbo Feng free_prog_sec: 1288afdb09c7SChenbo Feng security_bpf_prog_free(prog->aux); 1289aaac3ba9SAlexei Starovoitov free_prog_nouncharge: 129009756af4SAlexei Starovoitov bpf_prog_free(prog); 129109756af4SAlexei Starovoitov return err; 129209756af4SAlexei Starovoitov } 129309756af4SAlexei Starovoitov 12946e71b04aSChenbo Feng #define BPF_OBJ_LAST_FIELD file_flags 1295b2197755SDaniel Borkmann 1296b2197755SDaniel Borkmann static int bpf_obj_pin(const union bpf_attr *attr) 1297b2197755SDaniel Borkmann { 12986e71b04aSChenbo Feng if (CHECK_ATTR(BPF_OBJ) || attr->file_flags != 0) 1299b2197755SDaniel Borkmann return -EINVAL; 1300b2197755SDaniel Borkmann 1301535e7b4bSMickaël Salaün return bpf_obj_pin_user(attr->bpf_fd, u64_to_user_ptr(attr->pathname)); 1302b2197755SDaniel Borkmann } 1303b2197755SDaniel Borkmann 1304b2197755SDaniel Borkmann static int bpf_obj_get(const union bpf_attr *attr) 1305b2197755SDaniel Borkmann { 13066e71b04aSChenbo Feng if (CHECK_ATTR(BPF_OBJ) || attr->bpf_fd != 0 || 13076e71b04aSChenbo Feng attr->file_flags & ~BPF_OBJ_FLAG_MASK) 1308b2197755SDaniel Borkmann return -EINVAL; 1309b2197755SDaniel Borkmann 13106e71b04aSChenbo Feng return bpf_obj_get_user(u64_to_user_ptr(attr->pathname), 13116e71b04aSChenbo Feng attr->file_flags); 1312b2197755SDaniel Borkmann } 1313b2197755SDaniel Borkmann 1314f4324551SDaniel Mack #ifdef CONFIG_CGROUP_BPF 1315f4324551SDaniel Mack 1316464bc0fdSJohn Fastabend #define BPF_PROG_ATTACH_LAST_FIELD attach_flags 1317174a79ffSJohn Fastabend 13185a67da2aSJohn Fastabend static int sockmap_get_from_fd(const union bpf_attr *attr, bool attach) 1319174a79ffSJohn Fastabend { 13205a67da2aSJohn Fastabend struct bpf_prog *prog = NULL; 1321174a79ffSJohn Fastabend int ufd = attr->target_fd; 1322174a79ffSJohn Fastabend struct bpf_map *map; 1323174a79ffSJohn Fastabend struct fd f; 1324174a79ffSJohn Fastabend int err; 1325174a79ffSJohn Fastabend 1326174a79ffSJohn Fastabend f = fdget(ufd); 1327174a79ffSJohn Fastabend map = __bpf_map_get(f); 1328174a79ffSJohn Fastabend if (IS_ERR(map)) 1329174a79ffSJohn Fastabend return PTR_ERR(map); 1330174a79ffSJohn Fastabend 13315a67da2aSJohn Fastabend if (attach) { 13325a67da2aSJohn Fastabend prog = bpf_prog_get_type(attr->attach_bpf_fd, 13335a67da2aSJohn Fastabend BPF_PROG_TYPE_SK_SKB); 1334464bc0fdSJohn Fastabend if (IS_ERR(prog)) { 1335174a79ffSJohn Fastabend fdput(f); 1336464bc0fdSJohn Fastabend return PTR_ERR(prog); 1337174a79ffSJohn Fastabend } 13385a67da2aSJohn Fastabend } 1339174a79ffSJohn Fastabend 13405a67da2aSJohn Fastabend err = sock_map_prog(map, prog, attr->attach_type); 1341174a79ffSJohn Fastabend if (err) { 1342174a79ffSJohn Fastabend fdput(f); 13435a67da2aSJohn Fastabend if (prog) 1344464bc0fdSJohn Fastabend bpf_prog_put(prog); 1345ae2b27b8SDan Carpenter return err; 1346174a79ffSJohn Fastabend } 1347174a79ffSJohn Fastabend 1348174a79ffSJohn Fastabend fdput(f); 1349ae2b27b8SDan Carpenter return 0; 1350174a79ffSJohn Fastabend } 1351f4324551SDaniel Mack 1352324bda9eSAlexei Starovoitov #define BPF_F_ATTACH_MASK \ 1353324bda9eSAlexei Starovoitov (BPF_F_ALLOW_OVERRIDE | BPF_F_ALLOW_MULTI) 1354324bda9eSAlexei Starovoitov 1355f4324551SDaniel Mack static int bpf_prog_attach(const union bpf_attr *attr) 1356f4324551SDaniel Mack { 13577f677633SAlexei Starovoitov enum bpf_prog_type ptype; 1358f4324551SDaniel Mack struct bpf_prog *prog; 1359f4324551SDaniel Mack struct cgroup *cgrp; 13607f677633SAlexei Starovoitov int ret; 1361f4324551SDaniel Mack 1362f4324551SDaniel Mack if (!capable(CAP_NET_ADMIN)) 1363f4324551SDaniel Mack return -EPERM; 1364f4324551SDaniel Mack 1365f4324551SDaniel Mack if (CHECK_ATTR(BPF_PROG_ATTACH)) 1366f4324551SDaniel Mack return -EINVAL; 1367f4324551SDaniel Mack 1368324bda9eSAlexei Starovoitov if (attr->attach_flags & ~BPF_F_ATTACH_MASK) 13697f677633SAlexei Starovoitov return -EINVAL; 13707f677633SAlexei Starovoitov 1371f4324551SDaniel Mack switch (attr->attach_type) { 1372f4324551SDaniel Mack case BPF_CGROUP_INET_INGRESS: 1373f4324551SDaniel Mack case BPF_CGROUP_INET_EGRESS: 1374b2cd1257SDavid Ahern ptype = BPF_PROG_TYPE_CGROUP_SKB; 1375b2cd1257SDavid Ahern break; 137661023658SDavid Ahern case BPF_CGROUP_INET_SOCK_CREATE: 137761023658SDavid Ahern ptype = BPF_PROG_TYPE_CGROUP_SOCK; 137861023658SDavid Ahern break; 137940304b2aSLawrence Brakmo case BPF_CGROUP_SOCK_OPS: 138040304b2aSLawrence Brakmo ptype = BPF_PROG_TYPE_SOCK_OPS; 138140304b2aSLawrence Brakmo break; 1382ebc614f6SRoman Gushchin case BPF_CGROUP_DEVICE: 1383ebc614f6SRoman Gushchin ptype = BPF_PROG_TYPE_CGROUP_DEVICE; 1384ebc614f6SRoman Gushchin break; 1385464bc0fdSJohn Fastabend case BPF_SK_SKB_STREAM_PARSER: 1386464bc0fdSJohn Fastabend case BPF_SK_SKB_STREAM_VERDICT: 13875a67da2aSJohn Fastabend return sockmap_get_from_fd(attr, true); 1388b2cd1257SDavid Ahern default: 1389b2cd1257SDavid Ahern return -EINVAL; 1390b2cd1257SDavid Ahern } 1391b2cd1257SDavid Ahern 1392b2cd1257SDavid Ahern prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype); 1393f4324551SDaniel Mack if (IS_ERR(prog)) 1394f4324551SDaniel Mack return PTR_ERR(prog); 1395f4324551SDaniel Mack 1396f4324551SDaniel Mack cgrp = cgroup_get_from_fd(attr->target_fd); 1397f4324551SDaniel Mack if (IS_ERR(cgrp)) { 1398f4324551SDaniel Mack bpf_prog_put(prog); 1399f4324551SDaniel Mack return PTR_ERR(cgrp); 1400f4324551SDaniel Mack } 1401f4324551SDaniel Mack 1402324bda9eSAlexei Starovoitov ret = cgroup_bpf_attach(cgrp, prog, attr->attach_type, 1403324bda9eSAlexei Starovoitov attr->attach_flags); 14047f677633SAlexei Starovoitov if (ret) 14057f677633SAlexei Starovoitov bpf_prog_put(prog); 1406f4324551SDaniel Mack cgroup_put(cgrp); 1407f4324551SDaniel Mack 14087f677633SAlexei Starovoitov return ret; 1409f4324551SDaniel Mack } 1410f4324551SDaniel Mack 1411f4324551SDaniel Mack #define BPF_PROG_DETACH_LAST_FIELD attach_type 1412f4324551SDaniel Mack 1413f4324551SDaniel Mack static int bpf_prog_detach(const union bpf_attr *attr) 1414f4324551SDaniel Mack { 1415324bda9eSAlexei Starovoitov enum bpf_prog_type ptype; 1416324bda9eSAlexei Starovoitov struct bpf_prog *prog; 1417f4324551SDaniel Mack struct cgroup *cgrp; 14187f677633SAlexei Starovoitov int ret; 1419f4324551SDaniel Mack 1420f4324551SDaniel Mack if (!capable(CAP_NET_ADMIN)) 1421f4324551SDaniel Mack return -EPERM; 1422f4324551SDaniel Mack 1423f4324551SDaniel Mack if (CHECK_ATTR(BPF_PROG_DETACH)) 1424f4324551SDaniel Mack return -EINVAL; 1425f4324551SDaniel Mack 1426f4324551SDaniel Mack switch (attr->attach_type) { 1427f4324551SDaniel Mack case BPF_CGROUP_INET_INGRESS: 1428f4324551SDaniel Mack case BPF_CGROUP_INET_EGRESS: 1429324bda9eSAlexei Starovoitov ptype = BPF_PROG_TYPE_CGROUP_SKB; 1430324bda9eSAlexei Starovoitov break; 143161023658SDavid Ahern case BPF_CGROUP_INET_SOCK_CREATE: 1432324bda9eSAlexei Starovoitov ptype = BPF_PROG_TYPE_CGROUP_SOCK; 1433324bda9eSAlexei Starovoitov break; 143440304b2aSLawrence Brakmo case BPF_CGROUP_SOCK_OPS: 1435324bda9eSAlexei Starovoitov ptype = BPF_PROG_TYPE_SOCK_OPS; 1436f4324551SDaniel Mack break; 1437ebc614f6SRoman Gushchin case BPF_CGROUP_DEVICE: 1438ebc614f6SRoman Gushchin ptype = BPF_PROG_TYPE_CGROUP_DEVICE; 1439ebc614f6SRoman Gushchin break; 14405a67da2aSJohn Fastabend case BPF_SK_SKB_STREAM_PARSER: 14415a67da2aSJohn Fastabend case BPF_SK_SKB_STREAM_VERDICT: 1442324bda9eSAlexei Starovoitov return sockmap_get_from_fd(attr, false); 1443f4324551SDaniel Mack default: 1444f4324551SDaniel Mack return -EINVAL; 1445f4324551SDaniel Mack } 1446f4324551SDaniel Mack 1447324bda9eSAlexei Starovoitov cgrp = cgroup_get_from_fd(attr->target_fd); 1448324bda9eSAlexei Starovoitov if (IS_ERR(cgrp)) 1449324bda9eSAlexei Starovoitov return PTR_ERR(cgrp); 1450324bda9eSAlexei Starovoitov 1451324bda9eSAlexei Starovoitov prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype); 1452324bda9eSAlexei Starovoitov if (IS_ERR(prog)) 1453324bda9eSAlexei Starovoitov prog = NULL; 1454324bda9eSAlexei Starovoitov 1455324bda9eSAlexei Starovoitov ret = cgroup_bpf_detach(cgrp, prog, attr->attach_type, 0); 1456324bda9eSAlexei Starovoitov if (prog) 1457324bda9eSAlexei Starovoitov bpf_prog_put(prog); 1458324bda9eSAlexei Starovoitov cgroup_put(cgrp); 14597f677633SAlexei Starovoitov return ret; 1460f4324551SDaniel Mack } 146140304b2aSLawrence Brakmo 1462468e2f64SAlexei Starovoitov #define BPF_PROG_QUERY_LAST_FIELD query.prog_cnt 1463468e2f64SAlexei Starovoitov 1464468e2f64SAlexei Starovoitov static int bpf_prog_query(const union bpf_attr *attr, 1465468e2f64SAlexei Starovoitov union bpf_attr __user *uattr) 1466468e2f64SAlexei Starovoitov { 1467468e2f64SAlexei Starovoitov struct cgroup *cgrp; 1468468e2f64SAlexei Starovoitov int ret; 1469468e2f64SAlexei Starovoitov 1470468e2f64SAlexei Starovoitov if (!capable(CAP_NET_ADMIN)) 1471468e2f64SAlexei Starovoitov return -EPERM; 1472468e2f64SAlexei Starovoitov if (CHECK_ATTR(BPF_PROG_QUERY)) 1473468e2f64SAlexei Starovoitov return -EINVAL; 1474468e2f64SAlexei Starovoitov if (attr->query.query_flags & ~BPF_F_QUERY_EFFECTIVE) 1475468e2f64SAlexei Starovoitov return -EINVAL; 1476468e2f64SAlexei Starovoitov 1477468e2f64SAlexei Starovoitov switch (attr->query.attach_type) { 1478468e2f64SAlexei Starovoitov case BPF_CGROUP_INET_INGRESS: 1479468e2f64SAlexei Starovoitov case BPF_CGROUP_INET_EGRESS: 1480468e2f64SAlexei Starovoitov case BPF_CGROUP_INET_SOCK_CREATE: 1481468e2f64SAlexei Starovoitov case BPF_CGROUP_SOCK_OPS: 1482ebc614f6SRoman Gushchin case BPF_CGROUP_DEVICE: 1483468e2f64SAlexei Starovoitov break; 1484468e2f64SAlexei Starovoitov default: 1485468e2f64SAlexei Starovoitov return -EINVAL; 1486468e2f64SAlexei Starovoitov } 1487468e2f64SAlexei Starovoitov cgrp = cgroup_get_from_fd(attr->query.target_fd); 1488468e2f64SAlexei Starovoitov if (IS_ERR(cgrp)) 1489468e2f64SAlexei Starovoitov return PTR_ERR(cgrp); 1490468e2f64SAlexei Starovoitov ret = cgroup_bpf_query(cgrp, attr, uattr); 1491468e2f64SAlexei Starovoitov cgroup_put(cgrp); 1492468e2f64SAlexei Starovoitov return ret; 1493468e2f64SAlexei Starovoitov } 1494f4324551SDaniel Mack #endif /* CONFIG_CGROUP_BPF */ 1495f4324551SDaniel Mack 14961cf1cae9SAlexei Starovoitov #define BPF_PROG_TEST_RUN_LAST_FIELD test.duration 14971cf1cae9SAlexei Starovoitov 14981cf1cae9SAlexei Starovoitov static int bpf_prog_test_run(const union bpf_attr *attr, 14991cf1cae9SAlexei Starovoitov union bpf_attr __user *uattr) 15001cf1cae9SAlexei Starovoitov { 15011cf1cae9SAlexei Starovoitov struct bpf_prog *prog; 15021cf1cae9SAlexei Starovoitov int ret = -ENOTSUPP; 15031cf1cae9SAlexei Starovoitov 150461f3c964SAlexei Starovoitov if (!capable(CAP_SYS_ADMIN)) 150561f3c964SAlexei Starovoitov return -EPERM; 15061cf1cae9SAlexei Starovoitov if (CHECK_ATTR(BPF_PROG_TEST_RUN)) 15071cf1cae9SAlexei Starovoitov return -EINVAL; 15081cf1cae9SAlexei Starovoitov 15091cf1cae9SAlexei Starovoitov prog = bpf_prog_get(attr->test.prog_fd); 15101cf1cae9SAlexei Starovoitov if (IS_ERR(prog)) 15111cf1cae9SAlexei Starovoitov return PTR_ERR(prog); 15121cf1cae9SAlexei Starovoitov 15131cf1cae9SAlexei Starovoitov if (prog->aux->ops->test_run) 15141cf1cae9SAlexei Starovoitov ret = prog->aux->ops->test_run(prog, attr, uattr); 15151cf1cae9SAlexei Starovoitov 15161cf1cae9SAlexei Starovoitov bpf_prog_put(prog); 15171cf1cae9SAlexei Starovoitov return ret; 15181cf1cae9SAlexei Starovoitov } 15191cf1cae9SAlexei Starovoitov 152034ad5580SMartin KaFai Lau #define BPF_OBJ_GET_NEXT_ID_LAST_FIELD next_id 152134ad5580SMartin KaFai Lau 152234ad5580SMartin KaFai Lau static int bpf_obj_get_next_id(const union bpf_attr *attr, 152334ad5580SMartin KaFai Lau union bpf_attr __user *uattr, 152434ad5580SMartin KaFai Lau struct idr *idr, 152534ad5580SMartin KaFai Lau spinlock_t *lock) 152634ad5580SMartin KaFai Lau { 152734ad5580SMartin KaFai Lau u32 next_id = attr->start_id; 152834ad5580SMartin KaFai Lau int err = 0; 152934ad5580SMartin KaFai Lau 153034ad5580SMartin KaFai Lau if (CHECK_ATTR(BPF_OBJ_GET_NEXT_ID) || next_id >= INT_MAX) 153134ad5580SMartin KaFai Lau return -EINVAL; 153234ad5580SMartin KaFai Lau 153334ad5580SMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) 153434ad5580SMartin KaFai Lau return -EPERM; 153534ad5580SMartin KaFai Lau 153634ad5580SMartin KaFai Lau next_id++; 153734ad5580SMartin KaFai Lau spin_lock_bh(lock); 153834ad5580SMartin KaFai Lau if (!idr_get_next(idr, &next_id)) 153934ad5580SMartin KaFai Lau err = -ENOENT; 154034ad5580SMartin KaFai Lau spin_unlock_bh(lock); 154134ad5580SMartin KaFai Lau 154234ad5580SMartin KaFai Lau if (!err) 154334ad5580SMartin KaFai Lau err = put_user(next_id, &uattr->next_id); 154434ad5580SMartin KaFai Lau 154534ad5580SMartin KaFai Lau return err; 154634ad5580SMartin KaFai Lau } 154734ad5580SMartin KaFai Lau 1548b16d9aa4SMartin KaFai Lau #define BPF_PROG_GET_FD_BY_ID_LAST_FIELD prog_id 1549b16d9aa4SMartin KaFai Lau 1550b16d9aa4SMartin KaFai Lau static int bpf_prog_get_fd_by_id(const union bpf_attr *attr) 1551b16d9aa4SMartin KaFai Lau { 1552b16d9aa4SMartin KaFai Lau struct bpf_prog *prog; 1553b16d9aa4SMartin KaFai Lau u32 id = attr->prog_id; 1554b16d9aa4SMartin KaFai Lau int fd; 1555b16d9aa4SMartin KaFai Lau 1556b16d9aa4SMartin KaFai Lau if (CHECK_ATTR(BPF_PROG_GET_FD_BY_ID)) 1557b16d9aa4SMartin KaFai Lau return -EINVAL; 1558b16d9aa4SMartin KaFai Lau 1559b16d9aa4SMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) 1560b16d9aa4SMartin KaFai Lau return -EPERM; 1561b16d9aa4SMartin KaFai Lau 1562b16d9aa4SMartin KaFai Lau spin_lock_bh(&prog_idr_lock); 1563b16d9aa4SMartin KaFai Lau prog = idr_find(&prog_idr, id); 1564b16d9aa4SMartin KaFai Lau if (prog) 1565b16d9aa4SMartin KaFai Lau prog = bpf_prog_inc_not_zero(prog); 1566b16d9aa4SMartin KaFai Lau else 1567b16d9aa4SMartin KaFai Lau prog = ERR_PTR(-ENOENT); 1568b16d9aa4SMartin KaFai Lau spin_unlock_bh(&prog_idr_lock); 1569b16d9aa4SMartin KaFai Lau 1570b16d9aa4SMartin KaFai Lau if (IS_ERR(prog)) 1571b16d9aa4SMartin KaFai Lau return PTR_ERR(prog); 1572b16d9aa4SMartin KaFai Lau 1573b16d9aa4SMartin KaFai Lau fd = bpf_prog_new_fd(prog); 1574b16d9aa4SMartin KaFai Lau if (fd < 0) 1575b16d9aa4SMartin KaFai Lau bpf_prog_put(prog); 1576b16d9aa4SMartin KaFai Lau 1577b16d9aa4SMartin KaFai Lau return fd; 1578b16d9aa4SMartin KaFai Lau } 1579b16d9aa4SMartin KaFai Lau 15806e71b04aSChenbo Feng #define BPF_MAP_GET_FD_BY_ID_LAST_FIELD open_flags 1581bd5f5f4eSMartin KaFai Lau 1582bd5f5f4eSMartin KaFai Lau static int bpf_map_get_fd_by_id(const union bpf_attr *attr) 1583bd5f5f4eSMartin KaFai Lau { 1584bd5f5f4eSMartin KaFai Lau struct bpf_map *map; 1585bd5f5f4eSMartin KaFai Lau u32 id = attr->map_id; 15866e71b04aSChenbo Feng int f_flags; 1587bd5f5f4eSMartin KaFai Lau int fd; 1588bd5f5f4eSMartin KaFai Lau 15896e71b04aSChenbo Feng if (CHECK_ATTR(BPF_MAP_GET_FD_BY_ID) || 15906e71b04aSChenbo Feng attr->open_flags & ~BPF_OBJ_FLAG_MASK) 1591bd5f5f4eSMartin KaFai Lau return -EINVAL; 1592bd5f5f4eSMartin KaFai Lau 1593bd5f5f4eSMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) 1594bd5f5f4eSMartin KaFai Lau return -EPERM; 1595bd5f5f4eSMartin KaFai Lau 15966e71b04aSChenbo Feng f_flags = bpf_get_file_flag(attr->open_flags); 15976e71b04aSChenbo Feng if (f_flags < 0) 15986e71b04aSChenbo Feng return f_flags; 15996e71b04aSChenbo Feng 1600bd5f5f4eSMartin KaFai Lau spin_lock_bh(&map_idr_lock); 1601bd5f5f4eSMartin KaFai Lau map = idr_find(&map_idr, id); 1602bd5f5f4eSMartin KaFai Lau if (map) 1603bd5f5f4eSMartin KaFai Lau map = bpf_map_inc_not_zero(map, true); 1604bd5f5f4eSMartin KaFai Lau else 1605bd5f5f4eSMartin KaFai Lau map = ERR_PTR(-ENOENT); 1606bd5f5f4eSMartin KaFai Lau spin_unlock_bh(&map_idr_lock); 1607bd5f5f4eSMartin KaFai Lau 1608bd5f5f4eSMartin KaFai Lau if (IS_ERR(map)) 1609bd5f5f4eSMartin KaFai Lau return PTR_ERR(map); 1610bd5f5f4eSMartin KaFai Lau 16116e71b04aSChenbo Feng fd = bpf_map_new_fd(map, f_flags); 1612bd5f5f4eSMartin KaFai Lau if (fd < 0) 1613bd5f5f4eSMartin KaFai Lau bpf_map_put(map); 1614bd5f5f4eSMartin KaFai Lau 1615bd5f5f4eSMartin KaFai Lau return fd; 1616bd5f5f4eSMartin KaFai Lau } 1617bd5f5f4eSMartin KaFai Lau 16187105e828SDaniel Borkmann static const struct bpf_map *bpf_map_from_imm(const struct bpf_prog *prog, 16197105e828SDaniel Borkmann unsigned long addr) 16207105e828SDaniel Borkmann { 16217105e828SDaniel Borkmann int i; 16227105e828SDaniel Borkmann 16237105e828SDaniel Borkmann for (i = 0; i < prog->aux->used_map_cnt; i++) 16247105e828SDaniel Borkmann if (prog->aux->used_maps[i] == (void *)addr) 16257105e828SDaniel Borkmann return prog->aux->used_maps[i]; 16267105e828SDaniel Borkmann return NULL; 16277105e828SDaniel Borkmann } 16287105e828SDaniel Borkmann 16297105e828SDaniel Borkmann static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog) 16307105e828SDaniel Borkmann { 16317105e828SDaniel Borkmann const struct bpf_map *map; 16327105e828SDaniel Borkmann struct bpf_insn *insns; 16337105e828SDaniel Borkmann u64 imm; 16347105e828SDaniel Borkmann int i; 16357105e828SDaniel Borkmann 16367105e828SDaniel Borkmann insns = kmemdup(prog->insnsi, bpf_prog_insn_size(prog), 16377105e828SDaniel Borkmann GFP_USER); 16387105e828SDaniel Borkmann if (!insns) 16397105e828SDaniel Borkmann return insns; 16407105e828SDaniel Borkmann 16417105e828SDaniel Borkmann for (i = 0; i < prog->len; i++) { 16427105e828SDaniel Borkmann if (insns[i].code == (BPF_JMP | BPF_TAIL_CALL)) { 16437105e828SDaniel Borkmann insns[i].code = BPF_JMP | BPF_CALL; 16447105e828SDaniel Borkmann insns[i].imm = BPF_FUNC_tail_call; 16457105e828SDaniel Borkmann /* fall-through */ 16467105e828SDaniel Borkmann } 16477105e828SDaniel Borkmann if (insns[i].code == (BPF_JMP | BPF_CALL) || 16487105e828SDaniel Borkmann insns[i].code == (BPF_JMP | BPF_CALL_ARGS)) { 16497105e828SDaniel Borkmann if (insns[i].code == (BPF_JMP | BPF_CALL_ARGS)) 16507105e828SDaniel Borkmann insns[i].code = BPF_JMP | BPF_CALL; 16517105e828SDaniel Borkmann if (!bpf_dump_raw_ok()) 16527105e828SDaniel Borkmann insns[i].imm = 0; 16537105e828SDaniel Borkmann continue; 16547105e828SDaniel Borkmann } 16557105e828SDaniel Borkmann 16567105e828SDaniel Borkmann if (insns[i].code != (BPF_LD | BPF_IMM | BPF_DW)) 16577105e828SDaniel Borkmann continue; 16587105e828SDaniel Borkmann 16597105e828SDaniel Borkmann imm = ((u64)insns[i + 1].imm << 32) | (u32)insns[i].imm; 16607105e828SDaniel Borkmann map = bpf_map_from_imm(prog, imm); 16617105e828SDaniel Borkmann if (map) { 16627105e828SDaniel Borkmann insns[i].src_reg = BPF_PSEUDO_MAP_FD; 16637105e828SDaniel Borkmann insns[i].imm = map->id; 16647105e828SDaniel Borkmann insns[i + 1].imm = 0; 16657105e828SDaniel Borkmann continue; 16667105e828SDaniel Borkmann } 16677105e828SDaniel Borkmann 16687105e828SDaniel Borkmann if (!bpf_dump_raw_ok() && 16697105e828SDaniel Borkmann imm == (unsigned long)prog->aux) { 16707105e828SDaniel Borkmann insns[i].imm = 0; 16717105e828SDaniel Borkmann insns[i + 1].imm = 0; 16727105e828SDaniel Borkmann continue; 16737105e828SDaniel Borkmann } 16747105e828SDaniel Borkmann } 16757105e828SDaniel Borkmann 16767105e828SDaniel Borkmann return insns; 16777105e828SDaniel Borkmann } 16787105e828SDaniel Borkmann 16791e270976SMartin KaFai Lau static int bpf_prog_get_info_by_fd(struct bpf_prog *prog, 16801e270976SMartin KaFai Lau const union bpf_attr *attr, 16811e270976SMartin KaFai Lau union bpf_attr __user *uattr) 16821e270976SMartin KaFai Lau { 16831e270976SMartin KaFai Lau struct bpf_prog_info __user *uinfo = u64_to_user_ptr(attr->info.info); 16841e270976SMartin KaFai Lau struct bpf_prog_info info = {}; 16851e270976SMartin KaFai Lau u32 info_len = attr->info.info_len; 16861e270976SMartin KaFai Lau char __user *uinsns; 16871e270976SMartin KaFai Lau u32 ulen; 16881e270976SMartin KaFai Lau int err; 16891e270976SMartin KaFai Lau 16901e270976SMartin KaFai Lau err = check_uarg_tail_zero(uinfo, sizeof(info), info_len); 16911e270976SMartin KaFai Lau if (err) 16921e270976SMartin KaFai Lau return err; 16931e270976SMartin KaFai Lau info_len = min_t(u32, sizeof(info), info_len); 16941e270976SMartin KaFai Lau 16951e270976SMartin KaFai Lau if (copy_from_user(&info, uinfo, info_len)) 169689b09689SDaniel Borkmann return -EFAULT; 16971e270976SMartin KaFai Lau 16981e270976SMartin KaFai Lau info.type = prog->type; 16991e270976SMartin KaFai Lau info.id = prog->aux->id; 1700cb4d2b3fSMartin KaFai Lau info.load_time = prog->aux->load_time; 1701cb4d2b3fSMartin KaFai Lau info.created_by_uid = from_kuid_munged(current_user_ns(), 1702cb4d2b3fSMartin KaFai Lau prog->aux->user->uid); 17031e270976SMartin KaFai Lau 17041e270976SMartin KaFai Lau memcpy(info.tag, prog->tag, sizeof(prog->tag)); 1705cb4d2b3fSMartin KaFai Lau memcpy(info.name, prog->aux->name, sizeof(prog->aux->name)); 1706cb4d2b3fSMartin KaFai Lau 1707cb4d2b3fSMartin KaFai Lau ulen = info.nr_map_ids; 1708cb4d2b3fSMartin KaFai Lau info.nr_map_ids = prog->aux->used_map_cnt; 1709cb4d2b3fSMartin KaFai Lau ulen = min_t(u32, info.nr_map_ids, ulen); 1710cb4d2b3fSMartin KaFai Lau if (ulen) { 1711721e08daSMartin KaFai Lau u32 __user *user_map_ids = u64_to_user_ptr(info.map_ids); 1712cb4d2b3fSMartin KaFai Lau u32 i; 1713cb4d2b3fSMartin KaFai Lau 1714cb4d2b3fSMartin KaFai Lau for (i = 0; i < ulen; i++) 1715cb4d2b3fSMartin KaFai Lau if (put_user(prog->aux->used_maps[i]->id, 1716cb4d2b3fSMartin KaFai Lau &user_map_ids[i])) 1717cb4d2b3fSMartin KaFai Lau return -EFAULT; 1718cb4d2b3fSMartin KaFai Lau } 17191e270976SMartin KaFai Lau 17201e270976SMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) { 17211e270976SMartin KaFai Lau info.jited_prog_len = 0; 17221e270976SMartin KaFai Lau info.xlated_prog_len = 0; 17231e270976SMartin KaFai Lau goto done; 17241e270976SMartin KaFai Lau } 17251e270976SMartin KaFai Lau 17261e270976SMartin KaFai Lau ulen = info.xlated_prog_len; 17279975a54bSDaniel Borkmann info.xlated_prog_len = bpf_prog_insn_size(prog); 17281e270976SMartin KaFai Lau if (info.xlated_prog_len && ulen) { 17297105e828SDaniel Borkmann struct bpf_insn *insns_sanitized; 17307105e828SDaniel Borkmann bool fault; 17317105e828SDaniel Borkmann 17327105e828SDaniel Borkmann if (prog->blinded && !bpf_dump_raw_ok()) { 17337105e828SDaniel Borkmann info.xlated_prog_insns = 0; 17347105e828SDaniel Borkmann goto done; 17357105e828SDaniel Borkmann } 17367105e828SDaniel Borkmann insns_sanitized = bpf_insn_prepare_dump(prog); 17377105e828SDaniel Borkmann if (!insns_sanitized) 17387105e828SDaniel Borkmann return -ENOMEM; 17391e270976SMartin KaFai Lau uinsns = u64_to_user_ptr(info.xlated_prog_insns); 17401e270976SMartin KaFai Lau ulen = min_t(u32, info.xlated_prog_len, ulen); 17417105e828SDaniel Borkmann fault = copy_to_user(uinsns, insns_sanitized, ulen); 17427105e828SDaniel Borkmann kfree(insns_sanitized); 17437105e828SDaniel Borkmann if (fault) 17441e270976SMartin KaFai Lau return -EFAULT; 17451e270976SMartin KaFai Lau } 17461e270976SMartin KaFai Lau 1747675fc275SJakub Kicinski if (bpf_prog_is_dev_bound(prog->aux)) { 1748675fc275SJakub Kicinski err = bpf_prog_offload_info_fill(&info, prog); 1749675fc275SJakub Kicinski if (err) 1750675fc275SJakub Kicinski return err; 1751fcfb126dSJiong Wang goto done; 1752fcfb126dSJiong Wang } 1753fcfb126dSJiong Wang 1754fcfb126dSJiong Wang /* NOTE: the following code is supposed to be skipped for offload. 1755fcfb126dSJiong Wang * bpf_prog_offload_info_fill() is the place to fill similar fields 1756fcfb126dSJiong Wang * for offload. 1757fcfb126dSJiong Wang */ 1758fcfb126dSJiong Wang ulen = info.jited_prog_len; 1759fcfb126dSJiong Wang info.jited_prog_len = prog->jited_len; 1760fcfb126dSJiong Wang if (info.jited_prog_len && ulen) { 1761fcfb126dSJiong Wang if (bpf_dump_raw_ok()) { 1762fcfb126dSJiong Wang uinsns = u64_to_user_ptr(info.jited_prog_insns); 1763fcfb126dSJiong Wang ulen = min_t(u32, info.jited_prog_len, ulen); 1764fcfb126dSJiong Wang if (copy_to_user(uinsns, prog->bpf_func, ulen)) 1765fcfb126dSJiong Wang return -EFAULT; 1766fcfb126dSJiong Wang } else { 1767fcfb126dSJiong Wang info.jited_prog_insns = 0; 1768fcfb126dSJiong Wang } 1769675fc275SJakub Kicinski } 1770675fc275SJakub Kicinski 17711e270976SMartin KaFai Lau done: 17721e270976SMartin KaFai Lau if (copy_to_user(uinfo, &info, info_len) || 17731e270976SMartin KaFai Lau put_user(info_len, &uattr->info.info_len)) 17741e270976SMartin KaFai Lau return -EFAULT; 17751e270976SMartin KaFai Lau 17761e270976SMartin KaFai Lau return 0; 17771e270976SMartin KaFai Lau } 17781e270976SMartin KaFai Lau 17791e270976SMartin KaFai Lau static int bpf_map_get_info_by_fd(struct bpf_map *map, 17801e270976SMartin KaFai Lau const union bpf_attr *attr, 17811e270976SMartin KaFai Lau union bpf_attr __user *uattr) 17821e270976SMartin KaFai Lau { 17831e270976SMartin KaFai Lau struct bpf_map_info __user *uinfo = u64_to_user_ptr(attr->info.info); 17841e270976SMartin KaFai Lau struct bpf_map_info info = {}; 17851e270976SMartin KaFai Lau u32 info_len = attr->info.info_len; 17861e270976SMartin KaFai Lau int err; 17871e270976SMartin KaFai Lau 17881e270976SMartin KaFai Lau err = check_uarg_tail_zero(uinfo, sizeof(info), info_len); 17891e270976SMartin KaFai Lau if (err) 17901e270976SMartin KaFai Lau return err; 17911e270976SMartin KaFai Lau info_len = min_t(u32, sizeof(info), info_len); 17921e270976SMartin KaFai Lau 17931e270976SMartin KaFai Lau info.type = map->map_type; 17941e270976SMartin KaFai Lau info.id = map->id; 17951e270976SMartin KaFai Lau info.key_size = map->key_size; 17961e270976SMartin KaFai Lau info.value_size = map->value_size; 17971e270976SMartin KaFai Lau info.max_entries = map->max_entries; 17981e270976SMartin KaFai Lau info.map_flags = map->map_flags; 1799ad5b177bSMartin KaFai Lau memcpy(info.name, map->name, sizeof(map->name)); 18001e270976SMartin KaFai Lau 180152775b33SJakub Kicinski if (bpf_map_is_dev_bound(map)) { 180252775b33SJakub Kicinski err = bpf_map_offload_info_fill(&info, map); 180352775b33SJakub Kicinski if (err) 180452775b33SJakub Kicinski return err; 180552775b33SJakub Kicinski } 180652775b33SJakub Kicinski 18071e270976SMartin KaFai Lau if (copy_to_user(uinfo, &info, info_len) || 18081e270976SMartin KaFai Lau put_user(info_len, &uattr->info.info_len)) 18091e270976SMartin KaFai Lau return -EFAULT; 18101e270976SMartin KaFai Lau 18111e270976SMartin KaFai Lau return 0; 18121e270976SMartin KaFai Lau } 18131e270976SMartin KaFai Lau 18141e270976SMartin KaFai Lau #define BPF_OBJ_GET_INFO_BY_FD_LAST_FIELD info.info 18151e270976SMartin KaFai Lau 18161e270976SMartin KaFai Lau static int bpf_obj_get_info_by_fd(const union bpf_attr *attr, 18171e270976SMartin KaFai Lau union bpf_attr __user *uattr) 18181e270976SMartin KaFai Lau { 18191e270976SMartin KaFai Lau int ufd = attr->info.bpf_fd; 18201e270976SMartin KaFai Lau struct fd f; 18211e270976SMartin KaFai Lau int err; 18221e270976SMartin KaFai Lau 18231e270976SMartin KaFai Lau if (CHECK_ATTR(BPF_OBJ_GET_INFO_BY_FD)) 18241e270976SMartin KaFai Lau return -EINVAL; 18251e270976SMartin KaFai Lau 18261e270976SMartin KaFai Lau f = fdget(ufd); 18271e270976SMartin KaFai Lau if (!f.file) 18281e270976SMartin KaFai Lau return -EBADFD; 18291e270976SMartin KaFai Lau 18301e270976SMartin KaFai Lau if (f.file->f_op == &bpf_prog_fops) 18311e270976SMartin KaFai Lau err = bpf_prog_get_info_by_fd(f.file->private_data, attr, 18321e270976SMartin KaFai Lau uattr); 18331e270976SMartin KaFai Lau else if (f.file->f_op == &bpf_map_fops) 18341e270976SMartin KaFai Lau err = bpf_map_get_info_by_fd(f.file->private_data, attr, 18351e270976SMartin KaFai Lau uattr); 18361e270976SMartin KaFai Lau else 18371e270976SMartin KaFai Lau err = -EINVAL; 18381e270976SMartin KaFai Lau 18391e270976SMartin KaFai Lau fdput(f); 18401e270976SMartin KaFai Lau return err; 18411e270976SMartin KaFai Lau } 18421e270976SMartin KaFai Lau 184399c55f7dSAlexei Starovoitov SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size) 184499c55f7dSAlexei Starovoitov { 184599c55f7dSAlexei Starovoitov union bpf_attr attr = {}; 184699c55f7dSAlexei Starovoitov int err; 184799c55f7dSAlexei Starovoitov 1848*0fa4fe85SChenbo Feng if (sysctl_unprivileged_bpf_disabled && !capable(CAP_SYS_ADMIN)) 184999c55f7dSAlexei Starovoitov return -EPERM; 185099c55f7dSAlexei Starovoitov 18511e270976SMartin KaFai Lau err = check_uarg_tail_zero(uattr, sizeof(attr), size); 185299c55f7dSAlexei Starovoitov if (err) 185399c55f7dSAlexei Starovoitov return err; 18541e270976SMartin KaFai Lau size = min_t(u32, size, sizeof(attr)); 185599c55f7dSAlexei Starovoitov 185699c55f7dSAlexei Starovoitov /* copy attributes from user space, may be less than sizeof(bpf_attr) */ 185799c55f7dSAlexei Starovoitov if (copy_from_user(&attr, uattr, size) != 0) 185899c55f7dSAlexei Starovoitov return -EFAULT; 185999c55f7dSAlexei Starovoitov 1860afdb09c7SChenbo Feng err = security_bpf(cmd, &attr, size); 1861afdb09c7SChenbo Feng if (err < 0) 1862afdb09c7SChenbo Feng return err; 1863afdb09c7SChenbo Feng 186499c55f7dSAlexei Starovoitov switch (cmd) { 186599c55f7dSAlexei Starovoitov case BPF_MAP_CREATE: 186699c55f7dSAlexei Starovoitov err = map_create(&attr); 186799c55f7dSAlexei Starovoitov break; 1868db20fd2bSAlexei Starovoitov case BPF_MAP_LOOKUP_ELEM: 1869db20fd2bSAlexei Starovoitov err = map_lookup_elem(&attr); 1870db20fd2bSAlexei Starovoitov break; 1871db20fd2bSAlexei Starovoitov case BPF_MAP_UPDATE_ELEM: 1872db20fd2bSAlexei Starovoitov err = map_update_elem(&attr); 1873db20fd2bSAlexei Starovoitov break; 1874db20fd2bSAlexei Starovoitov case BPF_MAP_DELETE_ELEM: 1875db20fd2bSAlexei Starovoitov err = map_delete_elem(&attr); 1876db20fd2bSAlexei Starovoitov break; 1877db20fd2bSAlexei Starovoitov case BPF_MAP_GET_NEXT_KEY: 1878db20fd2bSAlexei Starovoitov err = map_get_next_key(&attr); 1879db20fd2bSAlexei Starovoitov break; 188009756af4SAlexei Starovoitov case BPF_PROG_LOAD: 188109756af4SAlexei Starovoitov err = bpf_prog_load(&attr); 188209756af4SAlexei Starovoitov break; 1883b2197755SDaniel Borkmann case BPF_OBJ_PIN: 1884b2197755SDaniel Borkmann err = bpf_obj_pin(&attr); 1885b2197755SDaniel Borkmann break; 1886b2197755SDaniel Borkmann case BPF_OBJ_GET: 1887b2197755SDaniel Borkmann err = bpf_obj_get(&attr); 1888b2197755SDaniel Borkmann break; 1889f4324551SDaniel Mack #ifdef CONFIG_CGROUP_BPF 1890f4324551SDaniel Mack case BPF_PROG_ATTACH: 1891f4324551SDaniel Mack err = bpf_prog_attach(&attr); 1892f4324551SDaniel Mack break; 1893f4324551SDaniel Mack case BPF_PROG_DETACH: 1894f4324551SDaniel Mack err = bpf_prog_detach(&attr); 1895f4324551SDaniel Mack break; 1896468e2f64SAlexei Starovoitov case BPF_PROG_QUERY: 1897468e2f64SAlexei Starovoitov err = bpf_prog_query(&attr, uattr); 1898468e2f64SAlexei Starovoitov break; 1899f4324551SDaniel Mack #endif 19001cf1cae9SAlexei Starovoitov case BPF_PROG_TEST_RUN: 19011cf1cae9SAlexei Starovoitov err = bpf_prog_test_run(&attr, uattr); 19021cf1cae9SAlexei Starovoitov break; 190334ad5580SMartin KaFai Lau case BPF_PROG_GET_NEXT_ID: 190434ad5580SMartin KaFai Lau err = bpf_obj_get_next_id(&attr, uattr, 190534ad5580SMartin KaFai Lau &prog_idr, &prog_idr_lock); 190634ad5580SMartin KaFai Lau break; 190734ad5580SMartin KaFai Lau case BPF_MAP_GET_NEXT_ID: 190834ad5580SMartin KaFai Lau err = bpf_obj_get_next_id(&attr, uattr, 190934ad5580SMartin KaFai Lau &map_idr, &map_idr_lock); 191034ad5580SMartin KaFai Lau break; 1911b16d9aa4SMartin KaFai Lau case BPF_PROG_GET_FD_BY_ID: 1912b16d9aa4SMartin KaFai Lau err = bpf_prog_get_fd_by_id(&attr); 1913b16d9aa4SMartin KaFai Lau break; 1914bd5f5f4eSMartin KaFai Lau case BPF_MAP_GET_FD_BY_ID: 1915bd5f5f4eSMartin KaFai Lau err = bpf_map_get_fd_by_id(&attr); 1916bd5f5f4eSMartin KaFai Lau break; 19171e270976SMartin KaFai Lau case BPF_OBJ_GET_INFO_BY_FD: 19181e270976SMartin KaFai Lau err = bpf_obj_get_info_by_fd(&attr, uattr); 19191e270976SMartin KaFai Lau break; 192099c55f7dSAlexei Starovoitov default: 192199c55f7dSAlexei Starovoitov err = -EINVAL; 192299c55f7dSAlexei Starovoitov break; 192399c55f7dSAlexei Starovoitov } 192499c55f7dSAlexei Starovoitov 192599c55f7dSAlexei Starovoitov return err; 192699c55f7dSAlexei Starovoitov } 1927