On Fri, Mar 24, 2023 at 12:11:07PM -0700, Linus Torvalds wrote: > On Fri, Mar 24, 2023 at 10:54 AM Luis Chamberlain <mcgrof@xxxxxxxxxx> wrote: > > > > +/* > > + * This clutch ensures we only allow a certain number concurrent threads at a > > kludge, not clutch. > > And it's much worse than a kludge. It's just wrong and disgusting. I wasn't happy with it either... > > + pr_warn_ratelimited("kread_concurrent_max (%u) close to 0 (max_loads: %u), throttling...", > > + atomic_read(&kread_concurrent_max), > > + MAX_KREAD_CONCURRENT); > > This is also wrong, since it's not kernel_read_file() that is the > problem, but whatever broken caller. > > Yeah, yeah, in practice it's presumably always just finit_module() > doing kernel_read_file_from_fd(), but it's still *completely* wrong to > just say "function X is throttling" when "X" isn't the problem, and > doesn't tell what the _real_ problem is. True. > I really think this all needs some core fixing at the module layer, > not these kinds of horrific hacks. On the modules side of things we can be super defensive on the second vmalloc allocation defensive [0] but other than this the initial kread also needs care too. To address the kread abuse within finit_module we could just move the kludge to the modules side of things until each free happens as in the below alternative. That just means any easy user interfacing call with kernel_read*() would likely have to be as careful. Untested below. [0] https://lkml.kernel.org/r/20230319214926.1794108-4-mcgrof@xxxxxxxxxx Luis >From 3c3f7e597ab35b4482ccb4064bb897eefa449071 Mon Sep 17 00:00:00 2001 From: Luis Chamberlain <mcgrof@xxxxxxxxxx> Date: Fri, 24 Mar 2023 12:51:44 -0700 Subject: [PATCH] module: kludge Signed-off-by: Luis Chamberlain <mcgrof@xxxxxxxxxx> --- kernel/module/main.c | 45 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/kernel/module/main.c b/kernel/module/main.c index 145e15f19576..a96de989532a 100644 --- a/kernel/module/main.c +++ b/kernel/module/main.c @@ -62,6 +62,16 @@ #define CREATE_TRACE_POINTS #include <trace/events/module.h> +#define MAX_INITMOD_CONCURRENT 50 +static atomic_t initmod_concurrent_max = ATOMIC_INIT(MAX_INITMOD_CONCURRENT); +static DECLARE_WAIT_QUEUE_HEAD(initmod_wq); + +/* + * How much time to wait for *all* MAX_INITMOD_CONCURRENT threads running + * at the same time without returning. + */ +#define MAX_INITMOD_ALL_BUSY_TIMEOUT 5 + /* * Mutex protects: * 1) List of modules (also safely readable with preempt_disable), @@ -3015,6 +3025,30 @@ SYSCALL_DEFINE3(init_module, void __user *, umod, return load_module(&info, uargs, 0); } +static int module_kread_concurrent(void) +{ + int err; + + if (atomic_dec_if_positive(&initmod_concurrent_max) < 0) { + pr_warn_ratelimited("finit_module: initkmod_concurrent_max (%u) close to 0 (max_loads: %u), throttling...", + atomic_read(&initmod_concurrent_max), + MAX_INITMOD_CONCURRENT); + err = wait_event_killable_timeout(initmod_wq, + atomic_dec_if_positive(&initmod_concurrent_max) >= 0, + MAX_INITMOD_ALL_BUSY_TIMEOUT * HZ); + if (!err) { + pr_warn_ratelimited("finit_module: loading module cannot be processed, kernel busy with %d threads loading modules now for more than %d seconds", + MAX_INITMOD_CONCURRENT, MAX_INITMOD_ALL_BUSY_TIMEOUT); + return -ETIME; + } else if (err == -ERESTARTSYS) { + pr_warn_ratelimited("finit_module: sigkill sent for load_module giving up"); + return err; + } + } + + return 0; +} + SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags) { struct load_info info = { }; @@ -3033,6 +3067,10 @@ SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags) |MODULE_INIT_COMPRESSED_FILE)) return -EINVAL; + err = module_kread_concurrent(); + if (err) + return err; + len = kernel_read_file_from_fd(fd, 0, &buf, INT_MAX, NULL, READING_MODULE); if (len < 0) @@ -3048,7 +3086,12 @@ SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags) info.len = len; } - return load_module(&info, uargs, flags); + err = load_module(&info, uargs, flags); + + atomic_inc(&initmod_concurrent_max); + wake_up(&initmod_wq); + + return err; } /* Keep in sync with MODULE_FLAGS_BUF_SIZE !!! */ -- 2.39.2