modutils: support finit_module syscall
authorMike Frysinger <vapier@chromium.org>
Thu, 15 Sep 2016 10:16:33 +0000 (12:16 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Thu, 15 Sep 2016 10:16:33 +0000 (12:16 +0200)
On some systems like Chromium OS, loading modules from non-verified
filesystems is denied.  Only finit_module is allowed because an open
fd is passed which can be checked against a verified location.

Change the module loading code to first attempt finit_module and if
that fails for whatever reason, fall back to the existing logic.

On x86_64, this adds ~80 bytes to modutils/modutils.o and ~68 bytes
to modutils/modprobe-small.o.

Signed-off-by: Mike Frysinger <vapier@chromium.org>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
modutils/modprobe-small.c
modutils/modutils.c

index 5936e48cff7971a1945327c8084edb18478389de..a47e52234bdfb4eedada66f578a0e625a161c28e 100644 (file)
 /* After libbb.h, since it needs sys/types.h on some systems */
 #include <sys/utsname.h> /* uname() */
 #include <fnmatch.h>
+#include <sys/syscall.h>
 
 extern int init_module(void *module, unsigned long len, const char *options);
 extern int delete_module(const char *module, unsigned flags);
+#ifdef __NR_finit_module
+# define finit_module(fd, uargs, flags) syscall(__NR_finit_module, fd, uargs, flags)
+#endif
 /* linux/include/linux/module.h has limit of 64 chars on module names */
 #undef MODULE_NAME_LEN
 #define MODULE_NAME_LEN 64
@@ -209,11 +213,34 @@ static int load_module(const char *fname, const char *options)
        int r;
        size_t len = MAXINT(ssize_t);
        char *module_image;
+
+       if (!options)
+               options = "";
+
        dbg1_error_msg("load_module('%s','%s')", fname, options);
 
-       module_image = xmalloc_open_zipped_read_close(fname, &len);
-       r = (!module_image || init_module(module_image, len, options ? options : "") != 0);
-       free(module_image);
+       /*
+        * First we try finit_module if available.  Some kernels are configured
+        * to only allow loading of modules off of secure storage (like a read-
+        * only rootfs) which needs the finit_module call.  If it fails, we fall
+        * back to normal module loading to support compressed modules.
+        */
+       r = 1;
+# ifdef __NR_finit_module
+       {
+               int fd = open(fname, O_RDONLY | O_CLOEXEC);
+               if (fd >= 0) {
+                       r = finit_module(fd, options, 0) != 0;
+                       close(fd);
+               }
+       }
+# endif
+       if (r != 0) {
+               module_image = xmalloc_open_zipped_read_close(fname, &len);
+               r = (!module_image || init_module(module_image, len, options) != 0);
+               free(module_image);
+       }
+
        dbg1_error_msg("load_module:%d", r);
        return r; /* 0 = success */
 #else
index 0a056731d2ad805bffd51976945923e87e58459d..d36caaf68e300cdd5670f3445cb353cb40a66814 100644 (file)
@@ -13,6 +13,9 @@ extern int delete_module(const char *module, unsigned int flags);
 #else
 # include <sys/syscall.h>
 # define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts)
+# if defined(__NR_finit_module)
+#  define finit_module(fd, uargs, flags) syscall(__NR_finit_module, fd, uargs, flags)
+# endif
 # define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags)
 #endif
 
@@ -212,6 +215,24 @@ int FAST_FUNC bb_init_module(const char *filename, const char *options)
                return bb_init_module_24(filename, options);
 #endif
 
+       /*
+        * First we try finit_module if available.  Some kernels are configured
+        * to only allow loading of modules off of secure storage (like a read-
+        * only rootfs) which needs the finit_module call.  If it fails, we fall
+        * back to normal module loading to support compressed modules.
+        */
+# ifdef __NR_finit_module
+       {
+               int fd = open(filename, O_RDONLY | O_CLOEXEC);
+               if (fd >= 0) {
+                       rc = finit_module(fd, options, 0) != 0;
+                       close(fd);
+                       if (rc == 0)
+                               return rc;
+               }
+       }
+# endif
+
        image_size = INT_MAX - 4095;
        mmaped = 0;
        image = try_to_mmap_module(filename, &image_size);