Blame view

kernel/bpf/inode.c 17.2 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
b2197755b   Daniel Borkmann   bpf: add support ...
2
3
4
5
6
7
8
  /*
   * Minimal file system backend for holding eBPF maps and programs,
   * used by bpf(2) object pinning.
   *
   * Authors:
   *
   *	Daniel Borkmann <daniel@iogearbox.net>
b2197755b   Daniel Borkmann   bpf: add support ...
9
   */
a536a6e13   Paul Gortmaker   bpf: make inode c...
10
  #include <linux/init.h>
b2197755b   Daniel Borkmann   bpf: add support ...
11
12
13
14
15
  #include <linux/magic.h>
  #include <linux/major.h>
  #include <linux/mount.h>
  #include <linux/namei.h>
  #include <linux/fs.h>
d2935de7e   David Howells   vfs: Convert bpf ...
16
17
  #include <linux/fs_context.h>
  #include <linux/fs_parser.h>
b2197755b   Daniel Borkmann   bpf: add support ...
18
19
20
  #include <linux/kdev_t.h>
  #include <linux/filter.h>
  #include <linux/bpf.h>
a67edbf4f   Daniel Borkmann   bpf: add initial ...
21
  #include <linux/bpf_trace.h>
d71fa5c97   Alexei Starovoitov   bpf: Add kernel m...
22
  #include "preload/bpf_preload.h"
b2197755b   Daniel Borkmann   bpf: add support ...
23
24
25
26
27
  
  enum bpf_type {
  	BPF_TYPE_UNSPEC	= 0,
  	BPF_TYPE_PROG,
  	BPF_TYPE_MAP,
70ed506c3   Andrii Nakryiko   bpf: Introduce pi...
28
  	BPF_TYPE_LINK,
b2197755b   Daniel Borkmann   bpf: add support ...
29
30
31
32
33
34
  };
  
  static void *bpf_any_get(void *raw, enum bpf_type type)
  {
  	switch (type) {
  	case BPF_TYPE_PROG:
85192dbf4   Andrii Nakryiko   bpf: Convert bpf_...
35
  		bpf_prog_inc(raw);
b2197755b   Daniel Borkmann   bpf: add support ...
36
37
  		break;
  	case BPF_TYPE_MAP:
1e0bd5a09   Andrii Nakryiko   bpf: Switch bpf_m...
38
  		bpf_map_inc_with_uref(raw);
b2197755b   Daniel Borkmann   bpf: add support ...
39
  		break;
70ed506c3   Andrii Nakryiko   bpf: Introduce pi...
40
41
42
  	case BPF_TYPE_LINK:
  		bpf_link_inc(raw);
  		break;
b2197755b   Daniel Borkmann   bpf: add support ...
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
  	default:
  		WARN_ON_ONCE(1);
  		break;
  	}
  
  	return raw;
  }
  
  static void bpf_any_put(void *raw, enum bpf_type type)
  {
  	switch (type) {
  	case BPF_TYPE_PROG:
  		bpf_prog_put(raw);
  		break;
  	case BPF_TYPE_MAP:
c9da161c6   Daniel Borkmann   bpf: fix clearing...
58
  		bpf_map_put_with_uref(raw);
b2197755b   Daniel Borkmann   bpf: add support ...
59
  		break;
70ed506c3   Andrii Nakryiko   bpf: Introduce pi...
60
61
62
  	case BPF_TYPE_LINK:
  		bpf_link_put(raw);
  		break;
b2197755b   Daniel Borkmann   bpf: add support ...
63
64
65
66
67
68
69
70
71
  	default:
  		WARN_ON_ONCE(1);
  		break;
  	}
  }
  
  static void *bpf_fd_probe_obj(u32 ufd, enum bpf_type *type)
  {
  	void *raw;
c9da161c6   Daniel Borkmann   bpf: fix clearing...
72
  	raw = bpf_map_get_with_uref(ufd);
70ed506c3   Andrii Nakryiko   bpf: Introduce pi...
73
74
75
76
77
78
79
  	if (!IS_ERR(raw)) {
  		*type = BPF_TYPE_MAP;
  		return raw;
  	}
  
  	raw = bpf_prog_get(ufd);
  	if (!IS_ERR(raw)) {
b2197755b   Daniel Borkmann   bpf: add support ...
80
  		*type = BPF_TYPE_PROG;
70ed506c3   Andrii Nakryiko   bpf: Introduce pi...
81
  		return raw;
b2197755b   Daniel Borkmann   bpf: add support ...
82
  	}
70ed506c3   Andrii Nakryiko   bpf: Introduce pi...
83
84
85
86
87
88
89
  	raw = bpf_link_get_from_fd(ufd);
  	if (!IS_ERR(raw)) {
  		*type = BPF_TYPE_LINK;
  		return raw;
  	}
  
  	return ERR_PTR(-EINVAL);
b2197755b   Daniel Borkmann   bpf: add support ...
90
91
92
93
94
95
  }
  
  static const struct inode_operations bpf_dir_iops;
  
  static const struct inode_operations bpf_prog_iops = { };
  static const struct inode_operations bpf_map_iops  = { };
