Blame view

kernel/bpf/syscall.c 18.9 KB
99c55f7d4   Alexei Starovoitov   bpf: introduce BP...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of version 2 of the GNU General Public
   * License as published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   * General Public License for more details.
   */
  #include <linux/bpf.h>
  #include <linux/syscalls.h>
  #include <linux/slab.h>
251d00bf1   Daniel Borkmann   bpf: don't trigge...
15
16
  #include <linux/vmalloc.h>
  #include <linux/mmzone.h>
99c55f7d4   Alexei Starovoitov   bpf: introduce BP...
17
  #include <linux/anon_inodes.h>
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
18
  #include <linux/file.h>
09756af46   Alexei Starovoitov   bpf: expand BPF s...
19
20
  #include <linux/license.h>
  #include <linux/filter.h>
2541517c3   Alexei Starovoitov   tracing, perf: Im...
21
  #include <linux/version.h>
99c55f7d4   Alexei Starovoitov   bpf: introduce BP...
22

b121d1e74   Alexei Starovoitov   bpf: prevent kpro...
23
  DEFINE_PER_CPU(int, bpf_prog_active);
1be7f75d1   Alexei Starovoitov   bpf: enable non-r...
24
  int sysctl_unprivileged_bpf_disabled __read_mostly;
99c55f7d4   Alexei Starovoitov   bpf: introduce BP...
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
  static LIST_HEAD(bpf_map_types);
  
  static struct bpf_map *find_and_alloc_map(union bpf_attr *attr)
  {
  	struct bpf_map_type_list *tl;
  	struct bpf_map *map;
  
  	list_for_each_entry(tl, &bpf_map_types, list_node) {
  		if (tl->type == attr->map_type) {
  			map = tl->ops->map_alloc(attr);
  			if (IS_ERR(map))
  				return map;
  			map->ops = tl->ops;
  			map->map_type = attr->map_type;
  			return map;
  		}
  	}
  	return ERR_PTR(-EINVAL);
  }
  
  /* boot time registration of different map implementations */
  void bpf_register_map_type(struct bpf_map_type_list *tl)
  {
  	list_add(&tl->list_node, &bpf_map_types);
  }
251d00bf1   Daniel Borkmann   bpf: don't trigge...
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
  void *bpf_map_area_alloc(size_t size)
  {
  	/* We definitely need __GFP_NORETRY, so OOM killer doesn't
  	 * trigger under memory pressure as we really just want to
  	 * fail instead.
  	 */
  	const gfp_t flags = __GFP_NOWARN | __GFP_NORETRY | __GFP_ZERO;
  	void *area;
  
  	if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) {
  		area = kmalloc(size, GFP_USER | flags);
  		if (area != NULL)
  			return area;
  	}
  
  	return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM | flags,
  			 PAGE_KERNEL);
  }
  
  void bpf_map_area_free(void *area)
  {
  	kvfree(area);
  }
6c9059817   Alexei Starovoitov   bpf: pre-allocate...
73
74
75
76
77
78
79
80
81
82
83
84
  int bpf_map_precharge_memlock(u32 pages)
  {
  	struct user_struct *user = get_current_user();
  	unsigned long memlock_limit, cur;
  
  	memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
  	cur = atomic_long_read(&user->locked_vm);
  	free_uid(user);
  	if (cur + pages > memlock_limit)
  		return -EPERM;
  	return 0;
  }
aaac3ba95   Alexei Starovoitov   bpf: charge user ...
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
  static int bpf_map_charge_memlock(struct bpf_map *map)
  {
  	struct user_struct *user = get_current_user();
  	unsigned long memlock_limit;
  
  	memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
  
  	atomic_long_add(map->pages, &user->locked_vm);
  
  	if (atomic_long_read(&user->locked_vm) > memlock_limit) {
  		atomic_long_sub(map->pages, &user->locked_vm);
  		free_uid(user);
  		return -EPERM;
  	}
  	map->user = user;
  	return 0;
  }
  
  static void bpf_map_uncharge_memlock(struct bpf_map *map)
  {
  	struct user_struct *user = map->user;
  
  	atomic_long_sub(map->pages, &user->locked_vm);
  	free_uid(user);
  }
99c55f7d4   Alexei Starovoitov   bpf: introduce BP...
110
111
112
113
  /* called from workqueue */
  static void bpf_map_free_deferred(struct work_struct *work)
  {
  	struct bpf_map *map = container_of(work, struct bpf_map, work);
aaac3ba95   Alexei Starovoitov   bpf: charge user ...
114
  	bpf_map_uncharge_memlock(map);
99c55f7d4   Alexei Starovoitov   bpf: introduce BP...
115
116
117
  	/* implementation dependent freeing */
  	map->ops->map_free(map);
  }
c9da161c6   Daniel Borkmann   bpf: fix clearing...
118
119
120
121
122
123
124
  static void bpf_map_put_uref(struct bpf_map *map)
  {
  	if (atomic_dec_and_test(&map->usercnt)) {
  		if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY)
  			bpf_fd_array_map_clear(map);
  	}
  }
