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 && 32696eabe7aSMartin KaFai Lau (numa_node >= nr_node_ids || !node_online(numa_node))) 32796eabe7aSMartin KaFai Lau return -EINVAL; 32896eabe7aSMartin KaFai Lau 32999c55f7dSAlexei Starovoitov /* find map type and init map: hashtable vs rbtree vs bloom vs ... */ 33099c55f7dSAlexei Starovoitov map = find_and_alloc_map(attr); 33199c55f7dSAlexei Starovoitov if (IS_ERR(map)) 33299c55f7dSAlexei Starovoitov return PTR_ERR(map); 33399c55f7dSAlexei Starovoitov 33499c55f7dSAlexei Starovoitov atomic_set(&map->refcnt, 1); 335c9da161cSDaniel Borkmann atomic_set(&map->usercnt, 1); 33699c55f7dSAlexei Starovoitov 337aaac3ba9SAlexei Starovoitov err = bpf_map_charge_memlock(map); 338aaac3ba9SAlexei Starovoitov if (err) 33920b2b24fSDaniel Borkmann goto free_map_nouncharge; 340aaac3ba9SAlexei Starovoitov 341f3f1c054SMartin KaFai Lau err = bpf_map_alloc_id(map); 342f3f1c054SMartin KaFai Lau if (err) 343f3f1c054SMartin KaFai Lau goto free_map; 344f3f1c054SMartin KaFai Lau 345aa79781bSDaniel Borkmann err = bpf_map_new_fd(map); 346bd5f5f4eSMartin KaFai Lau if (err < 0) { 347bd5f5f4eSMartin KaFai Lau /* failed to allocate fd. 348bd5f5f4eSMartin KaFai Lau * bpf_map_put() is needed because the above 349bd5f5f4eSMartin KaFai Lau * bpf_map_alloc_id() has published the map 350bd5f5f4eSMartin KaFai Lau * to the userspace and the userspace may 351bd5f5f4eSMartin KaFai Lau * have refcnt-ed it through BPF_MAP_GET_FD_BY_ID. 352bd5f5f4eSMartin KaFai Lau */ 353bd5f5f4eSMartin KaFai Lau bpf_map_put(map); 354bd5f5f4eSMartin KaFai Lau return err; 355bd5f5f4eSMartin KaFai Lau } 35699c55f7dSAlexei Starovoitov 357a67edbf4SDaniel Borkmann trace_bpf_map_create(map, err); 35899c55f7dSAlexei Starovoitov return err; 35999c55f7dSAlexei Starovoitov 36099c55f7dSAlexei Starovoitov free_map: 36120b2b24fSDaniel Borkmann bpf_map_uncharge_memlock(map); 36220b2b24fSDaniel Borkmann free_map_nouncharge: 36399c55f7dSAlexei Starovoitov map->ops->map_free(map); 36499c55f7dSAlexei Starovoitov return err; 36599c55f7dSAlexei Starovoitov } 36699c55f7dSAlexei Starovoitov 367db20fd2bSAlexei Starovoitov /* if error is returned, fd is released. 368db20fd2bSAlexei Starovoitov * On success caller should complete fd access with matching fdput() 369db20fd2bSAlexei Starovoitov */ 370c2101297SDaniel Borkmann struct bpf_map *__bpf_map_get(struct fd f) 371db20fd2bSAlexei Starovoitov { 372db20fd2bSAlexei Starovoitov if (!f.file) 373db20fd2bSAlexei Starovoitov return ERR_PTR(-EBADF); 374db20fd2bSAlexei Starovoitov if (f.file->f_op != &bpf_map_fops) { 375db20fd2bSAlexei Starovoitov fdput(f); 376db20fd2bSAlexei Starovoitov return ERR_PTR(-EINVAL); 377db20fd2bSAlexei Starovoitov } 378db20fd2bSAlexei Starovoitov 379c2101297SDaniel Borkmann return f.file->private_data; 380c2101297SDaniel Borkmann } 381c2101297SDaniel Borkmann 38292117d84SAlexei Starovoitov /* prog's and map's refcnt limit */ 38392117d84SAlexei Starovoitov #define BPF_MAX_REFCNT 32768 38492117d84SAlexei Starovoitov 38592117d84SAlexei Starovoitov struct bpf_map *bpf_map_inc(struct bpf_map *map, bool uref) 386c9da161cSDaniel Borkmann { 38792117d84SAlexei Starovoitov if (atomic_inc_return(&map->refcnt) > BPF_MAX_REFCNT) { 38892117d84SAlexei Starovoitov atomic_dec(&map->refcnt); 38992117d84SAlexei Starovoitov return ERR_PTR(-EBUSY); 39092117d84SAlexei Starovoitov } 391c9da161cSDaniel Borkmann if (uref) 392c9da161cSDaniel Borkmann atomic_inc(&map->usercnt); 39392117d84SAlexei Starovoitov return map; 394c9da161cSDaniel Borkmann } 395c9da161cSDaniel Borkmann 396c9da161cSDaniel Borkmann struct bpf_map *bpf_map_get_with_uref(u32 ufd) 397c2101297SDaniel Borkmann { 398c2101297SDaniel Borkmann struct fd f = fdget(ufd); 399c2101297SDaniel Borkmann struct bpf_map *map; 400c2101297SDaniel Borkmann 401c2101297SDaniel Borkmann map = __bpf_map_get(f); 402c2101297SDaniel Borkmann if (IS_ERR(map)) 403c2101297SDaniel Borkmann return map; 404c2101297SDaniel Borkmann 40592117d84SAlexei Starovoitov map = bpf_map_inc(map, true); 406c2101297SDaniel Borkmann fdput(f); 407db20fd2bSAlexei Starovoitov 408db20fd2bSAlexei Starovoitov return map; 409db20fd2bSAlexei Starovoitov } 410db20fd2bSAlexei Starovoitov 411bd5f5f4eSMartin KaFai Lau /* map_idr_lock should have been held */ 412bd5f5f4eSMartin KaFai Lau static struct bpf_map *bpf_map_inc_not_zero(struct bpf_map *map, 413bd5f5f4eSMartin KaFai Lau bool uref) 414bd5f5f4eSMartin KaFai Lau { 415bd5f5f4eSMartin KaFai Lau int refold; 416bd5f5f4eSMartin KaFai Lau 417bd5f5f4eSMartin KaFai Lau refold = __atomic_add_unless(&map->refcnt, 1, 0); 418bd5f5f4eSMartin KaFai Lau 419bd5f5f4eSMartin KaFai Lau if (refold >= BPF_MAX_REFCNT) { 420bd5f5f4eSMartin KaFai Lau __bpf_map_put(map, false); 421bd5f5f4eSMartin KaFai Lau return ERR_PTR(-EBUSY); 422bd5f5f4eSMartin KaFai Lau } 423bd5f5f4eSMartin KaFai Lau 424bd5f5f4eSMartin KaFai Lau if (!refold) 425bd5f5f4eSMartin KaFai Lau return ERR_PTR(-ENOENT); 426bd5f5f4eSMartin KaFai Lau 427bd5f5f4eSMartin KaFai Lau if (uref) 428bd5f5f4eSMartin KaFai Lau atomic_inc(&map->usercnt); 429bd5f5f4eSMartin KaFai Lau 430bd5f5f4eSMartin KaFai Lau return map; 431bd5f5f4eSMartin KaFai Lau } 432bd5f5f4eSMartin KaFai Lau 433b8cdc051SAlexei Starovoitov int __weak bpf_stackmap_copy(struct bpf_map *map, void *key, void *value) 434b8cdc051SAlexei Starovoitov { 435b8cdc051SAlexei Starovoitov return -ENOTSUPP; 436b8cdc051SAlexei Starovoitov } 437b8cdc051SAlexei Starovoitov 438db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */ 439db20fd2bSAlexei Starovoitov #define BPF_MAP_LOOKUP_ELEM_LAST_FIELD value 440db20fd2bSAlexei Starovoitov 441db20fd2bSAlexei Starovoitov static int map_lookup_elem(union bpf_attr *attr) 442db20fd2bSAlexei Starovoitov { 443535e7b4bSMickaël Salaün void __user *ukey = u64_to_user_ptr(attr->key); 444535e7b4bSMickaël Salaün void __user *uvalue = u64_to_user_ptr(attr->value); 445db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 446db20fd2bSAlexei Starovoitov struct bpf_map *map; 4478ebe667cSAlexei Starovoitov void *key, *value, *ptr; 44815a07b33SAlexei Starovoitov u32 value_size; 449592867bfSDaniel Borkmann struct fd f; 450db20fd2bSAlexei Starovoitov int err; 451db20fd2bSAlexei Starovoitov 452db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM)) 453db20fd2bSAlexei Starovoitov return -EINVAL; 454db20fd2bSAlexei Starovoitov 455592867bfSDaniel Borkmann f = fdget(ufd); 456c2101297SDaniel Borkmann map = __bpf_map_get(f); 457db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 458db20fd2bSAlexei Starovoitov return PTR_ERR(map); 459db20fd2bSAlexei Starovoitov 460e4448ed8SAl Viro key = memdup_user(ukey, map->key_size); 461e4448ed8SAl Viro if (IS_ERR(key)) { 462e4448ed8SAl Viro err = PTR_ERR(key); 463db20fd2bSAlexei Starovoitov goto err_put; 464e4448ed8SAl Viro } 465db20fd2bSAlexei Starovoitov 46615a07b33SAlexei Starovoitov if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 4678f844938SMartin KaFai Lau map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH || 46815a07b33SAlexei Starovoitov map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) 46915a07b33SAlexei Starovoitov value_size = round_up(map->value_size, 8) * num_possible_cpus(); 47014dc6f04SMartin KaFai Lau else if (IS_FD_MAP(map)) 47114dc6f04SMartin KaFai Lau value_size = sizeof(u32); 47215a07b33SAlexei Starovoitov else 47315a07b33SAlexei Starovoitov value_size = map->value_size; 47415a07b33SAlexei Starovoitov 4758ebe667cSAlexei Starovoitov err = -ENOMEM; 47615a07b33SAlexei Starovoitov value = kmalloc(value_size, GFP_USER | __GFP_NOWARN); 477db20fd2bSAlexei Starovoitov if (!value) 4788ebe667cSAlexei Starovoitov goto free_key; 4798ebe667cSAlexei Starovoitov 4808f844938SMartin KaFai Lau if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 4818f844938SMartin KaFai Lau map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) { 48215a07b33SAlexei Starovoitov err = bpf_percpu_hash_copy(map, key, value); 48315a07b33SAlexei Starovoitov } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) { 48415a07b33SAlexei Starovoitov err = bpf_percpu_array_copy(map, key, value); 485557c0c6eSAlexei Starovoitov } else if (map->map_type == BPF_MAP_TYPE_STACK_TRACE) { 486557c0c6eSAlexei Starovoitov err = bpf_stackmap_copy(map, key, value); 48714dc6f04SMartin KaFai Lau } else if (IS_FD_ARRAY(map)) { 48814dc6f04SMartin KaFai Lau err = bpf_fd_array_map_lookup_elem(map, key, value); 48914dc6f04SMartin KaFai Lau } else if (IS_FD_HASH(map)) { 49014dc6f04SMartin KaFai Lau err = bpf_fd_htab_map_lookup_elem(map, key, value); 49115a07b33SAlexei Starovoitov } else { 4928ebe667cSAlexei Starovoitov rcu_read_lock(); 4938ebe667cSAlexei Starovoitov ptr = map->ops->map_lookup_elem(map, key); 4948ebe667cSAlexei Starovoitov if (ptr) 49515a07b33SAlexei Starovoitov memcpy(value, ptr, value_size); 4968ebe667cSAlexei Starovoitov rcu_read_unlock(); 49715a07b33SAlexei Starovoitov err = ptr ? 0 : -ENOENT; 49815a07b33SAlexei Starovoitov } 4998ebe667cSAlexei Starovoitov 50015a07b33SAlexei Starovoitov if (err) 5018ebe667cSAlexei Starovoitov goto free_value; 502db20fd2bSAlexei Starovoitov 503db20fd2bSAlexei Starovoitov err = -EFAULT; 50415a07b33SAlexei Starovoitov if (copy_to_user(uvalue, value, value_size) != 0) 5058ebe667cSAlexei Starovoitov goto free_value; 506db20fd2bSAlexei Starovoitov 507a67edbf4SDaniel Borkmann trace_bpf_map_lookup_elem(map, ufd, key, value); 508db20fd2bSAlexei Starovoitov err = 0; 509db20fd2bSAlexei Starovoitov 5108ebe667cSAlexei Starovoitov free_value: 5118ebe667cSAlexei Starovoitov kfree(value); 512db20fd2bSAlexei Starovoitov free_key: 513db20fd2bSAlexei Starovoitov kfree(key); 514db20fd2bSAlexei Starovoitov err_put: 515db20fd2bSAlexei Starovoitov fdput(f); 516db20fd2bSAlexei Starovoitov return err; 517db20fd2bSAlexei Starovoitov } 518db20fd2bSAlexei Starovoitov 5193274f520SAlexei Starovoitov #define BPF_MAP_UPDATE_ELEM_LAST_FIELD flags 520db20fd2bSAlexei Starovoitov 521db20fd2bSAlexei Starovoitov static int map_update_elem(union bpf_attr *attr) 522db20fd2bSAlexei Starovoitov { 523535e7b4bSMickaël Salaün void __user *ukey = u64_to_user_ptr(attr->key); 524535e7b4bSMickaël Salaün void __user *uvalue = u64_to_user_ptr(attr->value); 525db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 526db20fd2bSAlexei Starovoitov struct bpf_map *map; 527db20fd2bSAlexei Starovoitov void *key, *value; 52815a07b33SAlexei Starovoitov u32 value_size; 529592867bfSDaniel Borkmann struct fd f; 530db20fd2bSAlexei Starovoitov int err; 531db20fd2bSAlexei Starovoitov 532db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_UPDATE_ELEM)) 533db20fd2bSAlexei Starovoitov return -EINVAL; 534db20fd2bSAlexei Starovoitov 535592867bfSDaniel Borkmann f = fdget(ufd); 536c2101297SDaniel Borkmann map = __bpf_map_get(f); 537db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 538db20fd2bSAlexei Starovoitov return PTR_ERR(map); 539db20fd2bSAlexei Starovoitov 540e4448ed8SAl Viro key = memdup_user(ukey, map->key_size); 541e4448ed8SAl Viro if (IS_ERR(key)) { 542e4448ed8SAl Viro err = PTR_ERR(key); 543db20fd2bSAlexei Starovoitov goto err_put; 544e4448ed8SAl Viro } 545db20fd2bSAlexei Starovoitov 54615a07b33SAlexei Starovoitov if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 5478f844938SMartin KaFai Lau map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH || 54815a07b33SAlexei Starovoitov map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) 54915a07b33SAlexei Starovoitov value_size = round_up(map->value_size, 8) * num_possible_cpus(); 55015a07b33SAlexei Starovoitov else 55115a07b33SAlexei Starovoitov value_size = map->value_size; 55215a07b33SAlexei Starovoitov 553db20fd2bSAlexei Starovoitov err = -ENOMEM; 55415a07b33SAlexei Starovoitov value = kmalloc(value_size, GFP_USER | __GFP_NOWARN); 555db20fd2bSAlexei Starovoitov if (!value) 556db20fd2bSAlexei Starovoitov goto free_key; 557db20fd2bSAlexei Starovoitov 558db20fd2bSAlexei Starovoitov err = -EFAULT; 55915a07b33SAlexei Starovoitov if (copy_from_user(value, uvalue, value_size) != 0) 560db20fd2bSAlexei Starovoitov goto free_value; 561db20fd2bSAlexei Starovoitov 562b121d1e7SAlexei Starovoitov /* must increment bpf_prog_active to avoid kprobe+bpf triggering from 563b121d1e7SAlexei Starovoitov * inside bpf map update or delete otherwise deadlocks are possible 564b121d1e7SAlexei Starovoitov */ 565b121d1e7SAlexei Starovoitov preempt_disable(); 566b121d1e7SAlexei Starovoitov __this_cpu_inc(bpf_prog_active); 5678f844938SMartin KaFai Lau if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 5688f844938SMartin KaFai Lau map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) { 56915a07b33SAlexei Starovoitov err = bpf_percpu_hash_update(map, key, value, attr->flags); 57015a07b33SAlexei Starovoitov } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) { 57115a07b33SAlexei Starovoitov err = bpf_percpu_array_update(map, key, value, attr->flags); 572d056a788SDaniel Borkmann } else if (map->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || 5734ed8ec52SMartin KaFai Lau map->map_type == BPF_MAP_TYPE_PROG_ARRAY || 57456f668dfSMartin KaFai Lau map->map_type == BPF_MAP_TYPE_CGROUP_ARRAY || 57556f668dfSMartin KaFai Lau map->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS) { 576d056a788SDaniel Borkmann rcu_read_lock(); 577d056a788SDaniel Borkmann err = bpf_fd_array_map_update_elem(map, f.file, key, value, 578d056a788SDaniel Borkmann attr->flags); 579d056a788SDaniel Borkmann rcu_read_unlock(); 580bcc6b1b7SMartin KaFai Lau } else if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) { 581bcc6b1b7SMartin KaFai Lau rcu_read_lock(); 582bcc6b1b7SMartin KaFai Lau err = bpf_fd_htab_map_update_elem(map, f.file, key, value, 583bcc6b1b7SMartin KaFai Lau attr->flags); 584bcc6b1b7SMartin KaFai Lau rcu_read_unlock(); 58515a07b33SAlexei Starovoitov } else { 586db20fd2bSAlexei Starovoitov rcu_read_lock(); 5873274f520SAlexei Starovoitov err = map->ops->map_update_elem(map, key, value, attr->flags); 588db20fd2bSAlexei Starovoitov rcu_read_unlock(); 58915a07b33SAlexei Starovoitov } 590b121d1e7SAlexei Starovoitov __this_cpu_dec(bpf_prog_active); 591b121d1e7SAlexei Starovoitov preempt_enable(); 592db20fd2bSAlexei Starovoitov 593a67edbf4SDaniel Borkmann if (!err) 594a67edbf4SDaniel Borkmann trace_bpf_map_update_elem(map, ufd, key, value); 595db20fd2bSAlexei Starovoitov free_value: 596db20fd2bSAlexei Starovoitov kfree(value); 597db20fd2bSAlexei Starovoitov free_key: 598db20fd2bSAlexei Starovoitov kfree(key); 599db20fd2bSAlexei Starovoitov err_put: 600db20fd2bSAlexei Starovoitov fdput(f); 601db20fd2bSAlexei Starovoitov return err; 602db20fd2bSAlexei Starovoitov } 603db20fd2bSAlexei Starovoitov 604db20fd2bSAlexei Starovoitov #define BPF_MAP_DELETE_ELEM_LAST_FIELD key 605db20fd2bSAlexei Starovoitov 606db20fd2bSAlexei Starovoitov static int map_delete_elem(union bpf_attr *attr) 607db20fd2bSAlexei Starovoitov { 608535e7b4bSMickaël Salaün void __user *ukey = u64_to_user_ptr(attr->key); 609db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 610db20fd2bSAlexei Starovoitov struct bpf_map *map; 611592867bfSDaniel Borkmann struct fd f; 612db20fd2bSAlexei Starovoitov void *key; 613db20fd2bSAlexei Starovoitov int err; 614db20fd2bSAlexei Starovoitov 615db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_DELETE_ELEM)) 616db20fd2bSAlexei Starovoitov return -EINVAL; 617db20fd2bSAlexei Starovoitov 618592867bfSDaniel Borkmann f = fdget(ufd); 619c2101297SDaniel Borkmann map = __bpf_map_get(f); 620db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 621db20fd2bSAlexei Starovoitov return PTR_ERR(map); 622db20fd2bSAlexei Starovoitov 623e4448ed8SAl Viro key = memdup_user(ukey, map->key_size); 624e4448ed8SAl Viro if (IS_ERR(key)) { 625e4448ed8SAl Viro err = PTR_ERR(key); 626db20fd2bSAlexei Starovoitov goto err_put; 627e4448ed8SAl Viro } 628db20fd2bSAlexei Starovoitov 629b121d1e7SAlexei Starovoitov preempt_disable(); 630b121d1e7SAlexei Starovoitov __this_cpu_inc(bpf_prog_active); 631db20fd2bSAlexei Starovoitov rcu_read_lock(); 632db20fd2bSAlexei Starovoitov err = map->ops->map_delete_elem(map, key); 633db20fd2bSAlexei Starovoitov rcu_read_unlock(); 634b121d1e7SAlexei Starovoitov __this_cpu_dec(bpf_prog_active); 635b121d1e7SAlexei Starovoitov preempt_enable(); 636db20fd2bSAlexei Starovoitov 637a67edbf4SDaniel Borkmann if (!err) 638a67edbf4SDaniel Borkmann trace_bpf_map_delete_elem(map, ufd, key); 639db20fd2bSAlexei Starovoitov kfree(key); 640db20fd2bSAlexei Starovoitov err_put: 641db20fd2bSAlexei Starovoitov fdput(f); 642db20fd2bSAlexei Starovoitov return err; 643db20fd2bSAlexei Starovoitov } 644db20fd2bSAlexei Starovoitov 645db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */ 646db20fd2bSAlexei Starovoitov #define BPF_MAP_GET_NEXT_KEY_LAST_FIELD next_key 647db20fd2bSAlexei Starovoitov 648db20fd2bSAlexei Starovoitov static int map_get_next_key(union bpf_attr *attr) 649db20fd2bSAlexei Starovoitov { 650535e7b4bSMickaël Salaün void __user *ukey = u64_to_user_ptr(attr->key); 651535e7b4bSMickaël Salaün void __user *unext_key = u64_to_user_ptr(attr->next_key); 652db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 653db20fd2bSAlexei Starovoitov struct bpf_map *map; 654db20fd2bSAlexei Starovoitov void *key, *next_key; 655592867bfSDaniel Borkmann struct fd f; 656db20fd2bSAlexei Starovoitov int err; 657db20fd2bSAlexei Starovoitov 658db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_GET_NEXT_KEY)) 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 6668fe45924STeng Qin if (ukey) { 667e4448ed8SAl Viro key = memdup_user(ukey, map->key_size); 668e4448ed8SAl Viro if (IS_ERR(key)) { 669e4448ed8SAl Viro err = PTR_ERR(key); 670db20fd2bSAlexei Starovoitov goto err_put; 671e4448ed8SAl Viro } 6728fe45924STeng Qin } else { 6738fe45924STeng Qin key = NULL; 6748fe45924STeng Qin } 675db20fd2bSAlexei Starovoitov 676db20fd2bSAlexei Starovoitov err = -ENOMEM; 677db20fd2bSAlexei Starovoitov next_key = kmalloc(map->key_size, GFP_USER); 678db20fd2bSAlexei Starovoitov if (!next_key) 679db20fd2bSAlexei Starovoitov goto free_key; 680db20fd2bSAlexei Starovoitov 681db20fd2bSAlexei Starovoitov rcu_read_lock(); 682db20fd2bSAlexei Starovoitov err = map->ops->map_get_next_key(map, key, next_key); 683db20fd2bSAlexei Starovoitov rcu_read_unlock(); 684db20fd2bSAlexei Starovoitov if (err) 685db20fd2bSAlexei Starovoitov goto free_next_key; 686db20fd2bSAlexei Starovoitov 687db20fd2bSAlexei Starovoitov err = -EFAULT; 688db20fd2bSAlexei Starovoitov if (copy_to_user(unext_key, next_key, map->key_size) != 0) 689db20fd2bSAlexei Starovoitov goto free_next_key; 690db20fd2bSAlexei Starovoitov 691a67edbf4SDaniel Borkmann trace_bpf_map_next_key(map, ufd, key, next_key); 692db20fd2bSAlexei Starovoitov err = 0; 693db20fd2bSAlexei Starovoitov 694db20fd2bSAlexei Starovoitov free_next_key: 695db20fd2bSAlexei Starovoitov kfree(next_key); 696db20fd2bSAlexei Starovoitov free_key: 697db20fd2bSAlexei Starovoitov kfree(key); 698db20fd2bSAlexei Starovoitov err_put: 699db20fd2bSAlexei Starovoitov fdput(f); 700db20fd2bSAlexei Starovoitov return err; 701db20fd2bSAlexei Starovoitov } 702db20fd2bSAlexei Starovoitov 703be9370a7SJohannes Berg static const struct bpf_verifier_ops * const bpf_prog_types[] = { 704be9370a7SJohannes Berg #define BPF_PROG_TYPE(_id, _ops) \ 705be9370a7SJohannes Berg [_id] = &_ops, 70640077e0cSJohannes Berg #define BPF_MAP_TYPE(_id, _ops) 707be9370a7SJohannes Berg #include <linux/bpf_types.h> 708be9370a7SJohannes Berg #undef BPF_PROG_TYPE 70940077e0cSJohannes Berg #undef BPF_MAP_TYPE 710be9370a7SJohannes Berg }; 71109756af4SAlexei Starovoitov 71209756af4SAlexei Starovoitov static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog) 71309756af4SAlexei Starovoitov { 714be9370a7SJohannes Berg if (type >= ARRAY_SIZE(bpf_prog_types) || !bpf_prog_types[type]) 715be9370a7SJohannes Berg return -EINVAL; 71609756af4SAlexei Starovoitov 717be9370a7SJohannes Berg prog->aux->ops = bpf_prog_types[type]; 71824701eceSDaniel Borkmann prog->type = type; 71909756af4SAlexei Starovoitov return 0; 72009756af4SAlexei Starovoitov } 72109756af4SAlexei Starovoitov 72209756af4SAlexei Starovoitov /* drop refcnt on maps used by eBPF program and free auxilary data */ 72309756af4SAlexei Starovoitov static void free_used_maps(struct bpf_prog_aux *aux) 72409756af4SAlexei Starovoitov { 72509756af4SAlexei Starovoitov int i; 72609756af4SAlexei Starovoitov 72709756af4SAlexei Starovoitov for (i = 0; i < aux->used_map_cnt; i++) 72809756af4SAlexei Starovoitov bpf_map_put(aux->used_maps[i]); 72909756af4SAlexei Starovoitov 73009756af4SAlexei Starovoitov kfree(aux->used_maps); 73109756af4SAlexei Starovoitov } 73209756af4SAlexei Starovoitov 7335ccb071eSDaniel Borkmann int __bpf_prog_charge(struct user_struct *user, u32 pages) 7345ccb071eSDaniel Borkmann { 7355ccb071eSDaniel Borkmann unsigned long memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; 7365ccb071eSDaniel Borkmann unsigned long user_bufs; 7375ccb071eSDaniel Borkmann 7385ccb071eSDaniel Borkmann if (user) { 7395ccb071eSDaniel Borkmann user_bufs = atomic_long_add_return(pages, &user->locked_vm); 7405ccb071eSDaniel Borkmann if (user_bufs > memlock_limit) { 7415ccb071eSDaniel Borkmann atomic_long_sub(pages, &user->locked_vm); 7425ccb071eSDaniel Borkmann return -EPERM; 7435ccb071eSDaniel Borkmann } 7445ccb071eSDaniel Borkmann } 7455ccb071eSDaniel Borkmann 7465ccb071eSDaniel Borkmann return 0; 7475ccb071eSDaniel Borkmann } 7485ccb071eSDaniel Borkmann 7495ccb071eSDaniel Borkmann void __bpf_prog_uncharge(struct user_struct *user, u32 pages) 7505ccb071eSDaniel Borkmann { 7515ccb071eSDaniel Borkmann if (user) 7525ccb071eSDaniel Borkmann atomic_long_sub(pages, &user->locked_vm); 7535ccb071eSDaniel Borkmann } 7545ccb071eSDaniel Borkmann 755aaac3ba9SAlexei Starovoitov static int bpf_prog_charge_memlock(struct bpf_prog *prog) 756aaac3ba9SAlexei Starovoitov { 757aaac3ba9SAlexei Starovoitov struct user_struct *user = get_current_user(); 7585ccb071eSDaniel Borkmann int ret; 759aaac3ba9SAlexei Starovoitov 7605ccb071eSDaniel Borkmann ret = __bpf_prog_charge(user, prog->pages); 7615ccb071eSDaniel Borkmann if (ret) { 762aaac3ba9SAlexei Starovoitov free_uid(user); 7635ccb071eSDaniel Borkmann return ret; 764aaac3ba9SAlexei Starovoitov } 7655ccb071eSDaniel Borkmann 766aaac3ba9SAlexei Starovoitov prog->aux->user = user; 767aaac3ba9SAlexei Starovoitov return 0; 768aaac3ba9SAlexei Starovoitov } 769aaac3ba9SAlexei Starovoitov 770aaac3ba9SAlexei Starovoitov static void bpf_prog_uncharge_memlock(struct bpf_prog *prog) 771aaac3ba9SAlexei Starovoitov { 772aaac3ba9SAlexei Starovoitov struct user_struct *user = prog->aux->user; 773aaac3ba9SAlexei Starovoitov 7745ccb071eSDaniel Borkmann __bpf_prog_uncharge(user, prog->pages); 775aaac3ba9SAlexei Starovoitov free_uid(user); 776aaac3ba9SAlexei Starovoitov } 777aaac3ba9SAlexei Starovoitov 778dc4bb0e2SMartin KaFai Lau static int bpf_prog_alloc_id(struct bpf_prog *prog) 779dc4bb0e2SMartin KaFai Lau { 780dc4bb0e2SMartin KaFai Lau int id; 781dc4bb0e2SMartin KaFai Lau 782dc4bb0e2SMartin KaFai Lau spin_lock_bh(&prog_idr_lock); 783dc4bb0e2SMartin KaFai Lau id = idr_alloc_cyclic(&prog_idr, prog, 1, INT_MAX, GFP_ATOMIC); 784dc4bb0e2SMartin KaFai Lau if (id > 0) 785dc4bb0e2SMartin KaFai Lau prog->aux->id = id; 786dc4bb0e2SMartin KaFai Lau spin_unlock_bh(&prog_idr_lock); 787dc4bb0e2SMartin KaFai Lau 788dc4bb0e2SMartin KaFai Lau /* id is in [1, INT_MAX) */ 789dc4bb0e2SMartin KaFai Lau if (WARN_ON_ONCE(!id)) 790dc4bb0e2SMartin KaFai Lau return -ENOSPC; 791dc4bb0e2SMartin KaFai Lau 792dc4bb0e2SMartin KaFai Lau return id > 0 ? 0 : id; 793dc4bb0e2SMartin KaFai Lau } 794dc4bb0e2SMartin KaFai Lau 795b16d9aa4SMartin KaFai Lau static void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock) 796dc4bb0e2SMartin KaFai Lau { 797dc4bb0e2SMartin KaFai Lau /* cBPF to eBPF migrations are currently not in the idr store. */ 798dc4bb0e2SMartin KaFai Lau if (!prog->aux->id) 799dc4bb0e2SMartin KaFai Lau return; 800dc4bb0e2SMartin KaFai Lau 801b16d9aa4SMartin KaFai Lau if (do_idr_lock) 802dc4bb0e2SMartin KaFai Lau spin_lock_bh(&prog_idr_lock); 803b16d9aa4SMartin KaFai Lau else 804b16d9aa4SMartin KaFai Lau __acquire(&prog_idr_lock); 805b16d9aa4SMartin KaFai Lau 806dc4bb0e2SMartin KaFai Lau idr_remove(&prog_idr, prog->aux->id); 807b16d9aa4SMartin KaFai Lau 808b16d9aa4SMartin KaFai Lau if (do_idr_lock) 809dc4bb0e2SMartin KaFai Lau spin_unlock_bh(&prog_idr_lock); 810b16d9aa4SMartin KaFai Lau else 811b16d9aa4SMartin KaFai Lau __release(&prog_idr_lock); 812dc4bb0e2SMartin KaFai Lau } 813dc4bb0e2SMartin KaFai Lau 8141aacde3dSDaniel Borkmann static void __bpf_prog_put_rcu(struct rcu_head *rcu) 815abf2e7d6SAlexei Starovoitov { 816abf2e7d6SAlexei Starovoitov struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu); 817abf2e7d6SAlexei Starovoitov 818abf2e7d6SAlexei Starovoitov free_used_maps(aux); 819aaac3ba9SAlexei Starovoitov bpf_prog_uncharge_memlock(aux->prog); 820abf2e7d6SAlexei Starovoitov bpf_prog_free(aux->prog); 821abf2e7d6SAlexei Starovoitov } 822abf2e7d6SAlexei Starovoitov 823b16d9aa4SMartin KaFai Lau static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock) 82409756af4SAlexei Starovoitov { 825a67edbf4SDaniel Borkmann if (atomic_dec_and_test(&prog->aux->refcnt)) { 826a67edbf4SDaniel Borkmann trace_bpf_prog_put_rcu(prog); 82734ad5580SMartin KaFai Lau /* bpf_prog_free_id() must be called first */ 828b16d9aa4SMartin KaFai Lau bpf_prog_free_id(prog, do_idr_lock); 82974451e66SDaniel Borkmann bpf_prog_kallsyms_del(prog); 8301aacde3dSDaniel Borkmann call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu); 83109756af4SAlexei Starovoitov } 832a67edbf4SDaniel Borkmann } 833b16d9aa4SMartin KaFai Lau 834b16d9aa4SMartin KaFai Lau void bpf_prog_put(struct bpf_prog *prog) 835b16d9aa4SMartin KaFai Lau { 836b16d9aa4SMartin KaFai Lau __bpf_prog_put(prog, true); 837b16d9aa4SMartin KaFai Lau } 838e2e9b654SDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_put); 83909756af4SAlexei Starovoitov 84009756af4SAlexei Starovoitov static int bpf_prog_release(struct inode *inode, struct file *filp) 84109756af4SAlexei Starovoitov { 84209756af4SAlexei Starovoitov struct bpf_prog *prog = filp->private_data; 84309756af4SAlexei Starovoitov 8441aacde3dSDaniel Borkmann bpf_prog_put(prog); 84509756af4SAlexei Starovoitov return 0; 84609756af4SAlexei Starovoitov } 84709756af4SAlexei Starovoitov 8487bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS 8497bd509e3SDaniel Borkmann static void bpf_prog_show_fdinfo(struct seq_file *m, struct file *filp) 8507bd509e3SDaniel Borkmann { 8517bd509e3SDaniel Borkmann const struct bpf_prog *prog = filp->private_data; 852f1f7714eSDaniel Borkmann char prog_tag[sizeof(prog->tag) * 2 + 1] = { }; 8537bd509e3SDaniel Borkmann 854f1f7714eSDaniel Borkmann bin2hex(prog_tag, prog->tag, sizeof(prog->tag)); 8557bd509e3SDaniel Borkmann seq_printf(m, 8567bd509e3SDaniel Borkmann "prog_type:\t%u\n" 8577bd509e3SDaniel Borkmann "prog_jited:\t%u\n" 858f1f7714eSDaniel Borkmann "prog_tag:\t%s\n" 8597bd509e3SDaniel Borkmann "memlock:\t%llu\n", 8607bd509e3SDaniel Borkmann prog->type, 8617bd509e3SDaniel Borkmann prog->jited, 862f1f7714eSDaniel Borkmann prog_tag, 8637bd509e3SDaniel Borkmann prog->pages * 1ULL << PAGE_SHIFT); 8647bd509e3SDaniel Borkmann } 8657bd509e3SDaniel Borkmann #endif 8667bd509e3SDaniel Borkmann 86709756af4SAlexei Starovoitov static const struct file_operations bpf_prog_fops = { 8687bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS 8697bd509e3SDaniel Borkmann .show_fdinfo = bpf_prog_show_fdinfo, 8707bd509e3SDaniel Borkmann #endif 87109756af4SAlexei Starovoitov .release = bpf_prog_release, 87209756af4SAlexei Starovoitov }; 87309756af4SAlexei Starovoitov 874b2197755SDaniel Borkmann int bpf_prog_new_fd(struct bpf_prog *prog) 875aa79781bSDaniel Borkmann { 876aa79781bSDaniel Borkmann return anon_inode_getfd("bpf-prog", &bpf_prog_fops, prog, 877aa79781bSDaniel Borkmann O_RDWR | O_CLOEXEC); 878aa79781bSDaniel Borkmann } 879aa79781bSDaniel Borkmann 880113214beSDaniel Borkmann static struct bpf_prog *____bpf_prog_get(struct fd f) 88109756af4SAlexei Starovoitov { 88209756af4SAlexei Starovoitov if (!f.file) 88309756af4SAlexei Starovoitov return ERR_PTR(-EBADF); 88409756af4SAlexei Starovoitov if (f.file->f_op != &bpf_prog_fops) { 88509756af4SAlexei Starovoitov fdput(f); 88609756af4SAlexei Starovoitov return ERR_PTR(-EINVAL); 88709756af4SAlexei Starovoitov } 88809756af4SAlexei Starovoitov 889c2101297SDaniel Borkmann return f.file->private_data; 89009756af4SAlexei Starovoitov } 89109756af4SAlexei Starovoitov 89259d3656dSBrenden Blanco struct bpf_prog *bpf_prog_add(struct bpf_prog *prog, int i) 89392117d84SAlexei Starovoitov { 89459d3656dSBrenden Blanco if (atomic_add_return(i, &prog->aux->refcnt) > BPF_MAX_REFCNT) { 89559d3656dSBrenden Blanco atomic_sub(i, &prog->aux->refcnt); 89692117d84SAlexei Starovoitov return ERR_PTR(-EBUSY); 89792117d84SAlexei Starovoitov } 89892117d84SAlexei Starovoitov return prog; 89992117d84SAlexei Starovoitov } 90059d3656dSBrenden Blanco EXPORT_SYMBOL_GPL(bpf_prog_add); 90159d3656dSBrenden Blanco 902c540594fSDaniel Borkmann void bpf_prog_sub(struct bpf_prog *prog, int i) 903c540594fSDaniel Borkmann { 904c540594fSDaniel Borkmann /* Only to be used for undoing previous bpf_prog_add() in some 905c540594fSDaniel Borkmann * error path. We still know that another entity in our call 906c540594fSDaniel Borkmann * path holds a reference to the program, thus atomic_sub() can 907c540594fSDaniel Borkmann * be safely used in such cases! 908c540594fSDaniel Borkmann */ 909c540594fSDaniel Borkmann WARN_ON(atomic_sub_return(i, &prog->aux->refcnt) == 0); 910c540594fSDaniel Borkmann } 911c540594fSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_sub); 912c540594fSDaniel Borkmann 91359d3656dSBrenden Blanco struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog) 91459d3656dSBrenden Blanco { 91559d3656dSBrenden Blanco return bpf_prog_add(prog, 1); 91659d3656dSBrenden Blanco } 91797bc402dSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_inc); 91892117d84SAlexei Starovoitov 919b16d9aa4SMartin KaFai Lau /* prog_idr_lock should have been held */ 920a6f6df69SJohn Fastabend struct bpf_prog *bpf_prog_inc_not_zero(struct bpf_prog *prog) 921b16d9aa4SMartin KaFai Lau { 922b16d9aa4SMartin KaFai Lau int refold; 923b16d9aa4SMartin KaFai Lau 924b16d9aa4SMartin KaFai Lau refold = __atomic_add_unless(&prog->aux->refcnt, 1, 0); 925b16d9aa4SMartin KaFai Lau 926b16d9aa4SMartin KaFai Lau if (refold >= BPF_MAX_REFCNT) { 927b16d9aa4SMartin KaFai Lau __bpf_prog_put(prog, false); 928b16d9aa4SMartin KaFai Lau return ERR_PTR(-EBUSY); 929b16d9aa4SMartin KaFai Lau } 930b16d9aa4SMartin KaFai Lau 931b16d9aa4SMartin KaFai Lau if (!refold) 932b16d9aa4SMartin KaFai Lau return ERR_PTR(-ENOENT); 933b16d9aa4SMartin KaFai Lau 934b16d9aa4SMartin KaFai Lau return prog; 935b16d9aa4SMartin KaFai Lau } 936a6f6df69SJohn Fastabend EXPORT_SYMBOL_GPL(bpf_prog_inc_not_zero); 937b16d9aa4SMartin KaFai Lau 938113214beSDaniel Borkmann static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *type) 93909756af4SAlexei Starovoitov { 94009756af4SAlexei Starovoitov struct fd f = fdget(ufd); 94109756af4SAlexei Starovoitov struct bpf_prog *prog; 94209756af4SAlexei Starovoitov 943113214beSDaniel Borkmann prog = ____bpf_prog_get(f); 94409756af4SAlexei Starovoitov if (IS_ERR(prog)) 94509756af4SAlexei Starovoitov return prog; 946113214beSDaniel Borkmann if (type && prog->type != *type) { 947113214beSDaniel Borkmann prog = ERR_PTR(-EINVAL); 948113214beSDaniel Borkmann goto out; 949113214beSDaniel Borkmann } 95009756af4SAlexei Starovoitov 95192117d84SAlexei Starovoitov prog = bpf_prog_inc(prog); 952113214beSDaniel Borkmann out: 95309756af4SAlexei Starovoitov fdput(f); 95409756af4SAlexei Starovoitov return prog; 95509756af4SAlexei Starovoitov } 956113214beSDaniel Borkmann 957113214beSDaniel Borkmann struct bpf_prog *bpf_prog_get(u32 ufd) 958113214beSDaniel Borkmann { 959113214beSDaniel Borkmann return __bpf_prog_get(ufd, NULL); 960113214beSDaniel Borkmann } 961113214beSDaniel Borkmann 962113214beSDaniel Borkmann struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type) 963113214beSDaniel Borkmann { 964a67edbf4SDaniel Borkmann struct bpf_prog *prog = __bpf_prog_get(ufd, &type); 965a67edbf4SDaniel Borkmann 966a67edbf4SDaniel Borkmann if (!IS_ERR(prog)) 967a67edbf4SDaniel Borkmann trace_bpf_prog_get_type(prog); 968a67edbf4SDaniel Borkmann return prog; 969113214beSDaniel Borkmann } 970113214beSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_get_type); 97109756af4SAlexei Starovoitov 97209756af4SAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */ 973e07b98d9SDavid S. Miller #define BPF_PROG_LOAD_LAST_FIELD prog_flags 97409756af4SAlexei Starovoitov 97509756af4SAlexei Starovoitov static int bpf_prog_load(union bpf_attr *attr) 97609756af4SAlexei Starovoitov { 97709756af4SAlexei Starovoitov enum bpf_prog_type type = attr->prog_type; 97809756af4SAlexei Starovoitov struct bpf_prog *prog; 97909756af4SAlexei Starovoitov int err; 98009756af4SAlexei Starovoitov char license[128]; 98109756af4SAlexei Starovoitov bool is_gpl; 98209756af4SAlexei Starovoitov 98309756af4SAlexei Starovoitov if (CHECK_ATTR(BPF_PROG_LOAD)) 98409756af4SAlexei Starovoitov return -EINVAL; 98509756af4SAlexei Starovoitov 986e07b98d9SDavid S. Miller if (attr->prog_flags & ~BPF_F_STRICT_ALIGNMENT) 987e07b98d9SDavid S. Miller return -EINVAL; 988e07b98d9SDavid S. Miller 98909756af4SAlexei Starovoitov /* copy eBPF program license from user space */ 990535e7b4bSMickaël Salaün if (strncpy_from_user(license, u64_to_user_ptr(attr->license), 99109756af4SAlexei Starovoitov sizeof(license) - 1) < 0) 99209756af4SAlexei Starovoitov return -EFAULT; 99309756af4SAlexei Starovoitov license[sizeof(license) - 1] = 0; 99409756af4SAlexei Starovoitov 99509756af4SAlexei Starovoitov /* eBPF programs must be GPL compatible to use GPL-ed functions */ 99609756af4SAlexei Starovoitov is_gpl = license_is_gpl_compatible(license); 99709756af4SAlexei Starovoitov 998ef0915caSDaniel Borkmann if (attr->insn_cnt == 0 || attr->insn_cnt > BPF_MAXINSNS) 999ef0915caSDaniel Borkmann return -E2BIG; 100009756af4SAlexei Starovoitov 10012541517cSAlexei Starovoitov if (type == BPF_PROG_TYPE_KPROBE && 10022541517cSAlexei Starovoitov attr->kern_version != LINUX_VERSION_CODE) 10032541517cSAlexei Starovoitov return -EINVAL; 10042541517cSAlexei Starovoitov 100580b7d819SChenbo Feng if (type != BPF_PROG_TYPE_SOCKET_FILTER && 100680b7d819SChenbo Feng type != BPF_PROG_TYPE_CGROUP_SKB && 100780b7d819SChenbo Feng !capable(CAP_SYS_ADMIN)) 10081be7f75dSAlexei Starovoitov return -EPERM; 10091be7f75dSAlexei Starovoitov 101009756af4SAlexei Starovoitov /* plain bpf_prog allocation */ 101109756af4SAlexei Starovoitov prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER); 101209756af4SAlexei Starovoitov if (!prog) 101309756af4SAlexei Starovoitov return -ENOMEM; 101409756af4SAlexei Starovoitov 1015aaac3ba9SAlexei Starovoitov err = bpf_prog_charge_memlock(prog); 1016aaac3ba9SAlexei Starovoitov if (err) 1017aaac3ba9SAlexei Starovoitov goto free_prog_nouncharge; 1018aaac3ba9SAlexei Starovoitov 101909756af4SAlexei Starovoitov prog->len = attr->insn_cnt; 102009756af4SAlexei Starovoitov 102109756af4SAlexei Starovoitov err = -EFAULT; 1022535e7b4bSMickaël Salaün if (copy_from_user(prog->insns, u64_to_user_ptr(attr->insns), 1023aafe6ae9SDaniel Borkmann bpf_prog_insn_size(prog)) != 0) 102409756af4SAlexei Starovoitov goto free_prog; 102509756af4SAlexei Starovoitov 102609756af4SAlexei Starovoitov prog->orig_prog = NULL; 1027a91263d5SDaniel Borkmann prog->jited = 0; 102809756af4SAlexei Starovoitov 102909756af4SAlexei Starovoitov atomic_set(&prog->aux->refcnt, 1); 1030a91263d5SDaniel Borkmann prog->gpl_compatible = is_gpl ? 1 : 0; 103109756af4SAlexei Starovoitov 103209756af4SAlexei Starovoitov /* find program type: socket_filter vs tracing_filter */ 103309756af4SAlexei Starovoitov err = find_prog_type(type, prog); 103409756af4SAlexei Starovoitov if (err < 0) 103509756af4SAlexei Starovoitov goto free_prog; 103609756af4SAlexei Starovoitov 103709756af4SAlexei Starovoitov /* run eBPF verifier */ 10389bac3d6dSAlexei Starovoitov err = bpf_check(&prog, attr); 103909756af4SAlexei Starovoitov if (err < 0) 104009756af4SAlexei Starovoitov goto free_used_maps; 104109756af4SAlexei Starovoitov 104209756af4SAlexei Starovoitov /* eBPF program is ready to be JITed */ 1043d1c55ab5SDaniel Borkmann prog = bpf_prog_select_runtime(prog, &err); 104404fd61abSAlexei Starovoitov if (err < 0) 104504fd61abSAlexei Starovoitov goto free_used_maps; 104609756af4SAlexei Starovoitov 1047dc4bb0e2SMartin KaFai Lau err = bpf_prog_alloc_id(prog); 1048dc4bb0e2SMartin KaFai Lau if (err) 1049dc4bb0e2SMartin KaFai Lau goto free_used_maps; 1050dc4bb0e2SMartin KaFai Lau 1051aa79781bSDaniel Borkmann err = bpf_prog_new_fd(prog); 1052b16d9aa4SMartin KaFai Lau if (err < 0) { 1053b16d9aa4SMartin KaFai Lau /* failed to allocate fd. 1054b16d9aa4SMartin KaFai Lau * bpf_prog_put() is needed because the above 1055b16d9aa4SMartin KaFai Lau * bpf_prog_alloc_id() has published the prog 1056b16d9aa4SMartin KaFai Lau * to the userspace and the userspace may 1057b16d9aa4SMartin KaFai Lau * have refcnt-ed it through BPF_PROG_GET_FD_BY_ID. 1058b16d9aa4SMartin KaFai Lau */ 1059b16d9aa4SMartin KaFai Lau bpf_prog_put(prog); 1060b16d9aa4SMartin KaFai Lau return err; 1061b16d9aa4SMartin KaFai Lau } 106209756af4SAlexei Starovoitov 106374451e66SDaniel Borkmann bpf_prog_kallsyms_add(prog); 1064a67edbf4SDaniel Borkmann trace_bpf_prog_load(prog, err); 106509756af4SAlexei Starovoitov return err; 106609756af4SAlexei Starovoitov 106709756af4SAlexei Starovoitov free_used_maps: 106809756af4SAlexei Starovoitov free_used_maps(prog->aux); 106909756af4SAlexei Starovoitov free_prog: 1070aaac3ba9SAlexei Starovoitov bpf_prog_uncharge_memlock(prog); 1071aaac3ba9SAlexei Starovoitov free_prog_nouncharge: 107209756af4SAlexei Starovoitov bpf_prog_free(prog); 107309756af4SAlexei Starovoitov return err; 107409756af4SAlexei Starovoitov } 107509756af4SAlexei Starovoitov 1076b2197755SDaniel Borkmann #define BPF_OBJ_LAST_FIELD bpf_fd 1077b2197755SDaniel Borkmann 1078b2197755SDaniel Borkmann static int bpf_obj_pin(const union bpf_attr *attr) 1079b2197755SDaniel Borkmann { 1080b2197755SDaniel Borkmann if (CHECK_ATTR(BPF_OBJ)) 1081b2197755SDaniel Borkmann return -EINVAL; 1082b2197755SDaniel Borkmann 1083535e7b4bSMickaël Salaün return bpf_obj_pin_user(attr->bpf_fd, u64_to_user_ptr(attr->pathname)); 1084b2197755SDaniel Borkmann } 1085b2197755SDaniel Borkmann 1086b2197755SDaniel Borkmann static int bpf_obj_get(const union bpf_attr *attr) 1087b2197755SDaniel Borkmann { 1088b2197755SDaniel Borkmann if (CHECK_ATTR(BPF_OBJ) || attr->bpf_fd != 0) 1089b2197755SDaniel Borkmann return -EINVAL; 1090b2197755SDaniel Borkmann 1091535e7b4bSMickaël Salaün return bpf_obj_get_user(u64_to_user_ptr(attr->pathname)); 1092b2197755SDaniel Borkmann } 1093b2197755SDaniel Borkmann 1094f4324551SDaniel Mack #ifdef CONFIG_CGROUP_BPF 1095f4324551SDaniel Mack 1096*464bc0fdSJohn Fastabend #define BPF_PROG_ATTACH_LAST_FIELD attach_flags 1097174a79ffSJohn Fastabend 1098*464bc0fdSJohn Fastabend static int sockmap_get_from_fd(const union bpf_attr *attr) 1099174a79ffSJohn Fastabend { 1100174a79ffSJohn Fastabend int ufd = attr->target_fd; 1101*464bc0fdSJohn Fastabend struct bpf_prog *prog; 1102174a79ffSJohn Fastabend struct bpf_map *map; 1103174a79ffSJohn Fastabend struct fd f; 1104174a79ffSJohn Fastabend int err; 1105174a79ffSJohn Fastabend 1106174a79ffSJohn Fastabend f = fdget(ufd); 1107174a79ffSJohn Fastabend map = __bpf_map_get(f); 1108174a79ffSJohn Fastabend if (IS_ERR(map)) 1109174a79ffSJohn Fastabend return PTR_ERR(map); 1110174a79ffSJohn Fastabend 1111*464bc0fdSJohn Fastabend prog = bpf_prog_get_type(attr->attach_bpf_fd, BPF_PROG_TYPE_SK_SKB); 1112*464bc0fdSJohn Fastabend if (IS_ERR(prog)) { 1113174a79ffSJohn Fastabend fdput(f); 1114*464bc0fdSJohn Fastabend return PTR_ERR(prog); 1115174a79ffSJohn Fastabend } 1116174a79ffSJohn Fastabend 1117*464bc0fdSJohn Fastabend err = sock_map_attach_prog(map, prog, attr->attach_type); 1118174a79ffSJohn Fastabend if (err) { 1119174a79ffSJohn Fastabend fdput(f); 1120*464bc0fdSJohn Fastabend bpf_prog_put(prog); 1121ae2b27b8SDan Carpenter return err; 1122174a79ffSJohn Fastabend } 1123174a79ffSJohn Fastabend 1124174a79ffSJohn Fastabend fdput(f); 1125ae2b27b8SDan Carpenter return 0; 1126174a79ffSJohn Fastabend } 1127f4324551SDaniel Mack 1128f4324551SDaniel Mack static int bpf_prog_attach(const union bpf_attr *attr) 1129f4324551SDaniel Mack { 11307f677633SAlexei Starovoitov enum bpf_prog_type ptype; 1131f4324551SDaniel Mack struct bpf_prog *prog; 1132f4324551SDaniel Mack struct cgroup *cgrp; 11337f677633SAlexei Starovoitov int ret; 1134f4324551SDaniel Mack 1135f4324551SDaniel Mack if (!capable(CAP_NET_ADMIN)) 1136f4324551SDaniel Mack return -EPERM; 1137f4324551SDaniel Mack 1138f4324551SDaniel Mack if (CHECK_ATTR(BPF_PROG_ATTACH)) 1139f4324551SDaniel Mack return -EINVAL; 1140f4324551SDaniel Mack 11417f677633SAlexei Starovoitov if (attr->attach_flags & ~BPF_F_ALLOW_OVERRIDE) 11427f677633SAlexei Starovoitov return -EINVAL; 11437f677633SAlexei Starovoitov 1144f4324551SDaniel Mack switch (attr->attach_type) { 1145f4324551SDaniel Mack case BPF_CGROUP_INET_INGRESS: 1146f4324551SDaniel Mack case BPF_CGROUP_INET_EGRESS: 1147b2cd1257SDavid Ahern ptype = BPF_PROG_TYPE_CGROUP_SKB; 1148b2cd1257SDavid Ahern break; 114961023658SDavid Ahern case BPF_CGROUP_INET_SOCK_CREATE: 115061023658SDavid Ahern ptype = BPF_PROG_TYPE_CGROUP_SOCK; 115161023658SDavid Ahern break; 115240304b2aSLawrence Brakmo case BPF_CGROUP_SOCK_OPS: 115340304b2aSLawrence Brakmo ptype = BPF_PROG_TYPE_SOCK_OPS; 115440304b2aSLawrence Brakmo break; 1155*464bc0fdSJohn Fastabend case BPF_SK_SKB_STREAM_PARSER: 1156*464bc0fdSJohn Fastabend case BPF_SK_SKB_STREAM_VERDICT: 1157*464bc0fdSJohn Fastabend return sockmap_get_from_fd(attr); 1158b2cd1257SDavid Ahern default: 1159b2cd1257SDavid Ahern return -EINVAL; 1160b2cd1257SDavid Ahern } 1161b2cd1257SDavid Ahern 1162b2cd1257SDavid Ahern prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype); 1163f4324551SDaniel Mack if (IS_ERR(prog)) 1164f4324551SDaniel Mack return PTR_ERR(prog); 1165f4324551SDaniel Mack 1166f4324551SDaniel Mack cgrp = cgroup_get_from_fd(attr->target_fd); 1167f4324551SDaniel Mack if (IS_ERR(cgrp)) { 1168f4324551SDaniel Mack bpf_prog_put(prog); 1169f4324551SDaniel Mack return PTR_ERR(cgrp); 1170f4324551SDaniel Mack } 1171f4324551SDaniel Mack 11727f677633SAlexei Starovoitov ret = cgroup_bpf_update(cgrp, prog, attr->attach_type, 11737f677633SAlexei Starovoitov attr->attach_flags & BPF_F_ALLOW_OVERRIDE); 11747f677633SAlexei Starovoitov if (ret) 11757f677633SAlexei Starovoitov bpf_prog_put(prog); 1176f4324551SDaniel Mack cgroup_put(cgrp); 1177f4324551SDaniel Mack 11787f677633SAlexei Starovoitov return ret; 1179f4324551SDaniel Mack } 1180f4324551SDaniel Mack 1181f4324551SDaniel Mack #define BPF_PROG_DETACH_LAST_FIELD attach_type 1182f4324551SDaniel Mack 1183f4324551SDaniel Mack static int bpf_prog_detach(const union bpf_attr *attr) 1184f4324551SDaniel Mack { 1185f4324551SDaniel Mack struct cgroup *cgrp; 11867f677633SAlexei Starovoitov int ret; 1187f4324551SDaniel Mack 1188f4324551SDaniel Mack if (!capable(CAP_NET_ADMIN)) 1189f4324551SDaniel Mack return -EPERM; 1190f4324551SDaniel Mack 1191f4324551SDaniel Mack if (CHECK_ATTR(BPF_PROG_DETACH)) 1192f4324551SDaniel Mack return -EINVAL; 1193f4324551SDaniel Mack 1194f4324551SDaniel Mack switch (attr->attach_type) { 1195f4324551SDaniel Mack case BPF_CGROUP_INET_INGRESS: 1196f4324551SDaniel Mack case BPF_CGROUP_INET_EGRESS: 119761023658SDavid Ahern case BPF_CGROUP_INET_SOCK_CREATE: 119840304b2aSLawrence Brakmo case BPF_CGROUP_SOCK_OPS: 1199f4324551SDaniel Mack cgrp = cgroup_get_from_fd(attr->target_fd); 1200f4324551SDaniel Mack if (IS_ERR(cgrp)) 1201f4324551SDaniel Mack return PTR_ERR(cgrp); 1202f4324551SDaniel Mack 12037f677633SAlexei Starovoitov ret = cgroup_bpf_update(cgrp, NULL, attr->attach_type, false); 1204f4324551SDaniel Mack cgroup_put(cgrp); 1205f4324551SDaniel Mack break; 1206f4324551SDaniel Mack 1207f4324551SDaniel Mack default: 1208f4324551SDaniel Mack return -EINVAL; 1209f4324551SDaniel Mack } 1210f4324551SDaniel Mack 12117f677633SAlexei Starovoitov return ret; 1212f4324551SDaniel Mack } 121340304b2aSLawrence Brakmo 1214f4324551SDaniel Mack #endif /* CONFIG_CGROUP_BPF */ 1215f4324551SDaniel Mack 12161cf1cae9SAlexei Starovoitov #define BPF_PROG_TEST_RUN_LAST_FIELD test.duration 12171cf1cae9SAlexei Starovoitov 12181cf1cae9SAlexei Starovoitov static int bpf_prog_test_run(const union bpf_attr *attr, 12191cf1cae9SAlexei Starovoitov union bpf_attr __user *uattr) 12201cf1cae9SAlexei Starovoitov { 12211cf1cae9SAlexei Starovoitov struct bpf_prog *prog; 12221cf1cae9SAlexei Starovoitov int ret = -ENOTSUPP; 12231cf1cae9SAlexei Starovoitov 12241cf1cae9SAlexei Starovoitov if (CHECK_ATTR(BPF_PROG_TEST_RUN)) 12251cf1cae9SAlexei Starovoitov return -EINVAL; 12261cf1cae9SAlexei Starovoitov 12271cf1cae9SAlexei Starovoitov prog = bpf_prog_get(attr->test.prog_fd); 12281cf1cae9SAlexei Starovoitov if (IS_ERR(prog)) 12291cf1cae9SAlexei Starovoitov return PTR_ERR(prog); 12301cf1cae9SAlexei Starovoitov 12311cf1cae9SAlexei Starovoitov if (prog->aux->ops->test_run) 12321cf1cae9SAlexei Starovoitov ret = prog->aux->ops->test_run(prog, attr, uattr); 12331cf1cae9SAlexei Starovoitov 12341cf1cae9SAlexei Starovoitov bpf_prog_put(prog); 12351cf1cae9SAlexei Starovoitov return ret; 12361cf1cae9SAlexei Starovoitov } 12371cf1cae9SAlexei Starovoitov 123834ad5580SMartin KaFai Lau #define BPF_OBJ_GET_NEXT_ID_LAST_FIELD next_id 123934ad5580SMartin KaFai Lau 124034ad5580SMartin KaFai Lau static int bpf_obj_get_next_id(const union bpf_attr *attr, 124134ad5580SMartin KaFai Lau union bpf_attr __user *uattr, 124234ad5580SMartin KaFai Lau struct idr *idr, 124334ad5580SMartin KaFai Lau spinlock_t *lock) 124434ad5580SMartin KaFai Lau { 124534ad5580SMartin KaFai Lau u32 next_id = attr->start_id; 124634ad5580SMartin KaFai Lau int err = 0; 124734ad5580SMartin KaFai Lau 124834ad5580SMartin KaFai Lau if (CHECK_ATTR(BPF_OBJ_GET_NEXT_ID) || next_id >= INT_MAX) 124934ad5580SMartin KaFai Lau return -EINVAL; 125034ad5580SMartin KaFai Lau 125134ad5580SMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) 125234ad5580SMartin KaFai Lau return -EPERM; 125334ad5580SMartin KaFai Lau 125434ad5580SMartin KaFai Lau next_id++; 125534ad5580SMartin KaFai Lau spin_lock_bh(lock); 125634ad5580SMartin KaFai Lau if (!idr_get_next(idr, &next_id)) 125734ad5580SMartin KaFai Lau err = -ENOENT; 125834ad5580SMartin KaFai Lau spin_unlock_bh(lock); 125934ad5580SMartin KaFai Lau 126034ad5580SMartin KaFai Lau if (!err) 126134ad5580SMartin KaFai Lau err = put_user(next_id, &uattr->next_id); 126234ad5580SMartin KaFai Lau 126334ad5580SMartin KaFai Lau return err; 126434ad5580SMartin KaFai Lau } 126534ad5580SMartin KaFai Lau 1266b16d9aa4SMartin KaFai Lau #define BPF_PROG_GET_FD_BY_ID_LAST_FIELD prog_id 1267b16d9aa4SMartin KaFai Lau 1268b16d9aa4SMartin KaFai Lau static int bpf_prog_get_fd_by_id(const union bpf_attr *attr) 1269b16d9aa4SMartin KaFai Lau { 1270b16d9aa4SMartin KaFai Lau struct bpf_prog *prog; 1271b16d9aa4SMartin KaFai Lau u32 id = attr->prog_id; 1272b16d9aa4SMartin KaFai Lau int fd; 1273b16d9aa4SMartin KaFai Lau 1274b16d9aa4SMartin KaFai Lau if (CHECK_ATTR(BPF_PROG_GET_FD_BY_ID)) 1275b16d9aa4SMartin KaFai Lau return -EINVAL; 1276b16d9aa4SMartin KaFai Lau 1277b16d9aa4SMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) 1278b16d9aa4SMartin KaFai Lau return -EPERM; 1279b16d9aa4SMartin KaFai Lau 1280b16d9aa4SMartin KaFai Lau spin_lock_bh(&prog_idr_lock); 1281b16d9aa4SMartin KaFai Lau prog = idr_find(&prog_idr, id); 1282b16d9aa4SMartin KaFai Lau if (prog) 1283b16d9aa4SMartin KaFai Lau prog = bpf_prog_inc_not_zero(prog); 1284b16d9aa4SMartin KaFai Lau else 1285b16d9aa4SMartin KaFai Lau prog = ERR_PTR(-ENOENT); 1286b16d9aa4SMartin KaFai Lau spin_unlock_bh(&prog_idr_lock); 1287b16d9aa4SMartin KaFai Lau 1288b16d9aa4SMartin KaFai Lau if (IS_ERR(prog)) 1289b16d9aa4SMartin KaFai Lau return PTR_ERR(prog); 1290b16d9aa4SMartin KaFai Lau 1291b16d9aa4SMartin KaFai Lau fd = bpf_prog_new_fd(prog); 1292b16d9aa4SMartin KaFai Lau if (fd < 0) 1293b16d9aa4SMartin KaFai Lau bpf_prog_put(prog); 1294b16d9aa4SMartin KaFai Lau 1295b16d9aa4SMartin KaFai Lau return fd; 1296b16d9aa4SMartin KaFai Lau } 1297b16d9aa4SMartin KaFai Lau 1298bd5f5f4eSMartin KaFai Lau #define BPF_MAP_GET_FD_BY_ID_LAST_FIELD map_id 1299bd5f5f4eSMartin KaFai Lau 1300bd5f5f4eSMartin KaFai Lau static int bpf_map_get_fd_by_id(const union bpf_attr *attr) 1301bd5f5f4eSMartin KaFai Lau { 1302bd5f5f4eSMartin KaFai Lau struct bpf_map *map; 1303bd5f5f4eSMartin KaFai Lau u32 id = attr->map_id; 1304bd5f5f4eSMartin KaFai Lau int fd; 1305bd5f5f4eSMartin KaFai Lau 1306bd5f5f4eSMartin KaFai Lau if (CHECK_ATTR(BPF_MAP_GET_FD_BY_ID)) 1307bd5f5f4eSMartin KaFai Lau return -EINVAL; 1308bd5f5f4eSMartin KaFai Lau 1309bd5f5f4eSMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) 1310bd5f5f4eSMartin KaFai Lau return -EPERM; 1311bd5f5f4eSMartin KaFai Lau 1312bd5f5f4eSMartin KaFai Lau spin_lock_bh(&map_idr_lock); 1313bd5f5f4eSMartin KaFai Lau map = idr_find(&map_idr, id); 1314bd5f5f4eSMartin KaFai Lau if (map) 1315bd5f5f4eSMartin KaFai Lau map = bpf_map_inc_not_zero(map, true); 1316bd5f5f4eSMartin KaFai Lau else 1317bd5f5f4eSMartin KaFai Lau map = ERR_PTR(-ENOENT); 1318bd5f5f4eSMartin KaFai Lau spin_unlock_bh(&map_idr_lock); 1319bd5f5f4eSMartin KaFai Lau 1320bd5f5f4eSMartin KaFai Lau if (IS_ERR(map)) 1321bd5f5f4eSMartin KaFai Lau return PTR_ERR(map); 1322bd5f5f4eSMartin KaFai Lau 1323bd5f5f4eSMartin KaFai Lau fd = bpf_map_new_fd(map); 1324bd5f5f4eSMartin KaFai Lau if (fd < 0) 1325bd5f5f4eSMartin KaFai Lau bpf_map_put(map); 1326bd5f5f4eSMartin KaFai Lau 1327bd5f5f4eSMartin KaFai Lau return fd; 1328bd5f5f4eSMartin KaFai Lau } 1329bd5f5f4eSMartin KaFai Lau 13301e270976SMartin KaFai Lau static int bpf_prog_get_info_by_fd(struct bpf_prog *prog, 13311e270976SMartin KaFai Lau const union bpf_attr *attr, 13321e270976SMartin KaFai Lau union bpf_attr __user *uattr) 13331e270976SMartin KaFai Lau { 13341e270976SMartin KaFai Lau struct bpf_prog_info __user *uinfo = u64_to_user_ptr(attr->info.info); 13351e270976SMartin KaFai Lau struct bpf_prog_info info = {}; 13361e270976SMartin KaFai Lau u32 info_len = attr->info.info_len; 13371e270976SMartin KaFai Lau char __user *uinsns; 13381e270976SMartin KaFai Lau u32 ulen; 13391e270976SMartin KaFai Lau int err; 13401e270976SMartin KaFai Lau 13411e270976SMartin KaFai Lau err = check_uarg_tail_zero(uinfo, sizeof(info), info_len); 13421e270976SMartin KaFai Lau if (err) 13431e270976SMartin KaFai Lau return err; 13441e270976SMartin KaFai Lau info_len = min_t(u32, sizeof(info), info_len); 13451e270976SMartin KaFai Lau 13461e270976SMartin KaFai Lau if (copy_from_user(&info, uinfo, info_len)) 134789b09689SDaniel Borkmann return -EFAULT; 13481e270976SMartin KaFai Lau 13491e270976SMartin KaFai Lau info.type = prog->type; 13501e270976SMartin KaFai Lau info.id = prog->aux->id; 13511e270976SMartin KaFai Lau 13521e270976SMartin KaFai Lau memcpy(info.tag, prog->tag, sizeof(prog->tag)); 13531e270976SMartin KaFai Lau 13541e270976SMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) { 13551e270976SMartin KaFai Lau info.jited_prog_len = 0; 13561e270976SMartin KaFai Lau info.xlated_prog_len = 0; 13571e270976SMartin KaFai Lau goto done; 13581e270976SMartin KaFai Lau } 13591e270976SMartin KaFai Lau 13601e270976SMartin KaFai Lau ulen = info.jited_prog_len; 13611e270976SMartin KaFai Lau info.jited_prog_len = prog->jited_len; 13621e270976SMartin KaFai Lau if (info.jited_prog_len && ulen) { 13631e270976SMartin KaFai Lau uinsns = u64_to_user_ptr(info.jited_prog_insns); 13641e270976SMartin KaFai Lau ulen = min_t(u32, info.jited_prog_len, ulen); 13651e270976SMartin KaFai Lau if (copy_to_user(uinsns, prog->bpf_func, ulen)) 13661e270976SMartin KaFai Lau return -EFAULT; 13671e270976SMartin KaFai Lau } 13681e270976SMartin KaFai Lau 13691e270976SMartin KaFai Lau ulen = info.xlated_prog_len; 13709975a54bSDaniel Borkmann info.xlated_prog_len = bpf_prog_insn_size(prog); 13711e270976SMartin KaFai Lau if (info.xlated_prog_len && ulen) { 13721e270976SMartin KaFai Lau uinsns = u64_to_user_ptr(info.xlated_prog_insns); 13731e270976SMartin KaFai Lau ulen = min_t(u32, info.xlated_prog_len, ulen); 13741e270976SMartin KaFai Lau if (copy_to_user(uinsns, prog->insnsi, ulen)) 13751e270976SMartin KaFai Lau return -EFAULT; 13761e270976SMartin KaFai Lau } 13771e270976SMartin KaFai Lau 13781e270976SMartin KaFai Lau done: 13791e270976SMartin KaFai Lau if (copy_to_user(uinfo, &info, info_len) || 13801e270976SMartin KaFai Lau put_user(info_len, &uattr->info.info_len)) 13811e270976SMartin KaFai Lau return -EFAULT; 13821e270976SMartin KaFai Lau 13831e270976SMartin KaFai Lau return 0; 13841e270976SMartin KaFai Lau } 13851e270976SMartin KaFai Lau 13861e270976SMartin KaFai Lau static int bpf_map_get_info_by_fd(struct bpf_map *map, 13871e270976SMartin KaFai Lau const union bpf_attr *attr, 13881e270976SMartin KaFai Lau union bpf_attr __user *uattr) 13891e270976SMartin KaFai Lau { 13901e270976SMartin KaFai Lau struct bpf_map_info __user *uinfo = u64_to_user_ptr(attr->info.info); 13911e270976SMartin KaFai Lau struct bpf_map_info info = {}; 13921e270976SMartin KaFai Lau u32 info_len = attr->info.info_len; 13931e270976SMartin KaFai Lau int err; 13941e270976SMartin KaFai Lau 13951e270976SMartin KaFai Lau err = check_uarg_tail_zero(uinfo, sizeof(info), info_len); 13961e270976SMartin KaFai Lau if (err) 13971e270976SMartin KaFai Lau return err; 13981e270976SMartin KaFai Lau info_len = min_t(u32, sizeof(info), info_len); 13991e270976SMartin KaFai Lau 14001e270976SMartin KaFai Lau info.type = map->map_type; 14011e270976SMartin KaFai Lau info.id = map->id; 14021e270976SMartin KaFai Lau info.key_size = map->key_size; 14031e270976SMartin KaFai Lau info.value_size = map->value_size; 14041e270976SMartin KaFai Lau info.max_entries = map->max_entries; 14051e270976SMartin KaFai Lau info.map_flags = map->map_flags; 14061e270976SMartin KaFai Lau 14071e270976SMartin KaFai Lau if (copy_to_user(uinfo, &info, info_len) || 14081e270976SMartin KaFai Lau put_user(info_len, &uattr->info.info_len)) 14091e270976SMartin KaFai Lau return -EFAULT; 14101e270976SMartin KaFai Lau 14111e270976SMartin KaFai Lau return 0; 14121e270976SMartin KaFai Lau } 14131e270976SMartin KaFai Lau 14141e270976SMartin KaFai Lau #define BPF_OBJ_GET_INFO_BY_FD_LAST_FIELD info.info 14151e270976SMartin KaFai Lau 14161e270976SMartin KaFai Lau static int bpf_obj_get_info_by_fd(const union bpf_attr *attr, 14171e270976SMartin KaFai Lau union bpf_attr __user *uattr) 14181e270976SMartin KaFai Lau { 14191e270976SMartin KaFai Lau int ufd = attr->info.bpf_fd; 14201e270976SMartin KaFai Lau struct fd f; 14211e270976SMartin KaFai Lau int err; 14221e270976SMartin KaFai Lau 14231e270976SMartin KaFai Lau if (CHECK_ATTR(BPF_OBJ_GET_INFO_BY_FD)) 14241e270976SMartin KaFai Lau return -EINVAL; 14251e270976SMartin KaFai Lau 14261e270976SMartin KaFai Lau f = fdget(ufd); 14271e270976SMartin KaFai Lau if (!f.file) 14281e270976SMartin KaFai Lau return -EBADFD; 14291e270976SMartin KaFai Lau 14301e270976SMartin KaFai Lau if (f.file->f_op == &bpf_prog_fops) 14311e270976SMartin KaFai Lau err = bpf_prog_get_info_by_fd(f.file->private_data, attr, 14321e270976SMartin KaFai Lau uattr); 14331e270976SMartin KaFai Lau else if (f.file->f_op == &bpf_map_fops) 14341e270976SMartin KaFai Lau err = bpf_map_get_info_by_fd(f.file->private_data, attr, 14351e270976SMartin KaFai Lau uattr); 14361e270976SMartin KaFai Lau else 14371e270976SMartin KaFai Lau err = -EINVAL; 14381e270976SMartin KaFai Lau 14391e270976SMartin KaFai Lau fdput(f); 14401e270976SMartin KaFai Lau return err; 14411e270976SMartin KaFai Lau } 14421e270976SMartin KaFai Lau 144399c55f7dSAlexei Starovoitov SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size) 144499c55f7dSAlexei Starovoitov { 144599c55f7dSAlexei Starovoitov union bpf_attr attr = {}; 144699c55f7dSAlexei Starovoitov int err; 144799c55f7dSAlexei Starovoitov 14481be7f75dSAlexei Starovoitov if (!capable(CAP_SYS_ADMIN) && sysctl_unprivileged_bpf_disabled) 144999c55f7dSAlexei Starovoitov return -EPERM; 145099c55f7dSAlexei Starovoitov 14511e270976SMartin KaFai Lau err = check_uarg_tail_zero(uattr, sizeof(attr), size); 145299c55f7dSAlexei Starovoitov if (err) 145399c55f7dSAlexei Starovoitov return err; 14541e270976SMartin KaFai Lau size = min_t(u32, size, sizeof(attr)); 145599c55f7dSAlexei Starovoitov 145699c55f7dSAlexei Starovoitov /* copy attributes from user space, may be less than sizeof(bpf_attr) */ 145799c55f7dSAlexei Starovoitov if (copy_from_user(&attr, uattr, size) != 0) 145899c55f7dSAlexei Starovoitov return -EFAULT; 145999c55f7dSAlexei Starovoitov 146099c55f7dSAlexei Starovoitov switch (cmd) { 146199c55f7dSAlexei Starovoitov case BPF_MAP_CREATE: 146299c55f7dSAlexei Starovoitov err = map_create(&attr); 146399c55f7dSAlexei Starovoitov break; 1464db20fd2bSAlexei Starovoitov case BPF_MAP_LOOKUP_ELEM: 1465db20fd2bSAlexei Starovoitov err = map_lookup_elem(&attr); 1466db20fd2bSAlexei Starovoitov break; 1467db20fd2bSAlexei Starovoitov case BPF_MAP_UPDATE_ELEM: 1468db20fd2bSAlexei Starovoitov err = map_update_elem(&attr); 1469db20fd2bSAlexei Starovoitov break; 1470db20fd2bSAlexei Starovoitov case BPF_MAP_DELETE_ELEM: 1471db20fd2bSAlexei Starovoitov err = map_delete_elem(&attr); 1472db20fd2bSAlexei Starovoitov break; 1473db20fd2bSAlexei Starovoitov case BPF_MAP_GET_NEXT_KEY: 1474db20fd2bSAlexei Starovoitov err = map_get_next_key(&attr); 1475db20fd2bSAlexei Starovoitov break; 147609756af4SAlexei Starovoitov case BPF_PROG_LOAD: 147709756af4SAlexei Starovoitov err = bpf_prog_load(&attr); 147809756af4SAlexei Starovoitov break; 1479b2197755SDaniel Borkmann case BPF_OBJ_PIN: 1480b2197755SDaniel Borkmann err = bpf_obj_pin(&attr); 1481b2197755SDaniel Borkmann break; 1482b2197755SDaniel Borkmann case BPF_OBJ_GET: 1483b2197755SDaniel Borkmann err = bpf_obj_get(&attr); 1484b2197755SDaniel Borkmann break; 1485f4324551SDaniel Mack #ifdef CONFIG_CGROUP_BPF 1486f4324551SDaniel Mack case BPF_PROG_ATTACH: 1487f4324551SDaniel Mack err = bpf_prog_attach(&attr); 1488f4324551SDaniel Mack break; 1489f4324551SDaniel Mack case BPF_PROG_DETACH: 1490f4324551SDaniel Mack err = bpf_prog_detach(&attr); 1491f4324551SDaniel Mack break; 1492f4324551SDaniel Mack #endif 14931cf1cae9SAlexei Starovoitov case BPF_PROG_TEST_RUN: 14941cf1cae9SAlexei Starovoitov err = bpf_prog_test_run(&attr, uattr); 14951cf1cae9SAlexei Starovoitov break; 149634ad5580SMartin KaFai Lau case BPF_PROG_GET_NEXT_ID: 149734ad5580SMartin KaFai Lau err = bpf_obj_get_next_id(&attr, uattr, 149834ad5580SMartin KaFai Lau &prog_idr, &prog_idr_lock); 149934ad5580SMartin KaFai Lau break; 150034ad5580SMartin KaFai Lau case BPF_MAP_GET_NEXT_ID: 150134ad5580SMartin KaFai Lau err = bpf_obj_get_next_id(&attr, uattr, 150234ad5580SMartin KaFai Lau &map_idr, &map_idr_lock); 150334ad5580SMartin KaFai Lau break; 1504b16d9aa4SMartin KaFai Lau case BPF_PROG_GET_FD_BY_ID: 1505b16d9aa4SMartin KaFai Lau err = bpf_prog_get_fd_by_id(&attr); 1506b16d9aa4SMartin KaFai Lau break; 1507bd5f5f4eSMartin KaFai Lau case BPF_MAP_GET_FD_BY_ID: 1508bd5f5f4eSMartin KaFai Lau err = bpf_map_get_fd_by_id(&attr); 1509bd5f5f4eSMartin KaFai Lau break; 15101e270976SMartin KaFai Lau case BPF_OBJ_GET_INFO_BY_FD: 15111e270976SMartin KaFai Lau err = bpf_obj_get_info_by_fd(&attr, uattr); 15121e270976SMartin KaFai Lau break; 151399c55f7dSAlexei Starovoitov default: 151499c55f7dSAlexei Starovoitov err = -EINVAL; 151599c55f7dSAlexei Starovoitov break; 151699c55f7dSAlexei Starovoitov } 151799c55f7dSAlexei Starovoitov 151899c55f7dSAlexei Starovoitov return err; 151999c55f7dSAlexei Starovoitov } 1520