linux-um archives
 help / color / mirror / Atom feed
* [PATCH] um: fix shutdown __inittext access
@ 2026-09-28  7:39 Johannes Berg
  2026-09-28  8:11 ` Hajime Tazaki
  0 siblings, 1 reply; 2+ messages in thread
From: Johannes Berg @ 2026-09-28  7:39 UTC (permalink / raw)
  To: linux-um; +Cc: Johannes Berg, Hajime Tazaki

From: Johannes Berg <johannes.berg@intel.com>

Since first moving __init text into the right place in commit
8966ed0b2d48 ("um: move init text between __init_begin/end")
and then making all init sections inaccessible, shutdown and
reboot crash instead of working correctly, for the obvious
reason that the functions are __init but run on the way out.

Removing the __init markers would work in some way, but that
would bubble through a lot of functions.

Instead, mark the relevant functions __noreturn (including
longjmp() since that's now needed so start_idle_thread() can
be __noreturn), and split out the part of main() that's done
on the way out into a new os_exit() function that's called
directly.

Reported-by: Hajime Tazaki <thehajime@gmail.com>
Closes: https://lore.kernel.org/linux-um/m24ifc4v6m.wl-thehajime@gmail.com/
Fixes: a418ab8fddea ("um: mprotect() __init memory")
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 arch/um/include/shared/as-layout.h |  3 ++-
 arch/um/include/shared/kern_util.h |  3 ++-
 arch/um/include/shared/longjmp.h   |  3 ++-
 arch/um/include/shared/os.h        |  6 +++++-
 arch/um/kernel/skas/process.c      |  6 +++---
 arch/um/kernel/um_arch.c           |  4 ++--
 arch/um/os-Linux/main.c            | 17 +++++++++++------
 arch/um/os-Linux/skas/process.c    | 11 +++--------
 8 files changed, 30 insertions(+), 23 deletions(-)

diff --git a/arch/um/include/shared/as-layout.h b/arch/um/include/shared/as-layout.h
index 02ef258e3395..7c4ccb6d9d37 100644
--- a/arch/um/include/shared/as-layout.h
+++ b/arch/um/include/shared/as-layout.h
@@ -29,6 +29,7 @@
 
 #ifndef __ASSEMBLER__
 
+#include <linux/compiler_types.h>
 #include <sysdep/ptrace.h>
 
 struct task_struct;
@@ -46,7 +47,7 @@ extern unsigned long brk_start;
 
 extern unsigned long stub_start;
 
-extern int linux_main(int argc, char **argv, char **envp);
+extern void __noreturn linux_main(int argc, char **argv, char **envp);
 extern void uml_finishsetup(void);
 
 struct siginfo;
diff --git a/arch/um/include/shared/kern_util.h b/arch/um/include/shared/kern_util.h
index 9812efd14ec0..7950d58a4ae8 100644
--- a/arch/um/include/shared/kern_util.h
+++ b/arch/um/include/shared/kern_util.h
@@ -6,6 +6,7 @@
 #ifndef __KERN_UTIL_H__
 #define __KERN_UTIL_H__
 
+#include <linux/compiler_types.h>
 #include <sysdep/ptrace.h>
 #include <sysdep/faultinfo.h>
 
@@ -37,7 +38,7 @@ extern void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs
 
 extern void uml_pm_wake(void);
 
-extern int start_uml(void);
+extern void __noreturn start_uml(void);
 
 extern void uml_cleanup(void);
 extern void do_uml_exitcalls(void);
diff --git a/arch/um/include/shared/longjmp.h b/arch/um/include/shared/longjmp.h
index c53e43d980c8..b35ed756e3e4 100644
--- a/arch/um/include/shared/longjmp.h
+++ b/arch/um/include/shared/longjmp.h
@@ -2,11 +2,12 @@
 #ifndef __UML_LONGJMP_H
 #define __UML_LONGJMP_H
 
+#include <linux/compiler_types.h>
 #include <sysdep/archsetjmp.h>
 #include <os.h>
 
 extern int setjmp(jmp_buf);
-extern void longjmp(jmp_buf, int);
+extern void __noreturn longjmp(jmp_buf, int);
 
 #define UML_LONGJMP(buf, val) do { \
 	longjmp(*buf, val);	\
diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h
index b26e94292fc1..0067c5208c4c 100644
--- a/arch/um/include/shared/os.h
+++ b/arch/um/include/shared/os.h
@@ -15,6 +15,7 @@
 #ifndef __UM_HOST__
 #include <linux/types.h>
 #else
+#include <stdbool.h>
 #include <sys/types.h>
 #endif
 
@@ -196,6 +197,9 @@ extern int create_mem_file(unsigned long long len);
 /* tlb.c */
 extern void report_enomem(void);
 
+/* main.c */
+extern void __noreturn os_exit(bool reboot);
+
 /* process.c */
 pid_t os_reap_child(void);
 extern void os_alarm_process(int pid);
@@ -295,7 +299,7 @@ extern int start_userspace(struct mm_id *mm_id);
 extern void userspace(struct uml_pt_regs *regs);
 extern void new_thread(void *stack, jmp_buf *buf, void (*handler)(void));
 extern void switch_threads(jmp_buf *me, jmp_buf *you);
-extern int start_idle_thread(void *stack, jmp_buf *switch_buf);
+extern void __noreturn start_idle_thread(void *stack, jmp_buf *switch_buf);
 extern void initial_thread_cb_skas(void (*proc)(void *),
 				 void *arg);
 extern void halt_skas(void);
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
index dcdce50b4595..f60541df209f 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -27,7 +27,7 @@ static int __init start_kernel_proc(void *unused)
 
 char cpu_irqstacks[NR_CPUS][THREAD_SIZE] __aligned(THREAD_SIZE);
 
-int __init start_uml(void)
+void __init start_uml(void)
 {
 	stack_protections((unsigned long) &cpu_irqstacks[0]);
 	set_sigstack(cpu_irqstacks[0], THREAD_SIZE);
@@ -36,8 +36,8 @@ int __init start_uml(void)
 
 	init_task.thread.request.thread.proc = start_kernel_proc;
 	init_task.thread.request.thread.arg = NULL;
-	return start_idle_thread(task_stack_page(&init_task),
-				 &init_task.thread.switch_buf);
+	start_idle_thread(task_stack_page(&init_task),
+			  &init_task.thread.switch_buf);
 }
 
 static DEFINE_SPINLOCK(initial_jmpbuf_spinlock);
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index 13e84e605630..3dbe3acc4833 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -308,7 +308,7 @@ static unsigned long __init get_top_address(char **envp)
 	return PAGE_ALIGN(top_addr + 1);
 }
 
-int __init linux_main(int argc, char **argv, char **envp)
+void __init linux_main(int argc, char **argv, char **envp)
 {
 	unsigned long avail, diff;
 	unsigned long virtmem_size, max_physmem;
@@ -401,7 +401,7 @@ int __init linux_main(int argc, char **argv, char **envp)
 
 	os_flush_stdout();
 
-	return start_uml();
+	start_uml();
 }
 
 int __init __weak read_initrd(void)
diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c
index 7e114862a723..ea41188ef2d0 100644
--- a/arch/um/os-Linux/main.c
+++ b/arch/um/os-Linux/main.c
@@ -100,10 +100,11 @@ static void __init setup_env_path(void)
 	}
 }
 
+static char **new_argv;
+
 int __init main(int argc, char **argv, char **envp)
 {
-	char **new_argv;
-	int ret, i, err;
+	int ret, i;
 
 	/* Disable randomization and re-exec if it was changed successfully */
 	ret = personality(PER_LINUX | ADDR_NO_RANDOMIZE);
@@ -150,7 +151,12 @@ int __init main(int argc, char **argv, char **envp)
 	scan_elf_aux(envp);
 
 	change_sig(SIGPIPE, 0);
-	ret = linux_main(argc, argv, envp);
+	linux_main(argc, argv, envp);
+}
+
+void os_exit(bool reboot)
+{
+	int err;
 
 	/*
 	 * Disable SIGPROF - I have no idea why libc doesn't do this or turn
@@ -183,12 +189,11 @@ int __init main(int argc, char **argv, char **envp)
 
 	os_info("\n");
 	/* Reboot */
-	if (ret) {
+	if (reboot) {
 		execvp(new_argv[0], new_argv);
 		perror("Failed to exec kernel");
-		ret = 1;
 	}
-	return uml_exitcode;
+	exit(uml_exitcode);
 }
 
 extern void *__real_malloc(int);
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
index d6c22f8aa06d..bca05a5a7a83 100644
--- a/arch/um/os-Linux/skas/process.c
+++ b/arch/um/os-Linux/skas/process.c
@@ -816,7 +816,7 @@ static __thread void (*cb_proc)(void *arg);
 static __thread void *cb_arg;
 static __thread jmp_buf *cb_back;
 
-int start_idle_thread(void *stack, jmp_buf *switch_buf)
+void start_idle_thread(void *stack, jmp_buf *switch_buf)
 {
 	int n;
 
@@ -843,21 +843,16 @@ int start_idle_thread(void *stack, jmp_buf *switch_buf)
 		break;
 	case INIT_JMP_HALT:
 		kmalloc_ok = 0;
-		return 0;
+		os_exit(false);
 	case INIT_JMP_REBOOT:
 		kmalloc_ok = 0;
-		return 1;
+		os_exit(true);
 	default:
 		printk(UM_KERN_ERR "Bad sigsetjmp return in %s - %d\n",
 		       __func__, n);
 		fatal_sigsegv();
 	}
 	longjmp(*switch_buf, 1);
-
-	/* unreachable */
-	printk(UM_KERN_ERR "impossible long jump!");
-	fatal_sigsegv();
-	return 0;
 }
 
 void initial_thread_cb_skas(void (*proc)(void *), void *arg)
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-09-28  8:11 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-28  7:39 [PATCH] um: fix shutdown __inittext access Johannes Berg
2026-09-28  8:11 ` Hajime Tazaki

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox