eBPF already allows programs to be preloaded and kept running without intervention from user space. There is a dedicated kernel module called bpf_preload, which contains the light skeleton of the iterators_bpf eBPF program. If this module is enabled in the kernel configuration, its loading will be triggered when the bpf filesystem is mounted (unless the module is built-in), and the links of iterators_bpf are pinned in that filesystem (they will appear as the progs.debug and maps.debug files).
However, the current mechanism, if used to preload an LSM, would not offer the same security guarantees of LSMs integrated in the security subsystem. Also, it is not generic enough to be used for preloading arbitrary eBPF programs, unless the bpf_preload code is heavily modified.
More specifically, the security problems are: - any program can be pinned to the bpf filesystem without limitations (unless a MAC mechanism enforces some restrictions); - programs being executed can be terminated at any time by deleting the pinned objects or unmounting the bpf filesystem.
The usability problems are: - only a fixed amount of links can be pinned; - only links can be pinned, other object types are not supported; - code to pin objects has to be written manually; - preloading multiple eBPF programs is not practical, bpf_preload has to be modified to include additional light skeletons.
Solve the security problems by mounting the bpf filesystem from the kernel, by preloading authenticated kernel modules (e.g. with module.sig_enforce) and by pinning objects to that filesystem. This particular filesystem instance guarantees that desired eBPF programs run until the very end of the kernel lifecycle, since even root cannot interfere with it.
Solve the usability problems by generalizing the pinning function, to handle not only links but also maps and progs. Also increment the object reference count and call the pinning function directly from the preload method (currently in the bpf_preload kernel module) rather than from the bpf filesystem code itself, so that a generic eBPF program can do those operations depending on its objects (this also avoids the limitation of the fixed-size array for storing the objects to pin).
Then, simplify the process of pinning objects defined by a generic eBPF program by automatically generating the required methods in the light skeleton. Also, generate a separate kernel module for each eBPF program to preload, so that existing ones don't have to be modified. Finally, support preloading multiple eBPF programs by allowing users to specify a list from the kernel configuration, at build time, or with the new kernel option bpf_preload_list=, at run-time.
To summarize, this patch set makes it possible to plug in out-of-tree LSMs matching the security guarantees of their counterpart in the security subsystem, without having to modify the kernel itself. The same benefits are extended to other eBPF program types.
Only one remaining problem is how to support auto-attaching eBPF programs with LSM type. It will be solved with a separate patch set.
Patches 1-2 export some definitions, to build out-of-tree kernel modules with eBPF programs to preload. Patches 3-4 allow eBPF programs to pin objects by themselves. Patches 5-10 automatically generate the methods for preloading in the light skeleton. Patches 11-14 make it possible to preload multiple eBPF programs. Patch 15 automatically generates the kernel module for preloading an eBPF program, patch 16 does a kernel mount of the bpf filesystem, and finally patches 17-18 test the functionality introduced.
Roberto Sassu (18): bpf: Export bpf_link_inc() bpf-preload: Move bpf_preload.h to include/linux bpf-preload: Generalize object pinning from the kernel bpf-preload: Export and call bpf_obj_do_pin_kernel() bpf-preload: Generate static variables bpf-preload: Generate free_objs_and_skel() bpf-preload: Generate preload() bpf-preload: Generate load_skel() bpf-preload: Generate code to pin non-internal maps bpf-preload: Generate bpf_preload_ops bpf-preload: Store multiple bpf_preload_ops structures in a linked list bpf-preload: Implement new registration method for preloading eBPF programs bpf-preload: Move pinned links and maps to a dedicated directory in bpffs bpf-preload: Switch to new preload registration method bpf-preload: Generate code of kernel module to preload bpf-preload: Do kernel mount to ensure that pinned objects don't disappear bpf-preload/selftests: Add test for automatic generation of preload methods bpf-preload/selftests: Preload a test eBPF program and check pinned objects
.../admin-guide/kernel-parameters.txt | 8 + fs/namespace.c | 1 + include/linux/bpf.h | 5 + include/linux/bpf_preload.h | 37 ++ init/main.c | 2 + kernel/bpf/inode.c | 295 +++++++++-- kernel/bpf/preload/Kconfig | 25 +- kernel/bpf/preload/bpf_preload.h | 16 - kernel/bpf/preload/bpf_preload_kern.c | 85 +--- kernel/bpf/preload/iterators/Makefile | 9 +- .../bpf/preload/iterators/iterators.lskel.h | 466 +++++++++++------- kernel/bpf/syscall.c | 1 + .../bpf/bpftool/Documentation/bpftool-gen.rst | 13 + tools/bpf/bpftool/bash-completion/bpftool | 6 +- tools/bpf/bpftool/gen.c | 331 +++++++++++++ tools/bpf/bpftool/main.c | 7 +- tools/bpf/bpftool/main.h | 1 + tools/testing/selftests/bpf/Makefile | 32 +- .../bpf/bpf_testmod_preload/.gitignore | 7 + .../bpf/bpf_testmod_preload/Makefile | 20 + .../gen_preload_methods.expected.diff | 97 ++++ .../bpf/prog_tests/test_gen_preload_methods.c | 27 + .../bpf/prog_tests/test_preload_methods.c | 69 +++ .../selftests/bpf/progs/gen_preload_methods.c | 23 + 24 files changed, 1246 insertions(+), 337 deletions(-) create mode 100644 include/linux/bpf_preload.h delete mode 100644 kernel/bpf/preload/bpf_preload.h create mode 100644 tools/testing/selftests/bpf/bpf_testmod_preload/.gitignore create mode 100644 tools/testing/selftests/bpf/bpf_testmod_preload/Makefile create mode 100644 tools/testing/selftests/bpf/prog_tests/gen_preload_methods.expected.diff create mode 100644 tools/testing/selftests/bpf/prog_tests/test_gen_preload_methods.c create mode 100644 tools/testing/selftests/bpf/prog_tests/test_preload_methods.c create mode 100644 tools/testing/selftests/bpf/progs/gen_preload_methods.c
In the upcoming patches, populate_bpffs() will not have visibility anymore on the links and maps to be pinned (to avoid the limitation of the 'objs' fixed-size array), but the eBPF-program-specific preload method will directly do the pinning and increase/decrease the reference count.
Since the preload method can be implemented in a kernel module, also bpf_link_inc(), before called by populate_bpffs(), should be exported. Thus, export bpf_link_inc().
Signed-off-by: Roberto Sassu roberto.sassu@huawei.com --- kernel/bpf/syscall.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index cdaa1152436a..8ffe342545c3 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2459,6 +2459,7 @@ void bpf_link_inc(struct bpf_link *link) { atomic64_inc(&link->refcnt); } +EXPORT_SYMBOL_GPL(bpf_link_inc);
/* bpf_link_free is guaranteed to be called from process context */ static void bpf_link_free(struct bpf_link *link)
Move bpf_preload.h to include/linux, so that third-party providers can develop out-of-tree kernel modules to preload eBPF programs.
Export the bpf_preload_ops global variable if CONFIG_BPF_SYSCALL is defined.
Signed-off-by: Roberto Sassu roberto.sassu@huawei.com --- {kernel/bpf/preload => include/linux}/bpf_preload.h | 4 ++++ kernel/bpf/inode.c | 2 +- kernel/bpf/preload/bpf_preload_kern.c | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) rename {kernel/bpf/preload => include/linux}/bpf_preload.h (85%)
diff --git a/kernel/bpf/preload/bpf_preload.h b/include/linux/bpf_preload.h similarity index 85% rename from kernel/bpf/preload/bpf_preload.h rename to include/linux/bpf_preload.h index f065c91213a0..09d55d9f1131 100644 --- a/kernel/bpf/preload/bpf_preload.h +++ b/include/linux/bpf_preload.h @@ -11,6 +11,10 @@ struct bpf_preload_ops { int (*preload)(struct bpf_preload_info *); struct module *owner; }; + +#ifdef CONFIG_BPF_SYSCALL extern struct bpf_preload_ops *bpf_preload_ops; +#endif /*CONFIG_BPF_SYSCALL*/ + #define BPF_PRELOAD_LINKS 2 #endif diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index 4f841e16779e..1f2d468abf58 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -20,7 +20,7 @@ #include <linux/filter.h> #include <linux/bpf.h> #include <linux/bpf_trace.h> -#include "preload/bpf_preload.h" +#include <linux/bpf_preload.h>
enum bpf_type { BPF_TYPE_UNSPEC = 0, diff --git a/kernel/bpf/preload/bpf_preload_kern.c b/kernel/bpf/preload/bpf_preload_kern.c index 5106b5372f0c..f43391d1c49c 100644 --- a/kernel/bpf/preload/bpf_preload_kern.c +++ b/kernel/bpf/preload/bpf_preload_kern.c @@ -2,7 +2,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/init.h> #include <linux/module.h> -#include "bpf_preload.h" +#include <linux/bpf_preload.h> #include "iterators/iterators.lskel.h"
static struct bpf_link *maps_link, *progs_link;
Rename bpf_iter_link_pin_kernel() to bpf_obj_do_pin_kernel(), to match the user space counterpart bpf_obj_do_pin() and similarly to the latter, accept a generic object pointer and its type, so that the preload method can pin not only links but also maps and progs.
Signed-off-by: Roberto Sassu roberto.sassu@huawei.com --- kernel/bpf/inode.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-)
diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index 1f2d468abf58..a9d725db4cf4 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -414,9 +414,10 @@ static const struct inode_operations bpf_dir_iops = { .unlink = simple_unlink, };
-/* pin iterator link into bpffs */ -static int bpf_iter_link_pin_kernel(struct dentry *parent, - const char *name, struct bpf_link *link) +/* pin object into bpffs */ +static int bpf_obj_do_pin_kernel(struct dentry *parent, + const char *name, void *raw, + enum bpf_type type) { umode_t mode = S_IFREG | S_IRUSR; struct dentry *dentry; @@ -428,8 +429,22 @@ static int bpf_iter_link_pin_kernel(struct dentry *parent, inode_unlock(parent->d_inode); return PTR_ERR(dentry); } - ret = bpf_mkobj_ops(dentry, mode, link, &bpf_link_iops, - &bpf_iter_fops); + + switch (type) { + case BPF_TYPE_PROG: + ret = bpf_mkprog(dentry, mode, raw); + break; + case BPF_TYPE_MAP: + ret = bpf_mkmap(dentry, mode, raw); + break; + case BPF_TYPE_LINK: + ret = bpf_mklink(dentry, mode, raw); + break; + default: + ret = -EOPNOTSUPP; + break; + } + dput(dentry); inode_unlock(parent->d_inode); return ret; @@ -726,8 +741,8 @@ static int populate_bpffs(struct dentry *parent) goto out_put; for (i = 0; i < BPF_PRELOAD_LINKS; i++) { bpf_link_inc(objs[i].link); - err = bpf_iter_link_pin_kernel(parent, - objs[i].link_name, objs[i].link); + err = bpf_obj_do_pin_kernel(parent, objs[i].link_name, + objs[i].link, BPF_TYPE_LINK); if (err) { bpf_link_put(objs[i].link); goto out_put;
Export bpf_obj_do_pin_kernel(), so that the preload method of an eBPF program (built-in or in a kernel module) can call this function to pin links, maps and progs.
This removes the need of defining the bpf_preload_info structure, to hold the links to be pinned by populate_bpffs().
Since after this patch the preload method has everything needed to pin objects, that makes it possible to pin arbitrary objects of eBPF programs, by generating the corresponding preload method in the light skeleton.
Signed-off-by: Roberto Sassu roberto.sassu@huawei.com --- include/linux/bpf_preload.h | 20 +++++++++++++----- kernel/bpf/inode.c | 30 +++++---------------------- kernel/bpf/preload/bpf_preload_kern.c | 25 +++++++++++++++++----- 3 files changed, 40 insertions(+), 35 deletions(-)
diff --git a/include/linux/bpf_preload.h b/include/linux/bpf_preload.h index 09d55d9f1131..e604933b3daa 100644 --- a/include/linux/bpf_preload.h +++ b/include/linux/bpf_preload.h @@ -2,19 +2,29 @@ #ifndef _BPF_PRELOAD_H #define _BPF_PRELOAD_H
-struct bpf_preload_info { - char link_name[16]; - struct bpf_link *link; +enum bpf_type { + BPF_TYPE_UNSPEC = 0, + BPF_TYPE_PROG, + BPF_TYPE_MAP, + BPF_TYPE_LINK, };
struct bpf_preload_ops { - int (*preload)(struct bpf_preload_info *); + int (*preload)(struct dentry *parent); struct module *owner; };
#ifdef CONFIG_BPF_SYSCALL 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); +#else +static inline int bpf_obj_do_pin_kernel(struct dentry *parent, const char *name, + void *raw, enum bpf_type type) +{ + return -EOPNOTSUPP; +} #endif /*CONFIG_BPF_SYSCALL*/
-#define BPF_PRELOAD_LINKS 2 #endif diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index a9d725db4cf4..bb8762abbf3d 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -22,13 +22,6 @@ #include <linux/bpf_trace.h> #include <linux/bpf_preload.h>
-enum bpf_type { - BPF_TYPE_UNSPEC = 0, - BPF_TYPE_PROG, - BPF_TYPE_MAP, - BPF_TYPE_LINK, -}; - static void *bpf_any_get(void *raw, enum bpf_type type) { switch (type) { @@ -415,9 +408,8 @@ static const struct inode_operations bpf_dir_iops = { };
/* pin object into bpffs */ -static int bpf_obj_do_pin_kernel(struct dentry *parent, - const char *name, void *raw, - enum bpf_type type) +int bpf_obj_do_pin_kernel(struct dentry *parent, const char *name, void *raw, + enum bpf_type type) { umode_t mode = S_IFREG | S_IRUSR; struct dentry *dentry; @@ -449,6 +441,7 @@ static int bpf_obj_do_pin_kernel(struct dentry *parent, inode_unlock(parent->d_inode); return ret; } +EXPORT_SYMBOL(bpf_obj_do_pin_kernel);
static int bpf_obj_do_pin(const char __user *pathname, void *raw, enum bpf_type type) @@ -724,8 +717,7 @@ static DEFINE_MUTEX(bpf_preload_lock);
static int populate_bpffs(struct dentry *parent) { - struct bpf_preload_info objs[BPF_PRELOAD_LINKS] = {}; - int err = 0, i; + int err = 0;
/* grab the mutex to make sure the kernel interactions with bpf_preload * are serialized @@ -736,19 +728,7 @@ static int populate_bpffs(struct dentry *parent) if (!bpf_preload_mod_get()) goto out;
- err = bpf_preload_ops->preload(objs); - if (err) - goto out_put; - for (i = 0; i < BPF_PRELOAD_LINKS; i++) { - bpf_link_inc(objs[i].link); - err = bpf_obj_do_pin_kernel(parent, objs[i].link_name, - objs[i].link, BPF_TYPE_LINK); - if (err) { - bpf_link_put(objs[i].link); - goto out_put; - } - } -out_put: + err = bpf_preload_ops->preload(parent); bpf_preload_mod_put(); out: mutex_unlock(&bpf_preload_lock); diff --git a/kernel/bpf/preload/bpf_preload_kern.c b/kernel/bpf/preload/bpf_preload_kern.c index f43391d1c49c..d70047108bb3 100644 --- a/kernel/bpf/preload/bpf_preload_kern.c +++ b/kernel/bpf/preload/bpf_preload_kern.c @@ -17,13 +17,28 @@ static void free_links_and_skel(void) iterators_bpf__destroy(skel); }
-static int preload(struct bpf_preload_info *obj) +static int preload(struct dentry *parent) { - strlcpy(obj[0].link_name, "maps.debug", sizeof(obj[0].link_name)); - obj[0].link = maps_link; - strlcpy(obj[1].link_name, "progs.debug", sizeof(obj[1].link_name)); - obj[1].link = progs_link; + int err; + + bpf_link_inc(maps_link); + bpf_link_inc(progs_link); + + err = bpf_obj_do_pin_kernel(parent, "maps.debug", maps_link, + BPF_TYPE_LINK); + if (err) + goto undo; + + err = bpf_obj_do_pin_kernel(parent, "progs.debug", progs_link, + BPF_TYPE_LINK); + if (err) + goto undo; + return 0; +undo: + bpf_link_put(maps_link); + bpf_link_put(progs_link); + return err; }
static struct bpf_preload_ops ops = {
The first part of the preload code generation consists in generating the static variables to be used by the code itself: the links and maps to be pinned, and the skeleton. Generation of the preload variables and methods is enabled with the option -P added to 'bpftool gen skeleton'.
The existing variables maps_link and progs_links in bpf_preload_kern.c have been renamed respectively to dump_bpf_map_link and dump_bpf_prog_link, to match the name of the variables in the main structure of the light skeleton.
Signed-off-by: Roberto Sassu roberto.sassu@huawei.com --- kernel/bpf/preload/bpf_preload_kern.c | 35 +- kernel/bpf/preload/iterators/Makefile | 2 +- .../bpf/preload/iterators/iterators.lskel.h | 378 +++++++++--------- .../bpf/bpftool/Documentation/bpftool-gen.rst | 5 + tools/bpf/bpftool/bash-completion/bpftool | 2 +- tools/bpf/bpftool/gen.c | 27 ++ tools/bpf/bpftool/main.c | 7 +- tools/bpf/bpftool/main.h | 1 + 8 files changed, 254 insertions(+), 203 deletions(-)
diff --git a/kernel/bpf/preload/bpf_preload_kern.c b/kernel/bpf/preload/bpf_preload_kern.c index d70047108bb3..485589e03bd2 100644 --- a/kernel/bpf/preload/bpf_preload_kern.c +++ b/kernel/bpf/preload/bpf_preload_kern.c @@ -5,15 +5,12 @@ #include <linux/bpf_preload.h> #include "iterators/iterators.lskel.h"
-static struct bpf_link *maps_link, *progs_link; -static struct iterators_bpf *skel; - static void free_links_and_skel(void) { - if (!IS_ERR_OR_NULL(maps_link)) - bpf_link_put(maps_link); - if (!IS_ERR_OR_NULL(progs_link)) - bpf_link_put(progs_link); + if (!IS_ERR_OR_NULL(dump_bpf_map_link)) + bpf_link_put(dump_bpf_map_link); + if (!IS_ERR_OR_NULL(dump_bpf_prog_link)) + bpf_link_put(dump_bpf_prog_link); iterators_bpf__destroy(skel); }
@@ -21,23 +18,23 @@ static int preload(struct dentry *parent) { int err;
- bpf_link_inc(maps_link); - bpf_link_inc(progs_link); + bpf_link_inc(dump_bpf_map_link); + bpf_link_inc(dump_bpf_prog_link);
- err = bpf_obj_do_pin_kernel(parent, "maps.debug", maps_link, + err = bpf_obj_do_pin_kernel(parent, "maps.debug", dump_bpf_map_link, BPF_TYPE_LINK); if (err) goto undo;
- err = bpf_obj_do_pin_kernel(parent, "progs.debug", progs_link, + err = bpf_obj_do_pin_kernel(parent, "progs.debug", dump_bpf_prog_link, BPF_TYPE_LINK); if (err) goto undo;
return 0; undo: - bpf_link_put(maps_link); - bpf_link_put(progs_link); + bpf_link_put(dump_bpf_map_link); + bpf_link_put(dump_bpf_prog_link); return err; }
@@ -59,14 +56,14 @@ static int load_skel(void) err = iterators_bpf__attach(skel); if (err) goto out; - maps_link = bpf_link_get_from_fd(skel->links.dump_bpf_map_fd); - if (IS_ERR(maps_link)) { - err = PTR_ERR(maps_link); + dump_bpf_map_link = bpf_link_get_from_fd(skel->links.dump_bpf_map_fd); + if (IS_ERR(dump_bpf_map_link)) { + err = PTR_ERR(dump_bpf_map_link); goto out; } - progs_link = bpf_link_get_from_fd(skel->links.dump_bpf_prog_fd); - if (IS_ERR(progs_link)) { - err = PTR_ERR(progs_link); + dump_bpf_prog_link = bpf_link_get_from_fd(skel->links.dump_bpf_prog_fd); + if (IS_ERR(dump_bpf_prog_link)) { + err = PTR_ERR(dump_bpf_prog_link); goto out; } /* Avoid taking over stdin/stdout/stderr of init process. Zeroing out diff --git a/kernel/bpf/preload/iterators/Makefile b/kernel/bpf/preload/iterators/Makefile index bfe24f8c5a20..d36a822d3e16 100644 --- a/kernel/bpf/preload/iterators/Makefile +++ b/kernel/bpf/preload/iterators/Makefile @@ -43,7 +43,7 @@ clean:
iterators.lskel.h: $(OUTPUT)/iterators.bpf.o | $(BPFTOOL) $(call msg,GEN-SKEL,$@) - $(Q)$(BPFTOOL) gen skeleton -L $< > $@ + $(Q)$(BPFTOOL) gen skeleton -L -P $< > $@
$(OUTPUT)/iterators.bpf.o: iterators.bpf.c $(BPFOBJ) | $(OUTPUT) diff --git a/kernel/bpf/preload/iterators/iterators.lskel.h b/kernel/bpf/preload/iterators/iterators.lskel.h index 70f236a82fe1..9794acdfacf9 100644 --- a/kernel/bpf/preload/iterators/iterators.lskel.h +++ b/kernel/bpf/preload/iterators/iterators.lskel.h @@ -103,7 +103,7 @@ iterators_bpf__load(struct iterators_bpf *skel) int err;
opts.ctx = (struct bpf_loader_ctx *)skel; - opts.data_sz = 6056; + opts.data_sz = 6088; opts.data = (void *)"\ \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ @@ -138,63 +138,64 @@ iterators_bpf__load(struct iterators_bpf *skel) \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x9f\xeb\x01\0\ -\x18\0\0\0\0\0\0\0\x1c\x04\0\0\x1c\x04\0\0\xf9\x04\0\0\0\0\0\0\0\0\0\x02\x02\0\ +\x18\0\0\0\0\0\0\0\x1c\x04\0\0\x1c\x04\0\0\x0b\x05\0\0\0\0\0\0\0\0\0\x02\x02\0\ \0\0\x01\0\0\0\x02\0\0\x04\x10\0\0\0\x13\0\0\0\x03\0\0\0\0\0\0\0\x18\0\0\0\x04\ \0\0\0\x40\0\0\0\0\0\0\0\0\0\0\x02\x08\0\0\0\0\0\0\0\0\0\0\x02\x0d\0\0\0\0\0\0\ \0\x01\0\0\x0d\x06\0\0\0\x1c\0\0\0\x01\0\0\0\x20\0\0\0\0\0\0\x01\x04\0\0\0\x20\ -\0\0\x01\x24\0\0\0\x01\0\0\x0c\x05\0\0\0\xa3\0\0\0\x03\0\0\x04\x18\0\0\0\xb1\0\ -\0\0\x09\0\0\0\0\0\0\0\xb5\0\0\0\x0b\0\0\0\x40\0\0\0\xc0\0\0\0\x0b\0\0\0\x80\0\ -\0\0\0\0\0\0\0\0\0\x02\x0a\0\0\0\xc8\0\0\0\0\0\0\x07\0\0\0\0\xd1\0\0\0\0\0\0\ -\x08\x0c\0\0\0\xd7\0\0\0\0\0\0\x01\x08\0\0\0\x40\0\0\0\x94\x01\0\0\x03\0\0\x04\ -\x18\0\0\0\x9c\x01\0\0\x0e\0\0\0\0\0\0\0\x9f\x01\0\0\x11\0\0\0\x20\0\0\0\xa4\ -\x01\0\0\x0e\0\0\0\xa0\0\0\0\xb0\x01\0\0\0\0\0\x08\x0f\0\0\0\xb6\x01\0\0\0\0\0\ -\x01\x04\0\0\0\x20\0\0\0\xc3\x01\0\0\0\0\0\x01\x01\0\0\0\x08\0\0\x01\0\0\0\0\0\ -\0\0\x03\0\0\0\0\x10\0\0\0\x12\0\0\0\x10\0\0\0\xc8\x01\0\0\0\0\0\x01\x04\0\0\0\ -\x20\0\0\0\0\0\0\0\0\0\0\x02\x14\0\0\0\x2c\x02\0\0\x02\0\0\x04\x10\0\0\0\x13\0\ -\0\0\x03\0\0\0\0\0\0\0\x3f\x02\0\0\x15\0\0\0\x40\0\0\0\0\0\0\0\0\0\0\x02\x18\0\ -\0\0\0\0\0\0\x01\0\0\x0d\x06\0\0\0\x1c\0\0\0\x13\0\0\0\x44\x02\0\0\x01\0\0\x0c\ -\x16\0\0\0\x90\x02\0\0\x01\0\0\x04\x08\0\0\0\x99\x02\0\0\x19\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\x02\x1a\0\0\0\xea\x02\0\0\x06\0\0\x04\x38\0\0\0\x9c\x01\0\0\x0e\0\0\ -\0\0\0\0\0\x9f\x01\0\0\x11\0\0\0\x20\0\0\0\xf7\x02\0\0\x1b\0\0\0\xc0\0\0\0\x08\ -\x03\0\0\x15\0\0\0\0\x01\0\0\x11\x03\0\0\x1d\0\0\0\x40\x01\0\0\x1b\x03\0\0\x1e\ +\0\0\x01\x24\0\0\0\x01\0\0\x0c\x05\0\0\0\xb1\0\0\0\x03\0\0\x04\x18\0\0\0\xbf\0\ +\0\0\x09\0\0\0\0\0\0\0\xc3\0\0\0\x0b\0\0\0\x40\0\0\0\xce\0\0\0\x0b\0\0\0\x80\0\ +\0\0\0\0\0\0\0\0\0\x02\x0a\0\0\0\xd6\0\0\0\0\0\0\x07\0\0\0\0\xdf\0\0\0\0\0\0\ +\x08\x0c\0\0\0\xe5\0\0\0\0\0\0\x01\x08\0\0\0\x40\0\0\0\xa6\x01\0\0\x03\0\0\x04\ +\x18\0\0\0\xae\x01\0\0\x0e\0\0\0\0\0\0\0\xb1\x01\0\0\x11\0\0\0\x20\0\0\0\xb6\ +\x01\0\0\x0e\0\0\0\xa0\0\0\0\xc2\x01\0\0\0\0\0\x08\x0f\0\0\0\xc8\x01\0\0\0\0\0\ +\x01\x04\0\0\0\x20\0\0\0\xd5\x01\0\0\0\0\0\x01\x01\0\0\0\x08\0\0\x01\0\0\0\0\0\ +\0\0\x03\0\0\0\0\x10\0\0\0\x12\0\0\0\x10\0\0\0\xda\x01\0\0\0\0\0\x01\x04\0\0\0\ +\x20\0\0\0\0\0\0\0\0\0\0\x02\x14\0\0\0\x3e\x02\0\0\x02\0\0\x04\x10\0\0\0\x13\0\ +\0\0\x03\0\0\0\0\0\0\0\x51\x02\0\0\x15\0\0\0\x40\0\0\0\0\0\0\0\0\0\0\x02\x18\0\ +\0\0\0\0\0\0\x01\0\0\x0d\x06\0\0\0\x1c\0\0\0\x13\0\0\0\x56\x02\0\0\x01\0\0\x0c\ +\x16\0\0\0\xa2\x02\0\0\x01\0\0\x04\x08\0\0\0\xab\x02\0\0\x19\0\0\0\0\0\0\0\0\0\ +\0\0\0\0\0\x02\x1a\0\0\0\xfc\x02\0\0\x06\0\0\x04\x38\0\0\0\xae\x01\0\0\x0e\0\0\ +\0\0\0\0\0\xb1\x01\0\0\x11\0\0\0\x20\0\0\0\x09\x03\0\0\x1b\0\0\0\xc0\0\0\0\x1a\ +\x03\0\0\x15\0\0\0\0\x01\0\0\x23\x03\0\0\x1d\0\0\0\x40\x01\0\0\x2d\x03\0\0\x1e\ \0\0\0\x80\x01\0\0\0\0\0\0\0\0\0\x02\x1c\0\0\0\0\0\0\0\0\0\0\x0a\x10\0\0\0\0\0\ -\0\0\0\0\0\x02\x1f\0\0\0\0\0\0\0\0\0\0\x02\x20\0\0\0\x65\x03\0\0\x02\0\0\x04\ -\x08\0\0\0\x73\x03\0\0\x0e\0\0\0\0\0\0\0\x7c\x03\0\0\x0e\0\0\0\x20\0\0\0\x1b\ -\x03\0\0\x03\0\0\x04\x18\0\0\0\x86\x03\0\0\x1b\0\0\0\0\0\0\0\x8e\x03\0\0\x21\0\ -\0\0\x40\0\0\0\x94\x03\0\0\x23\0\0\0\x80\0\0\0\0\0\0\0\0\0\0\x02\x22\0\0\0\0\0\ -\0\0\0\0\0\x02\x24\0\0\0\x98\x03\0\0\x01\0\0\x04\x04\0\0\0\xa3\x03\0\0\x0e\0\0\ -\0\0\0\0\0\x0c\x04\0\0\x01\0\0\x04\x04\0\0\0\x15\x04\0\0\x0e\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\x03\0\0\0\0\x1c\0\0\0\x12\0\0\0\x23\0\0\0\x8b\x04\0\0\0\0\0\x0e\x25\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\x1c\0\0\0\x12\0\0\0\x0e\0\0\0\x9f\x04\ +\0\0\0\0\0\x02\x1f\0\0\0\0\0\0\0\0\0\0\x02\x20\0\0\0\x77\x03\0\0\x02\0\0\x04\ +\x08\0\0\0\x85\x03\0\0\x0e\0\0\0\0\0\0\0\x8e\x03\0\0\x0e\0\0\0\x20\0\0\0\x2d\ +\x03\0\0\x03\0\0\x04\x18\0\0\0\x98\x03\0\0\x1b\0\0\0\0\0\0\0\xa0\x03\0\0\x21\0\ +\0\0\x40\0\0\0\xa6\x03\0\0\x23\0\0\0\x80\0\0\0\0\0\0\0\0\0\0\x02\x22\0\0\0\0\0\ +\0\0\0\0\0\x02\x24\0\0\0\xaa\x03\0\0\x01\0\0\x04\x04\0\0\0\xb5\x03\0\0\x0e\0\0\ +\0\0\0\0\0\x1e\x04\0\0\x01\0\0\x04\x04\0\0\0\x27\x04\0\0\x0e\0\0\0\0\0\0\0\0\0\ +\0\0\0\0\0\x03\0\0\0\0\x1c\0\0\0\x12\0\0\0\x23\0\0\0\x9d\x04\0\0\0\0\0\x0e\x25\ +\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\x1c\0\0\0\x12\0\0\0\x0e\0\0\0\xb1\x04\ \0\0\0\0\0\x0e\x27\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\x1c\0\0\0\x12\0\0\0\ -\x20\0\0\0\xb5\x04\0\0\0\0\0\x0e\x29\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\ -\x1c\0\0\0\x12\0\0\0\x11\0\0\0\xca\x04\0\0\0\0\0\x0e\x2b\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\x03\0\0\0\0\x10\0\0\0\x12\0\0\0\x04\0\0\0\xe1\x04\0\0\0\0\0\x0e\x2d\0\0\ -\0\x01\0\0\0\xe9\x04\0\0\x04\0\0\x0f\x62\0\0\0\x26\0\0\0\0\0\0\0\x23\0\0\0\x28\ +\x20\0\0\0\xc7\x04\0\0\0\0\0\x0e\x29\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\ +\x1c\0\0\0\x12\0\0\0\x11\0\0\0\xdc\x04\0\0\0\0\0\x0e\x2b\0\0\0\0\0\0\0\0\0\0\0\ +\0\0\0\x03\0\0\0\0\x10\0\0\0\x12\0\0\0\x04\0\0\0\xf3\x04\0\0\0\0\0\x0e\x2d\0\0\ +\0\x01\0\0\0\xfb\x04\0\0\x04\0\0\x0f\x62\0\0\0\x26\0\0\0\0\0\0\0\x23\0\0\0\x28\ \0\0\0\x23\0\0\0\x0e\0\0\0\x2a\0\0\0\x31\0\0\0\x20\0\0\0\x2c\0\0\0\x51\0\0\0\ -\x11\0\0\0\xf1\x04\0\0\x01\0\0\x0f\x04\0\0\0\x2e\0\0\0\0\0\0\0\x04\0\0\0\0\x62\ +\x11\0\0\0\x03\x05\0\0\x01\0\0\x0f\x04\0\0\0\x2e\0\0\0\0\0\0\0\x04\0\0\0\0\x62\ \x70\x66\x5f\x69\x74\x65\x72\x5f\x5f\x62\x70\x66\x5f\x6d\x61\x70\0\x6d\x65\x74\ \x61\0\x6d\x61\x70\0\x63\x74\x78\0\x69\x6e\x74\0\x64\x75\x6d\x70\x5f\x62\x70\ \x66\x5f\x6d\x61\x70\0\x69\x74\x65\x72\x2f\x62\x70\x66\x5f\x6d\x61\x70\0\x30\ -\x3a\x30\0\x2f\x77\x2f\x6e\x65\x74\x2d\x6e\x65\x78\x74\x2f\x6b\x65\x72\x6e\x65\ -\x6c\x2f\x62\x70\x66\x2f\x70\x72\x65\x6c\x6f\x61\x64\x2f\x69\x74\x65\x72\x61\ -\x74\x6f\x72\x73\x2f\x69\x74\x65\x72\x61\x74\x6f\x72\x73\x2e\x62\x70\x66\x2e\ -\x63\0\x09\x73\x74\x72\x75\x63\x74\x20\x73\x65\x71\x5f\x66\x69\x6c\x65\x20\x2a\ -\x73\x65\x71\x20\x3d\x20\x63\x74\x78\x2d\x3e\x6d\x65\x74\x61\x2d\x3e\x73\x65\ -\x71\x3b\0\x62\x70\x66\x5f\x69\x74\x65\x72\x5f\x6d\x65\x74\x61\0\x73\x65\x71\0\ -\x73\x65\x73\x73\x69\x6f\x6e\x5f\x69\x64\0\x73\x65\x71\x5f\x6e\x75\x6d\0\x73\ -\x65\x71\x5f\x66\x69\x6c\x65\0\x5f\x5f\x75\x36\x34\0\x75\x6e\x73\x69\x67\x6e\ -\x65\x64\x20\x6c\x6f\x6e\x67\x20\x6c\x6f\x6e\x67\0\x30\x3a\x31\0\x09\x73\x74\ -\x72\x75\x63\x74\x20\x62\x70\x66\x5f\x6d\x61\x70\x20\x2a\x6d\x61\x70\x20\x3d\ -\x20\x63\x74\x78\x2d\x3e\x6d\x61\x70\x3b\0\x09\x69\x66\x20\x28\x21\x6d\x61\x70\ -\x29\0\x09\x5f\x5f\x75\x36\x34\x20\x73\x65\x71\x5f\x6e\x75\x6d\x20\x3d\x20\x63\ -\x74\x78\x2d\x3e\x6d\x65\x74\x61\x2d\x3e\x73\x65\x71\x5f\x6e\x75\x6d\x3b\0\x30\ -\x3a\x32\0\x09\x69\x66\x20\x28\x73\x65\x71\x5f\x6e\x75\x6d\x20\x3d\x3d\x20\x30\ -\x29\0\x09\x09\x42\x50\x46\x5f\x53\x45\x51\x5f\x50\x52\x49\x4e\x54\x46\x28\x73\ -\x65\x71\x2c\x20\x22\x20\x20\x69\x64\x20\x6e\x61\x6d\x65\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x6d\x61\x78\x5f\x65\x6e\x74\x72\x69\x65\x73\ -\x5c\x6e\x22\x29\x3b\0\x62\x70\x66\x5f\x6d\x61\x70\0\x69\x64\0\x6e\x61\x6d\x65\ -\0\x6d\x61\x78\x5f\x65\x6e\x74\x72\x69\x65\x73\0\x5f\x5f\x75\x33\x32\0\x75\x6e\ +\x3a\x30\0\x2f\x68\x6f\x6d\x65\x2f\x72\x6f\x62\x65\x72\x74\x6f\x2f\x72\x65\x70\ +\x6f\x73\x2f\x6c\x69\x6e\x75\x78\x2f\x6b\x65\x72\x6e\x65\x6c\x2f\x62\x70\x66\ +\x2f\x70\x72\x65\x6c\x6f\x61\x64\x2f\x69\x74\x65\x72\x61\x74\x6f\x72\x73\x2f\ +\x69\x74\x65\x72\x61\x74\x6f\x72\x73\x2e\x62\x70\x66\x2e\x63\0\x09\x73\x74\x72\ +\x75\x63\x74\x20\x73\x65\x71\x5f\x66\x69\x6c\x65\x20\x2a\x73\x65\x71\x20\x3d\ +\x20\x63\x74\x78\x2d\x3e\x6d\x65\x74\x61\x2d\x3e\x73\x65\x71\x3b\0\x62\x70\x66\ +\x5f\x69\x74\x65\x72\x5f\x6d\x65\x74\x61\0\x73\x65\x71\0\x73\x65\x73\x73\x69\ +\x6f\x6e\x5f\x69\x64\0\x73\x65\x71\x5f\x6e\x75\x6d\0\x73\x65\x71\x5f\x66\x69\ +\x6c\x65\0\x5f\x5f\x75\x36\x34\0\x6c\x6f\x6e\x67\x20\x6c\x6f\x6e\x67\x20\x75\ +\x6e\x73\x69\x67\x6e\x65\x64\x20\x69\x6e\x74\0\x30\x3a\x31\0\x09\x73\x74\x72\ +\x75\x63\x74\x20\x62\x70\x66\x5f\x6d\x61\x70\x20\x2a\x6d\x61\x70\x20\x3d\x20\ +\x63\x74\x78\x2d\x3e\x6d\x61\x70\x3b\0\x09\x69\x66\x20\x28\x21\x6d\x61\x70\x29\ +\0\x09\x5f\x5f\x75\x36\x34\x20\x73\x65\x71\x5f\x6e\x75\x6d\x20\x3d\x20\x63\x74\ +\x78\x2d\x3e\x6d\x65\x74\x61\x2d\x3e\x73\x65\x71\x5f\x6e\x75\x6d\x3b\0\x30\x3a\ +\x32\0\x09\x69\x66\x20\x28\x73\x65\x71\x5f\x6e\x75\x6d\x20\x3d\x3d\x20\x30\x29\ +\0\x09\x09\x42\x50\x46\x5f\x53\x45\x51\x5f\x50\x52\x49\x4e\x54\x46\x28\x73\x65\ +\x71\x2c\x20\x22\x20\x20\x69\x64\x20\x6e\x61\x6d\x65\x20\x20\x20\x20\x20\x20\ +\x20\x20\x20\x20\x20\x20\x20\x6d\x61\x78\x5f\x65\x6e\x74\x72\x69\x65\x73\x5c\ +\x6e\x22\x29\x3b\0\x62\x70\x66\x5f\x6d\x61\x70\0\x69\x64\0\x6e\x61\x6d\x65\0\ +\x6d\x61\x78\x5f\x65\x6e\x74\x72\x69\x65\x73\0\x5f\x5f\x75\x33\x32\0\x75\x6e\ \x73\x69\x67\x6e\x65\x64\x20\x69\x6e\x74\0\x63\x68\x61\x72\0\x5f\x5f\x41\x52\ \x52\x41\x59\x5f\x53\x49\x5a\x45\x5f\x54\x59\x50\x45\x5f\x5f\0\x09\x42\x50\x46\ \x5f\x53\x45\x51\x5f\x50\x52\x49\x4e\x54\x46\x28\x73\x65\x71\x2c\x20\x22\x25\ @@ -237,90 +238,90 @@ iterators_bpf__load(struct iterators_bpf *skel) \x5f\x70\x72\x6f\x67\x2e\x5f\x5f\x5f\x66\x6d\x74\0\x64\x75\x6d\x70\x5f\x62\x70\ \x66\x5f\x70\x72\x6f\x67\x2e\x5f\x5f\x5f\x66\x6d\x74\x2e\x32\0\x4c\x49\x43\x45\ \x4e\x53\x45\0\x2e\x72\x6f\x64\x61\x74\x61\0\x6c\x69\x63\x65\x6e\x73\x65\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x2d\x09\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x02\0\0\ -\0\x04\0\0\0\x62\0\0\0\x01\0\0\0\x80\x04\0\0\0\0\0\0\0\0\0\0\x69\x74\x65\x72\ -\x61\x74\x6f\x72\x2e\x72\x6f\x64\x61\x74\x61\0\0\0\0\0\0\0\0\0\0\0\0\0\x2f\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\x20\x20\x69\x64\x20\x6e\x61\x6d\x65\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6d\x61\x78\x5f\x65\x6e\x74\x72\x69\x65\ -\x73\x0a\0\x25\x34\x75\x20\x25\x2d\x31\x36\x73\x25\x36\x64\x0a\0\x20\x20\x69\ -\x64\x20\x6e\x61\x6d\x65\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x61\x74\x74\x61\x63\x68\x65\x64\x0a\0\x25\x34\x75\x20\x25\x2d\x31\x36\x73\x20\ -\x25\x73\x20\x25\x73\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x47\x50\x4c\0\0\0\0\0\ -\x79\x12\0\0\0\0\0\0\x79\x26\0\0\0\0\0\0\x79\x17\x08\0\0\0\0\0\x15\x07\x1b\0\0\ -\0\0\0\x79\x11\0\0\0\0\0\0\x79\x11\x10\0\0\0\0\0\x55\x01\x08\0\0\0\0\0\xbf\xa4\ -\0\0\0\0\0\0\x07\x04\0\0\xe8\xff\xff\xff\xbf\x61\0\0\0\0\0\0\x18\x62\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\xb7\x03\0\0\x23\0\0\0\xb7\x05\0\0\0\0\0\0\x85\0\0\0\x7e\0\0\ -\0\x61\x71\0\0\0\0\0\0\x7b\x1a\xe8\xff\0\0\0\0\xb7\x01\0\0\x04\0\0\0\xbf\x72\0\ -\0\0\0\0\0\x0f\x12\0\0\0\0\0\0\x7b\x2a\xf0\xff\0\0\0\0\x61\x71\x14\0\0\0\0\0\ -\x7b\x1a\xf8\xff\0\0\0\0\xbf\xa4\0\0\0\0\0\0\x07\x04\0\0\xe8\xff\xff\xff\xbf\ -\x61\0\0\0\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x23\0\0\0\xb7\x03\0\0\x0e\0\0\0\ -\xb7\x05\0\0\x18\0\0\0\x85\0\0\0\x7e\0\0\0\xb7\0\0\0\0\0\0\0\x95\0\0\0\0\0\0\0\ -\0\0\0\0\x07\0\0\0\0\0\0\0\x42\0\0\0\x7b\0\0\0\x1e\x3c\x01\0\x01\0\0\0\x42\0\0\ -\0\x7b\0\0\0\x24\x3c\x01\0\x02\0\0\0\x42\0\0\0\xee\0\0\0\x1d\x44\x01\0\x03\0\0\ -\0\x42\0\0\0\x0f\x01\0\0\x06\x4c\x01\0\x04\0\0\0\x42\0\0\0\x1a\x01\0\0\x17\x40\ -\x01\0\x05\0\0\0\x42\0\0\0\x1a\x01\0\0\x1d\x40\x01\0\x06\0\0\0\x42\0\0\0\x43\ -\x01\0\0\x06\x58\x01\0\x08\0\0\0\x42\0\0\0\x56\x01\0\0\x03\x5c\x01\0\x0f\0\0\0\ -\x42\0\0\0\xdc\x01\0\0\x02\x64\x01\0\x1f\0\0\0\x42\0\0\0\x2a\x02\0\0\x01\x6c\ -\x01\0\0\0\0\0\x02\0\0\0\x3e\0\0\0\0\0\0\0\x08\0\0\0\x08\0\0\0\x3e\0\0\0\0\0\0\ -\0\x10\0\0\0\x02\0\0\0\xea\0\0\0\0\0\0\0\x20\0\0\0\x02\0\0\0\x3e\0\0\0\0\0\0\0\ -\x28\0\0\0\x08\0\0\0\x3f\x01\0\0\0\0\0\0\x78\0\0\0\x0d\0\0\0\x3e\0\0\0\0\0\0\0\ -\x88\0\0\0\x0d\0\0\0\xea\0\0\0\0\0\0\0\xa8\0\0\0\x0d\0\0\0\x3f\x01\0\0\0\0\0\0\ -\x1a\0\0\0\x21\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\x64\x75\x6d\x70\x5f\x62\x70\x66\x5f\x6d\x61\x70\0\0\0\0\ -\0\0\0\0\x1c\0\0\0\0\0\0\0\x08\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\x10\0\0\0\0\0\0\ -\0\0\0\0\0\x0a\0\0\0\x01\0\0\0\0\0\0\0\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\x10\0\0\0\0\0\0\0\x62\x70\x66\x5f\x69\x74\x65\x72\x5f\x62\x70\x66\x5f\x6d\ -\x61\x70\0\0\0\0\0\0\0\0\x47\x50\x4c\0\0\0\0\0\x79\x12\0\0\0\0\0\0\x79\x26\0\0\ -\0\0\0\0\x79\x12\x08\0\0\0\0\0\x15\x02\x3c\0\0\0\0\0\x79\x11\0\0\0\0\0\0\x79\ -\x27\0\0\0\0\0\0\x79\x11\x10\0\0\0\0\0\x55\x01\x08\0\0\0\0\0\xbf\xa4\0\0\0\0\0\ -\0\x07\x04\0\0\xd0\xff\xff\xff\xbf\x61\0\0\0\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\ -\x31\0\0\0\xb7\x03\0\0\x20\0\0\0\xb7\x05\0\0\0\0\0\0\x85\0\0\0\x7e\0\0\0\x7b\ -\x6a\xc8\xff\0\0\0\0\x61\x71\0\0\0\0\0\0\x7b\x1a\xd0\xff\0\0\0\0\xb7\x03\0\0\ -\x04\0\0\0\xbf\x79\0\0\0\0\0\0\x0f\x39\0\0\0\0\0\0\x79\x71\x28\0\0\0\0\0\x79\ -\x78\x30\0\0\0\0\0\x15\x08\x18\0\0\0\0\0\xb7\x02\0\0\0\0\0\0\x0f\x21\0\0\0\0\0\ -\0\x61\x11\x04\0\0\0\0\0\x79\x83\x08\0\0\0\0\0\x67\x01\0\0\x03\0\0\0\x0f\x13\0\ -\0\0\0\0\0\x79\x86\0\0\0\0\0\0\xbf\xa1\0\0\0\0\0\0\x07\x01\0\0\xf8\xff\xff\xff\ -\xb7\x02\0\0\x08\0\0\0\x85\0\0\0\x71\0\0\0\xb7\x01\0\0\0\0\0\0\x79\xa3\xf8\xff\ -\0\0\0\0\x0f\x13\0\0\0\0\0\0\xbf\xa1\0\0\0\0\0\0\x07\x01\0\0\xf4\xff\xff\xff\ -\xb7\x02\0\0\x04\0\0\0\x85\0\0\0\x71\0\0\0\xb7\x03\0\0\x04\0\0\0\x61\xa1\xf4\ -\xff\0\0\0\0\x61\x82\x10\0\0\0\0\0\x3d\x21\x02\0\0\0\0\0\x0f\x16\0\0\0\0\0\0\ -\xbf\x69\0\0\0\0\0\0\x7b\x9a\xd8\xff\0\0\0\0\x79\x71\x18\0\0\0\0\0\x7b\x1a\xe0\ -\xff\0\0\0\0\x79\x71\x20\0\0\0\0\0\x79\x11\0\0\0\0\0\0\x0f\x31\0\0\0\0\0\0\x7b\ -\x1a\xe8\xff\0\0\0\0\xbf\xa4\0\0\0\0\0\0\x07\x04\0\0\xd0\xff\xff\xff\x79\xa1\ -\xc8\xff\0\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x51\0\0\0\xb7\x03\0\0\x11\0\0\0\ -\xb7\x05\0\0\x20\0\0\0\x85\0\0\0\x7e\0\0\0\xb7\0\0\0\0\0\0\0\x95\0\0\0\0\0\0\0\ -\0\0\0\0\x17\0\0\0\0\0\0\0\x42\0\0\0\x7b\0\0\0\x1e\x80\x01\0\x01\0\0\0\x42\0\0\ -\0\x7b\0\0\0\x24\x80\x01\0\x02\0\0\0\x42\0\0\0\x60\x02\0\0\x1f\x88\x01\0\x03\0\ -\0\0\x42\0\0\0\x84\x02\0\0\x06\x94\x01\0\x04\0\0\0\x42\0\0\0\x1a\x01\0\0\x17\ -\x84\x01\0\x05\0\0\0\x42\0\0\0\x9d\x02\0\0\x0e\xa0\x01\0\x06\0\0\0\x42\0\0\0\ -\x1a\x01\0\0\x1d\x84\x01\0\x07\0\0\0\x42\0\0\0\x43\x01\0\0\x06\xa4\x01\0\x09\0\ -\0\0\x42\0\0\0\xaf\x02\0\0\x03\xa8\x01\0\x11\0\0\0\x42\0\0\0\x1f\x03\0\0\x02\ -\xb0\x01\0\x18\0\0\0\x42\0\0\0\x5a\x03\0\0\x06\x04\x01\0\x1b\0\0\0\x42\0\0\0\0\ -\0\0\0\0\0\0\0\x1c\0\0\0\x42\0\0\0\xab\x03\0\0\x0f\x10\x01\0\x1d\0\0\0\x42\0\0\ -\0\xc0\x03\0\0\x2d\x14\x01\0\x1f\0\0\0\x42\0\0\0\xf7\x03\0\0\x0d\x0c\x01\0\x21\ -\0\0\0\x42\0\0\0\0\0\0\0\0\0\0\0\x22\0\0\0\x42\0\0\0\xc0\x03\0\0\x02\x14\x01\0\ -\x25\0\0\0\x42\0\0\0\x1e\x04\0\0\x0d\x18\x01\0\x28\0\0\0\x42\0\0\0\0\0\0\0\0\0\ -\0\0\x29\0\0\0\x42\0\0\0\x1e\x04\0\0\x0d\x18\x01\0\x2c\0\0\0\x42\0\0\0\x1e\x04\ -\0\0\x0d\x18\x01\0\x2d\0\0\0\x42\0\0\0\x4c\x04\0\0\x1b\x1c\x01\0\x2e\0\0\0\x42\ -\0\0\0\x4c\x04\0\0\x06\x1c\x01\0\x2f\0\0\0\x42\0\0\0\x6f\x04\0\0\x0d\x24\x01\0\ -\x31\0\0\0\x42\0\0\0\x1f\x03\0\0\x02\xb0\x01\0\x40\0\0\0\x42\0\0\0\x2a\x02\0\0\ -\x01\xc0\x01\0\0\0\0\0\x14\0\0\0\x3e\0\0\0\0\0\0\0\x08\0\0\0\x08\0\0\0\x3e\0\0\ -\0\0\0\0\0\x10\0\0\0\x14\0\0\0\xea\0\0\0\0\0\0\0\x20\0\0\0\x14\0\0\0\x3e\0\0\0\ -\0\0\0\0\x28\0\0\0\x18\0\0\0\x3e\0\0\0\0\0\0\0\x30\0\0\0\x08\0\0\0\x3f\x01\0\0\ -\0\0\0\0\x88\0\0\0\x1a\0\0\0\x3e\0\0\0\0\0\0\0\x98\0\0\0\x1a\0\0\0\xea\0\0\0\0\ -\0\0\0\xb0\0\0\0\x1a\0\0\0\x52\x03\0\0\0\0\0\0\xb8\0\0\0\x1a\0\0\0\x56\x03\0\0\ -\0\0\0\0\xc8\0\0\0\x1f\0\0\0\x84\x03\0\0\0\0\0\0\xe0\0\0\0\x20\0\0\0\xea\0\0\0\ -\0\0\0\0\xf8\0\0\0\x20\0\0\0\x3e\0\0\0\0\0\0\0\x20\x01\0\0\x24\0\0\0\x3e\0\0\0\ -\0\0\0\0\x58\x01\0\0\x1a\0\0\0\xea\0\0\0\0\0\0\0\x68\x01\0\0\x20\0\0\0\x46\x04\ -\0\0\0\0\0\0\x90\x01\0\0\x1a\0\0\0\x3f\x01\0\0\0\0\0\0\xa0\x01\0\0\x1a\0\0\0\ -\x87\x04\0\0\0\0\0\0\xa8\x01\0\0\x18\0\0\0\x3e\0\0\0\0\0\0\0\x1a\0\0\0\x42\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\x64\x75\x6d\x70\x5f\x62\x70\x66\x5f\x70\x72\x6f\x67\0\0\0\0\0\0\0\x1c\0\0\ -\0\0\0\0\0\x08\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\x10\0\0\0\0\0\0\0\0\0\0\0\x1a\0\ -\0\0\x01\0\0\0\0\0\0\0\x13\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x10\0\0\0\0\0\ -\0\0\x62\x70\x66\x5f\x69\x74\x65\x72\x5f\x62\x70\x66\x5f\x70\x72\x6f\x67\0\0\0\ -\0\0\0\0"; +\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x3f\x09\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x02\0\0\0\ +\x04\0\0\0\x62\0\0\0\x01\0\0\0\x80\x04\0\0\0\0\0\0\0\0\0\0\x69\x74\x65\x72\x61\ +\x74\x6f\x72\x2e\x72\x6f\x64\x61\x74\x61\0\0\0\0\0\0\0\0\0\0\0\0\0\x2f\0\0\0\0\ +\0\0\0\0\0\0\0\0\0\0\0\x20\x20\x69\x64\x20\x6e\x61\x6d\x65\x20\x20\x20\x20\x20\ +\x20\x20\x20\x20\x20\x20\x20\x20\x6d\x61\x78\x5f\x65\x6e\x74\x72\x69\x65\x73\ +\x0a\0\x25\x34\x75\x20\x25\x2d\x31\x36\x73\x25\x36\x64\x0a\0\x20\x20\x69\x64\ +\x20\x6e\x61\x6d\x65\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x61\ +\x74\x74\x61\x63\x68\x65\x64\x0a\0\x25\x34\x75\x20\x25\x2d\x31\x36\x73\x20\x25\ +\x73\x20\x25\x73\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ +\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x47\x50\x4c\0\0\0\0\0\x79\ +\x12\0\0\0\0\0\0\x79\x26\0\0\0\0\0\0\x79\x17\x08\0\0\0\0\0\x15\x07\x1b\0\0\0\0\ +\0\x79\x11\0\0\0\0\0\0\x79\x11\x10\0\0\0\0\0\x55\x01\x08\0\0\0\0\0\xbf\xa4\0\0\ +\0\0\0\0\x07\x04\0\0\xe8\xff\xff\xff\xbf\x61\0\0\0\0\0\0\x18\x62\0\0\0\0\0\0\0\ +\0\0\0\0\0\0\0\xb7\x03\0\0\x23\0\0\0\xb7\x05\0\0\0\0\0\0\x85\0\0\0\x7e\0\0\0\ +\x61\x71\0\0\0\0\0\0\x7b\x1a\xe8\xff\0\0\0\0\xb7\x01\0\0\x04\0\0\0\xbf\x72\0\0\ +\0\0\0\0\x0f\x12\0\0\0\0\0\0\x7b\x2a\xf0\xff\0\0\0\0\x61\x71\x14\0\0\0\0\0\x7b\ +\x1a\xf8\xff\0\0\0\0\xbf\xa4\0\0\0\0\0\0\x07\x04\0\0\xe8\xff\xff\xff\xbf\x61\0\ +\0\0\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x23\0\0\0\xb7\x03\0\0\x0e\0\0\0\xb7\x05\ +\0\0\x18\0\0\0\x85\0\0\0\x7e\0\0\0\xb7\0\0\0\0\0\0\0\x95\0\0\0\0\0\0\0\0\0\0\0\ +\x07\0\0\0\0\0\0\0\x42\0\0\0\x89\0\0\0\x1e\x3c\x01\0\x01\0\0\0\x42\0\0\0\x89\0\ +\0\0\x24\x3c\x01\0\x02\0\0\0\x42\0\0\0\0\x01\0\0\x1d\x44\x01\0\x03\0\0\0\x42\0\ +\0\0\x21\x01\0\0\x06\x4c\x01\0\x04\0\0\0\x42\0\0\0\x2c\x01\0\0\x17\x40\x01\0\ +\x05\0\0\0\x42\0\0\0\x2c\x01\0\0\x1d\x40\x01\0\x06\0\0\0\x42\0\0\0\x55\x01\0\0\ +\x06\x58\x01\0\x08\0\0\0\x42\0\0\0\x68\x01\0\0\x03\x5c\x01\0\x0f\0\0\0\x42\0\0\ +\0\xee\x01\0\0\x02\x64\x01\0\x1f\0\0\0\x42\0\0\0\x3c\x02\0\0\x01\x6c\x01\0\0\0\ +\0\0\x02\0\0\0\x3e\0\0\0\0\0\0\0\x08\0\0\0\x08\0\0\0\x3e\0\0\0\0\0\0\0\x10\0\0\ +\0\x02\0\0\0\xfc\0\0\0\0\0\0\0\x20\0\0\0\x02\0\0\0\x3e\0\0\0\0\0\0\0\x28\0\0\0\ +\x08\0\0\0\x51\x01\0\0\0\0\0\0\x78\0\0\0\x0d\0\0\0\x3e\0\0\0\0\0\0\0\x88\0\0\0\ +\x0d\0\0\0\xfc\0\0\0\0\0\0\0\xa8\0\0\0\x0d\0\0\0\x51\x01\0\0\0\0\0\0\x1a\0\0\0\ +\x21\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ +\0\0\0\0\0\0\x64\x75\x6d\x70\x5f\x62\x70\x66\x5f\x6d\x61\x70\0\0\0\0\0\0\0\0\ +\x1c\0\0\0\0\0\0\0\x08\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\x10\0\0\0\0\0\0\0\0\0\0\ +\0\x0a\0\0\0\x01\0\0\0\0\0\0\0\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x10\0\ +\0\0\0\0\0\0\x62\x70\x66\x5f\x69\x74\x65\x72\x5f\x62\x70\x66\x5f\x6d\x61\x70\0\ +\0\0\0\0\0\0\0\x47\x50\x4c\0\0\0\0\0\x79\x12\0\0\0\0\0\0\x79\x26\0\0\0\0\0\0\ +\x79\x12\x08\0\0\0\0\0\x15\x02\x3c\0\0\0\0\0\x79\x11\0\0\0\0\0\0\x79\x27\0\0\0\ +\0\0\0\x79\x11\x10\0\0\0\0\0\x55\x01\x08\0\0\0\0\0\xbf\xa4\0\0\0\0\0\0\x07\x04\ +\0\0\xd0\xff\xff\xff\xbf\x61\0\0\0\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x31\0\0\0\ +\xb7\x03\0\0\x20\0\0\0\xb7\x05\0\0\0\0\0\0\x85\0\0\0\x7e\0\0\0\x7b\x6a\xc8\xff\ +\0\0\0\0\x61\x71\0\0\0\0\0\0\x7b\x1a\xd0\xff\0\0\0\0\xb7\x03\0\0\x04\0\0\0\xbf\ +\x79\0\0\0\0\0\0\x0f\x39\0\0\0\0\0\0\x79\x71\x28\0\0\0\0\0\x79\x78\x30\0\0\0\0\ +\0\x15\x08\x18\0\0\0\0\0\xb7\x02\0\0\0\0\0\0\x0f\x21\0\0\0\0\0\0\x61\x11\x04\0\ +\0\0\0\0\x79\x83\x08\0\0\0\0\0\x67\x01\0\0\x03\0\0\0\x0f\x13\0\0\0\0\0\0\x79\ +\x86\0\0\0\0\0\0\xbf\xa1\0\0\0\0\0\0\x07\x01\0\0\xf8\xff\xff\xff\xb7\x02\0\0\ +\x08\0\0\0\x85\0\0\0\x71\0\0\0\xb7\x01\0\0\0\0\0\0\x79\xa3\xf8\xff\0\0\0\0\x0f\ +\x13\0\0\0\0\0\0\xbf\xa1\0\0\0\0\0\0\x07\x01\0\0\xf4\xff\xff\xff\xb7\x02\0\0\ +\x04\0\0\0\x85\0\0\0\x71\0\0\0\xb7\x03\0\0\x04\0\0\0\x61\xa1\xf4\xff\0\0\0\0\ +\x61\x82\x10\0\0\0\0\0\x3d\x21\x02\0\0\0\0\0\x0f\x16\0\0\0\0\0\0\xbf\x69\0\0\0\ +\0\0\0\x7b\x9a\xd8\xff\0\0\0\0\x79\x71\x18\0\0\0\0\0\x7b\x1a\xe0\xff\0\0\0\0\ +\x79\x71\x20\0\0\0\0\0\x79\x11\0\0\0\0\0\0\x0f\x31\0\0\0\0\0\0\x7b\x1a\xe8\xff\ +\0\0\0\0\xbf\xa4\0\0\0\0\0\0\x07\x04\0\0\xd0\xff\xff\xff\x79\xa1\xc8\xff\0\0\0\ +\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x51\0\0\0\xb7\x03\0\0\x11\0\0\0\xb7\x05\0\0\x20\ +\0\0\0\x85\0\0\0\x7e\0\0\0\xb7\0\0\0\0\0\0\0\x95\0\0\0\0\0\0\0\0\0\0\0\x17\0\0\ +\0\0\0\0\0\x42\0\0\0\x89\0\0\0\x1e\x80\x01\0\x01\0\0\0\x42\0\0\0\x89\0\0\0\x24\ +\x80\x01\0\x02\0\0\0\x42\0\0\0\x72\x02\0\0\x1f\x88\x01\0\x03\0\0\0\x42\0\0\0\ +\x96\x02\0\0\x06\x94\x01\0\x04\0\0\0\x42\0\0\0\x2c\x01\0\0\x17\x84\x01\0\x05\0\ +\0\0\x42\0\0\0\xaf\x02\0\0\x0e\xa0\x01\0\x06\0\0\0\x42\0\0\0\x2c\x01\0\0\x1d\ +\x84\x01\0\x07\0\0\0\x42\0\0\0\x55\x01\0\0\x06\xa4\x01\0\x09\0\0\0\x42\0\0\0\ +\xc1\x02\0\0\x03\xa8\x01\0\x11\0\0\0\x42\0\0\0\x31\x03\0\0\x02\xb0\x01\0\x18\0\ +\0\0\x42\0\0\0\x6c\x03\0\0\x06\x04\x01\0\x1b\0\0\0\x42\0\0\0\0\0\0\0\0\0\0\0\ +\x1c\0\0\0\x42\0\0\0\xbd\x03\0\0\x0f\x10\x01\0\x1d\0\0\0\x42\0\0\0\xd2\x03\0\0\ +\x2d\x14\x01\0\x1f\0\0\0\x42\0\0\0\x09\x04\0\0\x0d\x0c\x01\0\x21\0\0\0\x42\0\0\ +\0\0\0\0\0\0\0\0\0\x22\0\0\0\x42\0\0\0\xd2\x03\0\0\x02\x14\x01\0\x25\0\0\0\x42\ +\0\0\0\x30\x04\0\0\x0d\x18\x01\0\x28\0\0\0\x42\0\0\0\0\0\0\0\0\0\0\0\x29\0\0\0\ +\x42\0\0\0\x30\x04\0\0\x0d\x18\x01\0\x2c\0\0\0\x42\0\0\0\x30\x04\0\0\x0d\x18\ +\x01\0\x2d\0\0\0\x42\0\0\0\x5e\x04\0\0\x1b\x1c\x01\0\x2e\0\0\0\x42\0\0\0\x5e\ +\x04\0\0\x06\x1c\x01\0\x2f\0\0\0\x42\0\0\0\x81\x04\0\0\x0d\x24\x01\0\x30\0\0\0\ +\x42\0\0\0\0\0\0\0\0\0\0\0\x31\0\0\0\x42\0\0\0\x31\x03\0\0\x02\xb0\x01\0\x40\0\ +\0\0\x42\0\0\0\x3c\x02\0\0\x01\xc0\x01\0\0\0\0\0\x14\0\0\0\x3e\0\0\0\0\0\0\0\ +\x08\0\0\0\x08\0\0\0\x3e\0\0\0\0\0\0\0\x10\0\0\0\x14\0\0\0\xfc\0\0\0\0\0\0\0\ +\x20\0\0\0\x14\0\0\0\x3e\0\0\0\0\0\0\0\x28\0\0\0\x18\0\0\0\x3e\0\0\0\0\0\0\0\ +\x30\0\0\0\x08\0\0\0\x51\x01\0\0\0\0\0\0\x88\0\0\0\x1a\0\0\0\x3e\0\0\0\0\0\0\0\ +\x98\0\0\0\x1a\0\0\0\xfc\0\0\0\0\0\0\0\xb0\0\0\0\x1a\0\0\0\x64\x03\0\0\0\0\0\0\ +\xb8\0\0\0\x1a\0\0\0\x68\x03\0\0\0\0\0\0\xc8\0\0\0\x1f\0\0\0\x96\x03\0\0\0\0\0\ +\0\xe0\0\0\0\x20\0\0\0\xfc\0\0\0\0\0\0\0\xf8\0\0\0\x20\0\0\0\x3e\0\0\0\0\0\0\0\ +\x20\x01\0\0\x24\0\0\0\x3e\0\0\0\0\0\0\0\x58\x01\0\0\x1a\0\0\0\xfc\0\0\0\0\0\0\ +\0\x68\x01\0\0\x20\0\0\0\x58\x04\0\0\0\0\0\0\x90\x01\0\0\x1a\0\0\0\x51\x01\0\0\ +\0\0\0\0\xa0\x01\0\0\x1a\0\0\0\x99\x04\0\0\0\0\0\0\xa8\x01\0\0\x18\0\0\0\x3e\0\ +\0\0\0\0\0\0\x1a\0\0\0\x42\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ +\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x64\x75\x6d\x70\x5f\x62\x70\x66\x5f\x70\x72\ +\x6f\x67\0\0\0\0\0\0\0\x1c\0\0\0\0\0\0\0\x08\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\ +\x10\0\0\0\0\0\0\0\0\0\0\0\x1b\0\0\0\x01\0\0\0\0\0\0\0\x13\0\0\0\0\0\0\0\0\0\0\ +\0\0\0\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\x62\x70\x66\x5f\x69\x74\x65\x72\x5f\x62\ +\x70\x66\x5f\x70\x72\x6f\x67\0\0\0\0\0\0\0"; opts.insns_sz = 2216; opts.insns = (void *)"\ \xbf\x16\0\0\0\0\0\0\xbf\xa1\0\0\0\0\0\0\x07\x01\0\0\x78\xff\xff\xff\xb7\x02\0\ @@ -331,66 +332,66 @@ iterators_bpf__load(struct iterators_bpf *skel) \0\0\0\x85\0\0\0\xa8\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x61\x01\0\0\0\0\ \0\0\xd5\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\xbf\x70\0\0\ \0\0\0\0\x95\0\0\0\0\0\0\0\x61\x60\x08\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\ -\x48\x0e\0\0\x63\x01\0\0\0\0\0\0\x61\x60\x0c\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\ -\0\0\x44\x0e\0\0\x63\x01\0\0\0\0\0\0\x79\x60\x10\0\0\0\0\0\x18\x61\0\0\0\0\0\0\ -\0\0\0\0\x38\x0e\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\x05\0\0\ -\x18\x61\0\0\0\0\0\0\0\0\0\0\x30\x0e\0\0\x7b\x01\0\0\0\0\0\0\xb7\x01\0\0\x12\0\ -\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x30\x0e\0\0\xb7\x03\0\0\x1c\0\0\0\x85\0\0\0\ +\x58\x0e\0\0\x63\x01\0\0\0\0\0\0\x61\x60\x0c\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\ +\0\0\x54\x0e\0\0\x63\x01\0\0\0\0\0\0\x79\x60\x10\0\0\0\0\0\x18\x61\0\0\0\0\0\0\ +\0\0\0\0\x48\x0e\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\x05\0\0\ +\x18\x61\0\0\0\0\0\0\0\0\0\0\x40\x0e\0\0\x7b\x01\0\0\0\0\0\0\xb7\x01\0\0\x12\0\ +\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x40\x0e\0\0\xb7\x03\0\0\x1c\0\0\0\x85\0\0\0\ \xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\xd4\xff\0\0\0\0\x63\x7a\x78\xff\0\0\0\0\ -\x61\xa0\x78\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x80\x0e\0\0\x63\x01\0\0\0\ +\x61\xa0\x78\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x90\x0e\0\0\x63\x01\0\0\0\ \0\0\0\x61\x60\x1c\0\0\0\0\0\x15\0\x03\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\ -\x5c\x0e\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\0\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\ -\0\x50\x0e\0\0\xb7\x03\0\0\x48\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\ +\x6c\x0e\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\0\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\ +\0\x60\x0e\0\0\xb7\x03\0\0\x48\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\ \xc5\x07\xc3\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x63\x71\0\0\0\0\0\ -\0\x79\x63\x20\0\0\0\0\0\x15\x03\x08\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x98\ +\0\x79\x63\x20\0\0\0\0\0\x15\x03\x08\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xa8\ \x0e\0\0\xb7\x02\0\0\x62\0\0\0\x61\x60\x04\0\0\0\0\0\x45\0\x02\0\x01\0\0\0\x85\ \0\0\0\x94\0\0\0\x05\0\x01\0\0\0\0\0\x85\0\0\0\x71\0\0\0\x18\x62\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\x61\x20\0\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x08\x0f\0\0\x63\ -\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\x0f\0\0\x18\x61\0\0\0\0\0\0\0\0\ -\0\0\x10\x0f\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x98\x0e\0\0\ -\x18\x61\0\0\0\0\0\0\0\0\0\0\x18\x0f\0\0\x7b\x01\0\0\0\0\0\0\xb7\x01\0\0\x02\0\ -\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x08\x0f\0\0\xb7\x03\0\0\x20\0\0\0\x85\0\0\0\ +\0\0\0\0\0\0\0\x61\x20\0\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x18\x0f\0\0\x63\ +\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x10\x0f\0\0\x18\x61\0\0\0\0\0\0\0\ +\0\0\0\x20\x0f\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xa8\x0e\0\0\ +\x18\x61\0\0\0\0\0\0\0\0\0\0\x28\x0f\0\0\x7b\x01\0\0\0\0\0\0\xb7\x01\0\0\x02\0\ +\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x18\x0f\0\0\xb7\x03\0\0\x20\0\0\0\x85\0\0\0\ \xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\x9f\xff\0\0\0\0\x18\x62\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\x61\x20\0\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x28\x0f\0\0\x63\ -\x01\0\0\0\0\0\0\xb7\x01\0\0\x16\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x28\x0f\0\0\ +\0\0\0\0\0\0\x61\x20\0\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x38\x0f\0\0\x63\ +\x01\0\0\0\0\0\0\xb7\x01\0\0\x16\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x38\x0f\0\0\ \xb7\x03\0\0\x04\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\x92\xff\ -\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x30\x0f\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\ -\x78\x11\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x38\x0f\0\0\x18\ -\x61\0\0\0\0\0\0\0\0\0\0\x70\x11\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\ -\0\0\0\x40\x10\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xb8\x11\0\0\x7b\x01\0\0\0\0\0\0\ -\x18\x60\0\0\0\0\0\0\0\0\0\0\x48\x10\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xc8\x11\0\ -\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xe8\x10\0\0\x18\x61\0\0\0\0\ -\0\0\0\0\0\0\xe8\x11\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xe0\x11\0\0\x7b\x01\0\0\0\0\0\0\x61\x60\x08\0\0\ -\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x80\x11\0\0\x63\x01\0\0\0\0\0\0\x61\x60\x0c\ -\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x84\x11\0\0\x63\x01\0\0\0\0\0\0\x79\x60\ -\x10\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x88\x11\0\0\x7b\x01\0\0\0\0\0\0\x61\ -\xa0\x78\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xb0\x11\0\0\x63\x01\0\0\0\0\0\ -\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xf8\x11\0\0\xb7\x02\0\0\x11\0\0\0\xb7\x03\0\0\ +\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x40\x0f\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\ +\x88\x11\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x48\x0f\0\0\x18\ +\x61\0\0\0\0\0\0\0\0\0\0\x80\x11\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\ +\0\0\0\x50\x10\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xc8\x11\0\0\x7b\x01\0\0\0\0\0\0\ +\x18\x60\0\0\0\0\0\0\0\0\0\0\x58\x10\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xd8\x11\0\ +\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xf8\x10\0\0\x18\x61\0\0\0\0\ +\0\0\0\0\0\0\xf8\x11\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\0\0\ +\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xf0\x11\0\0\x7b\x01\0\0\0\0\0\0\x61\x60\x08\0\0\ +\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x90\x11\0\0\x63\x01\0\0\0\0\0\0\x61\x60\x0c\ +\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x94\x11\0\0\x63\x01\0\0\0\0\0\0\x79\x60\ +\x10\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x98\x11\0\0\x7b\x01\0\0\0\0\0\0\x61\ +\xa0\x78\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xc0\x11\0\0\x63\x01\0\0\0\0\0\ +\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x08\x12\0\0\xb7\x02\0\0\x11\0\0\0\xb7\x03\0\0\ \x0c\0\0\0\xb7\x04\0\0\0\0\0\0\x85\0\0\0\xa7\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\ -\x5c\xff\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x68\x11\0\0\x63\x70\x6c\0\0\0\0\0\ +\x5c\xff\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x78\x11\0\0\x63\x70\x6c\0\0\0\0\0\ \x77\x07\0\0\x20\0\0\0\x63\x70\x70\0\0\0\0\0\xb7\x01\0\0\x05\0\0\0\x18\x62\0\0\ -\0\0\0\0\0\0\0\0\x68\x11\0\0\xb7\x03\0\0\x8c\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\ -\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xd8\x11\0\0\x61\x01\0\0\0\0\0\0\xd5\ +\0\0\0\0\0\0\0\0\x78\x11\0\0\xb7\x03\0\0\x8c\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\ +\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xe8\x11\0\0\x61\x01\0\0\0\0\0\0\xd5\ \x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\xc5\x07\x4a\xff\0\0\ -\0\0\x63\x7a\x80\xff\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x10\x12\0\0\x18\x61\0\ -\0\0\0\0\0\0\0\0\0\x10\x17\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\ -\x18\x12\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x08\x17\0\0\x7b\x01\0\0\0\0\0\0\x18\ -\x60\0\0\0\0\0\0\0\0\0\0\x28\x14\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x50\x17\0\0\ -\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x30\x14\0\0\x18\x61\0\0\0\0\0\ -\0\0\0\0\0\x60\x17\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xd0\x15\ -\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x80\x17\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x78\x17\0\0\x7b\x01\0\0\0\0\ -\0\0\x61\x60\x08\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x18\x17\0\0\x63\x01\0\0\ -\0\0\0\0\x61\x60\x0c\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x1c\x17\0\0\x63\x01\ -\0\0\0\0\0\0\x79\x60\x10\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x20\x17\0\0\x7b\ -\x01\0\0\0\0\0\0\x61\xa0\x78\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x48\x17\0\ -\0\x63\x01\0\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x90\x17\0\0\xb7\x02\0\0\x12\ +\0\0\x63\x7a\x80\xff\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x20\x12\0\0\x18\x61\0\ +\0\0\0\0\0\0\0\0\0\x30\x17\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\ +\x28\x12\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x28\x17\0\0\x7b\x01\0\0\0\0\0\0\x18\ +\x60\0\0\0\0\0\0\0\0\0\0\x38\x14\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x70\x17\0\0\ +\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x40\x14\0\0\x18\x61\0\0\0\0\0\ +\0\0\0\0\0\x80\x17\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xf0\x15\ +\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xa0\x17\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\ +\0\0\0\0\0\0\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x98\x17\0\0\x7b\x01\0\0\0\0\ +\0\0\x61\x60\x08\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x38\x17\0\0\x63\x01\0\0\ +\0\0\0\0\x61\x60\x0c\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x3c\x17\0\0\x63\x01\ +\0\0\0\0\0\0\x79\x60\x10\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x40\x17\0\0\x7b\ +\x01\0\0\0\0\0\0\x61\xa0\x78\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x68\x17\0\ +\0\x63\x01\0\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xb0\x17\0\0\xb7\x02\0\0\x12\ \0\0\0\xb7\x03\0\0\x0c\0\0\0\xb7\x04\0\0\0\0\0\0\x85\0\0\0\xa7\0\0\0\xbf\x07\0\ -\0\0\0\0\0\xc5\x07\x13\xff\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\x17\0\0\x63\ +\0\0\0\0\0\xc5\x07\x13\xff\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x20\x17\0\0\x63\ \x70\x6c\0\0\0\0\0\x77\x07\0\0\x20\0\0\0\x63\x70\x70\0\0\0\0\0\xb7\x01\0\0\x05\ -\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\0\x17\0\0\xb7\x03\0\0\x8c\0\0\0\x85\0\0\0\ -\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x70\x17\0\0\x61\x01\ +\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x20\x17\0\0\xb7\x03\0\0\x8c\0\0\0\x85\0\0\0\ +\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x90\x17\0\0\x61\x01\ \0\0\0\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\xc5\ \x07\x01\xff\0\0\0\0\x63\x7a\x84\xff\0\0\0\0\x61\xa1\x78\xff\0\0\0\0\xd5\x01\ \x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa0\x80\xff\0\0\0\0\ @@ -422,4 +423,19 @@ iterators_bpf__open_and_load(void) return skel; }
+__attribute__((unused)) static void +iterators_bpf__assert(struct iterators_bpf *s) +{ +#ifdef __cplusplus +#define _Static_assert static_assert +#endif +#ifdef __cplusplus +#undef _Static_assert +#endif +} + +static struct bpf_link *dump_bpf_map_link; +static struct bpf_link *dump_bpf_prog_link; +static struct iterators_bpf *skel; + #endif /* __ITERATORS_BPF_SKEL_H__ */ diff --git a/tools/bpf/bpftool/Documentation/bpftool-gen.rst b/tools/bpf/bpftool/Documentation/bpftool-gen.rst index 68454ef28f58..74bbefa28212 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-gen.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-gen.rst @@ -208,6 +208,11 @@ OPTIONS not use the majority of the libbpf infrastructure, and does not need libelf.
+ -P, --gen-preload-methods + For light skeletons, generate the static variables and the methods + required to preload an eBPF program and pin its objects to the bpf + filesystem. + EXAMPLES ======== **$ cat example1.bpf.c** diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool index 5df8d72c5179..6e433e86fb26 100644 --- a/tools/bpf/bpftool/bash-completion/bpftool +++ b/tools/bpf/bpftool/bash-completion/bpftool @@ -261,7 +261,7 @@ _bpftool() # Deal with options if [[ ${words[cword]} == -* ]]; then local c='--version --json --pretty --bpffs --mapcompat --debug \ - --use-loader --base-btf --legacy' + --use-loader --gen-preload-methods --base-btf --legacy' COMPREPLY=( $( compgen -W "$c" -- "$cur" ) ) return 0 fi diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c index 7ba7ff55d2ea..c62c4c65b631 100644 --- a/tools/bpf/bpftool/gen.c +++ b/tools/bpf/bpftool/gen.c @@ -652,6 +652,28 @@ static void codegen_destroy(struct bpf_object *obj, const char *obj_name) obj_name); }
+static void codegen_preload_vars(struct bpf_object *obj, const char *obj_name) +{ + struct bpf_program *prog; + + codegen("\ + \n\ + \n\ + "); + + bpf_object__for_each_program(prog, obj) { + codegen("\ + \n\ + static struct bpf_link *%s_link; \n\ + ", bpf_program__name(prog)); + } + + codegen("\ + \n\ + static struct %s *skel; \n\ + ", obj_name); +} + static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *header_guard) { DECLARE_LIBBPF_OPTS(gen_loader_opts, opts); @@ -800,6 +822,10 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
codegen_asserts(obj, obj_name);
+ if (gen_preload_methods) { + codegen_preload_vars(obj, obj_name); + } + codegen("\ \n\ \n\ @@ -1615,6 +1641,7 @@ static int do_help(int argc, char **argv) "\n" " " HELP_SPEC_OPTIONS " |\n" " {-L|--use-loader} }\n" + " {-P|--gen-preload-methods} }\n" "", bin_name, "gen");
diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c index e81227761f5d..5d5dae6215a3 100644 --- a/tools/bpf/bpftool/main.c +++ b/tools/bpf/bpftool/main.c @@ -31,6 +31,7 @@ bool block_mount; bool verifier_logs; bool relaxed_maps; bool use_loader; +bool gen_preload_methods; bool legacy_libbpf; struct btf *base_btf; struct hashmap *refs_table; @@ -426,6 +427,7 @@ int main(int argc, char **argv) { "nomount", no_argument, NULL, 'n' }, { "debug", no_argument, NULL, 'd' }, { "use-loader", no_argument, NULL, 'L' }, + { "gen-preload-methods", no_argument, NULL, 'P' }, { "base-btf", required_argument, NULL, 'B' }, { "legacy", no_argument, NULL, 'l' }, { 0 } @@ -443,7 +445,7 @@ int main(int argc, char **argv) bin_name = argv[0];
opterr = 0; - while ((opt = getopt_long(argc, argv, "VhpjfLmndB:l", + while ((opt = getopt_long(argc, argv, "VhpjfLmndB:lP", options, NULL)) >= 0) { switch (opt) { case 'V': @@ -493,6 +495,9 @@ int main(int argc, char **argv) case 'l': legacy_libbpf = true; break; + case 'P': + gen_preload_methods = true; + break; default: p_err("unrecognized option '%s'", argv[optind - 1]); if (json_output) diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index 6e9277ffc68c..9485b354a084 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h @@ -90,6 +90,7 @@ extern bool block_mount; extern bool verifier_logs; extern bool relaxed_maps; extern bool use_loader; +extern bool gen_preload_methods; extern bool legacy_libbpf; extern struct btf *base_btf; extern struct hashmap *refs_table;
On Mon, Mar 28, 2022 at 10:52 AM Roberto Sassu roberto.sassu@huawei.com wrote:
The first part of the preload code generation consists in generating the static variables to be used by the code itself: the links and maps to be pinned, and the skeleton. Generation of the preload variables and methods is enabled with the option -P added to 'bpftool gen skeleton'.
The existing variables maps_link and progs_links in bpf_preload_kern.c have been renamed respectively to dump_bpf_map_link and dump_bpf_prog_link, to match the name of the variables in the main structure of the light skeleton.
Signed-off-by: Roberto Sassu roberto.sassu@huawei.com
kernel/bpf/preload/bpf_preload_kern.c | 35 +- kernel/bpf/preload/iterators/Makefile | 2 +- .../bpf/preload/iterators/iterators.lskel.h | 378 +++++++++--------- .../bpf/bpftool/Documentation/bpftool-gen.rst | 5 + tools/bpf/bpftool/bash-completion/bpftool | 2 +- tools/bpf/bpftool/gen.c | 27 ++ tools/bpf/bpftool/main.c | 7 +- tools/bpf/bpftool/main.h | 1 + 8 files changed, 254 insertions(+), 203 deletions(-)
[...]
+__attribute__((unused)) static void +iterators_bpf__assert(struct iterators_bpf *s) +{ +#ifdef __cplusplus +#define _Static_assert static_assert +#endif +#ifdef __cplusplus +#undef _Static_assert +#endif +}
+static struct bpf_link *dump_bpf_map_link; +static struct bpf_link *dump_bpf_prog_link; +static struct iterators_bpf *skel;
I don't understand what is this and what for? You are making an assumption that light skeleton can be instantiated just once, why? And adding extra bpftool option to light skeleton codegen just to save a bit of typing at the place where light skeleton is actually instantiated and used doesn't seems like a right approach.
Further, even if this is the way to go, please split out bpftool changes from kernel changes. There is nothing requiring them to be coupled together.
[...]
From: Andrii Nakryiko [mailto:andrii.nakryiko@gmail.com] Sent: Wednesday, March 30, 2022 1:52 AM On Mon, Mar 28, 2022 at 10:52 AM Roberto Sassu roberto.sassu@huawei.com wrote:
The first part of the preload code generation consists in generating the static variables to be used by the code itself: the links and maps to be pinned, and the skeleton. Generation of the preload variables and
methods
is enabled with the option -P added to 'bpftool gen skeleton'.
The existing variables maps_link and progs_links in bpf_preload_kern.c
have
been renamed respectively to dump_bpf_map_link and
dump_bpf_prog_link, to
match the name of the variables in the main structure of the light skeleton.
Signed-off-by: Roberto Sassu roberto.sassu@huawei.com
kernel/bpf/preload/bpf_preload_kern.c | 35 +- kernel/bpf/preload/iterators/Makefile | 2 +- .../bpf/preload/iterators/iterators.lskel.h | 378 +++++++++--------- .../bpf/bpftool/Documentation/bpftool-gen.rst | 5 + tools/bpf/bpftool/bash-completion/bpftool | 2 +- tools/bpf/bpftool/gen.c | 27 ++ tools/bpf/bpftool/main.c | 7 +- tools/bpf/bpftool/main.h | 1 + 8 files changed, 254 insertions(+), 203 deletions(-)
[...]
+__attribute__((unused)) static void +iterators_bpf__assert(struct iterators_bpf *s) +{ +#ifdef __cplusplus +#define _Static_assert static_assert +#endif +#ifdef __cplusplus +#undef _Static_assert +#endif +}
+static struct bpf_link *dump_bpf_map_link; +static struct bpf_link *dump_bpf_prog_link; +static struct iterators_bpf *skel;
I don't understand what is this and what for? You are making an assumption that light skeleton can be instantiated just once, why? And adding extra bpftool option to light skeleton codegen just to save a bit of typing at the place where light skeleton is actually instantiated and used doesn't seems like a right approach.
True, iterator_bpf is simple. Writing the preloading code for it is simple. But, what if you wanted to preload an LSM with 10 hooks or more?
Ok, regarding where the preloading code should be, I will try to move the generated code to the kernel module instead of the light skeleton.
Thanks
Roberto
HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063 Managing Director: Li Peng, Zhong Ronghua
Further, even if this is the way to go, please split out bpftool changes from kernel changes. There is nothing requiring them to be coupled together.
[...]
On Wed, Mar 30, 2022 at 12:44 AM Roberto Sassu roberto.sassu@huawei.com wrote:
From: Andrii Nakryiko [mailto:andrii.nakryiko@gmail.com] Sent: Wednesday, March 30, 2022 1:52 AM On Mon, Mar 28, 2022 at 10:52 AM Roberto Sassu roberto.sassu@huawei.com wrote:
The first part of the preload code generation consists in generating the static variables to be used by the code itself: the links and maps to be pinned, and the skeleton. Generation of the preload variables and
methods
is enabled with the option -P added to 'bpftool gen skeleton'.
The existing variables maps_link and progs_links in bpf_preload_kern.c
have
been renamed respectively to dump_bpf_map_link and
dump_bpf_prog_link, to
match the name of the variables in the main structure of the light skeleton.
Signed-off-by: Roberto Sassu roberto.sassu@huawei.com
kernel/bpf/preload/bpf_preload_kern.c | 35 +- kernel/bpf/preload/iterators/Makefile | 2 +- .../bpf/preload/iterators/iterators.lskel.h | 378 +++++++++--------- .../bpf/bpftool/Documentation/bpftool-gen.rst | 5 + tools/bpf/bpftool/bash-completion/bpftool | 2 +- tools/bpf/bpftool/gen.c | 27 ++ tools/bpf/bpftool/main.c | 7 +- tools/bpf/bpftool/main.h | 1 + 8 files changed, 254 insertions(+), 203 deletions(-)
[...]
+__attribute__((unused)) static void +iterators_bpf__assert(struct iterators_bpf *s) +{ +#ifdef __cplusplus +#define _Static_assert static_assert +#endif +#ifdef __cplusplus +#undef _Static_assert +#endif +}
+static struct bpf_link *dump_bpf_map_link; +static struct bpf_link *dump_bpf_prog_link; +static struct iterators_bpf *skel;
I don't understand what is this and what for? You are making an assumption that light skeleton can be instantiated just once, why? And adding extra bpftool option to light skeleton codegen just to save a bit of typing at the place where light skeleton is actually instantiated and used doesn't seems like a right approach.
True, iterator_bpf is simple. Writing the preloading code for it is simple. But, what if you wanted to preload an LSM with 10 hooks or more?
I suppose you'd write a straightforward code to do pinning ten times for ten different programs to ten different paths. But with this you don't have to establish a random set of conventions that might not apply in all the situations to anyone that would try to use this feature.
Worst case, light skeleton can be extended to provide a way to iterate all programs programmatically.
Ok, regarding where the preloading code should be, I will try to move the generated code to the kernel module instead of the light skeleton.
Thanks
Roberto
HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063 Managing Director: Li Peng, Zhong Ronghua
Further, even if this is the way to go, please split out bpftool changes from kernel changes. There is nothing requiring them to be coupled together.
[...]
From: Roberto Sassu Sent: Wednesday, March 30, 2022 9:45 AM
From: Andrii Nakryiko [mailto:andrii.nakryiko@gmail.com] Sent: Wednesday, March 30, 2022 1:52 AM On Mon, Mar 28, 2022 at 10:52 AM Roberto Sassu roberto.sassu@huawei.com wrote:
The first part of the preload code generation consists in generating the static variables to be used by the code itself: the links and maps to be pinned, and the skeleton. Generation of the preload variables and
methods
is enabled with the option -P added to 'bpftool gen skeleton'.
The existing variables maps_link and progs_links in bpf_preload_kern.c
have
been renamed respectively to dump_bpf_map_link and
dump_bpf_prog_link, to
match the name of the variables in the main structure of the light skeleton.
Signed-off-by: Roberto Sassu roberto.sassu@huawei.com
kernel/bpf/preload/bpf_preload_kern.c | 35 +- kernel/bpf/preload/iterators/Makefile | 2 +- .../bpf/preload/iterators/iterators.lskel.h | 378 +++++++++--------- .../bpf/bpftool/Documentation/bpftool-gen.rst | 5 + tools/bpf/bpftool/bash-completion/bpftool | 2 +- tools/bpf/bpftool/gen.c | 27 ++ tools/bpf/bpftool/main.c | 7 +- tools/bpf/bpftool/main.h | 1 + 8 files changed, 254 insertions(+), 203 deletions(-)
[...]
+__attribute__((unused)) static void +iterators_bpf__assert(struct iterators_bpf *s) +{ +#ifdef __cplusplus +#define _Static_assert static_assert +#endif +#ifdef __cplusplus +#undef _Static_assert +#endif +}
+static struct bpf_link *dump_bpf_map_link; +static struct bpf_link *dump_bpf_prog_link; +static struct iterators_bpf *skel;
I don't understand what is this and what for? You are making an assumption that light skeleton can be instantiated just once, why? And adding extra bpftool option to light skeleton codegen just to save a bit of typing at the place where light skeleton is actually instantiated and used doesn't seems like a right approach.
True, iterator_bpf is simple. Writing the preloading code for it is simple. But, what if you wanted to preload an LSM with 10 hooks or more?
Ok, regarding where the preloading code should be, I will try to move the generated code to the kernel module instead of the light skeleton.
Done. I moved everything from the light skeleton to the kernel module. The changes now are also well separated, and regeneration of the kernel module occurs only after all the generation code is added to bpftool.
I pushed a new branch:
https://github.com/robertosassu/linux/commits/bpf-preload-v2-devel-v2
Roberto
HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063 Managing Director: Li Peng, Zhong Ronghua
Generate free_objs_and_skel() (renamed from free_links_and_skel()) to decrease the reference count of pinned objects, and to destroy the skeleton.
Signed-off-by: Roberto Sassu roberto.sassu@huawei.com --- kernel/bpf/preload/bpf_preload_kern.c | 13 ++------- .../bpf/preload/iterators/iterators.lskel.h | 10 +++++++ tools/bpf/bpftool/gen.c | 28 +++++++++++++++++++ 3 files changed, 40 insertions(+), 11 deletions(-)
diff --git a/kernel/bpf/preload/bpf_preload_kern.c b/kernel/bpf/preload/bpf_preload_kern.c index 485589e03bd2..8b49beb2b2d6 100644 --- a/kernel/bpf/preload/bpf_preload_kern.c +++ b/kernel/bpf/preload/bpf_preload_kern.c @@ -5,15 +5,6 @@ #include <linux/bpf_preload.h> #include "iterators/iterators.lskel.h"
-static void free_links_and_skel(void) -{ - if (!IS_ERR_OR_NULL(dump_bpf_map_link)) - bpf_link_put(dump_bpf_map_link); - if (!IS_ERR_OR_NULL(dump_bpf_prog_link)) - bpf_link_put(dump_bpf_prog_link); - iterators_bpf__destroy(skel); -} - static int preload(struct dentry *parent) { int err; @@ -75,7 +66,7 @@ static int load_skel(void) skel->links.dump_bpf_prog_fd = 0; return 0; out: - free_links_and_skel(); + free_objs_and_skel(); return err; }
@@ -93,7 +84,7 @@ static int __init load(void) static void __exit fini(void) { bpf_preload_ops = NULL; - free_links_and_skel(); + free_objs_and_skel(); } late_initcall(load); module_exit(fini); diff --git a/kernel/bpf/preload/iterators/iterators.lskel.h b/kernel/bpf/preload/iterators/iterators.lskel.h index 9794acdfacf9..4afd983ad40e 100644 --- a/kernel/bpf/preload/iterators/iterators.lskel.h +++ b/kernel/bpf/preload/iterators/iterators.lskel.h @@ -438,4 +438,14 @@ static struct bpf_link *dump_bpf_map_link; static struct bpf_link *dump_bpf_prog_link; static struct iterators_bpf *skel;
+static void free_objs_and_skel(void) +{ + if (!IS_ERR_OR_NULL(dump_bpf_map_link)) + bpf_link_put(dump_bpf_map_link); + if (!IS_ERR_OR_NULL(dump_bpf_prog_link)) + bpf_link_put(dump_bpf_prog_link); + + iterators_bpf__destroy(skel); +} + #endif /* __ITERATORS_BPF_SKEL_H__ */ diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c index c62c4c65b631..e167aa092b7f 100644 --- a/tools/bpf/bpftool/gen.c +++ b/tools/bpf/bpftool/gen.c @@ -674,6 +674,33 @@ static void codegen_preload_vars(struct bpf_object *obj, const char *obj_name) ", obj_name); }
+static void codegen_preload_free(struct bpf_object *obj, const char *obj_name) +{ + struct bpf_program *prog; + + codegen("\ + \n\ + \n\ + static void free_objs_and_skel(void) \n\ + { \n\ + "); + + bpf_object__for_each_program(prog, obj) { + codegen("\ + \n\ + if (!IS_ERR_OR_NULL(%1$s_link)) \n\ + bpf_link_put(%1$s_link); \n\ + ", bpf_program__name(prog)); + } + + codegen("\ + \n\ + \n\ + %s__destroy(skel); \n\ + } \n\ + ", obj_name); +} + static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *header_guard) { DECLARE_LIBBPF_OPTS(gen_loader_opts, opts); @@ -824,6 +851,7 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
if (gen_preload_methods) { codegen_preload_vars(obj, obj_name); + codegen_preload_free(obj, obj_name); }
codegen("\
Generate preload(), to pin defined objects. For pinning, use the bpf_obj_do_pin_kernel() function, just exported.
Signed-off-by: Roberto Sassu roberto.sassu@huawei.com --- kernel/bpf/preload/bpf_preload_kern.c | 24 ------- .../bpf/preload/iterators/iterators.lskel.h | 26 ++++++++ tools/bpf/bpftool/gen.c | 64 +++++++++++++++++++ 3 files changed, 90 insertions(+), 24 deletions(-)
diff --git a/kernel/bpf/preload/bpf_preload_kern.c b/kernel/bpf/preload/bpf_preload_kern.c index 8b49beb2b2d6..0869c889255c 100644 --- a/kernel/bpf/preload/bpf_preload_kern.c +++ b/kernel/bpf/preload/bpf_preload_kern.c @@ -5,30 +5,6 @@ #include <linux/bpf_preload.h> #include "iterators/iterators.lskel.h"
-static int preload(struct dentry *parent) -{ - int err; - - bpf_link_inc(dump_bpf_map_link); - bpf_link_inc(dump_bpf_prog_link); - - err = bpf_obj_do_pin_kernel(parent, "maps.debug", dump_bpf_map_link, - BPF_TYPE_LINK); - if (err) - goto undo; - - err = bpf_obj_do_pin_kernel(parent, "progs.debug", dump_bpf_prog_link, - BPF_TYPE_LINK); - if (err) - goto undo; - - return 0; -undo: - bpf_link_put(dump_bpf_map_link); - bpf_link_put(dump_bpf_prog_link); - return err; -} - static struct bpf_preload_ops ops = { .preload = preload, .owner = THIS_MODULE, diff --git a/kernel/bpf/preload/iterators/iterators.lskel.h b/kernel/bpf/preload/iterators/iterators.lskel.h index 4afd983ad40e..75b2e94b7547 100644 --- a/kernel/bpf/preload/iterators/iterators.lskel.h +++ b/kernel/bpf/preload/iterators/iterators.lskel.h @@ -448,4 +448,30 @@ static void free_objs_and_skel(void) iterators_bpf__destroy(skel); }
+static int preload(struct dentry *parent) +{ + int err; + + bpf_link_inc(dump_bpf_map_link); + bpf_link_inc(dump_bpf_prog_link); + + err = bpf_obj_do_pin_kernel(parent, "maps.debug", + dump_bpf_map_link, + BPF_TYPE_LINK); + if (err) + goto undo; + + err = bpf_obj_do_pin_kernel(parent, "progs.debug", + dump_bpf_prog_link, + BPF_TYPE_LINK); + if (err) + goto undo; + + return 0; +undo: + bpf_link_put(dump_bpf_map_link); + bpf_link_put(dump_bpf_prog_link); + return err; +} + #endif /* __ITERATORS_BPF_SKEL_H__ */ diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c index e167aa092b7f..fa2c6022b80d 100644 --- a/tools/bpf/bpftool/gen.c +++ b/tools/bpf/bpftool/gen.c @@ -701,6 +701,69 @@ static void codegen_preload_free(struct bpf_object *obj, const char *obj_name) ", obj_name); }
+static void codegen_preload(struct bpf_object *obj, const char *obj_name) +{ + struct bpf_program *prog; + const char *link_name; + + codegen("\ + \n\ + \n\ + static int preload(struct dentry *parent) \n\ + { \n\ + int err; \n\ + \n\ + "); + + bpf_object__for_each_program(prog, obj) { + codegen("\ + \n\ + bpf_link_inc(%s_link); \n\ + ", bpf_program__name(prog)); + } + + bpf_object__for_each_program(prog, obj) { + link_name = bpf_program__name(prog); + /* These need to be hardcoded for compatibility reasons. */ + if (!strcmp(obj_name, "iterators_bpf")) { + if (!strcmp(link_name, "dump_bpf_map")) + link_name = "maps.debug"; + else if (!strcmp(link_name, "dump_bpf_prog")) + link_name = "progs.debug"; + } + + codegen("\ + \n\ + \n\ + err = bpf_obj_do_pin_kernel(parent, "%s", \n\ + %s_link, \n\ + BPF_TYPE_LINK); \n\ + if (err) \n\ + goto undo; \n\ + ", link_name, bpf_program__name(prog)); + } + + codegen("\ + \n\ + \n\ + return 0; \n\ + undo: \n\ + "); + + bpf_object__for_each_program(prog, obj) { + codegen("\ + \n\ + bpf_link_put(%s_link); \n\ + ", bpf_program__name(prog)); + } + + codegen("\ + \n\ + return err; \n\ + } \n\ + "); +} + static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *header_guard) { DECLARE_LIBBPF_OPTS(gen_loader_opts, opts); @@ -852,6 +915,7 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h if (gen_preload_methods) { codegen_preload_vars(obj, obj_name); codegen_preload_free(obj, obj_name); + codegen_preload(obj, obj_name); }
codegen("\
Generate load_skel() to load and attach the eBPF program, and to retrieve the objects to be pinned.
Signed-off-by: Roberto Sassu roberto.sassu@huawei.com --- kernel/bpf/preload/bpf_preload_kern.c | 36 ----------- .../bpf/preload/iterators/iterators.lskel.h | 42 ++++++++++++ tools/bpf/bpftool/gen.c | 64 +++++++++++++++++++ 3 files changed, 106 insertions(+), 36 deletions(-)
diff --git a/kernel/bpf/preload/bpf_preload_kern.c b/kernel/bpf/preload/bpf_preload_kern.c index 0869c889255c..35e9abd1a668 100644 --- a/kernel/bpf/preload/bpf_preload_kern.c +++ b/kernel/bpf/preload/bpf_preload_kern.c @@ -10,42 +10,6 @@ static struct bpf_preload_ops ops = { .owner = THIS_MODULE, };
-static int load_skel(void) -{ - int err; - - skel = iterators_bpf__open(); - if (!skel) - return -ENOMEM; - err = iterators_bpf__load(skel); - if (err) - goto out; - err = iterators_bpf__attach(skel); - if (err) - goto out; - dump_bpf_map_link = bpf_link_get_from_fd(skel->links.dump_bpf_map_fd); - if (IS_ERR(dump_bpf_map_link)) { - err = PTR_ERR(dump_bpf_map_link); - goto out; - } - dump_bpf_prog_link = bpf_link_get_from_fd(skel->links.dump_bpf_prog_fd); - if (IS_ERR(dump_bpf_prog_link)) { - err = PTR_ERR(dump_bpf_prog_link); - goto out; - } - /* Avoid taking over stdin/stdout/stderr of init process. Zeroing out - * makes skel_closenz() a no-op later in iterators_bpf__destroy(). - */ - close_fd(skel->links.dump_bpf_map_fd); - skel->links.dump_bpf_map_fd = 0; - close_fd(skel->links.dump_bpf_prog_fd); - skel->links.dump_bpf_prog_fd = 0; - return 0; -out: - free_objs_and_skel(); - return err; -} - static int __init load(void) { int err; diff --git a/kernel/bpf/preload/iterators/iterators.lskel.h b/kernel/bpf/preload/iterators/iterators.lskel.h index 75b2e94b7547..6faf3708be01 100644 --- a/kernel/bpf/preload/iterators/iterators.lskel.h +++ b/kernel/bpf/preload/iterators/iterators.lskel.h @@ -474,4 +474,46 @@ static int preload(struct dentry *parent) return err; }
+static int load_skel(void) +{ + int err; + + skel = iterators_bpf__open(); + if (!skel) + return -ENOMEM; + + err = iterators_bpf__load(skel); + if (err) + goto out; + + err = iterators_bpf__attach(skel); + if (err) + goto out; + + dump_bpf_map_link = bpf_link_get_from_fd(skel->links.dump_bpf_map_fd); + if (IS_ERR(dump_bpf_map_link)) { + err = PTR_ERR(dump_bpf_map_link); + goto out; + } + + dump_bpf_prog_link = bpf_link_get_from_fd(skel->links.dump_bpf_prog_fd); + if (IS_ERR(dump_bpf_prog_link)) { + err = PTR_ERR(dump_bpf_prog_link); + goto out; + } + + /* Avoid taking over stdin/stdout/stderr of init process. Zeroing out + * makes skel_closenz() a no-op later in iterators_bpf__destroy(). + */ + close_fd(skel->links.dump_bpf_map_fd); + skel->links.dump_bpf_map_fd = 0; + close_fd(skel->links.dump_bpf_prog_fd); + skel->links.dump_bpf_prog_fd = 0; + + return 0; +out: + free_objs_and_skel(); + return err; +} + #endif /* __ITERATORS_BPF_SKEL_H__ */ diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c index fa2c6022b80d..ad948f1c90b5 100644 --- a/tools/bpf/bpftool/gen.c +++ b/tools/bpf/bpftool/gen.c @@ -764,6 +764,69 @@ static void codegen_preload(struct bpf_object *obj, const char *obj_name) "); }
+static void codegen_preload_load(struct bpf_object *obj, const char *obj_name) +{ + struct bpf_program *prog; + + codegen("\ + \n\ + \n\ + static int load_skel(void) \n\ + { \n\ + int err; \n\ + \n\ + skel = %1$s__open(); \n\ + if (!skel) \n\ + return -ENOMEM; \n\ + \n\ + err = %1$s__load(skel); \n\ + if (err) \n\ + goto out; \n\ + \n\ + err = %1$s__attach(skel); \n\ + if (err) \n\ + goto out; \n\ + ", obj_name); + + bpf_object__for_each_program(prog, obj) { + codegen("\ + \n\ + \n\ + %1$s_link = bpf_link_get_from_fd(skel->links.%1$s_fd); \n\ + if (IS_ERR(%1$s_link)) { \n\ + err = PTR_ERR(%1$s_link); \n\ + goto out; \n\ + } \n\ + ", bpf_program__name(prog)); + } + + codegen("\ + \n\ + \n\ + /* Avoid taking over stdin/stdout/stderr of init process. Zeroing out \n\ + * makes skel_closenz() a no-op later in iterators_bpf__destroy(). \n\ + */ \n\ + "); + + bpf_object__for_each_program(prog, obj) { + codegen("\ + \n\ + close_fd(skel->links.%1$s_fd); \n\ + skel->links.%1$s_fd = 0; \n\ + ", bpf_program__name(prog)); + } + + codegen("\ + \n\ + \n\ + return 0; \n\ + out: \n\ + free_objs_and_skel(); \n\ + return err; \n\ + } \n\ + "); +} + static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *header_guard) { DECLARE_LIBBPF_OPTS(gen_loader_opts, opts); @@ -916,6 +979,7 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h codegen_preload_vars(obj, obj_name); codegen_preload_free(obj, obj_name); codegen_preload(obj, obj_name); + codegen_preload_load(obj, obj_name); }
codegen("\
Take the non-internal maps from the skeleton, and generate the code for each of them (static variable declaration, additional code in free_objs_and_skel(), preload() and load_skel()).
Signed-off-by: Roberto Sassu roberto.sassu@huawei.com --- tools/bpf/bpftool/gen.c | 97 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+)
diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c index ad948f1c90b5..28b1fe718248 100644 --- a/tools/bpf/bpftool/gen.c +++ b/tools/bpf/bpftool/gen.c @@ -655,6 +655,8 @@ static void codegen_destroy(struct bpf_object *obj, const char *obj_name) static void codegen_preload_vars(struct bpf_object *obj, const char *obj_name) { struct bpf_program *prog; + struct bpf_map *map; + char ident[256];
codegen("\ \n\ @@ -668,6 +670,19 @@ static void codegen_preload_vars(struct bpf_object *obj, const char *obj_name) ", bpf_program__name(prog)); }
+ bpf_object__for_each_map(map, obj) { + if (!get_map_ident(map, ident, sizeof(ident))) + continue; + + if (bpf_map__is_internal(map)) + continue; + + codegen("\ + \n\ + static struct bpf_map *%s_map; \n\ + ", ident); + } + codegen("\ \n\ static struct %s *skel; \n\ @@ -677,6 +692,8 @@ static void codegen_preload_vars(struct bpf_object *obj, const char *obj_name) static void codegen_preload_free(struct bpf_object *obj, const char *obj_name) { struct bpf_program *prog; + struct bpf_map *map; + char ident[256];
codegen("\ \n\ @@ -693,6 +710,20 @@ static void codegen_preload_free(struct bpf_object *obj, const char *obj_name) ", bpf_program__name(prog)); }
+ bpf_object__for_each_map(map, obj) { + if (!get_map_ident(map, ident, sizeof(ident))) + continue; + + if (bpf_map__is_internal(map)) + continue; + + codegen("\ + \n\ + if (!IS_ERR_OR_NULL(%1$s_map)) \n\ + bpf_map_put(%1$s_map); \n\ + ", ident); + } + codegen("\ \n\ \n\ @@ -705,6 +736,8 @@ static void codegen_preload(struct bpf_object *obj, const char *obj_name) { struct bpf_program *prog; const char *link_name; + struct bpf_map *map; + char ident[256];
codegen("\ \n\ @@ -722,6 +755,19 @@ static void codegen_preload(struct bpf_object *obj, const char *obj_name) ", bpf_program__name(prog)); }
+ bpf_object__for_each_map(map, obj) { + if (!get_map_ident(map, ident, sizeof(ident))) + continue; + + if (bpf_map__is_internal(map)) + continue; + + codegen("\ + \n\ + bpf_map_inc(%s_map); \n\ + ", ident); + } + bpf_object__for_each_program(prog, obj) { link_name = bpf_program__name(prog); /* These need to be hardcoded for compatibility reasons. */ @@ -743,6 +789,24 @@ static void codegen_preload(struct bpf_object *obj, const char *obj_name) ", link_name, bpf_program__name(prog)); }
+ bpf_object__for_each_map(map, obj) { + if (!get_map_ident(map, ident, sizeof(ident))) + continue; + + if (bpf_map__is_internal(map)) + continue; + + codegen("\ + \n\ + \n\ + err = bpf_obj_do_pin_kernel(parent, "%1$s", \n\ + %1$s_map, \n\ + BPF_TYPE_MAP); \n\ + if (err) \n\ + goto undo; \n\ + ", ident); + } + codegen("\ \n\ \n\ @@ -757,6 +821,19 @@ static void codegen_preload(struct bpf_object *obj, const char *obj_name) ", bpf_program__name(prog)); }
+ bpf_object__for_each_map(map, obj) { + if (!get_map_ident(map, ident, sizeof(ident))) + continue; + + if (bpf_map__is_internal(map)) + continue; + + codegen("\ + \n\ + bpf_map_put(%s_map); \n\ + ", ident); + } + codegen("\ \n\ return err; \n\ @@ -767,6 +844,8 @@ static void codegen_preload(struct bpf_object *obj, const char *obj_name) static void codegen_preload_load(struct bpf_object *obj, const char *obj_name) { struct bpf_program *prog; + struct bpf_map *map; + char ident[256];
codegen("\ \n\ @@ -800,6 +879,24 @@ static void codegen_preload_load(struct bpf_object *obj, const char *obj_name) ", bpf_program__name(prog)); }
+ bpf_object__for_each_map(map, obj) { + if (!get_map_ident(map, ident, sizeof(ident))) + continue; + + if (bpf_map__is_internal(map)) + continue; + + codegen("\ + \n\ + \n\ + %1$s_map = bpf_map_get(skel->maps.%1$s.map_fd); \n\ + if (IS_ERR(%1$s_map)) { \n\ + err = PTR_ERR(%1$s_map); \n\ + goto out; \n\ + } \n\ + ", ident); + } + codegen("\ \n\ \n\
Generate a bpf_preload_ops structure, to specify the kernel module and the preload method.
Signed-off-by: Roberto Sassu roberto.sassu@huawei.com --- kernel/bpf/preload/bpf_preload_kern.c | 5 ----- kernel/bpf/preload/iterators/iterators.lskel.h | 5 +++++ tools/bpf/bpftool/gen.c | 13 +++++++++++++ 3 files changed, 18 insertions(+), 5 deletions(-)
diff --git a/kernel/bpf/preload/bpf_preload_kern.c b/kernel/bpf/preload/bpf_preload_kern.c index 35e9abd1a668..3839af367200 100644 --- a/kernel/bpf/preload/bpf_preload_kern.c +++ b/kernel/bpf/preload/bpf_preload_kern.c @@ -5,11 +5,6 @@ #include <linux/bpf_preload.h> #include "iterators/iterators.lskel.h"
-static struct bpf_preload_ops ops = { - .preload = preload, - .owner = THIS_MODULE, -}; - static int __init load(void) { int err; diff --git a/kernel/bpf/preload/iterators/iterators.lskel.h b/kernel/bpf/preload/iterators/iterators.lskel.h index 6faf3708be01..7595fc283a65 100644 --- a/kernel/bpf/preload/iterators/iterators.lskel.h +++ b/kernel/bpf/preload/iterators/iterators.lskel.h @@ -474,6 +474,11 @@ static int preload(struct dentry *parent) return err; }
+static struct bpf_preload_ops ops = { + .preload = preload, + .owner = THIS_MODULE, +}; + static int load_skel(void) { int err; diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c index 28b1fe718248..5593cbee1846 100644 --- a/tools/bpf/bpftool/gen.c +++ b/tools/bpf/bpftool/gen.c @@ -841,6 +841,18 @@ static void codegen_preload(struct bpf_object *obj, const char *obj_name) "); }
+static void codegen_preload_ops(void) +{ + codegen("\ + \n\ + \n\ + static struct bpf_preload_ops ops = { \n\ + .preload = preload, \n\ + .owner = THIS_MODULE, \n\ + }; \n\ + "); +} + static void codegen_preload_load(struct bpf_object *obj, const char *obj_name) { struct bpf_program *prog; @@ -1076,6 +1088,7 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h codegen_preload_vars(obj, obj_name); codegen_preload_free(obj, obj_name); codegen_preload(obj, obj_name); + codegen_preload_ops(); codegen_preload_load(obj, obj_name); }
In preparation to support preloading multiple eBPF programs, define a linked list of bpf_preload_ops_item structures. The new structure contains the object name from the eBPF program to preload (except for iterators_bpf whose kernel module name is bpf_preload, the object name and the kernel module name should match).
The new structure also contains a bpf_preload_ops structure declared in the light skeleton, with the preload method of the eBPF program.
The list of eBPF programs that can be preloaded can be specified in a subsequent patch from the kernel configuration or with the new option bpf_preload_list= in the kernel command line.
For now, bpf_preload is always preloaded, as it still relies on the old registration method consisting in setting the bpf_preload_ops global variable. That will change when bpf_preload will switch to the new registration method based on the linked list.
Signed-off-by: Roberto Sassu roberto.sassu@huawei.com --- kernel/bpf/inode.c | 89 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 73 insertions(+), 16 deletions(-)
diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index bb8762abbf3d..0a6e83d32360 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -685,35 +685,91 @@ static int bpf_parse_param(struct fs_context *fc, struct fs_parameter *param) struct bpf_preload_ops *bpf_preload_ops; EXPORT_SYMBOL_GPL(bpf_preload_ops);
-static bool bpf_preload_mod_get(void) +struct bpf_preload_ops_item { + struct list_head list; + struct bpf_preload_ops *ops; + char *obj_name; +}; + +static LIST_HEAD(preload_list); +static DEFINE_MUTEX(bpf_preload_lock); + +static bool bpf_preload_mod_get(const char *obj_name, + struct bpf_preload_ops **ops) { - /* If bpf_preload.ko wasn't loaded earlier then load it now. - * When bpf_preload is built into vmlinux the module's __init + /* If the kernel preload module wasn't loaded earlier then load it now. + * When the preload code is built into vmlinux the module's __init * function will populate it. */ - if (!bpf_preload_ops) { - request_module("bpf_preload"); - if (!bpf_preload_ops) + if (!*ops) { + mutex_unlock(&bpf_preload_lock); + request_module(obj_name); + mutex_lock(&bpf_preload_lock); + if (!*ops) return false; } /* And grab the reference, so the module doesn't disappear while the * kernel is interacting with the kernel module and its UMD. */ - if (!try_module_get(bpf_preload_ops->owner)) { + if (!try_module_get((*ops)->owner)) { pr_err("bpf_preload module get failed.\n"); return false; } return true; }
-static void bpf_preload_mod_put(void) +static void bpf_preload_mod_put(struct bpf_preload_ops *ops) { - if (bpf_preload_ops) - /* now user can "rmmod bpf_preload" if necessary */ - module_put(bpf_preload_ops->owner); + if (ops) + /* now user can "rmmod <kernel module>" if necessary */ + module_put(ops->owner); }
-static DEFINE_MUTEX(bpf_preload_lock); +static bool bpf_preload_list_mod_get(void) +{ + struct bpf_preload_ops_item *cur; + bool ret = false; + + ret |= bpf_preload_mod_get("bpf_preload", &bpf_preload_ops); + + list_for_each_entry(cur, &preload_list, list) + ret |= bpf_preload_mod_get(cur->obj_name, &cur->ops); + + return ret; +} + +static int bpf_preload_list(struct dentry *parent) +{ + struct bpf_preload_ops_item *cur; + int err; + + if (bpf_preload_ops) { + err = bpf_preload_ops->preload(parent); + if (err) + return err; + } + + list_for_each_entry(cur, &preload_list, list) { + if (!cur->ops) + continue; + + err = cur->ops->preload(parent); + if (err) + return err; + } + + return 0; +} + +static void bpf_preload_list_mod_put(void) +{ + struct bpf_preload_ops_item *cur; + + list_for_each_entry(cur, &preload_list, list) + bpf_preload_mod_put(cur->ops); + + bpf_preload_mod_put(bpf_preload_ops); +}
static int populate_bpffs(struct dentry *parent) { @@ -724,12 +780,13 @@ static int populate_bpffs(struct dentry *parent) */ mutex_lock(&bpf_preload_lock);
- /* if bpf_preload.ko wasn't built into vmlinux then load it */ - if (!bpf_preload_mod_get()) + /* if kernel preload mods weren't built into vmlinux then load them */ + if (!bpf_preload_list_mod_get()) goto out;
- err = bpf_preload_ops->preload(parent); - bpf_preload_mod_put(); + err = bpf_preload_list(parent); + bpf_preload_list_mod_put(); + out: mutex_unlock(&bpf_preload_lock); return err;
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@huawei.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; }
With support for preloading multiple eBPF programs, any map, link or prog will appear in the bpf filesystem. To identify which eBPF program a pinned object belongs to, create a subdir for each eBPF program preloaded and place the pinned object in the new subdir.
Keep the pinned objects of iterators_bpf in the root directory of bpffs, for compatibility reasons.
Signed-off-by: Roberto Sassu roberto.sassu@huawei.com --- kernel/bpf/inode.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-)
diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index 440ea517cc29..619cdef0ba54 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -740,9 +740,30 @@ static bool bpf_preload_list_mod_get(void) return ret; }
+static struct dentry *create_subdir(struct dentry *parent, const char *name) +{ + struct dentry *dentry; + int err; + + inode_lock(parent->d_inode); + dentry = lookup_one_len(name, parent, strlen(name)); + if (IS_ERR(dentry)) + goto out; + + err = vfs_mkdir(&init_user_ns, parent->d_inode, dentry, 0755); + if (err) { + dput(dentry); + dentry = ERR_PTR(err); + } +out: + inode_unlock(parent->d_inode); + return dentry; +} + static int bpf_preload_list(struct dentry *parent) { struct bpf_preload_ops_item *cur; + struct dentry *cur_parent; int err;
if (bpf_preload_ops) { @@ -755,7 +776,19 @@ static int bpf_preload_list(struct dentry *parent) if (!cur->ops) continue;
- err = cur->ops->preload(parent); + cur_parent = parent; + + if (strcmp(cur->obj_name, "bpf_preload")) { + cur_parent = create_subdir(parent, cur->obj_name); + if (IS_ERR(cur_parent)) + cur_parent = parent; + } + + err = cur->ops->preload(cur_parent); + + if (cur_parent != parent) + dput(cur_parent); + if (err) return err; }
Modify the automatic generator of the light skeleton by adding three calls to bpf_preload_set_ops() for registering and unregistering a preload method, two in load_skel() (set and unset if there is an error) and one in free_objs_and_skel().
Regenerate the light skeleton of the already preloaded eBPF program iterators_bpf, which will now use the new registration method, and directly call load_skel() and free_objs_and_skel() in the init and fini module entrypoints.
Finally, allow users to specify a customized list of eBPF programs to preload with the CONFIG_BPF_PRELOAD_LIST option in the kernel configuration, at build time, or with new kernel option bpf_preload_list=, at run-time.
By default, set CONFIG_BPF_PRELOAD_LIST to 'bpf_preload', so that the current preloading behavior is kept unchanged.
Signed-off-by: Roberto Sassu roberto.sassu@huawei.com --- .../admin-guide/kernel-parameters.txt | 8 ++++++ kernel/bpf/inode.c | 16 ++++++++++-- kernel/bpf/preload/Kconfig | 25 +++++++++++++------ kernel/bpf/preload/bpf_preload_kern.c | 20 ++------------- .../bpf/preload/iterators/iterators.lskel.h | 9 +++++-- tools/bpf/bpftool/gen.c | 15 ++++++++--- 6 files changed, 60 insertions(+), 33 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 9927564db88e..732d83764e6e 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -482,6 +482,14 @@ bgrt_disable [ACPI][X86] Disable BGRT to avoid flickering OEM logo.
+ bpf_preload_list= [BPF] + Specify a list of eBPF programs to preload. + Format: obj_name1,obj_name2,... + Default: bpf_preload + + Specify the list of eBPF programs to preload when the + bpf filesystem is mounted. + bttv.card= [HW,V4L] bttv (bt848 + bt878 based grabber cards) bttv.radio= Most important insmod options are available as kernel args too. diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index 619cdef0ba54..c1941c65ce95 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -22,7 +22,14 @@ #include <linux/bpf_trace.h> #include <linux/bpf_preload.h>
-static char *bpf_preload_list_str; +static char *bpf_preload_list_str = CONFIG_BPF_PRELOAD_LIST; + +static int __init bpf_preload_list_setup(char *str) +{ + bpf_preload_list_str = str; + return 1; +} +__setup("bpf_preload_list=", bpf_preload_list_setup);
static void *bpf_any_get(void *raw, enum bpf_type type) { @@ -732,7 +739,12 @@ static bool bpf_preload_list_mod_get(void) struct bpf_preload_ops_item *cur; bool ret = false;
- ret |= bpf_preload_mod_get("bpf_preload", &bpf_preload_ops); + /* + * Keep the legacy registration method, but do not attempt to load + * bpf_preload.ko, as it switched to the new registration method. + */ + if (bpf_preload_ops) + ret |= bpf_preload_mod_get("bpf_preload", &bpf_preload_ops);
list_for_each_entry(cur, &preload_list, list) ret |= bpf_preload_mod_get(cur->obj_name, &cur->ops); diff --git a/kernel/bpf/preload/Kconfig b/kernel/bpf/preload/Kconfig index c9d45c9d6918..f878e537b0ff 100644 --- a/kernel/bpf/preload/Kconfig +++ b/kernel/bpf/preload/Kconfig @@ -4,7 +4,7 @@ config USERMODE_DRIVER default n
menuconfig BPF_PRELOAD - bool "Preload BPF file system with kernel specific program and map iterators" + bool "Preload eBPF programs" depends on BPF depends on BPF_SYSCALL # The dependency on !COMPILE_TEST prevents it from being enabled @@ -12,15 +12,26 @@ menuconfig BPF_PRELOAD depends on !COMPILE_TEST select USERMODE_DRIVER help - This builds kernel module with several embedded BPF programs that are - pinned into BPF FS mount point as human readable files that are - useful in debugging and introspection of BPF programs and maps. + This enables preloading eBPF programs chosen from the kernel + configuration or from the kernel option bpf_preload_list=.
if BPF_PRELOAD config BPF_PRELOAD_UMD - tristate "bpf_preload kernel module" + tristate "Preload BPF file system with kernel specific program and map iterators" default m help - This builds bpf_preload kernel module with embedded BPF programs for - introspection in bpffs. + This builds bpf_preload kernel module with several embedded BPF + programs that are pinned into BPF FS mount point as human readable + files that are useful in debugging and introspection of BPF programs + and maps. + +config BPF_PRELOAD_LIST + string "Ordered list of eBPF programs to preload" + default "bpf_preload" + help + A comma-separated list of eBPF programs to preload. Any eBPF program + left off this list will be ignored. This can be controlled at boot + with the "bpf_preload_list=" parameter. + + If unsure, leave this as the default. endif diff --git a/kernel/bpf/preload/bpf_preload_kern.c b/kernel/bpf/preload/bpf_preload_kern.c index 3839af367200..c6d97872225b 100644 --- a/kernel/bpf/preload/bpf_preload_kern.c +++ b/kernel/bpf/preload/bpf_preload_kern.c @@ -5,22 +5,6 @@ #include <linux/bpf_preload.h> #include "iterators/iterators.lskel.h"
-static int __init load(void) -{ - int err; - - err = load_skel(); - if (err) - return err; - bpf_preload_ops = &ops; - return err; -} - -static void __exit fini(void) -{ - bpf_preload_ops = NULL; - free_objs_and_skel(); -} -late_initcall(load); -module_exit(fini); +late_initcall(load_skel); +module_exit(free_objs_and_skel); MODULE_LICENSE("GPL"); diff --git a/kernel/bpf/preload/iterators/iterators.lskel.h b/kernel/bpf/preload/iterators/iterators.lskel.h index 7595fc283a65..5e999564cc7a 100644 --- a/kernel/bpf/preload/iterators/iterators.lskel.h +++ b/kernel/bpf/preload/iterators/iterators.lskel.h @@ -440,6 +440,8 @@ static struct iterators_bpf *skel;
static void free_objs_and_skel(void) { + bpf_preload_set_ops("bpf_preload", THIS_MODULE, NULL); + if (!IS_ERR_OR_NULL(dump_bpf_map_link)) bpf_link_put(dump_bpf_map_link); if (!IS_ERR_OR_NULL(dump_bpf_prog_link)) @@ -481,11 +483,14 @@ static struct bpf_preload_ops ops = {
static int load_skel(void) { - int err; + int err = -ENOMEM; + + if (!bpf_preload_set_ops("bpf_preload", THIS_MODULE, &ops)) + return 0;
skel = iterators_bpf__open(); if (!skel) - return -ENOMEM; + goto out;
err = iterators_bpf__load(skel); if (err) diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c index 5593cbee1846..af939183f57a 100644 --- a/tools/bpf/bpftool/gen.c +++ b/tools/bpf/bpftool/gen.c @@ -700,7 +700,10 @@ static void codegen_preload_free(struct bpf_object *obj, const char *obj_name) \n\ static void free_objs_and_skel(void) \n\ { \n\ - "); + bpf_preload_set_ops("%s", THIS_MODULE, NULL); \n\ + \n\ + ", !strcmp(obj_name, "iterators_bpf") ? + "bpf_preload" : obj_name);
bpf_object__for_each_program(prog, obj) { codegen("\ @@ -864,11 +867,14 @@ static void codegen_preload_load(struct bpf_object *obj, const char *obj_name) \n\ static int load_skel(void) \n\ { \n\ - int err; \n\ + int err = -ENOMEM; \n\ + \n\ + if (!bpf_preload_set_ops("%2$s", THIS_MODULE, &ops)) \n\ + return 0; \n\ \n\ skel = %1$s__open(); \n\ if (!skel) \n\ - return -ENOMEM; \n\ + goto out; \n\ \n\ err = %1$s__load(skel); \n\ if (err) \n\ @@ -877,7 +883,8 @@ static void codegen_preload_load(struct bpf_object *obj, const char *obj_name) err = %1$s__attach(skel); \n\ if (err) \n\ goto out; \n\ - ", obj_name); + ", obj_name, !strcmp(obj_name, "iterators_bpf") ? + "bpf_preload" : obj_name);
bpf_object__for_each_program(prog, obj) { codegen("\
Hi Roberto,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on bpf-next/master] [also build test ERROR on linus/master next-20220328] [cannot apply to bpf/master v5.17] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch]
url: https://github.com/intel-lab-lkp/linux/commits/Roberto-Sassu/bpf-Secure-and-... base: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master config: i386-randconfig-c001 (https://download.01.org/0day-ci/archive/20220329/202203291042.8dll5BFm-lkp@i...) compiler: gcc-9 (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0 reproduce (this is a W=1 build): # https://github.com/intel-lab-lkp/linux/commit/2e0e81b0296abc384efb2a73520ce0... git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Roberto-Sassu/bpf-Secure-and-authenticated-preloading-of-eBPF-programs/20220329-015829 git checkout 2e0e81b0296abc384efb2a73520ce03c2a5344ea # save the config file to linux build tree mkdir build_dir make W=1 O=build_dir ARCH=i386 SHELL=/bin/bash
If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot lkp@intel.com
All errors (new ones prefixed by >>):
kernel/bpf/inode.c:25:37: error: 'CONFIG_BPF_PRELOAD_LIST' undeclared here (not in a function)
25 | static char *bpf_preload_list_str = CONFIG_BPF_PRELOAD_LIST; | ^~~~~~~~~~~~~~~~~~~~~~~
vim +/CONFIG_BPF_PRELOAD_LIST +25 kernel/bpf/inode.c
24
25 static char *bpf_preload_list_str = CONFIG_BPF_PRELOAD_LIST;
26
Hi Roberto,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on bpf-next/master] [also build test ERROR on bpf/master linus/master next-20220328] [cannot apply to v5.17] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch]
url: https://github.com/intel-lab-lkp/linux/commits/Roberto-Sassu/bpf-Secure-and-... base: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master config: arm64-randconfig-r026-20220328 (https://download.01.org/0day-ci/archive/20220329/202203291125.8NpccWn1-lkp@i...) compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 0f6d9501cf49ce02937099350d08f20c4af86f3d) reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # install arm64 cross compiling tool for clang build # apt-get install binutils-aarch64-linux-gnu # https://github.com/intel-lab-lkp/linux/commit/2e0e81b0296abc384efb2a73520ce0... git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Roberto-Sassu/bpf-Secure-and-authenticated-preloading-of-eBPF-programs/20220329-015829 git checkout 2e0e81b0296abc384efb2a73520ce03c2a5344ea # save the config file to linux build tree mkdir build_dir COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm64 SHELL=/bin/bash
If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot lkp@intel.com
All errors (new ones prefixed by >>):
kernel/bpf/inode.c:25:37: error: use of undeclared identifier 'CONFIG_BPF_PRELOAD_LIST'
static char *bpf_preload_list_str = CONFIG_BPF_PRELOAD_LIST; ^ 1 error generated.
vim +/CONFIG_BPF_PRELOAD_LIST +25 kernel/bpf/inode.c
24
25 static char *bpf_preload_list_str = CONFIG_BPF_PRELOAD_LIST;
26
Since every function is automatically generated and placed to the light skeleton, the kernel module for preloading an eBPF program is very small and with a well-defined structure. The only variable part is the path of the light skeleton.
Introduce the new 'subcommand' module of the 'gen' bpftool command, which takes the path of the light skeleton to be included in the #include directive and generates the code of the kernel module to preload the eBPF program.
Signed-off-by: Roberto Sassu roberto.sassu@huawei.com --- kernel/bpf/preload/bpf_preload_kern.c | 1 + kernel/bpf/preload/iterators/Makefile | 7 +++-- .../bpf/bpftool/Documentation/bpftool-gen.rst | 8 +++++ tools/bpf/bpftool/bash-completion/bpftool | 4 +++ tools/bpf/bpftool/gen.c | 31 +++++++++++++++++++ 5 files changed, 49 insertions(+), 2 deletions(-)
diff --git a/kernel/bpf/preload/bpf_preload_kern.c b/kernel/bpf/preload/bpf_preload_kern.c index c6d97872225b..048bca3ba499 100644 --- a/kernel/bpf/preload/bpf_preload_kern.c +++ b/kernel/bpf/preload/bpf_preload_kern.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 +/* THIS FILE IS AUTOGENERATED! */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/init.h> #include <linux/module.h> diff --git a/kernel/bpf/preload/iterators/Makefile b/kernel/bpf/preload/iterators/Makefile index d36a822d3e16..9dcad1c5c44b 100644 --- a/kernel/bpf/preload/iterators/Makefile +++ b/kernel/bpf/preload/iterators/Makefile @@ -35,17 +35,20 @@ endif
.PHONY: all clean
-all: iterators.lskel.h +all: iterators.lskel.h bpf_preload_kern.c
clean: $(call msg,CLEAN) $(Q)rm -rf $(OUTPUT) iterators
+bpf_preload_kern.c: iterators.lskel.h $(BPFTOOL) + $(call msg,GEN-PRELOAD,$@) + $(Q)$(BPFTOOL) gen module iterators/iterators.lskel.h $< > ../$@ + iterators.lskel.h: $(OUTPUT)/iterators.bpf.o | $(BPFTOOL) $(call msg,GEN-SKEL,$@) $(Q)$(BPFTOOL) gen skeleton -L -P $< > $@
- $(OUTPUT)/iterators.bpf.o: iterators.bpf.c $(BPFOBJ) | $(OUTPUT) $(call msg,BPF,$@) $(Q)$(CLANG) -g -O2 -target bpf $(INCLUDES) \ diff --git a/tools/bpf/bpftool/Documentation/bpftool-gen.rst b/tools/bpf/bpftool/Documentation/bpftool-gen.rst index 74bbefa28212..6d29d2b1e4e2 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-gen.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-gen.rst @@ -27,6 +27,7 @@ GEN COMMANDS | **bpftool** **gen skeleton** *FILE* [**name** *OBJECT_NAME*] | **bpftool** **gen subskeleton** *FILE* [**name** *OBJECT_NAME*] | **bpftool** **gen min_core_btf** *INPUT* *OUTPUT* *OBJECT* [*OBJECT*...] +| **bpftool** **gen module** *FILE* | **bpftool** **gen help**
DESCRIPTION @@ -195,6 +196,13 @@ DESCRIPTION
Check examples bellow for more information how to use it.
+ **bpftool** **gen module** *FILE* + Generate the code of a kernel module including the light + skeleton of an eBPF program to preload. The only variable part + is the path of the light skeleton. All kernel modules call + load_skel() and free_objs_and_skel() respectively in the init + and fini module entrypoints. + **bpftool gen help** Print short help message.
diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool index 6e433e86fb26..82e8716fd3ad 100644 --- a/tools/bpf/bpftool/bash-completion/bpftool +++ b/tools/bpf/bpftool/bash-completion/bpftool @@ -1019,6 +1019,10 @@ _bpftool() _filedir return 0 ;; + module) + _filedir + return 0 + ;; *) [[ $prev == $object ]] && \ COMPREPLY=( $( compgen -W 'object skeleton subskeleton help min_core_btf' -- "$cur" ) ) diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c index af939183f57a..77ab78884285 100644 --- a/tools/bpf/bpftool/gen.c +++ b/tools/bpf/bpftool/gen.c @@ -1898,6 +1898,35 @@ static int do_object(int argc, char **argv) return err; }
+static int do_module(int argc, char **argv) +{ + const char *skeleton_file; + + if (!REQ_ARGS(1)) { + usage(); + return -1; + } + + skeleton_file = GET_ARG(); + + codegen("\ + \n\ + // SPDX-License-Identifier: GPL-2.0 \n\ + /* THIS FILE IS AUTOGENERATED! */ \n\ + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt \n\ + #include <linux/init.h> \n\ + #include <linux/module.h> \n\ + #include <linux/bpf_preload.h> \n\ + #include "%s" \n\ + \n\ + late_initcall(load_skel); \n\ + module_exit(free_objs_and_skel); \n\ + MODULE_LICENSE("GPL"); \n\ + ", skeleton_file); + + return 0; +} + static int do_help(int argc, char **argv) { if (json_output) { @@ -1910,6 +1939,7 @@ static int do_help(int argc, char **argv) " %1$s %2$s skeleton FILE [name OBJECT_NAME]\n" " %1$s %2$s subskeleton FILE [name OBJECT_NAME]\n" " %1$s %2$s min_core_btf INPUT OUTPUT OBJECT [OBJECT...]\n" + " %1$s %2$s module SKELETON_FILE\n" " %1$s %2$s help\n" "\n" " " HELP_SPEC_OPTIONS " |\n" @@ -2508,6 +2538,7 @@ static const struct cmd cmds[] = { { "skeleton", do_skeleton }, { "subskeleton", do_subskeleton }, { "min_core_btf", do_min_core_btf}, + { "module", do_module}, { "help", do_help }, { 0 } };
One of the differences between traditional LSMs in the security subsystem and LSMs implemented as eBPF programs is that for the latter category it cannot be guaranteed that they cannot be stopped.
If a pinned program is unpinned, its execution will be stopped and will not enforce anymore its policy. For traditional LSMs this problem does not arise as, once they are invoked by the kernel, only the LSMs themselves decide whether or not they could be stopped.
Solve this problem by mounting the bpf filesystem from the kernel, so that an object cannot be unpinned (a kernel mount is not accessible to user space). This will ensure that the LSM will run until the very end of the kernel lifecycle.
Delay the kernel mount until the security subsystem (e.g. IMA) is fully initialized (e.g. keys loaded), so that the security subsystem can evaluate kernel modules loaded by populate_bpffs().
Signed-off-by: Roberto Sassu roberto.sassu@huawei.com --- fs/namespace.c | 1 + include/linux/bpf.h | 5 +++++ init/main.c | 2 ++ kernel/bpf/inode.c | 9 +++++++++ 4 files changed, 17 insertions(+)
diff --git a/fs/namespace.c b/fs/namespace.c index 6e9844b8c6fb..3b69f96dc641 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -31,6 +31,7 @@ #include <uapi/linux/mount.h> #include <linux/fs_context.h> #include <linux/shmem_fs.h> +#include <linux/bpf.h> #include <linux/mnt_idmapping.h>
#include "pnode.h" diff --git a/include/linux/bpf.h b/include/linux/bpf.h index bdb5298735ce..5f624310fda2 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1103,6 +1103,8 @@ static inline void bpf_module_put(const void *data, struct module *owner) module_put(owner); }
+void __init mount_bpffs(void); + #ifdef CONFIG_NET /* Define it here to avoid the use of forward declaration */ struct bpf_dummy_ops_state { @@ -1141,6 +1143,9 @@ static inline int bpf_struct_ops_map_sys_lookup_elem(struct bpf_map *map, { return -EINVAL; } +static inline void __init mount_bpffs(void) +{ +} #endif
struct bpf_array { diff --git a/init/main.c b/init/main.c index 0c064c2c79fd..30dcd0dd9faa 100644 --- a/init/main.c +++ b/init/main.c @@ -99,6 +99,7 @@ #include <linux/kcsan.h> #include <linux/init_syscalls.h> #include <linux/stackdepot.h> +#include <linux/bpf.h> #include <net/net_namespace.h>
#include <asm/io.h> @@ -1638,4 +1639,5 @@ static noinline void __init kernel_init_freeable(void) */
integrity_load_keys(); + mount_bpffs(); } diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index c1941c65ce95..e8361d7679d0 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -1020,3 +1020,12 @@ static int __init bpf_init(void) return ret; } fs_initcall(bpf_init); + +static struct vfsmount *bpffs_mount __read_mostly; + +void __init mount_bpffs(void) +{ + bpffs_mount = kern_mount(&bpf_fs_type); + if (IS_ERR(bpffs_mount)) + pr_err("bpffs: could not mount!\n"); +}
Hi Roberto,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on bpf-next/master] [also build test ERROR on linus/master next-20220328] [cannot apply to bpf/master v5.17] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch]
url: https://github.com/intel-lab-lkp/linux/commits/Roberto-Sassu/bpf-Secure-and-... base: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master config: riscv-randconfig-c004-20220327 (https://download.01.org/0day-ci/archive/20220329/202203291034.vCkMuZo5-lkp@i...) compiler: riscv64-linux-gcc (GCC) 11.2.0 reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/intel-lab-lkp/linux/commit/eddbb1ec1e92ba00c4acc9f1237692... git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Roberto-Sassu/bpf-Secure-and-authenticated-preloading-of-eBPF-programs/20220329-015829 git checkout eddbb1ec1e92ba00c4acc9f123769265e17e8e40 # save the config file to linux build tree mkdir build_dir COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=riscv SHELL=/bin/bash
If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot lkp@intel.com
All errors (new ones prefixed by >>):
kernel/bpf/inode.c:25:37: error: 'CONFIG_BPF_PRELOAD_LIST' undeclared here (not in a function) 25 | static char *bpf_preload_list_str = CONFIG_BPF_PRELOAD_LIST; | ^~~~~~~~~~~~~~~~~~~~~~~
kernel/bpf/inode.c:1026:13: error: redefinition of 'mount_bpffs'
1026 | void __init mount_bpffs(void) | ^~~~~~~~~~~ In file included from include/linux/filter.h:9, from kernel/bpf/inode.c:20: include/linux/bpf.h:1146:27: note: previous definition of 'mount_bpffs' with type 'void(void)' 1146 | static inline void __init mount_bpffs(void) | ^~~~~~~~~~~
vim +/mount_bpffs +1026 kernel/bpf/inode.c
1025
1026 void __init mount_bpffs(void)
Hi Roberto,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on bpf-next/master] [also build test ERROR on linus/master next-20220328] [cannot apply to bpf/master v5.17] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch]
url: https://github.com/intel-lab-lkp/linux/commits/Roberto-Sassu/bpf-Secure-and-... base: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master config: hexagon-randconfig-r041-20220328 (https://download.01.org/0day-ci/archive/20220329/202203291256.TUOyKEtD-lkp@i...) compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 0f6d9501cf49ce02937099350d08f20c4af86f3d) reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/intel-lab-lkp/linux/commit/eddbb1ec1e92ba00c4acc9f1237692... git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Roberto-Sassu/bpf-Secure-and-authenticated-preloading-of-eBPF-programs/20220329-015829 git checkout eddbb1ec1e92ba00c4acc9f123769265e17e8e40 # save the config file to linux build tree mkdir build_dir COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=hexagon SHELL=/bin/bash
If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot lkp@intel.com
All errors (new ones prefixed by >>):
kernel/bpf/inode.c:25:37: error: use of undeclared identifier 'CONFIG_BPF_PRELOAD_LIST' static char *bpf_preload_list_str = CONFIG_BPF_PRELOAD_LIST; ^
kernel/bpf/inode.c:1026:13: error: redefinition of 'mount_bpffs'
void __init mount_bpffs(void) ^ include/linux/bpf.h:1146:27: note: previous definition is here static inline void __init mount_bpffs(void) ^ 2 errors generated.
vim +/mount_bpffs +1026 kernel/bpf/inode.c
1025
1026 void __init mount_bpffs(void)
Add the test 'gen_preload_methods' to ensure that the preload methods are correctly generated. Introduce a sample eBPF program in progs/gen_preload_methods.c, generate the light skeleton without and with the preload methods, and finally compare the diff with the expected diff output in prog_tests/gen_preload_methods.expected.diff.
Signed-off-by: Roberto Sassu roberto.sassu@huawei.com --- tools/testing/selftests/bpf/Makefile | 15 ++- .../gen_preload_methods.expected.diff | 97 +++++++++++++++++++ .../bpf/prog_tests/test_gen_preload_methods.c | 27 ++++++ .../selftests/bpf/progs/gen_preload_methods.c | 23 +++++ 4 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 tools/testing/selftests/bpf/prog_tests/gen_preload_methods.expected.diff create mode 100644 tools/testing/selftests/bpf/prog_tests/test_gen_preload_methods.c create mode 100644 tools/testing/selftests/bpf/progs/gen_preload_methods.c
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 3820608faf57..de81779e90e3 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -337,10 +337,11 @@ test_subskeleton_lib.skel.h-deps := test_subskeleton_lib2.o test_subskeleton_lib
LSKELS := kfunc_call_test.c fentry_test.c fexit_test.c fexit_sleep.c \ test_ringbuf.c atomics.c trace_printk.c trace_vprintk.c \ - map_ptr_kern.c core_kern.c core_kern_overflow.c + map_ptr_kern.c core_kern.c core_kern_overflow.c gen_preload_methods.c +LSKELSP := gen_preload_methods.c # Generate both light skeleton and libbpf skeleton for these LSKELS_EXTRA := test_ksyms_module.c test_ksyms_weak.c kfunc_call_test_subprog.c -SKEL_BLACKLIST += $$(LSKELS) +SKEL_BLACKLIST += $$(LSKELS) $$(LSKELSP)
test_static_linked.skel.h-deps := test_static_linked1.o test_static_linked2.o linked_funcs.skel.h-deps := linked_funcs1.o linked_funcs2.o @@ -370,6 +371,7 @@ TRUNNER_BPF_SKELS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.skel.h, \ $$(filter-out $(SKEL_BLACKLIST) $(LINKED_BPF_SRCS),\ $$(TRUNNER_BPF_SRCS))) TRUNNER_BPF_LSKELS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.lskel.h, $$(LSKELS) $$(LSKELS_EXTRA)) +TRUNNER_BPF_LSKELSP := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.preload.lskel.h, $$(LSKELSP)) TRUNNER_BPF_SKELS_LINKED := $$(addprefix $$(TRUNNER_OUTPUT)/,$(LINKED_SKELS)) TEST_GEN_FILES += $$(TRUNNER_BPF_OBJS)
@@ -421,6 +423,14 @@ $(TRUNNER_BPF_LSKELS): %.lskel.h: %.o $(BPFTOOL) | $(TRUNNER_OUTPUT) $(Q)diff $$(<:.o=.linked2.o) $$(<:.o=.linked3.o) $(Q)$$(BPFTOOL) gen skeleton -L $$(<:.o=.linked3.o) name $$(notdir $$(<:.o=_lskel)) > $$@
+$(TRUNNER_BPF_LSKELSP): %.preload.lskel.h: %.o $(BPFTOOL) | $(TRUNNER_OUTPUT) + $$(call msg,GEN-SKEL,$(TRUNNER_BINARY),$$@) + $(Q)$$(BPFTOOL) gen object $$(<:.o=.linked1.o) $$< + $(Q)$$(BPFTOOL) gen object $$(<:.o=.linked2.o) $$(<:.o=.linked1.o) + $(Q)$$(BPFTOOL) gen object $$(<:.o=.linked3.o) $$(<:.o=.linked2.o) + $(Q)diff $$(<:.o=.linked2.o) $$(<:.o=.linked3.o) + $(Q)$$(BPFTOOL) gen skeleton -L -P $$(<:.o=.linked3.o) name $$(notdir $$(<:.o=_lskel)) > $$@ + $(TRUNNER_BPF_SKELS_LINKED): $(TRUNNER_BPF_OBJS) $(BPFTOOL) | $(TRUNNER_OUTPUT) $$(call msg,LINK-BPF,$(TRUNNER_BINARY),$$(@:.skel.h=.o)) $(Q)$$(BPFTOOL) gen object $$(@:.skel.h=.linked1.o) $$(addprefix $(TRUNNER_OUTPUT)/,$$($$(@F)-deps)) @@ -451,6 +461,7 @@ $(TRUNNER_TEST_OBJS): $(TRUNNER_OUTPUT)/%.test.o: \ $(TRUNNER_BPF_OBJS) \ $(TRUNNER_BPF_SKELS) \ $(TRUNNER_BPF_LSKELS) \ + $(TRUNNER_BPF_LSKELSP) \ $(TRUNNER_BPF_SKELS_LINKED) \ $$(BPFOBJ) | $(TRUNNER_OUTPUT) $$(call msg,TEST-OBJ,$(TRUNNER_BINARY),$$@) diff --git a/tools/testing/selftests/bpf/prog_tests/gen_preload_methods.expected.diff b/tools/testing/selftests/bpf/prog_tests/gen_preload_methods.expected.diff new file mode 100644 index 000000000000..5e010d380e50 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/gen_preload_methods.expected.diff @@ -0,0 +1,97 @@ +--- gen_preload_methods.lskel.h 2022-03-28 13:40:22.042715754 +0200 ++++ gen_preload_methods.preload.lskel.h 2022-03-28 13:40:22.530715750 +0200 +@@ -221,4 +221,94 @@ gen_preload_methods_lskel__assert(struct + #endif + } + ++static struct bpf_link *dump_bpf_map_link; ++static struct bpf_map *ringbuf_map; ++static struct gen_preload_methods_lskel *skel; ++ ++static void free_objs_and_skel(void) ++{ ++ bpf_preload_set_ops("gen_preload_methods_lskel", THIS_MODULE, NULL); ++ ++ if (!IS_ERR_OR_NULL(dump_bpf_map_link)) ++ bpf_link_put(dump_bpf_map_link); ++ if (!IS_ERR_OR_NULL(ringbuf_map)) ++ bpf_map_put(ringbuf_map); ++ ++ gen_preload_methods_lskel__destroy(skel); ++} ++ ++static int preload(struct dentry *parent) ++{ ++ int err; ++ ++ bpf_link_inc(dump_bpf_map_link); ++ bpf_map_inc(ringbuf_map); ++ ++ err = bpf_obj_do_pin_kernel(parent, "dump_bpf_map", ++ dump_bpf_map_link, ++ BPF_TYPE_LINK); ++ if (err) ++ goto undo; ++ ++ err = bpf_obj_do_pin_kernel(parent, "ringbuf", ++ ringbuf_map, ++ BPF_TYPE_MAP); ++ if (err) ++ goto undo; ++ ++ return 0; ++undo: ++ bpf_link_put(dump_bpf_map_link); ++ bpf_map_put(ringbuf_map); ++ return err; ++} ++ ++static struct bpf_preload_ops ops = { ++ .preload = preload, ++ .owner = THIS_MODULE, ++}; ++ ++static int load_skel(void) ++{ ++ int err = -ENOMEM; ++ ++ if (!bpf_preload_set_ops("gen_preload_methods_lskel", THIS_MODULE, &ops)) ++ return 0; ++ ++ skel = gen_preload_methods_lskel__open(); ++ if (!skel) ++ goto out; ++ ++ err = gen_preload_methods_lskel__load(skel); ++ if (err) ++ goto out; ++ ++ err = gen_preload_methods_lskel__attach(skel); ++ if (err) ++ goto out; ++ ++ dump_bpf_map_link = bpf_link_get_from_fd(skel->links.dump_bpf_map_fd); ++ if (IS_ERR(dump_bpf_map_link)) { ++ err = PTR_ERR(dump_bpf_map_link); ++ goto out; ++ } ++ ++ ringbuf_map = bpf_map_get(skel->maps.ringbuf.map_fd); ++ if (IS_ERR(ringbuf_map)) { ++ err = PTR_ERR(ringbuf_map); ++ goto out; ++ } ++ ++ /* Avoid taking over stdin/stdout/stderr of init process. Zeroing out ++ * makes skel_closenz() a no-op later in iterators_bpf__destroy(). ++ */ ++ close_fd(skel->links.dump_bpf_map_fd); ++ skel->links.dump_bpf_map_fd = 0; ++ ++ return 0; ++out: ++ free_objs_and_skel(); ++ return err; ++} ++ + #endif /* __GEN_PRELOAD_METHODS_LSKEL_SKEL_H__ */ diff --git a/tools/testing/selftests/bpf/prog_tests/test_gen_preload_methods.c b/tools/testing/selftests/bpf/prog_tests/test_gen_preload_methods.c new file mode 100644 index 000000000000..937b3e606f53 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/test_gen_preload_methods.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH + */ + +#include <test_progs.h> + +static int duration; + +void test_test_gen_preload_methods(void) +{ + char diff_cmd[1024]; + int err; + + snprintf(diff_cmd, sizeof(diff_cmd), + "diff -up gen_preload_methods.lskel.h " + "gen_preload_methods.preload.lskel.h " + "| tail -n +4 | " + "diff -u - " + "<(tail -n +4 prog_tests/gen_preload_methods.expected.diff)"); + err = system(diff_cmd); + if (CHECK(err, "diff", + "differing test output, err=%d, diff cmd:\n%s\n", + err, diff_cmd)) + return; +} diff --git a/tools/testing/selftests/bpf/progs/gen_preload_methods.c b/tools/testing/selftests/bpf/progs/gen_preload_methods.c new file mode 100644 index 000000000000..5b3ab27f945d --- /dev/null +++ b/tools/testing/selftests/bpf/progs/gen_preload_methods.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH + */ + +#include "vmlinux.h" +#include <errno.h> +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_tracing.h> + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 1 << 12); +} ringbuf SEC(".maps"); + +char _license[] SEC("license") = "GPL"; + +SEC("iter/bpf_map") +int dump_bpf_map(struct bpf_iter__bpf_map *ctx) +{ + return 0; +}
Introduce the 'preload_methods' test, which loads the new kernel module bpf_testmod_preload.ko (with the light skeleton from gen_preload_methods.c), mounts a new instance of the bpf filesystem, and checks if the pinned objects exist.
The test requires to include 'gen_preload_methods_lskel' among the list of eBPF programs to preload.
Signed-off-by: Roberto Sassu roberto.sassu@huawei.com --- tools/testing/selftests/bpf/Makefile | 17 ++++- .../bpf/bpf_testmod_preload/.gitignore | 7 ++ .../bpf/bpf_testmod_preload/Makefile | 20 ++++++ .../bpf/prog_tests/test_preload_methods.c | 69 +++++++++++++++++++ 4 files changed, 110 insertions(+), 3 deletions(-) create mode 100644 tools/testing/selftests/bpf/bpf_testmod_preload/.gitignore create mode 100644 tools/testing/selftests/bpf/bpf_testmod_preload/Makefile create mode 100644 tools/testing/selftests/bpf/prog_tests/test_preload_methods.c
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index de81779e90e3..ca419b0a083c 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -82,7 +82,7 @@ TEST_PROGS_EXTENDED := with_addr.sh \ TEST_GEN_PROGS_EXTENDED = test_sock_addr test_skb_cgroup_id_user \ flow_dissector_load test_flow_dissector test_tcp_check_syncookie_user \ test_lirc_mode2_user xdping test_cpp runqslower bench bpf_testmod.ko \ - xdpxceiver xdp_redirect_multi + xdpxceiver xdp_redirect_multi bpf_testmod_preload.ko
TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read
@@ -110,6 +110,7 @@ override define CLEAN $(Q)$(RM) -r $(TEST_GEN_FILES) $(Q)$(RM) -r $(EXTRA_CLEAN) $(Q)$(MAKE) -C bpf_testmod clean + $(Q)$(MAKE) -C bpf_testmod_preload clean $(Q)$(MAKE) docs-clean endef
@@ -502,7 +503,7 @@ TRUNNER_EXTRA_SOURCES := test_progs.c cgroup_helpers.c trace_helpers.c \ btf_helpers.c flow_dissector_load.h \ cap_helpers.c TRUNNER_EXTRA_FILES := $(OUTPUT)/urandom_read $(OUTPUT)/bpf_testmod.ko \ - ima_setup.sh \ + ima_setup.sh $(OUTPUT)/bpf_testmod_preload.ko \ $(wildcard progs/btf_dump_test_case_*.c) TRUNNER_BPF_BUILD_RULE := CLANG_BPF_BUILD_RULE TRUNNER_BPF_CFLAGS := $(BPF_CFLAGS) $(CLANG_CFLAGS) -DENABLE_ATOMICS_TESTS @@ -575,9 +576,19 @@ $(OUTPUT)/bench: $(OUTPUT)/bench.o \ $(call msg,BINARY,,$@) $(Q)$(CC) $(CFLAGS) $(LDFLAGS) $(filter %.a %.o,$^) $(LDLIBS) -o $@
+bpf_testmod_preload/bpf_testmod_preload.c: $(OUTPUT)/gen_preload_methods.preload.lskel.h $(BPFTOOL) $(TRUNNER_BPF_LSKELSP) + $(call msg,GEN-MOD,,$@) + $(BPFTOOL) gen module $< > $@ + +$(OUTPUT)/bpf_testmod_preload.ko: bpf_testmod_preload/bpf_testmod_preload.c + $(call msg,MOD,,$@) + $(Q)$(RM) bpf_testmod_preload/bpf_testmod_preload.ko # force re-compilation + $(Q)$(MAKE) $(submake_extras) -C bpf_testmod_preload + $(Q)cp bpf_testmod_preload/bpf_testmod_preload.ko $@ + EXTRA_CLEAN := $(TEST_CUSTOM_PROGS) $(SCRATCH_DIR) $(HOST_SCRATCH_DIR) \ prog_tests/tests.h map_tests/tests.h verifier/tests.h \ feature bpftool \ - $(addprefix $(OUTPUT)/,*.o *.skel.h *.lskel.h *.subskel.h no_alu32 bpf_gcc bpf_testmod.ko) + $(addprefix $(OUTPUT)/,*.o *.skel.h *.lskel.h *.subskel.h no_alu32 bpf_gcc bpf_testmod.ko bpf_testmod_preload.ko)
.PHONY: docs docs-clean diff --git a/tools/testing/selftests/bpf/bpf_testmod_preload/.gitignore b/tools/testing/selftests/bpf/bpf_testmod_preload/.gitignore new file mode 100644 index 000000000000..989530ffc79f --- /dev/null +++ b/tools/testing/selftests/bpf/bpf_testmod_preload/.gitignore @@ -0,0 +1,7 @@ +*.mod +*.mod.c +*.o +.ko +/Module.symvers +/modules.order +bpf_testmod_preload.c diff --git a/tools/testing/selftests/bpf/bpf_testmod_preload/Makefile b/tools/testing/selftests/bpf/bpf_testmod_preload/Makefile new file mode 100644 index 000000000000..d17ac6670974 --- /dev/null +++ b/tools/testing/selftests/bpf/bpf_testmod_preload/Makefile @@ -0,0 +1,20 @@ +BPF_TESTMOD_PRELOAD_DIR := $(realpath $(dir $(abspath $(lastword $(MAKEFILE_LIST))))) +KDIR ?= $(abspath $(BPF_TESTMOD_PRELOAD_DIR)/../../../../..) + +ifeq ($(V),1) +Q = +else +Q = @ +endif + +MODULES = bpf_testmod_preload.ko + +obj-m += bpf_testmod_preload.o +CFLAGS_bpf_testmod_preload.o = -I$(BPF_TESTMOD_PRELOAD_DIR)/../tools/include + +all: + +$(Q)make -C $(KDIR) M=$(BPF_TESTMOD_PRELOAD_DIR) modules + +clean: + +$(Q)make -C $(KDIR) M=$(BPF_TESTMOD_PRELOAD_DIR) clean + diff --git a/tools/testing/selftests/bpf/prog_tests/test_preload_methods.c b/tools/testing/selftests/bpf/prog_tests/test_preload_methods.c new file mode 100644 index 000000000000..bad3b187794b --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/test_preload_methods.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH + */ + +#include <errno.h> +#include <limits.h> +#include <test_progs.h> +#include <sys/mount.h> +#include <sys/stat.h> + +#define MOUNT_FLAGS (MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME) + +static int duration; + +void test_test_preload_methods(void) +{ + char bpf_mntpoint[] = "/tmp/bpf_mntpointXXXXXX", *dir; + char path[PATH_MAX]; + struct stat st; + int err; + + system("rmmod bpf_testmod_preload 2> /dev/null"); + + err = system("insmod bpf_testmod_preload.ko"); + if (CHECK(err, "insmod", + "cannot load bpf_testmod_preload.ko, err=%d\n", err)) + return; + + dir = mkdtemp(bpf_mntpoint); + if (CHECK(!dir, "mkstemp", "cannot create temp file, err=%d\n", + -errno)) + goto out_rmmod; + + err = mount(bpf_mntpoint, bpf_mntpoint, "bpf", MOUNT_FLAGS, NULL); + if (CHECK(err, "mount", + "cannot mount bpf filesystem to %s, err=%d\n", bpf_mntpoint, + err)) + goto out_unlink; + + snprintf(path, sizeof(path), "%s/gen_preload_methods_lskel", + bpf_mntpoint); + + err = stat(path, &st); + if (CHECK(err, "stat", "cannot find %s\n", path)) + goto out_unmount; + + snprintf(path, sizeof(path), + "%s/gen_preload_methods_lskel/dump_bpf_map", bpf_mntpoint); + + err = stat(path, &st); + if (CHECK(err, "stat", "cannot find %s\n", path)) + goto out_unmount; + + snprintf(path, sizeof(path), "%s/gen_preload_methods_lskel/ringbuf", + bpf_mntpoint); + + err = stat(path, &st); + if (CHECK(err, "stat", "cannot find %s\n", path)) + goto out_unmount; + +out_unmount: + umount(bpf_mntpoint); +out_unlink: + rmdir(bpf_mntpoint); +out_rmmod: + system("rmmod bpf_testmod_preload"); +}
On Mon, Mar 28, 2022 at 10:51 AM Roberto Sassu roberto.sassu@huawei.com wrote:
eBPF already allows programs to be preloaded and kept running without intervention from user space. There is a dedicated kernel module called bpf_preload, which contains the light skeleton of the iterators_bpf eBPF program. If this module is enabled in the kernel configuration, its loading will be triggered when the bpf filesystem is mounted (unless the module is built-in), and the links of iterators_bpf are pinned in that filesystem (they will appear as the progs.debug and maps.debug files).
However, the current mechanism, if used to preload an LSM, would not offer the same security guarantees of LSMs integrated in the security subsystem. Also, it is not generic enough to be used for preloading arbitrary eBPF programs, unless the bpf_preload code is heavily modified.
More specifically, the security problems are:
- any program can be pinned to the bpf filesystem without limitations (unless a MAC mechanism enforces some restrictions);
- programs being executed can be terminated at any time by deleting the pinned objects or unmounting the bpf filesystem.
The usability problems are:
- only a fixed amount of links can be pinned;
- only links can be pinned, other object types are not supported;
- code to pin objects has to be written manually;
- preloading multiple eBPF programs is not practical, bpf_preload has to be modified to include additional light skeletons.
Solve the security problems by mounting the bpf filesystem from the kernel, by preloading authenticated kernel modules (e.g. with module.sig_enforce) and by pinning objects to that filesystem. This particular filesystem instance guarantees that desired eBPF programs run until the very end of the kernel lifecycle, since even root cannot interfere with it.
Solve the usability problems by generalizing the pinning function, to handle not only links but also maps and progs. Also increment the object reference count and call the pinning function directly from the preload method (currently in the bpf_preload kernel module) rather than from the bpf filesystem code itself, so that a generic eBPF program can do those operations depending on its objects (this also avoids the limitation of the fixed-size array for storing the objects to pin).
Then, simplify the process of pinning objects defined by a generic eBPF program by automatically generating the required methods in the light skeleton. Also, generate a separate kernel module for each eBPF program to preload, so that existing ones don't have to be modified. Finally, support preloading multiple eBPF programs by allowing users to specify a list from the kernel configuration, at build time, or with the new kernel option bpf_preload_list=, at run-time.
To summarize, this patch set makes it possible to plug in out-of-tree LSMs matching the security guarantees of their counterpart in the security subsystem, without having to modify the kernel itself. The same benefits are extended to other eBPF program types.
Only one remaining problem is how to support auto-attaching eBPF programs with LSM type. It will be solved with a separate patch set.
Patches 1-2 export some definitions, to build out-of-tree kernel modules with eBPF programs to preload. Patches 3-4 allow eBPF programs to pin objects by themselves. Patches 5-10 automatically generate the methods for preloading in the light skeleton. Patches 11-14 make it possible to preload multiple eBPF programs. Patch 15 automatically generates the kernel module for preloading an eBPF program, patch 16 does a kernel mount of the bpf filesystem, and finally patches 17-18 test the functionality introduced.
This approach of moving tons of pretty generic code into codegen of lskel seems suboptimal. Why so much code has to be codegenerated? Especially that tiny module code?
Can you please elaborate on why it can't be done in a way that doesn't require such extensive light skeleton codegen changes?
Roberto Sassu (18): bpf: Export bpf_link_inc() bpf-preload: Move bpf_preload.h to include/linux bpf-preload: Generalize object pinning from the kernel bpf-preload: Export and call bpf_obj_do_pin_kernel() bpf-preload: Generate static variables bpf-preload: Generate free_objs_and_skel() bpf-preload: Generate preload() bpf-preload: Generate load_skel() bpf-preload: Generate code to pin non-internal maps bpf-preload: Generate bpf_preload_ops bpf-preload: Store multiple bpf_preload_ops structures in a linked list bpf-preload: Implement new registration method for preloading eBPF programs bpf-preload: Move pinned links and maps to a dedicated directory in bpffs bpf-preload: Switch to new preload registration method bpf-preload: Generate code of kernel module to preload bpf-preload: Do kernel mount to ensure that pinned objects don't disappear bpf-preload/selftests: Add test for automatic generation of preload methods bpf-preload/selftests: Preload a test eBPF program and check pinned objects
please use proper prefixes: bpf (for kernel-side changes), libbpf, bpftool, selftests/bpf, etc
.../admin-guide/kernel-parameters.txt | 8 + fs/namespace.c | 1 + include/linux/bpf.h | 5 + include/linux/bpf_preload.h | 37 ++ init/main.c | 2 + kernel/bpf/inode.c | 295 +++++++++-- kernel/bpf/preload/Kconfig | 25 +- kernel/bpf/preload/bpf_preload.h | 16 - kernel/bpf/preload/bpf_preload_kern.c | 85 +--- kernel/bpf/preload/iterators/Makefile | 9 +- .../bpf/preload/iterators/iterators.lskel.h | 466 +++++++++++------- kernel/bpf/syscall.c | 1 + .../bpf/bpftool/Documentation/bpftool-gen.rst | 13 + tools/bpf/bpftool/bash-completion/bpftool | 6 +- tools/bpf/bpftool/gen.c | 331 +++++++++++++ tools/bpf/bpftool/main.c | 7 +- tools/bpf/bpftool/main.h | 1 + tools/testing/selftests/bpf/Makefile | 32 +- .../bpf/bpf_testmod_preload/.gitignore | 7 + .../bpf/bpf_testmod_preload/Makefile | 20 + .../gen_preload_methods.expected.diff | 97 ++++ .../bpf/prog_tests/test_gen_preload_methods.c | 27 + .../bpf/prog_tests/test_preload_methods.c | 69 +++ .../selftests/bpf/progs/gen_preload_methods.c | 23 + 24 files changed, 1246 insertions(+), 337 deletions(-) create mode 100644 include/linux/bpf_preload.h delete mode 100644 kernel/bpf/preload/bpf_preload.h create mode 100644 tools/testing/selftests/bpf/bpf_testmod_preload/.gitignore create mode 100644 tools/testing/selftests/bpf/bpf_testmod_preload/Makefile create mode 100644 tools/testing/selftests/bpf/prog_tests/gen_preload_methods.expected.diff create mode 100644 tools/testing/selftests/bpf/prog_tests/test_gen_preload_methods.c create mode 100644 tools/testing/selftests/bpf/prog_tests/test_preload_methods.c create mode 100644 tools/testing/selftests/bpf/progs/gen_preload_methods.c
-- 2.32.0
From: Andrii Nakryiko [mailto:andrii.nakryiko@gmail.com] Sent: Wednesday, March 30, 2022 1:51 AM On Mon, Mar 28, 2022 at 10:51 AM Roberto Sassu roberto.sassu@huawei.com wrote:
[...]
Patches 1-2 export some definitions, to build out-of-tree kernel modules with eBPF programs to preload. Patches 3-4 allow eBPF programs to pin objects by themselves. Patches 5-10 automatically generate the methods
for
preloading in the light skeleton. Patches 11-14 make it possible to preload multiple eBPF programs. Patch 15 automatically generates the kernel
module
for preloading an eBPF program, patch 16 does a kernel mount of the bpf filesystem, and finally patches 17-18 test the functionality introduced.
This approach of moving tons of pretty generic code into codegen of lskel seems suboptimal. Why so much code has to be codegenerated? Especially that tiny module code?
Hi Andrii
the main goal of this patch set is to use the preloading mechanism to plug in securely LSMs implemented as eBPF programs.
I have a use case, I want to plug in my eBPF program, DIGLIM eBPF.
I started to modify the preloading code manually, and I realized how complicated the process is if you want to add something more than the existing iterators_bpf program.
First, you have to look at which objects you want to preload, then write code for each of them. This process is repetitive and deterministic, this is why I immediately thought that it is a good case for automatic code generation.
My idea is that, if this mechanism is accepted, an implementer of an LSM wishing to be preloaded at the very beginning, only has to write his eBPF code, the kernel and bpftool take care of the rest. Generation of the preloading code is optional, and need to be enabled with the -P option, in addition to -L.
The light skeleton of DIGLIM eBPF looks like:
https://github.com/robertosassu/linux/blob/bpf-preload-v1/kernel/bpf/preload...
The preloading interface is very similar to the one used by the security subsystem: an ordered list of eBPF programs to preload set in the kernel configuration, that can be overwritten with the kernel option bpf_preload_list=.
The changes that would be required to preload DIGLIM eBPF look like:
https://github.com/robertosassu/linux/commit/c07e1a78584ee688aeb812f07dc7ab3...
Thanks
Roberto
HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063 Managing Director: Li Peng, Zhong Ronghua
Can you please elaborate on why it can't be done in a way that doesn't require such extensive light skeleton codegen changes?
Roberto Sassu (18): bpf: Export bpf_link_inc() bpf-preload: Move bpf_preload.h to include/linux bpf-preload: Generalize object pinning from the kernel bpf-preload: Export and call bpf_obj_do_pin_kernel() bpf-preload: Generate static variables bpf-preload: Generate free_objs_and_skel() bpf-preload: Generate preload() bpf-preload: Generate load_skel() bpf-preload: Generate code to pin non-internal maps bpf-preload: Generate bpf_preload_ops bpf-preload: Store multiple bpf_preload_ops structures in a linked list bpf-preload: Implement new registration method for preloading eBPF programs bpf-preload: Move pinned links and maps to a dedicated directory in bpffs bpf-preload: Switch to new preload registration method bpf-preload: Generate code of kernel module to preload bpf-preload: Do kernel mount to ensure that pinned objects don't disappear bpf-preload/selftests: Add test for automatic generation of preload methods bpf-preload/selftests: Preload a test eBPF program and check pinned objects
please use proper prefixes: bpf (for kernel-side changes), libbpf, bpftool, selftests/bpf, etc
.../admin-guide/kernel-parameters.txt | 8 + fs/namespace.c | 1 + include/linux/bpf.h | 5 + include/linux/bpf_preload.h | 37 ++ init/main.c | 2 + kernel/bpf/inode.c | 295 +++++++++-- kernel/bpf/preload/Kconfig | 25 +- kernel/bpf/preload/bpf_preload.h | 16 - kernel/bpf/preload/bpf_preload_kern.c | 85 +--- kernel/bpf/preload/iterators/Makefile | 9 +- .../bpf/preload/iterators/iterators.lskel.h | 466 +++++++++++------- kernel/bpf/syscall.c | 1 + .../bpf/bpftool/Documentation/bpftool-gen.rst | 13 + tools/bpf/bpftool/bash-completion/bpftool | 6 +- tools/bpf/bpftool/gen.c | 331 +++++++++++++ tools/bpf/bpftool/main.c | 7 +- tools/bpf/bpftool/main.h | 1 + tools/testing/selftests/bpf/Makefile | 32 +- .../bpf/bpf_testmod_preload/.gitignore | 7 + .../bpf/bpf_testmod_preload/Makefile | 20 + .../gen_preload_methods.expected.diff | 97 ++++ .../bpf/prog_tests/test_gen_preload_methods.c | 27 + .../bpf/prog_tests/test_preload_methods.c | 69 +++ .../selftests/bpf/progs/gen_preload_methods.c | 23 + 24 files changed, 1246 insertions(+), 337 deletions(-) create mode 100644 include/linux/bpf_preload.h delete mode 100644 kernel/bpf/preload/bpf_preload.h create mode 100644
tools/testing/selftests/bpf/bpf_testmod_preload/.gitignore
create mode 100644
tools/testing/selftests/bpf/bpf_testmod_preload/Makefile
create mode 100644
tools/testing/selftests/bpf/prog_tests/gen_preload_methods.expected.diff
create mode 100644
tools/testing/selftests/bpf/prog_tests/test_gen_preload_methods.c
create mode 100644
tools/testing/selftests/bpf/prog_tests/test_preload_methods.c
create mode 100644
tools/testing/selftests/bpf/progs/gen_preload_methods.c
-- 2.32.0
On Mon, Mar 28, 2022 at 07:50:15PM +0200, Roberto Sassu wrote:
eBPF already allows programs to be preloaded and kept running without intervention from user space. There is a dedicated kernel module called bpf_preload, which contains the light skeleton of the iterators_bpf eBPF program. If this module is enabled in the kernel configuration, its loading will be triggered when the bpf filesystem is mounted (unless the module is built-in), and the links of iterators_bpf are pinned in that filesystem (they will appear as the progs.debug and maps.debug files).
However, the current mechanism, if used to preload an LSM, would not offer the same security guarantees of LSMs integrated in the security subsystem. Also, it is not generic enough to be used for preloading arbitrary eBPF programs, unless the bpf_preload code is heavily modified.
More specifically, the security problems are:
- any program can be pinned to the bpf filesystem without limitations (unless a MAC mechanism enforces some restrictions);
- programs being executed can be terminated at any time by deleting the pinned objects or unmounting the bpf filesystem.
So many things to untangle here.
The above paragraphs are misleading and incorrect. The commit log sounds like there are security issues that this patch set is fixing. This is not true. Looks like there is a massive misunderstanding on what bpffs is. It's a file system to pin and get bpf objects with normal file access permissions. Nothing else. Do NOT use it to pin LSM or any other security sensitive bpf programs and then complain that root can unpin them. Yes. Root can and should be able to 'rm -rf' anything in bpffs instance.
The usability problems are:
- only a fixed amount of links can be pinned;
where do you see this limit?
- only links can be pinned, other object types are not supported;
really? progs, maps can be pinned as well.
- code to pin objects has to be written manually;
huh?
Solve the security problems by mounting the bpf filesystem from the kernel, by preloading authenticated kernel modules (e.g. with module.sig_enforce) and by pinning objects to that filesystem. This particular filesystem instance guarantees that desired eBPF programs run until the very end of the kernel lifecycle, since even root cannot interfere with it.
No.
I suspect there is huge confusion on what these two "progs.debug" and "maps.debug" files are in a bpffs instance. They are debug files to pretty pring loaded maps and progs for folks who like to use 'cat' to examine the state of the system instead of 'bpftool'. The root can remove these files from bpffs.
There is no reason for kernel module to pin its bpf progs. If you want to develop DIGLIM as a kernel module that uses light skeleton just do: #include <linux/init.h> #include <linux/module.h> #include "diglim.lskel.h"
static struct diglim_bpf *skel;
static int __init load(void) { skel = diglim_bpf__open_and_load(); err = diglim_bpf__attach(skel); } /* detach skel in __fini */
It's really that short.
Then you will be able to - insmod diglim.ko -> will load and attach bpf progs. - rmmod diglim -> will detach them.
Independantly from these two mistunderstandings of bpffs and light skel we've been talking about auto exposing loaded bpf progs, maps, links in a bpffs without incrementing refcnt of them. When progs get unloaded the files will disappear. Some folks believe that doing 'ls' in a directory and see one file for each bpf prog loaded and then doing 'cat' on that file would be useful for debugging. That idea wasn't rejected. We're still thinking what would be the best way to auto-expose all bpf objects for debugging and whether it's actually makes sense to do considering that bpftool already has commands to list all progs, maps, links, etc with great detail. It's pretty much an argument between 'cat+ls' believers and 'bpftool' cmdline believers. That discussion is orthogonal and should not be mixed with bpffs, lsm, security or anything else.
From: Alexei Starovoitov [mailto:alexei.starovoitov@gmail.com] Sent: Thursday, March 31, 2022 4:27 AM On Mon, Mar 28, 2022 at 07:50:15PM +0200, Roberto Sassu wrote:
eBPF already allows programs to be preloaded and kept running without intervention from user space. There is a dedicated kernel module called bpf_preload, which contains the light skeleton of the iterators_bpf eBPF program. If this module is enabled in the kernel configuration, its loading will be triggered when the bpf filesystem is mounted (unless the module is built-in), and the links of iterators_bpf are pinned in that filesystem (they will appear as the progs.debug and maps.debug files).
However, the current mechanism, if used to preload an LSM, would not
offer
the same security guarantees of LSMs integrated in the security
subsystem.
Also, it is not generic enough to be used for preloading arbitrary eBPF programs, unless the bpf_preload code is heavily modified.
More specifically, the security problems are:
- any program can be pinned to the bpf filesystem without limitations (unless a MAC mechanism enforces some restrictions);
- programs being executed can be terminated at any time by deleting the pinned objects or unmounting the bpf filesystem.
So many things to untangle here.
Hi Alexei
thanks for taking the time to provide such detailed explanation.
The above paragraphs are misleading and incorrect. The commit log sounds like there are security issues that this patch set is fixing. This is not true.
I reiterate the goal: enforce a mandatory policy with an out-of-tree LSM (a kernel module is fine), with the same guarantees of LSMs integrated in the security subsystem.
The root user is not part of the TCB (i.e. is untrusted), all the changes that user wants to make must be subject of decision by the LSM enforcing the mandatory policy.
I thought about adding support for LSMs from kernel modules via a new built-in LSM (called LoadLSM), but to me it looks that the bpf LSM is closer to achieve the same goal. And in addition, eBPF significantly simplifies with its helpers writing an LSM.
Looks like there is a massive misunderstanding on what bpffs is. It's a file system to pin and get bpf objects with normal file access permissions. Nothing else. Do NOT use it to pin LSM or any other security sensitive bpf programs and then complain that root can unpin them. Yes. Root can and should be able to 'rm -rf' anything in bpffs instance.
The usability problems are:
- only a fixed amount of links can be pinned;
where do you see this limit?
static int populate_bpffs(struct dentry *parent) { struct bpf_preload_info objs[BPF_PRELOAD_LINKS] = {};
#define BPF_PRELOAD_LINKS 2
- only links can be pinned, other object types are not supported;
really? progs, maps can be pinned as well.
struct bpf_preload_info { char link_name[16]; struct bpf_link *link; };
- code to pin objects has to be written manually;
huh?
I meant if you want to extend the bpf_preload kernel module.
Solve the security problems by mounting the bpf filesystem from the
kernel,
by preloading authenticated kernel modules (e.g. with
module.sig_enforce)
and by pinning objects to that filesystem. This particular filesystem instance guarantees that desired eBPF programs run until the very end of the kernel lifecycle, since even root cannot interfere with it.
No.
Ok. How can the goal I stated above be achieved properly?
I suspect there is huge confusion on what these two "progs.debug" and "maps.debug" files are in a bpffs instance. They are debug files to pretty pring loaded maps and progs for folks who like to use 'cat' to examine the state of the system instead of 'bpftool'. The root can remove these files from bpffs.
There is no reason for kernel module to pin its bpf progs. If you want to develop DIGLIM as a kernel module that uses light skeleton just do: #include <linux/init.h> #include <linux/module.h> #include "diglim.lskel.h"
static struct diglim_bpf *skel;
static int __init load(void) { skel = diglim_bpf__open_and_load(); err = diglim_bpf__attach(skel); } /* detach skel in __fini */
It's really that short.
Then you will be able to
- insmod diglim.ko -> will load and attach bpf progs.
- rmmod diglim -> will detach them.
root can stop the LSM without consulting the security policy. The goal of having root untrusted is not achieved.
Maybe there is another way to prevent unloading the kernel module. I didn't find it yet. If there was an LSM hook called when kernel modules are unloaded, that would be sufficient, I guess.
My point was that pinning progs seems to be the recommended way of keeping them running. Pinning them to unreachable inodes intuitively looked the way to go for achieving the stated goal. Or maybe I should just increment the reference count of links and don't decrement during an rmmod?
If there is something I'm missing, please let me know.
Thanks
Roberto
HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063 Managing Director: Li Peng, Zhong Ronghua
On Thu, Mar 31, 2022 at 08:25:22AM +0000, Roberto Sassu wrote:
From: Alexei Starovoitov [mailto:alexei.starovoitov@gmail.com] Sent: Thursday, March 31, 2022 4:27 AM On Mon, Mar 28, 2022 at 07:50:15PM +0200, Roberto Sassu wrote:
eBPF already allows programs to be preloaded and kept running without intervention from user space. There is a dedicated kernel module called bpf_preload, which contains the light skeleton of the iterators_bpf eBPF program. If this module is enabled in the kernel configuration, its loading will be triggered when the bpf filesystem is mounted (unless the module is built-in), and the links of iterators_bpf are pinned in that filesystem (they will appear as the progs.debug and maps.debug files).
However, the current mechanism, if used to preload an LSM, would not
offer
the same security guarantees of LSMs integrated in the security
subsystem.
Also, it is not generic enough to be used for preloading arbitrary eBPF programs, unless the bpf_preload code is heavily modified.
More specifically, the security problems are:
- any program can be pinned to the bpf filesystem without limitations (unless a MAC mechanism enforces some restrictions);
- programs being executed can be terminated at any time by deleting the pinned objects or unmounting the bpf filesystem.
So many things to untangle here.
Hi Alexei
thanks for taking the time to provide such detailed explanation.
The above paragraphs are misleading and incorrect. The commit log sounds like there are security issues that this patch set is fixing. This is not true.
I reiterate the goal: enforce a mandatory policy with an out-of-tree LSM (a kernel module is fine), with the same guarantees of LSMs integrated in the security subsystem.
To make it 100% clear: Any in-kernel feature that benefits out-of-tree module will be rejected.
The root user is not part of the TCB (i.e. is untrusted), all the changes that user wants to make must be subject of decision by the LSM enforcing the mandatory policy.
I thought about adding support for LSMs from kernel modules via a new built-in LSM (called LoadLSM), but
Such approach will be rejected. See above.
I suspect there is huge confusion on what these two "progs.debug" and "maps.debug" files are in a bpffs instance. They are debug files to pretty pring loaded maps and progs for folks who like to use 'cat' to examine the state of the system instead of 'bpftool'. The root can remove these files from bpffs.
There is no reason for kernel module to pin its bpf progs. If you want to develop DIGLIM as a kernel module that uses light skeleton just do: #include <linux/init.h> #include <linux/module.h> #include "diglim.lskel.h"
static struct diglim_bpf *skel;
static int __init load(void) { skel = diglim_bpf__open_and_load(); err = diglim_bpf__attach(skel); } /* detach skel in __fini */
It's really that short.
Then you will be able to
- insmod diglim.ko -> will load and attach bpf progs.
- rmmod diglim -> will detach them.
root can stop the LSM without consulting the security policy. The goal of having root untrusted is not achieved.
Out-of-tree module can do any hack. For example: 1. don't do detach skel in __fini rmmod will remove the module, but bpf progs will keep running. 2. do module_get(THIS_MODULE) in __init rmmod will return EBUSY and have some out-of-band way of dropping mod refcnt. 3. hack into sys_delete_module. if module_name==diglem return EBUSY. 4. add proper LSM hook to delete_module
My point was that pinning progs seems to be the recommended way of keeping them running.
Not quite. bpf_link refcnt is what keeps progs attached. bpffs is mainly used for: - to pass maps/links from one process to another when passing fd is not possible. - to solve the case of crashing user space. The user space agent will restart and will pick up where it's left by reading map, link, prog FDs from bpffs. - pinning bpf iterators that are later used to 'cat' such files. That is what bpf_preload is doing by creating two debug files "maps.debug" and "progs.debug".
Pinning them to unreachable inodes intuitively looked the way to go for achieving the stated goal.
We can consider inodes in bpffs that are not unlinkable by root in the future, but certainly not for this use case.
Or maybe I should just increment the reference count of links and don't decrement during an rmmod?
I suggest to abandon out-of-tree goal. Only then we can help and continue this discussion.
On Sat, Apr 2, 2022 at 1:55 AM Alexei Starovoitov alexei.starovoitov@gmail.com wrote:
On Thu, Mar 31, 2022 at 08:25:22AM +0000, Roberto Sassu wrote:
From: Alexei Starovoitov [mailto:alexei.starovoitov@gmail.com] Sent: Thursday, March 31, 2022 4:27 AM On Mon, Mar 28, 2022 at 07:50:15PM +0200, Roberto Sassu wrote:
eBPF already allows programs to be preloaded and kept running without intervention from user space. There is a dedicated kernel module called bpf_preload, which contains the light skeleton of the iterators_bpf eBPF program. If this module is enabled in the kernel configuration, its loading will be triggered when the bpf filesystem is mounted (unless the module is built-in), and the links of iterators_bpf are pinned in that filesystem (they will appear as the progs.debug and maps.debug files).
However, the current mechanism, if used to preload an LSM, would not
offer
the same security guarantees of LSMs integrated in the security
subsystem.
Also, it is not generic enough to be used for preloading arbitrary eBPF programs, unless the bpf_preload code is heavily modified.
More specifically, the security problems are:
- any program can be pinned to the bpf filesystem without limitations (unless a MAC mechanism enforces some restrictions);
- programs being executed can be terminated at any time by deleting the pinned objects or unmounting the bpf filesystem.
So many things to untangle here.
Hi Alexei
thanks for taking the time to provide such detailed explanation.
The above paragraphs are misleading and incorrect. The commit log sounds like there are security issues that this patch set is fixing. This is not true.
+1 these are not security issues. They are limitations of your MAC policy.
I reiterate the goal: enforce a mandatory policy with an out-of-tree LSM (a kernel module is fine), with the same guarantees of LSMs integrated in the security subsystem.
To make it 100% clear: Any in-kernel feature that benefits out-of-tree module will be rejected.
The root user is not part of the TCB (i.e. is untrusted), all the changes that user wants to make must be subject of decision by the LSM enforcing the mandatory policy.
I thought about adding support for LSMs from kernel modules via a new built-in LSM (called LoadLSM), but
Kernel modules cannot implement LSMs, this has already been proposed on the lists and has been rejected.
Such approach will be rejected. See above.
I suspect there is huge confusion on what these two "progs.debug" and "maps.debug" files are in a bpffs instance. They are debug files to pretty pring loaded maps and progs for folks who like to use 'cat' to examine the state of the system instead of 'bpftool'. The root can remove these files from bpffs.
There is no reason for kernel module to pin its bpf progs. If you want to develop DIGLIM as a kernel module that uses light skeleton just do: #include <linux/init.h> #include <linux/module.h> #include "diglim.lskel.h"
static struct diglim_bpf *skel;
static int __init load(void) { skel = diglim_bpf__open_and_load(); err = diglim_bpf__attach(skel); } /* detach skel in __fini */
It's really that short.
Then you will be able to
- insmod diglim.ko -> will load and attach bpf progs.
- rmmod diglim -> will detach them.
root can stop the LSM without consulting the security policy. The goal of having root untrusted is not achieved.
Ofcourse, this is an issue, if you are using BPF to define a MAC policy, the policy needs to be comprehensive to prevent itself from being overridden. This is why We have so many LSM hooks. If you think some are missing, let's add them.
This is why implementing a policy is not trivial, but we need to allow users to build such policies with the help from the kernel and not by using out-of-tree modules.
I do think we can add some more helpers (e.g. for modifying xattrs from BPF) that would help us build complex policies.
Out-of-tree module can do any hack. For example:
- don't do detach skel in __fini
rmmod will remove the module, but bpf progs will keep running. 2. do module_get(THIS_MODULE) in __init rmmod will return EBUSY and have some out-of-band way of dropping mod refcnt. 3. hack into sys_delete_module. if module_name==diglem return EBUSY. 4. add proper LSM hook to delete_module
+1 I recommend this (but not from an out of tree module)
My point was that pinning progs seems to be the recommended way of keeping them running.
Not quite. bpf_link refcnt is what keeps progs attached. bpffs is mainly used for:
- to pass maps/links from one process to another
when passing fd is not possible.
- to solve the case of crashing user space.
The user space agent will restart and will pick up where it's left by reading map, link, prog FDs from bpffs.
- pinning bpf iterators that are later used to 'cat' such files.
That is what bpf_preload is doing by creating two debug files "maps.debug" and "progs.debug".
Pinning them to unreachable inodes intuitively looked the way to go for achieving the stated goal.
We can consider inodes in bpffs that are not unlinkable by root in the future, but certainly not for this use case.
Can this not be already done by adding a BPF_LSM program to the inode_unlink LSM hook?
Or maybe I should just increment the reference count of links and don't decrement during an rmmod?
I suggest to abandon out-of-tree goal. Only then we can help and continue this discussion.
+1
On Sun, Apr 3, 2022 at 5:42 PM KP Singh kpsingh@kernel.org wrote:
On Sat, Apr 2, 2022 at 1:55 AM Alexei Starovoitov alexei.starovoitov@gmail.com wrote:
...
Pinning them to unreachable inodes intuitively looked the way to go for achieving the stated goal.
We can consider inodes in bpffs that are not unlinkable by root in the future, but certainly not for this use case.
Can this not be already done by adding a BPF_LSM program to the inode_unlink LSM hook?
Also, beside of the inode_unlink... and out of curiosity: making sysfs/bpffs/ readonly after pinning, then using bpf LSM hooks sb_mount|remount|unmount... family combining bpf() LSM hook... isn't this enough to: 1. Restrict who can pin to bpffs without using a full MAC 2. Restrict who can delete or unmount bpf filesystem
?
From: Djalal Harouni [mailto:tixxdz@gmail.com] Sent: Monday, April 4, 2022 9:45 AM On Sun, Apr 3, 2022 at 5:42 PM KP Singh kpsingh@kernel.org wrote:
On Sat, Apr 2, 2022 at 1:55 AM Alexei Starovoitov alexei.starovoitov@gmail.com wrote:
...
Pinning them to unreachable inodes intuitively looked the way to go for achieving the stated goal.
We can consider inodes in bpffs that are not unlinkable by root in the future, but certainly not for this use case.
Can this not be already done by adding a BPF_LSM program to the inode_unlink LSM hook?
Also, beside of the inode_unlink... and out of curiosity: making sysfs/bpffs/ readonly after pinning, then using bpf LSM hooks sb_mount|remount|unmount... family combining bpf() LSM hook... isn't this enough to:
- Restrict who can pin to bpffs without using a full MAC
- Restrict who can delete or unmount bpf filesystem
?
I'm thinking to implement something like this.
First, I add a new program flag called BPF_F_STOP_ONCONFIRM, which causes the ref count of the link to increase twice at creation time. In this way, user space cannot make the link disappear, unless a confirmation is explicitly sent via the bpf() system call.
Another advantage is that other LSMs can decide whether or not they allow a program with this flag (in the bpf security hook).
This would work regardless of the method used to load the eBPF program (user space or kernel space).
Second, I extend the bpf() system call with a new subcommand, BPF_LINK_CONFIRM_STOP, which decreases the ref count for the link of the programs with the BPF_F_STOP_ONCONFIRM flag. I will also introduce a new security hook (something like security_link_confirm_stop), so that an LSM has the opportunity to deny the stop (the bpf security hook would not be sufficient to determine exactly for which link the confirmation is given, an LSM should be able to deny the stop for its own programs).
What do you think?
Thanks
Roberto
HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063 Managing Director: Li Peng, Zhong Ronghua
On Mon, Apr 4, 2022 at 10:21 AM Roberto Sassu roberto.sassu@huawei.com wrote:
From: Djalal Harouni [mailto:tixxdz@gmail.com] Sent: Monday, April 4, 2022 9:45 AM On Sun, Apr 3, 2022 at 5:42 PM KP Singh kpsingh@kernel.org wrote:
On Sat, Apr 2, 2022 at 1:55 AM Alexei Starovoitov alexei.starovoitov@gmail.com wrote:
...
Pinning them to unreachable inodes intuitively looked the way to go for achieving the stated goal.
We can consider inodes in bpffs that are not unlinkable by root in the future, but certainly not for this use case.
Can this not be already done by adding a BPF_LSM program to the inode_unlink LSM hook?
Also, beside of the inode_unlink... and out of curiosity: making sysfs/bpffs/ readonly after pinning, then using bpf LSM hooks sb_mount|remount|unmount... family combining bpf() LSM hook... isn't this enough to:
- Restrict who can pin to bpffs without using a full MAC
- Restrict who can delete or unmount bpf filesystem
?
I'm thinking to implement something like this.
First, I add a new program flag called BPF_F_STOP_ONCONFIRM, which causes the ref count of the link to increase twice at creation time. In this way, user space cannot make the link disappear, unless a confirmation is explicitly sent via the bpf() system call.
Another advantage is that other LSMs can decide whether or not they allow a program with this flag (in the bpf security hook).
This would work regardless of the method used to load the eBPF program (user space or kernel space).
Second, I extend the bpf() system call with a new subcommand, BPF_LINK_CONFIRM_STOP, which decreases the ref count for the link of the programs with the BPF_F_STOP_ONCONFIRM flag. I will also introduce a new security hook (something like security_link_confirm_stop), so that an LSM has the opportunity to deny the stop (the bpf security hook would not be sufficient to determine exactly for which link the confirmation is given, an LSM should be able to deny the stop for its own programs).
What do you think?
Hack upon a hack? Makes no sense.
On Tue, Apr 5, 2022 at 12:49 AM Alexei Starovoitov alexei.starovoitov@gmail.com wrote:
On Mon, Apr 4, 2022 at 10:21 AM Roberto Sassu roberto.sassu@huawei.com wrote:
From: Djalal Harouni [mailto:tixxdz@gmail.com] Sent: Monday, April 4, 2022 9:45 AM On Sun, Apr 3, 2022 at 5:42 PM KP Singh kpsingh@kernel.org wrote:
On Sat, Apr 2, 2022 at 1:55 AM Alexei Starovoitov alexei.starovoitov@gmail.com wrote:
...
Pinning them to unreachable inodes intuitively looked the way to go for achieving the stated goal.
We can consider inodes in bpffs that are not unlinkable by root in the future, but certainly not for this use case.
Can this not be already done by adding a BPF_LSM program to the inode_unlink LSM hook?
Also, beside of the inode_unlink... and out of curiosity: making sysfs/bpffs/ readonly after pinning, then using bpf LSM hooks sb_mount|remount|unmount... family combining bpf() LSM hook... isn't this enough to:
- Restrict who can pin to bpffs without using a full MAC
- Restrict who can delete or unmount bpf filesystem
I like this approach better, you will have to restrict the BPF, if you want to implement MAC policy using BPF.
Can you please try implementing something using these hooks?
?
I'm thinking to implement something like this.
First, I add a new program flag called BPF_F_STOP_ONCONFIRM, which causes the ref count of the link to increase twice at creation time. In this way, user space cannot make the link disappear, unless a confirmation is explicitly sent via the bpf() system call.
I don't like this approach, this just sounds like an intentional dangling reference, prone to refcounting errors and it does not really solve the purpose you want to achieve.
And you will still need a policy around the BPF syscall, so why not just use the LSM hooks as suggested above?
Another advantage is that other LSMs can decide whether or not they allow a program with this flag (in the bpf security hook).
This would work regardless of the method used to load the eBPF program (user space or kernel space).
Second, I extend the bpf() system call with a new subcommand, BPF_LINK_CONFIRM_STOP, which decreases the ref count for the link of the programs with the BPF_F_STOP_ONCONFIRM flag. I will also introduce a new security hook (something like security_link_confirm_stop), so that an LSM has the opportunity to deny the stop (the bpf security hook would not be sufficient to determine exactly for which link the confirmation is given, an LSM should be able to deny the stop for its own programs).
What do you think?
Hack upon a hack? Makes no sense.
Introduce a new LSM to protect pinned objects in a bpf filesystem instance. This is useful for example to ensure that an LSM will always enforce its policy, even despite root tries to unload the corresponding eBPF program.
Achieve the protection by denying inode unlink and unmount of the protected bpf filesystem instance. Since protected inodes hold a reference of the link of loaded programs (e.g. LSM hooks), denying operations on them will prevent the ref count of the links from reaching zero, ensuring that the programs remain always active.
Enable the protection only for the instance created by the user space counterpart of the LSM, and don't interfere with other instances, so that their behavior remains unchanged.
Suggested-by: Djalal Harouni tixxdz@gmail.com Signed-off-by: Roberto Sassu roberto.sassu@huawei.com --- .gitignore | 4 +++ Makefile | 18 ++++++++++++++ bpffs_lsm_kern.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ bpffs_lsm_user.c | 60 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 145 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 bpffs_lsm_kern.c create mode 100644 bpffs_lsm_user.c
diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000000..7fa02964f1dc --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.o +vmlinux.h +bpffs_lsm_kern.skel.h +bpffs_lsm_user diff --git a/Makefile b/Makefile new file mode 100644 index 000000000000..c3d805759db3 --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0 +all: bpffs_lsm_user + +clean: + rm -rf bpffs_lsm.skel.h vmlinux.h bpffs_lsm_kern.o bpffs_lsm_user + +vmlinux.h: + /usr/sbin/bpftool btf dump file /sys/kernel/btf/vmlinux format c > \ + vmlinux.h + +bpffs_lsm_kern.skel.h: bpffs_lsm_kern.o + bpftool gen skeleton $< > $@ + +bpffs_lsm_kern.o: bpffs_lsm_kern.c vmlinux.h + clang -Wall -Werror -g -O2 -target bpf -c $< -o $@ + +bpffs_lsm_user: bpffs_lsm_user.c bpffs_lsm_kern.skel.h bpffs_lsm_kern.o + cc -Wall -Werror -g -o $@ $< -lbpf diff --git a/bpffs_lsm_kern.c b/bpffs_lsm_kern.c new file mode 100644 index 000000000000..b3ccb2a75c95 --- /dev/null +++ b/bpffs_lsm_kern.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH + * + * Authors: + * Roberto Sassu roberto.sassu@huawei.com + * + * Implement an LSM to protect a bpf filesystem instance. + */ + +#include "vmlinux.h" +#include <errno.h> +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_tracing.h> +#include <bpf/bpf_core_read.h> + +char _license[] SEC("license") = "GPL"; + +uint32_t monitored_pid = 0; + +struct { + __uint(type, BPF_MAP_TYPE_INODE_STORAGE); + __uint(map_flags, BPF_F_NO_PREALLOC); + __type(key, int); + __type(value, sizeof(uint8_t)); +} inode_storage_map SEC(".maps"); + +SEC("lsm/sb_set_mnt_opts") +int BPF_PROG(sb_set_mnt_opts, struct super_block *sb, void *mnt_opts, + unsigned long kern_flags, unsigned long *set_kern_flags) +{ + u32 pid; + + pid = bpf_get_current_pid_tgid() >> 32; + if (pid != monitored_pid) + return 0; + + if (!bpf_inode_storage_get(&inode_storage_map, sb->s_root->d_inode, 0, + BPF_LOCAL_STORAGE_GET_F_CREATE)) + return -EPERM; + + return 0; +} + +SEC("lsm/inode_unlink") +int BPF_PROG(inode_unlink, struct inode *dir, struct dentry *dentry) +{ + if (bpf_inode_storage_get(&inode_storage_map, + dir->i_sb->s_root->d_inode, 0, 0)) + return -EPERM; + + return 0; +} + +SEC("lsm/sb_umount") +int BPF_PROG(sb_umount, struct vfsmount *mnt, int flags) +{ + if (bpf_inode_storage_get(&inode_storage_map, + mnt->mnt_sb->s_root->d_inode, 0, 0)) + return -EPERM; + + return 0; +} diff --git a/bpffs_lsm_user.c b/bpffs_lsm_user.c new file mode 100644 index 000000000000..e20180cc5db9 --- /dev/null +++ b/bpffs_lsm_user.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH + * + * Author: Roberto Sassu roberto.sassu@huawei.com + * + * Implement the user space side of the LSM for bpffs. + */ + +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <limits.h> +#include <sys/mount.h> +#include <sys/stat.h> + +#include "bpffs_lsm_kern.skel.h" + +#define MOUNT_FLAGS (MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME) + +int main(int argc, char *argv[]) +{ + char mntpoint[] = "/tmp/bpf_private_mountXXXXXX"; + char path[PATH_MAX]; + struct bpffs_lsm_kern *skel; + int ret, i; + + skel = bpffs_lsm_kern__open_and_load(); + if (!skel) + return -EINVAL; + + ret = bpffs_lsm_kern__attach(skel); + if (ret < 0) + goto out_destroy; + + mkdtemp(mntpoint); + + skel->bss->monitored_pid = getpid(); + ret = mount(mntpoint, mntpoint, "bpf", MOUNT_FLAGS, NULL); + skel->bss->monitored_pid = 0; + + if (ret < 0) + goto out_destroy; + + for (i = 0; i < skel->skeleton->prog_cnt; i++) { + snprintf(path, sizeof(path), "%s/%s", mntpoint, + skel->skeleton->progs[i].name); + ret = bpf_link__pin(*skel->skeleton->progs[i].link, path); + if (ret < 0) + goto out_destroy; + } + + ret = 0; +out_destroy: + bpffs_lsm_kern__destroy(skel); + return ret; +}
On 4/5/2022 6:11 AM, Roberto Sassu wrote:
Introduce a new LSM to protect pinned objects in a bpf filesystem
This is *not an LSM*. Do not call it an LSM. It is a set of eBPF programs. We have all the opportunities for confusion that we need. I suggested that you call this a BPF security module (BSM) earlier today. You have any number of things you can call this that won't be objectionable.
instance. This is useful for example to ensure that an LSM will always enforce its policy, even despite root tries to unload the corresponding eBPF program.
How is this going to ensure that SELinux enforces its policy? AppArmor has no eBPF program that corresponds to its policy, neither does any other existing LSM, save BPF. Your claim is nonsensical in the face of LSM behavior.
Achieve the protection by denying inode unlink and unmount of the protected bpf filesystem instance. Since protected inodes hold a reference of the link of loaded programs (e.g. LSM hooks), denying operations on them will prevent the ref count of the links from reaching zero, ensuring that the programs remain always active.
Enable the protection only for the instance created by the user space counterpart of the LSM, and don't interfere with other instances, so that their behavior remains unchanged.
Suggested-by: Djalal Harouni tixxdz@gmail.com Signed-off-by: Roberto Sassu roberto.sassu@huawei.com
.gitignore | 4 +++ Makefile | 18 ++++++++++++++ bpffs_lsm_kern.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ bpffs_lsm_user.c | 60 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 145 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 bpffs_lsm_kern.c create mode 100644 bpffs_lsm_user.c
diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000000..7fa02964f1dc --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.o +vmlinux.h +bpffs_lsm_kern.skel.h +bpffs_lsm_user diff --git a/Makefile b/Makefile new file mode 100644 index 000000000000..c3d805759db3 --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0 +all: bpffs_lsm_user
+clean:
- rm -rf bpffs_lsm.skel.h vmlinux.h bpffs_lsm_kern.o bpffs_lsm_user
+vmlinux.h:
- /usr/sbin/bpftool btf dump file /sys/kernel/btf/vmlinux format c > \
vmlinux.h
+bpffs_lsm_kern.skel.h: bpffs_lsm_kern.o
- bpftool gen skeleton $< > $@
+bpffs_lsm_kern.o: bpffs_lsm_kern.c vmlinux.h
- clang -Wall -Werror -g -O2 -target bpf -c $< -o $@
+bpffs_lsm_user: bpffs_lsm_user.c bpffs_lsm_kern.skel.h bpffs_lsm_kern.o
- cc -Wall -Werror -g -o $@ $< -lbpf
diff --git a/bpffs_lsm_kern.c b/bpffs_lsm_kern.c new file mode 100644 index 000000000000..b3ccb2a75c95 --- /dev/null +++ b/bpffs_lsm_kern.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH
- Authors:
- Roberto Sassu roberto.sassu@huawei.com
- Implement an LSM to protect a bpf filesystem instance.
- */
+#include "vmlinux.h" +#include <errno.h> +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_tracing.h> +#include <bpf/bpf_core_read.h>
+char _license[] SEC("license") = "GPL";
+uint32_t monitored_pid = 0;
+struct {
- __uint(type, BPF_MAP_TYPE_INODE_STORAGE);
- __uint(map_flags, BPF_F_NO_PREALLOC);
- __type(key, int);
- __type(value, sizeof(uint8_t));
+} inode_storage_map SEC(".maps");
+SEC("lsm/sb_set_mnt_opts") +int BPF_PROG(sb_set_mnt_opts, struct super_block *sb, void *mnt_opts,
unsigned long kern_flags, unsigned long *set_kern_flags)
+{
- u32 pid;
- pid = bpf_get_current_pid_tgid() >> 32;
- if (pid != monitored_pid)
return 0;
- if (!bpf_inode_storage_get(&inode_storage_map, sb->s_root->d_inode, 0,
BPF_LOCAL_STORAGE_GET_F_CREATE))
return -EPERM;
- return 0;
+}
+SEC("lsm/inode_unlink") +int BPF_PROG(inode_unlink, struct inode *dir, struct dentry *dentry) +{
- if (bpf_inode_storage_get(&inode_storage_map,
dir->i_sb->s_root->d_inode, 0, 0))
return -EPERM;
- return 0;
+}
+SEC("lsm/sb_umount") +int BPF_PROG(sb_umount, struct vfsmount *mnt, int flags) +{
- if (bpf_inode_storage_get(&inode_storage_map,
mnt->mnt_sb->s_root->d_inode, 0, 0))
return -EPERM;
- return 0;
+} diff --git a/bpffs_lsm_user.c b/bpffs_lsm_user.c new file mode 100644 index 000000000000..e20180cc5db9 --- /dev/null +++ b/bpffs_lsm_user.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH
- Author: Roberto Sassu roberto.sassu@huawei.com
- Implement the user space side of the LSM for bpffs.
- */
+#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <limits.h> +#include <sys/mount.h> +#include <sys/stat.h>
+#include "bpffs_lsm_kern.skel.h"
+#define MOUNT_FLAGS (MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME)
+int main(int argc, char *argv[]) +{
- char mntpoint[] = "/tmp/bpf_private_mountXXXXXX";
- char path[PATH_MAX];
- struct bpffs_lsm_kern *skel;
- int ret, i;
- skel = bpffs_lsm_kern__open_and_load();
- if (!skel)
return -EINVAL;
- ret = bpffs_lsm_kern__attach(skel);
- if (ret < 0)
goto out_destroy;
- mkdtemp(mntpoint);
- skel->bss->monitored_pid = getpid();
- ret = mount(mntpoint, mntpoint, "bpf", MOUNT_FLAGS, NULL);
- skel->bss->monitored_pid = 0;
- if (ret < 0)
goto out_destroy;
- for (i = 0; i < skel->skeleton->prog_cnt; i++) {
snprintf(path, sizeof(path), "%s/%s", mntpoint,
skel->skeleton->progs[i].name);
ret = bpf_link__pin(*skel->skeleton->progs[i].link, path);
if (ret < 0)
goto out_destroy;
- }
- ret = 0;
+out_destroy:
- bpffs_lsm_kern__destroy(skel);
- return ret;
+}
From: Casey Schaufler [mailto:casey@schaufler-ca.com] Sent: Wednesday, April 6, 2022 12:48 AM On 4/5/2022 6:11 AM, Roberto Sassu wrote:
Introduce a new LSM to protect pinned objects in a bpf filesystem
This is *not an LSM*. Do not call it an LSM. It is a set of eBPF programs. We have all the opportunities for confusion that we need. I suggested that you call this a BPF security module (BSM) earlier today. You have any number of things you can call this that won't be objectionable.
instance. This is useful for example to ensure that an LSM will always enforce its policy, even despite root tries to unload the corresponding eBPF program.
How is this going to ensure that SELinux enforces its policy?
I should have said above: that an LSM implemented with eBPF. Built-in LSMs are not affected by this change.
Ok, next time I call it BSM.
Thanks
Roberto
HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063 Managing Director: Li Peng, Zhong Ronghua
AppArmor has no eBPF program that corresponds to its policy, neither does any other existing LSM, save BPF. Your claim is nonsensical in the face of LSM behavior.
Achieve the protection by denying inode unlink and unmount of the protected bpf filesystem instance. Since protected inodes hold a reference of the link of loaded programs (e.g. LSM hooks), denying operations on them will prevent the ref count of the links from reaching zero, ensuring that the programs remain always active.
Enable the protection only for the instance created by the user space counterpart of the LSM, and don't interfere with other instances, so that their behavior remains unchanged.
Suggested-by: Djalal Harouni tixxdz@gmail.com Signed-off-by: Roberto Sassu roberto.sassu@huawei.com
.gitignore | 4 +++ Makefile | 18 ++++++++++++++ bpffs_lsm_kern.c | 63
++++++++++++++++++++++++++++++++++++++++++++++++
bpffs_lsm_user.c | 60
+++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 145 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 bpffs_lsm_kern.c create mode 100644 bpffs_lsm_user.c
diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000000..7fa02964f1dc --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.o +vmlinux.h +bpffs_lsm_kern.skel.h +bpffs_lsm_user diff --git a/Makefile b/Makefile new file mode 100644 index 000000000000..c3d805759db3 --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0 +all: bpffs_lsm_user
+clean:
- rm -rf bpffs_lsm.skel.h vmlinux.h bpffs_lsm_kern.o bpffs_lsm_user
+vmlinux.h:
- /usr/sbin/bpftool btf dump file /sys/kernel/btf/vmlinux format c > \
vmlinux.h
+bpffs_lsm_kern.skel.h: bpffs_lsm_kern.o
- bpftool gen skeleton $< > $@
+bpffs_lsm_kern.o: bpffs_lsm_kern.c vmlinux.h
- clang -Wall -Werror -g -O2 -target bpf -c $< -o $@
+bpffs_lsm_user: bpffs_lsm_user.c bpffs_lsm_kern.skel.h
bpffs_lsm_kern.o
- cc -Wall -Werror -g -o $@ $< -lbpf
diff --git a/bpffs_lsm_kern.c b/bpffs_lsm_kern.c new file mode 100644 index 000000000000..b3ccb2a75c95 --- /dev/null +++ b/bpffs_lsm_kern.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH
- Authors:
- Roberto Sassu roberto.sassu@huawei.com
- Implement an LSM to protect a bpf filesystem instance.
- */
+#include "vmlinux.h" +#include <errno.h> +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_tracing.h> +#include <bpf/bpf_core_read.h>
+char _license[] SEC("license") = "GPL";
+uint32_t monitored_pid = 0;
+struct {
- __uint(type, BPF_MAP_TYPE_INODE_STORAGE);
- __uint(map_flags, BPF_F_NO_PREALLOC);
- __type(key, int);
- __type(value, sizeof(uint8_t));
+} inode_storage_map SEC(".maps");
+SEC("lsm/sb_set_mnt_opts") +int BPF_PROG(sb_set_mnt_opts, struct super_block *sb, void
*mnt_opts,
unsigned long kern_flags, unsigned long *set_kern_flags)
+{
- u32 pid;
- pid = bpf_get_current_pid_tgid() >> 32;
- if (pid != monitored_pid)
return 0;
- if (!bpf_inode_storage_get(&inode_storage_map, sb->s_root-
d_inode, 0,
BPF_LOCAL_STORAGE_GET_F_CREATE))
return -EPERM;
- return 0;
+}
+SEC("lsm/inode_unlink") +int BPF_PROG(inode_unlink, struct inode *dir, struct dentry *dentry) +{
- if (bpf_inode_storage_get(&inode_storage_map,
dir->i_sb->s_root->d_inode, 0, 0))
return -EPERM;
- return 0;
+}
+SEC("lsm/sb_umount") +int BPF_PROG(sb_umount, struct vfsmount *mnt, int flags) +{
- if (bpf_inode_storage_get(&inode_storage_map,
mnt->mnt_sb->s_root->d_inode, 0, 0))
return -EPERM;
- return 0;
+} diff --git a/bpffs_lsm_user.c b/bpffs_lsm_user.c new file mode 100644 index 000000000000..e20180cc5db9 --- /dev/null +++ b/bpffs_lsm_user.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH
- Author: Roberto Sassu roberto.sassu@huawei.com
- Implement the user space side of the LSM for bpffs.
- */
+#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <limits.h> +#include <sys/mount.h> +#include <sys/stat.h>
+#include "bpffs_lsm_kern.skel.h"
+#define MOUNT_FLAGS (MS_NOSUID | MS_NODEV | MS_NOEXEC |
MS_RELATIME)
+int main(int argc, char *argv[]) +{
- char mntpoint[] = "/tmp/bpf_private_mountXXXXXX";
- char path[PATH_MAX];
- struct bpffs_lsm_kern *skel;
- int ret, i;
- skel = bpffs_lsm_kern__open_and_load();
- if (!skel)
return -EINVAL;
- ret = bpffs_lsm_kern__attach(skel);
- if (ret < 0)
goto out_destroy;
- mkdtemp(mntpoint);
- skel->bss->monitored_pid = getpid();
- ret = mount(mntpoint, mntpoint, "bpf", MOUNT_FLAGS, NULL);
- skel->bss->monitored_pid = 0;
- if (ret < 0)
goto out_destroy;
- for (i = 0; i < skel->skeleton->prog_cnt; i++) {
snprintf(path, sizeof(path), "%s/%s", mntpoint,
skel->skeleton->progs[i].name);
ret = bpf_link__pin(*skel->skeleton->progs[i].link, path);
if (ret < 0)
goto out_destroy;
- }
- ret = 0;
+out_destroy:
- bpffs_lsm_kern__destroy(skel);
- return ret;
+}
On 4/4/2022 10:20 AM, Roberto Sassu wrote:
From: Djalal Harouni [mailto:tixxdz@gmail.com] Sent: Monday, April 4, 2022 9:45 AM On Sun, Apr 3, 2022 at 5:42 PM KP Singh kpsingh@kernel.org wrote:
On Sat, Apr 2, 2022 at 1:55 AM Alexei Starovoitov alexei.starovoitov@gmail.com wrote:
...
Pinning them to unreachable inodes intuitively looked the way to go for achieving the stated goal.
We can consider inodes in bpffs that are not unlinkable by root in the future, but certainly not for this use case.
Can this not be already done by adding a BPF_LSM program to the inode_unlink LSM hook?
Also, beside of the inode_unlink... and out of curiosity: making sysfs/bpffs/ readonly after pinning, then using bpf LSM hooks sb_mount|remount|unmount... family combining bpf() LSM hook... isn't this enough to:
- Restrict who can pin to bpffs without using a full MAC
- Restrict who can delete or unmount bpf filesystem
?
I'm thinking to implement something like this.
First, I add a new program flag called BPF_F_STOP_ONCONFIRM, which causes the ref count of the link to increase twice at creation time. In this way, user space cannot make the link disappear, unless a confirmation is explicitly sent via the bpf() system call.
Another advantage is that other LSMs can decide whether or not they allow a program with this flag (in the bpf security hook).
This would work regardless of the method used to load the eBPF program (user space or kernel space).
Second, I extend the bpf() system call with a new subcommand, BPF_LINK_CONFIRM_STOP, which decreasres the ref count for the link of the programs with the BPF_F_STOP_ONCONFIRM flag. I will also introduce a new security hook (something like security_link_confirm_stop), so that an LSM has the opportunity to deny the stop (the bpf security hook would not be sufficient to determine exactly for which link the confirmation is given, an LSM should be able to deny the stop for its own programs).
Would you please stop referring to a set of eBPF programs loaded into the BPF LSM as an LSM? Call it a BPF security module (BSM) if you must use an abbreviation. An LSM is a provider of security_ hooks. In your case that is BPF. When you call the set of eBPF programs an LSM it is like calling an SELinux policy an LSM.
What do you think?
Thanks
Roberto
HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063 Managing Director: Li Peng, Zhong Ronghua
From: Casey Schaufler [mailto:casey@schaufler-ca.com] Sent: Tuesday, April 5, 2022 4:50 PM On 4/4/2022 10:20 AM, Roberto Sassu wrote:
From: Djalal Harouni [mailto:tixxdz@gmail.com] Sent: Monday, April 4, 2022 9:45 AM On Sun, Apr 3, 2022 at 5:42 PM KP Singh kpsingh@kernel.org wrote:
On Sat, Apr 2, 2022 at 1:55 AM Alexei Starovoitov alexei.starovoitov@gmail.com wrote:
...
Pinning them to unreachable inodes intuitively looked the way to go for achieving the stated goal.
We can consider inodes in bpffs that are not unlinkable by root in the future, but certainly not for this use case.
Can this not be already done by adding a BPF_LSM program to the inode_unlink LSM hook?
Also, beside of the inode_unlink... and out of curiosity: making
sysfs/bpffs/
readonly after pinning, then using bpf LSM hooks sb_mount|remount|unmount... family combining bpf() LSM hook... isn't this enough to:
- Restrict who can pin to bpffs without using a full MAC
- Restrict who can delete or unmount bpf filesystem
?
I'm thinking to implement something like this.
First, I add a new program flag called BPF_F_STOP_ONCONFIRM, which causes the ref count of the link to increase twice at creation time. In this way, user space cannot make the link disappear, unless a confirmation is explicitly sent via the bpf() system call.
Another advantage is that other LSMs can decide whether or not they allow a program with this flag (in the bpf security hook).
This would work regardless of the method used to load the eBPF program (user space or kernel space).
Second, I extend the bpf() system call with a new subcommand, BPF_LINK_CONFIRM_STOP, which decreasres the ref count for the link of the programs with the BPF_F_STOP_ONCONFIRM flag. I will also introduce a new security hook (something like security_link_confirm_stop), so that an LSM has the opportunity to deny the stop (the bpf security hook would not be sufficient to determine exactly for which link the confirmation is given, an LSM should be able to deny the stop for its own programs).
Would you please stop referring to a set of eBPF programs loaded into the BPF LSM as an LSM? Call it a BPF security module (BSM) if you must use an abbreviation. An LSM is a provider of security_ hooks. In your case that is BPF. When you call the set of eBPF programs an LSM it is like calling an SELinux policy an LSM.
An eBPF program could be a provider of security_ hooks too. The bpf LSM is an aggregator, similarly to your infrastructure to manage built-in LSMs. Maybe, calling it second-level LSM or secondary LSM would better represent this new class.
The only differences are the registration method, (SEC directive instead of DEFINE_LSM), and what the hook implementation can access.
The implementation of a security_ hook via eBPF can follow the same structure of built-in LSMs, i.e. it can be uniquely responsible for enforcing and be policy-agnostic, and can retrieve the decisions based on a policy from a component implemented somewhere else.
Hopefully, I understood the basic principles correctly. I let the eBPF maintainers comment on this.
Thanks
Roberto
HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063 Managing Director: Li Peng, Zhong Ronghua
What do you think?
Thanks
Roberto
HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063 Managing Director: Li Peng, Zhong Ronghua
On 4/5/2022 8:29 AM, Roberto Sassu wrote:
From: Casey Schaufler [mailto:casey@schaufler-ca.com] Sent: Tuesday, April 5, 2022 4:50 PM On 4/4/2022 10:20 AM, Roberto Sassu wrote:
From: Djalal Harouni [mailto:tixxdz@gmail.com] Sent: Monday, April 4, 2022 9:45 AM On Sun, Apr 3, 2022 at 5:42 PM KP Singh kpsingh@kernel.org wrote:
On Sat, Apr 2, 2022 at 1:55 AM Alexei Starovoitov alexei.starovoitov@gmail.com wrote:
...
> Pinning > them to unreachable inodes intuitively looked the > way to go for achieving the stated goal. We can consider inodes in bpffs that are not unlinkable by root in the future, but certainly not for this use case.
Can this not be already done by adding a BPF_LSM program to the inode_unlink LSM hook?
Also, beside of the inode_unlink... and out of curiosity: making
sysfs/bpffs/
readonly after pinning, then using bpf LSM hooks sb_mount|remount|unmount... family combining bpf() LSM hook... isn't this enough to:
- Restrict who can pin to bpffs without using a full MAC
- Restrict who can delete or unmount bpf filesystem
?
I'm thinking to implement something like this.
First, I add a new program flag called BPF_F_STOP_ONCONFIRM, which causes the ref count of the link to increase twice at creation time. In this way, user space cannot make the link disappear, unless a confirmation is explicitly sent via the bpf() system call.
Another advantage is that other LSMs can decide whether or not they allow a program with this flag (in the bpf security hook).
This would work regardless of the method used to load the eBPF program (user space or kernel space).
Second, I extend the bpf() system call with a new subcommand, BPF_LINK_CONFIRM_STOP, which decreasres the ref count for the link of the programs with the BPF_F_STOP_ONCONFIRM flag. I will also introduce a new security hook (something like security_link_confirm_stop), so that an LSM has the opportunity to deny the stop (the bpf security hook would not be sufficient to determine exactly for which link the confirmation is given, an LSM should be able to deny the stop for its own programs).
Would you please stop referring to a set of eBPF programs loaded into the BPF LSM as an LSM? Call it a BPF security module (BSM) if you must use an abbreviation. An LSM is a provider of security_ hooks. In your case that is BPF. When you call the set of eBPF programs an LSM it is like calling an SELinux policy an LSM.
An eBPF program could be a provider of security_ hooks too.
No, it can't. If I look in /sys/kernel/security/lsm what you see is "bpf". The LSM is BPF. What BPF does in its hooks is up to it and its responsibility.
The bpf LSM is an aggregator, similarly to your infrastructure to manage built-in LSMs. Maybe, calling it second-level LSM or secondary LSM would better represent this new class.
It isn't an LSM, and adding a qualifier doesn't make it one and only adds to the confusion.
The only differences are the registration method, (SEC directive instead of DEFINE_LSM), and what the hook implementation can access.
Those two things pretty well define what an LSM is.
The implementation of a security_ hook via eBPF can follow the same structure of built-in LSMs, i.e. it can be uniquely responsible for enforcing and be policy-agnostic, and can retrieve the decisions based on a policy from a component implemented somewhere else.
The BPF LSM provides mechanism. The eBPF programs provide policy.
Hopefully, I understood the basic principles correctly. I let the eBPF maintainers comment on this.
Thanks
Roberto
HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063 Managing Director: Li Peng, Zhong Ronghua
What do you think?
Thanks
Roberto
HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063 Managing Director: Li Peng, Zhong Ronghua
On Tue, Apr 5, 2022 at 6:22 PM Casey Schaufler casey@schaufler-ca.com wrote:
On 4/5/2022 8:29 AM, Roberto Sassu wrote:
From: Casey Schaufler [mailto:casey@schaufler-ca.com] Sent: Tuesday, April 5, 2022 4:50 PM On 4/4/2022 10:20 AM, Roberto Sassu wrote:
From: Djalal Harouni [mailto:tixxdz@gmail.com] Sent: Monday, April 4, 2022 9:45 AM On Sun, Apr 3, 2022 at 5:42 PM KP Singh kpsingh@kernel.org wrote:
On Sat, Apr 2, 2022 at 1:55 AM Alexei Starovoitov alexei.starovoitov@gmail.com wrote:
...
>> Pinning >> them to unreachable inodes intuitively looked the >> way to go for achieving the stated goal. > We can consider inodes in bpffs that are not unlinkable by root > in the future, but certainly not for this use case. Can this not be already done by adding a BPF_LSM program to the inode_unlink LSM hook?
Also, beside of the inode_unlink... and out of curiosity: making
sysfs/bpffs/
readonly after pinning, then using bpf LSM hooks sb_mount|remount|unmount... family combining bpf() LSM hook... isn't this enough to:
- Restrict who can pin to bpffs without using a full MAC
- Restrict who can delete or unmount bpf filesystem
?
I'm thinking to implement something like this.
First, I add a new program flag called BPF_F_STOP_ONCONFIRM, which causes the ref count of the link to increase twice at creation time. In this way, user space cannot make the link disappear, unless a confirmation is explicitly sent via the bpf() system call.
Another advantage is that other LSMs can decide whether or not they allow a program with this flag (in the bpf security hook).
This would work regardless of the method used to load the eBPF program (user space or kernel space).
Second, I extend the bpf() system call with a new subcommand, BPF_LINK_CONFIRM_STOP, which decreasres the ref count for the link of the programs with the BPF_F_STOP_ONCONFIRM flag. I will also introduce a new security hook (something like security_link_confirm_stop), so that an LSM has the opportunity to deny the stop (the bpf security hook would not be sufficient to determine exactly for which link the confirmation is given, an LSM should be able to deny the stop for its own programs).
Would you please stop referring to a set of eBPF programs loaded into the BPF LSM as an LSM? Call it a BPF security module (BSM) if you must use an abbreviation. An LSM is a provider of security_ hooks. In your case that is BPF. When you call the set of eBPF programs an LSM it is like calling an SELinux policy an LSM.
An eBPF program could be a provider of security_ hooks too.
No, it can't. If I look in /sys/kernel/security/lsm what you see is "bpf". The LSM is BPF. What BPF does in its hooks is up to it and its responsibility.
The bpf LSM is an aggregator, similarly to your infrastructure to manage built-in LSMs. Maybe, calling it second-level LSM or secondary LSM would better represent this new class.
It isn't an LSM, and adding a qualifier doesn't make it one and only adds to the confusion.
The only differences are the registration method, (SEC directive instead of DEFINE_LSM), and what the hook implementation can access.
Those two things pretty well define what an LSM is.
The implementation of a security_ hook via eBPF can follow the same structure of built-in LSMs, i.e. it can be uniquely responsible for enforcing and be policy-agnostic, and can retrieve the decisions based on a policy from a component implemented somewhere else.
The BPF LSM provides mechanism. The eBPF programs provide policy.
Yeah, let's stick what we call an LSM in the kernel, Here, "bpf" is the LSM like selinux,apparmor and this is what you set in CONFIG_LSM or pass on cmdline as lsm= and can be seen in /sys/kernel/security/lsm
Calling your BPF programs an LSM will just confuse people.
Hopefully, I understood the basic principles correctly. I let the eBPF maintainers comment on this.
Thanks
Roberto
HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063 Managing Director: Li Peng, Zhong Ronghua
What do you think?
Thanks
Roberto
HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063 Managing Director: Li Peng, Zhong Ronghua
From: KP Singh [mailto:kpsingh@kernel.org] Sent: Saturday, April 2, 2022 3:03 AM On Sat, Apr 2, 2022 at 1:55 AM Alexei Starovoitov alexei.starovoitov@gmail.com wrote:
On Thu, Mar 31, 2022 at 08:25:22AM +0000, Roberto Sassu wrote:
From: Alexei Starovoitov [mailto:alexei.starovoitov@gmail.com] Sent: Thursday, March 31, 2022 4:27 AM On Mon, Mar 28, 2022 at 07:50:15PM +0200, Roberto Sassu wrote:
eBPF already allows programs to be preloaded and kept running
without
intervention from user space. There is a dedicated kernel module
called
bpf_preload, which contains the light skeleton of the iterators_bpf
eBPF
program. If this module is enabled in the kernel configuration, its
loading
will be triggered when the bpf filesystem is mounted (unless the
module is
built-in), and the links of iterators_bpf are pinned in that filesystem (they will appear as the progs.debug and maps.debug files).
However, the current mechanism, if used to preload an LSM, would
not
offer
the same security guarantees of LSMs integrated in the security
subsystem.
Also, it is not generic enough to be used for preloading arbitrary eBPF programs, unless the bpf_preload code is heavily modified.
More specifically, the security problems are:
- any program can be pinned to the bpf filesystem without limitations (unless a MAC mechanism enforces some restrictions);
- programs being executed can be terminated at any time by deleting
the
pinned objects or unmounting the bpf filesystem.
So many things to untangle here.
Hi Alexei
thanks for taking the time to provide such detailed explanation.
The above paragraphs are misleading and incorrect. The commit log sounds like there are security issues that this patch set is fixing. This is not true.
+1 these are not security issues. They are limitations of your MAC policy.
I reiterate the goal: enforce a mandatory policy with an out-of-tree LSM (a kernel module is fine), with the same guarantees of LSMs integrated in the security subsystem.
To make it 100% clear: Any in-kernel feature that benefits out-of-tree module will be rejected.
The root user is not part of the TCB (i.e. is untrusted), all the changes that user wants to make must be subject of decision by the LSM enforcing the mandatory policy.
I thought about adding support for LSMs from kernel modules via a new built-in LSM (called LoadLSM), but
Kernel modules cannot implement LSMs, this has already been proposed on the lists and has been rejected.
Looking at commit cb80ddc67152 ("bpf: Convert bpf_preload.ko to use light skeleton."), I got that it is the most efficient way to load an eBPF program (does not even require libbpf).
Another advantage was that we get integrity verification from the module infrastructure. This would have been the optimal solution in terms of dependencies. Enforcing integrity could be turned on with the module.sig_enforce kernel option.
If we switch to user space, the choice would be IMA. However, in my use case (DIGLIM) it would be used just for the purpose of doing integrity verifications pre-init.
Thinking which policy could be implemented for such purpose, maybe something like appraise every process that is not linked to an executable? And since there are no xattrs in the initial ram disk, could I append a module signature to an ELF binary?
Thanks
Roberto
HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063 Managing Director: Li Peng, Zhong Ronghua
Such approach will be rejected. See above.
I suspect there is huge confusion on what these two "progs.debug" and "maps.debug" files are in a bpffs instance. They are debug files to pretty pring loaded maps and progs for folks
who
like to use 'cat' to examine the state of the system instead of 'bpftool'. The root can remove these files from bpffs.
There is no reason for kernel module to pin its bpf progs. If you want to develop DIGLIM as a kernel module that uses light
skeleton
just do: #include <linux/init.h> #include <linux/module.h> #include "diglim.lskel.h"
static struct diglim_bpf *skel;
static int __init load(void) { skel = diglim_bpf__open_and_load(); err = diglim_bpf__attach(skel); } /* detach skel in __fini */
It's really that short.
Then you will be able to
- insmod diglim.ko -> will load and attach bpf progs.
- rmmod diglim -> will detach them.
root can stop the LSM without consulting the security policy. The goal of having root untrusted is not achieved.
Ofcourse, this is an issue, if you are using BPF to define a MAC policy, the policy needs to be comprehensive to prevent itself from being overridden. This is why We have so many LSM hooks. If you think some are missing, let's add them.
This is why implementing a policy is not trivial, but we need to allow users to build such policies with the help from the kernel and not by using out-of-tree modules.
I do think we can add some more helpers (e.g. for modifying xattrs from BPF) that would help us build complex policies.
Out-of-tree module can do any hack. For example:
- don't do detach skel in __fini
rmmod will remove the module, but bpf progs will keep running. 2. do module_get(THIS_MODULE) in __init rmmod will return EBUSY and have some out-of-band way of dropping mod refcnt. 3. hack into sys_delete_module. if module_name==diglem return EBUSY. 4. add proper LSM hook to delete_module
+1 I recommend this (but not from an out of tree module)
My point was that pinning progs seems to be the recommended way of keeping them running.
Not quite. bpf_link refcnt is what keeps progs attached. bpffs is mainly used for:
- to pass maps/links from one process to another
when passing fd is not possible.
- to solve the case of crashing user space.
The user space agent will restart and will pick up where it's left by reading map, link, prog FDs from bpffs.
- pinning bpf iterators that are later used to 'cat' such files.
That is what bpf_preload is doing by creating two debug files "maps.debug" and "progs.debug".
Pinning them to unreachable inodes intuitively looked the way to go for achieving the stated goal.
We can consider inodes in bpffs that are not unlinkable by root in the future, but certainly not for this use case.
Can this not be already done by adding a BPF_LSM program to the inode_unlink LSM hook?
Or maybe I should just increment the reference count of links and don't decrement during an rmmod?
I suggest to abandon out-of-tree goal. Only then we can help and continue this discussion.
+1
linux-kselftest-mirror@lists.linaro.org