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 <[email protected]>
---
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