[PATCH] module: kludge

From: Luis Chamberlain
Date: Fri Mar 24 2023 - 15:51:44 EST


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