aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/sys-i386
diff options
context:
space:
mode:
authorJeff Dike <jdike@addtoit.com>2006-03-27 04:14:38 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-03-27 11:44:38 -0500
commit98c18238f146a9038098244d60a7d2b1f67ee790 (patch)
tree97149aafbc265e63cec55d37a655dabbbf64c232 /arch/um/sys-i386
parent6c29256c5703ad7c3cf62276dbc38d802a05669e (diff)
[PATCH] uml: fix segfault on signal delivery
This fixes a process segfault where a signal was being delivered such that a new stack page needed to be allocated to hold the signal frame. This was tripping some logic in the page fault handler which wouldn't allocate the page if the faulting address was more that 32 bytes lower than the current stack pointer. Since a signal frame is greater than 32 bytes, this exercised that case. It's fixed by updating the SP in the pt_regs before starting to copy the signal frame. Since those are the registers that will be copied on to the stack, we have to be careful to put the original SP, not the new one which points to the signal frame, on the stack. Signed-off-by: Jeff Dike <jdike@addtoit.com> Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/um/sys-i386')
-rw-r--r--arch/um/sys-i386/signal.c59
1 files changed, 44 insertions, 15 deletions
diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c
index 7cd1a82dc8c2..33a40f5ef0d2 100644
--- a/arch/um/sys-i386/signal.c
+++ b/arch/um/sys-i386/signal.c
@@ -58,7 +58,7 @@ static int copy_sc_from_user_skas(struct pt_regs *regs,
58} 58}
59 59
60int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, 60int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp,
61 struct pt_regs *regs) 61 struct pt_regs *regs, unsigned long sp)
62{ 62{
63 struct sigcontext sc; 63 struct sigcontext sc;
64 unsigned long fpregs[HOST_FP_SIZE]; 64 unsigned long fpregs[HOST_FP_SIZE];
@@ -72,7 +72,7 @@ int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp,
72 sc.edi = REGS_EDI(regs->regs.skas.regs); 72 sc.edi = REGS_EDI(regs->regs.skas.regs);
73 sc.esi = REGS_ESI(regs->regs.skas.regs); 73 sc.esi = REGS_ESI(regs->regs.skas.regs);
74 sc.ebp = REGS_EBP(regs->regs.skas.regs); 74 sc.ebp = REGS_EBP(regs->regs.skas.regs);
75 sc.esp = REGS_SP(regs->regs.skas.regs); 75 sc.esp = sp;
76 sc.ebx = REGS_EBX(regs->regs.skas.regs); 76 sc.ebx = REGS_EBX(regs->regs.skas.regs);
77 sc.edx = REGS_EDX(regs->regs.skas.regs); 77 sc.edx = REGS_EDX(regs->regs.skas.regs);
78 sc.ecx = REGS_ECX(regs->regs.skas.regs); 78 sc.ecx = REGS_ECX(regs->regs.skas.regs);
@@ -132,7 +132,7 @@ int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from,
132} 132}
133 133
134int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, 134int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp,
135 struct sigcontext *from, int fpsize) 135 struct sigcontext *from, int fpsize, unsigned long sp)
136{ 136{
137 struct _fpstate *to_fp, *from_fp; 137 struct _fpstate *to_fp, *from_fp;
138 int err; 138 int err;
@@ -140,11 +140,18 @@ int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp,
140 to_fp = (fp ? fp : (struct _fpstate *) (to + 1)); 140 to_fp = (fp ? fp : (struct _fpstate *) (to + 1));
141 from_fp = from->fpstate; 141 from_fp = from->fpstate;
142 err = copy_to_user(to, from, sizeof(*to)); 142 err = copy_to_user(to, from, sizeof(*to));
143
144 /* The SP in the sigcontext is the updated one for the signal
145 * delivery. The sp passed in is the original, and this needs
146 * to be restored, so we stick it in separately.
147 */
148 err |= copy_to_user(&SC_SP(to), sp, sizeof(sp));
149
143 if(from_fp != NULL){ 150 if(from_fp != NULL){
144 err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); 151 err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate));
145 err |= copy_to_user(to_fp, from_fp, fpsize); 152 err |= copy_to_user(to_fp, from_fp, fpsize);
146 } 153 }
147 return(err); 154 return err;
148} 155}
149#endif 156#endif
150 157
@@ -159,11 +166,11 @@ static int copy_sc_from_user(struct pt_regs *to, void __user *from)
159} 166}
160 167
161static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp, 168static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp,
162 struct pt_regs *from) 169 struct pt_regs *from, unsigned long sp)
163{ 170{
164 return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), 171 return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs),
165 sizeof(*fp)), 172 sizeof(*fp), sp),
166 copy_sc_to_user_skas(to, fp, from))); 173 copy_sc_to_user_skas(to, fp, from, sp)));
167} 174}
168 175
169static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp, 176static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp,
@@ -174,7 +181,7 @@ static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp,
174 err |= put_user(current->sas_ss_sp, &uc->uc_stack.ss_sp); 181 err |= put_user(current->sas_ss_sp, &uc->uc_stack.ss_sp);
175 err |= put_user(sas_ss_flags(sp), &uc->uc_stack.ss_flags); 182 err |= put_user(sas_ss_flags(sp), &uc->uc_stack.ss_flags);
176 err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size); 183 err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size);
177 err |= copy_sc_to_user(&uc->uc_mcontext, fp, &current->thread.regs); 184 err |= copy_sc_to_user(&uc->uc_mcontext, fp, &current->thread.regs, sp);
178 err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set)); 185 err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set));
179 return(err); 186 return(err);
180} 187}
@@ -207,6 +214,7 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig,
207{ 214{
208 struct sigframe __user *frame; 215 struct sigframe __user *frame;
209 void *restorer; 216 void *restorer;
217 unsigned long save_sp = PT_REGS_SP(regs);
210 int err = 0; 218 int err = 0;
211 219
212 stack_top &= -8UL; 220 stack_top &= -8UL;
@@ -218,9 +226,19 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig,
218 if(ka->sa.sa_flags & SA_RESTORER) 226 if(ka->sa.sa_flags & SA_RESTORER)
219 restorer = ka->sa.sa_restorer; 227 restorer = ka->sa.sa_restorer;
220 228
229 /* Update SP now because the page fault handler refuses to extend
230 * the stack if the faulting address is too far below the current
231 * SP, which frame now certainly is. If there's an error, the original
232 * value is restored on the way out.
233 * When writing the sigcontext to the stack, we have to write the
234 * original value, so that's passed to copy_sc_to_user, which does
235 * the right thing with it.
236 */
237 PT_REGS_SP(regs) = (unsigned long) frame;
238
221 err |= __put_user(restorer, &frame->pretcode); 239 err |= __put_user(restorer, &frame->pretcode);
222 err |= __put_user(sig, &frame->sig); 240 err |= __put_user(sig, &frame->sig);
223 err |= copy_sc_to_user(&frame->sc, NULL, regs); 241 err |= copy_sc_to_user(&frame->sc, NULL, regs, save_sp);
224 err |= __put_user(mask->sig[0], &frame->sc.oldmask); 242 err |= __put_user(mask->sig[0], &frame->sc.oldmask);
225 if (_NSIG_WORDS > 1) 243 if (_NSIG_WORDS > 1)
226 err |= __copy_to_user(&frame->extramask, &mask->sig[1], 244 err |= __copy_to_user(&frame->extramask, &mask->sig[1],
@@ -238,7 +256,7 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig,
238 err |= __put_user(0x80cd, (short __user *)(frame->retcode+6)); 256 err |= __put_user(0x80cd, (short __user *)(frame->retcode+6));
239 257
240 if(err) 258 if(err)
241 return(err); 259 goto err;
242 260
243 PT_REGS_SP(regs) = (unsigned long) frame; 261 PT_REGS_SP(regs) = (unsigned long) frame;
244 PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler; 262 PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler;
@@ -248,7 +266,11 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig,
248 266
249 if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED)) 267 if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
250 ptrace_notify(SIGTRAP); 268 ptrace_notify(SIGTRAP);
251 return(0); 269 return 0;
270
271err:
272 PT_REGS_SP(regs) = save_sp;
273 return err;
252} 274}
253 275
254int setup_signal_stack_si(unsigned long stack_top, int sig, 276int setup_signal_stack_si(unsigned long stack_top, int sig,
@@ -257,6 +279,7 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
257{ 279{
258 struct rt_sigframe __user *frame; 280 struct rt_sigframe __user *frame;
259 void *restorer; 281 void *restorer;
282 unsigned long save_sp = PT_REGS_SP(regs);
260 int err = 0; 283 int err = 0;
261 284
262 stack_top &= -8UL; 285 stack_top &= -8UL;
@@ -268,13 +291,16 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
268 if(ka->sa.sa_flags & SA_RESTORER) 291 if(ka->sa.sa_flags & SA_RESTORER)
269 restorer = ka->sa.sa_restorer; 292 restorer = ka->sa.sa_restorer;
270 293
294 /* See comment above about why this is here */
295 PT_REGS_SP(regs) = (unsigned long) frame;
296
271 err |= __put_user(restorer, &frame->pretcode); 297 err |= __put_user(restorer, &frame->pretcode);
272 err |= __put_user(sig, &frame->sig); 298 err |= __put_user(sig, &frame->sig);
273 err |= __put_user(&frame->info, &frame->pinfo); 299 err |= __put_user(&frame->info, &frame->pinfo);
274 err |= __put_user(&frame->uc, &frame->puc); 300 err |= __put_user(&frame->uc, &frame->puc);
275 err |= copy_siginfo_to_user(&frame->info, info); 301 err |= copy_siginfo_to_user(&frame->info, info);
276 err |= copy_ucontext_to_user(&frame->uc, &frame->fpstate, mask, 302 err |= copy_ucontext_to_user(&frame->uc, &frame->fpstate, mask,
277 PT_REGS_SP(regs)); 303 save_sp);
278 304
279 /* 305 /*
280 * This is movl $,%eax ; int $0x80 306 * This is movl $,%eax ; int $0x80
@@ -288,9 +314,8 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
288 err |= __put_user(0x80cd, (short __user *)(frame->retcode+5)); 314 err |= __put_user(0x80cd, (short __user *)(frame->retcode+5));
289 315
290 if(err) 316 if(err)
291 return(err); 317 goto err;
292 318
293 PT_REGS_SP(regs) = (unsigned long) frame;
294 PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler; 319 PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler;
295 PT_REGS_EAX(regs) = (unsigned long) sig; 320 PT_REGS_EAX(regs) = (unsigned long) sig;
296 PT_REGS_EDX(regs) = (unsigned long) &frame->info; 321 PT_REGS_EDX(regs) = (unsigned long) &frame->info;
@@ -298,7 +323,11 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
298 323
299 if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED)) 324 if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
300 ptrace_notify(SIGTRAP); 325 ptrace_notify(SIGTRAP);
301 return(0); 326 return 0;
327
328err:
329 PT_REGS_SP(regs) = save_sp;
330 return err;
302} 331}
303 332
304long sys_sigreturn(struct pt_regs regs) 333long sys_sigreturn(struct pt_regs regs)