xref: /linux/arch/um/kernel/skas/stub_exe.c (revision 831c1926ee728c3e747255f7c0f434762e8e863d)
132e8eaf2SBenjamin Berg #include <sys/ptrace.h>
232e8eaf2SBenjamin Berg #include <sys/prctl.h>
332e8eaf2SBenjamin Berg #include <asm/unistd.h>
432e8eaf2SBenjamin Berg #include <sysdep/stub.h>
532e8eaf2SBenjamin Berg #include <stub-data.h>
632e8eaf2SBenjamin Berg 
732e8eaf2SBenjamin Berg void _start(void);
832e8eaf2SBenjamin Berg 
real_init(void)932e8eaf2SBenjamin Berg noinline static void real_init(void)
1032e8eaf2SBenjamin Berg {
1132e8eaf2SBenjamin Berg 	struct stub_init_data init_data;
1232e8eaf2SBenjamin Berg 	unsigned long res;
1332e8eaf2SBenjamin Berg 	struct {
1432e8eaf2SBenjamin Berg 		void  *ss_sp;
1532e8eaf2SBenjamin Berg 		int    ss_flags;
1632e8eaf2SBenjamin Berg 		size_t ss_size;
1732e8eaf2SBenjamin Berg 	} stack = {
1832e8eaf2SBenjamin Berg 		.ss_size = STUB_DATA_PAGES * UM_KERN_PAGE_SIZE,
1932e8eaf2SBenjamin Berg 	};
2032e8eaf2SBenjamin Berg 	struct {
2132e8eaf2SBenjamin Berg 		void *sa_handler_;
2232e8eaf2SBenjamin Berg 		unsigned long sa_flags;
2332e8eaf2SBenjamin Berg 		void *sa_restorer;
2432e8eaf2SBenjamin Berg 		unsigned long long sa_mask;
2532e8eaf2SBenjamin Berg 	} sa = {
2632e8eaf2SBenjamin Berg 		/* Need to set SA_RESTORER (but the handler never returns) */
2732e8eaf2SBenjamin Berg 		.sa_flags = SA_ONSTACK | SA_NODEFER | SA_SIGINFO | 0x04000000,
2832e8eaf2SBenjamin Berg 		/* no need to mask any signals */
2932e8eaf2SBenjamin Berg 		.sa_mask = 0,
3032e8eaf2SBenjamin Berg 	};
3132e8eaf2SBenjamin Berg 
3232e8eaf2SBenjamin Berg 	/* set a nice name */
3332e8eaf2SBenjamin Berg 	stub_syscall2(__NR_prctl, PR_SET_NAME, (unsigned long)"uml-userspace");
3432e8eaf2SBenjamin Berg 
35801e00d3SBenjamin Berg 	/* Make sure this process dies if the kernel dies */
36801e00d3SBenjamin Berg 	stub_syscall2(__NR_prctl, PR_SET_PDEATHSIG, SIGKILL);
37801e00d3SBenjamin Berg 
3832e8eaf2SBenjamin Berg 	/* read information from STDIN and close it */
3932e8eaf2SBenjamin Berg 	res = stub_syscall3(__NR_read, 0,
4032e8eaf2SBenjamin Berg 			    (unsigned long)&init_data, sizeof(init_data));
4132e8eaf2SBenjamin Berg 	if (res != sizeof(init_data))
4232e8eaf2SBenjamin Berg 		stub_syscall1(__NR_exit, 10);
4332e8eaf2SBenjamin Berg 
4432e8eaf2SBenjamin Berg 	stub_syscall1(__NR_close, 0);
4532e8eaf2SBenjamin Berg 
4632e8eaf2SBenjamin Berg 	/* map stub code + data */
4732e8eaf2SBenjamin Berg 	res = stub_syscall6(STUB_MMAP_NR,
4832e8eaf2SBenjamin Berg 			    init_data.stub_start, UM_KERN_PAGE_SIZE,
4932e8eaf2SBenjamin Berg 			    PROT_READ | PROT_EXEC, MAP_FIXED | MAP_SHARED,
5032e8eaf2SBenjamin Berg 			    init_data.stub_code_fd, init_data.stub_code_offset);
5132e8eaf2SBenjamin Berg 	if (res != init_data.stub_start)
5232e8eaf2SBenjamin Berg 		stub_syscall1(__NR_exit, 11);
5332e8eaf2SBenjamin Berg 
5432e8eaf2SBenjamin Berg 	res = stub_syscall6(STUB_MMAP_NR,
5532e8eaf2SBenjamin Berg 			    init_data.stub_start + UM_KERN_PAGE_SIZE,
5632e8eaf2SBenjamin Berg 			    STUB_DATA_PAGES * UM_KERN_PAGE_SIZE,
5732e8eaf2SBenjamin Berg 			    PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED,
5832e8eaf2SBenjamin Berg 			    init_data.stub_data_fd, init_data.stub_data_offset);
5932e8eaf2SBenjamin Berg 	if (res != init_data.stub_start + UM_KERN_PAGE_SIZE)
6032e8eaf2SBenjamin Berg 		stub_syscall1(__NR_exit, 12);
6132e8eaf2SBenjamin Berg 
6232e8eaf2SBenjamin Berg 	/* setup signal stack inside stub data */
6332e8eaf2SBenjamin Berg 	stack.ss_sp = (void *)init_data.stub_start + UM_KERN_PAGE_SIZE;
6432e8eaf2SBenjamin Berg 	stub_syscall2(__NR_sigaltstack, (unsigned long)&stack, 0);
6532e8eaf2SBenjamin Berg 
6632e8eaf2SBenjamin Berg 	/* register SIGSEGV handler */
6732e8eaf2SBenjamin Berg 	sa.sa_handler_ = (void *) init_data.segv_handler;
6832e8eaf2SBenjamin Berg 	res = stub_syscall4(__NR_rt_sigaction, SIGSEGV, (unsigned long)&sa, 0,
6932e8eaf2SBenjamin Berg 			    sizeof(sa.sa_mask));
7032e8eaf2SBenjamin Berg 	if (res != 0)
7132e8eaf2SBenjamin Berg 		stub_syscall1(__NR_exit, 13);
7232e8eaf2SBenjamin Berg 
7332e8eaf2SBenjamin Berg 	stub_syscall4(__NR_ptrace, PTRACE_TRACEME, 0, 0, 0);
7432e8eaf2SBenjamin Berg 
7532e8eaf2SBenjamin Berg 	stub_syscall2(__NR_kill, stub_syscall0(__NR_getpid), SIGSTOP);
7632e8eaf2SBenjamin Berg 
7732e8eaf2SBenjamin Berg 	stub_syscall1(__NR_exit, 14);
7832e8eaf2SBenjamin Berg 
7932e8eaf2SBenjamin Berg 	__builtin_unreachable();
8032e8eaf2SBenjamin Berg }
8132e8eaf2SBenjamin Berg 
_start(void)828508a5e0SDavid Gow __attribute__((naked)) void _start(void)
8332e8eaf2SBenjamin Berg {
84*14d4a7b5SJohannes Berg 	/*
85*14d4a7b5SJohannes Berg 	 * Since the stack after exec() starts at the top-most address,
86*14d4a7b5SJohannes Berg 	 * but that's exactly where we also want to map the stub data
87*14d4a7b5SJohannes Berg 	 * and code, this must:
88*14d4a7b5SJohannes Berg 	 *  - push the stack by 1 code and STUB_DATA_PAGES data pages
89*14d4a7b5SJohannes Berg 	 *  - call real_init()
90*14d4a7b5SJohannes Berg 	 * This way, real_init() can use the stack normally, while the
91*14d4a7b5SJohannes Berg 	 * original stack further down (higher address) will become
92*14d4a7b5SJohannes Berg 	 * inaccessible after the mmap() calls above.
93*14d4a7b5SJohannes Berg 	 */
94*14d4a7b5SJohannes Berg 	stub_start(real_init);
9532e8eaf2SBenjamin Berg }
96