diff mbox series

[14/18] bpf-preload: Switch to new preload registration method

Message ID 20220328175033.2437312-15-roberto.sassu@huawei.com (mailing list archive)
State New
Headers show
Series bpf: Secure and authenticated preloading of eBPF programs | expand

Commit Message

Roberto Sassu March 28, 2022, 5:50 p.m. UTC
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(-)

Comments

kernel test robot March 29, 2022, 2:35 a.m. UTC | #1
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-authenticated-preloading-of-eBPF-programs/20220329-015829
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@intel.com/config)
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/2e0e81b0296abc384efb2a73520ce03c2a5344ea
        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
kernel test robot March 29, 2022, 3:27 a.m. UTC | #2
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-authenticated-preloading-of-eBPF-programs/20220329-015829
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@intel.com/config)
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/2e0e81b0296abc384efb2a73520ce03c2a5344ea
        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
diff mbox series

Patch

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("\