diff options
Diffstat (limited to 'arch/x86/kernel/signal.c')
-rw-r--r-- | arch/x86/kernel/signal.c | 463 |
1 files changed, 218 insertions, 245 deletions
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index df0587f24c54..d2cc6428c587 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c | |||
@@ -50,27 +50,23 @@ | |||
50 | # define FIX_EFLAGS __FIX_EFLAGS | 50 | # define FIX_EFLAGS __FIX_EFLAGS |
51 | #endif | 51 | #endif |
52 | 52 | ||
53 | #define COPY(x) { \ | 53 | #define COPY(x) do { \ |
54 | err |= __get_user(regs->x, &sc->x); \ | 54 | get_user_ex(regs->x, &sc->x); \ |
55 | } | 55 | } while (0) |
56 | 56 | ||
57 | #define COPY_SEG(seg) { \ | 57 | #define GET_SEG(seg) ({ \ |
58 | unsigned short tmp; \ | 58 | unsigned short tmp; \ |
59 | err |= __get_user(tmp, &sc->seg); \ | 59 | get_user_ex(tmp, &sc->seg); \ |
60 | regs->seg = tmp; \ | 60 | tmp; \ |
61 | } | 61 | }) |
62 | 62 | ||
63 | #define COPY_SEG_CPL3(seg) { \ | 63 | #define COPY_SEG(seg) do { \ |
64 | unsigned short tmp; \ | 64 | regs->seg = GET_SEG(seg); \ |
65 | err |= __get_user(tmp, &sc->seg); \ | 65 | } while (0) |
66 | regs->seg = tmp | 3; \ | ||
67 | } | ||
68 | 66 | ||
69 | #define GET_SEG(seg) { \ | 67 | #define COPY_SEG_CPL3(seg) do { \ |
70 | unsigned short tmp; \ | 68 | regs->seg = GET_SEG(seg) | 3; \ |
71 | err |= __get_user(tmp, &sc->seg); \ | 69 | } while (0) |
72 | loadsegment(seg, tmp); \ | ||
73 | } | ||
74 | 70 | ||
75 | static int | 71 | static int |
76 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | 72 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, |
@@ -83,45 +79,49 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | |||
83 | /* Always make any pending restarted system calls return -EINTR */ | 79 | /* Always make any pending restarted system calls return -EINTR */ |
84 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | 80 | current_thread_info()->restart_block.fn = do_no_restart_syscall; |
85 | 81 | ||
82 | get_user_try { | ||
83 | |||
86 | #ifdef CONFIG_X86_32 | 84 | #ifdef CONFIG_X86_32 |
87 | GET_SEG(gs); | 85 | set_user_gs(regs, GET_SEG(gs)); |
88 | COPY_SEG(fs); | 86 | COPY_SEG(fs); |
89 | COPY_SEG(es); | 87 | COPY_SEG(es); |
90 | COPY_SEG(ds); | 88 | COPY_SEG(ds); |
91 | #endif /* CONFIG_X86_32 */ | 89 | #endif /* CONFIG_X86_32 */ |
92 | 90 | ||
93 | COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); | 91 | COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); |
94 | COPY(dx); COPY(cx); COPY(ip); | 92 | COPY(dx); COPY(cx); COPY(ip); |
95 | 93 | ||
96 | #ifdef CONFIG_X86_64 | 94 | #ifdef CONFIG_X86_64 |
97 | COPY(r8); | 95 | COPY(r8); |
98 | COPY(r9); | 96 | COPY(r9); |
99 | COPY(r10); | 97 | COPY(r10); |
100 | COPY(r11); | 98 | COPY(r11); |
101 | COPY(r12); | 99 | COPY(r12); |
102 | COPY(r13); | 100 | COPY(r13); |
103 | COPY(r14); | 101 | COPY(r14); |
104 | COPY(r15); | 102 | COPY(r15); |
105 | #endif /* CONFIG_X86_64 */ | 103 | #endif /* CONFIG_X86_64 */ |
106 | 104 | ||
107 | #ifdef CONFIG_X86_32 | 105 | #ifdef CONFIG_X86_32 |
108 | COPY_SEG_CPL3(cs); | 106 | COPY_SEG_CPL3(cs); |
109 | COPY_SEG_CPL3(ss); | 107 | COPY_SEG_CPL3(ss); |
110 | #else /* !CONFIG_X86_32 */ | 108 | #else /* !CONFIG_X86_32 */ |
111 | /* Kernel saves and restores only the CS segment register on signals, | 109 | /* Kernel saves and restores only the CS segment register on signals, |
112 | * which is the bare minimum needed to allow mixed 32/64-bit code. | 110 | * which is the bare minimum needed to allow mixed 32/64-bit code. |
113 | * App's signal handler can save/restore other segments if needed. */ | 111 | * App's signal handler can save/restore other segments if needed. */ |
114 | COPY_SEG_CPL3(cs); | 112 | COPY_SEG_CPL3(cs); |
115 | #endif /* CONFIG_X86_32 */ | 113 | #endif /* CONFIG_X86_32 */ |
116 | 114 | ||
117 | err |= __get_user(tmpflags, &sc->flags); | 115 | get_user_ex(tmpflags, &sc->flags); |
118 | regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); | 116 | regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); |
119 | regs->orig_ax = -1; /* disable syscall checks */ | 117 | regs->orig_ax = -1; /* disable syscall checks */ |
120 | 118 | ||
121 | err |= __get_user(buf, &sc->fpstate); | 119 | get_user_ex(buf, &sc->fpstate); |
122 | err |= restore_i387_xstate(buf); | 120 | err |= restore_i387_xstate(buf); |
121 | |||
122 | get_user_ex(*pax, &sc->ax); | ||
123 | } get_user_catch(err); | ||
123 | 124 | ||
124 | err |= __get_user(*pax, &sc->ax); | ||
125 | return err; | 125 | return err; |
126 | } | 126 | } |
127 | 127 | ||
@@ -131,57 +131,55 @@ setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, | |||
131 | { | 131 | { |
132 | int err = 0; | 132 | int err = 0; |
133 | 133 | ||
134 | #ifdef CONFIG_X86_32 | 134 | put_user_try { |
135 | { | ||
136 | unsigned int tmp; | ||
137 | 135 | ||
138 | savesegment(gs, tmp); | 136 | #ifdef CONFIG_X86_32 |
139 | err |= __put_user(tmp, (unsigned int __user *)&sc->gs); | 137 | put_user_ex(get_user_gs(regs), (unsigned int __user *)&sc->gs); |
140 | } | 138 | put_user_ex(regs->fs, (unsigned int __user *)&sc->fs); |
141 | err |= __put_user(regs->fs, (unsigned int __user *)&sc->fs); | 139 | put_user_ex(regs->es, (unsigned int __user *)&sc->es); |
142 | err |= __put_user(regs->es, (unsigned int __user *)&sc->es); | 140 | put_user_ex(regs->ds, (unsigned int __user *)&sc->ds); |
143 | err |= __put_user(regs->ds, (unsigned int __user *)&sc->ds); | ||
144 | #endif /* CONFIG_X86_32 */ | 141 | #endif /* CONFIG_X86_32 */ |
145 | 142 | ||
146 | err |= __put_user(regs->di, &sc->di); | 143 | put_user_ex(regs->di, &sc->di); |
147 | err |= __put_user(regs->si, &sc->si); | 144 | put_user_ex(regs->si, &sc->si); |
148 | err |= __put_user(regs->bp, &sc->bp); | 145 | put_user_ex(regs->bp, &sc->bp); |
149 | err |= __put_user(regs->sp, &sc->sp); | 146 | put_user_ex(regs->sp, &sc->sp); |
150 | err |= __put_user(regs->bx, &sc->bx); | 147 | put_user_ex(regs->bx, &sc->bx); |
151 | err |= __put_user(regs->dx, &sc->dx); | 148 | put_user_ex(regs->dx, &sc->dx); |
152 | err |= __put_user(regs->cx, &sc->cx); | 149 | put_user_ex(regs->cx, &sc->cx); |
153 | err |= __put_user(regs->ax, &sc->ax); | 150 | put_user_ex(regs->ax, &sc->ax); |
154 | #ifdef CONFIG_X86_64 | 151 | #ifdef CONFIG_X86_64 |
155 | err |= __put_user(regs->r8, &sc->r8); | 152 | put_user_ex(regs->r8, &sc->r8); |
156 | err |= __put_user(regs->r9, &sc->r9); | 153 | put_user_ex(regs->r9, &sc->r9); |
157 | err |= __put_user(regs->r10, &sc->r10); | 154 | put_user_ex(regs->r10, &sc->r10); |
158 | err |= __put_user(regs->r11, &sc->r11); | 155 | put_user_ex(regs->r11, &sc->r11); |
159 | err |= __put_user(regs->r12, &sc->r12); | 156 | put_user_ex(regs->r12, &sc->r12); |
160 | err |= __put_user(regs->r13, &sc->r13); | 157 | put_user_ex(regs->r13, &sc->r13); |
161 | err |= __put_user(regs->r14, &sc->r14); | 158 | put_user_ex(regs->r14, &sc->r14); |
162 | err |= __put_user(regs->r15, &sc->r15); | 159 | put_user_ex(regs->r15, &sc->r15); |
163 | #endif /* CONFIG_X86_64 */ | 160 | #endif /* CONFIG_X86_64 */ |
164 | 161 | ||
165 | err |= __put_user(current->thread.trap_no, &sc->trapno); | 162 | put_user_ex(current->thread.trap_no, &sc->trapno); |
166 | err |= __put_user(current->thread.error_code, &sc->err); | 163 | put_user_ex(current->thread.error_code, &sc->err); |
167 | err |= __put_user(regs->ip, &sc->ip); | 164 | put_user_ex(regs->ip, &sc->ip); |
168 | #ifdef CONFIG_X86_32 | 165 | #ifdef CONFIG_X86_32 |
169 | err |= __put_user(regs->cs, (unsigned int __user *)&sc->cs); | 166 | put_user_ex(regs->cs, (unsigned int __user *)&sc->cs); |
170 | err |= __put_user(regs->flags, &sc->flags); | 167 | put_user_ex(regs->flags, &sc->flags); |
171 | err |= __put_user(regs->sp, &sc->sp_at_signal); | 168 | put_user_ex(regs->sp, &sc->sp_at_signal); |
172 | err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss); | 169 | put_user_ex(regs->ss, (unsigned int __user *)&sc->ss); |
173 | #else /* !CONFIG_X86_32 */ | 170 | #else /* !CONFIG_X86_32 */ |
174 | err |= __put_user(regs->flags, &sc->flags); | 171 | put_user_ex(regs->flags, &sc->flags); |
175 | err |= __put_user(regs->cs, &sc->cs); | 172 | put_user_ex(regs->cs, &sc->cs); |
176 | err |= __put_user(0, &sc->gs); | 173 | put_user_ex(0, &sc->gs); |
177 | err |= __put_user(0, &sc->fs); | 174 | put_user_ex(0, &sc->fs); |
178 | #endif /* CONFIG_X86_32 */ | 175 | #endif /* CONFIG_X86_32 */ |
179 | 176 | ||
180 | err |= __put_user(fpstate, &sc->fpstate); | 177 | put_user_ex(fpstate, &sc->fpstate); |
181 | 178 | ||
182 | /* non-iBCS2 extensions.. */ | 179 | /* non-iBCS2 extensions.. */ |
183 | err |= __put_user(mask, &sc->oldmask); | 180 | put_user_ex(mask, &sc->oldmask); |
184 | err |= __put_user(current->thread.cr2, &sc->cr2); | 181 | put_user_ex(current->thread.cr2, &sc->cr2); |
182 | } put_user_catch(err); | ||
185 | 183 | ||
186 | return err; | 184 | return err; |
187 | } | 185 | } |
@@ -189,40 +187,35 @@ setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, | |||
189 | /* | 187 | /* |
190 | * Set up a signal frame. | 188 | * Set up a signal frame. |
191 | */ | 189 | */ |
192 | #ifdef CONFIG_X86_32 | ||
193 | static const struct { | ||
194 | u16 poplmovl; | ||
195 | u32 val; | ||
196 | u16 int80; | ||
197 | } __attribute__((packed)) retcode = { | ||
198 | 0xb858, /* popl %eax; movl $..., %eax */ | ||
199 | __NR_sigreturn, | ||
200 | 0x80cd, /* int $0x80 */ | ||
201 | }; | ||
202 | |||
203 | static const struct { | ||
204 | u8 movl; | ||
205 | u32 val; | ||
206 | u16 int80; | ||
207 | u8 pad; | ||
208 | } __attribute__((packed)) rt_retcode = { | ||
209 | 0xb8, /* movl $..., %eax */ | ||
210 | __NR_rt_sigreturn, | ||
211 | 0x80cd, /* int $0x80 */ | ||
212 | 0 | ||
213 | }; | ||
214 | 190 | ||
215 | /* | 191 | /* |
216 | * Determine which stack to use.. | 192 | * Determine which stack to use.. |
217 | */ | 193 | */ |
194 | static unsigned long align_sigframe(unsigned long sp) | ||
195 | { | ||
196 | #ifdef CONFIG_X86_32 | ||
197 | /* | ||
198 | * Align the stack pointer according to the i386 ABI, | ||
199 | * i.e. so that on function entry ((sp + 4) & 15) == 0. | ||
200 | */ | ||
201 | sp = ((sp + 4) & -16ul) - 4; | ||
202 | #else /* !CONFIG_X86_32 */ | ||
203 | sp = round_down(sp, 16) - 8; | ||
204 | #endif | ||
205 | return sp; | ||
206 | } | ||
207 | |||
218 | static inline void __user * | 208 | static inline void __user * |
219 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, | 209 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, |
220 | void **fpstate) | 210 | void __user **fpstate) |
221 | { | 211 | { |
222 | unsigned long sp; | ||
223 | |||
224 | /* Default to using normal stack */ | 212 | /* Default to using normal stack */ |
225 | sp = regs->sp; | 213 | unsigned long sp = regs->sp; |
214 | |||
215 | #ifdef CONFIG_X86_64 | ||
216 | /* redzone */ | ||
217 | sp -= 128; | ||
218 | #endif /* CONFIG_X86_64 */ | ||
226 | 219 | ||
227 | /* | 220 | /* |
228 | * If we are on the alternate signal stack and would overflow it, don't. | 221 | * If we are on the alternate signal stack and would overflow it, don't. |
@@ -236,30 +229,52 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, | |||
236 | if (sas_ss_flags(sp) == 0) | 229 | if (sas_ss_flags(sp) == 0) |
237 | sp = current->sas_ss_sp + current->sas_ss_size; | 230 | sp = current->sas_ss_sp + current->sas_ss_size; |
238 | } else { | 231 | } else { |
232 | #ifdef CONFIG_X86_32 | ||
239 | /* This is the legacy signal stack switching. */ | 233 | /* This is the legacy signal stack switching. */ |
240 | if ((regs->ss & 0xffff) != __USER_DS && | 234 | if ((regs->ss & 0xffff) != __USER_DS && |
241 | !(ka->sa.sa_flags & SA_RESTORER) && | 235 | !(ka->sa.sa_flags & SA_RESTORER) && |
242 | ka->sa.sa_restorer) | 236 | ka->sa.sa_restorer) |
243 | sp = (unsigned long) ka->sa.sa_restorer; | 237 | sp = (unsigned long) ka->sa.sa_restorer; |
238 | #endif /* CONFIG_X86_32 */ | ||
244 | } | 239 | } |
245 | 240 | ||
246 | if (used_math()) { | 241 | if (used_math()) { |
247 | sp = sp - sig_xstate_size; | 242 | sp -= sig_xstate_size; |
248 | *fpstate = (struct _fpstate *) sp; | 243 | #ifdef CONFIG_X86_64 |
244 | sp = round_down(sp, 64); | ||
245 | #endif /* CONFIG_X86_64 */ | ||
246 | *fpstate = (void __user *)sp; | ||
247 | |||
249 | if (save_i387_xstate(*fpstate) < 0) | 248 | if (save_i387_xstate(*fpstate) < 0) |
250 | return (void __user *)-1L; | 249 | return (void __user *)-1L; |
251 | } | 250 | } |
252 | 251 | ||
253 | sp -= frame_size; | 252 | return (void __user *)align_sigframe(sp - frame_size); |
254 | /* | ||
255 | * Align the stack pointer according to the i386 ABI, | ||
256 | * i.e. so that on function entry ((sp + 4) & 15) == 0. | ||
257 | */ | ||
258 | sp = ((sp + 4) & -16ul) - 4; | ||
259 | |||
260 | return (void __user *) sp; | ||
261 | } | 253 | } |
262 | 254 | ||
255 | #ifdef CONFIG_X86_32 | ||
256 | static const struct { | ||
257 | u16 poplmovl; | ||
258 | u32 val; | ||
259 | u16 int80; | ||
260 | } __attribute__((packed)) retcode = { | ||
261 | 0xb858, /* popl %eax; movl $..., %eax */ | ||
262 | __NR_sigreturn, | ||
263 | 0x80cd, /* int $0x80 */ | ||
264 | }; | ||
265 | |||
266 | static const struct { | ||
267 | u8 movl; | ||
268 | u32 val; | ||
269 | u16 int80; | ||
270 | u8 pad; | ||
271 | } __attribute__((packed)) rt_retcode = { | ||
272 | 0xb8, /* movl $..., %eax */ | ||
273 | __NR_rt_sigreturn, | ||
274 | 0x80cd, /* int $0x80 */ | ||
275 | 0 | ||
276 | }; | ||
277 | |||
263 | static int | 278 | static int |
264 | __setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | 279 | __setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, |
265 | struct pt_regs *regs) | 280 | struct pt_regs *regs) |
@@ -336,43 +351,41 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
336 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 351 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
337 | return -EFAULT; | 352 | return -EFAULT; |
338 | 353 | ||
339 | err |= __put_user(sig, &frame->sig); | 354 | put_user_try { |
340 | err |= __put_user(&frame->info, &frame->pinfo); | 355 | put_user_ex(sig, &frame->sig); |
341 | err |= __put_user(&frame->uc, &frame->puc); | 356 | put_user_ex(&frame->info, &frame->pinfo); |
342 | err |= copy_siginfo_to_user(&frame->info, info); | 357 | put_user_ex(&frame->uc, &frame->puc); |
343 | if (err) | 358 | err |= copy_siginfo_to_user(&frame->info, info); |
344 | return -EFAULT; | ||
345 | 359 | ||
346 | /* Create the ucontext. */ | 360 | /* Create the ucontext. */ |
347 | if (cpu_has_xsave) | 361 | if (cpu_has_xsave) |
348 | err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags); | 362 | put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags); |
349 | else | 363 | else |
350 | err |= __put_user(0, &frame->uc.uc_flags); | 364 | put_user_ex(0, &frame->uc.uc_flags); |
351 | err |= __put_user(0, &frame->uc.uc_link); | 365 | put_user_ex(0, &frame->uc.uc_link); |
352 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | 366 | put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); |
353 | err |= __put_user(sas_ss_flags(regs->sp), | 367 | put_user_ex(sas_ss_flags(regs->sp), |
354 | &frame->uc.uc_stack.ss_flags); | 368 | &frame->uc.uc_stack.ss_flags); |
355 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | 369 | put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size); |
356 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, | 370 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, |
357 | regs, set->sig[0]); | 371 | regs, set->sig[0]); |
358 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 372 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
359 | if (err) | 373 | |
360 | return -EFAULT; | 374 | /* Set up to return from userspace. */ |
361 | 375 | restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn); | |
362 | /* Set up to return from userspace. */ | 376 | if (ka->sa.sa_flags & SA_RESTORER) |
363 | restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn); | 377 | restorer = ka->sa.sa_restorer; |
364 | if (ka->sa.sa_flags & SA_RESTORER) | 378 | put_user_ex(restorer, &frame->pretcode); |
365 | restorer = ka->sa.sa_restorer; | ||
366 | err |= __put_user(restorer, &frame->pretcode); | ||
367 | 379 | ||
368 | /* | 380 | /* |
369 | * This is movl $__NR_rt_sigreturn, %ax ; int $0x80 | 381 | * This is movl $__NR_rt_sigreturn, %ax ; int $0x80 |
370 | * | 382 | * |
371 | * WE DO NOT USE IT ANY MORE! It's only left here for historical | 383 | * WE DO NOT USE IT ANY MORE! It's only left here for historical |
372 | * reasons and because gdb uses it as a signature to notice | 384 | * reasons and because gdb uses it as a signature to notice |
373 | * signal handler stack frames. | 385 | * signal handler stack frames. |
374 | */ | 386 | */ |
375 | err |= __put_user(*((u64 *)&rt_retcode), (u64 *)frame->retcode); | 387 | put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode); |
388 | } put_user_catch(err); | ||
376 | 389 | ||
377 | if (err) | 390 | if (err) |
378 | return -EFAULT; | 391 | return -EFAULT; |
@@ -392,24 +405,6 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
392 | return 0; | 405 | return 0; |
393 | } | 406 | } |
394 | #else /* !CONFIG_X86_32 */ | 407 | #else /* !CONFIG_X86_32 */ |
395 | /* | ||
396 | * Determine which stack to use.. | ||
397 | */ | ||
398 | static void __user * | ||
399 | get_stack(struct k_sigaction *ka, unsigned long sp, unsigned long size) | ||
400 | { | ||
401 | /* Default to using normal stack - redzone*/ | ||
402 | sp -= 128; | ||
403 | |||
404 | /* This is the X/Open sanctioned signal stack switching. */ | ||
405 | if (ka->sa.sa_flags & SA_ONSTACK) { | ||
406 | if (sas_ss_flags(sp) == 0) | ||
407 | sp = current->sas_ss_sp + current->sas_ss_size; | ||
408 | } | ||
409 | |||
410 | return (void __user *)round_down(sp - size, 64); | ||
411 | } | ||
412 | |||
413 | static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 408 | static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
414 | sigset_t *set, struct pt_regs *regs) | 409 | sigset_t *set, struct pt_regs *regs) |
415 | { | 410 | { |
@@ -418,15 +413,7 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
418 | int err = 0; | 413 | int err = 0; |
419 | struct task_struct *me = current; | 414 | struct task_struct *me = current; |
420 | 415 | ||
421 | if (used_math()) { | 416 | frame = get_sigframe(ka, regs, sizeof(struct rt_sigframe), &fp); |
422 | fp = get_stack(ka, regs->sp, sig_xstate_size); | ||
423 | frame = (void __user *)round_down( | ||
424 | (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8; | ||
425 | |||
426 | if (save_i387_xstate(fp) < 0) | ||
427 | return -EFAULT; | ||
428 | } else | ||
429 | frame = get_stack(ka, regs->sp, sizeof(struct rt_sigframe)) - 8; | ||
430 | 417 | ||
431 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 418 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
432 | return -EFAULT; | 419 | return -EFAULT; |
@@ -436,28 +423,30 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
436 | return -EFAULT; | 423 | return -EFAULT; |
437 | } | 424 | } |
438 | 425 | ||
439 | /* Create the ucontext. */ | 426 | put_user_try { |
440 | if (cpu_has_xsave) | 427 | /* Create the ucontext. */ |
441 | err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags); | 428 | if (cpu_has_xsave) |
442 | else | 429 | put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags); |
443 | err |= __put_user(0, &frame->uc.uc_flags); | 430 | else |
444 | err |= __put_user(0, &frame->uc.uc_link); | 431 | put_user_ex(0, &frame->uc.uc_flags); |
445 | err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | 432 | put_user_ex(0, &frame->uc.uc_link); |
446 | err |= __put_user(sas_ss_flags(regs->sp), | 433 | put_user_ex(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); |
447 | &frame->uc.uc_stack.ss_flags); | 434 | put_user_ex(sas_ss_flags(regs->sp), |
448 | err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); | 435 | &frame->uc.uc_stack.ss_flags); |
449 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]); | 436 | put_user_ex(me->sas_ss_size, &frame->uc.uc_stack.ss_size); |
450 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 437 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]); |
451 | 438 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | |
452 | /* Set up to return from userspace. If provided, use a stub | 439 | |
453 | already in userspace. */ | 440 | /* Set up to return from userspace. If provided, use a stub |
454 | /* x86-64 should always use SA_RESTORER. */ | 441 | already in userspace. */ |
455 | if (ka->sa.sa_flags & SA_RESTORER) { | 442 | /* x86-64 should always use SA_RESTORER. */ |
456 | err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); | 443 | if (ka->sa.sa_flags & SA_RESTORER) { |
457 | } else { | 444 | put_user_ex(ka->sa.sa_restorer, &frame->pretcode); |
458 | /* could use a vstub here */ | 445 | } else { |
459 | return -EFAULT; | 446 | /* could use a vstub here */ |
460 | } | 447 | err |= -EFAULT; |
448 | } | ||
449 | } put_user_catch(err); | ||
461 | 450 | ||
462 | if (err) | 451 | if (err) |
463 | return -EFAULT; | 452 | return -EFAULT; |
@@ -509,31 +498,41 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, | |||
509 | struct old_sigaction __user *oact) | 498 | struct old_sigaction __user *oact) |
510 | { | 499 | { |
511 | struct k_sigaction new_ka, old_ka; | 500 | struct k_sigaction new_ka, old_ka; |
512 | int ret; | 501 | int ret = 0; |
513 | 502 | ||
514 | if (act) { | 503 | if (act) { |
515 | old_sigset_t mask; | 504 | old_sigset_t mask; |
516 | 505 | ||
517 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | 506 | if (!access_ok(VERIFY_READ, act, sizeof(*act))) |
518 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | ||
519 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) | ||
520 | return -EFAULT; | 507 | return -EFAULT; |
521 | 508 | ||
522 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); | 509 | get_user_try { |
523 | __get_user(mask, &act->sa_mask); | 510 | get_user_ex(new_ka.sa.sa_handler, &act->sa_handler); |
511 | get_user_ex(new_ka.sa.sa_flags, &act->sa_flags); | ||
512 | get_user_ex(mask, &act->sa_mask); | ||
513 | get_user_ex(new_ka.sa.sa_restorer, &act->sa_restorer); | ||
514 | } get_user_catch(ret); | ||
515 | |||
516 | if (ret) | ||
517 | return -EFAULT; | ||
524 | siginitset(&new_ka.sa.sa_mask, mask); | 518 | siginitset(&new_ka.sa.sa_mask, mask); |
525 | } | 519 | } |
526 | 520 | ||
527 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | 521 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); |
528 | 522 | ||
529 | if (!ret && oact) { | 523 | if (!ret && oact) { |
530 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | 524 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) |
531 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | ||
532 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) | ||
533 | return -EFAULT; | 525 | return -EFAULT; |
534 | 526 | ||
535 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | 527 | put_user_try { |
536 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | 528 | put_user_ex(old_ka.sa.sa_handler, &oact->sa_handler); |
529 | put_user_ex(old_ka.sa.sa_flags, &oact->sa_flags); | ||
530 | put_user_ex(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | ||
531 | put_user_ex(old_ka.sa.sa_restorer, &oact->sa_restorer); | ||
532 | } put_user_catch(ret); | ||
533 | |||
534 | if (ret) | ||
535 | return -EFAULT; | ||
537 | } | 536 | } |
538 | 537 | ||
539 | return ret; | 538 | return ret; |
@@ -541,14 +540,9 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, | |||
541 | #endif /* CONFIG_X86_32 */ | 540 | #endif /* CONFIG_X86_32 */ |
542 | 541 | ||
543 | #ifdef CONFIG_X86_32 | 542 | #ifdef CONFIG_X86_32 |
544 | asmlinkage int sys_sigaltstack(unsigned long bx) | 543 | int sys_sigaltstack(struct pt_regs *regs) |
545 | { | 544 | { |
546 | /* | 545 | const stack_t __user *uss = (const stack_t __user *)regs->bx; |
547 | * This is needed to make gcc realize it doesn't own the | ||
548 | * "struct pt_regs" | ||
549 | */ | ||
550 | struct pt_regs *regs = (struct pt_regs *)&bx; | ||
551 | const stack_t __user *uss = (const stack_t __user *)bx; | ||
552 | stack_t __user *uoss = (stack_t __user *)regs->cx; | 546 | stack_t __user *uoss = (stack_t __user *)regs->cx; |
553 | 547 | ||
554 | return do_sigaltstack(uss, uoss, regs->sp); | 548 | return do_sigaltstack(uss, uoss, regs->sp); |
@@ -566,14 +560,12 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | |||
566 | * Do a signal return; undo the signal stack. | 560 | * Do a signal return; undo the signal stack. |
567 | */ | 561 | */ |
568 | #ifdef CONFIG_X86_32 | 562 | #ifdef CONFIG_X86_32 |
569 | asmlinkage unsigned long sys_sigreturn(unsigned long __unused) | 563 | unsigned long sys_sigreturn(struct pt_regs *regs) |
570 | { | 564 | { |
571 | struct sigframe __user *frame; | 565 | struct sigframe __user *frame; |
572 | struct pt_regs *regs; | ||
573 | unsigned long ax; | 566 | unsigned long ax; |
574 | sigset_t set; | 567 | sigset_t set; |
575 | 568 | ||
576 | regs = (struct pt_regs *) &__unused; | ||
577 | frame = (struct sigframe __user *)(regs->sp - 8); | 569 | frame = (struct sigframe __user *)(regs->sp - 8); |
578 | 570 | ||
579 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 571 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
@@ -600,7 +592,7 @@ badframe: | |||
600 | } | 592 | } |
601 | #endif /* CONFIG_X86_32 */ | 593 | #endif /* CONFIG_X86_32 */ |
602 | 594 | ||
603 | static long do_rt_sigreturn(struct pt_regs *regs) | 595 | long sys_rt_sigreturn(struct pt_regs *regs) |
604 | { | 596 | { |
605 | struct rt_sigframe __user *frame; | 597 | struct rt_sigframe __user *frame; |
606 | unsigned long ax; | 598 | unsigned long ax; |
@@ -631,25 +623,6 @@ badframe: | |||
631 | return 0; | 623 | return 0; |
632 | } | 624 | } |
633 | 625 | ||
634 | #ifdef CONFIG_X86_32 | ||
635 | /* | ||
636 | * Note: do not pass in pt_regs directly as with tail-call optimization | ||
637 | * GCC will incorrectly stomp on the caller's frame and corrupt user-space | ||
638 | * register state: | ||
639 | */ | ||
640 | asmlinkage int sys_rt_sigreturn(unsigned long __unused) | ||
641 | { | ||
642 | struct pt_regs *regs = (struct pt_regs *)&__unused; | ||
643 | |||
644 | return do_rt_sigreturn(regs); | ||
645 | } | ||
646 | #else /* !CONFIG_X86_32 */ | ||
647 | asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | ||
648 | { | ||
649 | return do_rt_sigreturn(regs); | ||
650 | } | ||
651 | #endif /* CONFIG_X86_32 */ | ||
652 | |||
653 | /* | 626 | /* |
654 | * OK, we're invoking a handler: | 627 | * OK, we're invoking a handler: |
655 | */ | 628 | */ |