99c55f7d4   Alexei Starovoitov   bpf: introduce BP...
125
126
127
128
129
130
131
132
133
134
  /* decrement map refcnt and schedule it for freeing via workqueue
   * (unrelying map implementation ops->map_free() might sleep)
   */
  void bpf_map_put(struct bpf_map *map)
  {
  	if (atomic_dec_and_test(&map->refcnt)) {
  		INIT_WORK(&map->work, bpf_map_free_deferred);
  		schedule_work(&map->work);
  	}
  }
c9da161c6   Daniel Borkmann   bpf: fix clearing...
135
  void bpf_map_put_with_uref(struct bpf_map *map)
99c55f7d4   Alexei Starovoitov   bpf: introduce BP...
136
  {
c9da161c6   Daniel Borkmann   bpf: fix clearing...
137
  	bpf_map_put_uref(map);
99c55f7d4   Alexei Starovoitov   bpf: introduce BP...
138
  	bpf_map_put(map);
c9da161c6   Daniel Borkmann   bpf: fix clearing...
139
140
141
142
  }
  
  static int bpf_map_release(struct inode *inode, struct file *filp)
  {
61d1b6a42   Daniel Borkmann   bpf, maps: add re...
143
144
145
146
147
148
  	struct bpf_map *map = filp->private_data;
  
  	if (map->ops->map_release)
  		map->ops->map_release(map, filp);
  
  	bpf_map_put_with_uref(map);
99c55f7d4   Alexei Starovoitov   bpf: introduce BP...
149
150
  	return 0;
  }
f99bf205d   Daniel Borkmann   bpf: add show_fdi...
151
152
153
154
155
156
157
158
159
160
161
162
  #ifdef CONFIG_PROC_FS
  static void bpf_map_show_fdinfo(struct seq_file *m, struct file *filp)
  {
  	const struct bpf_map *map = filp->private_data;
  
  	seq_printf(m,
  		   "map_type:\t%u
  "
  		   "key_size:\t%u
  "
  		   "value_size:\t%u
  "
322cea2f4   Daniel Borkmann   bpf: add missing ...
163
164
165
166
  		   "max_entries:\t%u
  "
  		   "map_flags:\t%#x
  ",
f99bf205d   Daniel Borkmann   bpf: add show_fdi...
167
168
169
  		   map->map_type,
  		   map->key_size,
  		   map->value_size,
322cea2f4   Daniel Borkmann   bpf: add missing ...
170
171
  		   map->max_entries,
  		   map->map_flags);
f99bf205d   Daniel Borkmann   bpf: add show_fdi...
172
173
  }
  #endif
99c55f7d4   Alexei Starovoitov   bpf: introduce BP...
174
  static const struct file_operations bpf_map_fops = {
f99bf205d   Daniel Borkmann   bpf: add show_fdi...
175
176
177
178
  #ifdef CONFIG_PROC_FS
  	.show_fdinfo	= bpf_map_show_fdinfo,
  #endif
  	.release	= bpf_map_release,
99c55f7d4   Alexei Starovoitov   bpf: introduce BP...
179
  };
b2197755b   Daniel Borkmann   bpf: add support ...
180
  int bpf_map_new_fd(struct bpf_map *map)
aa79781b6   Daniel Borkmann   bpf: abstract ano...
181
182
183
184
  {
  	return anon_inode_getfd("bpf-map", &bpf_map_fops, map,
  				O_RDWR | O_CLOEXEC);
  }
