aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorJeff Dike <jdike@addtoit.com>2008-02-05 01:30:58 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-05 12:44:28 -0500
commit3e6f2ac480ce398ade2fd6b5e02d00d1265f1e0f (patch)
tree25f5589189170c20a765d4e6f0c56b42ad58ea20 /arch
parentd25f2e1235aab716c9fd6ba36c42503627a3a0e3 (diff)
uml: kill processes instead of panicing kernel
UML was panicing in the case of failures of libc calls which shouldn't happen. This is an overreaction since a failure from libc doesn't normally mean that kernel data structures are in an unknown state. Instead, the current process should just be killed if there is no way to recover. The case that prompted this was a failure of PTRACE_SETREGS restoring the same state that was read by PTRACE_GETREGS. It appears that when a process tries to load a bogus value into a segment register, it segfaults (as expected) and the value is actually loaded and is seen by PTRACE_GETREGS (not expected). This case is fixed by forcing a fatal SIGSEGV on the process so that it immediately dies. fatal_sigsegv was added for this purpose. It was declared as noreturn, so in order to pursuade gcc that it actually does not return, I added a call to os_dump_core (and declared it noreturn) so that I get a core file if somehow the process survives. All other calls in arch/um/os-Linux/skas/process.c got the same treatment, with failures causing the process to die instead of a kernel panic, with some exceptions. userspace_tramp exits with status 1 if anything goes wrong there. That will cause start_userspace to return an error. copy_context_skas0 and map_stub_pages also now return errors instead of panicing. Callers of thes functions were changed to check for errors and do something appropriate. Usually that's to return an error to their callers. check_skas3_ptrace_faultinfo just exits since that's too early to do anything else. save_registers, restore_registers, and init_registers now return status instead of panicing on failure, with their callers doing something appropriate. There were also duplicate declarations of save_registers and restore_registers in os.h - these are gone. I noticed and fixed up some whitespace damage. Signed-off-by: Jeff Dike <jdike@linux.intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/um/include/kern_util.h1
-rw-r--r--arch/um/include/os.h8
-rw-r--r--arch/um/include/registers.h6
-rw-r--r--arch/um/kernel/skas/mmu.c5
-rw-r--r--arch/um/kernel/skas/process.c20
-rw-r--r--arch/um/kernel/trap.c12
-rw-r--r--arch/um/os-Linux/registers.c21
-rw-r--r--arch/um/os-Linux/skas/process.c265
-rw-r--r--arch/um/os-Linux/start_up.c4
-rw-r--r--arch/um/sys-x86_64/syscalls.c8
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);
62extern void segv_handler(int sig, struct uml_pt_regs *regs); 62extern void segv_handler(int sig, struct uml_pt_regs *regs);
63extern void bus_handler(int sig, struct uml_pt_regs *regs); 63extern void bus_handler(int sig, struct uml_pt_regs *regs);
64extern void winch(int sig, struct uml_pt_regs *regs); 64extern void winch(int sig, struct uml_pt_regs *regs);
65extern 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);
238extern void setup_machinename(char *machine_out); 238extern void setup_machinename(char *machine_out);
239extern void setup_hostinfo(char *buf, int len); 239extern void setup_hostinfo(char *buf, int len);
240extern int setjmp_wrapper(void (*proc)(void *, void *), ...); 240extern int setjmp_wrapper(void (*proc)(void *, void *), ...);
241extern void os_dump_core(void); 241extern void os_dump_core(void) __attribute__ ((noreturn));
242 242
243/* time.c */ 243/* time.c */
244extern void idle_sleep(unsigned long long nsecs); 244extern void idle_sleep(unsigned long long nsecs);
@@ -267,11 +267,9 @@ extern int protect(struct mm_id * mm_idp, unsigned long addr,
267extern int is_skas_winch(int pid, int fd, void *data); 267extern int is_skas_winch(int pid, int fd, void *data);
268extern int start_userspace(unsigned long stub_stack); 268extern int start_userspace(unsigned long stub_stack);
269extern int copy_context_skas0(unsigned long stack, int pid); 269extern int copy_context_skas0(unsigned long stack, int pid);
270extern void save_registers(int pid, struct uml_pt_regs *regs);
271extern void restore_registers(int pid, struct uml_pt_regs *regs);
272extern void userspace(struct uml_pt_regs *regs); 270extern void userspace(struct uml_pt_regs *regs);
273extern void map_stub_pages(int fd, unsigned long code, 271extern int map_stub_pages(int fd, unsigned long code, unsigned long data,
274 unsigned long data, unsigned long stack); 272 unsigned long stack);
275extern void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)); 273extern void new_thread(void *stack, jmp_buf *buf, void (*handler)(void));
276extern void switch_threads(jmp_buf *me, jmp_buf *you); 274extern void switch_threads(jmp_buf *me, jmp_buf *you);
277extern int start_idle_thread(void *stack, jmp_buf *switch_buf); 275extern 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);
13extern int restore_fp_registers(int pid, unsigned long *fp_regs); 13extern int restore_fp_registers(int pid, unsigned long *fp_regs);
14extern int save_fpx_registers(int pid, unsigned long *fp_regs); 14extern int save_fpx_registers(int pid, unsigned long *fp_regs);
15extern int restore_fpx_registers(int pid, unsigned long *fp_regs); 15extern int restore_fpx_registers(int pid, unsigned long *fp_regs);
16extern void save_registers(int pid, struct uml_pt_regs *regs); 16extern int save_registers(int pid, struct uml_pt_regs *regs);
17extern void restore_registers(int pid, struct uml_pt_regs *regs); 17extern int restore_registers(int pid, struct uml_pt_regs *regs);
18extern void init_registers(int pid); 18extern int init_registers(int pid);
19extern void get_safe_registers(unsigned long *regs); 19extern void get_safe_registers(unsigned long *regs);
20extern unsigned long get_thread_reg(int reg, jmp_buf *buf); 20extern 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
12int new_mm(unsigned long stack) 13int 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
132void 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
132void segv_handler(int sig, struct uml_pt_regs *regs) 144void 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
13void save_registers(int pid, struct uml_pt_regs *regs) 12int 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
23void restore_registers(int pid, struct uml_pt_regs *regs) 22int 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
35static unsigned long exec_regs[MAX_REG_NR]; 34static unsigned long exec_regs[MAX_REG_NR];
36 35
37void init_registers(int pid) 36int 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
49void get_safe_registers(unsigned long *regs) 48void 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
39static int ptrace_dump_regs(int pid) 39static 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
93extern unsigned long current_stub_stack(void); 97extern 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
288void userspace(struct uml_pt_regs *regs) 332void 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 */
469void map_stub_pages(int fd, unsigned long code, 544int 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
519void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)) 600void 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, &current->thread.regs.regs); 51 ret = restore_registers(pid, &current->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, &current->thread.regs.regs); 75 ret = save_registers(pid, &current->thread.regs.regs);
74 break; 76 break;
75 case ARCH_SET_GS: 77 case ARCH_SET_GS:
76 save_registers(pid, &current->thread.regs.regs); 78 ret = save_registers(pid, &current->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);