1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2b2197755SDaniel Borkmann /* 3b2197755SDaniel Borkmann * Minimal file system backend for holding eBPF maps and programs, 4b2197755SDaniel Borkmann * used by bpf(2) object pinning. 5b2197755SDaniel Borkmann * 6b2197755SDaniel Borkmann * Authors: 7b2197755SDaniel Borkmann * 8b2197755SDaniel Borkmann * Daniel Borkmann <daniel@iogearbox.net> 9b2197755SDaniel Borkmann */ 10b2197755SDaniel Borkmann 11a536a6e1SPaul Gortmaker #include <linux/init.h> 12b2197755SDaniel Borkmann #include <linux/magic.h> 13b2197755SDaniel Borkmann #include <linux/major.h> 14b2197755SDaniel Borkmann #include <linux/mount.h> 15b2197755SDaniel Borkmann #include <linux/namei.h> 16b2197755SDaniel Borkmann #include <linux/fs.h> 17d2935de7SDavid Howells #include <linux/fs_context.h> 18d2935de7SDavid Howells #include <linux/fs_parser.h> 19b2197755SDaniel Borkmann #include <linux/kdev_t.h> 20b2197755SDaniel Borkmann #include <linux/filter.h> 21b2197755SDaniel Borkmann #include <linux/bpf.h> 22a67edbf4SDaniel Borkmann #include <linux/bpf_trace.h> 23d71fa5c9SAlexei Starovoitov #include "preload/bpf_preload.h" 24b2197755SDaniel Borkmann 25b2197755SDaniel Borkmann enum bpf_type { 26b2197755SDaniel Borkmann BPF_TYPE_UNSPEC = 0, 27b2197755SDaniel Borkmann BPF_TYPE_PROG, 28b2197755SDaniel Borkmann BPF_TYPE_MAP, 2970ed506cSAndrii Nakryiko BPF_TYPE_LINK, 30b2197755SDaniel Borkmann }; 31b2197755SDaniel Borkmann 32b2197755SDaniel Borkmann static void *bpf_any_get(void *raw, enum bpf_type type) 33b2197755SDaniel Borkmann { 34b2197755SDaniel Borkmann switch (type) { 35b2197755SDaniel Borkmann case BPF_TYPE_PROG: 3685192dbfSAndrii Nakryiko bpf_prog_inc(raw); 37b2197755SDaniel Borkmann break; 38b2197755SDaniel Borkmann case BPF_TYPE_MAP: 391e0bd5a0SAndrii Nakryiko bpf_map_inc_with_uref(raw); 40b2197755SDaniel Borkmann break; 4170ed506cSAndrii Nakryiko case BPF_TYPE_LINK: 4270ed506cSAndrii Nakryiko bpf_link_inc(raw); 4370ed506cSAndrii Nakryiko break; 44b2197755SDaniel Borkmann default: 45b2197755SDaniel Borkmann WARN_ON_ONCE(1); 46b2197755SDaniel Borkmann break; 47b2197755SDaniel Borkmann } 48b2197755SDaniel Borkmann 49b2197755SDaniel Borkmann return raw; 50b2197755SDaniel Borkmann } 51b2197755SDaniel Borkmann 52b2197755SDaniel Borkmann static void bpf_any_put(void *raw, enum bpf_type type) 53b2197755SDaniel Borkmann { 54b2197755SDaniel Borkmann switch (type) { 55b2197755SDaniel Borkmann case BPF_TYPE_PROG: 56b2197755SDaniel Borkmann bpf_prog_put(raw); 57b2197755SDaniel Borkmann break; 58b2197755SDaniel Borkmann case BPF_TYPE_MAP: 59c9da161cSDaniel Borkmann bpf_map_put_with_uref(raw); 60b2197755SDaniel Borkmann break; 6170ed506cSAndrii Nakryiko case BPF_TYPE_LINK: 6270ed506cSAndrii Nakryiko bpf_link_put(raw); 6370ed506cSAndrii Nakryiko break; 64b2197755SDaniel Borkmann default: 65b2197755SDaniel Borkmann WARN_ON_ONCE(1); 66b2197755SDaniel Borkmann break; 67b2197755SDaniel Borkmann } 68b2197755SDaniel Borkmann } 69b2197755SDaniel Borkmann 70b2197755SDaniel Borkmann static void *bpf_fd_probe_obj(u32 ufd, enum bpf_type *type) 71b2197755SDaniel Borkmann { 72b2197755SDaniel Borkmann void *raw; 73b2197755SDaniel Borkmann 74c9da161cSDaniel Borkmann raw = bpf_map_get_with_uref(ufd); 7570ed506cSAndrii Nakryiko if (!IS_ERR(raw)) { 7670ed506cSAndrii Nakryiko *type = BPF_TYPE_MAP; 7770ed506cSAndrii Nakryiko return raw; 78b2197755SDaniel Borkmann } 79b2197755SDaniel Borkmann 8070ed506cSAndrii Nakryiko raw = bpf_prog_get(ufd); 8170ed506cSAndrii Nakryiko if (!IS_ERR(raw)) { 8270ed506cSAndrii Nakryiko *type = BPF_TYPE_PROG; 83b2197755SDaniel Borkmann return raw; 84b2197755SDaniel Borkmann } 85b2197755SDaniel Borkmann 8670ed506cSAndrii Nakryiko raw = bpf_link_get_from_fd(ufd); 8770ed506cSAndrii Nakryiko if (!IS_ERR(raw)) { 8870ed506cSAndrii Nakryiko *type = BPF_TYPE_LINK; 8970ed506cSAndrii Nakryiko return raw; 9070ed506cSAndrii Nakryiko } 9170ed506cSAndrii Nakryiko 9270ed506cSAndrii Nakryiko return ERR_PTR(-EINVAL); 9370ed506cSAndrii Nakryiko } 9470ed506cSAndrii Nakryiko 95b2197755SDaniel Borkmann static const struct inode_operations bpf_dir_iops; 96b2197755SDaniel Borkmann 97b2197755SDaniel Borkmann static const struct inode_operations bpf_prog_iops = { }; 98b2197755SDaniel Borkmann static const struct inode_operations bpf_map_iops = { }; 9970ed506cSAndrii Nakryiko static const struct inode_operations bpf_link_iops = { }; 100b2197755SDaniel Borkmann 101b2197755SDaniel Borkmann static struct inode *bpf_get_inode(struct super_block *sb, 102b2197755SDaniel Borkmann const struct inode *dir, 103b2197755SDaniel Borkmann umode_t mode) 104b2197755SDaniel Borkmann { 105b2197755SDaniel Borkmann struct inode *inode; 106b2197755SDaniel Borkmann 107b2197755SDaniel Borkmann switch (mode & S_IFMT) { 108b2197755SDaniel Borkmann case S_IFDIR: 109b2197755SDaniel Borkmann case S_IFREG: 1100f98621bSDaniel Borkmann case S_IFLNK: 111b2197755SDaniel Borkmann break; 112b2197755SDaniel Borkmann default: 113b2197755SDaniel Borkmann return ERR_PTR(-EINVAL); 114b2197755SDaniel Borkmann } 115b2197755SDaniel Borkmann 116b2197755SDaniel Borkmann inode = new_inode(sb); 117b2197755SDaniel Borkmann if (!inode) 118b2197755SDaniel Borkmann return ERR_PTR(-ENOSPC); 119b2197755SDaniel Borkmann 120b2197755SDaniel Borkmann inode->i_ino = get_next_ino(); 121078cd827SDeepa Dinamani inode->i_atime = current_time(inode); 122b2197755SDaniel Borkmann inode->i_mtime = inode->i_atime; 123b2197755SDaniel Borkmann inode->i_ctime = inode->i_atime; 124b2197755SDaniel Borkmann 12521cb47beSChristian Brauner inode_init_owner(&init_user_ns, inode, dir, mode); 126b2197755SDaniel Borkmann 127b2197755SDaniel Borkmann return inode; 128b2197755SDaniel Borkmann } 129b2197755SDaniel Borkmann 130b2197755SDaniel Borkmann static int bpf_inode_type(const struct inode *inode, enum bpf_type *type) 131b2197755SDaniel Borkmann { 132b2197755SDaniel Borkmann *type = BPF_TYPE_UNSPEC; 133b2197755SDaniel Borkmann if (inode->i_op == &bpf_prog_iops) 134b2197755SDaniel Borkmann *type = BPF_TYPE_PROG; 135b2197755SDaniel Borkmann else if (inode->i_op == &bpf_map_iops) 136b2197755SDaniel Borkmann *type = BPF_TYPE_MAP; 13770ed506cSAndrii Nakryiko else if (inode->i_op == &bpf_link_iops) 13870ed506cSAndrii Nakryiko *type = BPF_TYPE_LINK; 139b2197755SDaniel Borkmann else 140b2197755SDaniel Borkmann return -EACCES; 141b2197755SDaniel Borkmann 142b2197755SDaniel Borkmann return 0; 143b2197755SDaniel Borkmann } 144b2197755SDaniel Borkmann 1450f98621bSDaniel Borkmann static void bpf_dentry_finalize(struct dentry *dentry, struct inode *inode, 1460f98621bSDaniel Borkmann struct inode *dir) 1470f98621bSDaniel Borkmann { 1480f98621bSDaniel Borkmann d_instantiate(dentry, inode); 1490f98621bSDaniel Borkmann dget(dentry); 1500f98621bSDaniel Borkmann 1510f98621bSDaniel Borkmann dir->i_mtime = current_time(dir); 1520f98621bSDaniel Borkmann dir->i_ctime = dir->i_mtime; 1530f98621bSDaniel Borkmann } 1540f98621bSDaniel Borkmann 155549c7297SChristian Brauner static int bpf_mkdir(struct user_namespace *mnt_userns, struct inode *dir, 156549c7297SChristian Brauner struct dentry *dentry, umode_t mode) 157b2197755SDaniel Borkmann { 158b2197755SDaniel Borkmann struct inode *inode; 159b2197755SDaniel Borkmann 160b2197755SDaniel Borkmann inode = bpf_get_inode(dir->i_sb, dir, mode | S_IFDIR); 161b2197755SDaniel Borkmann if (IS_ERR(inode)) 162b2197755SDaniel Borkmann return PTR_ERR(inode); 163b2197755SDaniel Borkmann 164b2197755SDaniel Borkmann inode->i_op = &bpf_dir_iops; 165b2197755SDaniel Borkmann inode->i_fop = &simple_dir_operations; 166b2197755SDaniel Borkmann 167b2197755SDaniel Borkmann inc_nlink(inode); 168b2197755SDaniel Borkmann inc_nlink(dir); 169b2197755SDaniel Borkmann 1700f98621bSDaniel Borkmann bpf_dentry_finalize(dentry, inode, dir); 171b2197755SDaniel Borkmann return 0; 172b2197755SDaniel Borkmann } 173b2197755SDaniel Borkmann 174a26ca7c9SMartin KaFai Lau struct map_iter { 175a26ca7c9SMartin KaFai Lau void *key; 176a26ca7c9SMartin KaFai Lau bool done; 177a26ca7c9SMartin KaFai Lau }; 178a26ca7c9SMartin KaFai Lau 179a26ca7c9SMartin KaFai Lau static struct map_iter *map_iter(struct seq_file *m) 180a26ca7c9SMartin KaFai Lau { 181a26ca7c9SMartin KaFai Lau return m->private; 182a26ca7c9SMartin KaFai Lau } 183a26ca7c9SMartin KaFai Lau 184a26ca7c9SMartin KaFai Lau static struct bpf_map *seq_file_to_map(struct seq_file *m) 185a26ca7c9SMartin KaFai Lau { 186a26ca7c9SMartin KaFai Lau return file_inode(m->file)->i_private; 187a26ca7c9SMartin KaFai Lau } 188a26ca7c9SMartin KaFai Lau 189a26ca7c9SMartin KaFai Lau static void map_iter_free(struct map_iter *iter) 190a26ca7c9SMartin KaFai Lau { 191a26ca7c9SMartin KaFai Lau if (iter) { 192a26ca7c9SMartin KaFai Lau kfree(iter->key); 193a26ca7c9SMartin KaFai Lau kfree(iter); 194a26ca7c9SMartin KaFai Lau } 195a26ca7c9SMartin KaFai Lau } 196a26ca7c9SMartin KaFai Lau 197a26ca7c9SMartin KaFai Lau static struct map_iter *map_iter_alloc(struct bpf_map *map) 198a26ca7c9SMartin KaFai Lau { 199a26ca7c9SMartin KaFai Lau struct map_iter *iter; 200a26ca7c9SMartin KaFai Lau 201a26ca7c9SMartin KaFai Lau iter = kzalloc(sizeof(*iter), GFP_KERNEL | __GFP_NOWARN); 202a26ca7c9SMartin KaFai Lau if (!iter) 203a26ca7c9SMartin KaFai Lau goto error; 204a26ca7c9SMartin KaFai Lau 205a26ca7c9SMartin KaFai Lau iter->key = kzalloc(map->key_size, GFP_KERNEL | __GFP_NOWARN); 206a26ca7c9SMartin KaFai Lau if (!iter->key) 207a26ca7c9SMartin KaFai Lau goto error; 208a26ca7c9SMartin KaFai Lau 209a26ca7c9SMartin KaFai Lau return iter; 210a26ca7c9SMartin KaFai Lau 211a26ca7c9SMartin KaFai Lau error: 212a26ca7c9SMartin KaFai Lau map_iter_free(iter); 213a26ca7c9SMartin KaFai Lau return NULL; 214a26ca7c9SMartin KaFai Lau } 215a26ca7c9SMartin KaFai Lau 216a26ca7c9SMartin KaFai Lau static void *map_seq_next(struct seq_file *m, void *v, loff_t *pos) 217a26ca7c9SMartin KaFai Lau { 218a26ca7c9SMartin KaFai Lau struct bpf_map *map = seq_file_to_map(m); 219a26ca7c9SMartin KaFai Lau void *key = map_iter(m)->key; 220dc1508a5SYonghong Song void *prev_key; 221a26ca7c9SMartin KaFai Lau 22290435a78SVasily Averin (*pos)++; 223a26ca7c9SMartin KaFai Lau if (map_iter(m)->done) 224a26ca7c9SMartin KaFai Lau return NULL; 225a26ca7c9SMartin KaFai Lau 226a26ca7c9SMartin KaFai Lau if (unlikely(v == SEQ_START_TOKEN)) 227dc1508a5SYonghong Song prev_key = NULL; 228dc1508a5SYonghong Song else 229dc1508a5SYonghong Song prev_key = key; 230a26ca7c9SMartin KaFai Lau 231ce880cb8SYonghong Song rcu_read_lock(); 232dc1508a5SYonghong Song if (map->ops->map_get_next_key(map, prev_key, key)) { 233a26ca7c9SMartin KaFai Lau map_iter(m)->done = true; 234ce880cb8SYonghong Song key = NULL; 235a26ca7c9SMartin KaFai Lau } 236ce880cb8SYonghong Song rcu_read_unlock(); 237a26ca7c9SMartin KaFai Lau return key; 238a26ca7c9SMartin KaFai Lau } 239a26ca7c9SMartin KaFai Lau 240a26ca7c9SMartin KaFai Lau static void *map_seq_start(struct seq_file *m, loff_t *pos) 241a26ca7c9SMartin KaFai Lau { 242a26ca7c9SMartin KaFai Lau if (map_iter(m)->done) 243a26ca7c9SMartin KaFai Lau return NULL; 244a26ca7c9SMartin KaFai Lau 245a26ca7c9SMartin KaFai Lau return *pos ? map_iter(m)->key : SEQ_START_TOKEN; 246a26ca7c9SMartin KaFai Lau } 247a26ca7c9SMartin KaFai Lau 248a26ca7c9SMartin KaFai Lau static void map_seq_stop(struct seq_file *m, void *v) 249a26ca7c9SMartin KaFai Lau { 250a26ca7c9SMartin KaFai Lau } 251a26ca7c9SMartin KaFai Lau 252a26ca7c9SMartin KaFai Lau static int map_seq_show(struct seq_file *m, void *v) 253a26ca7c9SMartin KaFai Lau { 254a26ca7c9SMartin KaFai Lau struct bpf_map *map = seq_file_to_map(m); 255a26ca7c9SMartin KaFai Lau void *key = map_iter(m)->key; 256a26ca7c9SMartin KaFai Lau 257a26ca7c9SMartin KaFai Lau if (unlikely(v == SEQ_START_TOKEN)) { 258a26ca7c9SMartin KaFai Lau seq_puts(m, "# WARNING!! The output is for debug purpose only\n"); 259a26ca7c9SMartin KaFai Lau seq_puts(m, "# WARNING!! The output format will change\n"); 260a26ca7c9SMartin KaFai Lau } else { 261a26ca7c9SMartin KaFai Lau map->ops->map_seq_show_elem(map, key, m); 262a26ca7c9SMartin KaFai Lau } 263a26ca7c9SMartin KaFai Lau 264a26ca7c9SMartin KaFai Lau return 0; 265a26ca7c9SMartin KaFai Lau } 266a26ca7c9SMartin KaFai Lau 267a26ca7c9SMartin KaFai Lau static const struct seq_operations bpffs_map_seq_ops = { 268a26ca7c9SMartin KaFai Lau .start = map_seq_start, 269a26ca7c9SMartin KaFai Lau .next = map_seq_next, 270a26ca7c9SMartin KaFai Lau .show = map_seq_show, 271a26ca7c9SMartin KaFai Lau .stop = map_seq_stop, 272a26ca7c9SMartin KaFai Lau }; 273a26ca7c9SMartin KaFai Lau 274a26ca7c9SMartin KaFai Lau static int bpffs_map_open(struct inode *inode, struct file *file) 275a26ca7c9SMartin KaFai Lau { 276a26ca7c9SMartin KaFai Lau struct bpf_map *map = inode->i_private; 277a26ca7c9SMartin KaFai Lau struct map_iter *iter; 278a26ca7c9SMartin KaFai Lau struct seq_file *m; 279a26ca7c9SMartin KaFai Lau int err; 280a26ca7c9SMartin KaFai Lau 281a26ca7c9SMartin KaFai Lau iter = map_iter_alloc(map); 282a26ca7c9SMartin KaFai Lau if (!iter) 283a26ca7c9SMartin KaFai Lau return -ENOMEM; 284a26ca7c9SMartin KaFai Lau 285a26ca7c9SMartin KaFai Lau err = seq_open(file, &bpffs_map_seq_ops); 286a26ca7c9SMartin KaFai Lau if (err) { 287a26ca7c9SMartin KaFai Lau map_iter_free(iter); 288a26ca7c9SMartin KaFai Lau return err; 289a26ca7c9SMartin KaFai Lau } 290a26ca7c9SMartin KaFai Lau 291a26ca7c9SMartin KaFai Lau m = file->private_data; 292a26ca7c9SMartin KaFai Lau m->private = iter; 293a26ca7c9SMartin KaFai Lau 294a26ca7c9SMartin KaFai Lau return 0; 295a26ca7c9SMartin KaFai Lau } 296a26ca7c9SMartin KaFai Lau 297a26ca7c9SMartin KaFai Lau static int bpffs_map_release(struct inode *inode, struct file *file) 298a26ca7c9SMartin KaFai Lau { 299a26ca7c9SMartin KaFai Lau struct seq_file *m = file->private_data; 300a26ca7c9SMartin KaFai Lau 301a26ca7c9SMartin KaFai Lau map_iter_free(map_iter(m)); 302a26ca7c9SMartin KaFai Lau 303a26ca7c9SMartin KaFai Lau return seq_release(inode, file); 304a26ca7c9SMartin KaFai Lau } 305a26ca7c9SMartin KaFai Lau 306a26ca7c9SMartin KaFai Lau /* bpffs_map_fops should only implement the basic 307a26ca7c9SMartin KaFai Lau * read operation for a BPF map. The purpose is to 308a26ca7c9SMartin KaFai Lau * provide a simple user intuitive way to do 309a26ca7c9SMartin KaFai Lau * "cat bpffs/pathto/a-pinned-map". 310a26ca7c9SMartin KaFai Lau * 311a26ca7c9SMartin KaFai Lau * Other operations (e.g. write, lookup...) should be realized by 312a26ca7c9SMartin KaFai Lau * the userspace tools (e.g. bpftool) through the 313a26ca7c9SMartin KaFai Lau * BPF_OBJ_GET_INFO_BY_FD and the map's lookup/update 314a26ca7c9SMartin KaFai Lau * interface. 315a26ca7c9SMartin KaFai Lau */ 316a26ca7c9SMartin KaFai Lau static const struct file_operations bpffs_map_fops = { 317a26ca7c9SMartin KaFai Lau .open = bpffs_map_open, 318a26ca7c9SMartin KaFai Lau .read = seq_read, 319a26ca7c9SMartin KaFai Lau .release = bpffs_map_release, 320a26ca7c9SMartin KaFai Lau }; 321a26ca7c9SMartin KaFai Lau 322b1655857SDaniel Borkmann static int bpffs_obj_open(struct inode *inode, struct file *file) 323b1655857SDaniel Borkmann { 324b1655857SDaniel Borkmann return -EIO; 325b1655857SDaniel Borkmann } 326b1655857SDaniel Borkmann 327b1655857SDaniel Borkmann static const struct file_operations bpffs_obj_fops = { 328b1655857SDaniel Borkmann .open = bpffs_obj_open, 329b1655857SDaniel Borkmann }; 330b1655857SDaniel Borkmann 331a4a0683fSAl Viro static int bpf_mkobj_ops(struct dentry *dentry, umode_t mode, void *raw, 332a26ca7c9SMartin KaFai Lau const struct inode_operations *iops, 333a26ca7c9SMartin KaFai Lau const struct file_operations *fops) 334b2197755SDaniel Borkmann { 335a4a0683fSAl Viro struct inode *dir = dentry->d_parent->d_inode; 336a4a0683fSAl Viro struct inode *inode = bpf_get_inode(dir->i_sb, dir, mode); 337b2197755SDaniel Borkmann if (IS_ERR(inode)) 338b2197755SDaniel Borkmann return PTR_ERR(inode); 339b2197755SDaniel Borkmann 340b2197755SDaniel Borkmann inode->i_op = iops; 341a26ca7c9SMartin KaFai Lau inode->i_fop = fops; 342a4a0683fSAl Viro inode->i_private = raw; 343b2197755SDaniel Borkmann 3440f98621bSDaniel Borkmann bpf_dentry_finalize(dentry, inode, dir); 345b2197755SDaniel Borkmann return 0; 346b2197755SDaniel Borkmann } 347b2197755SDaniel Borkmann 348a4a0683fSAl Viro static int bpf_mkprog(struct dentry *dentry, umode_t mode, void *arg) 349b2197755SDaniel Borkmann { 350b1655857SDaniel Borkmann return bpf_mkobj_ops(dentry, mode, arg, &bpf_prog_iops, 351b1655857SDaniel Borkmann &bpffs_obj_fops); 352b2197755SDaniel Borkmann } 353a4a0683fSAl Viro 354a4a0683fSAl Viro static int bpf_mkmap(struct dentry *dentry, umode_t mode, void *arg) 355a4a0683fSAl Viro { 356a26ca7c9SMartin KaFai Lau struct bpf_map *map = arg; 357a26ca7c9SMartin KaFai Lau 358a26ca7c9SMartin KaFai Lau return bpf_mkobj_ops(dentry, mode, arg, &bpf_map_iops, 359e8d2bec0SDaniel Borkmann bpf_map_support_seq_show(map) ? 360e8d2bec0SDaniel Borkmann &bpffs_map_fops : &bpffs_obj_fops); 361b2197755SDaniel Borkmann } 362b2197755SDaniel Borkmann 36370ed506cSAndrii Nakryiko static int bpf_mklink(struct dentry *dentry, umode_t mode, void *arg) 36470ed506cSAndrii Nakryiko { 365367ec3e4SYonghong Song struct bpf_link *link = arg; 366367ec3e4SYonghong Song 36770ed506cSAndrii Nakryiko return bpf_mkobj_ops(dentry, mode, arg, &bpf_link_iops, 368367ec3e4SYonghong Song bpf_link_is_iter(link) ? 369367ec3e4SYonghong Song &bpf_iter_fops : &bpffs_obj_fops); 37070ed506cSAndrii Nakryiko } 37170ed506cSAndrii Nakryiko 3720c93b7d8SAl Viro static struct dentry * 3730c93b7d8SAl Viro bpf_lookup(struct inode *dir, struct dentry *dentry, unsigned flags) 374bb35a6efSDaniel Borkmann { 3756d8cb045SQuentin Monnet /* Dots in names (e.g. "/sys/fs/bpf/foo.bar") are reserved for future 376d71fa5c9SAlexei Starovoitov * extensions. That allows popoulate_bpffs() create special files. 3776d8cb045SQuentin Monnet */ 378d71fa5c9SAlexei Starovoitov if ((dir->i_mode & S_IALLUGO) && 379d71fa5c9SAlexei Starovoitov strchr(dentry->d_name.name, '.')) 3800c93b7d8SAl Viro return ERR_PTR(-EPERM); 3810f98621bSDaniel Borkmann 3820c93b7d8SAl Viro return simple_lookup(dir, dentry, flags); 383bb35a6efSDaniel Borkmann } 384bb35a6efSDaniel Borkmann 385549c7297SChristian Brauner static int bpf_symlink(struct user_namespace *mnt_userns, struct inode *dir, 386549c7297SChristian Brauner struct dentry *dentry, const char *target) 3870f98621bSDaniel Borkmann { 3880f98621bSDaniel Borkmann char *link = kstrdup(target, GFP_USER | __GFP_NOWARN); 3890f98621bSDaniel Borkmann struct inode *inode; 3900f98621bSDaniel Borkmann 3910f98621bSDaniel Borkmann if (!link) 3920f98621bSDaniel Borkmann return -ENOMEM; 3930f98621bSDaniel Borkmann 3940f98621bSDaniel Borkmann inode = bpf_get_inode(dir->i_sb, dir, S_IRWXUGO | S_IFLNK); 3950f98621bSDaniel Borkmann if (IS_ERR(inode)) { 3960f98621bSDaniel Borkmann kfree(link); 3970f98621bSDaniel Borkmann return PTR_ERR(inode); 3980f98621bSDaniel Borkmann } 3990f98621bSDaniel Borkmann 4000f98621bSDaniel Borkmann inode->i_op = &simple_symlink_inode_operations; 4010f98621bSDaniel Borkmann inode->i_link = link; 4020f98621bSDaniel Borkmann 4030f98621bSDaniel Borkmann bpf_dentry_finalize(dentry, inode, dir); 4040f98621bSDaniel Borkmann return 0; 4050f98621bSDaniel Borkmann } 4060f98621bSDaniel Borkmann 407b2197755SDaniel Borkmann static const struct inode_operations bpf_dir_iops = { 4080c93b7d8SAl Viro .lookup = bpf_lookup, 409b2197755SDaniel Borkmann .mkdir = bpf_mkdir, 4100f98621bSDaniel Borkmann .symlink = bpf_symlink, 411b2197755SDaniel Borkmann .rmdir = simple_rmdir, 4120c93b7d8SAl Viro .rename = simple_rename, 4130c93b7d8SAl Viro .link = simple_link, 414b2197755SDaniel Borkmann .unlink = simple_unlink, 415b2197755SDaniel Borkmann }; 416b2197755SDaniel Borkmann 417d71fa5c9SAlexei Starovoitov /* pin iterator link into bpffs */ 418d71fa5c9SAlexei Starovoitov static int bpf_iter_link_pin_kernel(struct dentry *parent, 419d71fa5c9SAlexei Starovoitov const char *name, struct bpf_link *link) 420d71fa5c9SAlexei Starovoitov { 421d71fa5c9SAlexei Starovoitov umode_t mode = S_IFREG | S_IRUSR; 422d71fa5c9SAlexei Starovoitov struct dentry *dentry; 423d71fa5c9SAlexei Starovoitov int ret; 424d71fa5c9SAlexei Starovoitov 425d71fa5c9SAlexei Starovoitov inode_lock(parent->d_inode); 426d71fa5c9SAlexei Starovoitov dentry = lookup_one_len(name, parent, strlen(name)); 427d71fa5c9SAlexei Starovoitov if (IS_ERR(dentry)) { 428d71fa5c9SAlexei Starovoitov inode_unlock(parent->d_inode); 429d71fa5c9SAlexei Starovoitov return PTR_ERR(dentry); 430d71fa5c9SAlexei Starovoitov } 431d71fa5c9SAlexei Starovoitov ret = bpf_mkobj_ops(dentry, mode, link, &bpf_link_iops, 432d71fa5c9SAlexei Starovoitov &bpf_iter_fops); 433d71fa5c9SAlexei Starovoitov dput(dentry); 434d71fa5c9SAlexei Starovoitov inode_unlock(parent->d_inode); 435d71fa5c9SAlexei Starovoitov return ret; 436d71fa5c9SAlexei Starovoitov } 437d71fa5c9SAlexei Starovoitov 438b87121ddSAl Viro static int bpf_obj_do_pin(const char __user *pathname, void *raw, 439b2197755SDaniel Borkmann enum bpf_type type) 440b2197755SDaniel Borkmann { 441b2197755SDaniel Borkmann struct dentry *dentry; 442b2197755SDaniel Borkmann struct inode *dir; 443b2197755SDaniel Borkmann struct path path; 444b2197755SDaniel Borkmann umode_t mode; 445b2197755SDaniel Borkmann int ret; 446b2197755SDaniel Borkmann 447b87121ddSAl Viro dentry = user_path_create(AT_FDCWD, pathname, &path, 0); 448b2197755SDaniel Borkmann if (IS_ERR(dentry)) 449b2197755SDaniel Borkmann return PTR_ERR(dentry); 450b2197755SDaniel Borkmann 451b2197755SDaniel Borkmann mode = S_IFREG | ((S_IRUSR | S_IWUSR) & ~current_umask()); 452b2197755SDaniel Borkmann 453a4a0683fSAl Viro ret = security_path_mknod(&path, dentry, mode, 0); 454b2197755SDaniel Borkmann if (ret) 455b2197755SDaniel Borkmann goto out; 456b2197755SDaniel Borkmann 457b2197755SDaniel Borkmann dir = d_inode(path.dentry); 458b2197755SDaniel Borkmann if (dir->i_op != &bpf_dir_iops) { 459b2197755SDaniel Borkmann ret = -EPERM; 460b2197755SDaniel Borkmann goto out; 461b2197755SDaniel Borkmann } 462b2197755SDaniel Borkmann 463a4a0683fSAl Viro switch (type) { 464a4a0683fSAl Viro case BPF_TYPE_PROG: 465a4a0683fSAl Viro ret = vfs_mkobj(dentry, mode, bpf_mkprog, raw); 466a4a0683fSAl Viro break; 467a4a0683fSAl Viro case BPF_TYPE_MAP: 468a4a0683fSAl Viro ret = vfs_mkobj(dentry, mode, bpf_mkmap, raw); 469a4a0683fSAl Viro break; 47070ed506cSAndrii Nakryiko case BPF_TYPE_LINK: 47170ed506cSAndrii Nakryiko ret = vfs_mkobj(dentry, mode, bpf_mklink, raw); 47270ed506cSAndrii Nakryiko break; 473a4a0683fSAl Viro default: 474a4a0683fSAl Viro ret = -EPERM; 475a4a0683fSAl Viro } 476b2197755SDaniel Borkmann out: 477b2197755SDaniel Borkmann done_path_create(&path, dentry); 478b2197755SDaniel Borkmann return ret; 479b2197755SDaniel Borkmann } 480b2197755SDaniel Borkmann 481b2197755SDaniel Borkmann int bpf_obj_pin_user(u32 ufd, const char __user *pathname) 482b2197755SDaniel Borkmann { 483b2197755SDaniel Borkmann enum bpf_type type; 484b2197755SDaniel Borkmann void *raw; 485b2197755SDaniel Borkmann int ret; 486b2197755SDaniel Borkmann 487b2197755SDaniel Borkmann raw = bpf_fd_probe_obj(ufd, &type); 488b87121ddSAl Viro if (IS_ERR(raw)) 489b87121ddSAl Viro return PTR_ERR(raw); 490b2197755SDaniel Borkmann 491b87121ddSAl Viro ret = bpf_obj_do_pin(pathname, raw, type); 492b2197755SDaniel Borkmann if (ret != 0) 493b2197755SDaniel Borkmann bpf_any_put(raw, type); 494b87121ddSAl Viro 495b2197755SDaniel Borkmann return ret; 496b2197755SDaniel Borkmann } 497b2197755SDaniel Borkmann 498b87121ddSAl Viro static void *bpf_obj_do_get(const char __user *pathname, 4996e71b04aSChenbo Feng enum bpf_type *type, int flags) 500b2197755SDaniel Borkmann { 501b2197755SDaniel Borkmann struct inode *inode; 502b2197755SDaniel Borkmann struct path path; 503b2197755SDaniel Borkmann void *raw; 504b2197755SDaniel Borkmann int ret; 505b2197755SDaniel Borkmann 506b87121ddSAl Viro ret = user_path_at(AT_FDCWD, pathname, LOOKUP_FOLLOW, &path); 507b2197755SDaniel Borkmann if (ret) 508b2197755SDaniel Borkmann return ERR_PTR(ret); 509b2197755SDaniel Borkmann 510b2197755SDaniel Borkmann inode = d_backing_inode(path.dentry); 51102f92b38SChristian Brauner ret = path_permission(&path, ACC_MODE(flags)); 512b2197755SDaniel Borkmann if (ret) 513b2197755SDaniel Borkmann goto out; 514b2197755SDaniel Borkmann 515b2197755SDaniel Borkmann ret = bpf_inode_type(inode, type); 516b2197755SDaniel Borkmann if (ret) 517b2197755SDaniel Borkmann goto out; 518b2197755SDaniel Borkmann 519b2197755SDaniel Borkmann raw = bpf_any_get(inode->i_private, *type); 52092117d84SAlexei Starovoitov if (!IS_ERR(raw)) 521b2197755SDaniel Borkmann touch_atime(&path); 522b2197755SDaniel Borkmann 523b2197755SDaniel Borkmann path_put(&path); 524b2197755SDaniel Borkmann return raw; 525b2197755SDaniel Borkmann out: 526b2197755SDaniel Borkmann path_put(&path); 527b2197755SDaniel Borkmann return ERR_PTR(ret); 528b2197755SDaniel Borkmann } 529b2197755SDaniel Borkmann 5306e71b04aSChenbo Feng int bpf_obj_get_user(const char __user *pathname, int flags) 531b2197755SDaniel Borkmann { 532b2197755SDaniel Borkmann enum bpf_type type = BPF_TYPE_UNSPEC; 5336e71b04aSChenbo Feng int f_flags; 534b2197755SDaniel Borkmann void *raw; 535b87121ddSAl Viro int ret; 536b2197755SDaniel Borkmann 5376e71b04aSChenbo Feng f_flags = bpf_get_file_flag(flags); 5386e71b04aSChenbo Feng if (f_flags < 0) 5396e71b04aSChenbo Feng return f_flags; 5406e71b04aSChenbo Feng 541b87121ddSAl Viro raw = bpf_obj_do_get(pathname, &type, f_flags); 542b87121ddSAl Viro if (IS_ERR(raw)) 543b87121ddSAl Viro return PTR_ERR(raw); 544b2197755SDaniel Borkmann 545b2197755SDaniel Borkmann if (type == BPF_TYPE_PROG) 546b2197755SDaniel Borkmann ret = bpf_prog_new_fd(raw); 547b2197755SDaniel Borkmann else if (type == BPF_TYPE_MAP) 5486e71b04aSChenbo Feng ret = bpf_map_new_fd(raw, f_flags); 54970ed506cSAndrii Nakryiko else if (type == BPF_TYPE_LINK) 550*25fc94b2SLorenz Bauer ret = (f_flags != O_RDWR) ? -EINVAL : bpf_link_new_fd(raw); 551b2197755SDaniel Borkmann else 552b87121ddSAl Viro return -ENOENT; 553b2197755SDaniel Borkmann 5544d220ed0SAlexei Starovoitov if (ret < 0) 555b2197755SDaniel Borkmann bpf_any_put(raw, type); 556b2197755SDaniel Borkmann return ret; 557b2197755SDaniel Borkmann } 558040ee692SAl Viro 559040ee692SAl Viro static struct bpf_prog *__get_prog_inode(struct inode *inode, enum bpf_prog_type type) 560040ee692SAl Viro { 561040ee692SAl Viro struct bpf_prog *prog; 56247291baaSChristian Brauner int ret = inode_permission(&init_user_ns, inode, MAY_READ); 563040ee692SAl Viro if (ret) 564040ee692SAl Viro return ERR_PTR(ret); 565040ee692SAl Viro 566040ee692SAl Viro if (inode->i_op == &bpf_map_iops) 567040ee692SAl Viro return ERR_PTR(-EINVAL); 56870ed506cSAndrii Nakryiko if (inode->i_op == &bpf_link_iops) 56970ed506cSAndrii Nakryiko return ERR_PTR(-EINVAL); 570040ee692SAl Viro if (inode->i_op != &bpf_prog_iops) 571040ee692SAl Viro return ERR_PTR(-EACCES); 572040ee692SAl Viro 573040ee692SAl Viro prog = inode->i_private; 574040ee692SAl Viro 575040ee692SAl Viro ret = security_bpf_prog(prog); 576040ee692SAl Viro if (ret < 0) 577040ee692SAl Viro return ERR_PTR(ret); 578040ee692SAl Viro 579040ee692SAl Viro if (!bpf_prog_get_ok(prog, &type, false)) 580040ee692SAl Viro return ERR_PTR(-EINVAL); 581040ee692SAl Viro 58285192dbfSAndrii Nakryiko bpf_prog_inc(prog); 58385192dbfSAndrii Nakryiko return prog; 584040ee692SAl Viro } 585040ee692SAl Viro 586040ee692SAl Viro struct bpf_prog *bpf_prog_get_type_path(const char *name, enum bpf_prog_type type) 587040ee692SAl Viro { 588040ee692SAl Viro struct bpf_prog *prog; 589040ee692SAl Viro struct path path; 590040ee692SAl Viro int ret = kern_path(name, LOOKUP_FOLLOW, &path); 591040ee692SAl Viro if (ret) 592040ee692SAl Viro return ERR_PTR(ret); 593040ee692SAl Viro prog = __get_prog_inode(d_backing_inode(path.dentry), type); 594040ee692SAl Viro if (!IS_ERR(prog)) 595040ee692SAl Viro touch_atime(&path); 596040ee692SAl Viro path_put(&path); 597040ee692SAl Viro return prog; 598040ee692SAl Viro } 599040ee692SAl Viro EXPORT_SYMBOL(bpf_prog_get_type_path); 600b2197755SDaniel Borkmann 6014cc7c186SDavid Howells /* 6024cc7c186SDavid Howells * Display the mount options in /proc/mounts. 6034cc7c186SDavid Howells */ 6044cc7c186SDavid Howells static int bpf_show_options(struct seq_file *m, struct dentry *root) 6054cc7c186SDavid Howells { 6064cc7c186SDavid Howells umode_t mode = d_inode(root)->i_mode & S_IALLUGO & ~S_ISVTX; 6074cc7c186SDavid Howells 6084cc7c186SDavid Howells if (mode != S_IRWXUGO) 6094cc7c186SDavid Howells seq_printf(m, ",mode=%o", mode); 6104cc7c186SDavid Howells return 0; 6114cc7c186SDavid Howells } 6124cc7c186SDavid Howells 613524845ffSAl Viro static void bpf_free_inode(struct inode *inode) 6141da6c4d9SDaniel Borkmann { 6151da6c4d9SDaniel Borkmann enum bpf_type type; 6161da6c4d9SDaniel Borkmann 6171da6c4d9SDaniel Borkmann if (S_ISLNK(inode->i_mode)) 6181da6c4d9SDaniel Borkmann kfree(inode->i_link); 6191da6c4d9SDaniel Borkmann if (!bpf_inode_type(inode, &type)) 6201da6c4d9SDaniel Borkmann bpf_any_put(inode->i_private, type); 6211da6c4d9SDaniel Borkmann free_inode_nonrcu(inode); 6221da6c4d9SDaniel Borkmann } 6231da6c4d9SDaniel Borkmann 624b2197755SDaniel Borkmann static const struct super_operations bpf_super_ops = { 625b2197755SDaniel Borkmann .statfs = simple_statfs, 626b2197755SDaniel Borkmann .drop_inode = generic_delete_inode, 6274cc7c186SDavid Howells .show_options = bpf_show_options, 628524845ffSAl Viro .free_inode = bpf_free_inode, 629b2197755SDaniel Borkmann }; 630b2197755SDaniel Borkmann 631a3af5f80SDaniel Borkmann enum { 632a3af5f80SDaniel Borkmann OPT_MODE, 633a3af5f80SDaniel Borkmann }; 634a3af5f80SDaniel Borkmann 635d7167b14SAl Viro static const struct fs_parameter_spec bpf_fs_parameters[] = { 636d2935de7SDavid Howells fsparam_u32oct ("mode", OPT_MODE), 637d2935de7SDavid Howells {} 638d2935de7SDavid Howells }; 639d2935de7SDavid Howells 640a3af5f80SDaniel Borkmann struct bpf_mount_opts { 641a3af5f80SDaniel Borkmann umode_t mode; 642a3af5f80SDaniel Borkmann }; 643a3af5f80SDaniel Borkmann 644d2935de7SDavid Howells static int bpf_parse_param(struct fs_context *fc, struct fs_parameter *param) 645a3af5f80SDaniel Borkmann { 646d2935de7SDavid Howells struct bpf_mount_opts *opts = fc->fs_private; 647d2935de7SDavid Howells struct fs_parse_result result; 648d2935de7SDavid Howells int opt; 649a3af5f80SDaniel Borkmann 650d7167b14SAl Viro opt = fs_parse(fc, bpf_fs_parameters, param, &result); 651d2935de7SDavid Howells if (opt < 0) 652a3af5f80SDaniel Borkmann /* We might like to report bad mount options here, but 653a3af5f80SDaniel Borkmann * traditionally we've ignored all mount options, so we'd 654a3af5f80SDaniel Borkmann * better continue to ignore non-existing options for bpf. 655a3af5f80SDaniel Borkmann */ 656d2935de7SDavid Howells return opt == -ENOPARAM ? 0 : opt; 657d2935de7SDavid Howells 658d2935de7SDavid Howells switch (opt) { 659d2935de7SDavid Howells case OPT_MODE: 660d2935de7SDavid Howells opts->mode = result.uint_32 & S_IALLUGO; 661d2935de7SDavid Howells break; 662a3af5f80SDaniel Borkmann } 663a3af5f80SDaniel Borkmann 664a3af5f80SDaniel Borkmann return 0; 665a3af5f80SDaniel Borkmann } 666a3af5f80SDaniel Borkmann 667d71fa5c9SAlexei Starovoitov struct bpf_preload_ops *bpf_preload_ops; 668d71fa5c9SAlexei Starovoitov EXPORT_SYMBOL_GPL(bpf_preload_ops); 669d71fa5c9SAlexei Starovoitov 670d71fa5c9SAlexei Starovoitov static bool bpf_preload_mod_get(void) 671d71fa5c9SAlexei Starovoitov { 672d71fa5c9SAlexei Starovoitov /* If bpf_preload.ko wasn't loaded earlier then load it now. 673d71fa5c9SAlexei Starovoitov * When bpf_preload is built into vmlinux the module's __init 674d71fa5c9SAlexei Starovoitov * function will populate it. 675d71fa5c9SAlexei Starovoitov */ 676d71fa5c9SAlexei Starovoitov if (!bpf_preload_ops) { 677d71fa5c9SAlexei Starovoitov request_module("bpf_preload"); 678d71fa5c9SAlexei Starovoitov if (!bpf_preload_ops) 679d71fa5c9SAlexei Starovoitov return false; 680d71fa5c9SAlexei Starovoitov } 681d71fa5c9SAlexei Starovoitov /* And grab the reference, so the module doesn't disappear while the 682d71fa5c9SAlexei Starovoitov * kernel is interacting with the kernel module and its UMD. 683d71fa5c9SAlexei Starovoitov */ 684d71fa5c9SAlexei Starovoitov if (!try_module_get(bpf_preload_ops->owner)) { 685d71fa5c9SAlexei Starovoitov pr_err("bpf_preload module get failed.\n"); 686d71fa5c9SAlexei Starovoitov return false; 687d71fa5c9SAlexei Starovoitov } 688d71fa5c9SAlexei Starovoitov return true; 689d71fa5c9SAlexei Starovoitov } 690d71fa5c9SAlexei Starovoitov 691d71fa5c9SAlexei Starovoitov static void bpf_preload_mod_put(void) 692d71fa5c9SAlexei Starovoitov { 693d71fa5c9SAlexei Starovoitov if (bpf_preload_ops) 694d71fa5c9SAlexei Starovoitov /* now user can "rmmod bpf_preload" if necessary */ 695d71fa5c9SAlexei Starovoitov module_put(bpf_preload_ops->owner); 696d71fa5c9SAlexei Starovoitov } 697d71fa5c9SAlexei Starovoitov 698d71fa5c9SAlexei Starovoitov static DEFINE_MUTEX(bpf_preload_lock); 699d71fa5c9SAlexei Starovoitov 700d71fa5c9SAlexei Starovoitov static int populate_bpffs(struct dentry *parent) 701d71fa5c9SAlexei Starovoitov { 702d71fa5c9SAlexei Starovoitov struct bpf_preload_info objs[BPF_PRELOAD_LINKS] = {}; 703d71fa5c9SAlexei Starovoitov struct bpf_link *links[BPF_PRELOAD_LINKS] = {}; 704d71fa5c9SAlexei Starovoitov int err = 0, i; 705d71fa5c9SAlexei Starovoitov 706d71fa5c9SAlexei Starovoitov /* grab the mutex to make sure the kernel interactions with bpf_preload 707d71fa5c9SAlexei Starovoitov * UMD are serialized 708d71fa5c9SAlexei Starovoitov */ 709d71fa5c9SAlexei Starovoitov mutex_lock(&bpf_preload_lock); 710d71fa5c9SAlexei Starovoitov 711d71fa5c9SAlexei Starovoitov /* if bpf_preload.ko wasn't built into vmlinux then load it */ 712d71fa5c9SAlexei Starovoitov if (!bpf_preload_mod_get()) 713d71fa5c9SAlexei Starovoitov goto out; 714d71fa5c9SAlexei Starovoitov 715d71fa5c9SAlexei Starovoitov if (!bpf_preload_ops->info.tgid) { 716d71fa5c9SAlexei Starovoitov /* preload() will start UMD that will load BPF iterator programs */ 717d71fa5c9SAlexei Starovoitov err = bpf_preload_ops->preload(objs); 718d71fa5c9SAlexei Starovoitov if (err) 719d71fa5c9SAlexei Starovoitov goto out_put; 720d71fa5c9SAlexei Starovoitov for (i = 0; i < BPF_PRELOAD_LINKS; i++) { 721d71fa5c9SAlexei Starovoitov links[i] = bpf_link_by_id(objs[i].link_id); 722d71fa5c9SAlexei Starovoitov if (IS_ERR(links[i])) { 723d71fa5c9SAlexei Starovoitov err = PTR_ERR(links[i]); 724d71fa5c9SAlexei Starovoitov goto out_put; 725d71fa5c9SAlexei Starovoitov } 726d71fa5c9SAlexei Starovoitov } 727d71fa5c9SAlexei Starovoitov for (i = 0; i < BPF_PRELOAD_LINKS; i++) { 728d71fa5c9SAlexei Starovoitov err = bpf_iter_link_pin_kernel(parent, 729d71fa5c9SAlexei Starovoitov objs[i].link_name, links[i]); 730d71fa5c9SAlexei Starovoitov if (err) 731d71fa5c9SAlexei Starovoitov goto out_put; 732d71fa5c9SAlexei Starovoitov /* do not unlink successfully pinned links even 733d71fa5c9SAlexei Starovoitov * if later link fails to pin 734d71fa5c9SAlexei Starovoitov */ 735d71fa5c9SAlexei Starovoitov links[i] = NULL; 736d71fa5c9SAlexei Starovoitov } 737d71fa5c9SAlexei Starovoitov /* finish() will tell UMD process to exit */ 738d71fa5c9SAlexei Starovoitov err = bpf_preload_ops->finish(); 739d71fa5c9SAlexei Starovoitov if (err) 740d71fa5c9SAlexei Starovoitov goto out_put; 741d71fa5c9SAlexei Starovoitov } 742d71fa5c9SAlexei Starovoitov out_put: 743d71fa5c9SAlexei Starovoitov bpf_preload_mod_put(); 744d71fa5c9SAlexei Starovoitov out: 745d71fa5c9SAlexei Starovoitov mutex_unlock(&bpf_preload_lock); 746d71fa5c9SAlexei Starovoitov for (i = 0; i < BPF_PRELOAD_LINKS && err; i++) 747d71fa5c9SAlexei Starovoitov if (!IS_ERR_OR_NULL(links[i])) 748d71fa5c9SAlexei Starovoitov bpf_link_put(links[i]); 749d71fa5c9SAlexei Starovoitov return err; 750d71fa5c9SAlexei Starovoitov } 751d71fa5c9SAlexei Starovoitov 752d2935de7SDavid Howells static int bpf_fill_super(struct super_block *sb, struct fs_context *fc) 753b2197755SDaniel Borkmann { 754cda37124SEric Biggers static const struct tree_descr bpf_rfiles[] = { { "" } }; 755d2935de7SDavid Howells struct bpf_mount_opts *opts = fc->fs_private; 756b2197755SDaniel Borkmann struct inode *inode; 757b2197755SDaniel Borkmann int ret; 758b2197755SDaniel Borkmann 759b2197755SDaniel Borkmann ret = simple_fill_super(sb, BPF_FS_MAGIC, bpf_rfiles); 760b2197755SDaniel Borkmann if (ret) 761b2197755SDaniel Borkmann return ret; 762b2197755SDaniel Borkmann 763b2197755SDaniel Borkmann sb->s_op = &bpf_super_ops; 764b2197755SDaniel Borkmann 765b2197755SDaniel Borkmann inode = sb->s_root->d_inode; 766b2197755SDaniel Borkmann inode->i_op = &bpf_dir_iops; 767b2197755SDaniel Borkmann inode->i_mode &= ~S_IALLUGO; 768d71fa5c9SAlexei Starovoitov populate_bpffs(sb->s_root); 769d2935de7SDavid Howells inode->i_mode |= S_ISVTX | opts->mode; 770b2197755SDaniel Borkmann return 0; 771b2197755SDaniel Borkmann } 772b2197755SDaniel Borkmann 773d2935de7SDavid Howells static int bpf_get_tree(struct fs_context *fc) 774b2197755SDaniel Borkmann { 775d2935de7SDavid Howells return get_tree_nodev(fc, bpf_fill_super); 776d2935de7SDavid Howells } 777d2935de7SDavid Howells 778d2935de7SDavid Howells static void bpf_free_fc(struct fs_context *fc) 779d2935de7SDavid Howells { 780d2935de7SDavid Howells kfree(fc->fs_private); 781d2935de7SDavid Howells } 782d2935de7SDavid Howells 783d2935de7SDavid Howells static const struct fs_context_operations bpf_context_ops = { 784d2935de7SDavid Howells .free = bpf_free_fc, 785d2935de7SDavid Howells .parse_param = bpf_parse_param, 786d2935de7SDavid Howells .get_tree = bpf_get_tree, 787d2935de7SDavid Howells }; 788d2935de7SDavid Howells 789d2935de7SDavid Howells /* 790d2935de7SDavid Howells * Set up the filesystem mount context. 791d2935de7SDavid Howells */ 792d2935de7SDavid Howells static int bpf_init_fs_context(struct fs_context *fc) 793d2935de7SDavid Howells { 794d2935de7SDavid Howells struct bpf_mount_opts *opts; 795d2935de7SDavid Howells 796d2935de7SDavid Howells opts = kzalloc(sizeof(struct bpf_mount_opts), GFP_KERNEL); 797d2935de7SDavid Howells if (!opts) 798d2935de7SDavid Howells return -ENOMEM; 799d2935de7SDavid Howells 800d2935de7SDavid Howells opts->mode = S_IRWXUGO; 801d2935de7SDavid Howells 802d2935de7SDavid Howells fc->fs_private = opts; 803d2935de7SDavid Howells fc->ops = &bpf_context_ops; 804d2935de7SDavid Howells return 0; 805b2197755SDaniel Borkmann } 806b2197755SDaniel Borkmann 807b2197755SDaniel Borkmann static struct file_system_type bpf_fs_type = { 808b2197755SDaniel Borkmann .owner = THIS_MODULE, 809b2197755SDaniel Borkmann .name = "bpf", 810d2935de7SDavid Howells .init_fs_context = bpf_init_fs_context, 811d7167b14SAl Viro .parameters = bpf_fs_parameters, 812b2197755SDaniel Borkmann .kill_sb = kill_litter_super, 813b2197755SDaniel Borkmann }; 814b2197755SDaniel Borkmann 815b2197755SDaniel Borkmann static int __init bpf_init(void) 816b2197755SDaniel Borkmann { 817b2197755SDaniel Borkmann int ret; 818b2197755SDaniel Borkmann 819d71fa5c9SAlexei Starovoitov mutex_init(&bpf_preload_lock); 820d71fa5c9SAlexei Starovoitov 821b2197755SDaniel Borkmann ret = sysfs_create_mount_point(fs_kobj, "bpf"); 822b2197755SDaniel Borkmann if (ret) 823b2197755SDaniel Borkmann return ret; 824b2197755SDaniel Borkmann 825b2197755SDaniel Borkmann ret = register_filesystem(&bpf_fs_type); 826b2197755SDaniel Borkmann if (ret) 827b2197755SDaniel Borkmann sysfs_remove_mount_point(fs_kobj, "bpf"); 828b2197755SDaniel Borkmann 829b2197755SDaniel Borkmann return ret; 830b2197755SDaniel Borkmann } 831b2197755SDaniel Borkmann fs_initcall(bpf_init); 832