99c55f7d4   Alexei Starovoitov   bpf: introduce BP...
185
186
187
188
189
190
191
  /* helper macro to check that unused fields 'union bpf_attr' are zero */
  #define CHECK_ATTR(CMD) \
  	memchr_inv((void *) &attr->CMD##_LAST_FIELD + \
  		   sizeof(attr->CMD##_LAST_FIELD), 0, \
  		   sizeof(*attr) - \
  		   offsetof(union bpf_attr, CMD##_LAST_FIELD) - \
  		   sizeof(attr->CMD##_LAST_FIELD)) != NULL
6c9059817   Alexei Starovoitov   bpf: pre-allocate...
192
  #define BPF_MAP_CREATE_LAST_FIELD map_flags
99c55f7d4   Alexei Starovoitov   bpf: introduce BP...
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
  /* called via syscall */
  static int map_create(union bpf_attr *attr)
  {
  	struct bpf_map *map;
  	int err;
  
  	err = CHECK_ATTR(BPF_MAP_CREATE);
  	if (err)
  		return -EINVAL;
  
  	/* find map type and init map: hashtable vs rbtree vs bloom vs ... */
  	map = find_and_alloc_map(attr);
  	if (IS_ERR(map))
  		return PTR_ERR(map);
  
  	atomic_set(&map->refcnt, 1);
c9da161c6   Daniel Borkmann   bpf: fix clearing...
209
  	atomic_set(&map->usercnt, 1);
99c55f7d4   Alexei Starovoitov   bpf: introduce BP...
210

aaac3ba95   Alexei Starovoitov   bpf: charge user ...
211
212
  	err = bpf_map_charge_memlock(map);
  	if (err)
20b2b24f9   Daniel Borkmann   bpf: fix map not ...
213
  		goto free_map_nouncharge;
aaac3ba95   Alexei Starovoitov   bpf: charge user ...
214

aa79781b6   Daniel Borkmann   bpf: abstract ano...
215
  	err = bpf_map_new_fd(map);
99c55f7d4   Alexei Starovoitov   bpf: introduce BP...
216
217
218
219
220
221
222
  	if (err < 0)
  		/* failed to allocate fd */
  		goto free_map;
  
  	return err;
  
  free_map:
20b2b24f9   Daniel Borkmann   bpf: fix map not ...
223
224
  	bpf_map_uncharge_memlock(map);
  free_map_nouncharge:
99c55f7d4   Alexei Starovoitov   bpf: introduce BP...
225
226
227
  	map->ops->map_free(map);
  	return err;
  }
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
228
229
230
  /* if error is returned, fd is released.
   * On success caller should complete fd access with matching fdput()
   */
c21012976   Daniel Borkmann   bpf: align and cl...
231
  struct bpf_map *__bpf_map_get(struct fd f)
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
232
  {
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
233
234
  	if (!f.file)
  		return ERR_PTR(-EBADF);
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
235
236
237
238
  	if (f.file->f_op != &bpf_map_fops) {
  		fdput(f);
  		return ERR_PTR(-EINVAL);
  	}
c21012976   Daniel Borkmann   bpf: align and cl...
239
240
  	return f.file->private_data;
  }
92117d844   Alexei Starovoitov   bpf: fix refcnt o...
241
242
243
244
  /* prog's and map's refcnt limit */
  #define BPF_MAX_REFCNT 32768
  
  struct bpf_map *bpf_map_inc(struct bpf_map *map, bool uref)
c9da161c6   Daniel Borkmann   bpf: fix clearing...
245
  {
92117d844   Alexei Starovoitov   bpf: fix refcnt o...
246
247
248
249
  	if (atomic_inc_return(&map->refcnt) > BPF_MAX_REFCNT) {
  		atomic_dec(&map->refcnt);
  		return ERR_PTR(-EBUSY);
  	}
c9da161c6   Daniel Borkmann   bpf: fix clearing...
250
251
  	if (uref)
  		atomic_inc(&map->usercnt);
92117d844   Alexei Starovoitov   bpf: fix refcnt o...
252
  	return map;
c9da161c6   Daniel Borkmann   bpf: fix clearing...
253
254
255
  }
  
  struct bpf_map *bpf_map_get_with_uref(u32 ufd)
c21012976   Daniel Borkmann   bpf: align and cl...
256
257
258
259
260
261
262
  {
  	struct fd f = fdget(ufd);
  	struct bpf_map *map;
  
  	map = __bpf_map_get(f);
  	if (IS_ERR(map))
  		return map;
92117d844   Alexei Starovoitov   bpf: fix refcnt o...
263
  	map = bpf_map_inc(map, true);
c21012976   Daniel Borkmann   bpf: align and cl...
264
  	fdput(f);
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
265
266
267
268
269
270
271
272
273
  
  	return map;
  }
  
  /* helper to convert user pointers passed inside __aligned_u64 fields */
  static void __user *u64_to_ptr(__u64 val)
  {
  	return (void __user *) (unsigned long) val;
  }
b8cdc0517   Alexei Starovoitov   bpf: bpf_stackmap...
274
275
276
277
  int __weak bpf_stackmap_copy(struct bpf_map *map, void *key, void *value)
  {
  	return -ENOTSUPP;
  }
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
278
279
280
281
282
283
284
285
  /* last field in 'union bpf_attr' used by this command */
  #define BPF_MAP_LOOKUP_ELEM_LAST_FIELD value
  
  static int map_lookup_elem(union bpf_attr *attr)
  {
  	void __user *ukey = u64_to_ptr(attr->key);
  	void __user *uvalue = u64_to_ptr(attr->value);
  	int ufd = attr->map_fd;
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
286
  	struct bpf_map *map;
8ebe667c4   Alexei Starovoitov   bpf: rcu lock mus...
287
  	void *key, *value, *ptr;
15a07b338   Alexei Starovoitov   bpf: add lookup/u...
288
  	u32 value_size;
592867bfa   Daniel Borkmann   ebpf: fix fd refc...
289
  	struct fd f;
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
290
291
292
293
  	int err;
  
  	if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM))
  		return -EINVAL;
592867bfa   Daniel Borkmann   ebpf: fix fd refc...
294
  	f = fdget(ufd);
c21012976   Daniel Borkmann   bpf: align and cl...
295
  	map = __bpf_map_get(f);
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
296
297
298
299
300
301
302
303
304
305
306
  	if (IS_ERR(map))
  		return PTR_ERR(map);
  
  	err = -ENOMEM;
  	key = kmalloc(map->key_size, GFP_USER);
  	if (!key)
  		goto err_put;
  
  	err = -EFAULT;
  	if (copy_from_user(key, ukey, map->key_size) != 0)
  		goto free_key;
15a07b338   Alexei Starovoitov   bpf: add lookup/u...
307
308
309
310
311
  	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
  	    map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY)
  		value_size = round_up(map->value_size, 8) * num_possible_cpus();
  	else
  		value_size = map->value_size;
8ebe667c4   Alexei Starovoitov   bpf: rcu lock mus...
312
  	err = -ENOMEM;
15a07b338   Alexei Starovoitov   bpf: add lookup/u...
313
  	value = kmalloc(value_size, GFP_USER | __GFP_NOWARN);
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
314
  	if (!value)
8ebe667c4   Alexei Starovoitov   bpf: rcu lock mus...
315
  		goto free_key;
15a07b338   Alexei Starovoitov   bpf: add lookup/u...
316
317
318
319
  	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH) {
  		err = bpf_percpu_hash_copy(map, key, value);
  	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
  		err = bpf_percpu_array_copy(map, key, value);
557c0c6e7   Alexei Starovoitov   bpf: convert stac...
320
321
  	} else if (map->map_type == BPF_MAP_TYPE_STACK_TRACE) {
  		err = bpf_stackmap_copy(map, key, value);
15a07b338   Alexei Starovoitov   bpf: add lookup/u...
322
323
324
325
326
327
328
329
  	} else {
  		rcu_read_lock();
  		ptr = map->ops->map_lookup_elem(map, key);
  		if (ptr)
  			memcpy(value, ptr, value_size);
  		rcu_read_unlock();
  		err = ptr ? 0 : -ENOENT;
  	}
8ebe667c4   Alexei Starovoitov   bpf: rcu lock mus...
330

15a07b338   Alexei Starovoitov   bpf: add lookup/u...
331
  	if (err)
8ebe667c4   Alexei Starovoitov   bpf: rcu lock mus...
332
  		goto free_value;
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
333
334
  
  	err = -EFAULT;
15a07b338   Alexei Starovoitov   bpf: add lookup/u...
335
  	if (copy_to_user(uvalue, value, value_size) != 0)
8ebe667c4   Alexei Starovoitov   bpf: rcu lock mus...
336
  		goto free_value;
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
337
338
  
  	err = 0;
8ebe667c4   Alexei Starovoitov   bpf: rcu lock mus...
339
340
  free_value:
  	kfree(value);
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
341
342
343
344
345
346
  free_key:
  	kfree(key);
  err_put:
  	fdput(f);
  	return err;
  }
