diff options
Diffstat (limited to 'arch/um/sys-i386/signal.c')
-rw-r--r-- | arch/um/sys-i386/signal.c | 59 |
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 | ||
60 | int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, | 60 | int 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 | ||
134 | int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, | 134 | int 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 | ||
161 | static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp, | 168 | static 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 | ||
169 | static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp, | 176 | static 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, ¤t->thread.regs); | 184 | err |= copy_sc_to_user(&uc->uc_mcontext, fp, ¤t->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 | |||
271 | err: | ||
272 | PT_REGS_SP(regs) = save_sp; | ||
273 | return err; | ||
252 | } | 274 | } |
253 | 275 | ||
254 | int setup_signal_stack_si(unsigned long stack_top, int sig, | 276 | int 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 | |||
328 | err: | ||
329 | PT_REGS_SP(regs) = save_sp; | ||
330 | return err; | ||
302 | } | 331 | } |
303 | 332 | ||
304 | long sys_sigreturn(struct pt_regs regs) | 333 | long sys_sigreturn(struct pt_regs regs) |