modutils: support finit_module syscall

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>
This commit is contained in:
Mike Frysinger 2016-09-15 12:16:33 +02:00 committed by Denys Vlasenko
parent 7fa799a97d
commit 3a45b87ac3
2 changed files with 51 additions and 3 deletions

View File

@ -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

View 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);