3274f5207   Alexei Starovoitov   bpf: add 'flags' ...
347
  #define BPF_MAP_UPDATE_ELEM_LAST_FIELD flags
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
348
349
350
351
352
353
  
  static int map_update_elem(union bpf_attr *attr)
  {
  	void __user *ukey = u64_to_ptr(attr->key);
  	void __user *uvalue = u64_to_ptr(attr->value);
  	int ufd = attr->map_fd;
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
354
355
  	struct bpf_map *map;
  	void *key, *value;
15a07b338   Alexei Starovoitov   bpf: add lookup/u...
356
  	u32 value_size;
592867bfa   Daniel Borkmann   ebpf: fix fd refc...
357
  	struct fd f;
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
358
359
360
361
  	int err;
  
  	if (CHECK_ATTR(BPF_MAP_UPDATE_ELEM))
  		return -EINVAL;
592867bfa   Daniel Borkmann   ebpf: fix fd refc...
362
  	f = fdget(ufd);
c21012976   Daniel Borkmann   bpf: align and cl...
363
  	map = __bpf_map_get(f);
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
364
365
366
367
368
369
370
371
372
373
374
  	if (IS_ERR(map))
  		return PTR_ERR(map);
  
  	err = -ENOMEM;
  	key = kmalloc(map->key_size, GFP_USER);
  	if (!key)
  		goto err_put;
  
  	err = -EFAULT;
  	if (copy_from_user(key, ukey, map->key_size) != 0)
  		goto free_key;
15a07b338   Alexei Starovoitov   bpf: add lookup/u...
375
376
377
378
379
  	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
  	    map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY)
  		value_size = round_up(map->value_size, 8) * num_possible_cpus();
  	else
  		value_size = map->value_size;
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
380
  	err = -ENOMEM;
15a07b338   Alexei Starovoitov   bpf: add lookup/u...
381
  	value = kmalloc(value_size, GFP_USER | __GFP_NOWARN);
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
382
383
384
385
  	if (!value)
  		goto free_key;
  
  	err = -EFAULT;
15a07b338   Alexei Starovoitov   bpf: add lookup/u...
386
  	if (copy_from_user(value, uvalue, value_size) != 0)
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
387
  		goto free_value;
b121d1e74   Alexei Starovoitov   bpf: prevent kpro...
388
389
390
391
392
  	/* must increment bpf_prog_active to avoid kprobe+bpf triggering from
  	 * inside bpf map update or delete otherwise deadlocks are possible
  	 */
  	preempt_disable();
  	__this_cpu_inc(bpf_prog_active);