70ed506c3   Andrii Nakryiko   bpf: Introduce pi...
96
  static const struct inode_operations bpf_link_iops  = { };
b2197755b   Daniel Borkmann   bpf: add support ...
97
98
99
100
101
102
103
104
105
106
  
  static struct inode *bpf_get_inode(struct super_block *sb,
  				   const struct inode *dir,
  				   umode_t mode)
  {
  	struct inode *inode;
  
  	switch (mode & S_IFMT) {
  	case S_IFDIR:
  	case S_IFREG:
0f98621be   Daniel Borkmann   bpf, inode: add s...
107
  	case S_IFLNK:
b2197755b   Daniel Borkmann   bpf: add support ...
108
109
110
111
112
113
114
115
116
117
  		break;
  	default:
  		return ERR_PTR(-EINVAL);
  	}
  
  	inode = new_inode(sb);
  	if (!inode)
  		return ERR_PTR(-ENOSPC);
  
  	inode->i_ino = get_next_ino();
078cd8279   Deepa Dinamani   fs: Replace CURRE...
118
  	inode->i_atime = current_time(inode);
b2197755b   Daniel Borkmann   bpf: add support ...
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
  	inode->i_mtime = inode->i_atime;
  	inode->i_ctime = inode->i_atime;
  
  	inode_init_owner(inode, dir, mode);
  
  	return inode;
  }
  
  static int bpf_inode_type(const struct inode *inode, enum bpf_type *type)
  {
  	*type = BPF_TYPE_UNSPEC;
  	if (inode->i_op == &bpf_prog_iops)
  		*type = BPF_TYPE_PROG;
  	else if (inode->i_op == &bpf_map_iops)
  		*type = BPF_TYPE_MAP;
70ed506c3   Andrii Nakryiko   bpf: Introduce pi...
134
135
  	else if (inode->i_op == &bpf_link_iops)
  		*type = BPF_TYPE_LINK;
b2197755b   Daniel Borkmann   bpf: add support ...
136
137
138
139
140
  	else
  		return -EACCES;
  
  	return 0;
  }
0f98621be   Daniel Borkmann   bpf, inode: add s...
141
142
143
144
145
146
147
148
149
  static void bpf_dentry_finalize(struct dentry *dentry, struct inode *inode,
  				struct inode *dir)
  {
  	d_instantiate(dentry, inode);
  	dget(dentry);
  
  	dir->i_mtime = current_time(dir);
  	dir->i_ctime = dir->i_mtime;
  }
b2197755b   Daniel Borkmann   bpf: add support ...
150
151
152
  static int bpf_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
  {
  	struct inode *inode;
b2197755b   Daniel Borkmann   bpf: add support ...
153
154
155
156
157
158
159
160
161
  	inode = bpf_get_inode(dir->i_sb, dir, mode | S_IFDIR);
  	if (IS_ERR(inode))
  		return PTR_ERR(inode);
  
  	inode->i_op = &bpf_dir_iops;
  	inode->i_fop = &simple_dir_operations;
  
  	inc_nlink(inode);
  	inc_nlink(dir);
0f98621be   Daniel Borkmann   bpf, inode: add s...
162
  	bpf_dentry_finalize(dentry, inode, dir);
b2197755b   Daniel Borkmann   bpf: add support ...
163
164
  	return 0;
  }
