mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
um: fix shutdown __inittext access
Since first moving __init text into the right place in commit8966ed0b2d("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:a418ab8fdd("um: mprotect() __init memory") Signed-off-by: Johannes Berg <johannes.berg@intel.com> Tested-by: Hajime Tazaki <thehajime@gmail.com> Link: https://patch.msgid.link/20260928093934.ca7af44c59ca.I470ece16d176ea704aa6e5767b755055d106da35@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
0e70b1de88
commit
2f88f5689d
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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); \
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user