15a07b338   Alexei Starovoitov   bpf: add lookup/u...
393
394
395
396
  	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH) {
  		err = bpf_percpu_hash_update(map, key, value, attr->flags);
  	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
  		err = bpf_percpu_array_update(map, key, value, attr->flags);
d056a7887   Daniel Borkmann   bpf, maps: extend...
397
  	} else if (map->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY ||
4ed8ec521   Martin KaFai Lau   cgroup: bpf: Add ...
398
399
  		   map->map_type == BPF_MAP_TYPE_PROG_ARRAY ||
  		   map->map_type == BPF_MAP_TYPE_CGROUP_ARRAY) {
d056a7887   Daniel Borkmann   bpf, maps: extend...
400
401
402
403
  		rcu_read_lock();
  		err = bpf_fd_array_map_update_elem(map, f.file, key, value,
  						   attr->flags);
  		rcu_read_unlock();
15a07b338   Alexei Starovoitov   bpf: add lookup/u...
404
405
406
407
408
  	} else {
  		rcu_read_lock();
  		err = map->ops->map_update_elem(map, key, value, attr->flags);
  		rcu_read_unlock();
  	}
b121d1e74   Alexei Starovoitov   bpf: prevent kpro...
409
410
  	__this_cpu_dec(bpf_prog_active);
  	preempt_enable();
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
  
  free_value:
  	kfree(value);
  free_key:
  	kfree(key);
  err_put:
  	fdput(f);
  	return err;
  }
  
  #define BPF_MAP_DELETE_ELEM_LAST_FIELD key
  
  static int map_delete_elem(union bpf_attr *attr)
  {
  	void __user *ukey = u64_to_ptr(attr->key);
  	int ufd = attr->map_fd;
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
427
  	struct bpf_map *map;
592867bfa   Daniel Borkmann   ebpf: fix fd refc...
428
  	struct fd f;
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
429
430
431
432
433
  	void *key;
  	int err;
  
  	if (CHECK_ATTR(BPF_MAP_DELETE_ELEM))
  		return -EINVAL;
592867bfa   Daniel Borkmann   ebpf: fix fd refc...
434
  	f = fdget(ufd);
c21012976   Daniel Borkmann   bpf: align and cl...
435
  	map = __bpf_map_get(f);
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
436
437
438
439
440
441
442
443
444
445
446
  	if (IS_ERR(map))
  		return PTR_ERR(map);
  
  	err = -ENOMEM;
  	key = kmalloc(map->key_size, GFP_USER);
  	if (!key)
  		goto err_put;
  
  	err = -EFAULT;
  	if (copy_from_user(key, ukey, map->key_size) != 0)
  		goto free_key;
b121d1e74   Alexei Starovoitov   bpf: prevent kpro...
447
448
  	preempt_disable();
  	__this_cpu_inc(bpf_prog_active);
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
449
450
451
  	rcu_read_lock();
  	err = map->ops->map_delete_elem(map, key);
  	rcu_read_unlock();
b121d1e74   Alexei Starovoitov   bpf: prevent kpro...
452
453
  	__this_cpu_dec(bpf_prog_active);
  	preempt_enable();
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
  
  free_key:
  	kfree(key);
  err_put:
  	fdput(f);
  	return err;
  }
  
  /* last field in 'union bpf_attr' used by this command */
  #define BPF_MAP_GET_NEXT_KEY_LAST_FIELD next_key
  
  static int map_get_next_key(union bpf_attr *attr)
  {
  	void __user *ukey = u64_to_ptr(attr->key);
  	void __user *unext_key = u64_to_ptr(attr->next_key);
  	int ufd = attr->map_fd;
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
470
471
  	struct bpf_map *map;
  	void *key, *next_key;
592867bfa   Daniel Borkmann   ebpf: fix fd refc...
472
  	struct fd f;
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
473
474
475
476
  	int err;
  
  	if (CHECK_ATTR(BPF_MAP_GET_NEXT_KEY))
  		return -EINVAL;
592867bfa   Daniel Borkmann   ebpf: fix fd refc...
477
  	f = fdget(ufd);
c21012976   Daniel Borkmann   bpf: align and cl...
478
  	map = __bpf_map_get(f);
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
  	if (IS_ERR(map))
  		return PTR_ERR(map);
  
  	err = -ENOMEM;
  	key = kmalloc(map->key_size, GFP_USER);
  	if (!key)
  		goto err_put;
  
  	err = -EFAULT;
  	if (copy_from_user(key, ukey, map->key_size) != 0)
  		goto free_key;
  
  	err = -ENOMEM;
  	next_key = kmalloc(map->key_size, GFP_USER);
  	if (!next_key)
  		goto free_key;
  
  	rcu_read_lock();
  	err = map->ops->map_get_next_key(map, key, next_key);
  	rcu_read_unlock();
  	if (err)
  		goto free_next_key;
  
  	err = -EFAULT;
  	if (copy_to_user(unext_key, next_key, map->key_size) != 0)
  		goto free_next_key;
  
  	err = 0;
  
  free_next_key:
  	kfree(next_key);
  free_key:
  	kfree(key);
  err_put:
  	fdput(f);
  	return err;
  }
