xref: /linux/kernel/bpf/syscall.c (revision 540fefc08f75aedb517acbf525d393b8efddabd9)
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>
14f4364dcfSSean Young #include <linux/bpf_lirc.h>
15f56a653cSMartin KaFai Lau #include <linux/btf.h>
1699c55f7dSAlexei Starovoitov #include <linux/syscalls.h>
1799c55f7dSAlexei Starovoitov #include <linux/slab.h>
183f07c014SIngo Molnar #include <linux/sched/signal.h>
19d407bd25SDaniel Borkmann #include <linux/vmalloc.h>
20d407bd25SDaniel Borkmann #include <linux/mmzone.h>
2199c55f7dSAlexei Starovoitov #include <linux/anon_inodes.h>
2241bdc4b4SYonghong Song #include <linux/fdtable.h>
23db20fd2bSAlexei Starovoitov #include <linux/file.h>
2441bdc4b4SYonghong Song #include <linux/fs.h>
2509756af4SAlexei Starovoitov #include <linux/license.h>
2609756af4SAlexei Starovoitov #include <linux/filter.h>
272541517cSAlexei Starovoitov #include <linux/version.h>
28535e7b4bSMickaël Salaün #include <linux/kernel.h>
29dc4bb0e2SMartin KaFai Lau #include <linux/idr.h>
30cb4d2b3fSMartin KaFai Lau #include <linux/cred.h>
31cb4d2b3fSMartin KaFai Lau #include <linux/timekeeping.h>
32cb4d2b3fSMartin KaFai Lau #include <linux/ctype.h>
339ef09e35SMark Rutland #include <linux/nospec.h>
3499c55f7dSAlexei Starovoitov 
3514dc6f04SMartin KaFai Lau #define IS_FD_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PROG_ARRAY || \
3614dc6f04SMartin KaFai Lau 			   (map)->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || \
3714dc6f04SMartin KaFai Lau 			   (map)->map_type == BPF_MAP_TYPE_CGROUP_ARRAY || \
3814dc6f04SMartin KaFai Lau 			   (map)->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS)
3914dc6f04SMartin KaFai Lau #define IS_FD_HASH(map) ((map)->map_type == BPF_MAP_TYPE_HASH_OF_MAPS)
4014dc6f04SMartin KaFai Lau #define IS_FD_MAP(map) (IS_FD_ARRAY(map) || IS_FD_HASH(map))
4114dc6f04SMartin KaFai Lau 
426e71b04aSChenbo Feng #define BPF_OBJ_FLAG_MASK   (BPF_F_RDONLY | BPF_F_WRONLY)
436e71b04aSChenbo Feng 
44b121d1e7SAlexei Starovoitov DEFINE_PER_CPU(int, bpf_prog_active);
45dc4bb0e2SMartin KaFai Lau static DEFINE_IDR(prog_idr);
46dc4bb0e2SMartin KaFai Lau static DEFINE_SPINLOCK(prog_idr_lock);
47f3f1c054SMartin KaFai Lau static DEFINE_IDR(map_idr);
48f3f1c054SMartin KaFai Lau static DEFINE_SPINLOCK(map_idr_lock);
49b121d1e7SAlexei Starovoitov 
501be7f75dSAlexei Starovoitov int sysctl_unprivileged_bpf_disabled __read_mostly;
511be7f75dSAlexei Starovoitov 
5240077e0cSJohannes Berg static const struct bpf_map_ops * const bpf_map_types[] = {
5340077e0cSJohannes Berg #define BPF_PROG_TYPE(_id, _ops)
5440077e0cSJohannes Berg #define BPF_MAP_TYPE(_id, _ops) \
5540077e0cSJohannes Berg 	[_id] = &_ops,
5640077e0cSJohannes Berg #include <linux/bpf_types.h>
5740077e0cSJohannes Berg #undef BPF_PROG_TYPE
5840077e0cSJohannes Berg #undef BPF_MAP_TYPE
5940077e0cSJohannes Berg };
6099c55f7dSAlexei Starovoitov 
61752ba56fSMickaël Salaün /*
62752ba56fSMickaël Salaün  * If we're handed a bigger struct than we know of, ensure all the unknown bits
63752ba56fSMickaël Salaün  * are 0 - i.e. new user-space does not rely on any kernel feature extensions
64752ba56fSMickaël Salaün  * we don't know about yet.
65752ba56fSMickaël Salaün  *
66752ba56fSMickaël Salaün  * There is a ToCToU between this function call and the following
67752ba56fSMickaël Salaün  * copy_from_user() call. However, this is not a concern since this function is
68752ba56fSMickaël Salaün  * meant to be a future-proofing of bits.
69752ba56fSMickaël Salaün  */
70dcab51f1SMartin KaFai Lau int bpf_check_uarg_tail_zero(void __user *uaddr,
7158291a74SMickaël Salaün 			     size_t expected_size,
7258291a74SMickaël Salaün 			     size_t actual_size)
7358291a74SMickaël Salaün {
7458291a74SMickaël Salaün 	unsigned char __user *addr;
7558291a74SMickaël Salaün 	unsigned char __user *end;
7658291a74SMickaël Salaün 	unsigned char val;
7758291a74SMickaël Salaün 	int err;
7858291a74SMickaël Salaün 
79752ba56fSMickaël Salaün 	if (unlikely(actual_size > PAGE_SIZE))	/* silly large */
80752ba56fSMickaël Salaün 		return -E2BIG;
81752ba56fSMickaël Salaün 
82752ba56fSMickaël Salaün 	if (unlikely(!access_ok(VERIFY_READ, uaddr, actual_size)))
83752ba56fSMickaël Salaün 		return -EFAULT;
84752ba56fSMickaël Salaün 
8558291a74SMickaël Salaün 	if (actual_size <= expected_size)
8658291a74SMickaël Salaün 		return 0;
8758291a74SMickaël Salaün 
8858291a74SMickaël Salaün 	addr = uaddr + expected_size;
8958291a74SMickaël Salaün 	end  = uaddr + actual_size;
9058291a74SMickaël Salaün 
9158291a74SMickaël Salaün 	for (; addr < end; addr++) {
9258291a74SMickaël Salaün 		err = get_user(val, addr);
9358291a74SMickaël Salaün 		if (err)
9458291a74SMickaël Salaün 			return err;
9558291a74SMickaël Salaün 		if (val)
9658291a74SMickaël Salaün 			return -E2BIG;
9758291a74SMickaël Salaün 	}
9858291a74SMickaël Salaün 
9958291a74SMickaël Salaün 	return 0;
10058291a74SMickaël Salaün }
10158291a74SMickaël Salaün 
102a3884572SJakub Kicinski const struct bpf_map_ops bpf_map_offload_ops = {
103a3884572SJakub Kicinski 	.map_alloc = bpf_map_offload_map_alloc,
104a3884572SJakub Kicinski 	.map_free = bpf_map_offload_map_free,
105e8d2bec0SDaniel Borkmann 	.map_check_btf = map_check_no_btf,
106a3884572SJakub Kicinski };
107a3884572SJakub Kicinski 
10899c55f7dSAlexei Starovoitov static struct bpf_map *find_and_alloc_map(union bpf_attr *attr)
10999c55f7dSAlexei Starovoitov {
1101110f3a9SJakub Kicinski 	const struct bpf_map_ops *ops;
1119ef09e35SMark Rutland 	u32 type = attr->map_type;
11299c55f7dSAlexei Starovoitov 	struct bpf_map *map;
1131110f3a9SJakub Kicinski 	int err;
11499c55f7dSAlexei Starovoitov 
1159ef09e35SMark Rutland 	if (type >= ARRAY_SIZE(bpf_map_types))
1161110f3a9SJakub Kicinski 		return ERR_PTR(-EINVAL);
1179ef09e35SMark Rutland 	type = array_index_nospec(type, ARRAY_SIZE(bpf_map_types));
1189ef09e35SMark Rutland 	ops = bpf_map_types[type];
1191110f3a9SJakub Kicinski 	if (!ops)
12040077e0cSJohannes Berg 		return ERR_PTR(-EINVAL);
12140077e0cSJohannes Berg 
1221110f3a9SJakub Kicinski 	if (ops->map_alloc_check) {
1231110f3a9SJakub Kicinski 		err = ops->map_alloc_check(attr);
1241110f3a9SJakub Kicinski 		if (err)
1251110f3a9SJakub Kicinski 			return ERR_PTR(err);
1261110f3a9SJakub Kicinski 	}
127a3884572SJakub Kicinski 	if (attr->map_ifindex)
128a3884572SJakub Kicinski 		ops = &bpf_map_offload_ops;
1291110f3a9SJakub Kicinski 	map = ops->map_alloc(attr);
13099c55f7dSAlexei Starovoitov 	if (IS_ERR(map))
13199c55f7dSAlexei Starovoitov 		return map;
1321110f3a9SJakub Kicinski 	map->ops = ops;
1339ef09e35SMark Rutland 	map->map_type = type;
13499c55f7dSAlexei Starovoitov 	return map;
13599c55f7dSAlexei Starovoitov }
13699c55f7dSAlexei Starovoitov 
13796eabe7aSMartin KaFai Lau void *bpf_map_area_alloc(size_t size, int numa_node)
138d407bd25SDaniel Borkmann {
139d407bd25SDaniel Borkmann 	/* We definitely need __GFP_NORETRY, so OOM killer doesn't
140d407bd25SDaniel Borkmann 	 * trigger under memory pressure as we really just want to
141d407bd25SDaniel Borkmann 	 * fail instead.
142d407bd25SDaniel Borkmann 	 */
143d407bd25SDaniel Borkmann 	const gfp_t flags = __GFP_NOWARN | __GFP_NORETRY | __GFP_ZERO;
144d407bd25SDaniel Borkmann 	void *area;
145d407bd25SDaniel Borkmann 
146d407bd25SDaniel Borkmann 	if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) {
14796eabe7aSMartin KaFai Lau 		area = kmalloc_node(size, GFP_USER | flags, numa_node);
148d407bd25SDaniel Borkmann 		if (area != NULL)
149d407bd25SDaniel Borkmann 			return area;
150d407bd25SDaniel Borkmann 	}
151d407bd25SDaniel Borkmann 
15296eabe7aSMartin KaFai Lau 	return __vmalloc_node_flags_caller(size, numa_node, GFP_KERNEL | flags,
15396eabe7aSMartin KaFai Lau 					   __builtin_return_address(0));
154d407bd25SDaniel Borkmann }
155d407bd25SDaniel Borkmann 
156d407bd25SDaniel Borkmann void bpf_map_area_free(void *area)
157d407bd25SDaniel Borkmann {
158d407bd25SDaniel Borkmann 	kvfree(area);
159d407bd25SDaniel Borkmann }
160d407bd25SDaniel Borkmann 
161bd475643SJakub Kicinski void bpf_map_init_from_attr(struct bpf_map *map, union bpf_attr *attr)
162bd475643SJakub Kicinski {
163bd475643SJakub Kicinski 	map->map_type = attr->map_type;
164bd475643SJakub Kicinski 	map->key_size = attr->key_size;
165bd475643SJakub Kicinski 	map->value_size = attr->value_size;
166bd475643SJakub Kicinski 	map->max_entries = attr->max_entries;
167bd475643SJakub Kicinski 	map->map_flags = attr->map_flags;
168bd475643SJakub Kicinski 	map->numa_node = bpf_map_attr_numa_node(attr);
169bd475643SJakub Kicinski }
170bd475643SJakub Kicinski 
1716c905981SAlexei Starovoitov int bpf_map_precharge_memlock(u32 pages)
1726c905981SAlexei Starovoitov {
1736c905981SAlexei Starovoitov 	struct user_struct *user = get_current_user();
1746c905981SAlexei Starovoitov 	unsigned long memlock_limit, cur;
1756c905981SAlexei Starovoitov 
1766c905981SAlexei Starovoitov 	memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
1776c905981SAlexei Starovoitov 	cur = atomic_long_read(&user->locked_vm);
1786c905981SAlexei Starovoitov 	free_uid(user);
1796c905981SAlexei Starovoitov 	if (cur + pages > memlock_limit)
1806c905981SAlexei Starovoitov 		return -EPERM;
1816c905981SAlexei Starovoitov 	return 0;
1826c905981SAlexei Starovoitov }
1836c905981SAlexei Starovoitov 
1840a4c58f5SRoman Gushchin static int bpf_charge_memlock(struct user_struct *user, u32 pages)
185aaac3ba9SAlexei Starovoitov {
1860a4c58f5SRoman Gushchin 	unsigned long memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
187aaac3ba9SAlexei Starovoitov 
1880a4c58f5SRoman Gushchin 	if (atomic_long_add_return(pages, &user->locked_vm) > memlock_limit) {
1890a4c58f5SRoman Gushchin 		atomic_long_sub(pages, &user->locked_vm);
190aaac3ba9SAlexei Starovoitov 		return -EPERM;
191aaac3ba9SAlexei Starovoitov 	}
192aaac3ba9SAlexei Starovoitov 	return 0;
193aaac3ba9SAlexei Starovoitov }
194aaac3ba9SAlexei Starovoitov 
1950a4c58f5SRoman Gushchin static void bpf_uncharge_memlock(struct user_struct *user, u32 pages)
1960a4c58f5SRoman Gushchin {
1970a4c58f5SRoman Gushchin 	atomic_long_sub(pages, &user->locked_vm);
1980a4c58f5SRoman Gushchin }
1990a4c58f5SRoman Gushchin 
2000a4c58f5SRoman Gushchin static int bpf_map_init_memlock(struct bpf_map *map)
2010a4c58f5SRoman Gushchin {
2020a4c58f5SRoman Gushchin 	struct user_struct *user = get_current_user();
2030a4c58f5SRoman Gushchin 	int ret;
2040a4c58f5SRoman Gushchin 
2050a4c58f5SRoman Gushchin 	ret = bpf_charge_memlock(user, map->pages);
2060a4c58f5SRoman Gushchin 	if (ret) {
2070a4c58f5SRoman Gushchin 		free_uid(user);
2080a4c58f5SRoman Gushchin 		return ret;
2090a4c58f5SRoman Gushchin 	}
2100a4c58f5SRoman Gushchin 	map->user = user;
2110a4c58f5SRoman Gushchin 	return ret;
2120a4c58f5SRoman Gushchin }
2130a4c58f5SRoman Gushchin 
2140a4c58f5SRoman Gushchin static void bpf_map_release_memlock(struct bpf_map *map)
215aaac3ba9SAlexei Starovoitov {
216aaac3ba9SAlexei Starovoitov 	struct user_struct *user = map->user;
2170a4c58f5SRoman Gushchin 	bpf_uncharge_memlock(user, map->pages);
218aaac3ba9SAlexei Starovoitov 	free_uid(user);
219aaac3ba9SAlexei Starovoitov }
220aaac3ba9SAlexei Starovoitov 
2210a4c58f5SRoman Gushchin int bpf_map_charge_memlock(struct bpf_map *map, u32 pages)
2220a4c58f5SRoman Gushchin {
2230a4c58f5SRoman Gushchin 	int ret;
2240a4c58f5SRoman Gushchin 
2250a4c58f5SRoman Gushchin 	ret = bpf_charge_memlock(map->user, pages);
2260a4c58f5SRoman Gushchin 	if (ret)
2270a4c58f5SRoman Gushchin 		return ret;
2280a4c58f5SRoman Gushchin 	map->pages += pages;
2290a4c58f5SRoman Gushchin 	return ret;
2300a4c58f5SRoman Gushchin }
2310a4c58f5SRoman Gushchin 
2320a4c58f5SRoman Gushchin void bpf_map_uncharge_memlock(struct bpf_map *map, u32 pages)
2330a4c58f5SRoman Gushchin {
2340a4c58f5SRoman Gushchin 	bpf_uncharge_memlock(map->user, pages);
2350a4c58f5SRoman Gushchin 	map->pages -= pages;
2360a4c58f5SRoman Gushchin }
2370a4c58f5SRoman Gushchin 
238f3f1c054SMartin KaFai Lau static int bpf_map_alloc_id(struct bpf_map *map)
239f3f1c054SMartin KaFai Lau {
240f3f1c054SMartin KaFai Lau 	int id;
241f3f1c054SMartin KaFai Lau 
242b76354cdSShaohua Li 	idr_preload(GFP_KERNEL);
243f3f1c054SMartin KaFai Lau 	spin_lock_bh(&map_idr_lock);
244f3f1c054SMartin KaFai Lau 	id = idr_alloc_cyclic(&map_idr, map, 1, INT_MAX, GFP_ATOMIC);
245f3f1c054SMartin KaFai Lau 	if (id > 0)
246f3f1c054SMartin KaFai Lau 		map->id = id;
247f3f1c054SMartin KaFai Lau 	spin_unlock_bh(&map_idr_lock);
248b76354cdSShaohua Li 	idr_preload_end();
249f3f1c054SMartin KaFai Lau 
250f3f1c054SMartin KaFai Lau 	if (WARN_ON_ONCE(!id))
251f3f1c054SMartin KaFai Lau 		return -ENOSPC;
252f3f1c054SMartin KaFai Lau 
253f3f1c054SMartin KaFai Lau 	return id > 0 ? 0 : id;
254f3f1c054SMartin KaFai Lau }
255f3f1c054SMartin KaFai Lau 
256a3884572SJakub Kicinski void bpf_map_free_id(struct bpf_map *map, bool do_idr_lock)
257f3f1c054SMartin KaFai Lau {
258930651a7SEric Dumazet 	unsigned long flags;
259930651a7SEric Dumazet 
260a3884572SJakub Kicinski 	/* Offloaded maps are removed from the IDR store when their device
261a3884572SJakub Kicinski 	 * disappears - even if someone holds an fd to them they are unusable,
262a3884572SJakub Kicinski 	 * the memory is gone, all ops will fail; they are simply waiting for
263a3884572SJakub Kicinski 	 * refcnt to drop to be freed.
264a3884572SJakub Kicinski 	 */
265a3884572SJakub Kicinski 	if (!map->id)
266a3884572SJakub Kicinski 		return;
267a3884572SJakub Kicinski 
268bd5f5f4eSMartin KaFai Lau 	if (do_idr_lock)
269930651a7SEric Dumazet 		spin_lock_irqsave(&map_idr_lock, flags);
270bd5f5f4eSMartin KaFai Lau 	else
271bd5f5f4eSMartin KaFai Lau 		__acquire(&map_idr_lock);
272bd5f5f4eSMartin KaFai Lau 
273f3f1c054SMartin KaFai Lau 	idr_remove(&map_idr, map->id);
274a3884572SJakub Kicinski 	map->id = 0;
275bd5f5f4eSMartin KaFai Lau 
276bd5f5f4eSMartin KaFai Lau 	if (do_idr_lock)
277930651a7SEric Dumazet 		spin_unlock_irqrestore(&map_idr_lock, flags);
278bd5f5f4eSMartin KaFai Lau 	else
279bd5f5f4eSMartin KaFai Lau 		__release(&map_idr_lock);
280f3f1c054SMartin KaFai Lau }
281f3f1c054SMartin KaFai Lau 
28299c55f7dSAlexei Starovoitov /* called from workqueue */
28399c55f7dSAlexei Starovoitov static void bpf_map_free_deferred(struct work_struct *work)
28499c55f7dSAlexei Starovoitov {
28599c55f7dSAlexei Starovoitov 	struct bpf_map *map = container_of(work, struct bpf_map, work);
28699c55f7dSAlexei Starovoitov 
2870a4c58f5SRoman Gushchin 	bpf_map_release_memlock(map);
288afdb09c7SChenbo Feng 	security_bpf_map_free(map);
28999c55f7dSAlexei Starovoitov 	/* implementation dependent freeing */
29099c55f7dSAlexei Starovoitov 	map->ops->map_free(map);
29199c55f7dSAlexei Starovoitov }
29299c55f7dSAlexei Starovoitov 
293c9da161cSDaniel Borkmann static void bpf_map_put_uref(struct bpf_map *map)
294c9da161cSDaniel Borkmann {
295c9da161cSDaniel Borkmann 	if (atomic_dec_and_test(&map->usercnt)) {
296ba6b8de4SJohn Fastabend 		if (map->ops->map_release_uref)
297ba6b8de4SJohn Fastabend 			map->ops->map_release_uref(map);
298c9da161cSDaniel Borkmann 	}
299c9da161cSDaniel Borkmann }
300c9da161cSDaniel Borkmann 
30199c55f7dSAlexei Starovoitov /* decrement map refcnt and schedule it for freeing via workqueue
30299c55f7dSAlexei Starovoitov  * (unrelying map implementation ops->map_free() might sleep)
30399c55f7dSAlexei Starovoitov  */
304bd5f5f4eSMartin KaFai Lau static void __bpf_map_put(struct bpf_map *map, bool do_idr_lock)
30599c55f7dSAlexei Starovoitov {
30699c55f7dSAlexei Starovoitov 	if (atomic_dec_and_test(&map->refcnt)) {
30734ad5580SMartin KaFai Lau 		/* bpf_map_free_id() must be called first */
308bd5f5f4eSMartin KaFai Lau 		bpf_map_free_id(map, do_idr_lock);
30978958fcaSMartin KaFai Lau 		btf_put(map->btf);
31099c55f7dSAlexei Starovoitov 		INIT_WORK(&map->work, bpf_map_free_deferred);
31199c55f7dSAlexei Starovoitov 		schedule_work(&map->work);
31299c55f7dSAlexei Starovoitov 	}
31399c55f7dSAlexei Starovoitov }
31499c55f7dSAlexei Starovoitov 
315bd5f5f4eSMartin KaFai Lau void bpf_map_put(struct bpf_map *map)
316bd5f5f4eSMartin KaFai Lau {
317bd5f5f4eSMartin KaFai Lau 	__bpf_map_put(map, true);
318bd5f5f4eSMartin KaFai Lau }
319630a4d38SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_map_put);
320bd5f5f4eSMartin KaFai Lau 
321c9da161cSDaniel Borkmann void bpf_map_put_with_uref(struct bpf_map *map)
322c9da161cSDaniel Borkmann {
323c9da161cSDaniel Borkmann 	bpf_map_put_uref(map);
324c9da161cSDaniel Borkmann 	bpf_map_put(map);
325c9da161cSDaniel Borkmann }
326c9da161cSDaniel Borkmann 
32799c55f7dSAlexei Starovoitov static int bpf_map_release(struct inode *inode, struct file *filp)
32899c55f7dSAlexei Starovoitov {
32961d1b6a4SDaniel Borkmann 	struct bpf_map *map = filp->private_data;
33061d1b6a4SDaniel Borkmann 
33161d1b6a4SDaniel Borkmann 	if (map->ops->map_release)
33261d1b6a4SDaniel Borkmann 		map->ops->map_release(map, filp);
33361d1b6a4SDaniel Borkmann 
33461d1b6a4SDaniel Borkmann 	bpf_map_put_with_uref(map);
33599c55f7dSAlexei Starovoitov 	return 0;
33699c55f7dSAlexei Starovoitov }
33799c55f7dSAlexei Starovoitov 
338f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS
339f99bf205SDaniel Borkmann static void bpf_map_show_fdinfo(struct seq_file *m, struct file *filp)
340f99bf205SDaniel Borkmann {
341f99bf205SDaniel Borkmann 	const struct bpf_map *map = filp->private_data;
34221116b70SDaniel Borkmann 	const struct bpf_array *array;
34321116b70SDaniel Borkmann 	u32 owner_prog_type = 0;
3449780c0abSDaniel Borkmann 	u32 owner_jited = 0;
34521116b70SDaniel Borkmann 
34621116b70SDaniel Borkmann 	if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY) {
34721116b70SDaniel Borkmann 		array = container_of(map, struct bpf_array, map);
34821116b70SDaniel Borkmann 		owner_prog_type = array->owner_prog_type;
3499780c0abSDaniel Borkmann 		owner_jited = array->owner_jited;
35021116b70SDaniel Borkmann 	}
351f99bf205SDaniel Borkmann 
352f99bf205SDaniel Borkmann 	seq_printf(m,
353f99bf205SDaniel Borkmann 		   "map_type:\t%u\n"
354f99bf205SDaniel Borkmann 		   "key_size:\t%u\n"
355f99bf205SDaniel Borkmann 		   "value_size:\t%u\n"
356322cea2fSDaniel Borkmann 		   "max_entries:\t%u\n"
35721116b70SDaniel Borkmann 		   "map_flags:\t%#x\n"
3584316b409SDaniel Borkmann 		   "memlock:\t%llu\n"
3594316b409SDaniel Borkmann 		   "map_id:\t%u\n",
360f99bf205SDaniel Borkmann 		   map->map_type,
361f99bf205SDaniel Borkmann 		   map->key_size,
362f99bf205SDaniel Borkmann 		   map->value_size,
363322cea2fSDaniel Borkmann 		   map->max_entries,
36421116b70SDaniel Borkmann 		   map->map_flags,
3654316b409SDaniel Borkmann 		   map->pages * 1ULL << PAGE_SHIFT,
3664316b409SDaniel Borkmann 		   map->id);
36721116b70SDaniel Borkmann 
3689780c0abSDaniel Borkmann 	if (owner_prog_type) {
36921116b70SDaniel Borkmann 		seq_printf(m, "owner_prog_type:\t%u\n",
37021116b70SDaniel Borkmann 			   owner_prog_type);
3719780c0abSDaniel Borkmann 		seq_printf(m, "owner_jited:\t%u\n",
3729780c0abSDaniel Borkmann 			   owner_jited);
3739780c0abSDaniel Borkmann 	}
374f99bf205SDaniel Borkmann }
375f99bf205SDaniel Borkmann #endif
376f99bf205SDaniel Borkmann 
3776e71b04aSChenbo Feng static ssize_t bpf_dummy_read(struct file *filp, char __user *buf, size_t siz,
3786e71b04aSChenbo Feng 			      loff_t *ppos)
3796e71b04aSChenbo Feng {
3806e71b04aSChenbo Feng 	/* We need this handler such that alloc_file() enables
3816e71b04aSChenbo Feng 	 * f_mode with FMODE_CAN_READ.
3826e71b04aSChenbo Feng 	 */
3836e71b04aSChenbo Feng 	return -EINVAL;
3846e71b04aSChenbo Feng }
3856e71b04aSChenbo Feng 
3866e71b04aSChenbo Feng static ssize_t bpf_dummy_write(struct file *filp, const char __user *buf,
3876e71b04aSChenbo Feng 			       size_t siz, loff_t *ppos)
3886e71b04aSChenbo Feng {
3896e71b04aSChenbo Feng 	/* We need this handler such that alloc_file() enables
3906e71b04aSChenbo Feng 	 * f_mode with FMODE_CAN_WRITE.
3916e71b04aSChenbo Feng 	 */
3926e71b04aSChenbo Feng 	return -EINVAL;
3936e71b04aSChenbo Feng }
3946e71b04aSChenbo Feng 
395f66e448cSChenbo Feng const struct file_operations bpf_map_fops = {
396f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS
397f99bf205SDaniel Borkmann 	.show_fdinfo	= bpf_map_show_fdinfo,
398f99bf205SDaniel Borkmann #endif
39999c55f7dSAlexei Starovoitov 	.release	= bpf_map_release,
4006e71b04aSChenbo Feng 	.read		= bpf_dummy_read,
4016e71b04aSChenbo Feng 	.write		= bpf_dummy_write,
40299c55f7dSAlexei Starovoitov };
40399c55f7dSAlexei Starovoitov 
4046e71b04aSChenbo Feng int bpf_map_new_fd(struct bpf_map *map, int flags)
405aa79781bSDaniel Borkmann {
406afdb09c7SChenbo Feng 	int ret;
407afdb09c7SChenbo Feng 
408afdb09c7SChenbo Feng 	ret = security_bpf_map(map, OPEN_FMODE(flags));
409afdb09c7SChenbo Feng 	if (ret < 0)
410afdb09c7SChenbo Feng 		return ret;
411afdb09c7SChenbo Feng 
412aa79781bSDaniel Borkmann 	return anon_inode_getfd("bpf-map", &bpf_map_fops, map,
4136e71b04aSChenbo Feng 				flags | O_CLOEXEC);
4146e71b04aSChenbo Feng }
4156e71b04aSChenbo Feng 
4166e71b04aSChenbo Feng int bpf_get_file_flag(int flags)
4176e71b04aSChenbo Feng {
4186e71b04aSChenbo Feng 	if ((flags & BPF_F_RDONLY) && (flags & BPF_F_WRONLY))
4196e71b04aSChenbo Feng 		return -EINVAL;
4206e71b04aSChenbo Feng 	if (flags & BPF_F_RDONLY)
4216e71b04aSChenbo Feng 		return O_RDONLY;
4226e71b04aSChenbo Feng 	if (flags & BPF_F_WRONLY)
4236e71b04aSChenbo Feng 		return O_WRONLY;
4246e71b04aSChenbo Feng 	return O_RDWR;
425aa79781bSDaniel Borkmann }
426aa79781bSDaniel Borkmann 
42799c55f7dSAlexei Starovoitov /* helper macro to check that unused fields 'union bpf_attr' are zero */
42899c55f7dSAlexei Starovoitov #define CHECK_ATTR(CMD) \
42999c55f7dSAlexei Starovoitov 	memchr_inv((void *) &attr->CMD##_LAST_FIELD + \
43099c55f7dSAlexei Starovoitov 		   sizeof(attr->CMD##_LAST_FIELD), 0, \
43199c55f7dSAlexei Starovoitov 		   sizeof(*attr) - \
43299c55f7dSAlexei Starovoitov 		   offsetof(union bpf_attr, CMD##_LAST_FIELD) - \
43399c55f7dSAlexei Starovoitov 		   sizeof(attr->CMD##_LAST_FIELD)) != NULL
43499c55f7dSAlexei Starovoitov 
435cb4d2b3fSMartin KaFai Lau /* dst and src must have at least BPF_OBJ_NAME_LEN number of bytes.
436cb4d2b3fSMartin KaFai Lau  * Return 0 on success and < 0 on error.
437cb4d2b3fSMartin KaFai Lau  */
438cb4d2b3fSMartin KaFai Lau static int bpf_obj_name_cpy(char *dst, const char *src)
439cb4d2b3fSMartin KaFai Lau {
440cb4d2b3fSMartin KaFai Lau 	const char *end = src + BPF_OBJ_NAME_LEN;
441cb4d2b3fSMartin KaFai Lau 
442473d9734SMartin KaFai Lau 	memset(dst, 0, BPF_OBJ_NAME_LEN);
443473d9734SMartin KaFai Lau 
444cb4d2b3fSMartin KaFai Lau 	/* Copy all isalnum() and '_' char */
445cb4d2b3fSMartin KaFai Lau 	while (src < end && *src) {
446cb4d2b3fSMartin KaFai Lau 		if (!isalnum(*src) && *src != '_')
447cb4d2b3fSMartin KaFai Lau 			return -EINVAL;
448cb4d2b3fSMartin KaFai Lau 		*dst++ = *src++;
449cb4d2b3fSMartin KaFai Lau 	}
450cb4d2b3fSMartin KaFai Lau 
451cb4d2b3fSMartin KaFai Lau 	/* No '\0' found in BPF_OBJ_NAME_LEN number of bytes */
452cb4d2b3fSMartin KaFai Lau 	if (src == end)
453cb4d2b3fSMartin KaFai Lau 		return -EINVAL;
454cb4d2b3fSMartin KaFai Lau 
455cb4d2b3fSMartin KaFai Lau 	return 0;
456cb4d2b3fSMartin KaFai Lau }
457cb4d2b3fSMartin KaFai Lau 
458e8d2bec0SDaniel Borkmann int map_check_no_btf(const struct bpf_map *map,
459e8d2bec0SDaniel Borkmann 		     const struct btf_type *key_type,
460e8d2bec0SDaniel Borkmann 		     const struct btf_type *value_type)
461e8d2bec0SDaniel Borkmann {
462e8d2bec0SDaniel Borkmann 	return -ENOTSUPP;
463e8d2bec0SDaniel Borkmann }
464e8d2bec0SDaniel Borkmann 
465e8d2bec0SDaniel Borkmann static int map_check_btf(const struct bpf_map *map, const struct btf *btf,
466e8d2bec0SDaniel Borkmann 			 u32 btf_key_id, u32 btf_value_id)
467e8d2bec0SDaniel Borkmann {
468e8d2bec0SDaniel Borkmann 	const struct btf_type *key_type, *value_type;
469e8d2bec0SDaniel Borkmann 	u32 key_size, value_size;
470e8d2bec0SDaniel Borkmann 	int ret = 0;
471e8d2bec0SDaniel Borkmann 
472e8d2bec0SDaniel Borkmann 	key_type = btf_type_id_size(btf, &btf_key_id, &key_size);
473e8d2bec0SDaniel Borkmann 	if (!key_type || key_size != map->key_size)
474e8d2bec0SDaniel Borkmann 		return -EINVAL;
475e8d2bec0SDaniel Borkmann 
476e8d2bec0SDaniel Borkmann 	value_type = btf_type_id_size(btf, &btf_value_id, &value_size);
477e8d2bec0SDaniel Borkmann 	if (!value_type || value_size != map->value_size)
478e8d2bec0SDaniel Borkmann 		return -EINVAL;
479e8d2bec0SDaniel Borkmann 
480e8d2bec0SDaniel Borkmann 	if (map->ops->map_check_btf)
481e8d2bec0SDaniel Borkmann 		ret = map->ops->map_check_btf(map, key_type, value_type);
482e8d2bec0SDaniel Borkmann 
483e8d2bec0SDaniel Borkmann 	return ret;
484e8d2bec0SDaniel Borkmann }
485e8d2bec0SDaniel Borkmann 
4869b2cf328SMartin KaFai Lau #define BPF_MAP_CREATE_LAST_FIELD btf_value_type_id
48799c55f7dSAlexei Starovoitov /* called via syscall */
48899c55f7dSAlexei Starovoitov static int map_create(union bpf_attr *attr)
48999c55f7dSAlexei Starovoitov {
49096eabe7aSMartin KaFai Lau 	int numa_node = bpf_map_attr_numa_node(attr);
49199c55f7dSAlexei Starovoitov 	struct bpf_map *map;
4926e71b04aSChenbo Feng 	int f_flags;
49399c55f7dSAlexei Starovoitov 	int err;
49499c55f7dSAlexei Starovoitov 
49599c55f7dSAlexei Starovoitov 	err = CHECK_ATTR(BPF_MAP_CREATE);
49699c55f7dSAlexei Starovoitov 	if (err)
49799c55f7dSAlexei Starovoitov 		return -EINVAL;
49899c55f7dSAlexei Starovoitov 
4996e71b04aSChenbo Feng 	f_flags = bpf_get_file_flag(attr->map_flags);
5006e71b04aSChenbo Feng 	if (f_flags < 0)
5016e71b04aSChenbo Feng 		return f_flags;
5026e71b04aSChenbo Feng 
50396eabe7aSMartin KaFai Lau 	if (numa_node != NUMA_NO_NODE &&
50496e5ae4eSEric Dumazet 	    ((unsigned int)numa_node >= nr_node_ids ||
50596e5ae4eSEric Dumazet 	     !node_online(numa_node)))
50696eabe7aSMartin KaFai Lau 		return -EINVAL;
50796eabe7aSMartin KaFai Lau 
50899c55f7dSAlexei Starovoitov 	/* find map type and init map: hashtable vs rbtree vs bloom vs ... */
50999c55f7dSAlexei Starovoitov 	map = find_and_alloc_map(attr);
51099c55f7dSAlexei Starovoitov 	if (IS_ERR(map))
51199c55f7dSAlexei Starovoitov 		return PTR_ERR(map);
51299c55f7dSAlexei Starovoitov 
513ad5b177bSMartin KaFai Lau 	err = bpf_obj_name_cpy(map->name, attr->map_name);
514ad5b177bSMartin KaFai Lau 	if (err)
515ad5b177bSMartin KaFai Lau 		goto free_map_nouncharge;
516ad5b177bSMartin KaFai Lau 
51799c55f7dSAlexei Starovoitov 	atomic_set(&map->refcnt, 1);
518c9da161cSDaniel Borkmann 	atomic_set(&map->usercnt, 1);
51999c55f7dSAlexei Starovoitov 
520e8d2bec0SDaniel Borkmann 	if (attr->btf_key_type_id || attr->btf_value_type_id) {
521a26ca7c9SMartin KaFai Lau 		struct btf *btf;
522a26ca7c9SMartin KaFai Lau 
5239b2cf328SMartin KaFai Lau 		if (!attr->btf_key_type_id || !attr->btf_value_type_id) {
524a26ca7c9SMartin KaFai Lau 			err = -EINVAL;
525a26ca7c9SMartin KaFai Lau 			goto free_map_nouncharge;
526a26ca7c9SMartin KaFai Lau 		}
527a26ca7c9SMartin KaFai Lau 
528a26ca7c9SMartin KaFai Lau 		btf = btf_get_by_fd(attr->btf_fd);
529a26ca7c9SMartin KaFai Lau 		if (IS_ERR(btf)) {
530a26ca7c9SMartin KaFai Lau 			err = PTR_ERR(btf);
531a26ca7c9SMartin KaFai Lau 			goto free_map_nouncharge;
532a26ca7c9SMartin KaFai Lau 		}
533a26ca7c9SMartin KaFai Lau 
534e8d2bec0SDaniel Borkmann 		err = map_check_btf(map, btf, attr->btf_key_type_id,
5359b2cf328SMartin KaFai Lau 				    attr->btf_value_type_id);
536a26ca7c9SMartin KaFai Lau 		if (err) {
537a26ca7c9SMartin KaFai Lau 			btf_put(btf);
538a26ca7c9SMartin KaFai Lau 			goto free_map_nouncharge;
539a26ca7c9SMartin KaFai Lau 		}
540a26ca7c9SMartin KaFai Lau 
541a26ca7c9SMartin KaFai Lau 		map->btf = btf;
5429b2cf328SMartin KaFai Lau 		map->btf_key_type_id = attr->btf_key_type_id;
5439b2cf328SMartin KaFai Lau 		map->btf_value_type_id = attr->btf_value_type_id;
544a26ca7c9SMartin KaFai Lau 	}
545a26ca7c9SMartin KaFai Lau 
546afdb09c7SChenbo Feng 	err = security_bpf_map_alloc(map);
547aaac3ba9SAlexei Starovoitov 	if (err)
54820b2b24fSDaniel Borkmann 		goto free_map_nouncharge;
549aaac3ba9SAlexei Starovoitov 
5500a4c58f5SRoman Gushchin 	err = bpf_map_init_memlock(map);
551afdb09c7SChenbo Feng 	if (err)
552afdb09c7SChenbo Feng 		goto free_map_sec;
553afdb09c7SChenbo Feng 
554f3f1c054SMartin KaFai Lau 	err = bpf_map_alloc_id(map);
555f3f1c054SMartin KaFai Lau 	if (err)
556f3f1c054SMartin KaFai Lau 		goto free_map;
557f3f1c054SMartin KaFai Lau 
5586e71b04aSChenbo Feng 	err = bpf_map_new_fd(map, f_flags);
559bd5f5f4eSMartin KaFai Lau 	if (err < 0) {
560bd5f5f4eSMartin KaFai Lau 		/* failed to allocate fd.
561bd5f5f4eSMartin KaFai Lau 		 * bpf_map_put() is needed because the above
562bd5f5f4eSMartin KaFai Lau 		 * bpf_map_alloc_id() has published the map
563bd5f5f4eSMartin KaFai Lau 		 * to the userspace and the userspace may
564bd5f5f4eSMartin KaFai Lau 		 * have refcnt-ed it through BPF_MAP_GET_FD_BY_ID.
565bd5f5f4eSMartin KaFai Lau 		 */
566bd5f5f4eSMartin KaFai Lau 		bpf_map_put(map);
567bd5f5f4eSMartin KaFai Lau 		return err;
568bd5f5f4eSMartin KaFai Lau 	}
56999c55f7dSAlexei Starovoitov 
57099c55f7dSAlexei Starovoitov 	return err;
57199c55f7dSAlexei Starovoitov 
57299c55f7dSAlexei Starovoitov free_map:
5730a4c58f5SRoman Gushchin 	bpf_map_release_memlock(map);
574afdb09c7SChenbo Feng free_map_sec:
575afdb09c7SChenbo Feng 	security_bpf_map_free(map);
57620b2b24fSDaniel Borkmann free_map_nouncharge:
577a26ca7c9SMartin KaFai Lau 	btf_put(map->btf);
57899c55f7dSAlexei Starovoitov 	map->ops->map_free(map);
57999c55f7dSAlexei Starovoitov 	return err;
58099c55f7dSAlexei Starovoitov }
58199c55f7dSAlexei Starovoitov 
582db20fd2bSAlexei Starovoitov /* if error is returned, fd is released.
583db20fd2bSAlexei Starovoitov  * On success caller should complete fd access with matching fdput()
584db20fd2bSAlexei Starovoitov  */
585c2101297SDaniel Borkmann struct bpf_map *__bpf_map_get(struct fd f)
586db20fd2bSAlexei Starovoitov {
587db20fd2bSAlexei Starovoitov 	if (!f.file)
588db20fd2bSAlexei Starovoitov 		return ERR_PTR(-EBADF);
589db20fd2bSAlexei Starovoitov 	if (f.file->f_op != &bpf_map_fops) {
590db20fd2bSAlexei Starovoitov 		fdput(f);
591db20fd2bSAlexei Starovoitov 		return ERR_PTR(-EINVAL);
592db20fd2bSAlexei Starovoitov 	}
593db20fd2bSAlexei Starovoitov 
594c2101297SDaniel Borkmann 	return f.file->private_data;
595c2101297SDaniel Borkmann }
596c2101297SDaniel Borkmann 
59792117d84SAlexei Starovoitov /* prog's and map's refcnt limit */
59892117d84SAlexei Starovoitov #define BPF_MAX_REFCNT 32768
59992117d84SAlexei Starovoitov 
60092117d84SAlexei Starovoitov struct bpf_map *bpf_map_inc(struct bpf_map *map, bool uref)
601c9da161cSDaniel Borkmann {
60292117d84SAlexei Starovoitov 	if (atomic_inc_return(&map->refcnt) > BPF_MAX_REFCNT) {
60392117d84SAlexei Starovoitov 		atomic_dec(&map->refcnt);
60492117d84SAlexei Starovoitov 		return ERR_PTR(-EBUSY);
60592117d84SAlexei Starovoitov 	}
606c9da161cSDaniel Borkmann 	if (uref)
607c9da161cSDaniel Borkmann 		atomic_inc(&map->usercnt);
60892117d84SAlexei Starovoitov 	return map;
609c9da161cSDaniel Borkmann }
610630a4d38SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_map_inc);
611c9da161cSDaniel Borkmann 
612c9da161cSDaniel Borkmann struct bpf_map *bpf_map_get_with_uref(u32 ufd)
613c2101297SDaniel Borkmann {
614c2101297SDaniel Borkmann 	struct fd f = fdget(ufd);
615c2101297SDaniel Borkmann 	struct bpf_map *map;
616c2101297SDaniel Borkmann 
617c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
618c2101297SDaniel Borkmann 	if (IS_ERR(map))
619c2101297SDaniel Borkmann 		return map;
620c2101297SDaniel Borkmann 
62192117d84SAlexei Starovoitov 	map = bpf_map_inc(map, true);
622c2101297SDaniel Borkmann 	fdput(f);
623db20fd2bSAlexei Starovoitov 
624db20fd2bSAlexei Starovoitov 	return map;
625db20fd2bSAlexei Starovoitov }
626db20fd2bSAlexei Starovoitov 
627bd5f5f4eSMartin KaFai Lau /* map_idr_lock should have been held */
628bd5f5f4eSMartin KaFai Lau static struct bpf_map *bpf_map_inc_not_zero(struct bpf_map *map,
629bd5f5f4eSMartin KaFai Lau 					    bool uref)
630bd5f5f4eSMartin KaFai Lau {
631bd5f5f4eSMartin KaFai Lau 	int refold;
632bd5f5f4eSMartin KaFai Lau 
633bfc18e38SMark Rutland 	refold = atomic_fetch_add_unless(&map->refcnt, 1, 0);
634bd5f5f4eSMartin KaFai Lau 
635bd5f5f4eSMartin KaFai Lau 	if (refold >= BPF_MAX_REFCNT) {
636bd5f5f4eSMartin KaFai Lau 		__bpf_map_put(map, false);
637bd5f5f4eSMartin KaFai Lau 		return ERR_PTR(-EBUSY);
638bd5f5f4eSMartin KaFai Lau 	}
639bd5f5f4eSMartin KaFai Lau 
640bd5f5f4eSMartin KaFai Lau 	if (!refold)
641bd5f5f4eSMartin KaFai Lau 		return ERR_PTR(-ENOENT);
642bd5f5f4eSMartin KaFai Lau 
643bd5f5f4eSMartin KaFai Lau 	if (uref)
644bd5f5f4eSMartin KaFai Lau 		atomic_inc(&map->usercnt);
645bd5f5f4eSMartin KaFai Lau 
646bd5f5f4eSMartin KaFai Lau 	return map;
647bd5f5f4eSMartin KaFai Lau }
648bd5f5f4eSMartin KaFai Lau 
649b8cdc051SAlexei Starovoitov int __weak bpf_stackmap_copy(struct bpf_map *map, void *key, void *value)
650b8cdc051SAlexei Starovoitov {
651b8cdc051SAlexei Starovoitov 	return -ENOTSUPP;
652b8cdc051SAlexei Starovoitov }
653b8cdc051SAlexei Starovoitov 
654c9d29f46SMauricio Vasquez B static void *__bpf_copy_key(void __user *ukey, u64 key_size)
655c9d29f46SMauricio Vasquez B {
656c9d29f46SMauricio Vasquez B 	if (key_size)
657c9d29f46SMauricio Vasquez B 		return memdup_user(ukey, key_size);
658c9d29f46SMauricio Vasquez B 
659c9d29f46SMauricio Vasquez B 	if (ukey)
660c9d29f46SMauricio Vasquez B 		return ERR_PTR(-EINVAL);
661c9d29f46SMauricio Vasquez B 
662c9d29f46SMauricio Vasquez B 	return NULL;
663c9d29f46SMauricio Vasquez B }
664c9d29f46SMauricio Vasquez B 
665db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
666db20fd2bSAlexei Starovoitov #define BPF_MAP_LOOKUP_ELEM_LAST_FIELD value
667db20fd2bSAlexei Starovoitov 
668db20fd2bSAlexei Starovoitov static int map_lookup_elem(union bpf_attr *attr)
669db20fd2bSAlexei Starovoitov {
670535e7b4bSMickaël Salaün 	void __user *ukey = u64_to_user_ptr(attr->key);
671535e7b4bSMickaël Salaün 	void __user *uvalue = u64_to_user_ptr(attr->value);
672db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
673db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
6748ebe667cSAlexei Starovoitov 	void *key, *value, *ptr;
67515a07b33SAlexei Starovoitov 	u32 value_size;
676592867bfSDaniel Borkmann 	struct fd f;
677db20fd2bSAlexei Starovoitov 	int err;
678db20fd2bSAlexei Starovoitov 
679db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM))
680db20fd2bSAlexei Starovoitov 		return -EINVAL;
681db20fd2bSAlexei Starovoitov 
682592867bfSDaniel Borkmann 	f = fdget(ufd);
683c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
684db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
685db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
686db20fd2bSAlexei Starovoitov 
6876e71b04aSChenbo Feng 	if (!(f.file->f_mode & FMODE_CAN_READ)) {
6886e71b04aSChenbo Feng 		err = -EPERM;
6896e71b04aSChenbo Feng 		goto err_put;
6906e71b04aSChenbo Feng 	}
6916e71b04aSChenbo Feng 
692c9d29f46SMauricio Vasquez B 	key = __bpf_copy_key(ukey, map->key_size);
693e4448ed8SAl Viro 	if (IS_ERR(key)) {
694e4448ed8SAl Viro 		err = PTR_ERR(key);
695db20fd2bSAlexei Starovoitov 		goto err_put;
696e4448ed8SAl Viro 	}
697db20fd2bSAlexei Starovoitov 
69815a07b33SAlexei Starovoitov 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
6998f844938SMartin KaFai Lau 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
700b741f163SRoman Gushchin 	    map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY ||
701b741f163SRoman Gushchin 	    map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE)
70215a07b33SAlexei Starovoitov 		value_size = round_up(map->value_size, 8) * num_possible_cpus();
70314dc6f04SMartin KaFai Lau 	else if (IS_FD_MAP(map))
70414dc6f04SMartin KaFai Lau 		value_size = sizeof(u32);
70515a07b33SAlexei Starovoitov 	else
70615a07b33SAlexei Starovoitov 		value_size = map->value_size;
70715a07b33SAlexei Starovoitov 
7088ebe667cSAlexei Starovoitov 	err = -ENOMEM;
70915a07b33SAlexei Starovoitov 	value = kmalloc(value_size, GFP_USER | __GFP_NOWARN);
710db20fd2bSAlexei Starovoitov 	if (!value)
7118ebe667cSAlexei Starovoitov 		goto free_key;
7128ebe667cSAlexei Starovoitov 
713a3884572SJakub Kicinski 	if (bpf_map_is_dev_bound(map)) {
714a3884572SJakub Kicinski 		err = bpf_map_offload_lookup_elem(map, key, value);
715a3884572SJakub Kicinski 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
7168f844938SMartin KaFai Lau 		   map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
71715a07b33SAlexei Starovoitov 		err = bpf_percpu_hash_copy(map, key, value);
71815a07b33SAlexei Starovoitov 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
71915a07b33SAlexei Starovoitov 		err = bpf_percpu_array_copy(map, key, value);
720b741f163SRoman Gushchin 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) {
721b741f163SRoman Gushchin 		err = bpf_percpu_cgroup_storage_copy(map, key, value);
722557c0c6eSAlexei Starovoitov 	} else if (map->map_type == BPF_MAP_TYPE_STACK_TRACE) {
723557c0c6eSAlexei Starovoitov 		err = bpf_stackmap_copy(map, key, value);
72414dc6f04SMartin KaFai Lau 	} else if (IS_FD_ARRAY(map)) {
72514dc6f04SMartin KaFai Lau 		err = bpf_fd_array_map_lookup_elem(map, key, value);
72614dc6f04SMartin KaFai Lau 	} else if (IS_FD_HASH(map)) {
72714dc6f04SMartin KaFai Lau 		err = bpf_fd_htab_map_lookup_elem(map, key, value);
7285dc4c4b7SMartin KaFai Lau 	} else if (map->map_type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY) {
7295dc4c4b7SMartin KaFai Lau 		err = bpf_fd_reuseport_array_lookup_elem(map, key, value);
730f1a2e44aSMauricio Vasquez B 	} else if (map->map_type == BPF_MAP_TYPE_QUEUE ||
731f1a2e44aSMauricio Vasquez B 		   map->map_type == BPF_MAP_TYPE_STACK) {
732f1a2e44aSMauricio Vasquez B 		err = map->ops->map_peek_elem(map, value);
73315a07b33SAlexei Starovoitov 	} else {
7348ebe667cSAlexei Starovoitov 		rcu_read_lock();
7358ebe667cSAlexei Starovoitov 		ptr = map->ops->map_lookup_elem(map, key);
736509db283SPrashant Bhole 		if (IS_ERR(ptr)) {
737509db283SPrashant Bhole 			err = PTR_ERR(ptr);
738509db283SPrashant Bhole 		} else if (!ptr) {
739509db283SPrashant Bhole 			err = -ENOENT;
740509db283SPrashant Bhole 		} else {
741509db283SPrashant Bhole 			err = 0;
74215a07b33SAlexei Starovoitov 			memcpy(value, ptr, value_size);
743509db283SPrashant Bhole 		}
7448ebe667cSAlexei Starovoitov 		rcu_read_unlock();
74515a07b33SAlexei Starovoitov 	}
7468ebe667cSAlexei Starovoitov 
74715a07b33SAlexei Starovoitov 	if (err)
7488ebe667cSAlexei Starovoitov 		goto free_value;
749db20fd2bSAlexei Starovoitov 
750db20fd2bSAlexei Starovoitov 	err = -EFAULT;
75115a07b33SAlexei Starovoitov 	if (copy_to_user(uvalue, value, value_size) != 0)
7528ebe667cSAlexei Starovoitov 		goto free_value;
753db20fd2bSAlexei Starovoitov 
754db20fd2bSAlexei Starovoitov 	err = 0;
755db20fd2bSAlexei Starovoitov 
7568ebe667cSAlexei Starovoitov free_value:
7578ebe667cSAlexei Starovoitov 	kfree(value);
758db20fd2bSAlexei Starovoitov free_key:
759db20fd2bSAlexei Starovoitov 	kfree(key);
760db20fd2bSAlexei Starovoitov err_put:
761db20fd2bSAlexei Starovoitov 	fdput(f);
762db20fd2bSAlexei Starovoitov 	return err;
763db20fd2bSAlexei Starovoitov }
764db20fd2bSAlexei Starovoitov 
7651ae80cf3SDaniel Colascione static void maybe_wait_bpf_programs(struct bpf_map *map)
7661ae80cf3SDaniel Colascione {
7671ae80cf3SDaniel Colascione 	/* Wait for any running BPF programs to complete so that
7681ae80cf3SDaniel Colascione 	 * userspace, when we return to it, knows that all programs
7691ae80cf3SDaniel Colascione 	 * that could be running use the new map value.
7701ae80cf3SDaniel Colascione 	 */
7711ae80cf3SDaniel Colascione 	if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS ||
7721ae80cf3SDaniel Colascione 	    map->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS)
7731ae80cf3SDaniel Colascione 		synchronize_rcu();
7741ae80cf3SDaniel Colascione }
7751ae80cf3SDaniel Colascione 
7763274f520SAlexei Starovoitov #define BPF_MAP_UPDATE_ELEM_LAST_FIELD flags
777db20fd2bSAlexei Starovoitov 
778db20fd2bSAlexei Starovoitov static int map_update_elem(union bpf_attr *attr)
779db20fd2bSAlexei Starovoitov {
780535e7b4bSMickaël Salaün 	void __user *ukey = u64_to_user_ptr(attr->key);
781535e7b4bSMickaël Salaün 	void __user *uvalue = u64_to_user_ptr(attr->value);
782db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
783db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
784db20fd2bSAlexei Starovoitov 	void *key, *value;
78515a07b33SAlexei Starovoitov 	u32 value_size;
786592867bfSDaniel Borkmann 	struct fd f;
787db20fd2bSAlexei Starovoitov 	int err;
788db20fd2bSAlexei Starovoitov 
789db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_UPDATE_ELEM))
790db20fd2bSAlexei Starovoitov 		return -EINVAL;
791db20fd2bSAlexei Starovoitov 
792592867bfSDaniel Borkmann 	f = fdget(ufd);
793c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
794db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
795db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
796db20fd2bSAlexei Starovoitov 
7976e71b04aSChenbo Feng 	if (!(f.file->f_mode & FMODE_CAN_WRITE)) {
7986e71b04aSChenbo Feng 		err = -EPERM;
7996e71b04aSChenbo Feng 		goto err_put;
8006e71b04aSChenbo Feng 	}
8016e71b04aSChenbo Feng 
802c9d29f46SMauricio Vasquez B 	key = __bpf_copy_key(ukey, map->key_size);
803e4448ed8SAl Viro 	if (IS_ERR(key)) {
804e4448ed8SAl Viro 		err = PTR_ERR(key);
805db20fd2bSAlexei Starovoitov 		goto err_put;
806e4448ed8SAl Viro 	}
807db20fd2bSAlexei Starovoitov 
80815a07b33SAlexei Starovoitov 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
8098f844938SMartin KaFai Lau 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
810b741f163SRoman Gushchin 	    map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY ||
811b741f163SRoman Gushchin 	    map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE)
81215a07b33SAlexei Starovoitov 		value_size = round_up(map->value_size, 8) * num_possible_cpus();
81315a07b33SAlexei Starovoitov 	else
81415a07b33SAlexei Starovoitov 		value_size = map->value_size;
81515a07b33SAlexei Starovoitov 
816db20fd2bSAlexei Starovoitov 	err = -ENOMEM;
81715a07b33SAlexei Starovoitov 	value = kmalloc(value_size, GFP_USER | __GFP_NOWARN);
818db20fd2bSAlexei Starovoitov 	if (!value)
819db20fd2bSAlexei Starovoitov 		goto free_key;
820db20fd2bSAlexei Starovoitov 
821db20fd2bSAlexei Starovoitov 	err = -EFAULT;
82215a07b33SAlexei Starovoitov 	if (copy_from_user(value, uvalue, value_size) != 0)
823db20fd2bSAlexei Starovoitov 		goto free_value;
824db20fd2bSAlexei Starovoitov 
8256710e112SJesper Dangaard Brouer 	/* Need to create a kthread, thus must support schedule */
826a3884572SJakub Kicinski 	if (bpf_map_is_dev_bound(map)) {
827a3884572SJakub Kicinski 		err = bpf_map_offload_update_elem(map, key, value, attr->flags);
828a3884572SJakub Kicinski 		goto out;
82999ba2b5aSJohn Fastabend 	} else if (map->map_type == BPF_MAP_TYPE_CPUMAP ||
83099ba2b5aSJohn Fastabend 		   map->map_type == BPF_MAP_TYPE_SOCKHASH ||
83199ba2b5aSJohn Fastabend 		   map->map_type == BPF_MAP_TYPE_SOCKMAP) {
8326710e112SJesper Dangaard Brouer 		err = map->ops->map_update_elem(map, key, value, attr->flags);
8336710e112SJesper Dangaard Brouer 		goto out;
8346710e112SJesper Dangaard Brouer 	}
8356710e112SJesper Dangaard Brouer 
836b121d1e7SAlexei Starovoitov 	/* must increment bpf_prog_active to avoid kprobe+bpf triggering from
837b121d1e7SAlexei Starovoitov 	 * inside bpf map update or delete otherwise deadlocks are possible
838b121d1e7SAlexei Starovoitov 	 */
839b121d1e7SAlexei Starovoitov 	preempt_disable();
840b121d1e7SAlexei Starovoitov 	__this_cpu_inc(bpf_prog_active);
8418f844938SMartin KaFai Lau 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
8428f844938SMartin KaFai Lau 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
84315a07b33SAlexei Starovoitov 		err = bpf_percpu_hash_update(map, key, value, attr->flags);
84415a07b33SAlexei Starovoitov 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
84515a07b33SAlexei Starovoitov 		err = bpf_percpu_array_update(map, key, value, attr->flags);
846b741f163SRoman Gushchin 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) {
847b741f163SRoman Gushchin 		err = bpf_percpu_cgroup_storage_update(map, key, value,
848b741f163SRoman Gushchin 						       attr->flags);
8499c147b56SMickaël Salaün 	} else if (IS_FD_ARRAY(map)) {
850d056a788SDaniel Borkmann 		rcu_read_lock();
851d056a788SDaniel Borkmann 		err = bpf_fd_array_map_update_elem(map, f.file, key, value,
852d056a788SDaniel Borkmann 						   attr->flags);
853d056a788SDaniel Borkmann 		rcu_read_unlock();
854bcc6b1b7SMartin KaFai Lau 	} else if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) {
855bcc6b1b7SMartin KaFai Lau 		rcu_read_lock();
856bcc6b1b7SMartin KaFai Lau 		err = bpf_fd_htab_map_update_elem(map, f.file, key, value,
857bcc6b1b7SMartin KaFai Lau 						  attr->flags);
858bcc6b1b7SMartin KaFai Lau 		rcu_read_unlock();
8595dc4c4b7SMartin KaFai Lau 	} else if (map->map_type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY) {
8605dc4c4b7SMartin KaFai Lau 		/* rcu_read_lock() is not needed */
8615dc4c4b7SMartin KaFai Lau 		err = bpf_fd_reuseport_array_update_elem(map, key, value,
8625dc4c4b7SMartin KaFai Lau 							 attr->flags);
863f1a2e44aSMauricio Vasquez B 	} else if (map->map_type == BPF_MAP_TYPE_QUEUE ||
864f1a2e44aSMauricio Vasquez B 		   map->map_type == BPF_MAP_TYPE_STACK) {
865f1a2e44aSMauricio Vasquez B 		err = map->ops->map_push_elem(map, value, attr->flags);
86615a07b33SAlexei Starovoitov 	} else {
867db20fd2bSAlexei Starovoitov 		rcu_read_lock();
8683274f520SAlexei Starovoitov 		err = map->ops->map_update_elem(map, key, value, attr->flags);
869db20fd2bSAlexei Starovoitov 		rcu_read_unlock();
87015a07b33SAlexei Starovoitov 	}
871b121d1e7SAlexei Starovoitov 	__this_cpu_dec(bpf_prog_active);
872b121d1e7SAlexei Starovoitov 	preempt_enable();
8731ae80cf3SDaniel Colascione 	maybe_wait_bpf_programs(map);
8746710e112SJesper Dangaard Brouer out:
875db20fd2bSAlexei Starovoitov free_value:
876db20fd2bSAlexei Starovoitov 	kfree(value);
877db20fd2bSAlexei Starovoitov free_key:
878db20fd2bSAlexei Starovoitov 	kfree(key);
879db20fd2bSAlexei Starovoitov err_put:
880db20fd2bSAlexei Starovoitov 	fdput(f);
881db20fd2bSAlexei Starovoitov 	return err;
882db20fd2bSAlexei Starovoitov }
883db20fd2bSAlexei Starovoitov 
884db20fd2bSAlexei Starovoitov #define BPF_MAP_DELETE_ELEM_LAST_FIELD key
885db20fd2bSAlexei Starovoitov 
886db20fd2bSAlexei Starovoitov static int map_delete_elem(union bpf_attr *attr)
887db20fd2bSAlexei Starovoitov {
888535e7b4bSMickaël Salaün 	void __user *ukey = u64_to_user_ptr(attr->key);
889db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
890db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
891592867bfSDaniel Borkmann 	struct fd f;
892db20fd2bSAlexei Starovoitov 	void *key;
893db20fd2bSAlexei Starovoitov 	int err;
894db20fd2bSAlexei Starovoitov 
895db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_DELETE_ELEM))
896db20fd2bSAlexei Starovoitov 		return -EINVAL;
897db20fd2bSAlexei Starovoitov 
898592867bfSDaniel Borkmann 	f = fdget(ufd);
899c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
900db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
901db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
902db20fd2bSAlexei Starovoitov 
9036e71b04aSChenbo Feng 	if (!(f.file->f_mode & FMODE_CAN_WRITE)) {
9046e71b04aSChenbo Feng 		err = -EPERM;
9056e71b04aSChenbo Feng 		goto err_put;
9066e71b04aSChenbo Feng 	}
9076e71b04aSChenbo Feng 
908c9d29f46SMauricio Vasquez B 	key = __bpf_copy_key(ukey, map->key_size);
909e4448ed8SAl Viro 	if (IS_ERR(key)) {
910e4448ed8SAl Viro 		err = PTR_ERR(key);
911db20fd2bSAlexei Starovoitov 		goto err_put;
912e4448ed8SAl Viro 	}
913db20fd2bSAlexei Starovoitov 
914a3884572SJakub Kicinski 	if (bpf_map_is_dev_bound(map)) {
915a3884572SJakub Kicinski 		err = bpf_map_offload_delete_elem(map, key);
916a3884572SJakub Kicinski 		goto out;
917a3884572SJakub Kicinski 	}
918a3884572SJakub Kicinski 
919b121d1e7SAlexei Starovoitov 	preempt_disable();
920b121d1e7SAlexei Starovoitov 	__this_cpu_inc(bpf_prog_active);
921db20fd2bSAlexei Starovoitov 	rcu_read_lock();
922db20fd2bSAlexei Starovoitov 	err = map->ops->map_delete_elem(map, key);
923db20fd2bSAlexei Starovoitov 	rcu_read_unlock();
924b121d1e7SAlexei Starovoitov 	__this_cpu_dec(bpf_prog_active);
925b121d1e7SAlexei Starovoitov 	preempt_enable();
9261ae80cf3SDaniel Colascione 	maybe_wait_bpf_programs(map);
927a3884572SJakub Kicinski out:
928db20fd2bSAlexei Starovoitov 	kfree(key);
929db20fd2bSAlexei Starovoitov err_put:
930db20fd2bSAlexei Starovoitov 	fdput(f);
931db20fd2bSAlexei Starovoitov 	return err;
932db20fd2bSAlexei Starovoitov }
933db20fd2bSAlexei Starovoitov 
934db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
935db20fd2bSAlexei Starovoitov #define BPF_MAP_GET_NEXT_KEY_LAST_FIELD next_key
936db20fd2bSAlexei Starovoitov 
937db20fd2bSAlexei Starovoitov static int map_get_next_key(union bpf_attr *attr)
938db20fd2bSAlexei Starovoitov {
939535e7b4bSMickaël Salaün 	void __user *ukey = u64_to_user_ptr(attr->key);
940535e7b4bSMickaël Salaün 	void __user *unext_key = u64_to_user_ptr(attr->next_key);
941db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
942db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
943db20fd2bSAlexei Starovoitov 	void *key, *next_key;
944592867bfSDaniel Borkmann 	struct fd f;
945db20fd2bSAlexei Starovoitov 	int err;
946db20fd2bSAlexei Starovoitov 
947db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_GET_NEXT_KEY))
948db20fd2bSAlexei Starovoitov 		return -EINVAL;
949db20fd2bSAlexei Starovoitov 
950592867bfSDaniel Borkmann 	f = fdget(ufd);
951c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
952db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
953db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
954db20fd2bSAlexei Starovoitov 
9556e71b04aSChenbo Feng 	if (!(f.file->f_mode & FMODE_CAN_READ)) {
9566e71b04aSChenbo Feng 		err = -EPERM;
9576e71b04aSChenbo Feng 		goto err_put;
9586e71b04aSChenbo Feng 	}
9596e71b04aSChenbo Feng 
9608fe45924STeng Qin 	if (ukey) {
961c9d29f46SMauricio Vasquez B 		key = __bpf_copy_key(ukey, map->key_size);
962e4448ed8SAl Viro 		if (IS_ERR(key)) {
963e4448ed8SAl Viro 			err = PTR_ERR(key);
964db20fd2bSAlexei Starovoitov 			goto err_put;
965e4448ed8SAl Viro 		}
9668fe45924STeng Qin 	} else {
9678fe45924STeng Qin 		key = NULL;
9688fe45924STeng Qin 	}
969db20fd2bSAlexei Starovoitov 
970db20fd2bSAlexei Starovoitov 	err = -ENOMEM;
971db20fd2bSAlexei Starovoitov 	next_key = kmalloc(map->key_size, GFP_USER);
972db20fd2bSAlexei Starovoitov 	if (!next_key)
973db20fd2bSAlexei Starovoitov 		goto free_key;
974db20fd2bSAlexei Starovoitov 
975a3884572SJakub Kicinski 	if (bpf_map_is_dev_bound(map)) {
976a3884572SJakub Kicinski 		err = bpf_map_offload_get_next_key(map, key, next_key);
977a3884572SJakub Kicinski 		goto out;
978a3884572SJakub Kicinski 	}
979a3884572SJakub Kicinski 
980db20fd2bSAlexei Starovoitov 	rcu_read_lock();
981db20fd2bSAlexei Starovoitov 	err = map->ops->map_get_next_key(map, key, next_key);
982db20fd2bSAlexei Starovoitov 	rcu_read_unlock();
983a3884572SJakub Kicinski out:
984db20fd2bSAlexei Starovoitov 	if (err)
985db20fd2bSAlexei Starovoitov 		goto free_next_key;
986db20fd2bSAlexei Starovoitov 
987db20fd2bSAlexei Starovoitov 	err = -EFAULT;
988db20fd2bSAlexei Starovoitov 	if (copy_to_user(unext_key, next_key, map->key_size) != 0)
989db20fd2bSAlexei Starovoitov 		goto free_next_key;
990db20fd2bSAlexei Starovoitov 
991db20fd2bSAlexei Starovoitov 	err = 0;
992db20fd2bSAlexei Starovoitov 
993db20fd2bSAlexei Starovoitov free_next_key:
994db20fd2bSAlexei Starovoitov 	kfree(next_key);
995db20fd2bSAlexei Starovoitov free_key:
996db20fd2bSAlexei Starovoitov 	kfree(key);
997db20fd2bSAlexei Starovoitov err_put:
998db20fd2bSAlexei Starovoitov 	fdput(f);
999db20fd2bSAlexei Starovoitov 	return err;
1000db20fd2bSAlexei Starovoitov }
1001db20fd2bSAlexei Starovoitov 
1002bd513cd0SMauricio Vasquez B #define BPF_MAP_LOOKUP_AND_DELETE_ELEM_LAST_FIELD value
1003bd513cd0SMauricio Vasquez B 
1004bd513cd0SMauricio Vasquez B static int map_lookup_and_delete_elem(union bpf_attr *attr)
1005bd513cd0SMauricio Vasquez B {
1006bd513cd0SMauricio Vasquez B 	void __user *ukey = u64_to_user_ptr(attr->key);
1007bd513cd0SMauricio Vasquez B 	void __user *uvalue = u64_to_user_ptr(attr->value);
1008bd513cd0SMauricio Vasquez B 	int ufd = attr->map_fd;
1009bd513cd0SMauricio Vasquez B 	struct bpf_map *map;
1010*540fefc0SAlexei Starovoitov 	void *key, *value;
1011bd513cd0SMauricio Vasquez B 	u32 value_size;
1012bd513cd0SMauricio Vasquez B 	struct fd f;
1013bd513cd0SMauricio Vasquez B 	int err;
1014bd513cd0SMauricio Vasquez B 
1015bd513cd0SMauricio Vasquez B 	if (CHECK_ATTR(BPF_MAP_LOOKUP_AND_DELETE_ELEM))
1016bd513cd0SMauricio Vasquez B 		return -EINVAL;
1017bd513cd0SMauricio Vasquez B 
1018bd513cd0SMauricio Vasquez B 	f = fdget(ufd);
1019bd513cd0SMauricio Vasquez B 	map = __bpf_map_get(f);
1020bd513cd0SMauricio Vasquez B 	if (IS_ERR(map))
1021bd513cd0SMauricio Vasquez B 		return PTR_ERR(map);
1022bd513cd0SMauricio Vasquez B 
1023bd513cd0SMauricio Vasquez B 	if (!(f.file->f_mode & FMODE_CAN_WRITE)) {
1024bd513cd0SMauricio Vasquez B 		err = -EPERM;
1025bd513cd0SMauricio Vasquez B 		goto err_put;
1026bd513cd0SMauricio Vasquez B 	}
1027bd513cd0SMauricio Vasquez B 
1028bd513cd0SMauricio Vasquez B 	key = __bpf_copy_key(ukey, map->key_size);
1029bd513cd0SMauricio Vasquez B 	if (IS_ERR(key)) {
1030bd513cd0SMauricio Vasquez B 		err = PTR_ERR(key);
1031bd513cd0SMauricio Vasquez B 		goto err_put;
1032bd513cd0SMauricio Vasquez B 	}
1033bd513cd0SMauricio Vasquez B 
1034bd513cd0SMauricio Vasquez B 	value_size = map->value_size;
1035bd513cd0SMauricio Vasquez B 
1036bd513cd0SMauricio Vasquez B 	err = -ENOMEM;
1037bd513cd0SMauricio Vasquez B 	value = kmalloc(value_size, GFP_USER | __GFP_NOWARN);
1038bd513cd0SMauricio Vasquez B 	if (!value)
1039bd513cd0SMauricio Vasquez B 		goto free_key;
1040bd513cd0SMauricio Vasquez B 
1041bd513cd0SMauricio Vasquez B 	if (map->map_type == BPF_MAP_TYPE_QUEUE ||
1042bd513cd0SMauricio Vasquez B 	    map->map_type == BPF_MAP_TYPE_STACK) {
1043bd513cd0SMauricio Vasquez B 		err = map->ops->map_pop_elem(map, value);
1044bd513cd0SMauricio Vasquez B 	} else {
1045bd513cd0SMauricio Vasquez B 		err = -ENOTSUPP;
1046bd513cd0SMauricio Vasquez B 	}
1047bd513cd0SMauricio Vasquez B 
1048bd513cd0SMauricio Vasquez B 	if (err)
1049bd513cd0SMauricio Vasquez B 		goto free_value;
1050bd513cd0SMauricio Vasquez B 
1051bd513cd0SMauricio Vasquez B 	if (copy_to_user(uvalue, value, value_size) != 0)
1052bd513cd0SMauricio Vasquez B 		goto free_value;
1053bd513cd0SMauricio Vasquez B 
1054bd513cd0SMauricio Vasquez B 	err = 0;
1055bd513cd0SMauricio Vasquez B 
1056bd513cd0SMauricio Vasquez B free_value:
1057bd513cd0SMauricio Vasquez B 	kfree(value);
1058bd513cd0SMauricio Vasquez B free_key:
1059bd513cd0SMauricio Vasquez B 	kfree(key);
1060bd513cd0SMauricio Vasquez B err_put:
1061bd513cd0SMauricio Vasquez B 	fdput(f);
1062bd513cd0SMauricio Vasquez B 	return err;
1063bd513cd0SMauricio Vasquez B }
1064bd513cd0SMauricio Vasquez B 
10657de16e3aSJakub Kicinski static const struct bpf_prog_ops * const bpf_prog_types[] = {
10667de16e3aSJakub Kicinski #define BPF_PROG_TYPE(_id, _name) \
10677de16e3aSJakub Kicinski 	[_id] = & _name ## _prog_ops,
10687de16e3aSJakub Kicinski #define BPF_MAP_TYPE(_id, _ops)
10697de16e3aSJakub Kicinski #include <linux/bpf_types.h>
10707de16e3aSJakub Kicinski #undef BPF_PROG_TYPE
10717de16e3aSJakub Kicinski #undef BPF_MAP_TYPE
10727de16e3aSJakub Kicinski };
10737de16e3aSJakub Kicinski 
107409756af4SAlexei Starovoitov static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog)
107509756af4SAlexei Starovoitov {
1076d0f1a451SDaniel Borkmann 	const struct bpf_prog_ops *ops;
1077d0f1a451SDaniel Borkmann 
1078d0f1a451SDaniel Borkmann 	if (type >= ARRAY_SIZE(bpf_prog_types))
1079d0f1a451SDaniel Borkmann 		return -EINVAL;
1080d0f1a451SDaniel Borkmann 	type = array_index_nospec(type, ARRAY_SIZE(bpf_prog_types));
1081d0f1a451SDaniel Borkmann 	ops = bpf_prog_types[type];
1082d0f1a451SDaniel Borkmann 	if (!ops)
1083be9370a7SJohannes Berg 		return -EINVAL;
108409756af4SAlexei Starovoitov 
1085ab3f0063SJakub Kicinski 	if (!bpf_prog_is_dev_bound(prog->aux))
1086d0f1a451SDaniel Borkmann 		prog->aux->ops = ops;
1087ab3f0063SJakub Kicinski 	else
1088ab3f0063SJakub Kicinski 		prog->aux->ops = &bpf_offload_prog_ops;
108924701eceSDaniel Borkmann 	prog->type = type;
109009756af4SAlexei Starovoitov 	return 0;
109109756af4SAlexei Starovoitov }
109209756af4SAlexei Starovoitov 
109309756af4SAlexei Starovoitov /* drop refcnt on maps used by eBPF program and free auxilary data */
109409756af4SAlexei Starovoitov static void free_used_maps(struct bpf_prog_aux *aux)
109509756af4SAlexei Starovoitov {
10968bad74f9SRoman Gushchin 	enum bpf_cgroup_storage_type stype;
109709756af4SAlexei Starovoitov 	int i;
109809756af4SAlexei Starovoitov 
10998bad74f9SRoman Gushchin 	for_each_cgroup_storage_type(stype) {
11008bad74f9SRoman Gushchin 		if (!aux->cgroup_storage[stype])
11018bad74f9SRoman Gushchin 			continue;
11028bad74f9SRoman Gushchin 		bpf_cgroup_storage_release(aux->prog,
11038bad74f9SRoman Gushchin 					   aux->cgroup_storage[stype]);
11048bad74f9SRoman Gushchin 	}
1105de9cbbaaSRoman Gushchin 
110609756af4SAlexei Starovoitov 	for (i = 0; i < aux->used_map_cnt; i++)
110709756af4SAlexei Starovoitov 		bpf_map_put(aux->used_maps[i]);
110809756af4SAlexei Starovoitov 
110909756af4SAlexei Starovoitov 	kfree(aux->used_maps);
111009756af4SAlexei Starovoitov }
111109756af4SAlexei Starovoitov 
11125ccb071eSDaniel Borkmann int __bpf_prog_charge(struct user_struct *user, u32 pages)
11135ccb071eSDaniel Borkmann {
11145ccb071eSDaniel Borkmann 	unsigned long memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
11155ccb071eSDaniel Borkmann 	unsigned long user_bufs;
11165ccb071eSDaniel Borkmann 
11175ccb071eSDaniel Borkmann 	if (user) {
11185ccb071eSDaniel Borkmann 		user_bufs = atomic_long_add_return(pages, &user->locked_vm);
11195ccb071eSDaniel Borkmann 		if (user_bufs > memlock_limit) {
11205ccb071eSDaniel Borkmann 			atomic_long_sub(pages, &user->locked_vm);
11215ccb071eSDaniel Borkmann 			return -EPERM;
11225ccb071eSDaniel Borkmann 		}
11235ccb071eSDaniel Borkmann 	}
11245ccb071eSDaniel Borkmann 
11255ccb071eSDaniel Borkmann 	return 0;
11265ccb071eSDaniel Borkmann }
11275ccb071eSDaniel Borkmann 
11285ccb071eSDaniel Borkmann void __bpf_prog_uncharge(struct user_struct *user, u32 pages)
11295ccb071eSDaniel Borkmann {
11305ccb071eSDaniel Borkmann 	if (user)
11315ccb071eSDaniel Borkmann 		atomic_long_sub(pages, &user->locked_vm);
11325ccb071eSDaniel Borkmann }
11335ccb071eSDaniel Borkmann 
1134aaac3ba9SAlexei Starovoitov static int bpf_prog_charge_memlock(struct bpf_prog *prog)
1135aaac3ba9SAlexei Starovoitov {
1136aaac3ba9SAlexei Starovoitov 	struct user_struct *user = get_current_user();
11375ccb071eSDaniel Borkmann 	int ret;
1138aaac3ba9SAlexei Starovoitov 
11395ccb071eSDaniel Borkmann 	ret = __bpf_prog_charge(user, prog->pages);
11405ccb071eSDaniel Borkmann 	if (ret) {
1141aaac3ba9SAlexei Starovoitov 		free_uid(user);
11425ccb071eSDaniel Borkmann 		return ret;
1143aaac3ba9SAlexei Starovoitov 	}
11445ccb071eSDaniel Borkmann 
1145aaac3ba9SAlexei Starovoitov 	prog->aux->user = user;
1146aaac3ba9SAlexei Starovoitov 	return 0;
1147aaac3ba9SAlexei Starovoitov }
1148aaac3ba9SAlexei Starovoitov 
1149aaac3ba9SAlexei Starovoitov static void bpf_prog_uncharge_memlock(struct bpf_prog *prog)
1150aaac3ba9SAlexei Starovoitov {
1151aaac3ba9SAlexei Starovoitov 	struct user_struct *user = prog->aux->user;
1152aaac3ba9SAlexei Starovoitov 
11535ccb071eSDaniel Borkmann 	__bpf_prog_uncharge(user, prog->pages);
1154aaac3ba9SAlexei Starovoitov 	free_uid(user);
1155aaac3ba9SAlexei Starovoitov }
1156aaac3ba9SAlexei Starovoitov 
1157dc4bb0e2SMartin KaFai Lau static int bpf_prog_alloc_id(struct bpf_prog *prog)
1158dc4bb0e2SMartin KaFai Lau {
1159dc4bb0e2SMartin KaFai Lau 	int id;
1160dc4bb0e2SMartin KaFai Lau 
1161b76354cdSShaohua Li 	idr_preload(GFP_KERNEL);
1162dc4bb0e2SMartin KaFai Lau 	spin_lock_bh(&prog_idr_lock);
1163dc4bb0e2SMartin KaFai Lau 	id = idr_alloc_cyclic(&prog_idr, prog, 1, INT_MAX, GFP_ATOMIC);
1164dc4bb0e2SMartin KaFai Lau 	if (id > 0)
1165dc4bb0e2SMartin KaFai Lau 		prog->aux->id = id;
1166dc4bb0e2SMartin KaFai Lau 	spin_unlock_bh(&prog_idr_lock);
1167b76354cdSShaohua Li 	idr_preload_end();
1168dc4bb0e2SMartin KaFai Lau 
1169dc4bb0e2SMartin KaFai Lau 	/* id is in [1, INT_MAX) */
1170dc4bb0e2SMartin KaFai Lau 	if (WARN_ON_ONCE(!id))
1171dc4bb0e2SMartin KaFai Lau 		return -ENOSPC;
1172dc4bb0e2SMartin KaFai Lau 
1173dc4bb0e2SMartin KaFai Lau 	return id > 0 ? 0 : id;
1174dc4bb0e2SMartin KaFai Lau }
1175dc4bb0e2SMartin KaFai Lau 
1176ad8ad79fSJakub Kicinski void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock)
1177dc4bb0e2SMartin KaFai Lau {
1178ad8ad79fSJakub Kicinski 	/* cBPF to eBPF migrations are currently not in the idr store.
1179ad8ad79fSJakub Kicinski 	 * Offloaded programs are removed from the store when their device
1180ad8ad79fSJakub Kicinski 	 * disappears - even if someone grabs an fd to them they are unusable,
1181ad8ad79fSJakub Kicinski 	 * simply waiting for refcnt to drop to be freed.
1182ad8ad79fSJakub Kicinski 	 */
1183dc4bb0e2SMartin KaFai Lau 	if (!prog->aux->id)
1184dc4bb0e2SMartin KaFai Lau 		return;
1185dc4bb0e2SMartin KaFai Lau 
1186b16d9aa4SMartin KaFai Lau 	if (do_idr_lock)
1187dc4bb0e2SMartin KaFai Lau 		spin_lock_bh(&prog_idr_lock);
1188b16d9aa4SMartin KaFai Lau 	else
1189b16d9aa4SMartin KaFai Lau 		__acquire(&prog_idr_lock);
1190b16d9aa4SMartin KaFai Lau 
1191dc4bb0e2SMartin KaFai Lau 	idr_remove(&prog_idr, prog->aux->id);
1192ad8ad79fSJakub Kicinski 	prog->aux->id = 0;
1193b16d9aa4SMartin KaFai Lau 
1194b16d9aa4SMartin KaFai Lau 	if (do_idr_lock)
1195dc4bb0e2SMartin KaFai Lau 		spin_unlock_bh(&prog_idr_lock);
1196b16d9aa4SMartin KaFai Lau 	else
1197b16d9aa4SMartin KaFai Lau 		__release(&prog_idr_lock);
1198dc4bb0e2SMartin KaFai Lau }
1199dc4bb0e2SMartin KaFai Lau 
12001aacde3dSDaniel Borkmann static void __bpf_prog_put_rcu(struct rcu_head *rcu)
1201abf2e7d6SAlexei Starovoitov {
1202abf2e7d6SAlexei Starovoitov 	struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu);
1203abf2e7d6SAlexei Starovoitov 
1204abf2e7d6SAlexei Starovoitov 	free_used_maps(aux);
1205aaac3ba9SAlexei Starovoitov 	bpf_prog_uncharge_memlock(aux->prog);
1206afdb09c7SChenbo Feng 	security_bpf_prog_free(aux);
1207abf2e7d6SAlexei Starovoitov 	bpf_prog_free(aux->prog);
1208abf2e7d6SAlexei Starovoitov }
1209abf2e7d6SAlexei Starovoitov 
1210b16d9aa4SMartin KaFai Lau static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock)
121109756af4SAlexei Starovoitov {
1212a67edbf4SDaniel Borkmann 	if (atomic_dec_and_test(&prog->aux->refcnt)) {
121334ad5580SMartin KaFai Lau 		/* bpf_prog_free_id() must be called first */
1214b16d9aa4SMartin KaFai Lau 		bpf_prog_free_id(prog, do_idr_lock);
12157d1982b4SDaniel Borkmann 		bpf_prog_kallsyms_del_all(prog);
12164f74d809SDaniel Borkmann 
12171aacde3dSDaniel Borkmann 		call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu);
121809756af4SAlexei Starovoitov 	}
1219a67edbf4SDaniel Borkmann }
1220b16d9aa4SMartin KaFai Lau 
1221b16d9aa4SMartin KaFai Lau void bpf_prog_put(struct bpf_prog *prog)
1222b16d9aa4SMartin KaFai Lau {
1223b16d9aa4SMartin KaFai Lau 	__bpf_prog_put(prog, true);
1224b16d9aa4SMartin KaFai Lau }
1225e2e9b654SDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_put);
122609756af4SAlexei Starovoitov 
122709756af4SAlexei Starovoitov static int bpf_prog_release(struct inode *inode, struct file *filp)
122809756af4SAlexei Starovoitov {
122909756af4SAlexei Starovoitov 	struct bpf_prog *prog = filp->private_data;
123009756af4SAlexei Starovoitov 
12311aacde3dSDaniel Borkmann 	bpf_prog_put(prog);
123209756af4SAlexei Starovoitov 	return 0;
123309756af4SAlexei Starovoitov }
123409756af4SAlexei Starovoitov 
12357bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS
12367bd509e3SDaniel Borkmann static void bpf_prog_show_fdinfo(struct seq_file *m, struct file *filp)
12377bd509e3SDaniel Borkmann {
12387bd509e3SDaniel Borkmann 	const struct bpf_prog *prog = filp->private_data;
1239f1f7714eSDaniel Borkmann 	char prog_tag[sizeof(prog->tag) * 2 + 1] = { };
12407bd509e3SDaniel Borkmann 
1241f1f7714eSDaniel Borkmann 	bin2hex(prog_tag, prog->tag, sizeof(prog->tag));
12427bd509e3SDaniel Borkmann 	seq_printf(m,
12437bd509e3SDaniel Borkmann 		   "prog_type:\t%u\n"
12447bd509e3SDaniel Borkmann 		   "prog_jited:\t%u\n"
1245f1f7714eSDaniel Borkmann 		   "prog_tag:\t%s\n"
12464316b409SDaniel Borkmann 		   "memlock:\t%llu\n"
12474316b409SDaniel Borkmann 		   "prog_id:\t%u\n",
12487bd509e3SDaniel Borkmann 		   prog->type,
12497bd509e3SDaniel Borkmann 		   prog->jited,
1250f1f7714eSDaniel Borkmann 		   prog_tag,
12514316b409SDaniel Borkmann 		   prog->pages * 1ULL << PAGE_SHIFT,
12524316b409SDaniel Borkmann 		   prog->aux->id);
12537bd509e3SDaniel Borkmann }
12547bd509e3SDaniel Borkmann #endif
12557bd509e3SDaniel Borkmann 
1256f66e448cSChenbo Feng const struct file_operations bpf_prog_fops = {
12577bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS
12587bd509e3SDaniel Borkmann 	.show_fdinfo	= bpf_prog_show_fdinfo,
12597bd509e3SDaniel Borkmann #endif
126009756af4SAlexei Starovoitov 	.release	= bpf_prog_release,
12616e71b04aSChenbo Feng 	.read		= bpf_dummy_read,
12626e71b04aSChenbo Feng 	.write		= bpf_dummy_write,
126309756af4SAlexei Starovoitov };
126409756af4SAlexei Starovoitov 
1265b2197755SDaniel Borkmann int bpf_prog_new_fd(struct bpf_prog *prog)
1266aa79781bSDaniel Borkmann {
1267afdb09c7SChenbo Feng 	int ret;
1268afdb09c7SChenbo Feng 
1269afdb09c7SChenbo Feng 	ret = security_bpf_prog(prog);
1270afdb09c7SChenbo Feng 	if (ret < 0)
1271afdb09c7SChenbo Feng 		return ret;
1272afdb09c7SChenbo Feng 
1273aa79781bSDaniel Borkmann 	return anon_inode_getfd("bpf-prog", &bpf_prog_fops, prog,
1274aa79781bSDaniel Borkmann 				O_RDWR | O_CLOEXEC);
1275aa79781bSDaniel Borkmann }
1276aa79781bSDaniel Borkmann 
1277113214beSDaniel Borkmann static struct bpf_prog *____bpf_prog_get(struct fd f)
127809756af4SAlexei Starovoitov {
127909756af4SAlexei Starovoitov 	if (!f.file)
128009756af4SAlexei Starovoitov 		return ERR_PTR(-EBADF);
128109756af4SAlexei Starovoitov 	if (f.file->f_op != &bpf_prog_fops) {
128209756af4SAlexei Starovoitov 		fdput(f);
128309756af4SAlexei Starovoitov 		return ERR_PTR(-EINVAL);
128409756af4SAlexei Starovoitov 	}
128509756af4SAlexei Starovoitov 
1286c2101297SDaniel Borkmann 	return f.file->private_data;
128709756af4SAlexei Starovoitov }
128809756af4SAlexei Starovoitov 
128959d3656dSBrenden Blanco struct bpf_prog *bpf_prog_add(struct bpf_prog *prog, int i)
129092117d84SAlexei Starovoitov {
129159d3656dSBrenden Blanco 	if (atomic_add_return(i, &prog->aux->refcnt) > BPF_MAX_REFCNT) {
129259d3656dSBrenden Blanco 		atomic_sub(i, &prog->aux->refcnt);
129392117d84SAlexei Starovoitov 		return ERR_PTR(-EBUSY);
129492117d84SAlexei Starovoitov 	}
129592117d84SAlexei Starovoitov 	return prog;
129692117d84SAlexei Starovoitov }
129759d3656dSBrenden Blanco EXPORT_SYMBOL_GPL(bpf_prog_add);
129859d3656dSBrenden Blanco 
1299c540594fSDaniel Borkmann void bpf_prog_sub(struct bpf_prog *prog, int i)
1300c540594fSDaniel Borkmann {
1301c540594fSDaniel Borkmann 	/* Only to be used for undoing previous bpf_prog_add() in some
1302c540594fSDaniel Borkmann 	 * error path. We still know that another entity in our call
1303c540594fSDaniel Borkmann 	 * path holds a reference to the program, thus atomic_sub() can
1304c540594fSDaniel Borkmann 	 * be safely used in such cases!
1305c540594fSDaniel Borkmann 	 */
1306c540594fSDaniel Borkmann 	WARN_ON(atomic_sub_return(i, &prog->aux->refcnt) == 0);
1307c540594fSDaniel Borkmann }
1308c540594fSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_sub);
1309c540594fSDaniel Borkmann 
131059d3656dSBrenden Blanco struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog)
131159d3656dSBrenden Blanco {
131259d3656dSBrenden Blanco 	return bpf_prog_add(prog, 1);
131359d3656dSBrenden Blanco }
131497bc402dSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_inc);
131592117d84SAlexei Starovoitov 
1316b16d9aa4SMartin KaFai Lau /* prog_idr_lock should have been held */
1317a6f6df69SJohn Fastabend struct bpf_prog *bpf_prog_inc_not_zero(struct bpf_prog *prog)
1318b16d9aa4SMartin KaFai Lau {
1319b16d9aa4SMartin KaFai Lau 	int refold;
1320b16d9aa4SMartin KaFai Lau 
1321bfc18e38SMark Rutland 	refold = atomic_fetch_add_unless(&prog->aux->refcnt, 1, 0);
1322b16d9aa4SMartin KaFai Lau 
1323b16d9aa4SMartin KaFai Lau 	if (refold >= BPF_MAX_REFCNT) {
1324b16d9aa4SMartin KaFai Lau 		__bpf_prog_put(prog, false);
1325b16d9aa4SMartin KaFai Lau 		return ERR_PTR(-EBUSY);
1326b16d9aa4SMartin KaFai Lau 	}
1327b16d9aa4SMartin KaFai Lau 
1328b16d9aa4SMartin KaFai Lau 	if (!refold)
1329b16d9aa4SMartin KaFai Lau 		return ERR_PTR(-ENOENT);
1330b16d9aa4SMartin KaFai Lau 
1331b16d9aa4SMartin KaFai Lau 	return prog;
1332b16d9aa4SMartin KaFai Lau }
1333a6f6df69SJohn Fastabend EXPORT_SYMBOL_GPL(bpf_prog_inc_not_zero);
1334b16d9aa4SMartin KaFai Lau 
1335040ee692SAl Viro bool bpf_prog_get_ok(struct bpf_prog *prog,
1336288b3de5SJakub Kicinski 			    enum bpf_prog_type *attach_type, bool attach_drv)
1337248f346fSJakub Kicinski {
1338288b3de5SJakub Kicinski 	/* not an attachment, just a refcount inc, always allow */
1339288b3de5SJakub Kicinski 	if (!attach_type)
1340288b3de5SJakub Kicinski 		return true;
1341248f346fSJakub Kicinski 
1342248f346fSJakub Kicinski 	if (prog->type != *attach_type)
1343248f346fSJakub Kicinski 		return false;
1344288b3de5SJakub Kicinski 	if (bpf_prog_is_dev_bound(prog->aux) && !attach_drv)
1345248f346fSJakub Kicinski 		return false;
1346248f346fSJakub Kicinski 
1347248f346fSJakub Kicinski 	return true;
1348248f346fSJakub Kicinski }
1349248f346fSJakub Kicinski 
1350248f346fSJakub Kicinski static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *attach_type,
1351288b3de5SJakub Kicinski 				       bool attach_drv)
135209756af4SAlexei Starovoitov {
135309756af4SAlexei Starovoitov 	struct fd f = fdget(ufd);
135409756af4SAlexei Starovoitov 	struct bpf_prog *prog;
135509756af4SAlexei Starovoitov 
1356113214beSDaniel Borkmann 	prog = ____bpf_prog_get(f);
135709756af4SAlexei Starovoitov 	if (IS_ERR(prog))
135809756af4SAlexei Starovoitov 		return prog;
1359288b3de5SJakub Kicinski 	if (!bpf_prog_get_ok(prog, attach_type, attach_drv)) {
1360113214beSDaniel Borkmann 		prog = ERR_PTR(-EINVAL);
1361113214beSDaniel Borkmann 		goto out;
1362113214beSDaniel Borkmann 	}
136309756af4SAlexei Starovoitov 
136492117d84SAlexei Starovoitov 	prog = bpf_prog_inc(prog);
1365113214beSDaniel Borkmann out:
136609756af4SAlexei Starovoitov 	fdput(f);
136709756af4SAlexei Starovoitov 	return prog;
136809756af4SAlexei Starovoitov }
1369113214beSDaniel Borkmann 
1370113214beSDaniel Borkmann struct bpf_prog *bpf_prog_get(u32 ufd)
1371113214beSDaniel Borkmann {
1372288b3de5SJakub Kicinski 	return __bpf_prog_get(ufd, NULL, false);
1373113214beSDaniel Borkmann }
1374113214beSDaniel Borkmann 
1375248f346fSJakub Kicinski struct bpf_prog *bpf_prog_get_type_dev(u32 ufd, enum bpf_prog_type type,
1376288b3de5SJakub Kicinski 				       bool attach_drv)
1377248f346fSJakub Kicinski {
13784d220ed0SAlexei Starovoitov 	return __bpf_prog_get(ufd, &type, attach_drv);
1379248f346fSJakub Kicinski }
13806c8dfe21SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_prog_get_type_dev);
1381248f346fSJakub Kicinski 
1382aac3fc32SAndrey Ignatov /* Initially all BPF programs could be loaded w/o specifying
1383aac3fc32SAndrey Ignatov  * expected_attach_type. Later for some of them specifying expected_attach_type
1384aac3fc32SAndrey Ignatov  * at load time became required so that program could be validated properly.
1385aac3fc32SAndrey Ignatov  * Programs of types that are allowed to be loaded both w/ and w/o (for
1386aac3fc32SAndrey Ignatov  * backward compatibility) expected_attach_type, should have the default attach
1387aac3fc32SAndrey Ignatov  * type assigned to expected_attach_type for the latter case, so that it can be
1388aac3fc32SAndrey Ignatov  * validated later at attach time.
1389aac3fc32SAndrey Ignatov  *
1390aac3fc32SAndrey Ignatov  * bpf_prog_load_fixup_attach_type() sets expected_attach_type in @attr if
1391aac3fc32SAndrey Ignatov  * prog type requires it but has some attach types that have to be backward
1392aac3fc32SAndrey Ignatov  * compatible.
1393aac3fc32SAndrey Ignatov  */
1394aac3fc32SAndrey Ignatov static void bpf_prog_load_fixup_attach_type(union bpf_attr *attr)
1395aac3fc32SAndrey Ignatov {
1396aac3fc32SAndrey Ignatov 	switch (attr->prog_type) {
1397aac3fc32SAndrey Ignatov 	case BPF_PROG_TYPE_CGROUP_SOCK:
1398aac3fc32SAndrey Ignatov 		/* Unfortunately BPF_ATTACH_TYPE_UNSPEC enumeration doesn't
1399aac3fc32SAndrey Ignatov 		 * exist so checking for non-zero is the way to go here.
1400aac3fc32SAndrey Ignatov 		 */
1401aac3fc32SAndrey Ignatov 		if (!attr->expected_attach_type)
1402aac3fc32SAndrey Ignatov 			attr->expected_attach_type =
1403aac3fc32SAndrey Ignatov 				BPF_CGROUP_INET_SOCK_CREATE;
1404aac3fc32SAndrey Ignatov 		break;
1405aac3fc32SAndrey Ignatov 	}
1406aac3fc32SAndrey Ignatov }
1407aac3fc32SAndrey Ignatov 
14085e43f899SAndrey Ignatov static int
14095e43f899SAndrey Ignatov bpf_prog_load_check_attach_type(enum bpf_prog_type prog_type,
14105e43f899SAndrey Ignatov 				enum bpf_attach_type expected_attach_type)
14115e43f899SAndrey Ignatov {
14124fbac77dSAndrey Ignatov 	switch (prog_type) {
1413aac3fc32SAndrey Ignatov 	case BPF_PROG_TYPE_CGROUP_SOCK:
1414aac3fc32SAndrey Ignatov 		switch (expected_attach_type) {
1415aac3fc32SAndrey Ignatov 		case BPF_CGROUP_INET_SOCK_CREATE:
1416aac3fc32SAndrey Ignatov 		case BPF_CGROUP_INET4_POST_BIND:
1417aac3fc32SAndrey Ignatov 		case BPF_CGROUP_INET6_POST_BIND:
1418aac3fc32SAndrey Ignatov 			return 0;
1419aac3fc32SAndrey Ignatov 		default:
1420aac3fc32SAndrey Ignatov 			return -EINVAL;
1421aac3fc32SAndrey Ignatov 		}
14224fbac77dSAndrey Ignatov 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
14234fbac77dSAndrey Ignatov 		switch (expected_attach_type) {
14244fbac77dSAndrey Ignatov 		case BPF_CGROUP_INET4_BIND:
14254fbac77dSAndrey Ignatov 		case BPF_CGROUP_INET6_BIND:
1426d74bad4eSAndrey Ignatov 		case BPF_CGROUP_INET4_CONNECT:
1427d74bad4eSAndrey Ignatov 		case BPF_CGROUP_INET6_CONNECT:
14281cedee13SAndrey Ignatov 		case BPF_CGROUP_UDP4_SENDMSG:
14291cedee13SAndrey Ignatov 		case BPF_CGROUP_UDP6_SENDMSG:
14305e43f899SAndrey Ignatov 			return 0;
14314fbac77dSAndrey Ignatov 		default:
14324fbac77dSAndrey Ignatov 			return -EINVAL;
14334fbac77dSAndrey Ignatov 		}
14344fbac77dSAndrey Ignatov 	default:
14354fbac77dSAndrey Ignatov 		return 0;
14364fbac77dSAndrey Ignatov 	}
14375e43f899SAndrey Ignatov }
14385e43f899SAndrey Ignatov 
143909756af4SAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
14405e43f899SAndrey Ignatov #define	BPF_PROG_LOAD_LAST_FIELD expected_attach_type
144109756af4SAlexei Starovoitov 
144209756af4SAlexei Starovoitov static int bpf_prog_load(union bpf_attr *attr)
144309756af4SAlexei Starovoitov {
144409756af4SAlexei Starovoitov 	enum bpf_prog_type type = attr->prog_type;
144509756af4SAlexei Starovoitov 	struct bpf_prog *prog;
144609756af4SAlexei Starovoitov 	int err;
144709756af4SAlexei Starovoitov 	char license[128];
144809756af4SAlexei Starovoitov 	bool is_gpl;
144909756af4SAlexei Starovoitov 
145009756af4SAlexei Starovoitov 	if (CHECK_ATTR(BPF_PROG_LOAD))
145109756af4SAlexei Starovoitov 		return -EINVAL;
145209756af4SAlexei Starovoitov 
1453e07b98d9SDavid S. Miller 	if (attr->prog_flags & ~BPF_F_STRICT_ALIGNMENT)
1454e07b98d9SDavid S. Miller 		return -EINVAL;
1455e07b98d9SDavid S. Miller 
145609756af4SAlexei Starovoitov 	/* copy eBPF program license from user space */
1457535e7b4bSMickaël Salaün 	if (strncpy_from_user(license, u64_to_user_ptr(attr->license),
145809756af4SAlexei Starovoitov 			      sizeof(license) - 1) < 0)
145909756af4SAlexei Starovoitov 		return -EFAULT;
146009756af4SAlexei Starovoitov 	license[sizeof(license) - 1] = 0;
146109756af4SAlexei Starovoitov 
146209756af4SAlexei Starovoitov 	/* eBPF programs must be GPL compatible to use GPL-ed functions */
146309756af4SAlexei Starovoitov 	is_gpl = license_is_gpl_compatible(license);
146409756af4SAlexei Starovoitov 
1465ef0915caSDaniel Borkmann 	if (attr->insn_cnt == 0 || attr->insn_cnt > BPF_MAXINSNS)
1466ef0915caSDaniel Borkmann 		return -E2BIG;
146709756af4SAlexei Starovoitov 
14682541517cSAlexei Starovoitov 	if (type == BPF_PROG_TYPE_KPROBE &&
14692541517cSAlexei Starovoitov 	    attr->kern_version != LINUX_VERSION_CODE)
14702541517cSAlexei Starovoitov 		return -EINVAL;
14712541517cSAlexei Starovoitov 
147280b7d819SChenbo Feng 	if (type != BPF_PROG_TYPE_SOCKET_FILTER &&
147380b7d819SChenbo Feng 	    type != BPF_PROG_TYPE_CGROUP_SKB &&
147480b7d819SChenbo Feng 	    !capable(CAP_SYS_ADMIN))
14751be7f75dSAlexei Starovoitov 		return -EPERM;
14761be7f75dSAlexei Starovoitov 
1477aac3fc32SAndrey Ignatov 	bpf_prog_load_fixup_attach_type(attr);
14785e43f899SAndrey Ignatov 	if (bpf_prog_load_check_attach_type(type, attr->expected_attach_type))
14795e43f899SAndrey Ignatov 		return -EINVAL;
14805e43f899SAndrey Ignatov 
148109756af4SAlexei Starovoitov 	/* plain bpf_prog allocation */
148209756af4SAlexei Starovoitov 	prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER);
148309756af4SAlexei Starovoitov 	if (!prog)
148409756af4SAlexei Starovoitov 		return -ENOMEM;
148509756af4SAlexei Starovoitov 
14865e43f899SAndrey Ignatov 	prog->expected_attach_type = attr->expected_attach_type;
14875e43f899SAndrey Ignatov 
14889a18eedbSJakub Kicinski 	prog->aux->offload_requested = !!attr->prog_ifindex;
14899a18eedbSJakub Kicinski 
1490afdb09c7SChenbo Feng 	err = security_bpf_prog_alloc(prog->aux);
1491aaac3ba9SAlexei Starovoitov 	if (err)
1492aaac3ba9SAlexei Starovoitov 		goto free_prog_nouncharge;
1493aaac3ba9SAlexei Starovoitov 
1494afdb09c7SChenbo Feng 	err = bpf_prog_charge_memlock(prog);
1495afdb09c7SChenbo Feng 	if (err)
1496afdb09c7SChenbo Feng 		goto free_prog_sec;
1497afdb09c7SChenbo Feng 
149809756af4SAlexei Starovoitov 	prog->len = attr->insn_cnt;
149909756af4SAlexei Starovoitov 
150009756af4SAlexei Starovoitov 	err = -EFAULT;
1501535e7b4bSMickaël Salaün 	if (copy_from_user(prog->insns, u64_to_user_ptr(attr->insns),
1502aafe6ae9SDaniel Borkmann 			   bpf_prog_insn_size(prog)) != 0)
150309756af4SAlexei Starovoitov 		goto free_prog;
150409756af4SAlexei Starovoitov 
150509756af4SAlexei Starovoitov 	prog->orig_prog = NULL;
1506a91263d5SDaniel Borkmann 	prog->jited = 0;
150709756af4SAlexei Starovoitov 
150809756af4SAlexei Starovoitov 	atomic_set(&prog->aux->refcnt, 1);
1509a91263d5SDaniel Borkmann 	prog->gpl_compatible = is_gpl ? 1 : 0;
151009756af4SAlexei Starovoitov 
15119a18eedbSJakub Kicinski 	if (bpf_prog_is_dev_bound(prog->aux)) {
1512ab3f0063SJakub Kicinski 		err = bpf_prog_offload_init(prog, attr);
1513ab3f0063SJakub Kicinski 		if (err)
1514ab3f0063SJakub Kicinski 			goto free_prog;
1515ab3f0063SJakub Kicinski 	}
1516ab3f0063SJakub Kicinski 
151709756af4SAlexei Starovoitov 	/* find program type: socket_filter vs tracing_filter */
151809756af4SAlexei Starovoitov 	err = find_prog_type(type, prog);
151909756af4SAlexei Starovoitov 	if (err < 0)
152009756af4SAlexei Starovoitov 		goto free_prog;
152109756af4SAlexei Starovoitov 
1522cb4d2b3fSMartin KaFai Lau 	prog->aux->load_time = ktime_get_boot_ns();
1523cb4d2b3fSMartin KaFai Lau 	err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name);
1524cb4d2b3fSMartin KaFai Lau 	if (err)
1525cb4d2b3fSMartin KaFai Lau 		goto free_prog;
1526cb4d2b3fSMartin KaFai Lau 
152709756af4SAlexei Starovoitov 	/* run eBPF verifier */
15289bac3d6dSAlexei Starovoitov 	err = bpf_check(&prog, attr);
152909756af4SAlexei Starovoitov 	if (err < 0)
153009756af4SAlexei Starovoitov 		goto free_used_maps;
153109756af4SAlexei Starovoitov 
1532d1c55ab5SDaniel Borkmann 	prog = bpf_prog_select_runtime(prog, &err);
153304fd61abSAlexei Starovoitov 	if (err < 0)
153404fd61abSAlexei Starovoitov 		goto free_used_maps;
153509756af4SAlexei Starovoitov 
1536dc4bb0e2SMartin KaFai Lau 	err = bpf_prog_alloc_id(prog);
1537dc4bb0e2SMartin KaFai Lau 	if (err)
1538dc4bb0e2SMartin KaFai Lau 		goto free_used_maps;
1539dc4bb0e2SMartin KaFai Lau 
1540aa79781bSDaniel Borkmann 	err = bpf_prog_new_fd(prog);
1541b16d9aa4SMartin KaFai Lau 	if (err < 0) {
1542b16d9aa4SMartin KaFai Lau 		/* failed to allocate fd.
1543b16d9aa4SMartin KaFai Lau 		 * bpf_prog_put() is needed because the above
1544b16d9aa4SMartin KaFai Lau 		 * bpf_prog_alloc_id() has published the prog
1545b16d9aa4SMartin KaFai Lau 		 * to the userspace and the userspace may
1546b16d9aa4SMartin KaFai Lau 		 * have refcnt-ed it through BPF_PROG_GET_FD_BY_ID.
1547b16d9aa4SMartin KaFai Lau 		 */
1548b16d9aa4SMartin KaFai Lau 		bpf_prog_put(prog);
1549b16d9aa4SMartin KaFai Lau 		return err;
1550b16d9aa4SMartin KaFai Lau 	}
155109756af4SAlexei Starovoitov 
155274451e66SDaniel Borkmann 	bpf_prog_kallsyms_add(prog);
155309756af4SAlexei Starovoitov 	return err;
155409756af4SAlexei Starovoitov 
155509756af4SAlexei Starovoitov free_used_maps:
15567d1982b4SDaniel Borkmann 	bpf_prog_kallsyms_del_subprogs(prog);
155709756af4SAlexei Starovoitov 	free_used_maps(prog->aux);
155809756af4SAlexei Starovoitov free_prog:
1559aaac3ba9SAlexei Starovoitov 	bpf_prog_uncharge_memlock(prog);
1560afdb09c7SChenbo Feng free_prog_sec:
1561afdb09c7SChenbo Feng 	security_bpf_prog_free(prog->aux);
1562aaac3ba9SAlexei Starovoitov free_prog_nouncharge:
156309756af4SAlexei Starovoitov 	bpf_prog_free(prog);
156409756af4SAlexei Starovoitov 	return err;
156509756af4SAlexei Starovoitov }
156609756af4SAlexei Starovoitov 
15676e71b04aSChenbo Feng #define BPF_OBJ_LAST_FIELD file_flags
1568b2197755SDaniel Borkmann 
1569b2197755SDaniel Borkmann static int bpf_obj_pin(const union bpf_attr *attr)
1570b2197755SDaniel Borkmann {
15716e71b04aSChenbo Feng 	if (CHECK_ATTR(BPF_OBJ) || attr->file_flags != 0)
1572b2197755SDaniel Borkmann 		return -EINVAL;
1573b2197755SDaniel Borkmann 
1574535e7b4bSMickaël Salaün 	return bpf_obj_pin_user(attr->bpf_fd, u64_to_user_ptr(attr->pathname));
1575b2197755SDaniel Borkmann }
1576b2197755SDaniel Borkmann 
1577b2197755SDaniel Borkmann static int bpf_obj_get(const union bpf_attr *attr)
1578b2197755SDaniel Borkmann {
15796e71b04aSChenbo Feng 	if (CHECK_ATTR(BPF_OBJ) || attr->bpf_fd != 0 ||
15806e71b04aSChenbo Feng 	    attr->file_flags & ~BPF_OBJ_FLAG_MASK)
1581b2197755SDaniel Borkmann 		return -EINVAL;
1582b2197755SDaniel Borkmann 
15836e71b04aSChenbo Feng 	return bpf_obj_get_user(u64_to_user_ptr(attr->pathname),
15846e71b04aSChenbo Feng 				attr->file_flags);
1585b2197755SDaniel Borkmann }
1586b2197755SDaniel Borkmann 
1587c4f6699dSAlexei Starovoitov struct bpf_raw_tracepoint {
1588c4f6699dSAlexei Starovoitov 	struct bpf_raw_event_map *btp;
1589c4f6699dSAlexei Starovoitov 	struct bpf_prog *prog;
1590c4f6699dSAlexei Starovoitov };
1591c4f6699dSAlexei Starovoitov 
1592c4f6699dSAlexei Starovoitov static int bpf_raw_tracepoint_release(struct inode *inode, struct file *filp)
1593c4f6699dSAlexei Starovoitov {
1594c4f6699dSAlexei Starovoitov 	struct bpf_raw_tracepoint *raw_tp = filp->private_data;
1595c4f6699dSAlexei Starovoitov 
1596c4f6699dSAlexei Starovoitov 	if (raw_tp->prog) {
1597c4f6699dSAlexei Starovoitov 		bpf_probe_unregister(raw_tp->btp, raw_tp->prog);
1598c4f6699dSAlexei Starovoitov 		bpf_prog_put(raw_tp->prog);
1599c4f6699dSAlexei Starovoitov 	}
1600c4f6699dSAlexei Starovoitov 	kfree(raw_tp);
1601c4f6699dSAlexei Starovoitov 	return 0;
1602c4f6699dSAlexei Starovoitov }
1603c4f6699dSAlexei Starovoitov 
1604c4f6699dSAlexei Starovoitov static const struct file_operations bpf_raw_tp_fops = {
1605c4f6699dSAlexei Starovoitov 	.release	= bpf_raw_tracepoint_release,
1606c4f6699dSAlexei Starovoitov 	.read		= bpf_dummy_read,
1607c4f6699dSAlexei Starovoitov 	.write		= bpf_dummy_write,
1608c4f6699dSAlexei Starovoitov };
1609c4f6699dSAlexei Starovoitov 
1610c4f6699dSAlexei Starovoitov #define BPF_RAW_TRACEPOINT_OPEN_LAST_FIELD raw_tracepoint.prog_fd
1611c4f6699dSAlexei Starovoitov 
1612c4f6699dSAlexei Starovoitov static int bpf_raw_tracepoint_open(const union bpf_attr *attr)
1613c4f6699dSAlexei Starovoitov {
1614c4f6699dSAlexei Starovoitov 	struct bpf_raw_tracepoint *raw_tp;
1615c4f6699dSAlexei Starovoitov 	struct bpf_raw_event_map *btp;
1616c4f6699dSAlexei Starovoitov 	struct bpf_prog *prog;
1617c4f6699dSAlexei Starovoitov 	char tp_name[128];
1618c4f6699dSAlexei Starovoitov 	int tp_fd, err;
1619c4f6699dSAlexei Starovoitov 
1620c4f6699dSAlexei Starovoitov 	if (strncpy_from_user(tp_name, u64_to_user_ptr(attr->raw_tracepoint.name),
1621c4f6699dSAlexei Starovoitov 			      sizeof(tp_name) - 1) < 0)
1622c4f6699dSAlexei Starovoitov 		return -EFAULT;
1623c4f6699dSAlexei Starovoitov 	tp_name[sizeof(tp_name) - 1] = 0;
1624c4f6699dSAlexei Starovoitov 
1625c4f6699dSAlexei Starovoitov 	btp = bpf_find_raw_tracepoint(tp_name);
1626c4f6699dSAlexei Starovoitov 	if (!btp)
1627c4f6699dSAlexei Starovoitov 		return -ENOENT;
1628c4f6699dSAlexei Starovoitov 
1629c4f6699dSAlexei Starovoitov 	raw_tp = kzalloc(sizeof(*raw_tp), GFP_USER);
1630c4f6699dSAlexei Starovoitov 	if (!raw_tp)
1631c4f6699dSAlexei Starovoitov 		return -ENOMEM;
1632c4f6699dSAlexei Starovoitov 	raw_tp->btp = btp;
1633c4f6699dSAlexei Starovoitov 
1634c4f6699dSAlexei Starovoitov 	prog = bpf_prog_get_type(attr->raw_tracepoint.prog_fd,
1635c4f6699dSAlexei Starovoitov 				 BPF_PROG_TYPE_RAW_TRACEPOINT);
1636c4f6699dSAlexei Starovoitov 	if (IS_ERR(prog)) {
1637c4f6699dSAlexei Starovoitov 		err = PTR_ERR(prog);
1638c4f6699dSAlexei Starovoitov 		goto out_free_tp;
1639c4f6699dSAlexei Starovoitov 	}
1640c4f6699dSAlexei Starovoitov 
1641c4f6699dSAlexei Starovoitov 	err = bpf_probe_register(raw_tp->btp, prog);
1642c4f6699dSAlexei Starovoitov 	if (err)
1643c4f6699dSAlexei Starovoitov 		goto out_put_prog;
1644c4f6699dSAlexei Starovoitov 
1645c4f6699dSAlexei Starovoitov 	raw_tp->prog = prog;
1646c4f6699dSAlexei Starovoitov 	tp_fd = anon_inode_getfd("bpf-raw-tracepoint", &bpf_raw_tp_fops, raw_tp,
1647c4f6699dSAlexei Starovoitov 				 O_CLOEXEC);
1648c4f6699dSAlexei Starovoitov 	if (tp_fd < 0) {
1649c4f6699dSAlexei Starovoitov 		bpf_probe_unregister(raw_tp->btp, prog);
1650c4f6699dSAlexei Starovoitov 		err = tp_fd;
1651c4f6699dSAlexei Starovoitov 		goto out_put_prog;
1652c4f6699dSAlexei Starovoitov 	}
1653c4f6699dSAlexei Starovoitov 	return tp_fd;
1654c4f6699dSAlexei Starovoitov 
1655c4f6699dSAlexei Starovoitov out_put_prog:
1656c4f6699dSAlexei Starovoitov 	bpf_prog_put(prog);
1657c4f6699dSAlexei Starovoitov out_free_tp:
1658c4f6699dSAlexei Starovoitov 	kfree(raw_tp);
1659c4f6699dSAlexei Starovoitov 	return err;
1660c4f6699dSAlexei Starovoitov }
1661c4f6699dSAlexei Starovoitov 
166233491588SAnders Roxell static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog,
166333491588SAnders Roxell 					     enum bpf_attach_type attach_type)
166433491588SAnders Roxell {
166533491588SAnders Roxell 	switch (prog->type) {
166633491588SAnders Roxell 	case BPF_PROG_TYPE_CGROUP_SOCK:
166733491588SAnders Roxell 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
166833491588SAnders Roxell 		return attach_type == prog->expected_attach_type ? 0 : -EINVAL;
166933491588SAnders Roxell 	default:
167033491588SAnders Roxell 		return 0;
167133491588SAnders Roxell 	}
167233491588SAnders Roxell }
167333491588SAnders Roxell 
1674464bc0fdSJohn Fastabend #define BPF_PROG_ATTACH_LAST_FIELD attach_flags
1675174a79ffSJohn Fastabend 
1676324bda9eSAlexei Starovoitov #define BPF_F_ATTACH_MASK \
1677324bda9eSAlexei Starovoitov 	(BPF_F_ALLOW_OVERRIDE | BPF_F_ALLOW_MULTI)
1678324bda9eSAlexei Starovoitov 
1679f4324551SDaniel Mack static int bpf_prog_attach(const union bpf_attr *attr)
1680f4324551SDaniel Mack {
16817f677633SAlexei Starovoitov 	enum bpf_prog_type ptype;
1682f4324551SDaniel Mack 	struct bpf_prog *prog;
16837f677633SAlexei Starovoitov 	int ret;
1684f4324551SDaniel Mack 
1685f4324551SDaniel Mack 	if (!capable(CAP_NET_ADMIN))
1686f4324551SDaniel Mack 		return -EPERM;
1687f4324551SDaniel Mack 
1688f4324551SDaniel Mack 	if (CHECK_ATTR(BPF_PROG_ATTACH))
1689f4324551SDaniel Mack 		return -EINVAL;
1690f4324551SDaniel Mack 
1691324bda9eSAlexei Starovoitov 	if (attr->attach_flags & ~BPF_F_ATTACH_MASK)
16927f677633SAlexei Starovoitov 		return -EINVAL;
16937f677633SAlexei Starovoitov 
1694f4324551SDaniel Mack 	switch (attr->attach_type) {
1695f4324551SDaniel Mack 	case BPF_CGROUP_INET_INGRESS:
1696f4324551SDaniel Mack 	case BPF_CGROUP_INET_EGRESS:
1697b2cd1257SDavid Ahern 		ptype = BPF_PROG_TYPE_CGROUP_SKB;
1698b2cd1257SDavid Ahern 		break;
169961023658SDavid Ahern 	case BPF_CGROUP_INET_SOCK_CREATE:
1700aac3fc32SAndrey Ignatov 	case BPF_CGROUP_INET4_POST_BIND:
1701aac3fc32SAndrey Ignatov 	case BPF_CGROUP_INET6_POST_BIND:
170261023658SDavid Ahern 		ptype = BPF_PROG_TYPE_CGROUP_SOCK;
170361023658SDavid Ahern 		break;
17044fbac77dSAndrey Ignatov 	case BPF_CGROUP_INET4_BIND:
17054fbac77dSAndrey Ignatov 	case BPF_CGROUP_INET6_BIND:
1706d74bad4eSAndrey Ignatov 	case BPF_CGROUP_INET4_CONNECT:
1707d74bad4eSAndrey Ignatov 	case BPF_CGROUP_INET6_CONNECT:
17081cedee13SAndrey Ignatov 	case BPF_CGROUP_UDP4_SENDMSG:
17091cedee13SAndrey Ignatov 	case BPF_CGROUP_UDP6_SENDMSG:
17104fbac77dSAndrey Ignatov 		ptype = BPF_PROG_TYPE_CGROUP_SOCK_ADDR;
17114fbac77dSAndrey Ignatov 		break;
171240304b2aSLawrence Brakmo 	case BPF_CGROUP_SOCK_OPS:
171340304b2aSLawrence Brakmo 		ptype = BPF_PROG_TYPE_SOCK_OPS;
171440304b2aSLawrence Brakmo 		break;
1715ebc614f6SRoman Gushchin 	case BPF_CGROUP_DEVICE:
1716ebc614f6SRoman Gushchin 		ptype = BPF_PROG_TYPE_CGROUP_DEVICE;
1717ebc614f6SRoman Gushchin 		break;
17184f738adbSJohn Fastabend 	case BPF_SK_MSG_VERDICT:
1719fdb5c453SSean Young 		ptype = BPF_PROG_TYPE_SK_MSG;
1720fdb5c453SSean Young 		break;
1721464bc0fdSJohn Fastabend 	case BPF_SK_SKB_STREAM_PARSER:
1722464bc0fdSJohn Fastabend 	case BPF_SK_SKB_STREAM_VERDICT:
1723fdb5c453SSean Young 		ptype = BPF_PROG_TYPE_SK_SKB;
1724fdb5c453SSean Young 		break;
1725f4364dcfSSean Young 	case BPF_LIRC_MODE2:
1726fdb5c453SSean Young 		ptype = BPF_PROG_TYPE_LIRC_MODE2;
1727fdb5c453SSean Young 		break;
1728d58e468bSPetar Penkov 	case BPF_FLOW_DISSECTOR:
1729d58e468bSPetar Penkov 		ptype = BPF_PROG_TYPE_FLOW_DISSECTOR;
1730d58e468bSPetar Penkov 		break;
1731b2cd1257SDavid Ahern 	default:
1732b2cd1257SDavid Ahern 		return -EINVAL;
1733b2cd1257SDavid Ahern 	}
1734b2cd1257SDavid Ahern 
1735b2cd1257SDavid Ahern 	prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
1736f4324551SDaniel Mack 	if (IS_ERR(prog))
1737f4324551SDaniel Mack 		return PTR_ERR(prog);
1738f4324551SDaniel Mack 
17395e43f899SAndrey Ignatov 	if (bpf_prog_attach_check_attach_type(prog, attr->attach_type)) {
17405e43f899SAndrey Ignatov 		bpf_prog_put(prog);
17415e43f899SAndrey Ignatov 		return -EINVAL;
17425e43f899SAndrey Ignatov 	}
17435e43f899SAndrey Ignatov 
1744fdb5c453SSean Young 	switch (ptype) {
1745fdb5c453SSean Young 	case BPF_PROG_TYPE_SK_SKB:
1746fdb5c453SSean Young 	case BPF_PROG_TYPE_SK_MSG:
1747604326b4SDaniel Borkmann 		ret = sock_map_get_from_fd(attr, prog);
1748fdb5c453SSean Young 		break;
1749fdb5c453SSean Young 	case BPF_PROG_TYPE_LIRC_MODE2:
1750fdb5c453SSean Young 		ret = lirc_prog_attach(attr, prog);
1751fdb5c453SSean Young 		break;
1752d58e468bSPetar Penkov 	case BPF_PROG_TYPE_FLOW_DISSECTOR:
1753d58e468bSPetar Penkov 		ret = skb_flow_dissector_bpf_prog_attach(attr, prog);
1754d58e468bSPetar Penkov 		break;
1755fdb5c453SSean Young 	default:
1756fdb5c453SSean Young 		ret = cgroup_bpf_prog_attach(attr, ptype, prog);
1757f4324551SDaniel Mack 	}
1758f4324551SDaniel Mack 
17597f677633SAlexei Starovoitov 	if (ret)
17607f677633SAlexei Starovoitov 		bpf_prog_put(prog);
17617f677633SAlexei Starovoitov 	return ret;
1762f4324551SDaniel Mack }
1763f4324551SDaniel Mack 
1764f4324551SDaniel Mack #define BPF_PROG_DETACH_LAST_FIELD attach_type
1765f4324551SDaniel Mack 
1766f4324551SDaniel Mack static int bpf_prog_detach(const union bpf_attr *attr)
1767f4324551SDaniel Mack {
1768324bda9eSAlexei Starovoitov 	enum bpf_prog_type ptype;
1769f4324551SDaniel Mack 
1770f4324551SDaniel Mack 	if (!capable(CAP_NET_ADMIN))
1771f4324551SDaniel Mack 		return -EPERM;
1772f4324551SDaniel Mack 
1773f4324551SDaniel Mack 	if (CHECK_ATTR(BPF_PROG_DETACH))
1774f4324551SDaniel Mack 		return -EINVAL;
1775f4324551SDaniel Mack 
1776f4324551SDaniel Mack 	switch (attr->attach_type) {
1777f4324551SDaniel Mack 	case BPF_CGROUP_INET_INGRESS:
1778f4324551SDaniel Mack 	case BPF_CGROUP_INET_EGRESS:
1779324bda9eSAlexei Starovoitov 		ptype = BPF_PROG_TYPE_CGROUP_SKB;
1780324bda9eSAlexei Starovoitov 		break;
178161023658SDavid Ahern 	case BPF_CGROUP_INET_SOCK_CREATE:
1782aac3fc32SAndrey Ignatov 	case BPF_CGROUP_INET4_POST_BIND:
1783aac3fc32SAndrey Ignatov 	case BPF_CGROUP_INET6_POST_BIND:
1784324bda9eSAlexei Starovoitov 		ptype = BPF_PROG_TYPE_CGROUP_SOCK;
1785324bda9eSAlexei Starovoitov 		break;
17864fbac77dSAndrey Ignatov 	case BPF_CGROUP_INET4_BIND:
17874fbac77dSAndrey Ignatov 	case BPF_CGROUP_INET6_BIND:
1788d74bad4eSAndrey Ignatov 	case BPF_CGROUP_INET4_CONNECT:
1789d74bad4eSAndrey Ignatov 	case BPF_CGROUP_INET6_CONNECT:
17901cedee13SAndrey Ignatov 	case BPF_CGROUP_UDP4_SENDMSG:
17911cedee13SAndrey Ignatov 	case BPF_CGROUP_UDP6_SENDMSG:
17924fbac77dSAndrey Ignatov 		ptype = BPF_PROG_TYPE_CGROUP_SOCK_ADDR;
17934fbac77dSAndrey Ignatov 		break;
179440304b2aSLawrence Brakmo 	case BPF_CGROUP_SOCK_OPS:
1795324bda9eSAlexei Starovoitov 		ptype = BPF_PROG_TYPE_SOCK_OPS;
1796f4324551SDaniel Mack 		break;
1797ebc614f6SRoman Gushchin 	case BPF_CGROUP_DEVICE:
1798ebc614f6SRoman Gushchin 		ptype = BPF_PROG_TYPE_CGROUP_DEVICE;
1799ebc614f6SRoman Gushchin 		break;
18004f738adbSJohn Fastabend 	case BPF_SK_MSG_VERDICT:
1801604326b4SDaniel Borkmann 		return sock_map_get_from_fd(attr, NULL);
18025a67da2aSJohn Fastabend 	case BPF_SK_SKB_STREAM_PARSER:
18035a67da2aSJohn Fastabend 	case BPF_SK_SKB_STREAM_VERDICT:
1804604326b4SDaniel Borkmann 		return sock_map_get_from_fd(attr, NULL);
1805f4364dcfSSean Young 	case BPF_LIRC_MODE2:
1806f4364dcfSSean Young 		return lirc_prog_detach(attr);
1807d58e468bSPetar Penkov 	case BPF_FLOW_DISSECTOR:
1808d58e468bSPetar Penkov 		return skb_flow_dissector_bpf_prog_detach(attr);
1809f4324551SDaniel Mack 	default:
1810f4324551SDaniel Mack 		return -EINVAL;
1811f4324551SDaniel Mack 	}
1812f4324551SDaniel Mack 
1813fdb5c453SSean Young 	return cgroup_bpf_prog_detach(attr, ptype);
1814f4324551SDaniel Mack }
181540304b2aSLawrence Brakmo 
1816468e2f64SAlexei Starovoitov #define BPF_PROG_QUERY_LAST_FIELD query.prog_cnt
1817468e2f64SAlexei Starovoitov 
1818468e2f64SAlexei Starovoitov static int bpf_prog_query(const union bpf_attr *attr,
1819468e2f64SAlexei Starovoitov 			  union bpf_attr __user *uattr)
1820468e2f64SAlexei Starovoitov {
1821468e2f64SAlexei Starovoitov 	if (!capable(CAP_NET_ADMIN))
1822468e2f64SAlexei Starovoitov 		return -EPERM;
1823468e2f64SAlexei Starovoitov 	if (CHECK_ATTR(BPF_PROG_QUERY))
1824468e2f64SAlexei Starovoitov 		return -EINVAL;
1825468e2f64SAlexei Starovoitov 	if (attr->query.query_flags & ~BPF_F_QUERY_EFFECTIVE)
1826468e2f64SAlexei Starovoitov 		return -EINVAL;
1827468e2f64SAlexei Starovoitov 
1828468e2f64SAlexei Starovoitov 	switch (attr->query.attach_type) {
1829468e2f64SAlexei Starovoitov 	case BPF_CGROUP_INET_INGRESS:
1830468e2f64SAlexei Starovoitov 	case BPF_CGROUP_INET_EGRESS:
1831468e2f64SAlexei Starovoitov 	case BPF_CGROUP_INET_SOCK_CREATE:
18324fbac77dSAndrey Ignatov 	case BPF_CGROUP_INET4_BIND:
18334fbac77dSAndrey Ignatov 	case BPF_CGROUP_INET6_BIND:
1834aac3fc32SAndrey Ignatov 	case BPF_CGROUP_INET4_POST_BIND:
1835aac3fc32SAndrey Ignatov 	case BPF_CGROUP_INET6_POST_BIND:
1836d74bad4eSAndrey Ignatov 	case BPF_CGROUP_INET4_CONNECT:
1837d74bad4eSAndrey Ignatov 	case BPF_CGROUP_INET6_CONNECT:
18381cedee13SAndrey Ignatov 	case BPF_CGROUP_UDP4_SENDMSG:
18391cedee13SAndrey Ignatov 	case BPF_CGROUP_UDP6_SENDMSG:
1840468e2f64SAlexei Starovoitov 	case BPF_CGROUP_SOCK_OPS:
1841ebc614f6SRoman Gushchin 	case BPF_CGROUP_DEVICE:
1842468e2f64SAlexei Starovoitov 		break;
1843f4364dcfSSean Young 	case BPF_LIRC_MODE2:
1844f4364dcfSSean Young 		return lirc_prog_query(attr, uattr);
1845468e2f64SAlexei Starovoitov 	default:
1846468e2f64SAlexei Starovoitov 		return -EINVAL;
1847468e2f64SAlexei Starovoitov 	}
1848fdb5c453SSean Young 
1849fdb5c453SSean Young 	return cgroup_bpf_prog_query(attr, uattr);
1850468e2f64SAlexei Starovoitov }
1851f4324551SDaniel Mack 
18521cf1cae9SAlexei Starovoitov #define BPF_PROG_TEST_RUN_LAST_FIELD test.duration
18531cf1cae9SAlexei Starovoitov 
18541cf1cae9SAlexei Starovoitov static int bpf_prog_test_run(const union bpf_attr *attr,
18551cf1cae9SAlexei Starovoitov 			     union bpf_attr __user *uattr)
18561cf1cae9SAlexei Starovoitov {
18571cf1cae9SAlexei Starovoitov 	struct bpf_prog *prog;
18581cf1cae9SAlexei Starovoitov 	int ret = -ENOTSUPP;
18591cf1cae9SAlexei Starovoitov 
186061f3c964SAlexei Starovoitov 	if (!capable(CAP_SYS_ADMIN))
186161f3c964SAlexei Starovoitov 		return -EPERM;
18621cf1cae9SAlexei Starovoitov 	if (CHECK_ATTR(BPF_PROG_TEST_RUN))
18631cf1cae9SAlexei Starovoitov 		return -EINVAL;
18641cf1cae9SAlexei Starovoitov 
18651cf1cae9SAlexei Starovoitov 	prog = bpf_prog_get(attr->test.prog_fd);
18661cf1cae9SAlexei Starovoitov 	if (IS_ERR(prog))
18671cf1cae9SAlexei Starovoitov 		return PTR_ERR(prog);
18681cf1cae9SAlexei Starovoitov 
18691cf1cae9SAlexei Starovoitov 	if (prog->aux->ops->test_run)
18701cf1cae9SAlexei Starovoitov 		ret = prog->aux->ops->test_run(prog, attr, uattr);
18711cf1cae9SAlexei Starovoitov 
18721cf1cae9SAlexei Starovoitov 	bpf_prog_put(prog);
18731cf1cae9SAlexei Starovoitov 	return ret;
18741cf1cae9SAlexei Starovoitov }
18751cf1cae9SAlexei Starovoitov 
187634ad5580SMartin KaFai Lau #define BPF_OBJ_GET_NEXT_ID_LAST_FIELD next_id
187734ad5580SMartin KaFai Lau 
187834ad5580SMartin KaFai Lau static int bpf_obj_get_next_id(const union bpf_attr *attr,
187934ad5580SMartin KaFai Lau 			       union bpf_attr __user *uattr,
188034ad5580SMartin KaFai Lau 			       struct idr *idr,
188134ad5580SMartin KaFai Lau 			       spinlock_t *lock)
188234ad5580SMartin KaFai Lau {
188334ad5580SMartin KaFai Lau 	u32 next_id = attr->start_id;
188434ad5580SMartin KaFai Lau 	int err = 0;
188534ad5580SMartin KaFai Lau 
188634ad5580SMartin KaFai Lau 	if (CHECK_ATTR(BPF_OBJ_GET_NEXT_ID) || next_id >= INT_MAX)
188734ad5580SMartin KaFai Lau 		return -EINVAL;
188834ad5580SMartin KaFai Lau 
188934ad5580SMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
189034ad5580SMartin KaFai Lau 		return -EPERM;
189134ad5580SMartin KaFai Lau 
189234ad5580SMartin KaFai Lau 	next_id++;
189334ad5580SMartin KaFai Lau 	spin_lock_bh(lock);
189434ad5580SMartin KaFai Lau 	if (!idr_get_next(idr, &next_id))
189534ad5580SMartin KaFai Lau 		err = -ENOENT;
189634ad5580SMartin KaFai Lau 	spin_unlock_bh(lock);
189734ad5580SMartin KaFai Lau 
189834ad5580SMartin KaFai Lau 	if (!err)
189934ad5580SMartin KaFai Lau 		err = put_user(next_id, &uattr->next_id);
190034ad5580SMartin KaFai Lau 
190134ad5580SMartin KaFai Lau 	return err;
190234ad5580SMartin KaFai Lau }
190334ad5580SMartin KaFai Lau 
1904b16d9aa4SMartin KaFai Lau #define BPF_PROG_GET_FD_BY_ID_LAST_FIELD prog_id
1905b16d9aa4SMartin KaFai Lau 
1906b16d9aa4SMartin KaFai Lau static int bpf_prog_get_fd_by_id(const union bpf_attr *attr)
1907b16d9aa4SMartin KaFai Lau {
1908b16d9aa4SMartin KaFai Lau 	struct bpf_prog *prog;
1909b16d9aa4SMartin KaFai Lau 	u32 id = attr->prog_id;
1910b16d9aa4SMartin KaFai Lau 	int fd;
1911b16d9aa4SMartin KaFai Lau 
1912b16d9aa4SMartin KaFai Lau 	if (CHECK_ATTR(BPF_PROG_GET_FD_BY_ID))
1913b16d9aa4SMartin KaFai Lau 		return -EINVAL;
1914b16d9aa4SMartin KaFai Lau 
1915b16d9aa4SMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
1916b16d9aa4SMartin KaFai Lau 		return -EPERM;
1917b16d9aa4SMartin KaFai Lau 
1918b16d9aa4SMartin KaFai Lau 	spin_lock_bh(&prog_idr_lock);
1919b16d9aa4SMartin KaFai Lau 	prog = idr_find(&prog_idr, id);
1920b16d9aa4SMartin KaFai Lau 	if (prog)
1921b16d9aa4SMartin KaFai Lau 		prog = bpf_prog_inc_not_zero(prog);
1922b16d9aa4SMartin KaFai Lau 	else
1923b16d9aa4SMartin KaFai Lau 		prog = ERR_PTR(-ENOENT);
1924b16d9aa4SMartin KaFai Lau 	spin_unlock_bh(&prog_idr_lock);
1925b16d9aa4SMartin KaFai Lau 
1926b16d9aa4SMartin KaFai Lau 	if (IS_ERR(prog))
1927b16d9aa4SMartin KaFai Lau 		return PTR_ERR(prog);
1928b16d9aa4SMartin KaFai Lau 
1929b16d9aa4SMartin KaFai Lau 	fd = bpf_prog_new_fd(prog);
1930b16d9aa4SMartin KaFai Lau 	if (fd < 0)
1931b16d9aa4SMartin KaFai Lau 		bpf_prog_put(prog);
1932b16d9aa4SMartin KaFai Lau 
1933b16d9aa4SMartin KaFai Lau 	return fd;
1934b16d9aa4SMartin KaFai Lau }
1935b16d9aa4SMartin KaFai Lau 
19366e71b04aSChenbo Feng #define BPF_MAP_GET_FD_BY_ID_LAST_FIELD open_flags
1937bd5f5f4eSMartin KaFai Lau 
1938bd5f5f4eSMartin KaFai Lau static int bpf_map_get_fd_by_id(const union bpf_attr *attr)
1939bd5f5f4eSMartin KaFai Lau {
1940bd5f5f4eSMartin KaFai Lau 	struct bpf_map *map;
1941bd5f5f4eSMartin KaFai Lau 	u32 id = attr->map_id;
19426e71b04aSChenbo Feng 	int f_flags;
1943bd5f5f4eSMartin KaFai Lau 	int fd;
1944bd5f5f4eSMartin KaFai Lau 
19456e71b04aSChenbo Feng 	if (CHECK_ATTR(BPF_MAP_GET_FD_BY_ID) ||
19466e71b04aSChenbo Feng 	    attr->open_flags & ~BPF_OBJ_FLAG_MASK)
1947bd5f5f4eSMartin KaFai Lau 		return -EINVAL;
1948bd5f5f4eSMartin KaFai Lau 
1949bd5f5f4eSMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
1950bd5f5f4eSMartin KaFai Lau 		return -EPERM;
1951bd5f5f4eSMartin KaFai Lau 
19526e71b04aSChenbo Feng 	f_flags = bpf_get_file_flag(attr->open_flags);
19536e71b04aSChenbo Feng 	if (f_flags < 0)
19546e71b04aSChenbo Feng 		return f_flags;
19556e71b04aSChenbo Feng 
1956bd5f5f4eSMartin KaFai Lau 	spin_lock_bh(&map_idr_lock);
1957bd5f5f4eSMartin KaFai Lau 	map = idr_find(&map_idr, id);
1958bd5f5f4eSMartin KaFai Lau 	if (map)
1959bd5f5f4eSMartin KaFai Lau 		map = bpf_map_inc_not_zero(map, true);
1960bd5f5f4eSMartin KaFai Lau 	else
1961bd5f5f4eSMartin KaFai Lau 		map = ERR_PTR(-ENOENT);
1962bd5f5f4eSMartin KaFai Lau 	spin_unlock_bh(&map_idr_lock);
1963bd5f5f4eSMartin KaFai Lau 
1964bd5f5f4eSMartin KaFai Lau 	if (IS_ERR(map))
1965bd5f5f4eSMartin KaFai Lau 		return PTR_ERR(map);
1966bd5f5f4eSMartin KaFai Lau 
19676e71b04aSChenbo Feng 	fd = bpf_map_new_fd(map, f_flags);
1968bd5f5f4eSMartin KaFai Lau 	if (fd < 0)
1969bd5f5f4eSMartin KaFai Lau 		bpf_map_put(map);
1970bd5f5f4eSMartin KaFai Lau 
1971bd5f5f4eSMartin KaFai Lau 	return fd;
1972bd5f5f4eSMartin KaFai Lau }
1973bd5f5f4eSMartin KaFai Lau 
19747105e828SDaniel Borkmann static const struct bpf_map *bpf_map_from_imm(const struct bpf_prog *prog,
19757105e828SDaniel Borkmann 					      unsigned long addr)
19767105e828SDaniel Borkmann {
19777105e828SDaniel Borkmann 	int i;
19787105e828SDaniel Borkmann 
19797105e828SDaniel Borkmann 	for (i = 0; i < prog->aux->used_map_cnt; i++)
19807105e828SDaniel Borkmann 		if (prog->aux->used_maps[i] == (void *)addr)
19817105e828SDaniel Borkmann 			return prog->aux->used_maps[i];
19827105e828SDaniel Borkmann 	return NULL;
19837105e828SDaniel Borkmann }
19847105e828SDaniel Borkmann 
19857105e828SDaniel Borkmann static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog)
19867105e828SDaniel Borkmann {
19877105e828SDaniel Borkmann 	const struct bpf_map *map;
19887105e828SDaniel Borkmann 	struct bpf_insn *insns;
19897105e828SDaniel Borkmann 	u64 imm;
19907105e828SDaniel Borkmann 	int i;
19917105e828SDaniel Borkmann 
19927105e828SDaniel Borkmann 	insns = kmemdup(prog->insnsi, bpf_prog_insn_size(prog),
19937105e828SDaniel Borkmann 			GFP_USER);
19947105e828SDaniel Borkmann 	if (!insns)
19957105e828SDaniel Borkmann 		return insns;
19967105e828SDaniel Borkmann 
19977105e828SDaniel Borkmann 	for (i = 0; i < prog->len; i++) {
19987105e828SDaniel Borkmann 		if (insns[i].code == (BPF_JMP | BPF_TAIL_CALL)) {
19997105e828SDaniel Borkmann 			insns[i].code = BPF_JMP | BPF_CALL;
20007105e828SDaniel Borkmann 			insns[i].imm = BPF_FUNC_tail_call;
20017105e828SDaniel Borkmann 			/* fall-through */
20027105e828SDaniel Borkmann 		}
20037105e828SDaniel Borkmann 		if (insns[i].code == (BPF_JMP | BPF_CALL) ||
20047105e828SDaniel Borkmann 		    insns[i].code == (BPF_JMP | BPF_CALL_ARGS)) {
20057105e828SDaniel Borkmann 			if (insns[i].code == (BPF_JMP | BPF_CALL_ARGS))
20067105e828SDaniel Borkmann 				insns[i].code = BPF_JMP | BPF_CALL;
20077105e828SDaniel Borkmann 			if (!bpf_dump_raw_ok())
20087105e828SDaniel Borkmann 				insns[i].imm = 0;
20097105e828SDaniel Borkmann 			continue;
20107105e828SDaniel Borkmann 		}
20117105e828SDaniel Borkmann 
20127105e828SDaniel Borkmann 		if (insns[i].code != (BPF_LD | BPF_IMM | BPF_DW))
20137105e828SDaniel Borkmann 			continue;
20147105e828SDaniel Borkmann 
20157105e828SDaniel Borkmann 		imm = ((u64)insns[i + 1].imm << 32) | (u32)insns[i].imm;
20167105e828SDaniel Borkmann 		map = bpf_map_from_imm(prog, imm);
20177105e828SDaniel Borkmann 		if (map) {
20187105e828SDaniel Borkmann 			insns[i].src_reg = BPF_PSEUDO_MAP_FD;
20197105e828SDaniel Borkmann 			insns[i].imm = map->id;
20207105e828SDaniel Borkmann 			insns[i + 1].imm = 0;
20217105e828SDaniel Borkmann 			continue;
20227105e828SDaniel Borkmann 		}
20237105e828SDaniel Borkmann 
20247105e828SDaniel Borkmann 		if (!bpf_dump_raw_ok() &&
20257105e828SDaniel Borkmann 		    imm == (unsigned long)prog->aux) {
20267105e828SDaniel Borkmann 			insns[i].imm = 0;
20277105e828SDaniel Borkmann 			insns[i + 1].imm = 0;
20287105e828SDaniel Borkmann 			continue;
20297105e828SDaniel Borkmann 		}
20307105e828SDaniel Borkmann 	}
20317105e828SDaniel Borkmann 
20327105e828SDaniel Borkmann 	return insns;
20337105e828SDaniel Borkmann }
20347105e828SDaniel Borkmann 
20351e270976SMartin KaFai Lau static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
20361e270976SMartin KaFai Lau 				   const union bpf_attr *attr,
20371e270976SMartin KaFai Lau 				   union bpf_attr __user *uattr)
20381e270976SMartin KaFai Lau {
20391e270976SMartin KaFai Lau 	struct bpf_prog_info __user *uinfo = u64_to_user_ptr(attr->info.info);
20401e270976SMartin KaFai Lau 	struct bpf_prog_info info = {};
20411e270976SMartin KaFai Lau 	u32 info_len = attr->info.info_len;
20421e270976SMartin KaFai Lau 	char __user *uinsns;
20431e270976SMartin KaFai Lau 	u32 ulen;
20441e270976SMartin KaFai Lau 	int err;
20451e270976SMartin KaFai Lau 
2046dcab51f1SMartin KaFai Lau 	err = bpf_check_uarg_tail_zero(uinfo, sizeof(info), info_len);
20471e270976SMartin KaFai Lau 	if (err)
20481e270976SMartin KaFai Lau 		return err;
20491e270976SMartin KaFai Lau 	info_len = min_t(u32, sizeof(info), info_len);
20501e270976SMartin KaFai Lau 
20511e270976SMartin KaFai Lau 	if (copy_from_user(&info, uinfo, info_len))
205289b09689SDaniel Borkmann 		return -EFAULT;
20531e270976SMartin KaFai Lau 
20541e270976SMartin KaFai Lau 	info.type = prog->type;
20551e270976SMartin KaFai Lau 	info.id = prog->aux->id;
2056cb4d2b3fSMartin KaFai Lau 	info.load_time = prog->aux->load_time;
2057cb4d2b3fSMartin KaFai Lau 	info.created_by_uid = from_kuid_munged(current_user_ns(),
2058cb4d2b3fSMartin KaFai Lau 					       prog->aux->user->uid);
2059b85fab0eSJiri Olsa 	info.gpl_compatible = prog->gpl_compatible;
20601e270976SMartin KaFai Lau 
20611e270976SMartin KaFai Lau 	memcpy(info.tag, prog->tag, sizeof(prog->tag));
2062cb4d2b3fSMartin KaFai Lau 	memcpy(info.name, prog->aux->name, sizeof(prog->aux->name));
2063cb4d2b3fSMartin KaFai Lau 
2064cb4d2b3fSMartin KaFai Lau 	ulen = info.nr_map_ids;
2065cb4d2b3fSMartin KaFai Lau 	info.nr_map_ids = prog->aux->used_map_cnt;
2066cb4d2b3fSMartin KaFai Lau 	ulen = min_t(u32, info.nr_map_ids, ulen);
2067cb4d2b3fSMartin KaFai Lau 	if (ulen) {
2068721e08daSMartin KaFai Lau 		u32 __user *user_map_ids = u64_to_user_ptr(info.map_ids);
2069cb4d2b3fSMartin KaFai Lau 		u32 i;
2070cb4d2b3fSMartin KaFai Lau 
2071cb4d2b3fSMartin KaFai Lau 		for (i = 0; i < ulen; i++)
2072cb4d2b3fSMartin KaFai Lau 			if (put_user(prog->aux->used_maps[i]->id,
2073cb4d2b3fSMartin KaFai Lau 				     &user_map_ids[i]))
2074cb4d2b3fSMartin KaFai Lau 				return -EFAULT;
2075cb4d2b3fSMartin KaFai Lau 	}
20761e270976SMartin KaFai Lau 
20771e270976SMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN)) {
20781e270976SMartin KaFai Lau 		info.jited_prog_len = 0;
20791e270976SMartin KaFai Lau 		info.xlated_prog_len = 0;
2080dbecd738SSandipan Das 		info.nr_jited_ksyms = 0;
20811e270976SMartin KaFai Lau 		goto done;
20821e270976SMartin KaFai Lau 	}
20831e270976SMartin KaFai Lau 
20841e270976SMartin KaFai Lau 	ulen = info.xlated_prog_len;
20859975a54bSDaniel Borkmann 	info.xlated_prog_len = bpf_prog_insn_size(prog);
20861e270976SMartin KaFai Lau 	if (info.xlated_prog_len && ulen) {
20877105e828SDaniel Borkmann 		struct bpf_insn *insns_sanitized;
20887105e828SDaniel Borkmann 		bool fault;
20897105e828SDaniel Borkmann 
20907105e828SDaniel Borkmann 		if (prog->blinded && !bpf_dump_raw_ok()) {
20917105e828SDaniel Borkmann 			info.xlated_prog_insns = 0;
20927105e828SDaniel Borkmann 			goto done;
20937105e828SDaniel Borkmann 		}
20947105e828SDaniel Borkmann 		insns_sanitized = bpf_insn_prepare_dump(prog);
20957105e828SDaniel Borkmann 		if (!insns_sanitized)
20967105e828SDaniel Borkmann 			return -ENOMEM;
20971e270976SMartin KaFai Lau 		uinsns = u64_to_user_ptr(info.xlated_prog_insns);
20981e270976SMartin KaFai Lau 		ulen = min_t(u32, info.xlated_prog_len, ulen);
20997105e828SDaniel Borkmann 		fault = copy_to_user(uinsns, insns_sanitized, ulen);
21007105e828SDaniel Borkmann 		kfree(insns_sanitized);
21017105e828SDaniel Borkmann 		if (fault)
21021e270976SMartin KaFai Lau 			return -EFAULT;
21031e270976SMartin KaFai Lau 	}
21041e270976SMartin KaFai Lau 
2105675fc275SJakub Kicinski 	if (bpf_prog_is_dev_bound(prog->aux)) {
2106675fc275SJakub Kicinski 		err = bpf_prog_offload_info_fill(&info, prog);
2107675fc275SJakub Kicinski 		if (err)
2108675fc275SJakub Kicinski 			return err;
2109fcfb126dSJiong Wang 		goto done;
2110fcfb126dSJiong Wang 	}
2111fcfb126dSJiong Wang 
2112fcfb126dSJiong Wang 	/* NOTE: the following code is supposed to be skipped for offload.
2113fcfb126dSJiong Wang 	 * bpf_prog_offload_info_fill() is the place to fill similar fields
2114fcfb126dSJiong Wang 	 * for offload.
2115fcfb126dSJiong Wang 	 */
2116fcfb126dSJiong Wang 	ulen = info.jited_prog_len;
21174d56a76eSSandipan Das 	if (prog->aux->func_cnt) {
21184d56a76eSSandipan Das 		u32 i;
21194d56a76eSSandipan Das 
21204d56a76eSSandipan Das 		info.jited_prog_len = 0;
21214d56a76eSSandipan Das 		for (i = 0; i < prog->aux->func_cnt; i++)
21224d56a76eSSandipan Das 			info.jited_prog_len += prog->aux->func[i]->jited_len;
21234d56a76eSSandipan Das 	} else {
2124fcfb126dSJiong Wang 		info.jited_prog_len = prog->jited_len;
21254d56a76eSSandipan Das 	}
21264d56a76eSSandipan Das 
2127fcfb126dSJiong Wang 	if (info.jited_prog_len && ulen) {
2128fcfb126dSJiong Wang 		if (bpf_dump_raw_ok()) {
2129fcfb126dSJiong Wang 			uinsns = u64_to_user_ptr(info.jited_prog_insns);
2130fcfb126dSJiong Wang 			ulen = min_t(u32, info.jited_prog_len, ulen);
21314d56a76eSSandipan Das 
21324d56a76eSSandipan Das 			/* for multi-function programs, copy the JITed
21334d56a76eSSandipan Das 			 * instructions for all the functions
21344d56a76eSSandipan Das 			 */
21354d56a76eSSandipan Das 			if (prog->aux->func_cnt) {
21364d56a76eSSandipan Das 				u32 len, free, i;
21374d56a76eSSandipan Das 				u8 *img;
21384d56a76eSSandipan Das 
21394d56a76eSSandipan Das 				free = ulen;
21404d56a76eSSandipan Das 				for (i = 0; i < prog->aux->func_cnt; i++) {
21414d56a76eSSandipan Das 					len = prog->aux->func[i]->jited_len;
21424d56a76eSSandipan Das 					len = min_t(u32, len, free);
21434d56a76eSSandipan Das 					img = (u8 *) prog->aux->func[i]->bpf_func;
21444d56a76eSSandipan Das 					if (copy_to_user(uinsns, img, len))
21454d56a76eSSandipan Das 						return -EFAULT;
21464d56a76eSSandipan Das 					uinsns += len;
21474d56a76eSSandipan Das 					free -= len;
21484d56a76eSSandipan Das 					if (!free)
21494d56a76eSSandipan Das 						break;
21504d56a76eSSandipan Das 				}
21514d56a76eSSandipan Das 			} else {
2152fcfb126dSJiong Wang 				if (copy_to_user(uinsns, prog->bpf_func, ulen))
2153fcfb126dSJiong Wang 					return -EFAULT;
21544d56a76eSSandipan Das 			}
2155fcfb126dSJiong Wang 		} else {
2156fcfb126dSJiong Wang 			info.jited_prog_insns = 0;
2157fcfb126dSJiong Wang 		}
2158675fc275SJakub Kicinski 	}
2159675fc275SJakub Kicinski 
2160dbecd738SSandipan Das 	ulen = info.nr_jited_ksyms;
2161dbecd738SSandipan Das 	info.nr_jited_ksyms = prog->aux->func_cnt;
2162dbecd738SSandipan Das 	if (info.nr_jited_ksyms && ulen) {
2163dbecd738SSandipan Das 		if (bpf_dump_raw_ok()) {
2164dbecd738SSandipan Das 			u64 __user *user_ksyms;
2165dbecd738SSandipan Das 			ulong ksym_addr;
2166dbecd738SSandipan Das 			u32 i;
2167dbecd738SSandipan Das 
2168dbecd738SSandipan Das 			/* copy the address of the kernel symbol
2169dbecd738SSandipan Das 			 * corresponding to each function
2170dbecd738SSandipan Das 			 */
2171dbecd738SSandipan Das 			ulen = min_t(u32, info.nr_jited_ksyms, ulen);
2172dbecd738SSandipan Das 			user_ksyms = u64_to_user_ptr(info.jited_ksyms);
2173dbecd738SSandipan Das 			for (i = 0; i < ulen; i++) {
2174dbecd738SSandipan Das 				ksym_addr = (ulong) prog->aux->func[i]->bpf_func;
2175dbecd738SSandipan Das 				ksym_addr &= PAGE_MASK;
2176dbecd738SSandipan Das 				if (put_user((u64) ksym_addr, &user_ksyms[i]))
2177dbecd738SSandipan Das 					return -EFAULT;
2178dbecd738SSandipan Das 			}
2179dbecd738SSandipan Das 		} else {
2180dbecd738SSandipan Das 			info.jited_ksyms = 0;
2181dbecd738SSandipan Das 		}
2182dbecd738SSandipan Das 	}
2183dbecd738SSandipan Das 
2184815581c1SSandipan Das 	ulen = info.nr_jited_func_lens;
2185815581c1SSandipan Das 	info.nr_jited_func_lens = prog->aux->func_cnt;
2186815581c1SSandipan Das 	if (info.nr_jited_func_lens && ulen) {
2187815581c1SSandipan Das 		if (bpf_dump_raw_ok()) {
2188815581c1SSandipan Das 			u32 __user *user_lens;
2189815581c1SSandipan Das 			u32 func_len, i;
2190815581c1SSandipan Das 
2191815581c1SSandipan Das 			/* copy the JITed image lengths for each function */
2192815581c1SSandipan Das 			ulen = min_t(u32, info.nr_jited_func_lens, ulen);
2193815581c1SSandipan Das 			user_lens = u64_to_user_ptr(info.jited_func_lens);
2194815581c1SSandipan Das 			for (i = 0; i < ulen; i++) {
2195815581c1SSandipan Das 				func_len = prog->aux->func[i]->jited_len;
2196815581c1SSandipan Das 				if (put_user(func_len, &user_lens[i]))
2197815581c1SSandipan Das 					return -EFAULT;
2198815581c1SSandipan Das 			}
2199815581c1SSandipan Das 		} else {
2200815581c1SSandipan Das 			info.jited_func_lens = 0;
2201815581c1SSandipan Das 		}
2202815581c1SSandipan Das 	}
2203815581c1SSandipan Das 
22041e270976SMartin KaFai Lau done:
22051e270976SMartin KaFai Lau 	if (copy_to_user(uinfo, &info, info_len) ||
22061e270976SMartin KaFai Lau 	    put_user(info_len, &uattr->info.info_len))
22071e270976SMartin KaFai Lau 		return -EFAULT;
22081e270976SMartin KaFai Lau 
22091e270976SMartin KaFai Lau 	return 0;
22101e270976SMartin KaFai Lau }
22111e270976SMartin KaFai Lau 
22121e270976SMartin KaFai Lau static int bpf_map_get_info_by_fd(struct bpf_map *map,
22131e270976SMartin KaFai Lau 				  const union bpf_attr *attr,
22141e270976SMartin KaFai Lau 				  union bpf_attr __user *uattr)
22151e270976SMartin KaFai Lau {
22161e270976SMartin KaFai Lau 	struct bpf_map_info __user *uinfo = u64_to_user_ptr(attr->info.info);
22171e270976SMartin KaFai Lau 	struct bpf_map_info info = {};
22181e270976SMartin KaFai Lau 	u32 info_len = attr->info.info_len;
22191e270976SMartin KaFai Lau 	int err;
22201e270976SMartin KaFai Lau 
2221dcab51f1SMartin KaFai Lau 	err = bpf_check_uarg_tail_zero(uinfo, sizeof(info), info_len);
22221e270976SMartin KaFai Lau 	if (err)
22231e270976SMartin KaFai Lau 		return err;
22241e270976SMartin KaFai Lau 	info_len = min_t(u32, sizeof(info), info_len);
22251e270976SMartin KaFai Lau 
22261e270976SMartin KaFai Lau 	info.type = map->map_type;
22271e270976SMartin KaFai Lau 	info.id = map->id;
22281e270976SMartin KaFai Lau 	info.key_size = map->key_size;
22291e270976SMartin KaFai Lau 	info.value_size = map->value_size;
22301e270976SMartin KaFai Lau 	info.max_entries = map->max_entries;
22311e270976SMartin KaFai Lau 	info.map_flags = map->map_flags;
2232ad5b177bSMartin KaFai Lau 	memcpy(info.name, map->name, sizeof(map->name));
22331e270976SMartin KaFai Lau 
223478958fcaSMartin KaFai Lau 	if (map->btf) {
223578958fcaSMartin KaFai Lau 		info.btf_id = btf_id(map->btf);
22369b2cf328SMartin KaFai Lau 		info.btf_key_type_id = map->btf_key_type_id;
22379b2cf328SMartin KaFai Lau 		info.btf_value_type_id = map->btf_value_type_id;
223878958fcaSMartin KaFai Lau 	}
223978958fcaSMartin KaFai Lau 
224052775b33SJakub Kicinski 	if (bpf_map_is_dev_bound(map)) {
224152775b33SJakub Kicinski 		err = bpf_map_offload_info_fill(&info, map);
224252775b33SJakub Kicinski 		if (err)
224352775b33SJakub Kicinski 			return err;
224452775b33SJakub Kicinski 	}
224552775b33SJakub Kicinski 
22461e270976SMartin KaFai Lau 	if (copy_to_user(uinfo, &info, info_len) ||
22471e270976SMartin KaFai Lau 	    put_user(info_len, &uattr->info.info_len))
22481e270976SMartin KaFai Lau 		return -EFAULT;
22491e270976SMartin KaFai Lau 
22501e270976SMartin KaFai Lau 	return 0;
22511e270976SMartin KaFai Lau }
22521e270976SMartin KaFai Lau 
225362dab84cSMartin KaFai Lau static int bpf_btf_get_info_by_fd(struct btf *btf,
225462dab84cSMartin KaFai Lau 				  const union bpf_attr *attr,
225562dab84cSMartin KaFai Lau 				  union bpf_attr __user *uattr)
225662dab84cSMartin KaFai Lau {
225762dab84cSMartin KaFai Lau 	struct bpf_btf_info __user *uinfo = u64_to_user_ptr(attr->info.info);
225862dab84cSMartin KaFai Lau 	u32 info_len = attr->info.info_len;
225962dab84cSMartin KaFai Lau 	int err;
226062dab84cSMartin KaFai Lau 
2261dcab51f1SMartin KaFai Lau 	err = bpf_check_uarg_tail_zero(uinfo, sizeof(*uinfo), info_len);
226262dab84cSMartin KaFai Lau 	if (err)
226362dab84cSMartin KaFai Lau 		return err;
226462dab84cSMartin KaFai Lau 
226562dab84cSMartin KaFai Lau 	return btf_get_info_by_fd(btf, attr, uattr);
226662dab84cSMartin KaFai Lau }
226762dab84cSMartin KaFai Lau 
22681e270976SMartin KaFai Lau #define BPF_OBJ_GET_INFO_BY_FD_LAST_FIELD info.info
22691e270976SMartin KaFai Lau 
22701e270976SMartin KaFai Lau static int bpf_obj_get_info_by_fd(const union bpf_attr *attr,
22711e270976SMartin KaFai Lau 				  union bpf_attr __user *uattr)
22721e270976SMartin KaFai Lau {
22731e270976SMartin KaFai Lau 	int ufd = attr->info.bpf_fd;
22741e270976SMartin KaFai Lau 	struct fd f;
22751e270976SMartin KaFai Lau 	int err;
22761e270976SMartin KaFai Lau 
22771e270976SMartin KaFai Lau 	if (CHECK_ATTR(BPF_OBJ_GET_INFO_BY_FD))
22781e270976SMartin KaFai Lau 		return -EINVAL;
22791e270976SMartin KaFai Lau 
22801e270976SMartin KaFai Lau 	f = fdget(ufd);
22811e270976SMartin KaFai Lau 	if (!f.file)
22821e270976SMartin KaFai Lau 		return -EBADFD;
22831e270976SMartin KaFai Lau 
22841e270976SMartin KaFai Lau 	if (f.file->f_op == &bpf_prog_fops)
22851e270976SMartin KaFai Lau 		err = bpf_prog_get_info_by_fd(f.file->private_data, attr,
22861e270976SMartin KaFai Lau 					      uattr);
22871e270976SMartin KaFai Lau 	else if (f.file->f_op == &bpf_map_fops)
22881e270976SMartin KaFai Lau 		err = bpf_map_get_info_by_fd(f.file->private_data, attr,
22891e270976SMartin KaFai Lau 					     uattr);
229060197cfbSMartin KaFai Lau 	else if (f.file->f_op == &btf_fops)
229162dab84cSMartin KaFai Lau 		err = bpf_btf_get_info_by_fd(f.file->private_data, attr, uattr);
22921e270976SMartin KaFai Lau 	else
22931e270976SMartin KaFai Lau 		err = -EINVAL;
22941e270976SMartin KaFai Lau 
22951e270976SMartin KaFai Lau 	fdput(f);
22961e270976SMartin KaFai Lau 	return err;
22971e270976SMartin KaFai Lau }
22981e270976SMartin KaFai Lau 
2299f56a653cSMartin KaFai Lau #define BPF_BTF_LOAD_LAST_FIELD btf_log_level
2300f56a653cSMartin KaFai Lau 
2301f56a653cSMartin KaFai Lau static int bpf_btf_load(const union bpf_attr *attr)
2302f56a653cSMartin KaFai Lau {
2303f56a653cSMartin KaFai Lau 	if (CHECK_ATTR(BPF_BTF_LOAD))
2304f56a653cSMartin KaFai Lau 		return -EINVAL;
2305f56a653cSMartin KaFai Lau 
2306f56a653cSMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
2307f56a653cSMartin KaFai Lau 		return -EPERM;
2308f56a653cSMartin KaFai Lau 
2309f56a653cSMartin KaFai Lau 	return btf_new_fd(attr);
2310f56a653cSMartin KaFai Lau }
2311f56a653cSMartin KaFai Lau 
231278958fcaSMartin KaFai Lau #define BPF_BTF_GET_FD_BY_ID_LAST_FIELD btf_id
231378958fcaSMartin KaFai Lau 
231478958fcaSMartin KaFai Lau static int bpf_btf_get_fd_by_id(const union bpf_attr *attr)
231578958fcaSMartin KaFai Lau {
231678958fcaSMartin KaFai Lau 	if (CHECK_ATTR(BPF_BTF_GET_FD_BY_ID))
231778958fcaSMartin KaFai Lau 		return -EINVAL;
231878958fcaSMartin KaFai Lau 
231978958fcaSMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
232078958fcaSMartin KaFai Lau 		return -EPERM;
232178958fcaSMartin KaFai Lau 
232278958fcaSMartin KaFai Lau 	return btf_get_fd_by_id(attr->btf_id);
232378958fcaSMartin KaFai Lau }
232478958fcaSMartin KaFai Lau 
232541bdc4b4SYonghong Song static int bpf_task_fd_query_copy(const union bpf_attr *attr,
232641bdc4b4SYonghong Song 				    union bpf_attr __user *uattr,
232741bdc4b4SYonghong Song 				    u32 prog_id, u32 fd_type,
232841bdc4b4SYonghong Song 				    const char *buf, u64 probe_offset,
232941bdc4b4SYonghong Song 				    u64 probe_addr)
233041bdc4b4SYonghong Song {
233141bdc4b4SYonghong Song 	char __user *ubuf = u64_to_user_ptr(attr->task_fd_query.buf);
233241bdc4b4SYonghong Song 	u32 len = buf ? strlen(buf) : 0, input_len;
233341bdc4b4SYonghong Song 	int err = 0;
233441bdc4b4SYonghong Song 
233541bdc4b4SYonghong Song 	if (put_user(len, &uattr->task_fd_query.buf_len))
233641bdc4b4SYonghong Song 		return -EFAULT;
233741bdc4b4SYonghong Song 	input_len = attr->task_fd_query.buf_len;
233841bdc4b4SYonghong Song 	if (input_len && ubuf) {
233941bdc4b4SYonghong Song 		if (!len) {
234041bdc4b4SYonghong Song 			/* nothing to copy, just make ubuf NULL terminated */
234141bdc4b4SYonghong Song 			char zero = '\0';
234241bdc4b4SYonghong Song 
234341bdc4b4SYonghong Song 			if (put_user(zero, ubuf))
234441bdc4b4SYonghong Song 				return -EFAULT;
234541bdc4b4SYonghong Song 		} else if (input_len >= len + 1) {
234641bdc4b4SYonghong Song 			/* ubuf can hold the string with NULL terminator */
234741bdc4b4SYonghong Song 			if (copy_to_user(ubuf, buf, len + 1))
234841bdc4b4SYonghong Song 				return -EFAULT;
234941bdc4b4SYonghong Song 		} else {
235041bdc4b4SYonghong Song 			/* ubuf cannot hold the string with NULL terminator,
235141bdc4b4SYonghong Song 			 * do a partial copy with NULL terminator.
235241bdc4b4SYonghong Song 			 */
235341bdc4b4SYonghong Song 			char zero = '\0';
235441bdc4b4SYonghong Song 
235541bdc4b4SYonghong Song 			err = -ENOSPC;
235641bdc4b4SYonghong Song 			if (copy_to_user(ubuf, buf, input_len - 1))
235741bdc4b4SYonghong Song 				return -EFAULT;
235841bdc4b4SYonghong Song 			if (put_user(zero, ubuf + input_len - 1))
235941bdc4b4SYonghong Song 				return -EFAULT;
236041bdc4b4SYonghong Song 		}
236141bdc4b4SYonghong Song 	}
236241bdc4b4SYonghong Song 
236341bdc4b4SYonghong Song 	if (put_user(prog_id, &uattr->task_fd_query.prog_id) ||
236441bdc4b4SYonghong Song 	    put_user(fd_type, &uattr->task_fd_query.fd_type) ||
236541bdc4b4SYonghong Song 	    put_user(probe_offset, &uattr->task_fd_query.probe_offset) ||
236641bdc4b4SYonghong Song 	    put_user(probe_addr, &uattr->task_fd_query.probe_addr))
236741bdc4b4SYonghong Song 		return -EFAULT;
236841bdc4b4SYonghong Song 
236941bdc4b4SYonghong Song 	return err;
237041bdc4b4SYonghong Song }
237141bdc4b4SYonghong Song 
237241bdc4b4SYonghong Song #define BPF_TASK_FD_QUERY_LAST_FIELD task_fd_query.probe_addr
237341bdc4b4SYonghong Song 
237441bdc4b4SYonghong Song static int bpf_task_fd_query(const union bpf_attr *attr,
237541bdc4b4SYonghong Song 			     union bpf_attr __user *uattr)
237641bdc4b4SYonghong Song {
237741bdc4b4SYonghong Song 	pid_t pid = attr->task_fd_query.pid;
237841bdc4b4SYonghong Song 	u32 fd = attr->task_fd_query.fd;
237941bdc4b4SYonghong Song 	const struct perf_event *event;
238041bdc4b4SYonghong Song 	struct files_struct *files;
238141bdc4b4SYonghong Song 	struct task_struct *task;
238241bdc4b4SYonghong Song 	struct file *file;
238341bdc4b4SYonghong Song 	int err;
238441bdc4b4SYonghong Song 
238541bdc4b4SYonghong Song 	if (CHECK_ATTR(BPF_TASK_FD_QUERY))
238641bdc4b4SYonghong Song 		return -EINVAL;
238741bdc4b4SYonghong Song 
238841bdc4b4SYonghong Song 	if (!capable(CAP_SYS_ADMIN))
238941bdc4b4SYonghong Song 		return -EPERM;
239041bdc4b4SYonghong Song 
239141bdc4b4SYonghong Song 	if (attr->task_fd_query.flags != 0)
239241bdc4b4SYonghong Song 		return -EINVAL;
239341bdc4b4SYonghong Song 
239441bdc4b4SYonghong Song 	task = get_pid_task(find_vpid(pid), PIDTYPE_PID);
239541bdc4b4SYonghong Song 	if (!task)
239641bdc4b4SYonghong Song 		return -ENOENT;
239741bdc4b4SYonghong Song 
239841bdc4b4SYonghong Song 	files = get_files_struct(task);
239941bdc4b4SYonghong Song 	put_task_struct(task);
240041bdc4b4SYonghong Song 	if (!files)
240141bdc4b4SYonghong Song 		return -ENOENT;
240241bdc4b4SYonghong Song 
240341bdc4b4SYonghong Song 	err = 0;
240441bdc4b4SYonghong Song 	spin_lock(&files->file_lock);
240541bdc4b4SYonghong Song 	file = fcheck_files(files, fd);
240641bdc4b4SYonghong Song 	if (!file)
240741bdc4b4SYonghong Song 		err = -EBADF;
240841bdc4b4SYonghong Song 	else
240941bdc4b4SYonghong Song 		get_file(file);
241041bdc4b4SYonghong Song 	spin_unlock(&files->file_lock);
241141bdc4b4SYonghong Song 	put_files_struct(files);
241241bdc4b4SYonghong Song 
241341bdc4b4SYonghong Song 	if (err)
241441bdc4b4SYonghong Song 		goto out;
241541bdc4b4SYonghong Song 
241641bdc4b4SYonghong Song 	if (file->f_op == &bpf_raw_tp_fops) {
241741bdc4b4SYonghong Song 		struct bpf_raw_tracepoint *raw_tp = file->private_data;
241841bdc4b4SYonghong Song 		struct bpf_raw_event_map *btp = raw_tp->btp;
241941bdc4b4SYonghong Song 
242041bdc4b4SYonghong Song 		err = bpf_task_fd_query_copy(attr, uattr,
242141bdc4b4SYonghong Song 					     raw_tp->prog->aux->id,
242241bdc4b4SYonghong Song 					     BPF_FD_TYPE_RAW_TRACEPOINT,
242341bdc4b4SYonghong Song 					     btp->tp->name, 0, 0);
242441bdc4b4SYonghong Song 		goto put_file;
242541bdc4b4SYonghong Song 	}
242641bdc4b4SYonghong Song 
242741bdc4b4SYonghong Song 	event = perf_get_event(file);
242841bdc4b4SYonghong Song 	if (!IS_ERR(event)) {
242941bdc4b4SYonghong Song 		u64 probe_offset, probe_addr;
243041bdc4b4SYonghong Song 		u32 prog_id, fd_type;
243141bdc4b4SYonghong Song 		const char *buf;
243241bdc4b4SYonghong Song 
243341bdc4b4SYonghong Song 		err = bpf_get_perf_event_info(event, &prog_id, &fd_type,
243441bdc4b4SYonghong Song 					      &buf, &probe_offset,
243541bdc4b4SYonghong Song 					      &probe_addr);
243641bdc4b4SYonghong Song 		if (!err)
243741bdc4b4SYonghong Song 			err = bpf_task_fd_query_copy(attr, uattr, prog_id,
243841bdc4b4SYonghong Song 						     fd_type, buf,
243941bdc4b4SYonghong Song 						     probe_offset,
244041bdc4b4SYonghong Song 						     probe_addr);
244141bdc4b4SYonghong Song 		goto put_file;
244241bdc4b4SYonghong Song 	}
244341bdc4b4SYonghong Song 
244441bdc4b4SYonghong Song 	err = -ENOTSUPP;
244541bdc4b4SYonghong Song put_file:
244641bdc4b4SYonghong Song 	fput(file);
244741bdc4b4SYonghong Song out:
244841bdc4b4SYonghong Song 	return err;
244941bdc4b4SYonghong Song }
245041bdc4b4SYonghong Song 
245199c55f7dSAlexei Starovoitov SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
245299c55f7dSAlexei Starovoitov {
245399c55f7dSAlexei Starovoitov 	union bpf_attr attr = {};
245499c55f7dSAlexei Starovoitov 	int err;
245599c55f7dSAlexei Starovoitov 
24560fa4fe85SChenbo Feng 	if (sysctl_unprivileged_bpf_disabled && !capable(CAP_SYS_ADMIN))
245799c55f7dSAlexei Starovoitov 		return -EPERM;
245899c55f7dSAlexei Starovoitov 
2459dcab51f1SMartin KaFai Lau 	err = bpf_check_uarg_tail_zero(uattr, sizeof(attr), size);
246099c55f7dSAlexei Starovoitov 	if (err)
246199c55f7dSAlexei Starovoitov 		return err;
24621e270976SMartin KaFai Lau 	size = min_t(u32, size, sizeof(attr));
246399c55f7dSAlexei Starovoitov 
246499c55f7dSAlexei Starovoitov 	/* copy attributes from user space, may be less than sizeof(bpf_attr) */
246599c55f7dSAlexei Starovoitov 	if (copy_from_user(&attr, uattr, size) != 0)
246699c55f7dSAlexei Starovoitov 		return -EFAULT;
246799c55f7dSAlexei Starovoitov 
2468afdb09c7SChenbo Feng 	err = security_bpf(cmd, &attr, size);
2469afdb09c7SChenbo Feng 	if (err < 0)
2470afdb09c7SChenbo Feng 		return err;
2471afdb09c7SChenbo Feng 
247299c55f7dSAlexei Starovoitov 	switch (cmd) {
247399c55f7dSAlexei Starovoitov 	case BPF_MAP_CREATE:
247499c55f7dSAlexei Starovoitov 		err = map_create(&attr);
247599c55f7dSAlexei Starovoitov 		break;
2476db20fd2bSAlexei Starovoitov 	case BPF_MAP_LOOKUP_ELEM:
2477db20fd2bSAlexei Starovoitov 		err = map_lookup_elem(&attr);
2478db20fd2bSAlexei Starovoitov 		break;
2479db20fd2bSAlexei Starovoitov 	case BPF_MAP_UPDATE_ELEM:
2480db20fd2bSAlexei Starovoitov 		err = map_update_elem(&attr);
2481db20fd2bSAlexei Starovoitov 		break;
2482db20fd2bSAlexei Starovoitov 	case BPF_MAP_DELETE_ELEM:
2483db20fd2bSAlexei Starovoitov 		err = map_delete_elem(&attr);
2484db20fd2bSAlexei Starovoitov 		break;
2485db20fd2bSAlexei Starovoitov 	case BPF_MAP_GET_NEXT_KEY:
2486db20fd2bSAlexei Starovoitov 		err = map_get_next_key(&attr);
2487db20fd2bSAlexei Starovoitov 		break;
248809756af4SAlexei Starovoitov 	case BPF_PROG_LOAD:
248909756af4SAlexei Starovoitov 		err = bpf_prog_load(&attr);
249009756af4SAlexei Starovoitov 		break;
2491b2197755SDaniel Borkmann 	case BPF_OBJ_PIN:
2492b2197755SDaniel Borkmann 		err = bpf_obj_pin(&attr);
2493b2197755SDaniel Borkmann 		break;
2494b2197755SDaniel Borkmann 	case BPF_OBJ_GET:
2495b2197755SDaniel Borkmann 		err = bpf_obj_get(&attr);
2496b2197755SDaniel Borkmann 		break;
2497f4324551SDaniel Mack 	case BPF_PROG_ATTACH:
2498f4324551SDaniel Mack 		err = bpf_prog_attach(&attr);
2499f4324551SDaniel Mack 		break;
2500f4324551SDaniel Mack 	case BPF_PROG_DETACH:
2501f4324551SDaniel Mack 		err = bpf_prog_detach(&attr);
2502f4324551SDaniel Mack 		break;
2503468e2f64SAlexei Starovoitov 	case BPF_PROG_QUERY:
2504468e2f64SAlexei Starovoitov 		err = bpf_prog_query(&attr, uattr);
2505468e2f64SAlexei Starovoitov 		break;
25061cf1cae9SAlexei Starovoitov 	case BPF_PROG_TEST_RUN:
25071cf1cae9SAlexei Starovoitov 		err = bpf_prog_test_run(&attr, uattr);
25081cf1cae9SAlexei Starovoitov 		break;
250934ad5580SMartin KaFai Lau 	case BPF_PROG_GET_NEXT_ID:
251034ad5580SMartin KaFai Lau 		err = bpf_obj_get_next_id(&attr, uattr,
251134ad5580SMartin KaFai Lau 					  &prog_idr, &prog_idr_lock);
251234ad5580SMartin KaFai Lau 		break;
251334ad5580SMartin KaFai Lau 	case BPF_MAP_GET_NEXT_ID:
251434ad5580SMartin KaFai Lau 		err = bpf_obj_get_next_id(&attr, uattr,
251534ad5580SMartin KaFai Lau 					  &map_idr, &map_idr_lock);
251634ad5580SMartin KaFai Lau 		break;
2517b16d9aa4SMartin KaFai Lau 	case BPF_PROG_GET_FD_BY_ID:
2518b16d9aa4SMartin KaFai Lau 		err = bpf_prog_get_fd_by_id(&attr);
2519b16d9aa4SMartin KaFai Lau 		break;
2520bd5f5f4eSMartin KaFai Lau 	case BPF_MAP_GET_FD_BY_ID:
2521bd5f5f4eSMartin KaFai Lau 		err = bpf_map_get_fd_by_id(&attr);
2522bd5f5f4eSMartin KaFai Lau 		break;
25231e270976SMartin KaFai Lau 	case BPF_OBJ_GET_INFO_BY_FD:
25241e270976SMartin KaFai Lau 		err = bpf_obj_get_info_by_fd(&attr, uattr);
25251e270976SMartin KaFai Lau 		break;
2526c4f6699dSAlexei Starovoitov 	case BPF_RAW_TRACEPOINT_OPEN:
2527c4f6699dSAlexei Starovoitov 		err = bpf_raw_tracepoint_open(&attr);
2528c4f6699dSAlexei Starovoitov 		break;
2529f56a653cSMartin KaFai Lau 	case BPF_BTF_LOAD:
2530f56a653cSMartin KaFai Lau 		err = bpf_btf_load(&attr);
2531f56a653cSMartin KaFai Lau 		break;
253278958fcaSMartin KaFai Lau 	case BPF_BTF_GET_FD_BY_ID:
253378958fcaSMartin KaFai Lau 		err = bpf_btf_get_fd_by_id(&attr);
253478958fcaSMartin KaFai Lau 		break;
253541bdc4b4SYonghong Song 	case BPF_TASK_FD_QUERY:
253641bdc4b4SYonghong Song 		err = bpf_task_fd_query(&attr, uattr);
253741bdc4b4SYonghong Song 		break;
2538bd513cd0SMauricio Vasquez B 	case BPF_MAP_LOOKUP_AND_DELETE_ELEM:
2539bd513cd0SMauricio Vasquez B 		err = map_lookup_and_delete_elem(&attr);
2540bd513cd0SMauricio Vasquez B 		break;
254199c55f7dSAlexei Starovoitov 	default:
254299c55f7dSAlexei Starovoitov 		err = -EINVAL;
254399c55f7dSAlexei Starovoitov 		break;
254499c55f7dSAlexei Starovoitov 	}
254599c55f7dSAlexei Starovoitov 
254699c55f7dSAlexei Starovoitov 	return err;
254799c55f7dSAlexei Starovoitov }
2548