[RFC hid v1 02/10] WIP: bpf: allow to pin programs from the kernel when bpffs is mounted

Benjamin Tissoires posted 10 patches 2 months, 1 week ago
[RFC hid v1 02/10] WIP: bpf: allow to pin programs from the kernel when bpffs is mounted
Posted by Benjamin Tissoires 2 months, 1 week ago
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@redhat.com>
---
 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