09756af46   Alexei Starovoitov   bpf: expand BPF s...
516
517
518
519
520
521
522
523
524
  static LIST_HEAD(bpf_prog_types);
  
  static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog)
  {
  	struct bpf_prog_type_list *tl;
  
  	list_for_each_entry(tl, &bpf_prog_types, list_node) {
  		if (tl->type == type) {
  			prog->aux->ops = tl->ops;
24701ecea   Daniel Borkmann   ebpf: move read-o...
525
  			prog->type = type;
09756af46   Alexei Starovoitov   bpf: expand BPF s...
526
527
528
  			return 0;
  		}
  	}
24701ecea   Daniel Borkmann   ebpf: move read-o...
529

09756af46   Alexei Starovoitov   bpf: expand BPF s...
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
  	return -EINVAL;
  }
  
  void bpf_register_prog_type(struct bpf_prog_type_list *tl)
  {
  	list_add(&tl->list_node, &bpf_prog_types);
  }
  
  /* drop refcnt on maps used by eBPF program and free auxilary data */
  static void free_used_maps(struct bpf_prog_aux *aux)
  {
  	int i;
  
  	for (i = 0; i < aux->used_map_cnt; i++)
  		bpf_map_put(aux->used_maps[i]);
  
  	kfree(aux->used_maps);
  }
aaac3ba95   Alexei Starovoitov   bpf: charge user ...
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
  static int bpf_prog_charge_memlock(struct bpf_prog *prog)
  {
  	struct user_struct *user = get_current_user();
  	unsigned long memlock_limit;
  
  	memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
  
  	atomic_long_add(prog->pages, &user->locked_vm);
  	if (atomic_long_read(&user->locked_vm) > memlock_limit) {
  		atomic_long_sub(prog->pages, &user->locked_vm);
  		free_uid(user);
  		return -EPERM;
  	}
  	prog->aux->user = user;
  	return 0;
  }
  
  static void bpf_prog_uncharge_memlock(struct bpf_prog *prog)
  {
  	struct user_struct *user = prog->aux->user;
  
  	atomic_long_sub(prog->pages, &user->locked_vm);
  	free_uid(user);
  }
1aacde3d2   Daniel Borkmann   bpf: generally mo...
572
  static void __bpf_prog_put_rcu(struct rcu_head *rcu)
abf2e7d6e   Alexei Starovoitov   bpf: add missing ...
573
574
575
576
  {
  	struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu);
  
  	free_used_maps(aux);
aaac3ba95   Alexei Starovoitov   bpf: charge user ...
577
  	bpf_prog_uncharge_memlock(aux->prog);
abf2e7d6e   Alexei Starovoitov   bpf: add missing ...
578
579
  	bpf_prog_free(aux->prog);
  }
09756af46   Alexei Starovoitov   bpf: expand BPF s...
580
581
  void bpf_prog_put(struct bpf_prog *prog)
  {
e9d8afa90   Daniel Borkmann   bpf: consolidate ...
582
  	if (atomic_dec_and_test(&prog->aux->refcnt))
1aacde3d2   Daniel Borkmann   bpf: generally mo...
583
  		call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu);
09756af46   Alexei Starovoitov   bpf: expand BPF s...
584
  }
e2e9b6541   Daniel Borkmann   cls_bpf: add init...
585
  EXPORT_SYMBOL_GPL(bpf_prog_put);
09756af46   Alexei Starovoitov   bpf: expand BPF s...
586
587
588
589
  
  static int bpf_prog_release(struct inode *inode, struct file *filp)
  {
  	struct bpf_prog *prog = filp->private_data;
1aacde3d2   Daniel Borkmann   bpf: generally mo...
590
  	bpf_prog_put(prog);
09756af46   Alexei Starovoitov   bpf: expand BPF s...
591
592
593
594
595
596
  	return 0;
  }
  
  static const struct file_operations bpf_prog_fops = {
          .release = bpf_prog_release,
  };
b2197755b   Daniel Borkmann   bpf: add support ...
597
  int bpf_prog_new_fd(struct bpf_prog *prog)
aa79781b6   Daniel Borkmann   bpf: abstract ano...
598
599
600
601
  {
  	return anon_inode_getfd("bpf-prog", &bpf_prog_fops, prog,
  				O_RDWR | O_CLOEXEC);
  }
113214be7   Daniel Borkmann   bpf: refactor bpf...
602
  static struct bpf_prog *____bpf_prog_get(struct fd f)
09756af46   Alexei Starovoitov   bpf: expand BPF s...
603
  {
09756af46   Alexei Starovoitov   bpf: expand BPF s...
604
605
  	if (!f.file)
  		return ERR_PTR(-EBADF);
09756af46   Alexei Starovoitov   bpf: expand BPF s...
606
607
608
609
  	if (f.file->f_op != &bpf_prog_fops) {
  		fdput(f);
  		return ERR_PTR(-EINVAL);
  	}
c21012976   Daniel Borkmann   bpf: align and cl...
610
  	return f.file->private_data;
09756af46   Alexei Starovoitov   bpf: expand BPF s...
611
  }
59d3656d5   Brenden Blanco   bpf: add bpf_prog...
612
  struct bpf_prog *bpf_prog_add(struct bpf_prog *prog, int i)
92117d844   Alexei Starovoitov   bpf: fix refcnt o...
613
  {
59d3656d5   Brenden Blanco   bpf: add bpf_prog...
614
615
  	if (atomic_add_return(i, &prog->aux->refcnt) > BPF_MAX_REFCNT) {
  		atomic_sub(i, &prog->aux->refcnt);
92117d844   Alexei Starovoitov   bpf: fix refcnt o...
616
617
618
619
  		return ERR_PTR(-EBUSY);
  	}
  	return prog;
  }
