diff options
Diffstat (limited to 'arch/um/kernel')
-rw-r--r-- | arch/um/kernel/ptrace.c | 16 | ||||
-rw-r--r-- | arch/um/kernel/skas/include/skas.h | 3 | ||||
-rw-r--r-- | arch/um/kernel/skas/process.c | 26 | ||||
-rw-r--r-- | arch/um/kernel/skas/trap_user.c | 24 | ||||
-rw-r--r-- | arch/um/kernel/trap_kern.c | 25 | ||||
-rw-r--r-- | arch/um/kernel/trap_user.c | 13 | ||||
-rw-r--r-- | arch/um/kernel/tt/tracer.c | 4 | ||||
-rw-r--r-- | arch/um/kernel/tt/trap_user.c | 6 |
8 files changed, 76 insertions, 41 deletions
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index ffc599bd85c3..ec19fed7c64b 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c | |||
@@ -252,13 +252,13 @@ long sys_ptrace(long request, long pid, long addr, long data) | |||
252 | break; | 252 | break; |
253 | #endif | 253 | #endif |
254 | case PTRACE_FAULTINFO: { | 254 | case PTRACE_FAULTINFO: { |
255 | struct ptrace_faultinfo fault; | 255 | /* Take the info from thread->arch->faultinfo, |
256 | 256 | * but transfer max. sizeof(struct ptrace_faultinfo). | |
257 | fault = ((struct ptrace_faultinfo) | 257 | * On i386, ptrace_faultinfo is smaller! |
258 | { .is_write = child->thread.err, | 258 | */ |
259 | .addr = child->thread.cr2 }); | 259 | ret = copy_to_user((unsigned long __user *) data, |
260 | ret = copy_to_user((unsigned long __user *) data, &fault, | 260 | &child->thread.arch.faultinfo, |
261 | sizeof(fault)); | 261 | sizeof(struct ptrace_faultinfo)); |
262 | if(ret) | 262 | if(ret) |
263 | break; | 263 | break; |
264 | break; | 264 | break; |
@@ -269,6 +269,7 @@ long sys_ptrace(long request, long pid, long addr, long data) | |||
269 | sizeof(child->pending.signal)); | 269 | sizeof(child->pending.signal)); |
270 | break; | 270 | break; |
271 | 271 | ||
272 | #ifdef PTRACE_LDT | ||
272 | case PTRACE_LDT: { | 273 | case PTRACE_LDT: { |
273 | struct ptrace_ldt ldt; | 274 | struct ptrace_ldt ldt; |
274 | 275 | ||
@@ -284,6 +285,7 @@ long sys_ptrace(long request, long pid, long addr, long data) | |||
284 | ret = -EIO; | 285 | ret = -EIO; |
285 | break; | 286 | break; |
286 | } | 287 | } |
288 | #endif | ||
287 | #ifdef CONFIG_PROC_MM | 289 | #ifdef CONFIG_PROC_MM |
288 | case PTRACE_SWITCH_MM: { | 290 | case PTRACE_SWITCH_MM: { |
289 | struct mm_struct *old = child->mm; | 291 | struct mm_struct *old = child->mm; |
diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h index f0702c2c7204..96b51dba3471 100644 --- a/arch/um/kernel/skas/include/skas.h +++ b/arch/um/kernel/skas/include/skas.h | |||
@@ -27,9 +27,10 @@ extern void map(int fd, unsigned long virt, unsigned long len, int r, int w, | |||
27 | extern int unmap(int fd, void *addr, unsigned long len); | 27 | extern int unmap(int fd, void *addr, unsigned long len); |
28 | extern int protect(int fd, unsigned long addr, unsigned long len, | 28 | extern int protect(int fd, unsigned long addr, unsigned long len, |
29 | int r, int w, int x); | 29 | int r, int w, int x); |
30 | extern void user_signal(int sig, union uml_pt_regs *regs); | 30 | extern void user_signal(int sig, union uml_pt_regs *regs, int pid); |
31 | extern int new_mm(int from); | 31 | extern int new_mm(int from); |
32 | extern void start_userspace(int cpu); | 32 | extern void start_userspace(int cpu); |
33 | extern void get_skas_faultinfo(int pid, struct faultinfo * fi); | ||
33 | extern long execute_syscall_skas(void *r); | 34 | extern long execute_syscall_skas(void *r); |
34 | 35 | ||
35 | #endif | 36 | #endif |
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index b4ffaaa81241..c0b30515dfb6 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c | |||
@@ -4,6 +4,7 @@ | |||
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <stdlib.h> | 6 | #include <stdlib.h> |
7 | #include <string.h> | ||
7 | #include <unistd.h> | 8 | #include <unistd.h> |
8 | #include <errno.h> | 9 | #include <errno.h> |
9 | #include <signal.h> | 10 | #include <signal.h> |
@@ -37,17 +38,26 @@ int is_skas_winch(int pid, int fd, void *data) | |||
37 | return(1); | 38 | return(1); |
38 | } | 39 | } |
39 | 40 | ||
40 | static void handle_segv(int pid) | 41 | void get_skas_faultinfo(int pid, struct faultinfo * fi) |
41 | { | 42 | { |
42 | struct ptrace_faultinfo fault; | ||
43 | int err; | 43 | int err; |
44 | 44 | ||
45 | err = ptrace(PTRACE_FAULTINFO, pid, 0, &fault); | 45 | err = ptrace(PTRACE_FAULTINFO, pid, 0, fi); |
46 | if(err) | 46 | if(err) |
47 | panic("handle_segv - PTRACE_FAULTINFO failed, errno = %d\n", | 47 | panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, " |
48 | errno); | 48 | "errno = %d\n", errno); |
49 | |||
50 | /* Special handling for i386, which has different structs */ | ||
51 | if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo)) | ||
52 | memset((char *)fi + sizeof(struct ptrace_faultinfo), 0, | ||
53 | sizeof(struct faultinfo) - | ||
54 | sizeof(struct ptrace_faultinfo)); | ||
55 | } | ||
49 | 56 | ||
50 | segv(fault.addr, 0, FAULT_WRITE(fault.is_write), 1, NULL); | 57 | static void handle_segv(int pid, union uml_pt_regs * regs) |
58 | { | ||
59 | get_skas_faultinfo(pid, ®s->skas.faultinfo); | ||
60 | segv(regs->skas.faultinfo, 0, 1, NULL); | ||
51 | } | 61 | } |
52 | 62 | ||
53 | /*To use the same value of using_sysemu as the caller, ask it that value (in local_using_sysemu)*/ | 63 | /*To use the same value of using_sysemu as the caller, ask it that value (in local_using_sysemu)*/ |
@@ -163,7 +173,7 @@ void userspace(union uml_pt_regs *regs) | |||
163 | if(WIFSTOPPED(status)){ | 173 | if(WIFSTOPPED(status)){ |
164 | switch(WSTOPSIG(status)){ | 174 | switch(WSTOPSIG(status)){ |
165 | case SIGSEGV: | 175 | case SIGSEGV: |
166 | handle_segv(pid); | 176 | handle_segv(pid, regs); |
167 | break; | 177 | break; |
168 | case SIGTRAP + 0x80: | 178 | case SIGTRAP + 0x80: |
169 | handle_trap(pid, regs, local_using_sysemu); | 179 | handle_trap(pid, regs, local_using_sysemu); |
@@ -177,7 +187,7 @@ void userspace(union uml_pt_regs *regs) | |||
177 | case SIGBUS: | 187 | case SIGBUS: |
178 | case SIGFPE: | 188 | case SIGFPE: |
179 | case SIGWINCH: | 189 | case SIGWINCH: |
180 | user_signal(WSTOPSIG(status), regs); | 190 | user_signal(WSTOPSIG(status), regs, pid); |
181 | break; | 191 | break; |
182 | default: | 192 | default: |
183 | printk("userspace - child stopped with signal " | 193 | printk("userspace - child stopped with signal " |
diff --git a/arch/um/kernel/skas/trap_user.c b/arch/um/kernel/skas/trap_user.c index 8e9b46d4702e..0dee1d95c806 100644 --- a/arch/um/kernel/skas/trap_user.c +++ b/arch/um/kernel/skas/trap_user.c | |||
@@ -5,12 +5,15 @@ | |||
5 | 5 | ||
6 | #include <signal.h> | 6 | #include <signal.h> |
7 | #include <errno.h> | 7 | #include <errno.h> |
8 | #include "sysdep/ptrace.h" | ||
9 | #include "signal_user.h" | 8 | #include "signal_user.h" |
10 | #include "user_util.h" | 9 | #include "user_util.h" |
11 | #include "kern_util.h" | 10 | #include "kern_util.h" |
12 | #include "task.h" | 11 | #include "task.h" |
13 | #include "sigcontext.h" | 12 | #include "sigcontext.h" |
13 | #include "skas.h" | ||
14 | #include "ptrace_user.h" | ||
15 | #include "sysdep/ptrace.h" | ||
16 | #include "sysdep/ptrace_user.h" | ||
14 | 17 | ||
15 | void sig_handler_common_skas(int sig, void *sc_ptr) | 18 | void sig_handler_common_skas(int sig, void *sc_ptr) |
16 | { | 19 | { |
@@ -31,9 +34,11 @@ void sig_handler_common_skas(int sig, void *sc_ptr) | |||
31 | r = &TASK_REGS(get_current())->skas; | 34 | r = &TASK_REGS(get_current())->skas; |
32 | save_user = r->is_user; | 35 | save_user = r->is_user; |
33 | r->is_user = 0; | 36 | r->is_user = 0; |
34 | r->fault_addr = SC_FAULT_ADDR(sc); | 37 | if ( sig == SIGFPE || sig == SIGSEGV || |
35 | r->fault_type = SC_FAULT_TYPE(sc); | 38 | sig == SIGBUS || sig == SIGILL || |
36 | r->trap_type = SC_TRAP_TYPE(sc); | 39 | sig == SIGTRAP ) { |
40 | GET_FAULTINFO_FROM_SC(r->faultinfo, sc); | ||
41 | } | ||
37 | 42 | ||
38 | change_sig(SIGUSR1, 1); | 43 | change_sig(SIGUSR1, 1); |
39 | info = &sig_info[sig]; | 44 | info = &sig_info[sig]; |
@@ -45,14 +50,17 @@ void sig_handler_common_skas(int sig, void *sc_ptr) | |||
45 | r->is_user = save_user; | 50 | r->is_user = save_user; |
46 | } | 51 | } |
47 | 52 | ||
48 | void user_signal(int sig, union uml_pt_regs *regs) | 53 | extern int ptrace_faultinfo; |
54 | |||
55 | void user_signal(int sig, union uml_pt_regs *regs, int pid) | ||
49 | { | 56 | { |
50 | struct signal_info *info; | 57 | struct signal_info *info; |
58 | int segv = ((sig == SIGFPE) || (sig == SIGSEGV) || (sig == SIGBUS) || | ||
59 | (sig == SIGILL) || (sig == SIGTRAP)); | ||
51 | 60 | ||
52 | regs->skas.is_user = 1; | 61 | regs->skas.is_user = 1; |
53 | regs->skas.fault_addr = 0; | 62 | if (segv) |
54 | regs->skas.fault_type = 0; | 63 | get_skas_faultinfo(pid, ®s->skas.faultinfo); |
55 | regs->skas.trap_type = 0; | ||
56 | info = &sig_info[sig]; | 64 | info = &sig_info[sig]; |
57 | (*info->handler)(sig, regs); | 65 | (*info->handler)(sig, regs); |
58 | 66 | ||
diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c index 47e766e6ba10..54e2ec33a43c 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap_kern.c | |||
@@ -133,12 +133,19 @@ static int check_remapped_addr(unsigned long address, int is_write) | |||
133 | return(0); | 133 | return(0); |
134 | } | 134 | } |
135 | 135 | ||
136 | unsigned long segv(unsigned long address, unsigned long ip, int is_write, | 136 | /* |
137 | int is_user, void *sc) | 137 | * We give a *copy* of the faultinfo in the regs to segv. |
138 | * This must be done, since nesting SEGVs could overwrite | ||
139 | * the info in the regs. A pointer to the info then would | ||
140 | * give us bad data! | ||
141 | */ | ||
142 | unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) | ||
138 | { | 143 | { |
139 | struct siginfo si; | 144 | struct siginfo si; |
140 | void *catcher; | 145 | void *catcher; |
141 | int err; | 146 | int err; |
147 | int is_write = FAULT_WRITE(fi); | ||
148 | unsigned long address = FAULT_ADDRESS(fi); | ||
142 | 149 | ||
143 | if(!is_user && (address >= start_vm) && (address < end_vm)){ | 150 | if(!is_user && (address >= start_vm) && (address < end_vm)){ |
144 | flush_tlb_kernel_vm(); | 151 | flush_tlb_kernel_vm(); |
@@ -159,7 +166,7 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write, | |||
159 | } | 166 | } |
160 | else if(current->thread.fault_addr != NULL) | 167 | else if(current->thread.fault_addr != NULL) |
161 | panic("fault_addr set but no fault catcher"); | 168 | panic("fault_addr set but no fault catcher"); |
162 | else if(arch_fixup(ip, sc)) | 169 | else if(!is_user && arch_fixup(ip, sc)) |
163 | return(0); | 170 | return(0); |
164 | 171 | ||
165 | if(!is_user) | 172 | if(!is_user) |
@@ -171,6 +178,7 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write, | |||
171 | si.si_errno = 0; | 178 | si.si_errno = 0; |
172 | si.si_code = BUS_ADRERR; | 179 | si.si_code = BUS_ADRERR; |
173 | si.si_addr = (void *)address; | 180 | si.si_addr = (void *)address; |
181 | current->thread.arch.faultinfo = fi; | ||
174 | force_sig_info(SIGBUS, &si, current); | 182 | force_sig_info(SIGBUS, &si, current); |
175 | } | 183 | } |
176 | else if(err == -ENOMEM){ | 184 | else if(err == -ENOMEM){ |
@@ -180,22 +188,20 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write, | |||
180 | else { | 188 | else { |
181 | si.si_signo = SIGSEGV; | 189 | si.si_signo = SIGSEGV; |
182 | si.si_addr = (void *) address; | 190 | si.si_addr = (void *) address; |
183 | current->thread.cr2 = address; | 191 | current->thread.arch.faultinfo = fi; |
184 | current->thread.err = is_write; | ||
185 | force_sig_info(SIGSEGV, &si, current); | 192 | force_sig_info(SIGSEGV, &si, current); |
186 | } | 193 | } |
187 | return(0); | 194 | return(0); |
188 | } | 195 | } |
189 | 196 | ||
190 | void bad_segv(unsigned long address, unsigned long ip, int is_write) | 197 | void bad_segv(struct faultinfo fi, unsigned long ip) |
191 | { | 198 | { |
192 | struct siginfo si; | 199 | struct siginfo si; |
193 | 200 | ||
194 | si.si_signo = SIGSEGV; | 201 | si.si_signo = SIGSEGV; |
195 | si.si_code = SEGV_ACCERR; | 202 | si.si_code = SEGV_ACCERR; |
196 | si.si_addr = (void *) address; | 203 | si.si_addr = (void *) FAULT_ADDRESS(fi); |
197 | current->thread.cr2 = address; | 204 | current->thread.arch.faultinfo = fi; |
198 | current->thread.err = is_write; | ||
199 | force_sig_info(SIGSEGV, &si, current); | 205 | force_sig_info(SIGSEGV, &si, current); |
200 | } | 206 | } |
201 | 207 | ||
@@ -204,6 +210,7 @@ void relay_signal(int sig, union uml_pt_regs *regs) | |||
204 | if(arch_handle_signal(sig, regs)) return; | 210 | if(arch_handle_signal(sig, regs)) return; |
205 | if(!UPT_IS_USER(regs)) | 211 | if(!UPT_IS_USER(regs)) |
206 | panic("Kernel mode signal %d", sig); | 212 | panic("Kernel mode signal %d", sig); |
213 | current->thread.arch.faultinfo = *UPT_FAULTINFO(regs); | ||
207 | force_sig(sig, current); | 214 | force_sig(sig, current); |
208 | } | 215 | } |
209 | 216 | ||
diff --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c index 50a4042a509f..f825a6eda3f5 100644 --- a/arch/um/kernel/trap_user.c +++ b/arch/um/kernel/trap_user.c | |||
@@ -54,23 +54,22 @@ struct { | |||
54 | void segv_handler(int sig, union uml_pt_regs *regs) | 54 | void segv_handler(int sig, union uml_pt_regs *regs) |
55 | { | 55 | { |
56 | int index, max; | 56 | int index, max; |
57 | struct faultinfo * fi = UPT_FAULTINFO(regs); | ||
57 | 58 | ||
58 | if(UPT_IS_USER(regs) && !UPT_SEGV_IS_FIXABLE(regs)){ | 59 | if(UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)){ |
59 | bad_segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), | 60 | bad_segv(*fi, UPT_IP(regs)); |
60 | UPT_FAULT_WRITE(regs)); | ||
61 | return; | 61 | return; |
62 | } | 62 | } |
63 | max = sizeof(segfault_record)/sizeof(segfault_record[0]); | 63 | max = sizeof(segfault_record)/sizeof(segfault_record[0]); |
64 | index = next_trap_index(max); | 64 | index = next_trap_index(max); |
65 | 65 | ||
66 | nsegfaults++; | 66 | nsegfaults++; |
67 | segfault_record[index].address = UPT_FAULT_ADDR(regs); | 67 | segfault_record[index].address = FAULT_ADDRESS(*fi); |
68 | segfault_record[index].pid = os_getpid(); | 68 | segfault_record[index].pid = os_getpid(); |
69 | segfault_record[index].is_write = UPT_FAULT_WRITE(regs); | 69 | segfault_record[index].is_write = FAULT_WRITE(*fi); |
70 | segfault_record[index].sp = UPT_SP(regs); | 70 | segfault_record[index].sp = UPT_SP(regs); |
71 | segfault_record[index].is_user = UPT_IS_USER(regs); | 71 | segfault_record[index].is_user = UPT_IS_USER(regs); |
72 | segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), UPT_FAULT_WRITE(regs), | 72 | segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs); |
73 | UPT_IS_USER(regs), regs); | ||
74 | } | 73 | } |
75 | 74 | ||
76 | void usr2_handler(int sig, union uml_pt_regs *regs) | 75 | void usr2_handler(int sig, union uml_pt_regs *regs) |
diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c index 7b5d937e5955..f7b1753a025c 100644 --- a/arch/um/kernel/tt/tracer.c +++ b/arch/um/kernel/tt/tracer.c | |||
@@ -89,8 +89,10 @@ void tracer_panic(char *format, ...) | |||
89 | 89 | ||
90 | static void tracer_segv(int sig, struct sigcontext sc) | 90 | static void tracer_segv(int sig, struct sigcontext sc) |
91 | { | 91 | { |
92 | struct faultinfo fi; | ||
93 | GET_FAULTINFO_FROM_SC(fi, &sc); | ||
92 | printf("Tracing thread segfault at address 0x%lx, ip 0x%lx\n", | 94 | printf("Tracing thread segfault at address 0x%lx, ip 0x%lx\n", |
93 | SC_FAULT_ADDR(&sc), SC_IP(&sc)); | 95 | FAULT_ADDRESS(fi), SC_IP(&sc)); |
94 | while(1) | 96 | while(1) |
95 | pause(); | 97 | pause(); |
96 | } | 98 | } |
diff --git a/arch/um/kernel/tt/trap_user.c b/arch/um/kernel/tt/trap_user.c index 92a3820ca543..fc108615beaf 100644 --- a/arch/um/kernel/tt/trap_user.c +++ b/arch/um/kernel/tt/trap_user.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <errno.h> | 7 | #include <errno.h> |
8 | #include <signal.h> | 8 | #include <signal.h> |
9 | #include "sysdep/ptrace.h" | 9 | #include "sysdep/ptrace.h" |
10 | #include "sysdep/sigcontext.h" | ||
10 | #include "signal_user.h" | 11 | #include "signal_user.h" |
11 | #include "user_util.h" | 12 | #include "user_util.h" |
12 | #include "kern_util.h" | 13 | #include "kern_util.h" |
@@ -28,6 +29,11 @@ void sig_handler_common_tt(int sig, void *sc_ptr) | |||
28 | change_sig(SIGSEGV, 1); | 29 | change_sig(SIGSEGV, 1); |
29 | 30 | ||
30 | r = &TASK_REGS(get_current())->tt; | 31 | r = &TASK_REGS(get_current())->tt; |
32 | if ( sig == SIGFPE || sig == SIGSEGV || | ||
33 | sig == SIGBUS || sig == SIGILL || | ||
34 | sig == SIGTRAP ) { | ||
35 | GET_FAULTINFO_FROM_SC(r->faultinfo, sc); | ||
36 | } | ||
31 | save_regs = *r; | 37 | save_regs = *r; |
32 | is_user = user_context(SC_SP(sc)); | 38 | is_user = user_context(SC_SP(sc)); |
33 | r->sc = sc; | 39 | r->sc = sc; |