a26ca7c98   Martin KaFai Lau   bpf: btf: Add pre...
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
  struct map_iter {
  	void *key;
  	bool done;
  };
  
  static struct map_iter *map_iter(struct seq_file *m)
  {
  	return m->private;
  }
  
  static struct bpf_map *seq_file_to_map(struct seq_file *m)
  {
  	return file_inode(m->file)->i_private;
  }
  
  static void map_iter_free(struct map_iter *iter)
  {
  	if (iter) {
  		kfree(iter->key);
  		kfree(iter);
  	}
  }
  
  static struct map_iter *map_iter_alloc(struct bpf_map *map)
  {
  	struct map_iter *iter;
  
  	iter = kzalloc(sizeof(*iter), GFP_KERNEL | __GFP_NOWARN);
  	if (!iter)
  		goto error;
  
  	iter->key = kzalloc(map->key_size, GFP_KERNEL | __GFP_NOWARN);
  	if (!iter->key)
  		goto error;
  
  	return iter;
  
  error:
  	map_iter_free(iter);
  	return NULL;
  }
  
  static void *map_seq_next(struct seq_file *m, void *v, loff_t *pos)
  {
  	struct bpf_map *map = seq_file_to_map(m);
  	void *key = map_iter(m)->key;
dc1508a57   Yonghong Song   bpf: fix bpffs no...
211
  	void *prev_key;
a26ca7c98   Martin KaFai Lau   bpf: btf: Add pre...
212

90435a789   Vasily Averin   bpf: map_seq_next...
213
  	(*pos)++;
a26ca7c98   Martin KaFai Lau   bpf: btf: Add pre...
214
215
216
217
  	if (map_iter(m)->done)
  		return NULL;
  
  	if (unlikely(v == SEQ_START_TOKEN))
dc1508a57   Yonghong Song   bpf: fix bpffs no...
218
219
220
  		prev_key = NULL;
  	else
  		prev_key = key;
a26ca7c98   Martin KaFai Lau   bpf: btf: Add pre...
221

ce880cb82   Yonghong Song   bpf: Fix a rcu wa...
222
  	rcu_read_lock();
dc1508a57   Yonghong Song   bpf: fix bpffs no...
223
  	if (map->ops->map_get_next_key(map, prev_key, key)) {
a26ca7c98   Martin KaFai Lau   bpf: btf: Add pre...
224
  		map_iter(m)->done = true;
ce880cb82   Yonghong Song   bpf: Fix a rcu wa...
225
  		key = NULL;
a26ca7c98   Martin KaFai Lau   bpf: btf: Add pre...
226
  	}
ce880cb82   Yonghong Song   bpf: Fix a rcu wa...
227
  	rcu_read_unlock();
a26ca7c98   Martin KaFai Lau   bpf: btf: Add pre...
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
  	return key;
  }
  
  static void *map_seq_start(struct seq_file *m, loff_t *pos)
  {
  	if (map_iter(m)->done)
  		return NULL;
  
  	return *pos ? map_iter(m)->key : SEQ_START_TOKEN;
  }
  
  static void map_seq_stop(struct seq_file *m, void *v)
  {
  }
  
  static int map_seq_show(struct seq_file *m, void *v)
  {
  	struct bpf_map *map = seq_file_to_map(m);
  	void *key = map_iter(m)->key;
  
  	if (unlikely(v == SEQ_START_TOKEN)) {
  		seq_puts(m, "# WARNING!! The output is for debug purpose only
  ");
  		seq_puts(m, "# WARNING!! The output format will change
  ");
  	} else {
  		map->ops->map_seq_show_elem(map, key, m);
  	}
  
  	return 0;
  }
  
  static const struct seq_operations bpffs_map_seq_ops = {
  	.start	= map_seq_start,
  	.next	= map_seq_next,
  	.show	= map_seq_show,
  	.stop	= map_seq_stop,
  };
  
  static int bpffs_map_open(struct inode *inode, struct file *file)
  {
  	struct bpf_map *map = inode->i_private;
  	struct map_iter *iter;
  	struct seq_file *m;
  	int err;
  
  	iter = map_iter_alloc(map);
  	if (!iter)
  		return -ENOMEM;
  
  	err = seq_open(file, &bpffs_map_seq_ops);
  	if (err) {
  		map_iter_free(iter);
  		return err;
  	}
  
  	m = file->private_data;
  	m->private = iter;
  
  	return 0;
  }
  
  static int bpffs_map_release(struct inode *inode, struct file *file)
  {
  	struct seq_file *m = file->private_data;
  
  	map_iter_free(map_iter(m));
  
  	return seq_release(inode, file);
  }
  
  /* bpffs_map_fops should only implement the basic
   * read operation for a BPF map.  The purpose is to
   * provide a simple user intuitive way to do
   * "cat bpffs/pathto/a-pinned-map".
   *
   * Other operations (e.g. write, lookup...) should be realized by
   * the userspace tools (e.g. bpftool) through the
   * BPF_OBJ_GET_INFO_BY_FD and the map's lookup/update
   * interface.
   */
  static const struct file_operations bpffs_map_fops = {
  	.open		= bpffs_map_open,
  	.read		= seq_read,
  	.release	= bpffs_map_release,
  };
b16558579   Daniel Borkmann   bpf: implement du...
314
315
316
317
318
319
320
321
  static int bpffs_obj_open(struct inode *inode, struct file *file)
  {
  	return -EIO;
  }
  
  static const struct file_operations bpffs_obj_fops = {
  	.open		= bpffs_obj_open,
  };
a4a0683fd   Al Viro   bpf_obj_do_pin():...
322
  static int bpf_mkobj_ops(struct dentry *dentry, umode_t mode, void *raw,
a26ca7c98   Martin KaFai Lau   bpf: btf: Add pre...
323
324
  			 const struct inode_operations *iops,
  			 const struct file_operations *fops)
b2197755b   Daniel Borkmann   bpf: add support ...
325
  {
a4a0683fd   Al Viro   bpf_obj_do_pin():...
326
327
  	struct inode *dir = dentry->d_parent->d_inode;
  	struct inode *inode = bpf_get_inode(dir->i_sb, dir, mode);
b2197755b   Daniel Borkmann   bpf: add support ...
328
329
330
331
  	if (IS_ERR(inode))
  		return PTR_ERR(inode);
  
  	inode->i_op = iops;
a26ca7c98   Martin KaFai Lau   bpf: btf: Add pre...
332
  	inode->i_fop = fops;
a4a0683fd   Al Viro   bpf_obj_do_pin():...
333
  	inode->i_private = raw;
b2197755b   Daniel Borkmann   bpf: add support ...
334

0f98621be   Daniel Borkmann   bpf, inode: add s...
335
  	bpf_dentry_finalize(dentry, inode, dir);
b2197755b   Daniel Borkmann   bpf: add support ...
336
337
  	return 0;
  }
a4a0683fd   Al Viro   bpf_obj_do_pin():...
338
  static int bpf_mkprog(struct dentry *dentry, umode_t mode, void *arg)
b2197755b   Daniel Borkmann   bpf: add support ...
339
  {
b16558579   Daniel Borkmann   bpf: implement du...
340
341
  	return bpf_mkobj_ops(dentry, mode, arg, &bpf_prog_iops,
  			     &bpffs_obj_fops);
a4a0683fd   Al Viro   bpf_obj_do_pin():...
342
  }
b2197755b   Daniel Borkmann   bpf: add support ...
343

a4a0683fd   Al Viro   bpf_obj_do_pin():...
344
345
  static int bpf_mkmap(struct dentry *dentry, umode_t mode, void *arg)
  {
a26ca7c98   Martin KaFai Lau   bpf: btf: Add pre...
346
347
348
  	struct bpf_map *map = arg;
  
  	return bpf_mkobj_ops(dentry, mode, arg, &bpf_map_iops,
e8d2bec04   Daniel Borkmann   bpf: decouple btf...
349
350
  			     bpf_map_support_seq_show(map) ?
  			     &bpffs_map_fops : &bpffs_obj_fops);
b2197755b   Daniel Borkmann   bpf: add support ...
351
  }
70ed506c3   Andrii Nakryiko   bpf: Introduce pi...
352
353
  static int bpf_mklink(struct dentry *dentry, umode_t mode, void *arg)
  {
367ec3e48   Yonghong Song   bpf: Create file ...
354
  	struct bpf_link *link = arg;
70ed506c3   Andrii Nakryiko   bpf: Introduce pi...
355
  	return bpf_mkobj_ops(dentry, mode, arg, &bpf_link_iops,
367ec3e48   Yonghong Song   bpf: Create file ...
356
357
  			     bpf_link_is_iter(link) ?
  			     &bpf_iter_fops : &bpffs_obj_fops);
70ed506c3   Andrii Nakryiko   bpf: Introduce pi...
358
  }
0c93b7d85   Al Viro   bpf: reject inval...
359
360
  static struct dentry *
  bpf_lookup(struct inode *dir, struct dentry *dentry, unsigned flags)
bb35a6ef7   Daniel Borkmann   bpf, inode: allow...
361
  {
6d8cb045c   Quentin Monnet   bpf: comment why ...
362
  	/* Dots in names (e.g. "/sys/fs/bpf/foo.bar") are reserved for future
d71fa5c97   Alexei Starovoitov   bpf: Add kernel m...
363
  	 * extensions. That allows popoulate_bpffs() create special files.
6d8cb045c   Quentin Monnet   bpf: comment why ...
364
  	 */
d71fa5c97   Alexei Starovoitov   bpf: Add kernel m...
365
366
  	if ((dir->i_mode & S_IALLUGO) &&
  	    strchr(dentry->d_name.name, '.'))
0c93b7d85   Al Viro   bpf: reject inval...
367
  		return ERR_PTR(-EPERM);
0f98621be   Daniel Borkmann   bpf, inode: add s...
368

0c93b7d85   Al Viro   bpf: reject inval...
369
  	return simple_lookup(dir, dentry, flags);
bb35a6ef7   Daniel Borkmann   bpf, inode: allow...
370
  }
0f98621be   Daniel Borkmann   bpf, inode: add s...
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
  static int bpf_symlink(struct inode *dir, struct dentry *dentry,
  		       const char *target)
  {
  	char *link = kstrdup(target, GFP_USER | __GFP_NOWARN);
  	struct inode *inode;
  
  	if (!link)
  		return -ENOMEM;
  
  	inode = bpf_get_inode(dir->i_sb, dir, S_IRWXUGO | S_IFLNK);
  	if (IS_ERR(inode)) {
  		kfree(link);
  		return PTR_ERR(inode);
  	}
  
  	inode->i_op = &simple_symlink_inode_operations;
  	inode->i_link = link;
  
  	bpf_dentry_finalize(dentry, inode, dir);
  	return 0;
  }
b2197755b   Daniel Borkmann   bpf: add support ...
392
  static const struct inode_operations bpf_dir_iops = {
0c93b7d85   Al Viro   bpf: reject inval...
393
  	.lookup		= bpf_lookup,
b2197755b   Daniel Borkmann   bpf: add support ...
394
  	.mkdir		= bpf_mkdir,
0f98621be   Daniel Borkmann   bpf, inode: add s...
395
  	.symlink	= bpf_symlink,
b2197755b   Daniel Borkmann   bpf: add support ...
396
  	.rmdir		= simple_rmdir,
0c93b7d85   Al Viro   bpf: reject inval...
397
398
  	.rename		= simple_rename,
  	.link		= simple_link,
b2197755b   Daniel Borkmann   bpf: add support ...
399
400
  	.unlink		= simple_unlink,
  };
d71fa5c97   Alexei Starovoitov   bpf: Add kernel m...
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
  /* pin iterator link into bpffs */
  static int bpf_iter_link_pin_kernel(struct dentry *parent,
  				    const char *name, struct bpf_link *link)
  {
  	umode_t mode = S_IFREG | S_IRUSR;
  	struct dentry *dentry;
  	int ret;
  
  	inode_lock(parent->d_inode);
  	dentry = lookup_one_len(name, parent, strlen(name));
  	if (IS_ERR(dentry)) {
  		inode_unlock(parent->d_inode);
  		return PTR_ERR(dentry);
  	}
  	ret = bpf_mkobj_ops(dentry, mode, link, &bpf_link_iops,
  			    &bpf_iter_fops);
  	dput(dentry);
  	inode_unlock(parent->d_inode);
  	return ret;
  }
b87121dd3   Al Viro   bpf: don't bother...
421
  static int bpf_obj_do_pin(const char __user *pathname, void *raw,
b2197755b   Daniel Borkmann   bpf: add support ...
422
423
424
425
426
427
  			  enum bpf_type type)
  {
  	struct dentry *dentry;
  	struct inode *dir;
  	struct path path;
  	umode_t mode;
b2197755b   Daniel Borkmann   bpf: add support ...
428
  	int ret;
b87121dd3   Al Viro   bpf: don't bother...
429
  	dentry = user_path_create(AT_FDCWD, pathname, &path, 0);
b2197755b   Daniel Borkmann   bpf: add support ...
430
431
432
433
  	if (IS_ERR(dentry))
  		return PTR_ERR(dentry);
  
  	mode = S_IFREG | ((S_IRUSR | S_IWUSR) & ~current_umask());
b2197755b   Daniel Borkmann   bpf: add support ...
434

a4a0683fd   Al Viro   bpf_obj_do_pin():...
435
  	ret = security_path_mknod(&path, dentry, mode, 0);
b2197755b   Daniel Borkmann   bpf: add support ...
436
437
438
439
440
441
442
443
  	if (ret)
  		goto out;
  
  	dir = d_inode(path.dentry);
  	if (dir->i_op != &bpf_dir_iops) {
  		ret = -EPERM;
  		goto out;
  	}
a4a0683fd   Al Viro   bpf_obj_do_pin():...
444
445
446
447
448
449
450
  	switch (type) {
  	case BPF_TYPE_PROG:
  		ret = vfs_mkobj(dentry, mode, bpf_mkprog, raw);
  		break;
  	case BPF_TYPE_MAP:
  		ret = vfs_mkobj(dentry, mode, bpf_mkmap, raw);
  		break;
70ed506c3   Andrii Nakryiko   bpf: Introduce pi...
451
452
453
  	case BPF_TYPE_LINK:
  		ret = vfs_mkobj(dentry, mode, bpf_mklink, raw);
  		break;
a4a0683fd   Al Viro   bpf_obj_do_pin():...
454
455
456
  	default:
  		ret = -EPERM;
  	}
b2197755b   Daniel Borkmann   bpf: add support ...
457
458
459
460
461
462
463
  out:
  	done_path_create(&path, dentry);
  	return ret;
  }
  
  int bpf_obj_pin_user(u32 ufd, const char __user *pathname)
  {
b2197755b   Daniel Borkmann   bpf: add support ...
464
465
466
  	enum bpf_type type;
  	void *raw;
  	int ret;
b2197755b   Daniel Borkmann   bpf: add support ...
467
  	raw = bpf_fd_probe_obj(ufd, &type);
b87121dd3   Al Viro   bpf: don't bother...
468
469
  	if (IS_ERR(raw))
  		return PTR_ERR(raw);
b2197755b   Daniel Borkmann   bpf: add support ...
470

b87121dd3   Al Viro   bpf: don't bother...
471
  	ret = bpf_obj_do_pin(pathname, raw, type);
b2197755b   Daniel Borkmann   bpf: add support ...
472
473
  	if (ret != 0)
  		bpf_any_put(raw, type);
b87121dd3   Al Viro   bpf: don't bother...
474

b2197755b   Daniel Borkmann   bpf: add support ...
475
476
  	return ret;
  }
b87121dd3   Al Viro   bpf: don't bother...
477
  static void *bpf_obj_do_get(const char __user *pathname,
6e71b04a8   Chenbo Feng   bpf: Add file mod...
478
  			    enum bpf_type *type, int flags)
b2197755b   Daniel Borkmann   bpf: add support ...
479
480
481
482
483
  {
  	struct inode *inode;
  	struct path path;
  	void *raw;
  	int ret;
b87121dd3   Al Viro   bpf: don't bother...
484
  	ret = user_path_at(AT_FDCWD, pathname, LOOKUP_FOLLOW, &path);
b2197755b   Daniel Borkmann   bpf: add support ...
485
486
487
488
  	if (ret)
  		return ERR_PTR(ret);
  
  	inode = d_backing_inode(path.dentry);
6e71b04a8   Chenbo Feng   bpf: Add file mod...
489
  	ret = inode_permission(inode, ACC_MODE(flags));
b2197755b   Daniel Borkmann   bpf: add support ...
490
491
492
493
494
495
496
497
  	if (ret)
  		goto out;
  
  	ret = bpf_inode_type(inode, type);
  	if (ret)
  		goto out;
  
  	raw = bpf_any_get(inode->i_private, *type);
92117d844   Alexei Starovoitov   bpf: fix refcnt o...
498
499
  	if (!IS_ERR(raw))
  		touch_atime(&path);
b2197755b   Daniel Borkmann   bpf: add support ...
500
501
502
503
504
505
506
  
  	path_put(&path);
  	return raw;
  out:
  	path_put(&path);
  	return ERR_PTR(ret);
  }
6e71b04a8   Chenbo Feng   bpf: Add file mod...
507
  int bpf_obj_get_user(const char __user *pathname, int flags)
b2197755b   Daniel Borkmann   bpf: add support ...
508
509
  {
  	enum bpf_type type = BPF_TYPE_UNSPEC;
6e71b04a8   Chenbo Feng   bpf: Add file mod...
510
  	int f_flags;
b2197755b   Daniel Borkmann   bpf: add support ...
511
  	void *raw;
b87121dd3   Al Viro   bpf: don't bother...
512
  	int ret;
b2197755b   Daniel Borkmann   bpf: add support ...
513

6e71b04a8   Chenbo Feng   bpf: Add file mod...
514
515
516
  	f_flags = bpf_get_file_flag(flags);
  	if (f_flags < 0)
  		return f_flags;
b87121dd3   Al Viro   bpf: don't bother...
517
518
519
  	raw = bpf_obj_do_get(pathname, &type, f_flags);
  	if (IS_ERR(raw))
  		return PTR_ERR(raw);
b2197755b   Daniel Borkmann   bpf: add support ...
520
521
522
523
  
  	if (type == BPF_TYPE_PROG)
  		ret = bpf_prog_new_fd(raw);
  	else if (type == BPF_TYPE_MAP)
6e71b04a8   Chenbo Feng   bpf: Add file mod...
524
  		ret = bpf_map_new_fd(raw, f_flags);
70ed506c3   Andrii Nakryiko   bpf: Introduce pi...
525
526
  	else if (type == BPF_TYPE_LINK)
  		ret = bpf_link_new_fd(raw);
b2197755b   Daniel Borkmann   bpf: add support ...
527
  	else
b87121dd3   Al Viro   bpf: don't bother...
528
  		return -ENOENT;
b2197755b   Daniel Borkmann   bpf: add support ...
529

4d220ed0f   Alexei Starovoitov   bpf: remove trace...
530
  	if (ret < 0)
b2197755b   Daniel Borkmann   bpf: add support ...
531
  		bpf_any_put(raw, type);
b2197755b   Daniel Borkmann   bpf: add support ...
532
533
  	return ret;
  }
040ee6922   Al Viro   fix "netfilter: x...
534
535
536
537
  
  static struct bpf_prog *__get_prog_inode(struct inode *inode, enum bpf_prog_type type)
  {
  	struct bpf_prog *prog;
e547ff3f8   Chenbo Feng   bpf: relax inode ...
538
  	int ret = inode_permission(inode, MAY_READ);
040ee6922   Al Viro   fix "netfilter: x...
539
540
541
542
543
  	if (ret)
  		return ERR_PTR(ret);
  
  	if (inode->i_op == &bpf_map_iops)
  		return ERR_PTR(-EINVAL);
70ed506c3   Andrii Nakryiko   bpf: Introduce pi...
544
545
  	if (inode->i_op == &bpf_link_iops)
  		return ERR_PTR(-EINVAL);
040ee6922   Al Viro   fix "netfilter: x...
546
547
548
549
550
551
552
553
554
555
556
  	if (inode->i_op != &bpf_prog_iops)
  		return ERR_PTR(-EACCES);
  
  	prog = inode->i_private;
  
  	ret = security_bpf_prog(prog);
  	if (ret < 0)
  		return ERR_PTR(ret);
  
  	if (!bpf_prog_get_ok(prog, &type, false))
  		return ERR_PTR(-EINVAL);
85192dbf4   Andrii Nakryiko   bpf: Convert bpf_...
557
558
  	bpf_prog_inc(prog);
  	return prog;
040ee6922   Al Viro   fix "netfilter: x...
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
  }
  
  struct bpf_prog *bpf_prog_get_type_path(const char *name, enum bpf_prog_type type)
  {
  	struct bpf_prog *prog;
  	struct path path;
  	int ret = kern_path(name, LOOKUP_FOLLOW, &path);
  	if (ret)
  		return ERR_PTR(ret);
  	prog = __get_prog_inode(d_backing_inode(path.dentry), type);
  	if (!IS_ERR(prog))
  		touch_atime(&path);
  	path_put(&path);
  	return prog;
  }
  EXPORT_SYMBOL(bpf_prog_get_type_path);
b2197755b   Daniel Borkmann   bpf: add support ...
575

4cc7c1864   David Howells   bpf: Implement sh...
576
577
578
579
580
581
582
583
584
585
586
  /*
   * Display the mount options in /proc/mounts.
   */
  static int bpf_show_options(struct seq_file *m, struct dentry *root)
  {
  	umode_t mode = d_inode(root)->i_mode & S_IALLUGO & ~S_ISVTX;
  
  	if (mode != S_IRWXUGO)
  		seq_printf(m, ",mode=%o", mode);
  	return 0;
  }
524845ff9   Al Viro   bpf: switch to ->...
587
  static void bpf_free_inode(struct inode *inode)
1da6c4d91   Daniel Borkmann   bpf: fix use afte...
588
  {
1da6c4d91   Daniel Borkmann   bpf: fix use afte...
589
590
591
592
593
594
595
596
  	enum bpf_type type;
  
  	if (S_ISLNK(inode->i_mode))
  		kfree(inode->i_link);
  	if (!bpf_inode_type(inode, &type))
  		bpf_any_put(inode->i_private, type);
  	free_inode_nonrcu(inode);
  }
b2197755b   Daniel Borkmann   bpf: add support ...
597
598
599
  static const struct super_operations bpf_super_ops = {
  	.statfs		= simple_statfs,
  	.drop_inode	= generic_delete_inode,
4cc7c1864   David Howells   bpf: Implement sh...
600
  	.show_options	= bpf_show_options,
524845ff9   Al Viro   bpf: switch to ->...
601
  	.free_inode	= bpf_free_inode,
b2197755b   Daniel Borkmann   bpf: add support ...
602
  };
a3af5f800   Daniel Borkmann   bpf: allow for mo...
603
604
  enum {
  	OPT_MODE,
a3af5f800   Daniel Borkmann   bpf: allow for mo...
605
  };
d7167b149   Al Viro   fs_parse: fold fs...
606
  static const struct fs_parameter_spec bpf_fs_parameters[] = {
d2935de7e   David Howells   vfs: Convert bpf ...
607
608
609
  	fsparam_u32oct	("mode",			OPT_MODE),
  	{}
  };
a3af5f800   Daniel Borkmann   bpf: allow for mo...
610
611
612
  struct bpf_mount_opts {
  	umode_t mode;
  };
d2935de7e   David Howells   vfs: Convert bpf ...
613
  static int bpf_parse_param(struct fs_context *fc, struct fs_parameter *param)
a3af5f800   Daniel Borkmann   bpf: allow for mo...
614
  {
d2935de7e   David Howells   vfs: Convert bpf ...
615
616
617
  	struct bpf_mount_opts *opts = fc->fs_private;
  	struct fs_parse_result result;
  	int opt;
a3af5f800   Daniel Borkmann   bpf: allow for mo...
618

d7167b149   Al Viro   fs_parse: fold fs...
619
  	opt = fs_parse(fc, bpf_fs_parameters, param, &result);
d2935de7e   David Howells   vfs: Convert bpf ...
620
  	if (opt < 0)
a3af5f800   Daniel Borkmann   bpf: allow for mo...
621
622
623
624
  		/* We might like to report bad mount options here, but
  		 * traditionally we've ignored all mount options, so we'd
  		 * better continue to ignore non-existing options for bpf.
  		 */
d2935de7e   David Howells   vfs: Convert bpf ...
625
626
627
628
629
630
  		return opt == -ENOPARAM ? 0 : opt;
  
  	switch (opt) {
  	case OPT_MODE:
  		opts->mode = result.uint_32 & S_IALLUGO;
  		break;
a3af5f800   Daniel Borkmann   bpf: allow for mo...
631
632
633
634
  	}
  
  	return 0;
  }
d71fa5c97   Alexei Starovoitov   bpf: Add kernel m...
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
  struct bpf_preload_ops *bpf_preload_ops;
  EXPORT_SYMBOL_GPL(bpf_preload_ops);
  
  static bool bpf_preload_mod_get(void)
  {
  	/* If bpf_preload.ko wasn't loaded earlier then load it now.
  	 * When bpf_preload is built into vmlinux the module's __init
  	 * function will populate it.
  	 */
  	if (!bpf_preload_ops) {
  		request_module("bpf_preload");
  		if (!bpf_preload_ops)
  			return false;
  	}
  	/* And grab the reference, so the module doesn't disappear while the
  	 * kernel is interacting with the kernel module and its UMD.
  	 */
  	if (!try_module_get(bpf_preload_ops->owner)) {
  		pr_err("bpf_preload module get failed.
  ");
  		return false;
  	}
  	return true;
  }
  
  static void bpf_preload_mod_put(void)
  {
  	if (bpf_preload_ops)
  		/* now user can "rmmod bpf_preload" if necessary */
  		module_put(bpf_preload_ops->owner);
  }
  
  static DEFINE_MUTEX(bpf_preload_lock);
  
  static int populate_bpffs(struct dentry *parent)
  {
  	struct bpf_preload_info objs[BPF_PRELOAD_LINKS] = {};
  	struct bpf_link *links[BPF_PRELOAD_LINKS] = {};
  	int err = 0, i;
  
  	/* grab the mutex to make sure the kernel interactions with bpf_preload
  	 * UMD are serialized
  	 */
  	mutex_lock(&bpf_preload_lock);
  
  	/* if bpf_preload.ko wasn't built into vmlinux then load it */
  	if (!bpf_preload_mod_get())
  		goto out;
  
  	if (!bpf_preload_ops->info.tgid) {
  		/* preload() will start UMD that will load BPF iterator programs */
  		err = bpf_preload_ops->preload(objs);
  		if (err)
  			goto out_put;
  		for (i = 0; i < BPF_PRELOAD_LINKS; i++) {
  			links[i] = bpf_link_by_id(objs[i].link_id);
  			if (IS_ERR(links[i])) {
  				err = PTR_ERR(links[i]);
  				goto out_put;
  			}
  		}
  		for (i = 0; i < BPF_PRELOAD_LINKS; i++) {
  			err = bpf_iter_link_pin_kernel(parent,
  						       objs[i].link_name, links[i]);
  			if (err)
  				goto out_put;
  			/* do not unlink successfully pinned links even
  			 * if later link fails to pin
  			 */
  			links[i] = NULL;
  		}
  		/* finish() will tell UMD process to exit */
  		err = bpf_preload_ops->finish();
  		if (err)
  			goto out_put;
  	}
  out_put:
  	bpf_preload_mod_put();
  out:
  	mutex_unlock(&bpf_preload_lock);
  	for (i = 0; i < BPF_PRELOAD_LINKS && err; i++)
  		if (!IS_ERR_OR_NULL(links[i]))
  			bpf_link_put(links[i]);
  	return err;
  }
d2935de7e   David Howells   vfs: Convert bpf ...
720
  static int bpf_fill_super(struct super_block *sb, struct fs_context *fc)
b2197755b   Daniel Borkmann   bpf: add support ...
721
  {
cda37124f   Eric Biggers   fs: constify tree...
722
  	static const struct tree_descr bpf_rfiles[] = { { "" } };
d2935de7e   David Howells   vfs: Convert bpf ...
723
  	struct bpf_mount_opts *opts = fc->fs_private;
b2197755b   Daniel Borkmann   bpf: add support ...
724
725
726
727
728
729
730
731
732
733
734
735
  	struct inode *inode;
  	int ret;
  
  	ret = simple_fill_super(sb, BPF_FS_MAGIC, bpf_rfiles);
  	if (ret)
  		return ret;
  
  	sb->s_op = &bpf_super_ops;
  
  	inode = sb->s_root->d_inode;
  	inode->i_op = &bpf_dir_iops;
  	inode->i_mode &= ~S_IALLUGO;
d71fa5c97   Alexei Starovoitov   bpf: Add kernel m...
736
  	populate_bpffs(sb->s_root);
d2935de7e   David Howells   vfs: Convert bpf ...
737
  	inode->i_mode |= S_ISVTX | opts->mode;
b2197755b   Daniel Borkmann   bpf: add support ...
738
739
  	return 0;
  }
d2935de7e   David Howells   vfs: Convert bpf ...
740
741
742
743
744
745
  static int bpf_get_tree(struct fs_context *fc)
  {
  	return get_tree_nodev(fc, bpf_fill_super);
  }
  
  static void bpf_free_fc(struct fs_context *fc)
b2197755b   Daniel Borkmann   bpf: add support ...
746
  {
d2935de7e   David Howells   vfs: Convert bpf ...
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
  	kfree(fc->fs_private);
  }
  
  static const struct fs_context_operations bpf_context_ops = {
  	.free		= bpf_free_fc,
  	.parse_param	= bpf_parse_param,
  	.get_tree	= bpf_get_tree,
  };
  
  /*
   * Set up the filesystem mount context.
   */
  static int bpf_init_fs_context(struct fs_context *fc)
  {
  	struct bpf_mount_opts *opts;
  
  	opts = kzalloc(sizeof(struct bpf_mount_opts), GFP_KERNEL);
  	if (!opts)
  		return -ENOMEM;
  
  	opts->mode = S_IRWXUGO;
  
  	fc->fs_private = opts;
  	fc->ops = &bpf_context_ops;
  	return 0;
b2197755b   Daniel Borkmann   bpf: add support ...
772
773
774
775
776
  }
  
  static struct file_system_type bpf_fs_type = {
  	.owner		= THIS_MODULE,
  	.name		= "bpf",
d2935de7e   David Howells   vfs: Convert bpf ...
777
  	.init_fs_context = bpf_init_fs_context,
d7167b149   Al Viro   fs_parse: fold fs...
778
  	.parameters	= bpf_fs_parameters,
b2197755b   Daniel Borkmann   bpf: add support ...
779
  	.kill_sb	= kill_litter_super,
b2197755b   Daniel Borkmann   bpf: add support ...
780
  };
b2197755b   Daniel Borkmann   bpf: add support ...
781
782
783
  static int __init bpf_init(void)
  {
  	int ret;
d71fa5c97   Alexei Starovoitov   bpf: Add kernel m...
784
  	mutex_init(&bpf_preload_lock);
b2197755b   Daniel Borkmann   bpf: add support ...
785
786
787
788
789
790
791
792
793
794
795
  	ret = sysfs_create_mount_point(fs_kobj, "bpf");
  	if (ret)
  		return ret;
  
  	ret = register_filesystem(&bpf_fs_type);
  	if (ret)
  		sysfs_remove_mount_point(fs_kobj, "bpf");
  
  	return ret;
  }
  fs_initcall(bpf_init);