59d3656d5   Brenden Blanco   bpf: add bpf_prog...
620
621
622
623
624
625
  EXPORT_SYMBOL_GPL(bpf_prog_add);
  
  struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog)
  {
  	return bpf_prog_add(prog, 1);
  }
92117d844   Alexei Starovoitov   bpf: fix refcnt o...
626

113214be7   Daniel Borkmann   bpf: refactor bpf...
627
  static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *type)
09756af46   Alexei Starovoitov   bpf: expand BPF s...
628
629
630
  {
  	struct fd f = fdget(ufd);
  	struct bpf_prog *prog;
113214be7   Daniel Borkmann   bpf: refactor bpf...
631
  	prog = ____bpf_prog_get(f);
09756af46   Alexei Starovoitov   bpf: expand BPF s...
632
633
  	if (IS_ERR(prog))
  		return prog;
113214be7   Daniel Borkmann   bpf: refactor bpf...
634
635
636
637
  	if (type && prog->type != *type) {
  		prog = ERR_PTR(-EINVAL);
  		goto out;
  	}
09756af46   Alexei Starovoitov   bpf: expand BPF s...
638

92117d844   Alexei Starovoitov   bpf: fix refcnt o...
639
  	prog = bpf_prog_inc(prog);
113214be7   Daniel Borkmann   bpf: refactor bpf...
640
  out:
09756af46   Alexei Starovoitov   bpf: expand BPF s...
641
642
643
  	fdput(f);
  	return prog;
  }
113214be7   Daniel Borkmann   bpf: refactor bpf...
644
645
646
647
648
649
650
651
652
653
654
  
  struct bpf_prog *bpf_prog_get(u32 ufd)
  {
  	return __bpf_prog_get(ufd, NULL);
  }
  
  struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type)
  {
  	return __bpf_prog_get(ufd, &type);
  }
  EXPORT_SYMBOL_GPL(bpf_prog_get_type);
09756af46   Alexei Starovoitov   bpf: expand BPF s...
655
656
  
  /* last field in 'union bpf_attr' used by this command */
2541517c3   Alexei Starovoitov   tracing, perf: Im...
657
  #define	BPF_PROG_LOAD_LAST_FIELD kern_version
09756af46   Alexei Starovoitov   bpf: expand BPF s...
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
  
  static int bpf_prog_load(union bpf_attr *attr)
  {
  	enum bpf_prog_type type = attr->prog_type;
  	struct bpf_prog *prog;
  	int err;
  	char license[128];
  	bool is_gpl;
  
  	if (CHECK_ATTR(BPF_PROG_LOAD))
  		return -EINVAL;
  
  	/* copy eBPF program license from user space */
  	if (strncpy_from_user(license, u64_to_ptr(attr->license),
  			      sizeof(license) - 1) < 0)
  		return -EFAULT;
  	license[sizeof(license) - 1] = 0;
  
  	/* eBPF programs must be GPL compatible to use GPL-ed functions */
  	is_gpl = license_is_gpl_compatible(license);
  
  	if (attr->insn_cnt >= BPF_MAXINSNS)
  		return -EINVAL;
2541517c3   Alexei Starovoitov   tracing, perf: Im...
681
682
683
  	if (type == BPF_PROG_TYPE_KPROBE &&
  	    attr->kern_version != LINUX_VERSION_CODE)
  		return -EINVAL;
1be7f75d1   Alexei Starovoitov   bpf: enable non-r...
684
685
  	if (type != BPF_PROG_TYPE_SOCKET_FILTER && !capable(CAP_SYS_ADMIN))
  		return -EPERM;
09756af46   Alexei Starovoitov   bpf: expand BPF s...
686
687
688
689
  	/* plain bpf_prog allocation */
  	prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER);
  	if (!prog)
  		return -ENOMEM;
aaac3ba95   Alexei Starovoitov   bpf: charge user ...
690
691
692
  	err = bpf_prog_charge_memlock(prog);
  	if (err)
  		goto free_prog_nouncharge;
09756af46   Alexei Starovoitov   bpf: expand BPF s...
693
694
695
696
697
698
699
700
  	prog->len = attr->insn_cnt;
  
  	err = -EFAULT;
  	if (copy_from_user(prog->insns, u64_to_ptr(attr->insns),
  			   prog->len * sizeof(struct bpf_insn)) != 0)
  		goto free_prog;
  
  	prog->orig_prog = NULL;
a91263d52   Daniel Borkmann   ebpf: migrate bpf...
701
  	prog->jited = 0;
09756af46   Alexei Starovoitov   bpf: expand BPF s...
702
703
  
  	atomic_set(&prog->aux->refcnt, 1);
a91263d52   Daniel Borkmann   ebpf: migrate bpf...
704
  	prog->gpl_compatible = is_gpl ? 1 : 0;
09756af46   Alexei Starovoitov   bpf: expand BPF s...
705
706
707
708
709
710
711
  
  	/* find program type: socket_filter vs tracing_filter */
  	err = find_prog_type(type, prog);
  	if (err < 0)
  		goto free_prog;
  
  	/* run eBPF verifier */
