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> 2699c55f7dSAlexei Starovoitov 2714dc6f04SMartin KaFai Lau #define IS_FD_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PROG_ARRAY || \ 2814dc6f04SMartin KaFai Lau (map)->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || \ 2914dc6f04SMartin KaFai Lau (map)->map_type == BPF_MAP_TYPE_CGROUP_ARRAY || \ 3014dc6f04SMartin KaFai Lau (map)->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS) 3114dc6f04SMartin KaFai Lau #define IS_FD_HASH(map) ((map)->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) 3214dc6f04SMartin KaFai Lau #define IS_FD_MAP(map) (IS_FD_ARRAY(map) || IS_FD_HASH(map)) 3314dc6f04SMartin KaFai Lau 34b121d1e7SAlexei Starovoitov DEFINE_PER_CPU(int, bpf_prog_active); 35dc4bb0e2SMartin KaFai Lau static DEFINE_IDR(prog_idr); 36dc4bb0e2SMartin KaFai Lau static DEFINE_SPINLOCK(prog_idr_lock); 37f3f1c054SMartin KaFai Lau static DEFINE_IDR(map_idr); 38f3f1c054SMartin KaFai Lau static DEFINE_SPINLOCK(map_idr_lock); 39b121d1e7SAlexei Starovoitov 401be7f75dSAlexei Starovoitov int sysctl_unprivileged_bpf_disabled __read_mostly; 411be7f75dSAlexei Starovoitov 4240077e0cSJohannes Berg static const struct bpf_map_ops * const bpf_map_types[] = { 4340077e0cSJohannes Berg #define BPF_PROG_TYPE(_id, _ops) 4440077e0cSJohannes Berg #define BPF_MAP_TYPE(_id, _ops) \ 4540077e0cSJohannes Berg [_id] = &_ops, 4640077e0cSJohannes Berg #include <linux/bpf_types.h> 4740077e0cSJohannes Berg #undef BPF_PROG_TYPE 4840077e0cSJohannes Berg #undef BPF_MAP_TYPE 4940077e0cSJohannes Berg }; 5099c55f7dSAlexei Starovoitov 51752ba56fSMickaël Salaün /* 52752ba56fSMickaël Salaün * If we're handed a bigger struct than we know of, ensure all the unknown bits 53752ba56fSMickaël Salaün * are 0 - i.e. new user-space does not rely on any kernel feature extensions 54752ba56fSMickaël Salaün * we don't know about yet. 55752ba56fSMickaël Salaün * 56752ba56fSMickaël Salaün * There is a ToCToU between this function call and the following 57752ba56fSMickaël Salaün * copy_from_user() call. However, this is not a concern since this function is 58752ba56fSMickaël Salaün * meant to be a future-proofing of bits. 59752ba56fSMickaël Salaün */ 6058291a74SMickaël Salaün static int check_uarg_tail_zero(void __user *uaddr, 6158291a74SMickaël Salaün size_t expected_size, 6258291a74SMickaël Salaün size_t actual_size) 6358291a74SMickaël Salaün { 6458291a74SMickaël Salaün unsigned char __user *addr; 6558291a74SMickaël Salaün unsigned char __user *end; 6658291a74SMickaël Salaün unsigned char val; 6758291a74SMickaël Salaün int err; 6858291a74SMickaël Salaün 69752ba56fSMickaël Salaün if (unlikely(actual_size > PAGE_SIZE)) /* silly large */ 70752ba56fSMickaël Salaün return -E2BIG; 71752ba56fSMickaël Salaün 72752ba56fSMickaël Salaün if (unlikely(!access_ok(VERIFY_READ, uaddr, actual_size))) 73752ba56fSMickaël Salaün return -EFAULT; 74752ba56fSMickaël Salaün 7558291a74SMickaël Salaün if (actual_size <= expected_size) 7658291a74SMickaël Salaün return 0; 7758291a74SMickaël Salaün 7858291a74SMickaël Salaün addr = uaddr + expected_size; 7958291a74SMickaël Salaün end = uaddr + actual_size; 8058291a74SMickaël Salaün 8158291a74SMickaël Salaün for (; addr < end; addr++) { 8258291a74SMickaël Salaün err = get_user(val, addr); 8358291a74SMickaël Salaün if (err) 8458291a74SMickaël Salaün return err; 8558291a74SMickaël Salaün if (val) 8658291a74SMickaël Salaün return -E2BIG; 8758291a74SMickaël Salaün } 8858291a74SMickaël Salaün 8958291a74SMickaël Salaün return 0; 9058291a74SMickaël Salaün } 9158291a74SMickaël Salaün 9299c55f7dSAlexei Starovoitov static struct bpf_map *find_and_alloc_map(union bpf_attr *attr) 9399c55f7dSAlexei Starovoitov { 9499c55f7dSAlexei Starovoitov struct bpf_map *map; 9599c55f7dSAlexei Starovoitov 9640077e0cSJohannes Berg if (attr->map_type >= ARRAY_SIZE(bpf_map_types) || 9740077e0cSJohannes Berg !bpf_map_types[attr->map_type]) 9840077e0cSJohannes Berg return ERR_PTR(-EINVAL); 9940077e0cSJohannes Berg 10040077e0cSJohannes Berg map = bpf_map_types[attr->map_type]->map_alloc(attr); 10199c55f7dSAlexei Starovoitov if (IS_ERR(map)) 10299c55f7dSAlexei Starovoitov return map; 10340077e0cSJohannes Berg map->ops = bpf_map_types[attr->map_type]; 10499c55f7dSAlexei Starovoitov map->map_type = attr->map_type; 10599c55f7dSAlexei Starovoitov return map; 10699c55f7dSAlexei Starovoitov } 10799c55f7dSAlexei Starovoitov 10896eabe7aSMartin KaFai Lau void *bpf_map_area_alloc(size_t size, int numa_node) 109d407bd25SDaniel Borkmann { 110d407bd25SDaniel Borkmann /* We definitely need __GFP_NORETRY, so OOM killer doesn't 111d407bd25SDaniel Borkmann * trigger under memory pressure as we really just want to 112d407bd25SDaniel Borkmann * fail instead. 113d407bd25SDaniel Borkmann */ 114d407bd25SDaniel Borkmann const gfp_t flags = __GFP_NOWARN | __GFP_NORETRY | __GFP_ZERO; 115d407bd25SDaniel Borkmann void *area; 116d407bd25SDaniel Borkmann 117d407bd25SDaniel Borkmann if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) { 11896eabe7aSMartin KaFai Lau area = kmalloc_node(size, GFP_USER | flags, numa_node); 119d407bd25SDaniel Borkmann if (area != NULL) 120d407bd25SDaniel Borkmann return area; 121d407bd25SDaniel Borkmann } 122d407bd25SDaniel Borkmann 12396eabe7aSMartin KaFai Lau return __vmalloc_node_flags_caller(size, numa_node, GFP_KERNEL | flags, 12496eabe7aSMartin KaFai Lau __builtin_return_address(0)); 125d407bd25SDaniel Borkmann } 126d407bd25SDaniel Borkmann 127d407bd25SDaniel Borkmann void bpf_map_area_free(void *area) 128d407bd25SDaniel Borkmann { 129d407bd25SDaniel Borkmann kvfree(area); 130d407bd25SDaniel Borkmann } 131d407bd25SDaniel Borkmann 1326c905981SAlexei Starovoitov int bpf_map_precharge_memlock(u32 pages) 1336c905981SAlexei Starovoitov { 1346c905981SAlexei Starovoitov struct user_struct *user = get_current_user(); 1356c905981SAlexei Starovoitov unsigned long memlock_limit, cur; 1366c905981SAlexei Starovoitov 1376c905981SAlexei Starovoitov memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; 1386c905981SAlexei Starovoitov cur = atomic_long_read(&user->locked_vm); 1396c905981SAlexei Starovoitov free_uid(user); 1406c905981SAlexei Starovoitov if (cur + pages > memlock_limit) 1416c905981SAlexei Starovoitov return -EPERM; 1426c905981SAlexei Starovoitov return 0; 1436c905981SAlexei Starovoitov } 1446c905981SAlexei Starovoitov 145aaac3ba9SAlexei Starovoitov static int bpf_map_charge_memlock(struct bpf_map *map) 146aaac3ba9SAlexei Starovoitov { 147aaac3ba9SAlexei Starovoitov struct user_struct *user = get_current_user(); 148aaac3ba9SAlexei Starovoitov unsigned long memlock_limit; 149aaac3ba9SAlexei Starovoitov 150aaac3ba9SAlexei Starovoitov memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; 151aaac3ba9SAlexei Starovoitov 152aaac3ba9SAlexei Starovoitov atomic_long_add(map->pages, &user->locked_vm); 153aaac3ba9SAlexei Starovoitov 154aaac3ba9SAlexei Starovoitov if (atomic_long_read(&user->locked_vm) > memlock_limit) { 155aaac3ba9SAlexei Starovoitov atomic_long_sub(map->pages, &user->locked_vm); 156aaac3ba9SAlexei Starovoitov free_uid(user); 157aaac3ba9SAlexei Starovoitov return -EPERM; 158aaac3ba9SAlexei Starovoitov } 159aaac3ba9SAlexei Starovoitov map->user = user; 160aaac3ba9SAlexei Starovoitov return 0; 161aaac3ba9SAlexei Starovoitov } 162aaac3ba9SAlexei Starovoitov 163aaac3ba9SAlexei Starovoitov static void bpf_map_uncharge_memlock(struct bpf_map *map) 164aaac3ba9SAlexei Starovoitov { 165aaac3ba9SAlexei Starovoitov struct user_struct *user = map->user; 166aaac3ba9SAlexei Starovoitov 167aaac3ba9SAlexei Starovoitov atomic_long_sub(map->pages, &user->locked_vm); 168aaac3ba9SAlexei Starovoitov free_uid(user); 169aaac3ba9SAlexei Starovoitov } 170aaac3ba9SAlexei Starovoitov 171f3f1c054SMartin KaFai Lau static int bpf_map_alloc_id(struct bpf_map *map) 172f3f1c054SMartin KaFai Lau { 173f3f1c054SMartin KaFai Lau int id; 174f3f1c054SMartin KaFai Lau 175f3f1c054SMartin KaFai Lau spin_lock_bh(&map_idr_lock); 176f3f1c054SMartin KaFai Lau id = idr_alloc_cyclic(&map_idr, map, 1, INT_MAX, GFP_ATOMIC); 177f3f1c054SMartin KaFai Lau if (id > 0) 178f3f1c054SMartin KaFai Lau map->id = id; 179f3f1c054SMartin KaFai Lau spin_unlock_bh(&map_idr_lock); 180f3f1c054SMartin KaFai Lau 181f3f1c054SMartin KaFai Lau if (WARN_ON_ONCE(!id)) 182f3f1c054SMartin KaFai Lau return -ENOSPC; 183f3f1c054SMartin KaFai Lau 184f3f1c054SMartin KaFai Lau return id > 0 ? 0 : id; 185f3f1c054SMartin KaFai Lau } 186f3f1c054SMartin KaFai Lau 187bd5f5f4eSMartin KaFai Lau static void bpf_map_free_id(struct bpf_map *map, bool do_idr_lock) 188f3f1c054SMartin KaFai Lau { 189bd5f5f4eSMartin KaFai Lau if (do_idr_lock) 190f3f1c054SMartin KaFai Lau spin_lock_bh(&map_idr_lock); 191bd5f5f4eSMartin KaFai Lau else 192bd5f5f4eSMartin KaFai Lau __acquire(&map_idr_lock); 193bd5f5f4eSMartin KaFai Lau 194f3f1c054SMartin KaFai Lau idr_remove(&map_idr, map->id); 195bd5f5f4eSMartin KaFai Lau 196bd5f5f4eSMartin KaFai Lau if (do_idr_lock) 197f3f1c054SMartin KaFai Lau spin_unlock_bh(&map_idr_lock); 198bd5f5f4eSMartin KaFai Lau else 199bd5f5f4eSMartin KaFai Lau __release(&map_idr_lock); 200f3f1c054SMartin KaFai Lau } 201f3f1c054SMartin KaFai Lau 20299c55f7dSAlexei Starovoitov /* called from workqueue */ 20399c55f7dSAlexei Starovoitov static void bpf_map_free_deferred(struct work_struct *work) 20499c55f7dSAlexei Starovoitov { 20599c55f7dSAlexei Starovoitov struct bpf_map *map = container_of(work, struct bpf_map, work); 20699c55f7dSAlexei Starovoitov 207aaac3ba9SAlexei Starovoitov bpf_map_uncharge_memlock(map); 20899c55f7dSAlexei Starovoitov /* implementation dependent freeing */ 20999c55f7dSAlexei Starovoitov map->ops->map_free(map); 21099c55f7dSAlexei Starovoitov } 21199c55f7dSAlexei Starovoitov 212c9da161cSDaniel Borkmann static void bpf_map_put_uref(struct bpf_map *map) 213c9da161cSDaniel Borkmann { 214c9da161cSDaniel Borkmann if (atomic_dec_and_test(&map->usercnt)) { 215c9da161cSDaniel Borkmann if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY) 216c9da161cSDaniel Borkmann bpf_fd_array_map_clear(map); 217c9da161cSDaniel Borkmann } 218c9da161cSDaniel Borkmann } 219c9da161cSDaniel Borkmann 22099c55f7dSAlexei Starovoitov /* decrement map refcnt and schedule it for freeing via workqueue 22199c55f7dSAlexei Starovoitov * (unrelying map implementation ops->map_free() might sleep) 22299c55f7dSAlexei Starovoitov */ 223bd5f5f4eSMartin KaFai Lau static void __bpf_map_put(struct bpf_map *map, bool do_idr_lock) 22499c55f7dSAlexei Starovoitov { 22599c55f7dSAlexei Starovoitov if (atomic_dec_and_test(&map->refcnt)) { 22634ad5580SMartin KaFai Lau /* bpf_map_free_id() must be called first */ 227bd5f5f4eSMartin KaFai Lau bpf_map_free_id(map, do_idr_lock); 22899c55f7dSAlexei Starovoitov INIT_WORK(&map->work, bpf_map_free_deferred); 22999c55f7dSAlexei Starovoitov schedule_work(&map->work); 23099c55f7dSAlexei Starovoitov } 23199c55f7dSAlexei Starovoitov } 23299c55f7dSAlexei Starovoitov 233bd5f5f4eSMartin KaFai Lau void bpf_map_put(struct bpf_map *map) 234bd5f5f4eSMartin KaFai Lau { 235bd5f5f4eSMartin KaFai Lau __bpf_map_put(map, true); 236bd5f5f4eSMartin KaFai Lau } 237bd5f5f4eSMartin KaFai Lau 238c9da161cSDaniel Borkmann void bpf_map_put_with_uref(struct bpf_map *map) 239c9da161cSDaniel Borkmann { 240c9da161cSDaniel Borkmann bpf_map_put_uref(map); 241c9da161cSDaniel Borkmann bpf_map_put(map); 242c9da161cSDaniel Borkmann } 243c9da161cSDaniel Borkmann 24499c55f7dSAlexei Starovoitov static int bpf_map_release(struct inode *inode, struct file *filp) 24599c55f7dSAlexei Starovoitov { 24661d1b6a4SDaniel Borkmann struct bpf_map *map = filp->private_data; 24761d1b6a4SDaniel Borkmann 24861d1b6a4SDaniel Borkmann if (map->ops->map_release) 24961d1b6a4SDaniel Borkmann map->ops->map_release(map, filp); 25061d1b6a4SDaniel Borkmann 25161d1b6a4SDaniel Borkmann bpf_map_put_with_uref(map); 25299c55f7dSAlexei Starovoitov return 0; 25399c55f7dSAlexei Starovoitov } 25499c55f7dSAlexei Starovoitov 255f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS 256f99bf205SDaniel Borkmann static void bpf_map_show_fdinfo(struct seq_file *m, struct file *filp) 257f99bf205SDaniel Borkmann { 258f99bf205SDaniel Borkmann const struct bpf_map *map = filp->private_data; 25921116b70SDaniel Borkmann const struct bpf_array *array; 26021116b70SDaniel Borkmann u32 owner_prog_type = 0; 2619780c0abSDaniel Borkmann u32 owner_jited = 0; 26221116b70SDaniel Borkmann 26321116b70SDaniel Borkmann if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY) { 26421116b70SDaniel Borkmann array = container_of(map, struct bpf_array, map); 26521116b70SDaniel Borkmann owner_prog_type = array->owner_prog_type; 2669780c0abSDaniel Borkmann owner_jited = array->owner_jited; 26721116b70SDaniel Borkmann } 268f99bf205SDaniel Borkmann 269f99bf205SDaniel Borkmann seq_printf(m, 270f99bf205SDaniel Borkmann "map_type:\t%u\n" 271f99bf205SDaniel Borkmann "key_size:\t%u\n" 272f99bf205SDaniel Borkmann "value_size:\t%u\n" 273322cea2fSDaniel Borkmann "max_entries:\t%u\n" 27421116b70SDaniel Borkmann "map_flags:\t%#x\n" 27521116b70SDaniel Borkmann "memlock:\t%llu\n", 276f99bf205SDaniel Borkmann map->map_type, 277f99bf205SDaniel Borkmann map->key_size, 278f99bf205SDaniel Borkmann map->value_size, 279322cea2fSDaniel Borkmann map->max_entries, 28021116b70SDaniel Borkmann map->map_flags, 28121116b70SDaniel Borkmann map->pages * 1ULL << PAGE_SHIFT); 28221116b70SDaniel Borkmann 2839780c0abSDaniel Borkmann if (owner_prog_type) { 28421116b70SDaniel Borkmann seq_printf(m, "owner_prog_type:\t%u\n", 28521116b70SDaniel Borkmann owner_prog_type); 2869780c0abSDaniel Borkmann seq_printf(m, "owner_jited:\t%u\n", 2879780c0abSDaniel Borkmann owner_jited); 2889780c0abSDaniel Borkmann } 289f99bf205SDaniel Borkmann } 290f99bf205SDaniel Borkmann #endif 291f99bf205SDaniel Borkmann 29299c55f7dSAlexei Starovoitov static const struct file_operations bpf_map_fops = { 293f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS 294f99bf205SDaniel Borkmann .show_fdinfo = bpf_map_show_fdinfo, 295f99bf205SDaniel Borkmann #endif 29699c55f7dSAlexei Starovoitov .release = bpf_map_release, 29799c55f7dSAlexei Starovoitov }; 29899c55f7dSAlexei Starovoitov 299b2197755SDaniel Borkmann int bpf_map_new_fd(struct bpf_map *map) 300aa79781bSDaniel Borkmann { 301aa79781bSDaniel Borkmann return anon_inode_getfd("bpf-map", &bpf_map_fops, map, 302aa79781bSDaniel Borkmann O_RDWR | O_CLOEXEC); 303aa79781bSDaniel Borkmann } 304aa79781bSDaniel Borkmann 30599c55f7dSAlexei Starovoitov /* helper macro to check that unused fields 'union bpf_attr' are zero */ 30699c55f7dSAlexei Starovoitov #define CHECK_ATTR(CMD) \ 30799c55f7dSAlexei Starovoitov memchr_inv((void *) &attr->CMD##_LAST_FIELD + \ 30899c55f7dSAlexei Starovoitov sizeof(attr->CMD##_LAST_FIELD), 0, \ 30999c55f7dSAlexei Starovoitov sizeof(*attr) - \ 31099c55f7dSAlexei Starovoitov offsetof(union bpf_attr, CMD##_LAST_FIELD) - \ 31199c55f7dSAlexei Starovoitov sizeof(attr->CMD##_LAST_FIELD)) != NULL 31299c55f7dSAlexei Starovoitov 31396eabe7aSMartin KaFai Lau #define BPF_MAP_CREATE_LAST_FIELD numa_node 31499c55f7dSAlexei Starovoitov /* called via syscall */ 31599c55f7dSAlexei Starovoitov static int map_create(union bpf_attr *attr) 31699c55f7dSAlexei Starovoitov { 31796eabe7aSMartin KaFai Lau int numa_node = bpf_map_attr_numa_node(attr); 31899c55f7dSAlexei Starovoitov struct bpf_map *map; 31999c55f7dSAlexei Starovoitov int err; 32099c55f7dSAlexei Starovoitov 32199c55f7dSAlexei Starovoitov err = CHECK_ATTR(BPF_MAP_CREATE); 32299c55f7dSAlexei Starovoitov if (err) 32399c55f7dSAlexei Starovoitov return -EINVAL; 32499c55f7dSAlexei Starovoitov 32596eabe7aSMartin KaFai Lau if (numa_node != NUMA_NO_NODE && 32696e5ae4eSEric Dumazet ((unsigned int)numa_node >= nr_node_ids || 32796e5ae4eSEric Dumazet !node_online(numa_node))) 32896eabe7aSMartin KaFai Lau return -EINVAL; 32996eabe7aSMartin KaFai Lau 33099c55f7dSAlexei Starovoitov /* find map type and init map: hashtable vs rbtree vs bloom vs ... */ 33199c55f7dSAlexei Starovoitov map = find_and_alloc_map(attr); 33299c55f7dSAlexei Starovoitov if (IS_ERR(map)) 33399c55f7dSAlexei Starovoitov return PTR_ERR(map); 33499c55f7dSAlexei Starovoitov 33599c55f7dSAlexei Starovoitov atomic_set(&map->refcnt, 1); 336c9da161cSDaniel Borkmann atomic_set(&map->usercnt, 1); 33799c55f7dSAlexei Starovoitov 338aaac3ba9SAlexei Starovoitov err = bpf_map_charge_memlock(map); 339aaac3ba9SAlexei Starovoitov if (err) 34020b2b24fSDaniel Borkmann goto free_map_nouncharge; 341aaac3ba9SAlexei Starovoitov 342f3f1c054SMartin KaFai Lau err = bpf_map_alloc_id(map); 343f3f1c054SMartin KaFai Lau if (err) 344f3f1c054SMartin KaFai Lau goto free_map; 345f3f1c054SMartin KaFai Lau 346aa79781bSDaniel Borkmann err = bpf_map_new_fd(map); 347bd5f5f4eSMartin KaFai Lau if (err < 0) { 348bd5f5f4eSMartin KaFai Lau /* failed to allocate fd. 349bd5f5f4eSMartin KaFai Lau * bpf_map_put() is needed because the above 350bd5f5f4eSMartin KaFai Lau * bpf_map_alloc_id() has published the map 351bd5f5f4eSMartin KaFai Lau * to the userspace and the userspace may 352bd5f5f4eSMartin KaFai Lau * have refcnt-ed it through BPF_MAP_GET_FD_BY_ID. 353bd5f5f4eSMartin KaFai Lau */ 354bd5f5f4eSMartin KaFai Lau bpf_map_put(map); 355bd5f5f4eSMartin KaFai Lau return err; 356bd5f5f4eSMartin KaFai Lau } 35799c55f7dSAlexei Starovoitov 358a67edbf4SDaniel Borkmann trace_bpf_map_create(map, err); 35999c55f7dSAlexei Starovoitov return err; 36099c55f7dSAlexei Starovoitov 36199c55f7dSAlexei Starovoitov free_map: 36220b2b24fSDaniel Borkmann bpf_map_uncharge_memlock(map); 36320b2b24fSDaniel Borkmann free_map_nouncharge: 36499c55f7dSAlexei Starovoitov map->ops->map_free(map); 36599c55f7dSAlexei Starovoitov return err; 36699c55f7dSAlexei Starovoitov } 36799c55f7dSAlexei Starovoitov 368db20fd2bSAlexei Starovoitov /* if error is returned, fd is released. 369db20fd2bSAlexei Starovoitov * On success caller should complete fd access with matching fdput() 370db20fd2bSAlexei Starovoitov */ 371c2101297SDaniel Borkmann struct bpf_map *__bpf_map_get(struct fd f) 372db20fd2bSAlexei Starovoitov { 373db20fd2bSAlexei Starovoitov if (!f.file) 374db20fd2bSAlexei Starovoitov return ERR_PTR(-EBADF); 375db20fd2bSAlexei Starovoitov if (f.file->f_op != &bpf_map_fops) { 376db20fd2bSAlexei Starovoitov fdput(f); 377db20fd2bSAlexei Starovoitov return ERR_PTR(-EINVAL); 378db20fd2bSAlexei Starovoitov } 379db20fd2bSAlexei Starovoitov 380c2101297SDaniel Borkmann return f.file->private_data; 381c2101297SDaniel Borkmann } 382c2101297SDaniel Borkmann 38392117d84SAlexei Starovoitov /* prog's and map's refcnt limit */ 38492117d84SAlexei Starovoitov #define BPF_MAX_REFCNT 32768 38592117d84SAlexei Starovoitov 38692117d84SAlexei Starovoitov struct bpf_map *bpf_map_inc(struct bpf_map *map, bool uref) 387c9da161cSDaniel Borkmann { 38892117d84SAlexei Starovoitov if (atomic_inc_return(&map->refcnt) > BPF_MAX_REFCNT) { 38992117d84SAlexei Starovoitov atomic_dec(&map->refcnt); 39092117d84SAlexei Starovoitov return ERR_PTR(-EBUSY); 39192117d84SAlexei Starovoitov } 392c9da161cSDaniel Borkmann if (uref) 393c9da161cSDaniel Borkmann atomic_inc(&map->usercnt); 39492117d84SAlexei Starovoitov return map; 395c9da161cSDaniel Borkmann } 396c9da161cSDaniel Borkmann 397c9da161cSDaniel Borkmann struct bpf_map *bpf_map_get_with_uref(u32 ufd) 398c2101297SDaniel Borkmann { 399c2101297SDaniel Borkmann struct fd f = fdget(ufd); 400c2101297SDaniel Borkmann struct bpf_map *map; 401c2101297SDaniel Borkmann 402c2101297SDaniel Borkmann map = __bpf_map_get(f); 403c2101297SDaniel Borkmann if (IS_ERR(map)) 404c2101297SDaniel Borkmann return map; 405c2101297SDaniel Borkmann 40692117d84SAlexei Starovoitov map = bpf_map_inc(map, true); 407c2101297SDaniel Borkmann fdput(f); 408db20fd2bSAlexei Starovoitov 409db20fd2bSAlexei Starovoitov return map; 410db20fd2bSAlexei Starovoitov } 411db20fd2bSAlexei Starovoitov 412bd5f5f4eSMartin KaFai Lau /* map_idr_lock should have been held */ 413bd5f5f4eSMartin KaFai Lau static struct bpf_map *bpf_map_inc_not_zero(struct bpf_map *map, 414bd5f5f4eSMartin KaFai Lau bool uref) 415bd5f5f4eSMartin KaFai Lau { 416bd5f5f4eSMartin KaFai Lau int refold; 417bd5f5f4eSMartin KaFai Lau 418bd5f5f4eSMartin KaFai Lau refold = __atomic_add_unless(&map->refcnt, 1, 0); 419bd5f5f4eSMartin KaFai Lau 420bd5f5f4eSMartin KaFai Lau if (refold >= BPF_MAX_REFCNT) { 421bd5f5f4eSMartin KaFai Lau __bpf_map_put(map, false); 422bd5f5f4eSMartin KaFai Lau return ERR_PTR(-EBUSY); 423bd5f5f4eSMartin KaFai Lau } 424bd5f5f4eSMartin KaFai Lau 425bd5f5f4eSMartin KaFai Lau if (!refold) 426bd5f5f4eSMartin KaFai Lau return ERR_PTR(-ENOENT); 427bd5f5f4eSMartin KaFai Lau 428bd5f5f4eSMartin KaFai Lau if (uref) 429bd5f5f4eSMartin KaFai Lau atomic_inc(&map->usercnt); 430bd5f5f4eSMartin KaFai Lau 431bd5f5f4eSMartin KaFai Lau return map; 432bd5f5f4eSMartin KaFai Lau } 433bd5f5f4eSMartin KaFai Lau 434b8cdc051SAlexei Starovoitov int __weak bpf_stackmap_copy(struct bpf_map *map, void *key, void *value) 435b8cdc051SAlexei Starovoitov { 436b8cdc051SAlexei Starovoitov return -ENOTSUPP; 437b8cdc051SAlexei Starovoitov } 438b8cdc051SAlexei Starovoitov 439db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */ 440db20fd2bSAlexei Starovoitov #define BPF_MAP_LOOKUP_ELEM_LAST_FIELD value 441db20fd2bSAlexei Starovoitov 442db20fd2bSAlexei Starovoitov static int map_lookup_elem(union bpf_attr *attr) 443db20fd2bSAlexei Starovoitov { 444535e7b4bSMickaël Salaün void __user *ukey = u64_to_user_ptr(attr->key); 445535e7b4bSMickaël Salaün void __user *uvalue = u64_to_user_ptr(attr->value); 446db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 447db20fd2bSAlexei Starovoitov struct bpf_map *map; 4488ebe667cSAlexei Starovoitov void *key, *value, *ptr; 44915a07b33SAlexei Starovoitov u32 value_size; 450592867bfSDaniel Borkmann struct fd f; 451db20fd2bSAlexei Starovoitov int err; 452db20fd2bSAlexei Starovoitov 453db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM)) 454db20fd2bSAlexei Starovoitov return -EINVAL; 455db20fd2bSAlexei Starovoitov 456592867bfSDaniel Borkmann f = fdget(ufd); 457c2101297SDaniel Borkmann map = __bpf_map_get(f); 458db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 459db20fd2bSAlexei Starovoitov return PTR_ERR(map); 460db20fd2bSAlexei Starovoitov 461e4448ed8SAl Viro key = memdup_user(ukey, map->key_size); 462e4448ed8SAl Viro if (IS_ERR(key)) { 463e4448ed8SAl Viro err = PTR_ERR(key); 464db20fd2bSAlexei Starovoitov goto err_put; 465e4448ed8SAl Viro } 466db20fd2bSAlexei Starovoitov 46715a07b33SAlexei Starovoitov if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 4688f844938SMartin KaFai Lau map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH || 46915a07b33SAlexei Starovoitov map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) 47015a07b33SAlexei Starovoitov value_size = round_up(map->value_size, 8) * num_possible_cpus(); 47114dc6f04SMartin KaFai Lau else if (IS_FD_MAP(map)) 47214dc6f04SMartin KaFai Lau value_size = sizeof(u32); 47315a07b33SAlexei Starovoitov else 47415a07b33SAlexei Starovoitov value_size = map->value_size; 47515a07b33SAlexei Starovoitov 4768ebe667cSAlexei Starovoitov err = -ENOMEM; 47715a07b33SAlexei Starovoitov value = kmalloc(value_size, GFP_USER | __GFP_NOWARN); 478db20fd2bSAlexei Starovoitov if (!value) 4798ebe667cSAlexei Starovoitov goto free_key; 4808ebe667cSAlexei Starovoitov 4818f844938SMartin KaFai Lau if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 4828f844938SMartin KaFai Lau map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) { 48315a07b33SAlexei Starovoitov err = bpf_percpu_hash_copy(map, key, value); 48415a07b33SAlexei Starovoitov } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) { 48515a07b33SAlexei Starovoitov err = bpf_percpu_array_copy(map, key, value); 486557c0c6eSAlexei Starovoitov } else if (map->map_type == BPF_MAP_TYPE_STACK_TRACE) { 487557c0c6eSAlexei Starovoitov err = bpf_stackmap_copy(map, key, value); 48814dc6f04SMartin KaFai Lau } else if (IS_FD_ARRAY(map)) { 48914dc6f04SMartin KaFai Lau err = bpf_fd_array_map_lookup_elem(map, key, value); 49014dc6f04SMartin KaFai Lau } else if (IS_FD_HASH(map)) { 49114dc6f04SMartin KaFai Lau err = bpf_fd_htab_map_lookup_elem(map, key, value); 49215a07b33SAlexei Starovoitov } else { 4938ebe667cSAlexei Starovoitov rcu_read_lock(); 4948ebe667cSAlexei Starovoitov ptr = map->ops->map_lookup_elem(map, key); 4958ebe667cSAlexei Starovoitov if (ptr) 49615a07b33SAlexei Starovoitov memcpy(value, ptr, value_size); 4978ebe667cSAlexei Starovoitov rcu_read_unlock(); 49815a07b33SAlexei Starovoitov err = ptr ? 0 : -ENOENT; 49915a07b33SAlexei Starovoitov } 5008ebe667cSAlexei Starovoitov 50115a07b33SAlexei Starovoitov if (err) 5028ebe667cSAlexei Starovoitov goto free_value; 503db20fd2bSAlexei Starovoitov 504db20fd2bSAlexei Starovoitov err = -EFAULT; 50515a07b33SAlexei Starovoitov if (copy_to_user(uvalue, value, value_size) != 0) 5068ebe667cSAlexei Starovoitov goto free_value; 507db20fd2bSAlexei Starovoitov 508a67edbf4SDaniel Borkmann trace_bpf_map_lookup_elem(map, ufd, key, value); 509db20fd2bSAlexei Starovoitov err = 0; 510db20fd2bSAlexei Starovoitov 5118ebe667cSAlexei Starovoitov free_value: 5128ebe667cSAlexei Starovoitov kfree(value); 513db20fd2bSAlexei Starovoitov free_key: 514db20fd2bSAlexei Starovoitov kfree(key); 515db20fd2bSAlexei Starovoitov err_put: 516db20fd2bSAlexei Starovoitov fdput(f); 517db20fd2bSAlexei Starovoitov return err; 518db20fd2bSAlexei Starovoitov } 519db20fd2bSAlexei Starovoitov 5203274f520SAlexei Starovoitov #define BPF_MAP_UPDATE_ELEM_LAST_FIELD flags 521db20fd2bSAlexei Starovoitov 522db20fd2bSAlexei Starovoitov static int map_update_elem(union bpf_attr *attr) 523db20fd2bSAlexei Starovoitov { 524535e7b4bSMickaël Salaün void __user *ukey = u64_to_user_ptr(attr->key); 525535e7b4bSMickaël Salaün void __user *uvalue = u64_to_user_ptr(attr->value); 526db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 527db20fd2bSAlexei Starovoitov struct bpf_map *map; 528db20fd2bSAlexei Starovoitov void *key, *value; 52915a07b33SAlexei Starovoitov u32 value_size; 530592867bfSDaniel Borkmann struct fd f; 531db20fd2bSAlexei Starovoitov int err; 532db20fd2bSAlexei Starovoitov 533db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_UPDATE_ELEM)) 534db20fd2bSAlexei Starovoitov return -EINVAL; 535db20fd2bSAlexei Starovoitov 536592867bfSDaniel Borkmann f = fdget(ufd); 537c2101297SDaniel Borkmann map = __bpf_map_get(f); 538db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 539db20fd2bSAlexei Starovoitov return PTR_ERR(map); 540db20fd2bSAlexei Starovoitov 541e4448ed8SAl Viro key = memdup_user(ukey, map->key_size); 542e4448ed8SAl Viro if (IS_ERR(key)) { 543e4448ed8SAl Viro err = PTR_ERR(key); 544db20fd2bSAlexei Starovoitov goto err_put; 545e4448ed8SAl Viro } 546db20fd2bSAlexei Starovoitov 54715a07b33SAlexei Starovoitov if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 5488f844938SMartin KaFai Lau map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH || 54915a07b33SAlexei Starovoitov map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) 55015a07b33SAlexei Starovoitov value_size = round_up(map->value_size, 8) * num_possible_cpus(); 55115a07b33SAlexei Starovoitov else 55215a07b33SAlexei Starovoitov value_size = map->value_size; 55315a07b33SAlexei Starovoitov 554db20fd2bSAlexei Starovoitov err = -ENOMEM; 55515a07b33SAlexei Starovoitov value = kmalloc(value_size, GFP_USER | __GFP_NOWARN); 556db20fd2bSAlexei Starovoitov if (!value) 557db20fd2bSAlexei Starovoitov goto free_key; 558db20fd2bSAlexei Starovoitov 559db20fd2bSAlexei Starovoitov err = -EFAULT; 56015a07b33SAlexei Starovoitov if (copy_from_user(value, uvalue, value_size) != 0) 561db20fd2bSAlexei Starovoitov goto free_value; 562db20fd2bSAlexei Starovoitov 563b121d1e7SAlexei Starovoitov /* must increment bpf_prog_active to avoid kprobe+bpf triggering from 564b121d1e7SAlexei Starovoitov * inside bpf map update or delete otherwise deadlocks are possible 565b121d1e7SAlexei Starovoitov */ 566b121d1e7SAlexei Starovoitov preempt_disable(); 567b121d1e7SAlexei Starovoitov __this_cpu_inc(bpf_prog_active); 5688f844938SMartin KaFai Lau if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 5698f844938SMartin KaFai Lau map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) { 57015a07b33SAlexei Starovoitov err = bpf_percpu_hash_update(map, key, value, attr->flags); 57115a07b33SAlexei Starovoitov } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) { 57215a07b33SAlexei Starovoitov err = bpf_percpu_array_update(map, key, value, attr->flags); 573d056a788SDaniel Borkmann } else if (map->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || 5744ed8ec52SMartin KaFai Lau map->map_type == BPF_MAP_TYPE_PROG_ARRAY || 57556f668dfSMartin KaFai Lau map->map_type == BPF_MAP_TYPE_CGROUP_ARRAY || 57656f668dfSMartin KaFai Lau map->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS) { 577d056a788SDaniel Borkmann rcu_read_lock(); 578d056a788SDaniel Borkmann err = bpf_fd_array_map_update_elem(map, f.file, key, value, 579d056a788SDaniel Borkmann attr->flags); 580d056a788SDaniel Borkmann rcu_read_unlock(); 581bcc6b1b7SMartin KaFai Lau } else if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) { 582bcc6b1b7SMartin KaFai Lau rcu_read_lock(); 583bcc6b1b7SMartin KaFai Lau err = bpf_fd_htab_map_update_elem(map, f.file, key, value, 584bcc6b1b7SMartin KaFai Lau attr->flags); 585bcc6b1b7SMartin KaFai Lau rcu_read_unlock(); 58615a07b33SAlexei Starovoitov } else { 587db20fd2bSAlexei Starovoitov rcu_read_lock(); 5883274f520SAlexei Starovoitov err = map->ops->map_update_elem(map, key, value, attr->flags); 589db20fd2bSAlexei Starovoitov rcu_read_unlock(); 59015a07b33SAlexei Starovoitov } 591b121d1e7SAlexei Starovoitov __this_cpu_dec(bpf_prog_active); 592b121d1e7SAlexei Starovoitov preempt_enable(); 593db20fd2bSAlexei Starovoitov 594a67edbf4SDaniel Borkmann if (!err) 595a67edbf4SDaniel Borkmann trace_bpf_map_update_elem(map, ufd, key, value); 596db20fd2bSAlexei Starovoitov free_value: 597db20fd2bSAlexei Starovoitov kfree(value); 598db20fd2bSAlexei Starovoitov free_key: 599db20fd2bSAlexei Starovoitov kfree(key); 600db20fd2bSAlexei Starovoitov err_put: 601db20fd2bSAlexei Starovoitov fdput(f); 602db20fd2bSAlexei Starovoitov return err; 603db20fd2bSAlexei Starovoitov } 604db20fd2bSAlexei Starovoitov 605db20fd2bSAlexei Starovoitov #define BPF_MAP_DELETE_ELEM_LAST_FIELD key 606db20fd2bSAlexei Starovoitov 607db20fd2bSAlexei Starovoitov static int map_delete_elem(union bpf_attr *attr) 608db20fd2bSAlexei Starovoitov { 609535e7b4bSMickaël Salaün void __user *ukey = u64_to_user_ptr(attr->key); 610db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 611db20fd2bSAlexei Starovoitov struct bpf_map *map; 612592867bfSDaniel Borkmann struct fd f; 613db20fd2bSAlexei Starovoitov void *key; 614db20fd2bSAlexei Starovoitov int err; 615db20fd2bSAlexei Starovoitov 616db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_DELETE_ELEM)) 617db20fd2bSAlexei Starovoitov return -EINVAL; 618db20fd2bSAlexei Starovoitov 619592867bfSDaniel Borkmann f = fdget(ufd); 620c2101297SDaniel Borkmann map = __bpf_map_get(f); 621db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 622db20fd2bSAlexei Starovoitov return PTR_ERR(map); 623db20fd2bSAlexei Starovoitov 624e4448ed8SAl Viro key = memdup_user(ukey, map->key_size); 625e4448ed8SAl Viro if (IS_ERR(key)) { 626e4448ed8SAl Viro err = PTR_ERR(key); 627db20fd2bSAlexei Starovoitov goto err_put; 628e4448ed8SAl Viro } 629db20fd2bSAlexei Starovoitov 630b121d1e7SAlexei Starovoitov preempt_disable(); 631b121d1e7SAlexei Starovoitov __this_cpu_inc(bpf_prog_active); 632db20fd2bSAlexei Starovoitov rcu_read_lock(); 633db20fd2bSAlexei Starovoitov err = map->ops->map_delete_elem(map, key); 634db20fd2bSAlexei Starovoitov rcu_read_unlock(); 635b121d1e7SAlexei Starovoitov __this_cpu_dec(bpf_prog_active); 636b121d1e7SAlexei Starovoitov preempt_enable(); 637db20fd2bSAlexei Starovoitov 638a67edbf4SDaniel Borkmann if (!err) 639a67edbf4SDaniel Borkmann trace_bpf_map_delete_elem(map, ufd, key); 640db20fd2bSAlexei Starovoitov kfree(key); 641db20fd2bSAlexei Starovoitov err_put: 642db20fd2bSAlexei Starovoitov fdput(f); 643db20fd2bSAlexei Starovoitov return err; 644db20fd2bSAlexei Starovoitov } 645db20fd2bSAlexei Starovoitov 646db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */ 647db20fd2bSAlexei Starovoitov #define BPF_MAP_GET_NEXT_KEY_LAST_FIELD next_key 648db20fd2bSAlexei Starovoitov 649db20fd2bSAlexei Starovoitov static int map_get_next_key(union bpf_attr *attr) 650db20fd2bSAlexei Starovoitov { 651535e7b4bSMickaël Salaün void __user *ukey = u64_to_user_ptr(attr->key); 652535e7b4bSMickaël Salaün void __user *unext_key = u64_to_user_ptr(attr->next_key); 653db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 654db20fd2bSAlexei Starovoitov struct bpf_map *map; 655db20fd2bSAlexei Starovoitov void *key, *next_key; 656592867bfSDaniel Borkmann struct fd f; 657db20fd2bSAlexei Starovoitov int err; 658db20fd2bSAlexei Starovoitov 659db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_GET_NEXT_KEY)) 660db20fd2bSAlexei Starovoitov return -EINVAL; 661db20fd2bSAlexei Starovoitov 662592867bfSDaniel Borkmann f = fdget(ufd); 663c2101297SDaniel Borkmann map = __bpf_map_get(f); 664db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 665db20fd2bSAlexei Starovoitov return PTR_ERR(map); 666db20fd2bSAlexei Starovoitov 6678fe45924STeng Qin if (ukey) { 668e4448ed8SAl Viro key = memdup_user(ukey, map->key_size); 669e4448ed8SAl Viro if (IS_ERR(key)) { 670e4448ed8SAl Viro err = PTR_ERR(key); 671db20fd2bSAlexei Starovoitov goto err_put; 672e4448ed8SAl Viro } 6738fe45924STeng Qin } else { 6748fe45924STeng Qin key = NULL; 6758fe45924STeng Qin } 676db20fd2bSAlexei Starovoitov 677db20fd2bSAlexei Starovoitov err = -ENOMEM; 678db20fd2bSAlexei Starovoitov next_key = kmalloc(map->key_size, GFP_USER); 679db20fd2bSAlexei Starovoitov if (!next_key) 680db20fd2bSAlexei Starovoitov goto free_key; 681db20fd2bSAlexei Starovoitov 682db20fd2bSAlexei Starovoitov rcu_read_lock(); 683db20fd2bSAlexei Starovoitov err = map->ops->map_get_next_key(map, key, next_key); 684db20fd2bSAlexei Starovoitov rcu_read_unlock(); 685db20fd2bSAlexei Starovoitov if (err) 686db20fd2bSAlexei Starovoitov goto free_next_key; 687db20fd2bSAlexei Starovoitov 688db20fd2bSAlexei Starovoitov err = -EFAULT; 689db20fd2bSAlexei Starovoitov if (copy_to_user(unext_key, next_key, map->key_size) != 0) 690db20fd2bSAlexei Starovoitov goto free_next_key; 691db20fd2bSAlexei Starovoitov 692a67edbf4SDaniel Borkmann trace_bpf_map_next_key(map, ufd, key, next_key); 693db20fd2bSAlexei Starovoitov err = 0; 694db20fd2bSAlexei Starovoitov 695db20fd2bSAlexei Starovoitov free_next_key: 696db20fd2bSAlexei Starovoitov kfree(next_key); 697db20fd2bSAlexei Starovoitov free_key: 698db20fd2bSAlexei Starovoitov kfree(key); 699db20fd2bSAlexei Starovoitov err_put: 700db20fd2bSAlexei Starovoitov fdput(f); 701db20fd2bSAlexei Starovoitov return err; 702db20fd2bSAlexei Starovoitov } 703db20fd2bSAlexei Starovoitov 704be9370a7SJohannes Berg static const struct bpf_verifier_ops * const bpf_prog_types[] = { 705be9370a7SJohannes Berg #define BPF_PROG_TYPE(_id, _ops) \ 706be9370a7SJohannes Berg [_id] = &_ops, 70740077e0cSJohannes Berg #define BPF_MAP_TYPE(_id, _ops) 708be9370a7SJohannes Berg #include <linux/bpf_types.h> 709be9370a7SJohannes Berg #undef BPF_PROG_TYPE 71040077e0cSJohannes Berg #undef BPF_MAP_TYPE 711be9370a7SJohannes Berg }; 71209756af4SAlexei Starovoitov 71309756af4SAlexei Starovoitov static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog) 71409756af4SAlexei Starovoitov { 715be9370a7SJohannes Berg if (type >= ARRAY_SIZE(bpf_prog_types) || !bpf_prog_types[type]) 716be9370a7SJohannes Berg return -EINVAL; 71709756af4SAlexei Starovoitov 718be9370a7SJohannes Berg prog->aux->ops = bpf_prog_types[type]; 71924701eceSDaniel Borkmann prog->type = type; 72009756af4SAlexei Starovoitov return 0; 72109756af4SAlexei Starovoitov } 72209756af4SAlexei Starovoitov 72309756af4SAlexei Starovoitov /* drop refcnt on maps used by eBPF program and free auxilary data */ 72409756af4SAlexei Starovoitov static void free_used_maps(struct bpf_prog_aux *aux) 72509756af4SAlexei Starovoitov { 72609756af4SAlexei Starovoitov int i; 72709756af4SAlexei Starovoitov 72809756af4SAlexei Starovoitov for (i = 0; i < aux->used_map_cnt; i++) 72909756af4SAlexei Starovoitov bpf_map_put(aux->used_maps[i]); 73009756af4SAlexei Starovoitov 73109756af4SAlexei Starovoitov kfree(aux->used_maps); 73209756af4SAlexei Starovoitov } 73309756af4SAlexei Starovoitov 7345ccb071eSDaniel Borkmann int __bpf_prog_charge(struct user_struct *user, u32 pages) 7355ccb071eSDaniel Borkmann { 7365ccb071eSDaniel Borkmann unsigned long memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; 7375ccb071eSDaniel Borkmann unsigned long user_bufs; 7385ccb071eSDaniel Borkmann 7395ccb071eSDaniel Borkmann if (user) { 7405ccb071eSDaniel Borkmann user_bufs = atomic_long_add_return(pages, &user->locked_vm); 7415ccb071eSDaniel Borkmann if (user_bufs > memlock_limit) { 7425ccb071eSDaniel Borkmann atomic_long_sub(pages, &user->locked_vm); 7435ccb071eSDaniel Borkmann return -EPERM; 7445ccb071eSDaniel Borkmann } 7455ccb071eSDaniel Borkmann } 7465ccb071eSDaniel Borkmann 7475ccb071eSDaniel Borkmann return 0; 7485ccb071eSDaniel Borkmann } 7495ccb071eSDaniel Borkmann 7505ccb071eSDaniel Borkmann void __bpf_prog_uncharge(struct user_struct *user, u32 pages) 7515ccb071eSDaniel Borkmann { 7525ccb071eSDaniel Borkmann if (user) 7535ccb071eSDaniel Borkmann atomic_long_sub(pages, &user->locked_vm); 7545ccb071eSDaniel Borkmann } 7555ccb071eSDaniel Borkmann 756aaac3ba9SAlexei Starovoitov static int bpf_prog_charge_memlock(struct bpf_prog *prog) 757aaac3ba9SAlexei Starovoitov { 758aaac3ba9SAlexei Starovoitov struct user_struct *user = get_current_user(); 7595ccb071eSDaniel Borkmann int ret; 760aaac3ba9SAlexei Starovoitov 7615ccb071eSDaniel Borkmann ret = __bpf_prog_charge(user, prog->pages); 7625ccb071eSDaniel Borkmann if (ret) { 763aaac3ba9SAlexei Starovoitov free_uid(user); 7645ccb071eSDaniel Borkmann return ret; 765aaac3ba9SAlexei Starovoitov } 7665ccb071eSDaniel Borkmann 767aaac3ba9SAlexei Starovoitov prog->aux->user = user; 768aaac3ba9SAlexei Starovoitov return 0; 769aaac3ba9SAlexei Starovoitov } 770aaac3ba9SAlexei Starovoitov 771aaac3ba9SAlexei Starovoitov static void bpf_prog_uncharge_memlock(struct bpf_prog *prog) 772aaac3ba9SAlexei Starovoitov { 773aaac3ba9SAlexei Starovoitov struct user_struct *user = prog->aux->user; 774aaac3ba9SAlexei Starovoitov 7755ccb071eSDaniel Borkmann __bpf_prog_uncharge(user, prog->pages); 776aaac3ba9SAlexei Starovoitov free_uid(user); 777aaac3ba9SAlexei Starovoitov } 778aaac3ba9SAlexei Starovoitov 779dc4bb0e2SMartin KaFai Lau static int bpf_prog_alloc_id(struct bpf_prog *prog) 780dc4bb0e2SMartin KaFai Lau { 781dc4bb0e2SMartin KaFai Lau int id; 782dc4bb0e2SMartin KaFai Lau 783dc4bb0e2SMartin KaFai Lau spin_lock_bh(&prog_idr_lock); 784dc4bb0e2SMartin KaFai Lau id = idr_alloc_cyclic(&prog_idr, prog, 1, INT_MAX, GFP_ATOMIC); 785dc4bb0e2SMartin KaFai Lau if (id > 0) 786dc4bb0e2SMartin KaFai Lau prog->aux->id = id; 787dc4bb0e2SMartin KaFai Lau spin_unlock_bh(&prog_idr_lock); 788dc4bb0e2SMartin KaFai Lau 789dc4bb0e2SMartin KaFai Lau /* id is in [1, INT_MAX) */ 790dc4bb0e2SMartin KaFai Lau if (WARN_ON_ONCE(!id)) 791dc4bb0e2SMartin KaFai Lau return -ENOSPC; 792dc4bb0e2SMartin KaFai Lau 793dc4bb0e2SMartin KaFai Lau return id > 0 ? 0 : id; 794dc4bb0e2SMartin KaFai Lau } 795dc4bb0e2SMartin KaFai Lau 796b16d9aa4SMartin KaFai Lau static void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock) 797dc4bb0e2SMartin KaFai Lau { 798dc4bb0e2SMartin KaFai Lau /* cBPF to eBPF migrations are currently not in the idr store. */ 799dc4bb0e2SMartin KaFai Lau if (!prog->aux->id) 800dc4bb0e2SMartin KaFai Lau return; 801dc4bb0e2SMartin KaFai Lau 802b16d9aa4SMartin KaFai Lau if (do_idr_lock) 803dc4bb0e2SMartin KaFai Lau spin_lock_bh(&prog_idr_lock); 804b16d9aa4SMartin KaFai Lau else 805b16d9aa4SMartin KaFai Lau __acquire(&prog_idr_lock); 806b16d9aa4SMartin KaFai Lau 807dc4bb0e2SMartin KaFai Lau idr_remove(&prog_idr, prog->aux->id); 808b16d9aa4SMartin KaFai Lau 809b16d9aa4SMartin KaFai Lau if (do_idr_lock) 810dc4bb0e2SMartin KaFai Lau spin_unlock_bh(&prog_idr_lock); 811b16d9aa4SMartin KaFai Lau else 812b16d9aa4SMartin KaFai Lau __release(&prog_idr_lock); 813dc4bb0e2SMartin KaFai Lau } 814dc4bb0e2SMartin KaFai Lau 8151aacde3dSDaniel Borkmann static void __bpf_prog_put_rcu(struct rcu_head *rcu) 816abf2e7d6SAlexei Starovoitov { 817abf2e7d6SAlexei Starovoitov struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu); 818abf2e7d6SAlexei Starovoitov 819abf2e7d6SAlexei Starovoitov free_used_maps(aux); 820aaac3ba9SAlexei Starovoitov bpf_prog_uncharge_memlock(aux->prog); 821abf2e7d6SAlexei Starovoitov bpf_prog_free(aux->prog); 822abf2e7d6SAlexei Starovoitov } 823abf2e7d6SAlexei Starovoitov 824b16d9aa4SMartin KaFai Lau static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock) 82509756af4SAlexei Starovoitov { 826a67edbf4SDaniel Borkmann if (atomic_dec_and_test(&prog->aux->refcnt)) { 827a67edbf4SDaniel Borkmann trace_bpf_prog_put_rcu(prog); 82834ad5580SMartin KaFai Lau /* bpf_prog_free_id() must be called first */ 829b16d9aa4SMartin KaFai Lau bpf_prog_free_id(prog, do_idr_lock); 83074451e66SDaniel Borkmann bpf_prog_kallsyms_del(prog); 8311aacde3dSDaniel Borkmann call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu); 83209756af4SAlexei Starovoitov } 833a67edbf4SDaniel Borkmann } 834b16d9aa4SMartin KaFai Lau 835b16d9aa4SMartin KaFai Lau void bpf_prog_put(struct bpf_prog *prog) 836b16d9aa4SMartin KaFai Lau { 837b16d9aa4SMartin KaFai Lau __bpf_prog_put(prog, true); 838b16d9aa4SMartin KaFai Lau } 839e2e9b654SDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_put); 84009756af4SAlexei Starovoitov 84109756af4SAlexei Starovoitov static int bpf_prog_release(struct inode *inode, struct file *filp) 84209756af4SAlexei Starovoitov { 84309756af4SAlexei Starovoitov struct bpf_prog *prog = filp->private_data; 84409756af4SAlexei Starovoitov 8451aacde3dSDaniel Borkmann bpf_prog_put(prog); 84609756af4SAlexei Starovoitov return 0; 84709756af4SAlexei Starovoitov } 84809756af4SAlexei Starovoitov 8497bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS 8507bd509e3SDaniel Borkmann static void bpf_prog_show_fdinfo(struct seq_file *m, struct file *filp) 8517bd509e3SDaniel Borkmann { 8527bd509e3SDaniel Borkmann const struct bpf_prog *prog = filp->private_data; 853f1f7714eSDaniel Borkmann char prog_tag[sizeof(prog->tag) * 2 + 1] = { }; 8547bd509e3SDaniel Borkmann 855f1f7714eSDaniel Borkmann bin2hex(prog_tag, prog->tag, sizeof(prog->tag)); 8567bd509e3SDaniel Borkmann seq_printf(m, 8577bd509e3SDaniel Borkmann "prog_type:\t%u\n" 8587bd509e3SDaniel Borkmann "prog_jited:\t%u\n" 859f1f7714eSDaniel Borkmann "prog_tag:\t%s\n" 8607bd509e3SDaniel Borkmann "memlock:\t%llu\n", 8617bd509e3SDaniel Borkmann prog->type, 8627bd509e3SDaniel Borkmann prog->jited, 863f1f7714eSDaniel Borkmann prog_tag, 8647bd509e3SDaniel Borkmann prog->pages * 1ULL << PAGE_SHIFT); 8657bd509e3SDaniel Borkmann } 8667bd509e3SDaniel Borkmann #endif 8677bd509e3SDaniel Borkmann 86809756af4SAlexei Starovoitov static const struct file_operations bpf_prog_fops = { 8697bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS 8707bd509e3SDaniel Borkmann .show_fdinfo = bpf_prog_show_fdinfo, 8717bd509e3SDaniel Borkmann #endif 87209756af4SAlexei Starovoitov .release = bpf_prog_release, 87309756af4SAlexei Starovoitov }; 87409756af4SAlexei Starovoitov 875b2197755SDaniel Borkmann int bpf_prog_new_fd(struct bpf_prog *prog) 876aa79781bSDaniel Borkmann { 877aa79781bSDaniel Borkmann return anon_inode_getfd("bpf-prog", &bpf_prog_fops, prog, 878aa79781bSDaniel Borkmann O_RDWR | O_CLOEXEC); 879aa79781bSDaniel Borkmann } 880aa79781bSDaniel Borkmann 881113214beSDaniel Borkmann static struct bpf_prog *____bpf_prog_get(struct fd f) 88209756af4SAlexei Starovoitov { 88309756af4SAlexei Starovoitov if (!f.file) 88409756af4SAlexei Starovoitov return ERR_PTR(-EBADF); 88509756af4SAlexei Starovoitov if (f.file->f_op != &bpf_prog_fops) { 88609756af4SAlexei Starovoitov fdput(f); 88709756af4SAlexei Starovoitov return ERR_PTR(-EINVAL); 88809756af4SAlexei Starovoitov } 88909756af4SAlexei Starovoitov 890c2101297SDaniel Borkmann return f.file->private_data; 89109756af4SAlexei Starovoitov } 89209756af4SAlexei Starovoitov 89359d3656dSBrenden Blanco struct bpf_prog *bpf_prog_add(struct bpf_prog *prog, int i) 89492117d84SAlexei Starovoitov { 89559d3656dSBrenden Blanco if (atomic_add_return(i, &prog->aux->refcnt) > BPF_MAX_REFCNT) { 89659d3656dSBrenden Blanco atomic_sub(i, &prog->aux->refcnt); 89792117d84SAlexei Starovoitov return ERR_PTR(-EBUSY); 89892117d84SAlexei Starovoitov } 89992117d84SAlexei Starovoitov return prog; 90092117d84SAlexei Starovoitov } 90159d3656dSBrenden Blanco EXPORT_SYMBOL_GPL(bpf_prog_add); 90259d3656dSBrenden Blanco 903c540594fSDaniel Borkmann void bpf_prog_sub(struct bpf_prog *prog, int i) 904c540594fSDaniel Borkmann { 905c540594fSDaniel Borkmann /* Only to be used for undoing previous bpf_prog_add() in some 906c540594fSDaniel Borkmann * error path. We still know that another entity in our call 907c540594fSDaniel Borkmann * path holds a reference to the program, thus atomic_sub() can 908c540594fSDaniel Borkmann * be safely used in such cases! 909c540594fSDaniel Borkmann */ 910c540594fSDaniel Borkmann WARN_ON(atomic_sub_return(i, &prog->aux->refcnt) == 0); 911c540594fSDaniel Borkmann } 912c540594fSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_sub); 913c540594fSDaniel Borkmann 91459d3656dSBrenden Blanco struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog) 91559d3656dSBrenden Blanco { 91659d3656dSBrenden Blanco return bpf_prog_add(prog, 1); 91759d3656dSBrenden Blanco } 91897bc402dSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_inc); 91992117d84SAlexei Starovoitov 920b16d9aa4SMartin KaFai Lau /* prog_idr_lock should have been held */ 921a6f6df69SJohn Fastabend struct bpf_prog *bpf_prog_inc_not_zero(struct bpf_prog *prog) 922b16d9aa4SMartin KaFai Lau { 923b16d9aa4SMartin KaFai Lau int refold; 924b16d9aa4SMartin KaFai Lau 925b16d9aa4SMartin KaFai Lau refold = __atomic_add_unless(&prog->aux->refcnt, 1, 0); 926b16d9aa4SMartin KaFai Lau 927b16d9aa4SMartin KaFai Lau if (refold >= BPF_MAX_REFCNT) { 928b16d9aa4SMartin KaFai Lau __bpf_prog_put(prog, false); 929b16d9aa4SMartin KaFai Lau return ERR_PTR(-EBUSY); 930b16d9aa4SMartin KaFai Lau } 931b16d9aa4SMartin KaFai Lau 932b16d9aa4SMartin KaFai Lau if (!refold) 933b16d9aa4SMartin KaFai Lau return ERR_PTR(-ENOENT); 934b16d9aa4SMartin KaFai Lau 935b16d9aa4SMartin KaFai Lau return prog; 936b16d9aa4SMartin KaFai Lau } 937a6f6df69SJohn Fastabend EXPORT_SYMBOL_GPL(bpf_prog_inc_not_zero); 938b16d9aa4SMartin KaFai Lau 939113214beSDaniel Borkmann static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *type) 94009756af4SAlexei Starovoitov { 94109756af4SAlexei Starovoitov struct fd f = fdget(ufd); 94209756af4SAlexei Starovoitov struct bpf_prog *prog; 94309756af4SAlexei Starovoitov 944113214beSDaniel Borkmann prog = ____bpf_prog_get(f); 94509756af4SAlexei Starovoitov if (IS_ERR(prog)) 94609756af4SAlexei Starovoitov return prog; 947113214beSDaniel Borkmann if (type && prog->type != *type) { 948113214beSDaniel Borkmann prog = ERR_PTR(-EINVAL); 949113214beSDaniel Borkmann goto out; 950113214beSDaniel Borkmann } 95109756af4SAlexei Starovoitov 95292117d84SAlexei Starovoitov prog = bpf_prog_inc(prog); 953113214beSDaniel Borkmann out: 95409756af4SAlexei Starovoitov fdput(f); 95509756af4SAlexei Starovoitov return prog; 95609756af4SAlexei Starovoitov } 957113214beSDaniel Borkmann 958113214beSDaniel Borkmann struct bpf_prog *bpf_prog_get(u32 ufd) 959113214beSDaniel Borkmann { 960113214beSDaniel Borkmann return __bpf_prog_get(ufd, NULL); 961113214beSDaniel Borkmann } 962113214beSDaniel Borkmann 963113214beSDaniel Borkmann struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type) 964113214beSDaniel Borkmann { 965a67edbf4SDaniel Borkmann struct bpf_prog *prog = __bpf_prog_get(ufd, &type); 966a67edbf4SDaniel Borkmann 967a67edbf4SDaniel Borkmann if (!IS_ERR(prog)) 968a67edbf4SDaniel Borkmann trace_bpf_prog_get_type(prog); 969a67edbf4SDaniel Borkmann return prog; 970113214beSDaniel Borkmann } 971113214beSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_get_type); 97209756af4SAlexei Starovoitov 97309756af4SAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */ 974e07b98d9SDavid S. Miller #define BPF_PROG_LOAD_LAST_FIELD prog_flags 97509756af4SAlexei Starovoitov 97609756af4SAlexei Starovoitov static int bpf_prog_load(union bpf_attr *attr) 97709756af4SAlexei Starovoitov { 97809756af4SAlexei Starovoitov enum bpf_prog_type type = attr->prog_type; 97909756af4SAlexei Starovoitov struct bpf_prog *prog; 98009756af4SAlexei Starovoitov int err; 98109756af4SAlexei Starovoitov char license[128]; 98209756af4SAlexei Starovoitov bool is_gpl; 98309756af4SAlexei Starovoitov 98409756af4SAlexei Starovoitov if (CHECK_ATTR(BPF_PROG_LOAD)) 98509756af4SAlexei Starovoitov return -EINVAL; 98609756af4SAlexei Starovoitov 987e07b98d9SDavid S. Miller if (attr->prog_flags & ~BPF_F_STRICT_ALIGNMENT) 988e07b98d9SDavid S. Miller return -EINVAL; 989e07b98d9SDavid S. Miller 99009756af4SAlexei Starovoitov /* copy eBPF program license from user space */ 991535e7b4bSMickaël Salaün if (strncpy_from_user(license, u64_to_user_ptr(attr->license), 99209756af4SAlexei Starovoitov sizeof(license) - 1) < 0) 99309756af4SAlexei Starovoitov return -EFAULT; 99409756af4SAlexei Starovoitov license[sizeof(license) - 1] = 0; 99509756af4SAlexei Starovoitov 99609756af4SAlexei Starovoitov /* eBPF programs must be GPL compatible to use GPL-ed functions */ 99709756af4SAlexei Starovoitov is_gpl = license_is_gpl_compatible(license); 99809756af4SAlexei Starovoitov 999ef0915caSDaniel Borkmann if (attr->insn_cnt == 0 || attr->insn_cnt > BPF_MAXINSNS) 1000ef0915caSDaniel Borkmann return -E2BIG; 100109756af4SAlexei Starovoitov 10022541517cSAlexei Starovoitov if (type == BPF_PROG_TYPE_KPROBE && 10032541517cSAlexei Starovoitov attr->kern_version != LINUX_VERSION_CODE) 10042541517cSAlexei Starovoitov return -EINVAL; 10052541517cSAlexei Starovoitov 100680b7d819SChenbo Feng if (type != BPF_PROG_TYPE_SOCKET_FILTER && 100780b7d819SChenbo Feng type != BPF_PROG_TYPE_CGROUP_SKB && 100880b7d819SChenbo Feng !capable(CAP_SYS_ADMIN)) 10091be7f75dSAlexei Starovoitov return -EPERM; 10101be7f75dSAlexei Starovoitov 101109756af4SAlexei Starovoitov /* plain bpf_prog allocation */ 101209756af4SAlexei Starovoitov prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER); 101309756af4SAlexei Starovoitov if (!prog) 101409756af4SAlexei Starovoitov return -ENOMEM; 101509756af4SAlexei Starovoitov 1016aaac3ba9SAlexei Starovoitov err = bpf_prog_charge_memlock(prog); 1017aaac3ba9SAlexei Starovoitov if (err) 1018aaac3ba9SAlexei Starovoitov goto free_prog_nouncharge; 1019aaac3ba9SAlexei Starovoitov 102009756af4SAlexei Starovoitov prog->len = attr->insn_cnt; 102109756af4SAlexei Starovoitov 102209756af4SAlexei Starovoitov err = -EFAULT; 1023535e7b4bSMickaël Salaün if (copy_from_user(prog->insns, u64_to_user_ptr(attr->insns), 1024aafe6ae9SDaniel Borkmann bpf_prog_insn_size(prog)) != 0) 102509756af4SAlexei Starovoitov goto free_prog; 102609756af4SAlexei Starovoitov 102709756af4SAlexei Starovoitov prog->orig_prog = NULL; 1028a91263d5SDaniel Borkmann prog->jited = 0; 102909756af4SAlexei Starovoitov 103009756af4SAlexei Starovoitov atomic_set(&prog->aux->refcnt, 1); 1031a91263d5SDaniel Borkmann prog->gpl_compatible = is_gpl ? 1 : 0; 103209756af4SAlexei Starovoitov 103309756af4SAlexei Starovoitov /* find program type: socket_filter vs tracing_filter */ 103409756af4SAlexei Starovoitov err = find_prog_type(type, prog); 103509756af4SAlexei Starovoitov if (err < 0) 103609756af4SAlexei Starovoitov goto free_prog; 103709756af4SAlexei Starovoitov 103809756af4SAlexei Starovoitov /* run eBPF verifier */ 10399bac3d6dSAlexei Starovoitov err = bpf_check(&prog, attr); 104009756af4SAlexei Starovoitov if (err < 0) 104109756af4SAlexei Starovoitov goto free_used_maps; 104209756af4SAlexei Starovoitov 104309756af4SAlexei Starovoitov /* eBPF program is ready to be JITed */ 1044d1c55ab5SDaniel Borkmann prog = bpf_prog_select_runtime(prog, &err); 104504fd61abSAlexei Starovoitov if (err < 0) 104604fd61abSAlexei Starovoitov goto free_used_maps; 104709756af4SAlexei Starovoitov 1048dc4bb0e2SMartin KaFai Lau err = bpf_prog_alloc_id(prog); 1049dc4bb0e2SMartin KaFai Lau if (err) 1050dc4bb0e2SMartin KaFai Lau goto free_used_maps; 1051dc4bb0e2SMartin KaFai Lau 1052aa79781bSDaniel Borkmann err = bpf_prog_new_fd(prog); 1053b16d9aa4SMartin KaFai Lau if (err < 0) { 1054b16d9aa4SMartin KaFai Lau /* failed to allocate fd. 1055b16d9aa4SMartin KaFai Lau * bpf_prog_put() is needed because the above 1056b16d9aa4SMartin KaFai Lau * bpf_prog_alloc_id() has published the prog 1057b16d9aa4SMartin KaFai Lau * to the userspace and the userspace may 1058b16d9aa4SMartin KaFai Lau * have refcnt-ed it through BPF_PROG_GET_FD_BY_ID. 1059b16d9aa4SMartin KaFai Lau */ 1060b16d9aa4SMartin KaFai Lau bpf_prog_put(prog); 1061b16d9aa4SMartin KaFai Lau return err; 1062b16d9aa4SMartin KaFai Lau } 106309756af4SAlexei Starovoitov 106474451e66SDaniel Borkmann bpf_prog_kallsyms_add(prog); 1065a67edbf4SDaniel Borkmann trace_bpf_prog_load(prog, err); 106609756af4SAlexei Starovoitov return err; 106709756af4SAlexei Starovoitov 106809756af4SAlexei Starovoitov free_used_maps: 106909756af4SAlexei Starovoitov free_used_maps(prog->aux); 107009756af4SAlexei Starovoitov free_prog: 1071aaac3ba9SAlexei Starovoitov bpf_prog_uncharge_memlock(prog); 1072aaac3ba9SAlexei Starovoitov free_prog_nouncharge: 107309756af4SAlexei Starovoitov bpf_prog_free(prog); 107409756af4SAlexei Starovoitov return err; 107509756af4SAlexei Starovoitov } 107609756af4SAlexei Starovoitov 1077b2197755SDaniel Borkmann #define BPF_OBJ_LAST_FIELD bpf_fd 1078b2197755SDaniel Borkmann 1079b2197755SDaniel Borkmann static int bpf_obj_pin(const union bpf_attr *attr) 1080b2197755SDaniel Borkmann { 1081b2197755SDaniel Borkmann if (CHECK_ATTR(BPF_OBJ)) 1082b2197755SDaniel Borkmann return -EINVAL; 1083b2197755SDaniel Borkmann 1084535e7b4bSMickaël Salaün return bpf_obj_pin_user(attr->bpf_fd, u64_to_user_ptr(attr->pathname)); 1085b2197755SDaniel Borkmann } 1086b2197755SDaniel Borkmann 1087b2197755SDaniel Borkmann static int bpf_obj_get(const union bpf_attr *attr) 1088b2197755SDaniel Borkmann { 1089b2197755SDaniel Borkmann if (CHECK_ATTR(BPF_OBJ) || attr->bpf_fd != 0) 1090b2197755SDaniel Borkmann return -EINVAL; 1091b2197755SDaniel Borkmann 1092535e7b4bSMickaël Salaün return bpf_obj_get_user(u64_to_user_ptr(attr->pathname)); 1093b2197755SDaniel Borkmann } 1094b2197755SDaniel Borkmann 1095f4324551SDaniel Mack #ifdef CONFIG_CGROUP_BPF 1096f4324551SDaniel Mack 1097464bc0fdSJohn Fastabend #define BPF_PROG_ATTACH_LAST_FIELD attach_flags 1098174a79ffSJohn Fastabend 1099*5a67da2aSJohn Fastabend static int sockmap_get_from_fd(const union bpf_attr *attr, bool attach) 1100174a79ffSJohn Fastabend { 1101*5a67da2aSJohn Fastabend struct bpf_prog *prog = NULL; 1102174a79ffSJohn Fastabend int ufd = attr->target_fd; 1103174a79ffSJohn Fastabend struct bpf_map *map; 1104174a79ffSJohn Fastabend struct fd f; 1105174a79ffSJohn Fastabend int err; 1106174a79ffSJohn Fastabend 1107174a79ffSJohn Fastabend f = fdget(ufd); 1108174a79ffSJohn Fastabend map = __bpf_map_get(f); 1109174a79ffSJohn Fastabend if (IS_ERR(map)) 1110174a79ffSJohn Fastabend return PTR_ERR(map); 1111174a79ffSJohn Fastabend 1112*5a67da2aSJohn Fastabend if (attach) { 1113*5a67da2aSJohn Fastabend prog = bpf_prog_get_type(attr->attach_bpf_fd, 1114*5a67da2aSJohn Fastabend BPF_PROG_TYPE_SK_SKB); 1115464bc0fdSJohn Fastabend if (IS_ERR(prog)) { 1116174a79ffSJohn Fastabend fdput(f); 1117464bc0fdSJohn Fastabend return PTR_ERR(prog); 1118174a79ffSJohn Fastabend } 1119*5a67da2aSJohn Fastabend } 1120174a79ffSJohn Fastabend 1121*5a67da2aSJohn Fastabend err = sock_map_prog(map, prog, attr->attach_type); 1122174a79ffSJohn Fastabend if (err) { 1123174a79ffSJohn Fastabend fdput(f); 1124*5a67da2aSJohn Fastabend if (prog) 1125464bc0fdSJohn Fastabend bpf_prog_put(prog); 1126ae2b27b8SDan Carpenter return err; 1127174a79ffSJohn Fastabend } 1128174a79ffSJohn Fastabend 1129174a79ffSJohn Fastabend fdput(f); 1130ae2b27b8SDan Carpenter return 0; 1131174a79ffSJohn Fastabend } 1132f4324551SDaniel Mack 1133f4324551SDaniel Mack static int bpf_prog_attach(const union bpf_attr *attr) 1134f4324551SDaniel Mack { 11357f677633SAlexei Starovoitov enum bpf_prog_type ptype; 1136f4324551SDaniel Mack struct bpf_prog *prog; 1137f4324551SDaniel Mack struct cgroup *cgrp; 11387f677633SAlexei Starovoitov int ret; 1139f4324551SDaniel Mack 1140f4324551SDaniel Mack if (!capable(CAP_NET_ADMIN)) 1141f4324551SDaniel Mack return -EPERM; 1142f4324551SDaniel Mack 1143f4324551SDaniel Mack if (CHECK_ATTR(BPF_PROG_ATTACH)) 1144f4324551SDaniel Mack return -EINVAL; 1145f4324551SDaniel Mack 11467f677633SAlexei Starovoitov if (attr->attach_flags & ~BPF_F_ALLOW_OVERRIDE) 11477f677633SAlexei Starovoitov return -EINVAL; 11487f677633SAlexei Starovoitov 1149f4324551SDaniel Mack switch (attr->attach_type) { 1150f4324551SDaniel Mack case BPF_CGROUP_INET_INGRESS: 1151f4324551SDaniel Mack case BPF_CGROUP_INET_EGRESS: 1152b2cd1257SDavid Ahern ptype = BPF_PROG_TYPE_CGROUP_SKB; 1153b2cd1257SDavid Ahern break; 115461023658SDavid Ahern case BPF_CGROUP_INET_SOCK_CREATE: 115561023658SDavid Ahern ptype = BPF_PROG_TYPE_CGROUP_SOCK; 115661023658SDavid Ahern break; 115740304b2aSLawrence Brakmo case BPF_CGROUP_SOCK_OPS: 115840304b2aSLawrence Brakmo ptype = BPF_PROG_TYPE_SOCK_OPS; 115940304b2aSLawrence Brakmo break; 1160464bc0fdSJohn Fastabend case BPF_SK_SKB_STREAM_PARSER: 1161464bc0fdSJohn Fastabend case BPF_SK_SKB_STREAM_VERDICT: 1162*5a67da2aSJohn Fastabend return sockmap_get_from_fd(attr, true); 1163b2cd1257SDavid Ahern default: 1164b2cd1257SDavid Ahern return -EINVAL; 1165b2cd1257SDavid Ahern } 1166b2cd1257SDavid Ahern 1167b2cd1257SDavid Ahern prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype); 1168f4324551SDaniel Mack if (IS_ERR(prog)) 1169f4324551SDaniel Mack return PTR_ERR(prog); 1170f4324551SDaniel Mack 1171f4324551SDaniel Mack cgrp = cgroup_get_from_fd(attr->target_fd); 1172f4324551SDaniel Mack if (IS_ERR(cgrp)) { 1173f4324551SDaniel Mack bpf_prog_put(prog); 1174f4324551SDaniel Mack return PTR_ERR(cgrp); 1175f4324551SDaniel Mack } 1176f4324551SDaniel Mack 11777f677633SAlexei Starovoitov ret = cgroup_bpf_update(cgrp, prog, attr->attach_type, 11787f677633SAlexei Starovoitov attr->attach_flags & BPF_F_ALLOW_OVERRIDE); 11797f677633SAlexei Starovoitov if (ret) 11807f677633SAlexei Starovoitov bpf_prog_put(prog); 1181f4324551SDaniel Mack cgroup_put(cgrp); 1182f4324551SDaniel Mack 11837f677633SAlexei Starovoitov return ret; 1184f4324551SDaniel Mack } 1185f4324551SDaniel Mack 1186f4324551SDaniel Mack #define BPF_PROG_DETACH_LAST_FIELD attach_type 1187f4324551SDaniel Mack 1188f4324551SDaniel Mack static int bpf_prog_detach(const union bpf_attr *attr) 1189f4324551SDaniel Mack { 1190f4324551SDaniel Mack struct cgroup *cgrp; 11917f677633SAlexei Starovoitov int ret; 1192f4324551SDaniel Mack 1193f4324551SDaniel Mack if (!capable(CAP_NET_ADMIN)) 1194f4324551SDaniel Mack return -EPERM; 1195f4324551SDaniel Mack 1196f4324551SDaniel Mack if (CHECK_ATTR(BPF_PROG_DETACH)) 1197f4324551SDaniel Mack return -EINVAL; 1198f4324551SDaniel Mack 1199f4324551SDaniel Mack switch (attr->attach_type) { 1200f4324551SDaniel Mack case BPF_CGROUP_INET_INGRESS: 1201f4324551SDaniel Mack case BPF_CGROUP_INET_EGRESS: 120261023658SDavid Ahern case BPF_CGROUP_INET_SOCK_CREATE: 120340304b2aSLawrence Brakmo case BPF_CGROUP_SOCK_OPS: 1204f4324551SDaniel Mack cgrp = cgroup_get_from_fd(attr->target_fd); 1205f4324551SDaniel Mack if (IS_ERR(cgrp)) 1206f4324551SDaniel Mack return PTR_ERR(cgrp); 1207f4324551SDaniel Mack 12087f677633SAlexei Starovoitov ret = cgroup_bpf_update(cgrp, NULL, attr->attach_type, false); 1209f4324551SDaniel Mack cgroup_put(cgrp); 1210f4324551SDaniel Mack break; 1211*5a67da2aSJohn Fastabend case BPF_SK_SKB_STREAM_PARSER: 1212*5a67da2aSJohn Fastabend case BPF_SK_SKB_STREAM_VERDICT: 1213*5a67da2aSJohn Fastabend ret = sockmap_get_from_fd(attr, false); 1214*5a67da2aSJohn Fastabend break; 1215f4324551SDaniel Mack default: 1216f4324551SDaniel Mack return -EINVAL; 1217f4324551SDaniel Mack } 1218f4324551SDaniel Mack 12197f677633SAlexei Starovoitov return ret; 1220f4324551SDaniel Mack } 122140304b2aSLawrence Brakmo 1222f4324551SDaniel Mack #endif /* CONFIG_CGROUP_BPF */ 1223f4324551SDaniel Mack 12241cf1cae9SAlexei Starovoitov #define BPF_PROG_TEST_RUN_LAST_FIELD test.duration 12251cf1cae9SAlexei Starovoitov 12261cf1cae9SAlexei Starovoitov static int bpf_prog_test_run(const union bpf_attr *attr, 12271cf1cae9SAlexei Starovoitov union bpf_attr __user *uattr) 12281cf1cae9SAlexei Starovoitov { 12291cf1cae9SAlexei Starovoitov struct bpf_prog *prog; 12301cf1cae9SAlexei Starovoitov int ret = -ENOTSUPP; 12311cf1cae9SAlexei Starovoitov 12321cf1cae9SAlexei Starovoitov if (CHECK_ATTR(BPF_PROG_TEST_RUN)) 12331cf1cae9SAlexei Starovoitov return -EINVAL; 12341cf1cae9SAlexei Starovoitov 12351cf1cae9SAlexei Starovoitov prog = bpf_prog_get(attr->test.prog_fd); 12361cf1cae9SAlexei Starovoitov if (IS_ERR(prog)) 12371cf1cae9SAlexei Starovoitov return PTR_ERR(prog); 12381cf1cae9SAlexei Starovoitov 12391cf1cae9SAlexei Starovoitov if (prog->aux->ops->test_run) 12401cf1cae9SAlexei Starovoitov ret = prog->aux->ops->test_run(prog, attr, uattr); 12411cf1cae9SAlexei Starovoitov 12421cf1cae9SAlexei Starovoitov bpf_prog_put(prog); 12431cf1cae9SAlexei Starovoitov return ret; 12441cf1cae9SAlexei Starovoitov } 12451cf1cae9SAlexei Starovoitov 124634ad5580SMartin KaFai Lau #define BPF_OBJ_GET_NEXT_ID_LAST_FIELD next_id 124734ad5580SMartin KaFai Lau 124834ad5580SMartin KaFai Lau static int bpf_obj_get_next_id(const union bpf_attr *attr, 124934ad5580SMartin KaFai Lau union bpf_attr __user *uattr, 125034ad5580SMartin KaFai Lau struct idr *idr, 125134ad5580SMartin KaFai Lau spinlock_t *lock) 125234ad5580SMartin KaFai Lau { 125334ad5580SMartin KaFai Lau u32 next_id = attr->start_id; 125434ad5580SMartin KaFai Lau int err = 0; 125534ad5580SMartin KaFai Lau 125634ad5580SMartin KaFai Lau if (CHECK_ATTR(BPF_OBJ_GET_NEXT_ID) || next_id >= INT_MAX) 125734ad5580SMartin KaFai Lau return -EINVAL; 125834ad5580SMartin KaFai Lau 125934ad5580SMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) 126034ad5580SMartin KaFai Lau return -EPERM; 126134ad5580SMartin KaFai Lau 126234ad5580SMartin KaFai Lau next_id++; 126334ad5580SMartin KaFai Lau spin_lock_bh(lock); 126434ad5580SMartin KaFai Lau if (!idr_get_next(idr, &next_id)) 126534ad5580SMartin KaFai Lau err = -ENOENT; 126634ad5580SMartin KaFai Lau spin_unlock_bh(lock); 126734ad5580SMartin KaFai Lau 126834ad5580SMartin KaFai Lau if (!err) 126934ad5580SMartin KaFai Lau err = put_user(next_id, &uattr->next_id); 127034ad5580SMartin KaFai Lau 127134ad5580SMartin KaFai Lau return err; 127234ad5580SMartin KaFai Lau } 127334ad5580SMartin KaFai Lau 1274b16d9aa4SMartin KaFai Lau #define BPF_PROG_GET_FD_BY_ID_LAST_FIELD prog_id 1275b16d9aa4SMartin KaFai Lau 1276b16d9aa4SMartin KaFai Lau static int bpf_prog_get_fd_by_id(const union bpf_attr *attr) 1277b16d9aa4SMartin KaFai Lau { 1278b16d9aa4SMartin KaFai Lau struct bpf_prog *prog; 1279b16d9aa4SMartin KaFai Lau u32 id = attr->prog_id; 1280b16d9aa4SMartin KaFai Lau int fd; 1281b16d9aa4SMartin KaFai Lau 1282b16d9aa4SMartin KaFai Lau if (CHECK_ATTR(BPF_PROG_GET_FD_BY_ID)) 1283b16d9aa4SMartin KaFai Lau return -EINVAL; 1284b16d9aa4SMartin KaFai Lau 1285b16d9aa4SMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) 1286b16d9aa4SMartin KaFai Lau return -EPERM; 1287b16d9aa4SMartin KaFai Lau 1288b16d9aa4SMartin KaFai Lau spin_lock_bh(&prog_idr_lock); 1289b16d9aa4SMartin KaFai Lau prog = idr_find(&prog_idr, id); 1290b16d9aa4SMartin KaFai Lau if (prog) 1291b16d9aa4SMartin KaFai Lau prog = bpf_prog_inc_not_zero(prog); 1292b16d9aa4SMartin KaFai Lau else 1293b16d9aa4SMartin KaFai Lau prog = ERR_PTR(-ENOENT); 1294b16d9aa4SMartin KaFai Lau spin_unlock_bh(&prog_idr_lock); 1295b16d9aa4SMartin KaFai Lau 1296b16d9aa4SMartin KaFai Lau if (IS_ERR(prog)) 1297b16d9aa4SMartin KaFai Lau return PTR_ERR(prog); 1298b16d9aa4SMartin KaFai Lau 1299b16d9aa4SMartin KaFai Lau fd = bpf_prog_new_fd(prog); 1300b16d9aa4SMartin KaFai Lau if (fd < 0) 1301b16d9aa4SMartin KaFai Lau bpf_prog_put(prog); 1302b16d9aa4SMartin KaFai Lau 1303b16d9aa4SMartin KaFai Lau return fd; 1304b16d9aa4SMartin KaFai Lau } 1305b16d9aa4SMartin KaFai Lau 1306bd5f5f4eSMartin KaFai Lau #define BPF_MAP_GET_FD_BY_ID_LAST_FIELD map_id 1307bd5f5f4eSMartin KaFai Lau 1308bd5f5f4eSMartin KaFai Lau static int bpf_map_get_fd_by_id(const union bpf_attr *attr) 1309bd5f5f4eSMartin KaFai Lau { 1310bd5f5f4eSMartin KaFai Lau struct bpf_map *map; 1311bd5f5f4eSMartin KaFai Lau u32 id = attr->map_id; 1312bd5f5f4eSMartin KaFai Lau int fd; 1313bd5f5f4eSMartin KaFai Lau 1314bd5f5f4eSMartin KaFai Lau if (CHECK_ATTR(BPF_MAP_GET_FD_BY_ID)) 1315bd5f5f4eSMartin KaFai Lau return -EINVAL; 1316bd5f5f4eSMartin KaFai Lau 1317bd5f5f4eSMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) 1318bd5f5f4eSMartin KaFai Lau return -EPERM; 1319bd5f5f4eSMartin KaFai Lau 1320bd5f5f4eSMartin KaFai Lau spin_lock_bh(&map_idr_lock); 1321bd5f5f4eSMartin KaFai Lau map = idr_find(&map_idr, id); 1322bd5f5f4eSMartin KaFai Lau if (map) 1323bd5f5f4eSMartin KaFai Lau map = bpf_map_inc_not_zero(map, true); 1324bd5f5f4eSMartin KaFai Lau else 1325bd5f5f4eSMartin KaFai Lau map = ERR_PTR(-ENOENT); 1326bd5f5f4eSMartin KaFai Lau spin_unlock_bh(&map_idr_lock); 1327bd5f5f4eSMartin KaFai Lau 1328bd5f5f4eSMartin KaFai Lau if (IS_ERR(map)) 1329bd5f5f4eSMartin KaFai Lau return PTR_ERR(map); 1330bd5f5f4eSMartin KaFai Lau 1331bd5f5f4eSMartin KaFai Lau fd = bpf_map_new_fd(map); 1332bd5f5f4eSMartin KaFai Lau if (fd < 0) 1333bd5f5f4eSMartin KaFai Lau bpf_map_put(map); 1334bd5f5f4eSMartin KaFai Lau 1335bd5f5f4eSMartin KaFai Lau return fd; 1336bd5f5f4eSMartin KaFai Lau } 1337bd5f5f4eSMartin KaFai Lau 13381e270976SMartin KaFai Lau static int bpf_prog_get_info_by_fd(struct bpf_prog *prog, 13391e270976SMartin KaFai Lau const union bpf_attr *attr, 13401e270976SMartin KaFai Lau union bpf_attr __user *uattr) 13411e270976SMartin KaFai Lau { 13421e270976SMartin KaFai Lau struct bpf_prog_info __user *uinfo = u64_to_user_ptr(attr->info.info); 13431e270976SMartin KaFai Lau struct bpf_prog_info info = {}; 13441e270976SMartin KaFai Lau u32 info_len = attr->info.info_len; 13451e270976SMartin KaFai Lau char __user *uinsns; 13461e270976SMartin KaFai Lau u32 ulen; 13471e270976SMartin KaFai Lau int err; 13481e270976SMartin KaFai Lau 13491e270976SMartin KaFai Lau err = check_uarg_tail_zero(uinfo, sizeof(info), info_len); 13501e270976SMartin KaFai Lau if (err) 13511e270976SMartin KaFai Lau return err; 13521e270976SMartin KaFai Lau info_len = min_t(u32, sizeof(info), info_len); 13531e270976SMartin KaFai Lau 13541e270976SMartin KaFai Lau if (copy_from_user(&info, uinfo, info_len)) 135589b09689SDaniel Borkmann return -EFAULT; 13561e270976SMartin KaFai Lau 13571e270976SMartin KaFai Lau info.type = prog->type; 13581e270976SMartin KaFai Lau info.id = prog->aux->id; 13591e270976SMartin KaFai Lau 13601e270976SMartin KaFai Lau memcpy(info.tag, prog->tag, sizeof(prog->tag)); 13611e270976SMartin KaFai Lau 13621e270976SMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) { 13631e270976SMartin KaFai Lau info.jited_prog_len = 0; 13641e270976SMartin KaFai Lau info.xlated_prog_len = 0; 13651e270976SMartin KaFai Lau goto done; 13661e270976SMartin KaFai Lau } 13671e270976SMartin KaFai Lau 13681e270976SMartin KaFai Lau ulen = info.jited_prog_len; 13691e270976SMartin KaFai Lau info.jited_prog_len = prog->jited_len; 13701e270976SMartin KaFai Lau if (info.jited_prog_len && ulen) { 13711e270976SMartin KaFai Lau uinsns = u64_to_user_ptr(info.jited_prog_insns); 13721e270976SMartin KaFai Lau ulen = min_t(u32, info.jited_prog_len, ulen); 13731e270976SMartin KaFai Lau if (copy_to_user(uinsns, prog->bpf_func, ulen)) 13741e270976SMartin KaFai Lau return -EFAULT; 13751e270976SMartin KaFai Lau } 13761e270976SMartin KaFai Lau 13771e270976SMartin KaFai Lau ulen = info.xlated_prog_len; 13789975a54bSDaniel Borkmann info.xlated_prog_len = bpf_prog_insn_size(prog); 13791e270976SMartin KaFai Lau if (info.xlated_prog_len && ulen) { 13801e270976SMartin KaFai Lau uinsns = u64_to_user_ptr(info.xlated_prog_insns); 13811e270976SMartin KaFai Lau ulen = min_t(u32, info.xlated_prog_len, ulen); 13821e270976SMartin KaFai Lau if (copy_to_user(uinsns, prog->insnsi, ulen)) 13831e270976SMartin KaFai Lau return -EFAULT; 13841e270976SMartin KaFai Lau } 13851e270976SMartin KaFai Lau 13861e270976SMartin KaFai Lau done: 13871e270976SMartin KaFai Lau if (copy_to_user(uinfo, &info, info_len) || 13881e270976SMartin KaFai Lau put_user(info_len, &uattr->info.info_len)) 13891e270976SMartin KaFai Lau return -EFAULT; 13901e270976SMartin KaFai Lau 13911e270976SMartin KaFai Lau return 0; 13921e270976SMartin KaFai Lau } 13931e270976SMartin KaFai Lau 13941e270976SMartin KaFai Lau static int bpf_map_get_info_by_fd(struct bpf_map *map, 13951e270976SMartin KaFai Lau const union bpf_attr *attr, 13961e270976SMartin KaFai Lau union bpf_attr __user *uattr) 13971e270976SMartin KaFai Lau { 13981e270976SMartin KaFai Lau struct bpf_map_info __user *uinfo = u64_to_user_ptr(attr->info.info); 13991e270976SMartin KaFai Lau struct bpf_map_info info = {}; 14001e270976SMartin KaFai Lau u32 info_len = attr->info.info_len; 14011e270976SMartin KaFai Lau int err; 14021e270976SMartin KaFai Lau 14031e270976SMartin KaFai Lau err = check_uarg_tail_zero(uinfo, sizeof(info), info_len); 14041e270976SMartin KaFai Lau if (err) 14051e270976SMartin KaFai Lau return err; 14061e270976SMartin KaFai Lau info_len = min_t(u32, sizeof(info), info_len); 14071e270976SMartin KaFai Lau 14081e270976SMartin KaFai Lau info.type = map->map_type; 14091e270976SMartin KaFai Lau info.id = map->id; 14101e270976SMartin KaFai Lau info.key_size = map->key_size; 14111e270976SMartin KaFai Lau info.value_size = map->value_size; 14121e270976SMartin KaFai Lau info.max_entries = map->max_entries; 14131e270976SMartin KaFai Lau info.map_flags = map->map_flags; 14141e270976SMartin KaFai Lau 14151e270976SMartin KaFai Lau if (copy_to_user(uinfo, &info, info_len) || 14161e270976SMartin KaFai Lau put_user(info_len, &uattr->info.info_len)) 14171e270976SMartin KaFai Lau return -EFAULT; 14181e270976SMartin KaFai Lau 14191e270976SMartin KaFai Lau return 0; 14201e270976SMartin KaFai Lau } 14211e270976SMartin KaFai Lau 14221e270976SMartin KaFai Lau #define BPF_OBJ_GET_INFO_BY_FD_LAST_FIELD info.info 14231e270976SMartin KaFai Lau 14241e270976SMartin KaFai Lau static int bpf_obj_get_info_by_fd(const union bpf_attr *attr, 14251e270976SMartin KaFai Lau union bpf_attr __user *uattr) 14261e270976SMartin KaFai Lau { 14271e270976SMartin KaFai Lau int ufd = attr->info.bpf_fd; 14281e270976SMartin KaFai Lau struct fd f; 14291e270976SMartin KaFai Lau int err; 14301e270976SMartin KaFai Lau 14311e270976SMartin KaFai Lau if (CHECK_ATTR(BPF_OBJ_GET_INFO_BY_FD)) 14321e270976SMartin KaFai Lau return -EINVAL; 14331e270976SMartin KaFai Lau 14341e270976SMartin KaFai Lau f = fdget(ufd); 14351e270976SMartin KaFai Lau if (!f.file) 14361e270976SMartin KaFai Lau return -EBADFD; 14371e270976SMartin KaFai Lau 14381e270976SMartin KaFai Lau if (f.file->f_op == &bpf_prog_fops) 14391e270976SMartin KaFai Lau err = bpf_prog_get_info_by_fd(f.file->private_data, attr, 14401e270976SMartin KaFai Lau uattr); 14411e270976SMartin KaFai Lau else if (f.file->f_op == &bpf_map_fops) 14421e270976SMartin KaFai Lau err = bpf_map_get_info_by_fd(f.file->private_data, attr, 14431e270976SMartin KaFai Lau uattr); 14441e270976SMartin KaFai Lau else 14451e270976SMartin KaFai Lau err = -EINVAL; 14461e270976SMartin KaFai Lau 14471e270976SMartin KaFai Lau fdput(f); 14481e270976SMartin KaFai Lau return err; 14491e270976SMartin KaFai Lau } 14501e270976SMartin KaFai Lau 145199c55f7dSAlexei Starovoitov SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size) 145299c55f7dSAlexei Starovoitov { 145399c55f7dSAlexei Starovoitov union bpf_attr attr = {}; 145499c55f7dSAlexei Starovoitov int err; 145599c55f7dSAlexei Starovoitov 14561be7f75dSAlexei Starovoitov if (!capable(CAP_SYS_ADMIN) && sysctl_unprivileged_bpf_disabled) 145799c55f7dSAlexei Starovoitov return -EPERM; 145899c55f7dSAlexei Starovoitov 14591e270976SMartin KaFai Lau err = check_uarg_tail_zero(uattr, sizeof(attr), size); 146099c55f7dSAlexei Starovoitov if (err) 146199c55f7dSAlexei Starovoitov return err; 14621e270976SMartin KaFai Lau size = min_t(u32, size, sizeof(attr)); 146399c55f7dSAlexei Starovoitov 146499c55f7dSAlexei Starovoitov /* copy attributes from user space, may be less than sizeof(bpf_attr) */ 146599c55f7dSAlexei Starovoitov if (copy_from_user(&attr, uattr, size) != 0) 146699c55f7dSAlexei Starovoitov return -EFAULT; 146799c55f7dSAlexei Starovoitov 146899c55f7dSAlexei Starovoitov switch (cmd) { 146999c55f7dSAlexei Starovoitov case BPF_MAP_CREATE: 147099c55f7dSAlexei Starovoitov err = map_create(&attr); 147199c55f7dSAlexei Starovoitov break; 1472db20fd2bSAlexei Starovoitov case BPF_MAP_LOOKUP_ELEM: 1473db20fd2bSAlexei Starovoitov err = map_lookup_elem(&attr); 1474db20fd2bSAlexei Starovoitov break; 1475db20fd2bSAlexei Starovoitov case BPF_MAP_UPDATE_ELEM: 1476db20fd2bSAlexei Starovoitov err = map_update_elem(&attr); 1477db20fd2bSAlexei Starovoitov break; 1478db20fd2bSAlexei Starovoitov case BPF_MAP_DELETE_ELEM: 1479db20fd2bSAlexei Starovoitov err = map_delete_elem(&attr); 1480db20fd2bSAlexei Starovoitov break; 1481db20fd2bSAlexei Starovoitov case BPF_MAP_GET_NEXT_KEY: 1482db20fd2bSAlexei Starovoitov err = map_get_next_key(&attr); 1483db20fd2bSAlexei Starovoitov break; 148409756af4SAlexei Starovoitov case BPF_PROG_LOAD: 148509756af4SAlexei Starovoitov err = bpf_prog_load(&attr); 148609756af4SAlexei Starovoitov break; 1487b2197755SDaniel Borkmann case BPF_OBJ_PIN: 1488b2197755SDaniel Borkmann err = bpf_obj_pin(&attr); 1489b2197755SDaniel Borkmann break; 1490b2197755SDaniel Borkmann case BPF_OBJ_GET: 1491b2197755SDaniel Borkmann err = bpf_obj_get(&attr); 1492b2197755SDaniel Borkmann break; 1493f4324551SDaniel Mack #ifdef CONFIG_CGROUP_BPF 1494f4324551SDaniel Mack case BPF_PROG_ATTACH: 1495f4324551SDaniel Mack err = bpf_prog_attach(&attr); 1496f4324551SDaniel Mack break; 1497f4324551SDaniel Mack case BPF_PROG_DETACH: 1498f4324551SDaniel Mack err = bpf_prog_detach(&attr); 1499f4324551SDaniel Mack break; 1500f4324551SDaniel Mack #endif 15011cf1cae9SAlexei Starovoitov case BPF_PROG_TEST_RUN: 15021cf1cae9SAlexei Starovoitov err = bpf_prog_test_run(&attr, uattr); 15031cf1cae9SAlexei Starovoitov break; 150434ad5580SMartin KaFai Lau case BPF_PROG_GET_NEXT_ID: 150534ad5580SMartin KaFai Lau err = bpf_obj_get_next_id(&attr, uattr, 150634ad5580SMartin KaFai Lau &prog_idr, &prog_idr_lock); 150734ad5580SMartin KaFai Lau break; 150834ad5580SMartin KaFai Lau case BPF_MAP_GET_NEXT_ID: 150934ad5580SMartin KaFai Lau err = bpf_obj_get_next_id(&attr, uattr, 151034ad5580SMartin KaFai Lau &map_idr, &map_idr_lock); 151134ad5580SMartin KaFai Lau break; 1512b16d9aa4SMartin KaFai Lau case BPF_PROG_GET_FD_BY_ID: 1513b16d9aa4SMartin KaFai Lau err = bpf_prog_get_fd_by_id(&attr); 1514b16d9aa4SMartin KaFai Lau break; 1515bd5f5f4eSMartin KaFai Lau case BPF_MAP_GET_FD_BY_ID: 1516bd5f5f4eSMartin KaFai Lau err = bpf_map_get_fd_by_id(&attr); 1517bd5f5f4eSMartin KaFai Lau break; 15181e270976SMartin KaFai Lau case BPF_OBJ_GET_INFO_BY_FD: 15191e270976SMartin KaFai Lau err = bpf_obj_get_info_by_fd(&attr, uattr); 15201e270976SMartin KaFai Lau break; 152199c55f7dSAlexei Starovoitov default: 152299c55f7dSAlexei Starovoitov err = -EINVAL; 152399c55f7dSAlexei Starovoitov break; 152499c55f7dSAlexei Starovoitov } 152599c55f7dSAlexei Starovoitov 152699c55f7dSAlexei Starovoitov return err; 152799c55f7dSAlexei Starovoitov } 1528