I want to be able to pin programs loaded by the kernel and expose them through the bpffs so userspace knows what is loaded. There are a few things missings in this WIP: - locking on bpffs_sb - ability to create a hierarchy from the kernel: I'd like to store all of my programs in /sys/fs/bpf/hid, not everything at the root of the mount - ability to store programs when bpffs is not mounted Signed-off-by: Benjamin Tissoires <benjamin.tissoires@xxxxxxxxxx> --- include/linux/bpf.h | 1 + kernel/bpf/inode.c | 41 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 0566705c1d4e..f5a7dca520eb 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1806,6 +1806,7 @@ struct bpf_link *bpf_link_get_curr_or_next(u32 *id); int bpf_obj_pin_user(u32 ufd, const char __user *pathname); int bpf_obj_get_user(const char __user *pathname, int flags); +int bpf_prog_pin_kernel(const char *name, struct bpf_prog *prog); #define BPF_ITER_FUNC_PREFIX "bpf_iter_" #define DEFINE_BPF_ITER_FUNC(target, args...) \ diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index 4f841e16779e..7be24ffad7f7 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -29,6 +29,9 @@ enum bpf_type { BPF_TYPE_LINK, }; + +static struct super_block *bpffs_sb; + static void *bpf_any_get(void *raw, enum bpf_type type) { switch (type) { @@ -435,6 +438,34 @@ static int bpf_iter_link_pin_kernel(struct dentry *parent, return ret; } +/* pin a program in the bpffs */ +/* TODO: handle path relative to mount point instead of plain name by recreating + * the hierarchy, like in drivers/base/devtmpfs.c + */ +int bpf_prog_pin_kernel(const char *name, struct bpf_prog *prog) +{ + struct dentry *parent; + umode_t mode = S_IFREG | S_IRUSR; + struct dentry *dentry; + int ret; + + if (!bpffs_sb) + return -ENOENT; + + parent = bpffs_sb->s_root; + + 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_mkprog(dentry, mode, prog); + dput(dentry); + inode_unlock(parent->d_inode); + return ret; +} + static int bpf_obj_do_pin(const char __user *pathname, void *raw, enum bpf_type type) { @@ -758,6 +789,8 @@ static int bpf_fill_super(struct super_block *sb, struct fs_context *fc) inode->i_mode &= ~S_IALLUGO; populate_bpffs(sb->s_root); inode->i_mode |= S_ISVTX | opts->mode; + + bpffs_sb = sb; return 0; } @@ -795,12 +828,18 @@ static int bpf_init_fs_context(struct fs_context *fc) return 0; } +static void bpf_kill_sb(struct super_block *sb) +{ + bpffs_sb = NULL; + kill_litter_super(sb); +} + static struct file_system_type bpf_fs_type = { .owner = THIS_MODULE, .name = "bpf", .init_fs_context = bpf_init_fs_context, .parameters = bpf_fs_parameters, - .kill_sb = kill_litter_super, + .kill_sb = bpf_kill_sb, }; static int __init bpf_init(void) -- 2.38.1