diff options
-rw-r--r-- | arch/um/include/kern_util.h | 1 | ||||
-rw-r--r-- | arch/um/include/os.h | 8 | ||||
-rw-r--r-- | arch/um/include/registers.h | 6 | ||||
-rw-r--r-- | arch/um/kernel/skas/mmu.c | 5 | ||||
-rw-r--r-- | arch/um/kernel/skas/process.c | 20 | ||||
-rw-r--r-- | arch/um/kernel/trap.c | 12 | ||||
-rw-r--r-- | arch/um/os-Linux/registers.c | 21 | ||||
-rw-r--r-- | arch/um/os-Linux/skas/process.c | 265 | ||||
-rw-r--r-- | arch/um/os-Linux/start_up.c | 4 | ||||
-rw-r--r-- | arch/um/sys-x86_64/syscalls.c | 8 |
10 files changed, 233 insertions, 117 deletions
diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h index 8fadf8962e3e..625ca2924a56 100644 --- a/arch/um/include/kern_util.h +++ b/arch/um/include/kern_util.h | |||
@@ -62,6 +62,7 @@ extern int singlestepping(void *t); | |||
62 | extern void segv_handler(int sig, struct uml_pt_regs *regs); | 62 | extern void segv_handler(int sig, struct uml_pt_regs *regs); |
63 | extern void bus_handler(int sig, struct uml_pt_regs *regs); | 63 | extern void bus_handler(int sig, struct uml_pt_regs *regs); |
64 | extern void winch(int sig, struct uml_pt_regs *regs); | 64 | extern void winch(int sig, struct uml_pt_regs *regs); |
65 | extern void fatal_sigsegv(void) __attribute__ ((noreturn)); | ||
65 | 66 | ||
66 | 67 | ||
67 | #endif | 68 | #endif |
diff --git a/arch/um/include/os.h b/arch/um/include/os.h index 69c0d4ad0e52..9428d34792ca 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h | |||
@@ -238,7 +238,7 @@ extern int raw(int fd); | |||
238 | extern void setup_machinename(char *machine_out); | 238 | extern void setup_machinename(char *machine_out); |
239 | extern void setup_hostinfo(char *buf, int len); | 239 | extern void setup_hostinfo(char *buf, int len); |
240 | extern int setjmp_wrapper(void (*proc)(void *, void *), ...); | 240 | extern int setjmp_wrapper(void (*proc)(void *, void *), ...); |
241 | extern void os_dump_core(void); | 241 | extern void os_dump_core(void) __attribute__ ((noreturn)); |
242 | 242 | ||
243 | /* time.c */ | 243 | /* time.c */ |
244 | extern void idle_sleep(unsigned long long nsecs); | 244 | extern void idle_sleep(unsigned long long nsecs); |
@@ -267,11 +267,9 @@ extern int protect(struct mm_id * mm_idp, unsigned long addr, | |||
267 | extern int is_skas_winch(int pid, int fd, void *data); | 267 | extern int is_skas_winch(int pid, int fd, void *data); |
268 | extern int start_userspace(unsigned long stub_stack); | 268 | extern int start_userspace(unsigned long stub_stack); |
269 | extern int copy_context_skas0(unsigned long stack, int pid); | 269 | extern int copy_context_skas0(unsigned long stack, int pid); |
270 | extern void save_registers(int pid, struct uml_pt_regs *regs); | ||
271 | extern void restore_registers(int pid, struct uml_pt_regs *regs); | ||
272 | extern void userspace(struct uml_pt_regs *regs); | 270 | extern void userspace(struct uml_pt_regs *regs); |
273 | extern void map_stub_pages(int fd, unsigned long code, | 271 | extern int map_stub_pages(int fd, unsigned long code, unsigned long data, |
274 | unsigned long data, unsigned long stack); | 272 | unsigned long stack); |
275 | extern void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)); | 273 | extern void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)); |
276 | extern void switch_threads(jmp_buf *me, jmp_buf *you); | 274 | extern void switch_threads(jmp_buf *me, jmp_buf *you); |
277 | extern int start_idle_thread(void *stack, jmp_buf *switch_buf); | 275 | extern int start_idle_thread(void *stack, jmp_buf *switch_buf); |
diff --git a/arch/um/include/registers.h b/arch/um/include/registers.h index 6df37480cb8c..9ea1ae3c8f46 100644 --- a/arch/um/include/registers.h +++ b/arch/um/include/registers.h | |||
@@ -13,9 +13,9 @@ extern int save_fp_registers(int pid, unsigned long *fp_regs); | |||
13 | extern int restore_fp_registers(int pid, unsigned long *fp_regs); | 13 | extern int restore_fp_registers(int pid, unsigned long *fp_regs); |
14 | extern int save_fpx_registers(int pid, unsigned long *fp_regs); | 14 | extern int save_fpx_registers(int pid, unsigned long *fp_regs); |
15 | extern int restore_fpx_registers(int pid, unsigned long *fp_regs); | 15 | extern int restore_fpx_registers(int pid, unsigned long *fp_regs); |
16 | extern void save_registers(int pid, struct uml_pt_regs *regs); | 16 | extern int save_registers(int pid, struct uml_pt_regs *regs); |
17 | extern void restore_registers(int pid, struct uml_pt_regs *regs); | 17 | extern int restore_registers(int pid, struct uml_pt_regs *regs); |
18 | extern void init_registers(int pid); | 18 | extern int init_registers(int pid); |
19 | extern void get_safe_registers(unsigned long *regs); | 19 | extern void get_safe_registers(unsigned long *regs); |
20 | extern unsigned long get_thread_reg(int reg, jmp_buf *buf); | 20 | extern unsigned long get_thread_reg(int reg, jmp_buf *buf); |
21 | 21 | ||
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c index b56fe8b67a81..6da9ab4f5a18 100644 --- a/arch/um/kernel/skas/mmu.c +++ b/arch/um/kernel/skas/mmu.c | |||
@@ -114,6 +114,11 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm) | |||
114 | to_mm->id.u.pid = copy_context_skas0(stack, | 114 | to_mm->id.u.pid = copy_context_skas0(stack, |
115 | from_mm->id.u.pid); | 115 | from_mm->id.u.pid); |
116 | else to_mm->id.u.pid = start_userspace(stack); | 116 | else to_mm->id.u.pid = start_userspace(stack); |
117 | |||
118 | if (to_mm->id.u.pid < 0) { | ||
119 | ret = to_mm->id.u.pid; | ||
120 | goto out_free; | ||
121 | } | ||
117 | } | 122 | } |
118 | 123 | ||
119 | ret = init_new_ldt(to_mm, from_mm); | 124 | ret = init_new_ldt(to_mm, from_mm); |
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index fce389c2342f..2e9852c0d487 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c | |||
@@ -6,19 +6,25 @@ | |||
6 | #include "linux/init.h" | 6 | #include "linux/init.h" |
7 | #include "linux/sched.h" | 7 | #include "linux/sched.h" |
8 | #include "as-layout.h" | 8 | #include "as-layout.h" |
9 | #include "kern.h" | ||
9 | #include "os.h" | 10 | #include "os.h" |
10 | #include "skas.h" | 11 | #include "skas.h" |
11 | 12 | ||
12 | int new_mm(unsigned long stack) | 13 | int new_mm(unsigned long stack) |
13 | { | 14 | { |
14 | int fd; | 15 | int fd, err; |
15 | 16 | ||
16 | fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0); | 17 | fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0); |
17 | if (fd < 0) | 18 | if (fd < 0) |
18 | return fd; | 19 | return fd; |
19 | 20 | ||
20 | if (skas_needs_stub) | 21 | if (skas_needs_stub) { |
21 | map_stub_pages(fd, STUB_CODE, STUB_DATA, stack); | 22 | err = map_stub_pages(fd, STUB_CODE, STUB_DATA, stack); |
23 | if (err) { | ||
24 | os_close_file(fd); | ||
25 | return err; | ||
26 | } | ||
27 | } | ||
22 | 28 | ||
23 | return fd; | 29 | return fd; |
24 | } | 30 | } |
@@ -49,8 +55,14 @@ int __init start_uml(void) | |||
49 | { | 55 | { |
50 | stack_protections((unsigned long) &cpu0_irqstack); | 56 | stack_protections((unsigned long) &cpu0_irqstack); |
51 | set_sigstack(cpu0_irqstack, THREAD_SIZE); | 57 | set_sigstack(cpu0_irqstack, THREAD_SIZE); |
52 | if (proc_mm) | 58 | if (proc_mm) { |
53 | userspace_pid[0] = start_userspace(0); | 59 | userspace_pid[0] = start_userspace(0); |
60 | if (userspace_pid[0] < 0) { | ||
61 | printf("start_uml - start_userspace returned %d\n", | ||
62 | userspace_pid[0]); | ||
63 | exit(1); | ||
64 | } | ||
65 | } | ||
54 | 66 | ||
55 | init_new_thread_signals(); | 67 | init_new_thread_signals(); |
56 | 68 | ||
diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c index 8fd1a797c3eb..44e490419495 100644 --- a/arch/um/kernel/trap.c +++ b/arch/um/kernel/trap.c | |||
@@ -129,6 +129,18 @@ static void bad_segv(struct faultinfo fi, unsigned long ip) | |||
129 | force_sig_info(SIGSEGV, &si, current); | 129 | force_sig_info(SIGSEGV, &si, current); |
130 | } | 130 | } |
131 | 131 | ||
132 | void fatal_sigsegv(void) | ||
133 | { | ||
134 | force_sigsegv(SIGSEGV, current); | ||
135 | do_signal(); | ||
136 | /* | ||
137 | * This is to tell gcc that we're not returning - do_signal | ||
138 | * can, in general, return, but in this case, it's not, since | ||
139 | * we just got a fatal SIGSEGV queued. | ||
140 | */ | ||
141 | os_dump_core(); | ||
142 | } | ||
143 | |||
132 | void segv_handler(int sig, struct uml_pt_regs *regs) | 144 | void segv_handler(int sig, struct uml_pt_regs *regs) |
133 | { | 145 | { |
134 | struct faultinfo * fi = UPT_FAULTINFO(regs); | 146 | struct faultinfo * fi = UPT_FAULTINFO(regs); |
diff --git a/arch/um/os-Linux/registers.c b/arch/um/os-Linux/registers.c index c78fae3aba81..830fe6a1518a 100644 --- a/arch/um/os-Linux/registers.c +++ b/arch/um/os-Linux/registers.c | |||
@@ -8,42 +8,41 @@ | |||
8 | #include <string.h> | 8 | #include <string.h> |
9 | #include <sys/ptrace.h> | 9 | #include <sys/ptrace.h> |
10 | #include "sysdep/ptrace.h" | 10 | #include "sysdep/ptrace.h" |
11 | #include "user.h" | ||
12 | 11 | ||
13 | void save_registers(int pid, struct uml_pt_regs *regs) | 12 | int save_registers(int pid, struct uml_pt_regs *regs) |
14 | { | 13 | { |
15 | int err; | 14 | int err; |
16 | 15 | ||
17 | err = ptrace(PTRACE_GETREGS, pid, 0, regs->gp); | 16 | err = ptrace(PTRACE_GETREGS, pid, 0, regs->gp); |
18 | if (err < 0) | 17 | if (err < 0) |
19 | panic("save_registers - saving registers failed, errno = %d\n", | 18 | return -errno; |
20 | errno); | 19 | return 0; |
21 | } | 20 | } |
22 | 21 | ||
23 | void restore_registers(int pid, struct uml_pt_regs *regs) | 22 | int restore_registers(int pid, struct uml_pt_regs *regs) |
24 | { | 23 | { |
25 | int err; | 24 | int err; |
26 | 25 | ||
27 | err = ptrace(PTRACE_SETREGS, pid, 0, regs->gp); | 26 | err = ptrace(PTRACE_SETREGS, pid, 0, regs->gp); |
28 | if (err < 0) | 27 | if (err < 0) |
29 | panic("restore_registers - saving registers failed, " | 28 | return -errno; |
30 | "errno = %d\n", errno); | 29 | return 0; |
31 | } | 30 | } |
32 | 31 | ||
33 | /* This is set once at boot time and not changed thereafter */ | 32 | /* This is set once at boot time and not changed thereafter */ |
34 | 33 | ||
35 | static unsigned long exec_regs[MAX_REG_NR]; | 34 | static unsigned long exec_regs[MAX_REG_NR]; |
36 | 35 | ||
37 | void init_registers(int pid) | 36 | int init_registers(int pid) |
38 | { | 37 | { |
39 | int err; | 38 | int err; |
40 | 39 | ||
41 | err = ptrace(PTRACE_GETREGS, pid, 0, exec_regs); | 40 | err = ptrace(PTRACE_GETREGS, pid, 0, exec_regs); |
42 | if (err) | 41 | if (err < 0) |
43 | panic("check_ptrace : PTRACE_GETREGS failed, errno = %d", | 42 | return -errno; |
44 | errno); | ||
45 | 43 | ||
46 | arch_init_registers(pid); | 44 | arch_init_registers(pid); |
45 | return 0; | ||
47 | } | 46 | } |
48 | 47 | ||
49 | void get_safe_registers(unsigned long *regs) | 48 | void get_safe_registers(unsigned long *regs) |
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index 7dc24e3cb190..862fea0290ec 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c | |||
@@ -38,17 +38,17 @@ int is_skas_winch(int pid, int fd, void *data) | |||
38 | 38 | ||
39 | static int ptrace_dump_regs(int pid) | 39 | static int ptrace_dump_regs(int pid) |
40 | { | 40 | { |
41 | unsigned long regs[MAX_REG_NR]; | 41 | unsigned long regs[MAX_REG_NR]; |
42 | int i; | 42 | int i; |
43 | 43 | ||
44 | if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) | 44 | if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) |
45 | return -errno; | 45 | return -errno; |
46 | 46 | ||
47 | printk(UM_KERN_ERR "Stub registers -\n"); | 47 | printk(UM_KERN_ERR "Stub registers -\n"); |
48 | for (i = 0; i < ARRAY_SIZE(regs); i++) | 48 | for (i = 0; i < ARRAY_SIZE(regs); i++) |
49 | printk(UM_KERN_ERR "\t%d - %lx\n", i, regs[i]); | 49 | printk(UM_KERN_ERR "\t%d - %lx\n", i, regs[i]); |
50 | 50 | ||
51 | return 0; | 51 | return 0; |
52 | } | 52 | } |
53 | 53 | ||
54 | /* | 54 | /* |
@@ -73,9 +73,11 @@ void wait_stub_done(int pid) | |||
73 | break; | 73 | break; |
74 | 74 | ||
75 | err = ptrace(PTRACE_CONT, pid, 0, 0); | 75 | err = ptrace(PTRACE_CONT, pid, 0, 0); |
76 | if (err) | 76 | if (err) { |
77 | panic("wait_stub_done : continue failed, errno = %d\n", | 77 | printk(UM_KERN_ERR "wait_stub_done : continue failed, " |
78 | errno); | 78 | "errno = %d\n", errno); |
79 | fatal_sigsegv(); | ||
80 | } | ||
79 | } | 81 | } |
80 | 82 | ||
81 | if (((1 << WSTOPSIG(status)) & STUB_DONE_MASK) != 0) | 83 | if (((1 << WSTOPSIG(status)) & STUB_DONE_MASK) != 0) |
@@ -86,8 +88,10 @@ bad_wait: | |||
86 | if (err) | 88 | if (err) |
87 | printk(UM_KERN_ERR "Failed to get registers from stub, " | 89 | printk(UM_KERN_ERR "Failed to get registers from stub, " |
88 | "errno = %d\n", -err); | 90 | "errno = %d\n", -err); |
89 | panic("wait_stub_done : failed to wait for SIGUSR1/SIGTRAP, pid = %d, " | 91 | printk(UM_KERN_ERR "wait_stub_done : failed to wait for SIGTRAP, " |
90 | "n = %d, errno = %d, status = 0x%x\n", pid, n, errno, status); | 92 | "pid = %d, n = %d, errno = %d, status = 0x%x\n", pid, n, errno, |
93 | status); | ||
94 | fatal_sigsegv(); | ||
91 | } | 95 | } |
92 | 96 | ||
93 | extern unsigned long current_stub_stack(void); | 97 | extern unsigned long current_stub_stack(void); |
@@ -98,9 +102,11 @@ void get_skas_faultinfo(int pid, struct faultinfo * fi) | |||
98 | 102 | ||
99 | if (ptrace_faultinfo) { | 103 | if (ptrace_faultinfo) { |
100 | err = ptrace(PTRACE_FAULTINFO, pid, 0, fi); | 104 | err = ptrace(PTRACE_FAULTINFO, pid, 0, fi); |
101 | if (err) | 105 | if (err) { |
102 | panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, " | 106 | printk(UM_KERN_ERR "get_skas_faultinfo - " |
103 | "errno = %d\n", errno); | 107 | "PTRACE_FAULTINFO failed, errno = %d\n", errno); |
108 | fatal_sigsegv(); | ||
109 | } | ||
104 | 110 | ||
105 | /* Special handling for i386, which has different structs */ | 111 | /* Special handling for i386, which has different structs */ |
106 | if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo)) | 112 | if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo)) |
@@ -110,9 +116,11 @@ void get_skas_faultinfo(int pid, struct faultinfo * fi) | |||
110 | } | 116 | } |
111 | else { | 117 | else { |
112 | err = ptrace(PTRACE_CONT, pid, 0, SIGSEGV); | 118 | err = ptrace(PTRACE_CONT, pid, 0, SIGSEGV); |
113 | if (err) | 119 | if (err) { |
114 | panic("Failed to continue stub, pid = %d, errno = %d\n", | 120 | printk(UM_KERN_ERR "Failed to continue stub, pid = %d, " |
115 | pid, errno); | 121 | "errno = %d\n", pid, errno); |
122 | fatal_sigsegv(); | ||
123 | } | ||
116 | wait_stub_done(pid); | 124 | wait_stub_done(pid); |
117 | 125 | ||
118 | /* | 126 | /* |
@@ -145,25 +153,31 @@ static void handle_trap(int pid, struct uml_pt_regs *regs, | |||
145 | { | 153 | { |
146 | err = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, | 154 | err = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, |
147 | __NR_getpid); | 155 | __NR_getpid); |
148 | if (err < 0) | 156 | if (err < 0) { |
149 | panic("handle_trap - nullifying syscall failed, " | 157 | printk(UM_KERN_ERR "handle_trap - nullifying syscall " |
150 | "errno = %d\n", errno); | 158 | "failed, errno = %d\n", errno); |
159 | fatal_sigsegv(); | ||
160 | } | ||
151 | 161 | ||
152 | err = ptrace(PTRACE_SYSCALL, pid, 0, 0); | 162 | err = ptrace(PTRACE_SYSCALL, pid, 0, 0); |
153 | if (err < 0) | 163 | if (err < 0) { |
154 | panic("handle_trap - continuing to end of syscall " | 164 | printk(UM_KERN_ERR "handle_trap - continuing to end of " |
155 | "failed, errno = %d\n", errno); | 165 | "syscall failed, errno = %d\n", errno); |
166 | fatal_sigsegv(); | ||
167 | } | ||
156 | 168 | ||
157 | CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL)); | 169 | CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL)); |
158 | if ((err < 0) || !WIFSTOPPED(status) || | 170 | if ((err < 0) || !WIFSTOPPED(status) || |
159 | (WSTOPSIG(status) != SIGTRAP + 0x80)) { | 171 | (WSTOPSIG(status) != SIGTRAP + 0x80)) { |
160 | err = ptrace_dump_regs(pid); | 172 | err = ptrace_dump_regs(pid); |
161 | if (err) | 173 | if (err) |
162 | printk(UM_KERN_ERR "Failed to get registers " | 174 | printk(UM_KERN_ERR "Failed to get registers " |
163 | "from process, errno = %d\n", -err); | 175 | "from process, errno = %d\n", -err); |
164 | panic("handle_trap - failed to wait at end of syscall, " | 176 | printk(UM_KERN_ERR "handle_trap - failed to wait at " |
165 | "errno = %d, status = %d\n", errno, status); | 177 | "end of syscall, errno = %d, status = %d\n", |
166 | } | 178 | errno, status); |
179 | fatal_sigsegv(); | ||
180 | } | ||
167 | } | 181 | } |
168 | 182 | ||
169 | handle_syscall(regs); | 183 | handle_syscall(regs); |
@@ -181,9 +195,11 @@ static int userspace_tramp(void *stack) | |||
181 | signal(SIGTERM, SIG_DFL); | 195 | signal(SIGTERM, SIG_DFL); |
182 | signal(SIGWINCH, SIG_IGN); | 196 | signal(SIGWINCH, SIG_IGN); |
183 | err = set_interval(); | 197 | err = set_interval(); |
184 | if (err) | 198 | if (err) { |
185 | panic("userspace_tramp - setting timer failed, errno = %d\n", | 199 | printk(UM_KERN_ERR "userspace_tramp - setting timer failed, " |
186 | err); | 200 | "errno = %d\n", err); |
201 | exit(1); | ||
202 | } | ||
187 | 203 | ||
188 | if (!proc_mm) { | 204 | if (!proc_mm) { |
189 | /* | 205 | /* |
@@ -226,9 +242,11 @@ static int userspace_tramp(void *stack) | |||
226 | sa.sa_flags = SA_ONSTACK | SA_NODEFER; | 242 | sa.sa_flags = SA_ONSTACK | SA_NODEFER; |
227 | sa.sa_handler = (void *) v; | 243 | sa.sa_handler = (void *) v; |
228 | sa.sa_restorer = NULL; | 244 | sa.sa_restorer = NULL; |
229 | if (sigaction(SIGSEGV, &sa, NULL) < 0) | 245 | if (sigaction(SIGSEGV, &sa, NULL) < 0) { |
230 | panic("userspace_tramp - setting SIGSEGV handler " | 246 | printk(UM_KERN_ERR "userspace_tramp - setting SIGSEGV " |
231 | "failed - errno = %d\n", errno); | 247 | "handler failed - errno = %d\n", errno); |
248 | exit(1); | ||
249 | } | ||
232 | } | 250 | } |
233 | 251 | ||
234 | kill(os_getpid(), SIGSTOP); | 252 | kill(os_getpid(), SIGSTOP); |
@@ -244,13 +262,18 @@ int start_userspace(unsigned long stub_stack) | |||
244 | { | 262 | { |
245 | void *stack; | 263 | void *stack; |
246 | unsigned long sp; | 264 | unsigned long sp; |
247 | int pid, status, n, flags; | 265 | int pid, status, n, flags, err; |
248 | 266 | ||
249 | stack = mmap(NULL, UM_KERN_PAGE_SIZE, | 267 | stack = mmap(NULL, UM_KERN_PAGE_SIZE, |
250 | PROT_READ | PROT_WRITE | PROT_EXEC, | 268 | PROT_READ | PROT_WRITE | PROT_EXEC, |
251 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | 269 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
252 | if (stack == MAP_FAILED) | 270 | if (stack == MAP_FAILED) { |
253 | panic("start_userspace : mmap failed, errno = %d", errno); | 271 | err = -errno; |
272 | printk(UM_KERN_ERR "start_userspace : mmap failed, " | ||
273 | "errno = %d", errno); | ||
274 | return err; | ||
275 | } | ||
276 | |||
254 | sp = (unsigned long) stack + UM_KERN_PAGE_SIZE - sizeof(void *); | 277 | sp = (unsigned long) stack + UM_KERN_PAGE_SIZE - sizeof(void *); |
255 | 278 | ||
256 | flags = CLONE_FILES; | 279 | flags = CLONE_FILES; |
@@ -260,29 +283,50 @@ int start_userspace(unsigned long stub_stack) | |||
260 | flags |= SIGCHLD; | 283 | flags |= SIGCHLD; |
261 | 284 | ||
262 | pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack); | 285 | pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack); |
263 | if (pid < 0) | 286 | if (pid < 0) { |
264 | panic("start_userspace : clone failed, errno = %d", errno); | 287 | err = -errno; |
288 | printk(UM_KERN_ERR "start_userspace : clone failed, " | ||
289 | "errno = %d", errno); | ||
290 | return err; | ||
291 | } | ||
265 | 292 | ||
266 | do { | 293 | do { |
267 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED | __WALL)); | 294 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED | __WALL)); |
268 | if (n < 0) | 295 | if (n < 0) { |
269 | panic("start_userspace : wait failed, errno = %d", | 296 | err = -errno; |
270 | errno); | 297 | printk(UM_KERN_ERR "start_userspace : wait failed, " |
298 | "errno = %d", errno); | ||
299 | goto out_kill; | ||
300 | } | ||
271 | } while (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM)); | 301 | } while (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM)); |
272 | 302 | ||
273 | if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) | 303 | if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) { |
274 | panic("start_userspace : expected SIGSTOP, got status = %d", | 304 | err = -EINVAL; |
275 | status); | 305 | printk(UM_KERN_ERR "start_userspace : expected SIGSTOP, got " |
306 | "status = %d", status); | ||
307 | goto out_kill; | ||
308 | } | ||
276 | 309 | ||
277 | if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, | 310 | if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, |
278 | (void *) PTRACE_O_TRACESYSGOOD) < 0) | 311 | (void *) PTRACE_O_TRACESYSGOOD) < 0) { |
279 | panic("start_userspace : PTRACE_OLDSETOPTIONS failed, " | 312 | err = -errno; |
280 | "errno = %d\n", errno); | 313 | printk(UM_KERN_ERR "start_userspace : PTRACE_OLDSETOPTIONS " |
314 | "failed, errno = %d\n", errno); | ||
315 | goto out_kill; | ||
316 | } | ||
281 | 317 | ||
282 | if (munmap(stack, UM_KERN_PAGE_SIZE) < 0) | 318 | if (munmap(stack, UM_KERN_PAGE_SIZE) < 0) { |
283 | panic("start_userspace : munmap failed, errno = %d\n", errno); | 319 | err = -errno; |
320 | printk(UM_KERN_ERR "start_userspace : munmap failed, " | ||
321 | "errno = %d\n", errno); | ||
322 | goto out_kill; | ||
323 | } | ||
284 | 324 | ||
285 | return pid; | 325 | return pid; |
326 | |||
327 | out_kill: | ||
328 | os_kill_ptraced_process(pid, 1); | ||
329 | return err; | ||
286 | } | 330 | } |
287 | 331 | ||
288 | void userspace(struct uml_pt_regs *regs) | 332 | void userspace(struct uml_pt_regs *regs) |
@@ -300,9 +344,16 @@ void userspace(struct uml_pt_regs *regs) | |||
300 | nsecs += os_nsecs(); | 344 | nsecs += os_nsecs(); |
301 | 345 | ||
302 | while (1) { | 346 | while (1) { |
347 | /* | ||
348 | * This can legitimately fail if the process loads a | ||
349 | * bogus value into a segment register. It will | ||
350 | * segfault and PTRACE_GETREGS will read that value | ||
351 | * out of the process. However, PTRACE_SETREGS will | ||
352 | * fail. In this case, there is nothing to do but | ||
353 | * just kill the process. | ||
354 | */ | ||
303 | if (ptrace(PTRACE_SETREGS, pid, 0, regs->gp)) | 355 | if (ptrace(PTRACE_SETREGS, pid, 0, regs->gp)) |
304 | panic("userspace - PTRACE_SETREGS failed, " | 356 | fatal_sigsegv(); |
305 | "errno = %d\n", errno); | ||
306 | 357 | ||
307 | /* Now we set local_using_sysemu to be used for one loop */ | 358 | /* Now we set local_using_sysemu to be used for one loop */ |
308 | local_using_sysemu = get_using_sysemu(); | 359 | local_using_sysemu = get_using_sysemu(); |
@@ -310,21 +361,25 @@ void userspace(struct uml_pt_regs *regs) | |||
310 | op = SELECT_PTRACE_OPERATION(local_using_sysemu, | 361 | op = SELECT_PTRACE_OPERATION(local_using_sysemu, |
311 | singlestepping(NULL)); | 362 | singlestepping(NULL)); |
312 | 363 | ||
313 | err = ptrace(op, pid, 0, 0); | 364 | if (ptrace(op, pid, 0, 0)) { |
314 | if (err) | 365 | printk(UM_KERN_ERR "userspace - ptrace continue " |
315 | panic("userspace - could not resume userspace process, " | 366 | "failed, op = %d, errno = %d\n", op, errno); |
316 | "pid=%d, ptrace operation = %d, errno = %d\n", | 367 | fatal_sigsegv(); |
317 | pid, op, errno); | 368 | } |
318 | 369 | ||
319 | CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL)); | 370 | CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL)); |
320 | if (err < 0) | 371 | if (err < 0) { |
321 | panic("userspace - waitpid failed, errno = %d\n", | 372 | printk(UM_KERN_ERR "userspace - wait failed, " |
322 | errno); | 373 | "errno = %d\n", errno); |
374 | fatal_sigsegv(); | ||
375 | } | ||
323 | 376 | ||
324 | regs->is_user = 1; | 377 | regs->is_user = 1; |
325 | if (ptrace(PTRACE_GETREGS, pid, 0, regs->gp)) | 378 | if (ptrace(PTRACE_GETREGS, pid, 0, regs->gp)) { |
326 | panic("userspace - saving registers failed, " | 379 | printk(UM_KERN_ERR "userspace - PTRACE_GETREGS failed, " |
327 | "errno = %d\n", errno); | 380 | "errno = %d\n", errno); |
381 | fatal_sigsegv(); | ||
382 | } | ||
328 | 383 | ||
329 | UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */ | 384 | UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */ |
330 | 385 | ||
@@ -371,6 +426,7 @@ void userspace(struct uml_pt_regs *regs) | |||
371 | default: | 426 | default: |
372 | printk(UM_KERN_ERR "userspace - child stopped " | 427 | printk(UM_KERN_ERR "userspace - child stopped " |
373 | "with signal %d\n", sig); | 428 | "with signal %d\n", sig); |
429 | fatal_sigsegv(); | ||
374 | } | 430 | } |
375 | pid = userspace_pid[0]; | 431 | pid = userspace_pid[0]; |
376 | interrupt_end(); | 432 | interrupt_end(); |
@@ -422,9 +478,12 @@ int copy_context_skas0(unsigned long new_stack, int pid) | |||
422 | .it_interval = tv }) }); | 478 | .it_interval = tv }) }); |
423 | 479 | ||
424 | err = ptrace_setregs(pid, thread_regs); | 480 | err = ptrace_setregs(pid, thread_regs); |
425 | if (err < 0) | 481 | if (err < 0) { |
426 | panic("copy_context_skas0 : PTRACE_SETREGS failed, " | 482 | err = -errno; |
427 | "pid = %d, errno = %d\n", pid, -err); | 483 | printk(UM_KERN_ERR "copy_context_skas0 : PTRACE_SETREGS " |
484 | "failed, pid = %d, errno = %d\n", pid, -err); | ||
485 | return err; | ||
486 | } | ||
428 | 487 | ||
429 | /* set a well known return code for detection of child write failure */ | 488 | /* set a well known return code for detection of child write failure */ |
430 | child_data->err = 12345678; | 489 | child_data->err = 12345678; |
@@ -434,31 +493,47 @@ int copy_context_skas0(unsigned long new_stack, int pid) | |||
434 | * parent's stack, and check, if bad result. | 493 | * parent's stack, and check, if bad result. |
435 | */ | 494 | */ |
436 | err = ptrace(PTRACE_CONT, pid, 0, 0); | 495 | err = ptrace(PTRACE_CONT, pid, 0, 0); |
437 | if (err) | 496 | if (err) { |
438 | panic("Failed to continue new process, pid = %d, " | 497 | err = -errno; |
439 | "errno = %d\n", pid, errno); | 498 | printk(UM_KERN_ERR "Failed to continue new process, pid = %d, " |
499 | "errno = %d\n", pid, errno); | ||
500 | return err; | ||
501 | } | ||
502 | |||
440 | wait_stub_done(pid); | 503 | wait_stub_done(pid); |
441 | 504 | ||
442 | pid = data->err; | 505 | pid = data->err; |
443 | if (pid < 0) | 506 | if (pid < 0) { |
444 | panic("copy_context_skas0 - stub-parent reports error %d\n", | 507 | printk(UM_KERN_ERR "copy_context_skas0 - stub-parent reports " |
445 | -pid); | 508 | "error %d\n", -pid); |
509 | return pid; | ||
510 | } | ||
446 | 511 | ||
447 | /* | 512 | /* |
448 | * Wait, until child has finished too: read child's result from | 513 | * Wait, until child has finished too: read child's result from |
449 | * child's stack and check it. | 514 | * child's stack and check it. |
450 | */ | 515 | */ |
451 | wait_stub_done(pid); | 516 | wait_stub_done(pid); |
452 | if (child_data->err != STUB_DATA) | 517 | if (child_data->err != STUB_DATA) { |
453 | panic("copy_context_skas0 - stub-child reports error %ld\n", | 518 | printk(UM_KERN_ERR "copy_context_skas0 - stub-child reports " |
454 | child_data->err); | 519 | "error %ld\n", child_data->err); |
520 | err = child_data->err; | ||
521 | goto out_kill; | ||
522 | } | ||
455 | 523 | ||
456 | if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, | 524 | if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, |
457 | (void *)PTRACE_O_TRACESYSGOOD) < 0) | 525 | (void *)PTRACE_O_TRACESYSGOOD) < 0) { |
458 | panic("copy_context_skas0 : PTRACE_OLDSETOPTIONS failed, " | 526 | err = -errno; |
459 | "errno = %d\n", errno); | 527 | printk(UM_KERN_ERR "copy_context_skas0 : PTRACE_OLDSETOPTIONS " |
528 | "failed, errno = %d\n", errno); | ||
529 | goto out_kill; | ||
530 | } | ||
460 | 531 | ||
461 | return pid; | 532 | return pid; |
533 | |||
534 | out_kill: | ||
535 | os_kill_ptraced_process(pid, 1); | ||
536 | return err; | ||
462 | } | 537 | } |
463 | 538 | ||
464 | /* | 539 | /* |
@@ -466,8 +541,8 @@ int copy_context_skas0(unsigned long new_stack, int pid) | |||
466 | * available. Opening /proc/mm creates a new mm_context, which lacks | 541 | * available. Opening /proc/mm creates a new mm_context, which lacks |
467 | * the stub-pages. Thus, we map them using /proc/mm-fd | 542 | * the stub-pages. Thus, we map them using /proc/mm-fd |
468 | */ | 543 | */ |
469 | void map_stub_pages(int fd, unsigned long code, | 544 | int map_stub_pages(int fd, unsigned long code, unsigned long data, |
470 | unsigned long data, unsigned long stack) | 545 | unsigned long stack) |
471 | { | 546 | { |
472 | struct proc_mm_op mmop; | 547 | struct proc_mm_op mmop; |
473 | int n; | 548 | int n; |
@@ -491,8 +566,9 @@ void map_stub_pages(int fd, unsigned long code, | |||
491 | printk(UM_KERN_ERR "mmap args - addr = 0x%lx, fd = %d, " | 566 | printk(UM_KERN_ERR "mmap args - addr = 0x%lx, fd = %d, " |
492 | "offset = %llx\n", code, code_fd, | 567 | "offset = %llx\n", code, code_fd, |
493 | (unsigned long long) code_offset); | 568 | (unsigned long long) code_offset); |
494 | panic("map_stub_pages : /proc/mm map for code failed, " | 569 | printk(UM_KERN_ERR "map_stub_pages : /proc/mm map for code " |
495 | "err = %d\n", n); | 570 | "failed, err = %d\n", n); |
571 | return -n; | ||
496 | } | 572 | } |
497 | 573 | ||
498 | if (stack) { | 574 | if (stack) { |
@@ -510,10 +586,15 @@ void map_stub_pages(int fd, unsigned long code, | |||
510 | .offset = map_offset | 586 | .offset = map_offset |
511 | } } }); | 587 | } } }); |
512 | CATCH_EINTR(n = write(fd, &mmop, sizeof(mmop))); | 588 | CATCH_EINTR(n = write(fd, &mmop, sizeof(mmop))); |
513 | if (n != sizeof(mmop)) | 589 | if (n != sizeof(mmop)) { |
514 | panic("map_stub_pages : /proc/mm map for data failed, " | 590 | n = errno; |
515 | "err = %d\n", errno); | 591 | printk(UM_KERN_ERR "map_stub_pages : /proc/mm map for " |
592 | "data failed, err = %d\n", n); | ||
593 | return -n; | ||
594 | } | ||
516 | } | 595 | } |
596 | |||
597 | return 0; | ||
517 | } | 598 | } |
518 | 599 | ||
519 | void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)) | 600 | void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)) |
@@ -574,7 +655,9 @@ int start_idle_thread(void *stack, jmp_buf *switch_buf) | |||
574 | kmalloc_ok = 0; | 655 | kmalloc_ok = 0; |
575 | return 1; | 656 | return 1; |
576 | default: | 657 | default: |
577 | panic("Bad sigsetjmp return in start_idle_thread - %d\n", n); | 658 | printk(UM_KERN_ERR "Bad sigsetjmp return in " |
659 | "start_idle_thread - %d\n", n); | ||
660 | fatal_sigsegv(); | ||
578 | } | 661 | } |
579 | longjmp(*switch_buf, 1); | 662 | longjmp(*switch_buf, 1); |
580 | } | 663 | } |
@@ -617,9 +700,11 @@ void __switch_mm(struct mm_id *mm_idp) | |||
617 | if (proc_mm) { | 700 | if (proc_mm) { |
618 | err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, | 701 | err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, |
619 | mm_idp->u.mm_fd); | 702 | mm_idp->u.mm_fd); |
620 | if (err) | 703 | if (err) { |
621 | panic("__switch_mm - PTRACE_SWITCH_MM failed, " | 704 | printk(UM_KERN_ERR "__switch_mm - PTRACE_SWITCH_MM " |
622 | "errno = %d\n", errno); | 705 | "failed, errno = %d\n", errno); |
706 | fatal_sigsegv(); | ||
707 | } | ||
623 | } | 708 | } |
624 | else userspace_pid[0] = mm_idp->u.pid; | 709 | else userspace_pid[0] = mm_idp->u.pid; |
625 | } | 710 | } |
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index b07887c36bb0..6d56d15884fd 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c | |||
@@ -411,7 +411,9 @@ static inline void check_skas3_ptrace_faultinfo(void) | |||
411 | non_fatal("found\n"); | 411 | non_fatal("found\n"); |
412 | } | 412 | } |
413 | 413 | ||
414 | init_registers(pid); | 414 | if (init_registers(pid)) |
415 | fatal("Failed to initialize default registers"); | ||
416 | |||
415 | stop_ptraced_child(pid, 1, 1); | 417 | stop_ptraced_child(pid, 1, 1); |
416 | } | 418 | } |
417 | 419 | ||
diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c index e437ee2215c5..f1199fd34d38 100644 --- a/arch/um/sys-x86_64/syscalls.c +++ b/arch/um/sys-x86_64/syscalls.c | |||
@@ -48,7 +48,9 @@ long arch_prctl(struct task_struct *task, int code, unsigned long __user *addr) | |||
48 | switch (code) { | 48 | switch (code) { |
49 | case ARCH_SET_FS: | 49 | case ARCH_SET_FS: |
50 | case ARCH_SET_GS: | 50 | case ARCH_SET_GS: |
51 | restore_registers(pid, ¤t->thread.regs.regs); | 51 | ret = restore_registers(pid, ¤t->thread.regs.regs); |
52 | if (ret) | ||
53 | return ret; | ||
52 | break; | 54 | break; |
53 | case ARCH_GET_FS: | 55 | case ARCH_GET_FS: |
54 | case ARCH_GET_GS: | 56 | case ARCH_GET_GS: |
@@ -70,10 +72,10 @@ long arch_prctl(struct task_struct *task, int code, unsigned long __user *addr) | |||
70 | switch (code) { | 72 | switch (code) { |
71 | case ARCH_SET_FS: | 73 | case ARCH_SET_FS: |
72 | current->thread.arch.fs = (unsigned long) ptr; | 74 | current->thread.arch.fs = (unsigned long) ptr; |
73 | save_registers(pid, ¤t->thread.regs.regs); | 75 | ret = save_registers(pid, ¤t->thread.regs.regs); |
74 | break; | 76 | break; |
75 | case ARCH_SET_GS: | 77 | case ARCH_SET_GS: |
76 | save_registers(pid, ¤t->thread.regs.regs); | 78 | ret = save_registers(pid, ¤t->thread.regs.regs); |
77 | break; | 79 | break; |
78 | case ARCH_GET_FS: | 80 | case ARCH_GET_FS: |
79 | ret = put_user(tmp, addr); | 81 | ret = put_user(tmp, addr); |