9bac3d6d5   Alexei Starovoitov   bpf: allow extend...
712
  	err = bpf_check(&prog, attr);
09756af46   Alexei Starovoitov   bpf: expand BPF s...
713
714
715
716
  	if (err < 0)
  		goto free_used_maps;
  
  	/* eBPF program is ready to be JITed */
d1c55ab5e   Daniel Borkmann   bpf: prepare bpf_...
717
  	prog = bpf_prog_select_runtime(prog, &err);
04fd61ab3   Alexei Starovoitov   bpf: allow bpf pr...
718
719
  	if (err < 0)
  		goto free_used_maps;
09756af46   Alexei Starovoitov   bpf: expand BPF s...
720

aa79781b6   Daniel Borkmann   bpf: abstract ano...
721
  	err = bpf_prog_new_fd(prog);
09756af46   Alexei Starovoitov   bpf: expand BPF s...
722
723
724
725
726
727
728
729
730
  	if (err < 0)
  		/* failed to allocate fd */
  		goto free_used_maps;
  
  	return err;
  
  free_used_maps:
  	free_used_maps(prog->aux);
  free_prog:
aaac3ba95   Alexei Starovoitov   bpf: charge user ...
731
732
  	bpf_prog_uncharge_memlock(prog);
  free_prog_nouncharge:
09756af46   Alexei Starovoitov   bpf: expand BPF s...
733
734
735
  	bpf_prog_free(prog);
  	return err;
  }
b2197755b   Daniel Borkmann   bpf: add support ...
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
  #define BPF_OBJ_LAST_FIELD bpf_fd
  
  static int bpf_obj_pin(const union bpf_attr *attr)
  {
  	if (CHECK_ATTR(BPF_OBJ))
  		return -EINVAL;
  
  	return bpf_obj_pin_user(attr->bpf_fd, u64_to_ptr(attr->pathname));
  }
  
  static int bpf_obj_get(const union bpf_attr *attr)
  {
  	if (CHECK_ATTR(BPF_OBJ) || attr->bpf_fd != 0)
  		return -EINVAL;
  
  	return bpf_obj_get_user(u64_to_ptr(attr->pathname));
  }
99c55f7d4   Alexei Starovoitov   bpf: introduce BP...
753
754
755
756
  SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
  {
  	union bpf_attr attr = {};
  	int err;
1be7f75d1   Alexei Starovoitov   bpf: enable non-r...
757
  	if (!capable(CAP_SYS_ADMIN) && sysctl_unprivileged_bpf_disabled)
99c55f7d4   Alexei Starovoitov   bpf: introduce BP...
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
  		return -EPERM;
  
  	if (!access_ok(VERIFY_READ, uattr, 1))
  		return -EFAULT;
  
  	if (size > PAGE_SIZE)	/* silly large */
  		return -E2BIG;
  
  	/* If we're handed a bigger struct than we know of,
  	 * ensure all the unknown bits are 0 - i.e. new
  	 * user-space does not rely on any kernel feature
  	 * extensions we dont know about yet.
  	 */
  	if (size > sizeof(attr)) {
  		unsigned char __user *addr;
  		unsigned char __user *end;
  		unsigned char val;
  
  		addr = (void __user *)uattr + sizeof(attr);
  		end  = (void __user *)uattr + size;
  
  		for (; addr < end; addr++) {
  			err = get_user(val, addr);
  			if (err)
  				return err;
  			if (val)
  				return -E2BIG;
  		}
  		size = sizeof(attr);
  	}
  
  	/* copy attributes from user space, may be less than sizeof(bpf_attr) */
  	if (copy_from_user(&attr, uattr, size) != 0)
  		return -EFAULT;
  
  	switch (cmd) {
  	case BPF_MAP_CREATE:
  		err = map_create(&attr);
  		break;
db20fd2b0   Alexei Starovoitov   bpf: add lookup/u...
797
798
799
800
801
802
803
804
805
806
807
808
  	case BPF_MAP_LOOKUP_ELEM:
  		err = map_lookup_elem(&attr);
  		break;
  	case BPF_MAP_UPDATE_ELEM:
  		err = map_update_elem(&attr);
  		break;
  	case BPF_MAP_DELETE_ELEM:
  		err = map_delete_elem(&attr);
  		break;
  	case BPF_MAP_GET_NEXT_KEY:
  		err = map_get_next_key(&attr);
  		break;
09756af46   Alexei Starovoitov   bpf: expand BPF s...
809
810
811
  	case BPF_PROG_LOAD:
  		err = bpf_prog_load(&attr);
  		break;
b2197755b   Daniel Borkmann   bpf: add support ...
812
813
814
815
816
817
  	case BPF_OBJ_PIN:
  		err = bpf_obj_pin(&attr);
  		break;
  	case BPF_OBJ_GET:
  		err = bpf_obj_get(&attr);
  		break;
99c55f7d4   Alexei Starovoitov   bpf: introduce BP...
818
819
820
821
822
823
824
  	default:
  		err = -EINVAL;
  		break;
  	}
  
  	return err;
  }