Sometimes when kernel calls request_module to load a module into kernel space, it doesn't pass the module name appropriately, and request_module doesn't verify it as well. As a result, modprobe is invoked anyway and spend a lot of time searching a nonsense name. For example reported from a customer, he runs a user space process to call ioctl(fd, SIOCGIFINDEX, &ifr), the callstack in kernel is like that: dev_ioctl(net/core/dev_iovtl.c) dev_load request_module("netdev-%s", name); or request_module("%s", name); However if name of NIC is empty, neither dev_load nor request_module checks it at the first place, modprobe will search module "netdev-" in its default path, env path and path configured in etc for nothing, increase a lot system overhead. To address this problem, this patch copies va_list and introduces a helper is_module_name_valid to verify the parameters validity one by one, either null or empty. if it fails, no modprobe invoked. Signed-off-by: Song Chen <chensong_2000@xxxxxx> --- kernel/module/kmod.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/kernel/module/kmod.c b/kernel/module/kmod.c index 0800d9891692..161ad41b864e 100644 --- a/kernel/module/kmod.c +++ b/kernel/module/kmod.c @@ -113,6 +113,27 @@ static int call_modprobe(char *orig_module_name, int wait) return -ENOMEM; } +static inline bool is_module_name_valid(const char *fmt, va_list args) +{ + va_list args_verify; + bool ret = true; + const char *p, *arg; + + va_copy(args_verify, args); + for (p = fmt; *p; p++) { + if (*p == '%' && *(++p) == 's') { + arg = va_arg(args_verify, const char *); + if (!arg || arg[0] == '\0') { + ret = false; + break; + } + } + } + va_end(args_verify); + + return ret; +} + /** * __request_module - try to load a kernel module * @wait: wait (or not) for the operation to complete @@ -147,7 +168,13 @@ int __request_module(bool wait, const char *fmt, ...) return -ENOENT; va_start(args, fmt); - ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args); + if (is_module_name_valid(fmt, args)) + ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args); + else { + pr_warn_ratelimited("request_module: modprobe cannot be processed due to invalid module name"); + va_end(args); + return -EINVAL; + } va_end(args); if (ret >= MODULE_NAME_LEN) return -ENAMETOOLONG; -- 2.25.1