xref: /linux/arch/um/kernel/skas/stub_exe.c (revision 32e8eaf263d9be014ba1970444f745682fa9c6c0)
1 #include <sys/ptrace.h>
2 #include <sys/prctl.h>
3 #include <asm/unistd.h>
4 #include <sysdep/stub.h>
5 #include <stub-data.h>
6 
7 void _start(void);
8 
9 noinline static void real_init(void)
10 {
11 	struct stub_init_data init_data;
12 	unsigned long res;
13 	struct {
14 		void  *ss_sp;
15 		int    ss_flags;
16 		size_t ss_size;
17 	} stack = {
18 		.ss_size = STUB_DATA_PAGES * UM_KERN_PAGE_SIZE,
19 	};
20 	struct {
21 		void *sa_handler_;
22 		unsigned long sa_flags;
23 		void *sa_restorer;
24 		unsigned long long sa_mask;
25 	} sa = {
26 		/* Need to set SA_RESTORER (but the handler never returns) */
27 		.sa_flags = SA_ONSTACK | SA_NODEFER | SA_SIGINFO | 0x04000000,
28 		/* no need to mask any signals */
29 		.sa_mask = 0,
30 	};
31 
32 	/* set a nice name */
33 	stub_syscall2(__NR_prctl, PR_SET_NAME, (unsigned long)"uml-userspace");
34 
35 	/* read information from STDIN and close it */
36 	res = stub_syscall3(__NR_read, 0,
37 			    (unsigned long)&init_data, sizeof(init_data));
38 	if (res != sizeof(init_data))
39 		stub_syscall1(__NR_exit, 10);
40 
41 	stub_syscall1(__NR_close, 0);
42 
43 	/* map stub code + data */
44 	res = stub_syscall6(STUB_MMAP_NR,
45 			    init_data.stub_start, UM_KERN_PAGE_SIZE,
46 			    PROT_READ | PROT_EXEC, MAP_FIXED | MAP_SHARED,
47 			    init_data.stub_code_fd, init_data.stub_code_offset);
48 	if (res != init_data.stub_start)
49 		stub_syscall1(__NR_exit, 11);
50 
51 	res = stub_syscall6(STUB_MMAP_NR,
52 			    init_data.stub_start + UM_KERN_PAGE_SIZE,
53 			    STUB_DATA_PAGES * UM_KERN_PAGE_SIZE,
54 			    PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED,
55 			    init_data.stub_data_fd, init_data.stub_data_offset);
56 	if (res != init_data.stub_start + UM_KERN_PAGE_SIZE)
57 		stub_syscall1(__NR_exit, 12);
58 
59 	/* setup signal stack inside stub data */
60 	stack.ss_sp = (void *)init_data.stub_start + UM_KERN_PAGE_SIZE;
61 	stub_syscall2(__NR_sigaltstack, (unsigned long)&stack, 0);
62 
63 	/* register SIGSEGV handler */
64 	sa.sa_handler_ = (void *) init_data.segv_handler;
65 	res = stub_syscall4(__NR_rt_sigaction, SIGSEGV, (unsigned long)&sa, 0,
66 			    sizeof(sa.sa_mask));
67 	if (res != 0)
68 		stub_syscall1(__NR_exit, 13);
69 
70 	stub_syscall4(__NR_ptrace, PTRACE_TRACEME, 0, 0, 0);
71 
72 	stub_syscall2(__NR_kill, stub_syscall0(__NR_getpid), SIGSTOP);
73 
74 	stub_syscall1(__NR_exit, 14);
75 
76 	__builtin_unreachable();
77 }
78 
79 void _start(void)
80 {
81 	char *alloc;
82 
83 	/* Make enough space for the stub (including space for alignment) */
84 	alloc = __builtin_alloca((1 + 2 * STUB_DATA_PAGES - 1) * UM_KERN_PAGE_SIZE);
85 	asm volatile("" : "+r,m"(alloc) : : "memory");
86 
87 	real_init();
88 }
89