[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20220328175033.2437312-13-roberto.sassu@huawei.com>
Date: Mon, 28 Mar 2022 19:50:27 +0200
From: Roberto Sassu <roberto.sassu@...wei.com>
To: <corbet@....net>, <viro@...iv.linux.org.uk>, <ast@...nel.org>,
<daniel@...earbox.net>, <andrii@...nel.org>, <kpsingh@...nel.org>,
<shuah@...nel.org>, <mcoquelin.stm32@...il.com>,
<alexandre.torgue@...s.st.com>, <zohar@...ux.ibm.com>
CC: <linux-doc@...r.kernel.org>, <linux-fsdevel@...r.kernel.org>,
<netdev@...r.kernel.org>, <bpf@...r.kernel.org>,
<linux-kselftest@...r.kernel.org>,
<linux-stm32@...md-mailman.stormreply.com>,
<linux-arm-kernel@...ts.infradead.org>,
<linux-integrity@...r.kernel.org>,
<linux-security-module@...r.kernel.org>,
<linux-kernel@...r.kernel.org>,
Roberto Sassu <roberto.sassu@...wei.com>
Subject: [PATCH 12/18] bpf-preload: Implement new registration method for preloading eBPF programs
The current registration method consisting in setting the bpf_preload_ops
global variable is not suitable for preloading multiple eBPF programs, as
each eBPF program would overwrite the global variable with its own method.
Implement a new registration method in two steps. First, introduce
bpf_init_preload_list() to populate at kernel initialization time the new
linked list with an element for each of the desired eBPF programs to
preload.
Second, introduce bpf_preload_set_ops() to allow an eBPF program to set its
preload method in the corresponding item of the linked list. The condition
for a successful registration is that the item in the linked list should
already exist. Return a boolean value to report if registration was
successful or not.
Signed-off-by: Roberto Sassu <roberto.sassu@...wei.com>
---
include/linux/bpf_preload.h | 7 +++
kernel/bpf/inode.c | 107 +++++++++++++++++++++++++++++++++++-
2 files changed, 113 insertions(+), 1 deletion(-)
diff --git a/include/linux/bpf_preload.h b/include/linux/bpf_preload.h
index e604933b3daa..bdbe75c22fcb 100644
--- a/include/linux/bpf_preload.h
+++ b/include/linux/bpf_preload.h
@@ -19,12 +19,19 @@ extern struct bpf_preload_ops *bpf_preload_ops;
int bpf_obj_do_pin_kernel(struct dentry *parent, const char *name, void *raw,
enum bpf_type type);
+bool bpf_preload_set_ops(const char *name, struct module *owner,
+ struct bpf_preload_ops *ops);
#else
static inline int bpf_obj_do_pin_kernel(struct dentry *parent, const char *name,
void *raw, enum bpf_type type)
{
return -EOPNOTSUPP;
}
+
+static inline bool bpf_preload_set_ops(const char *name, struct module *owner,
+ struct bpf_preload_ops *ops)
+{
+}
#endif /*CONFIG_BPF_SYSCALL*/
#endif
diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c
index 0a6e83d32360..440ea517cc29 100644
--- a/kernel/bpf/inode.c
+++ b/kernel/bpf/inode.c
@@ -22,6 +22,8 @@
#include <linux/bpf_trace.h>
#include <linux/bpf_preload.h>
+static char *bpf_preload_list_str;
+
static void *bpf_any_get(void *raw, enum bpf_type type)
{
switch (type) {
@@ -855,6 +857,100 @@ static struct file_system_type bpf_fs_type = {
.kill_sb = kill_litter_super,
};
+static struct bpf_preload_ops_item *
+bpf_preload_list_lookup_entry(const char *obj_name)
+{
+ struct bpf_preload_ops_item *cur;
+
+ list_for_each_entry(cur, &preload_list, list)
+ if (!strcmp(obj_name, cur->obj_name))
+ return cur;
+
+ return NULL;
+}
+
+static int bpf_preload_list_add_entry(const char *obj_name,
+ struct bpf_preload_ops *ops)
+{
+ struct bpf_preload_ops_item *new;
+
+ if (!*obj_name)
+ return 0;
+
+ new = kzalloc(sizeof(*new), GFP_NOFS);
+ if (!new)
+ return -ENOMEM;
+
+ new->obj_name = kstrdup(obj_name, GFP_NOFS);
+ if (!new->obj_name) {
+ kfree(new);
+ return -ENOMEM;
+ }
+
+ new->ops = ops;
+
+ list_add(&new->list, &preload_list);
+ return 0;
+}
+
+bool bpf_preload_set_ops(const char *obj_name, struct module *owner,
+ struct bpf_preload_ops *ops)
+{
+ struct bpf_preload_ops_item *found_item;
+ bool set = false;
+
+ mutex_lock(&bpf_preload_lock);
+
+ found_item = bpf_preload_list_lookup_entry(obj_name);
+ if (found_item) {
+ if (!found_item->ops ||
+ (found_item->ops && found_item->ops->owner == owner)) {
+ found_item->ops = ops;
+ set = true;
+ }
+ }
+
+ mutex_unlock(&bpf_preload_lock);
+ return set;
+}
+EXPORT_SYMBOL_GPL(bpf_preload_set_ops);
+
+static int __init bpf_init_preload_list(void)
+{
+ char *str_ptr = bpf_preload_list_str, *str_end;
+ struct bpf_preload_ops_item *cur, *tmp;
+ char obj_name[NAME_MAX + 1];
+ int ret;
+
+ while (str_ptr && *str_ptr) {
+ str_end = strchrnul(str_ptr, ',');
+
+ snprintf(obj_name, sizeof(obj_name), "%.*s",
+ (int)(str_end - str_ptr), str_ptr);
+
+ if (!bpf_preload_list_lookup_entry(obj_name)) {
+ ret = bpf_preload_list_add_entry(obj_name, NULL);
+ if (ret)
+ goto out;
+ }
+
+ if (!*str_end)
+ break;
+
+ str_ptr = str_end + 1;
+ }
+
+ return 0;
+out:
+ list_for_each_entry_safe(cur, tmp, &preload_list, list) {
+ list_del(&cur->list);
+ kfree(cur->obj_name);
+ kfree(cur);
+ }
+
+ return ret;
+}
+
static int __init bpf_init(void)
{
int ret;
@@ -864,8 +960,17 @@ static int __init bpf_init(void)
return ret;
ret = register_filesystem(&bpf_fs_type);
- if (ret)
+ if (ret) {
sysfs_remove_mount_point(fs_kobj, "bpf");
+ return ret;
+ }
+
+ ret = bpf_init_preload_list();
+ if (ret) {
+ unregister_filesystem(&bpf_fs_type);
+ sysfs_remove_mount_point(fs_kobj, "bpf");
+ return ret;
+ }
return ret;
}
--
2.32.0
Powered by blists - more mailing lists