aboutsummaryrefslogtreecommitdiff
path: root/modutils/modprobe-small.c
diff options
context:
space:
mode:
Diffstat (limited to 'modutils/modprobe-small.c')
-rw-r--r--modutils/modprobe-small.c33
1 files changed, 30 insertions, 3 deletions
diff --git a/modutils/modprobe-small.c b/modutils/modprobe-small.c
index 5936e48cf..a47e52234 100644
--- a/modutils/modprobe-small.c
+++ b/modutils/modprobe-small.c
@@ -18,9 +18,13 @@
/* 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