* [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* Re: [PATCH] um: fix shutdown __inittext access
2026-09-28 7:39 [PATCH] um: fix shutdown __inittext access Johannes Berg
@ 2026-09-28 8:11 ` Hajime Tazaki
0 siblings, 0 replies; 2+ messages in thread
From: Hajime Tazaki @ 2026-09-28 8:11 UTC (permalink / raw)
To: johannes; +Cc: linux-um, johannes.berg
On Mon, 28 Sep 2026 16:39:35 +0900,
Johannes Berg wrote:
>
> 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>
thanks, separating the exit path from __init code is much nicer.
Tested-by: Hajime Tazaki <thehajime@gmail.com>
-- Hajime
^ permalink raw reply [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