[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250918201109.24620-6-julian.lagattuta@gmail.com>
Date: Thu, 18 Sep 2025 16:11:08 -0400
From: julian-lagattuta <julian.lagattuta@...il.com>
To: Luis Chamberlain <mcgrof@...nel.org>,
Petr Pavlu <petr.pavlu@...e.com>
Cc: Sami Tolvanen <samitolvanen@...gle.com>,
Daniel Gomez <da.gomez@...sung.com>,
linux-modules@...r.kernel.org,
linux-kernel@...r.kernel.org,
julian-lagattuta <julian.lagattuta@...il.com>
Subject: [PATCH 2/6] module: detect if init crashed and unload
Store idempotent and init_pid in struct module.
Signed-off-by: julian-lagattuta <julian.lagattuta@...il.com>
---
kernel/module/main.c | 36 ++++++++++++++++++++++++++++++++++--
1 file changed, 34 insertions(+), 2 deletions(-)
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 413ac6ea3702..2277c53aef2e 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -752,6 +752,7 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
char name[MODULE_NAME_LEN];
char buf[MODULE_FLAGS_BUF_SIZE];
int ret, forced = 0;
+ bool did_init_crash __maybe_unused = false;
if (!capable(CAP_SYS_MODULE) || modules_disabled)
return -EPERM;
@@ -778,8 +779,11 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
}
/* Doing init or already dying? */
- if (mod->state != MODULE_STATE_LIVE) {
- /* FIXME: if (force), slam module count damn the torpedoes */
+ if (mod->state == MODULE_STATE_GOING ||
+ (mod->state != MODULE_STATE_LIVE &&
+ !IS_ENABLED(CONFIG_MODULE_FORCE_UNLOAD))
+ ) {
+ if (mod->state == MODULE_STATE_GOING)
pr_debug("%s already dying\n", mod->name);
ret = -EBUSY;
goto out;
@@ -795,6 +799,21 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
}
}
+#ifdef CONFIG_MODULE_FORCE_UNLOAD
+ if (mod->state == MODULE_STATE_COMING) {
+ struct task_struct *init_process = get_pid_task(mod->init_pid, PIDTYPE_PID);
+
+ /* Did the init process die? */
+ if (init_process) {
+ put_task_struct(init_process);
+ ret = -EBUSY;
+ goto out;
+ } else {
+ did_init_crash = true;
+ }
+ }
+#endif
+
ret = try_stop_module(mod, flags, &forced);
if (ret != 0)
goto out;
@@ -1380,6 +1399,10 @@ static void free_module(struct module *mod)
mod->state = MODULE_STATE_UNFORMED;
mutex_unlock(&module_mutex);
+#ifdef CONFIG_MODULE_FORCE_UNLOAD
+ if (mod->init_pid)
+ put_pid(mod->init_pid);
+#endif
/* Arch-specific cleanup. */
module_arch_cleanup(mod);
@@ -3044,6 +3067,11 @@ static noinline int do_init_module(struct module *mod)
ftrace_free_mem(mod, mod->mem[MOD_INIT_TEXT].base,
mod->mem[MOD_INIT_TEXT].base + mod->mem[MOD_INIT_TEXT].size);
mutex_lock(&module_mutex);
+#ifdef CONFIG_MODULE_FORCE_UNLOAD
+ put_pid(mod->init_pid);
+ mod->init_pid = NULL;
+ mod->idempotent = NULL;
+#endif
/* Drop initial reference. */
module_put(mod);
trim_init_extable(mod);
@@ -3474,6 +3502,10 @@ static int load_module(struct load_info *info, const char __user *uargs,
if (codetag_load_module(mod))
goto sysfs_cleanup;
+#ifdef CONFIG_MODULE_FORCE_UNLOAD
+ mod->init_pid = get_pid(task_pid(current));
+ mod->idempotent = info->idempotent;
+#endif
/* Get rid of temporary copy. */
free_copy(info, flags);
--
2.45.2
Powered by blists - more mailing lists