diff options
Diffstat (limited to 'arch/x86/ia32/ia32_signal.c')
-rw-r--r-- | arch/x86/ia32/ia32_signal.c | 405 |
1 files changed, 207 insertions, 198 deletions
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index 9dabd00e9805..588a7aa937e1 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c | |||
@@ -33,8 +33,6 @@ | |||
33 | #include <asm/sigframe.h> | 33 | #include <asm/sigframe.h> |
34 | #include <asm/sys_ia32.h> | 34 | #include <asm/sys_ia32.h> |
35 | 35 | ||
36 | #define DEBUG_SIG 0 | ||
37 | |||
38 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 36 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
39 | 37 | ||
40 | #define FIX_EFLAGS (X86_EFLAGS_AC | X86_EFLAGS_OF | \ | 38 | #define FIX_EFLAGS (X86_EFLAGS_AC | X86_EFLAGS_OF | \ |
@@ -46,78 +44,83 @@ void signal_fault(struct pt_regs *regs, void __user *frame, char *where); | |||
46 | 44 | ||
47 | int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) | 45 | int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) |
48 | { | 46 | { |
49 | int err; | 47 | int err = 0; |
50 | 48 | ||
51 | if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t))) | 49 | if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t))) |
52 | return -EFAULT; | 50 | return -EFAULT; |
53 | 51 | ||
54 | /* If you change siginfo_t structure, please make sure that | 52 | put_user_try { |
55 | this code is fixed accordingly. | 53 | /* If you change siginfo_t structure, please make sure that |
56 | It should never copy any pad contained in the structure | 54 | this code is fixed accordingly. |
57 | to avoid security leaks, but must copy the generic | 55 | It should never copy any pad contained in the structure |
58 | 3 ints plus the relevant union member. */ | 56 | to avoid security leaks, but must copy the generic |
59 | err = __put_user(from->si_signo, &to->si_signo); | 57 | 3 ints plus the relevant union member. */ |
60 | err |= __put_user(from->si_errno, &to->si_errno); | 58 | put_user_ex(from->si_signo, &to->si_signo); |
61 | err |= __put_user((short)from->si_code, &to->si_code); | 59 | put_user_ex(from->si_errno, &to->si_errno); |
62 | 60 | put_user_ex((short)from->si_code, &to->si_code); | |
63 | if (from->si_code < 0) { | 61 | |
64 | err |= __put_user(from->si_pid, &to->si_pid); | 62 | if (from->si_code < 0) { |
65 | err |= __put_user(from->si_uid, &to->si_uid); | 63 | put_user_ex(from->si_pid, &to->si_pid); |
66 | err |= __put_user(ptr_to_compat(from->si_ptr), &to->si_ptr); | 64 | put_user_ex(from->si_uid, &to->si_uid); |
67 | } else { | 65 | put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr); |
68 | /* | 66 | } else { |
69 | * First 32bits of unions are always present: | 67 | /* |
70 | * si_pid === si_band === si_tid === si_addr(LS half) | 68 | * First 32bits of unions are always present: |
71 | */ | 69 | * si_pid === si_band === si_tid === si_addr(LS half) |
72 | err |= __put_user(from->_sifields._pad[0], | 70 | */ |
73 | &to->_sifields._pad[0]); | 71 | put_user_ex(from->_sifields._pad[0], |
74 | switch (from->si_code >> 16) { | 72 | &to->_sifields._pad[0]); |
75 | case __SI_FAULT >> 16: | 73 | switch (from->si_code >> 16) { |
76 | break; | 74 | case __SI_FAULT >> 16: |
77 | case __SI_CHLD >> 16: | 75 | break; |
78 | err |= __put_user(from->si_utime, &to->si_utime); | 76 | case __SI_CHLD >> 16: |
79 | err |= __put_user(from->si_stime, &to->si_stime); | 77 | put_user_ex(from->si_utime, &to->si_utime); |
80 | err |= __put_user(from->si_status, &to->si_status); | 78 | put_user_ex(from->si_stime, &to->si_stime); |
81 | /* FALL THROUGH */ | 79 | put_user_ex(from->si_status, &to->si_status); |
82 | default: | 80 | /* FALL THROUGH */ |
83 | case __SI_KILL >> 16: | 81 | default: |
84 | err |= __put_user(from->si_uid, &to->si_uid); | 82 | case __SI_KILL >> 16: |
85 | break; | 83 | put_user_ex(from->si_uid, &to->si_uid); |
86 | case __SI_POLL >> 16: | 84 | break; |
87 | err |= __put_user(from->si_fd, &to->si_fd); | 85 | case __SI_POLL >> 16: |
88 | break; | 86 | put_user_ex(from->si_fd, &to->si_fd); |
89 | case __SI_TIMER >> 16: | 87 | break; |
90 | err |= __put_user(from->si_overrun, &to->si_overrun); | 88 | case __SI_TIMER >> 16: |
91 | err |= __put_user(ptr_to_compat(from->si_ptr), | 89 | put_user_ex(from->si_overrun, &to->si_overrun); |
92 | &to->si_ptr); | 90 | put_user_ex(ptr_to_compat(from->si_ptr), |
93 | break; | 91 | &to->si_ptr); |
94 | /* This is not generated by the kernel as of now. */ | 92 | break; |
95 | case __SI_RT >> 16: | 93 | /* This is not generated by the kernel as of now. */ |
96 | case __SI_MESGQ >> 16: | 94 | case __SI_RT >> 16: |
97 | err |= __put_user(from->si_uid, &to->si_uid); | 95 | case __SI_MESGQ >> 16: |
98 | err |= __put_user(from->si_int, &to->si_int); | 96 | put_user_ex(from->si_uid, &to->si_uid); |
99 | break; | 97 | put_user_ex(from->si_int, &to->si_int); |
98 | break; | ||
99 | } | ||
100 | } | 100 | } |
101 | } | 101 | } put_user_catch(err); |
102 | |||
102 | return err; | 103 | return err; |
103 | } | 104 | } |
104 | 105 | ||
105 | int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) | 106 | int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) |
106 | { | 107 | { |
107 | int err; | 108 | int err = 0; |
108 | u32 ptr32; | 109 | u32 ptr32; |
109 | 110 | ||
110 | if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t))) | 111 | if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t))) |
111 | return -EFAULT; | 112 | return -EFAULT; |
112 | 113 | ||
113 | err = __get_user(to->si_signo, &from->si_signo); | 114 | get_user_try { |
114 | err |= __get_user(to->si_errno, &from->si_errno); | 115 | get_user_ex(to->si_signo, &from->si_signo); |
115 | err |= __get_user(to->si_code, &from->si_code); | 116 | get_user_ex(to->si_errno, &from->si_errno); |
117 | get_user_ex(to->si_code, &from->si_code); | ||
116 | 118 | ||
117 | err |= __get_user(to->si_pid, &from->si_pid); | 119 | get_user_ex(to->si_pid, &from->si_pid); |
118 | err |= __get_user(to->si_uid, &from->si_uid); | 120 | get_user_ex(to->si_uid, &from->si_uid); |
119 | err |= __get_user(ptr32, &from->si_ptr); | 121 | get_user_ex(ptr32, &from->si_ptr); |
120 | to->si_ptr = compat_ptr(ptr32); | 122 | to->si_ptr = compat_ptr(ptr32); |
123 | } get_user_catch(err); | ||
121 | 124 | ||
122 | return err; | 125 | return err; |
123 | } | 126 | } |
@@ -142,17 +145,23 @@ asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr, | |||
142 | struct pt_regs *regs) | 145 | struct pt_regs *regs) |
143 | { | 146 | { |
144 | stack_t uss, uoss; | 147 | stack_t uss, uoss; |
145 | int ret; | 148 | int ret, err = 0; |
146 | mm_segment_t seg; | 149 | mm_segment_t seg; |
147 | 150 | ||
148 | if (uss_ptr) { | 151 | if (uss_ptr) { |
149 | u32 ptr; | 152 | u32 ptr; |
150 | 153 | ||
151 | memset(&uss, 0, sizeof(stack_t)); | 154 | memset(&uss, 0, sizeof(stack_t)); |
152 | if (!access_ok(VERIFY_READ, uss_ptr, sizeof(stack_ia32_t)) || | 155 | if (!access_ok(VERIFY_READ, uss_ptr, sizeof(stack_ia32_t))) |
153 | __get_user(ptr, &uss_ptr->ss_sp) || | 156 | return -EFAULT; |
154 | __get_user(uss.ss_flags, &uss_ptr->ss_flags) || | 157 | |
155 | __get_user(uss.ss_size, &uss_ptr->ss_size)) | 158 | get_user_try { |
159 | get_user_ex(ptr, &uss_ptr->ss_sp); | ||
160 | get_user_ex(uss.ss_flags, &uss_ptr->ss_flags); | ||
161 | get_user_ex(uss.ss_size, &uss_ptr->ss_size); | ||
162 | } get_user_catch(err); | ||
163 | |||
164 | if (err) | ||
156 | return -EFAULT; | 165 | return -EFAULT; |
157 | uss.ss_sp = compat_ptr(ptr); | 166 | uss.ss_sp = compat_ptr(ptr); |
158 | } | 167 | } |
@@ -161,10 +170,16 @@ asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr, | |||
161 | ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs->sp); | 170 | ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs->sp); |
162 | set_fs(seg); | 171 | set_fs(seg); |
163 | if (ret >= 0 && uoss_ptr) { | 172 | if (ret >= 0 && uoss_ptr) { |
164 | if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t)) || | 173 | if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t))) |
165 | __put_user(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp) || | 174 | return -EFAULT; |
166 | __put_user(uoss.ss_flags, &uoss_ptr->ss_flags) || | 175 | |
167 | __put_user(uoss.ss_size, &uoss_ptr->ss_size)) | 176 | put_user_try { |
177 | put_user_ex(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp); | ||
178 | put_user_ex(uoss.ss_flags, &uoss_ptr->ss_flags); | ||
179 | put_user_ex(uoss.ss_size, &uoss_ptr->ss_size); | ||
180 | } put_user_catch(err); | ||
181 | |||
182 | if (err) | ||
168 | ret = -EFAULT; | 183 | ret = -EFAULT; |
169 | } | 184 | } |
170 | return ret; | 185 | return ret; |
@@ -173,75 +188,78 @@ asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr, | |||
173 | /* | 188 | /* |
174 | * Do a signal return; undo the signal stack. | 189 | * Do a signal return; undo the signal stack. |
175 | */ | 190 | */ |
191 | #define loadsegment_gs(v) load_gs_index(v) | ||
192 | #define loadsegment_fs(v) loadsegment(fs, v) | ||
193 | #define loadsegment_ds(v) loadsegment(ds, v) | ||
194 | #define loadsegment_es(v) loadsegment(es, v) | ||
195 | |||
196 | #define get_user_seg(seg) ({ unsigned int v; savesegment(seg, v); v; }) | ||
197 | #define set_user_seg(seg, v) loadsegment_##seg(v) | ||
198 | |||
176 | #define COPY(x) { \ | 199 | #define COPY(x) { \ |
177 | err |= __get_user(regs->x, &sc->x); \ | 200 | get_user_ex(regs->x, &sc->x); \ |
178 | } | 201 | } |
179 | 202 | ||
180 | #define COPY_SEG_CPL3(seg) { \ | 203 | #define GET_SEG(seg) ({ \ |
181 | unsigned short tmp; \ | 204 | unsigned short tmp; \ |
182 | err |= __get_user(tmp, &sc->seg); \ | 205 | get_user_ex(tmp, &sc->seg); \ |
183 | regs->seg = tmp | 3; \ | 206 | tmp; \ |
184 | } | 207 | }) |
208 | |||
209 | #define COPY_SEG_CPL3(seg) do { \ | ||
210 | regs->seg = GET_SEG(seg) | 3; \ | ||
211 | } while (0) | ||
185 | 212 | ||
186 | #define RELOAD_SEG(seg) { \ | 213 | #define RELOAD_SEG(seg) { \ |
187 | unsigned int cur, pre; \ | 214 | unsigned int pre = GET_SEG(seg); \ |
188 | err |= __get_user(pre, &sc->seg); \ | 215 | unsigned int cur = get_user_seg(seg); \ |
189 | savesegment(seg, cur); \ | ||
190 | pre |= 3; \ | 216 | pre |= 3; \ |
191 | if (pre != cur) \ | 217 | if (pre != cur) \ |
192 | loadsegment(seg, pre); \ | 218 | set_user_seg(seg, pre); \ |
193 | } | 219 | } |
194 | 220 | ||
195 | static int ia32_restore_sigcontext(struct pt_regs *regs, | 221 | static int ia32_restore_sigcontext(struct pt_regs *regs, |
196 | struct sigcontext_ia32 __user *sc, | 222 | struct sigcontext_ia32 __user *sc, |
197 | unsigned int *pax) | 223 | unsigned int *pax) |
198 | { | 224 | { |
199 | unsigned int tmpflags, gs, oldgs, err = 0; | 225 | unsigned int tmpflags, err = 0; |
200 | void __user *buf; | 226 | void __user *buf; |
201 | u32 tmp; | 227 | u32 tmp; |
202 | 228 | ||
203 | /* Always make any pending restarted system calls return -EINTR */ | 229 | /* Always make any pending restarted system calls return -EINTR */ |
204 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | 230 | current_thread_info()->restart_block.fn = do_no_restart_syscall; |
205 | 231 | ||
206 | #if DEBUG_SIG | 232 | get_user_try { |
207 | printk(KERN_DEBUG "SIG restore_sigcontext: " | 233 | /* |
208 | "sc=%p err(%x) eip(%x) cs(%x) flg(%x)\n", | 234 | * Reload fs and gs if they have changed in the signal |
209 | sc, sc->err, sc->ip, sc->cs, sc->flags); | 235 | * handler. This does not handle long fs/gs base changes in |
210 | #endif | 236 | * the handler, but does not clobber them at least in the |
211 | 237 | * normal case. | |
212 | /* | 238 | */ |
213 | * Reload fs and gs if they have changed in the signal | 239 | RELOAD_SEG(gs); |
214 | * handler. This does not handle long fs/gs base changes in | 240 | RELOAD_SEG(fs); |
215 | * the handler, but does not clobber them at least in the | 241 | RELOAD_SEG(ds); |
216 | * normal case. | 242 | RELOAD_SEG(es); |
217 | */ | 243 | |
218 | err |= __get_user(gs, &sc->gs); | 244 | COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); |
219 | gs |= 3; | 245 | COPY(dx); COPY(cx); COPY(ip); |
220 | savesegment(gs, oldgs); | 246 | /* Don't touch extended registers */ |
221 | if (gs != oldgs) | 247 | |
222 | load_gs_index(gs); | 248 | COPY_SEG_CPL3(cs); |
223 | 249 | COPY_SEG_CPL3(ss); | |
224 | RELOAD_SEG(fs); | 250 | |
225 | RELOAD_SEG(ds); | 251 | get_user_ex(tmpflags, &sc->flags); |
226 | RELOAD_SEG(es); | 252 | regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); |
227 | 253 | /* disable syscall checks */ | |
228 | COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); | 254 | regs->orig_ax = -1; |
229 | COPY(dx); COPY(cx); COPY(ip); | 255 | |
230 | /* Don't touch extended registers */ | 256 | get_user_ex(tmp, &sc->fpstate); |
231 | 257 | buf = compat_ptr(tmp); | |
232 | COPY_SEG_CPL3(cs); | 258 | err |= restore_i387_xstate_ia32(buf); |
233 | COPY_SEG_CPL3(ss); | 259 | |
234 | 260 | get_user_ex(*pax, &sc->ax); | |
235 | err |= __get_user(tmpflags, &sc->flags); | 261 | } get_user_catch(err); |
236 | regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); | 262 | |
237 | /* disable syscall checks */ | ||
238 | regs->orig_ax = -1; | ||
239 | |||
240 | err |= __get_user(tmp, &sc->fpstate); | ||
241 | buf = compat_ptr(tmp); | ||
242 | err |= restore_i387_xstate_ia32(buf); | ||
243 | |||
244 | err |= __get_user(*pax, &sc->ax); | ||
245 | return err; | 263 | return err; |
246 | } | 264 | } |
247 | 265 | ||
@@ -317,38 +335,36 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, | |||
317 | void __user *fpstate, | 335 | void __user *fpstate, |
318 | struct pt_regs *regs, unsigned int mask) | 336 | struct pt_regs *regs, unsigned int mask) |
319 | { | 337 | { |
320 | int tmp, err = 0; | 338 | int err = 0; |
321 | 339 | ||
322 | savesegment(gs, tmp); | 340 | put_user_try { |
323 | err |= __put_user(tmp, (unsigned int __user *)&sc->gs); | 341 | put_user_ex(get_user_seg(gs), (unsigned int __user *)&sc->gs); |
324 | savesegment(fs, tmp); | 342 | put_user_ex(get_user_seg(fs), (unsigned int __user *)&sc->fs); |
325 | err |= __put_user(tmp, (unsigned int __user *)&sc->fs); | 343 | put_user_ex(get_user_seg(ds), (unsigned int __user *)&sc->ds); |
326 | savesegment(ds, tmp); | 344 | put_user_ex(get_user_seg(es), (unsigned int __user *)&sc->es); |
327 | err |= __put_user(tmp, (unsigned int __user *)&sc->ds); | 345 | |
328 | savesegment(es, tmp); | 346 | put_user_ex(regs->di, &sc->di); |
329 | err |= __put_user(tmp, (unsigned int __user *)&sc->es); | 347 | put_user_ex(regs->si, &sc->si); |
330 | 348 | put_user_ex(regs->bp, &sc->bp); | |
331 | err |= __put_user(regs->di, &sc->di); | 349 | put_user_ex(regs->sp, &sc->sp); |
332 | err |= __put_user(regs->si, &sc->si); | 350 | put_user_ex(regs->bx, &sc->bx); |
333 | err |= __put_user(regs->bp, &sc->bp); | 351 | put_user_ex(regs->dx, &sc->dx); |
334 | err |= __put_user(regs->sp, &sc->sp); | 352 | put_user_ex(regs->cx, &sc->cx); |
335 | err |= __put_user(regs->bx, &sc->bx); | 353 | put_user_ex(regs->ax, &sc->ax); |
336 | err |= __put_user(regs->dx, &sc->dx); | 354 | put_user_ex(current->thread.trap_no, &sc->trapno); |
337 | err |= __put_user(regs->cx, &sc->cx); | 355 | put_user_ex(current->thread.error_code, &sc->err); |
338 | err |= __put_user(regs->ax, &sc->ax); | 356 | put_user_ex(regs->ip, &sc->ip); |
339 | err |= __put_user(current->thread.trap_no, &sc->trapno); | 357 | put_user_ex(regs->cs, (unsigned int __user *)&sc->cs); |
340 | err |= __put_user(current->thread.error_code, &sc->err); | 358 | put_user_ex(regs->flags, &sc->flags); |
341 | err |= __put_user(regs->ip, &sc->ip); | 359 | put_user_ex(regs->sp, &sc->sp_at_signal); |
342 | err |= __put_user(regs->cs, (unsigned int __user *)&sc->cs); | 360 | put_user_ex(regs->ss, (unsigned int __user *)&sc->ss); |
343 | err |= __put_user(regs->flags, &sc->flags); | 361 | |
344 | err |= __put_user(regs->sp, &sc->sp_at_signal); | 362 | put_user_ex(ptr_to_compat(fpstate), &sc->fpstate); |
345 | err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss); | 363 | |
346 | 364 | /* non-iBCS2 extensions.. */ | |
347 | err |= __put_user(ptr_to_compat(fpstate), &sc->fpstate); | 365 | put_user_ex(mask, &sc->oldmask); |
348 | 366 | put_user_ex(current->thread.cr2, &sc->cr2); | |
349 | /* non-iBCS2 extensions.. */ | 367 | } put_user_catch(err); |
350 | err |= __put_user(mask, &sc->oldmask); | ||
351 | err |= __put_user(current->thread.cr2, &sc->cr2); | ||
352 | 368 | ||
353 | return err; | 369 | return err; |
354 | } | 370 | } |
@@ -437,13 +453,17 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, | |||
437 | else | 453 | else |
438 | restorer = &frame->retcode; | 454 | restorer = &frame->retcode; |
439 | } | 455 | } |
440 | err |= __put_user(ptr_to_compat(restorer), &frame->pretcode); | ||
441 | 456 | ||
442 | /* | 457 | put_user_try { |
443 | * These are actually not used anymore, but left because some | 458 | put_user_ex(ptr_to_compat(restorer), &frame->pretcode); |
444 | * gdb versions depend on them as a marker. | 459 | |
445 | */ | 460 | /* |
446 | err |= __put_user(*((u64 *)&code), (u64 *)frame->retcode); | 461 | * These are actually not used anymore, but left because some |
462 | * gdb versions depend on them as a marker. | ||
463 | */ | ||
464 | put_user_ex(*((u64 *)&code), (u64 *)frame->retcode); | ||
465 | } put_user_catch(err); | ||
466 | |||
447 | if (err) | 467 | if (err) |
448 | return -EFAULT; | 468 | return -EFAULT; |
449 | 469 | ||
@@ -462,11 +482,6 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, | |||
462 | regs->cs = __USER32_CS; | 482 | regs->cs = __USER32_CS; |
463 | regs->ss = __USER32_DS; | 483 | regs->ss = __USER32_DS; |
464 | 484 | ||
465 | #if DEBUG_SIG | ||
466 | printk(KERN_DEBUG "SIG deliver (%s:%d): sp=%p pc=%lx ra=%u\n", | ||
467 | current->comm, current->pid, frame, regs->ip, frame->pretcode); | ||
468 | #endif | ||
469 | |||
470 | return 0; | 485 | return 0; |
471 | } | 486 | } |
472 | 487 | ||
@@ -496,41 +511,40 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
496 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 511 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
497 | return -EFAULT; | 512 | return -EFAULT; |
498 | 513 | ||
499 | err |= __put_user(sig, &frame->sig); | 514 | put_user_try { |
500 | err |= __put_user(ptr_to_compat(&frame->info), &frame->pinfo); | 515 | put_user_ex(sig, &frame->sig); |
501 | err |= __put_user(ptr_to_compat(&frame->uc), &frame->puc); | 516 | put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo); |
502 | err |= copy_siginfo_to_user32(&frame->info, info); | 517 | put_user_ex(ptr_to_compat(&frame->uc), &frame->puc); |
503 | if (err) | 518 | err |= copy_siginfo_to_user32(&frame->info, info); |
504 | return -EFAULT; | ||
505 | 519 | ||
506 | /* Create the ucontext. */ | 520 | /* Create the ucontext. */ |
507 | if (cpu_has_xsave) | 521 | if (cpu_has_xsave) |
508 | err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags); | 522 | put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags); |
509 | else | 523 | else |
510 | err |= __put_user(0, &frame->uc.uc_flags); | 524 | put_user_ex(0, &frame->uc.uc_flags); |
511 | err |= __put_user(0, &frame->uc.uc_link); | 525 | put_user_ex(0, &frame->uc.uc_link); |
512 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | 526 | put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); |
513 | err |= __put_user(sas_ss_flags(regs->sp), | 527 | put_user_ex(sas_ss_flags(regs->sp), |
514 | &frame->uc.uc_stack.ss_flags); | 528 | &frame->uc.uc_stack.ss_flags); |
515 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | 529 | put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size); |
516 | err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate, | 530 | err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate, |
517 | regs, set->sig[0]); | 531 | regs, set->sig[0]); |
518 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 532 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
519 | if (err) | 533 | |
520 | return -EFAULT; | 534 | if (ka->sa.sa_flags & SA_RESTORER) |
535 | restorer = ka->sa.sa_restorer; | ||
536 | else | ||
537 | restorer = VDSO32_SYMBOL(current->mm->context.vdso, | ||
538 | rt_sigreturn); | ||
539 | put_user_ex(ptr_to_compat(restorer), &frame->pretcode); | ||
540 | |||
541 | /* | ||
542 | * Not actually used anymore, but left because some gdb | ||
543 | * versions need it. | ||
544 | */ | ||
545 | put_user_ex(*((u64 *)&code), (u64 *)frame->retcode); | ||
546 | } put_user_catch(err); | ||
521 | 547 | ||
522 | if (ka->sa.sa_flags & SA_RESTORER) | ||
523 | restorer = ka->sa.sa_restorer; | ||
524 | else | ||
525 | restorer = VDSO32_SYMBOL(current->mm->context.vdso, | ||
526 | rt_sigreturn); | ||
527 | err |= __put_user(ptr_to_compat(restorer), &frame->pretcode); | ||
528 | |||
529 | /* | ||
530 | * Not actually used anymore, but left because some gdb | ||
531 | * versions need it. | ||
532 | */ | ||
533 | err |= __put_user(*((u64 *)&code), (u64 *)frame->retcode); | ||
534 | if (err) | 548 | if (err) |
535 | return -EFAULT; | 549 | return -EFAULT; |
536 | 550 | ||
@@ -549,10 +563,5 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
549 | regs->cs = __USER32_CS; | 563 | regs->cs = __USER32_CS; |
550 | regs->ss = __USER32_DS; | 564 | regs->ss = __USER32_DS; |
551 | 565 | ||
552 | #if DEBUG_SIG | ||
553 | printk(KERN_DEBUG "SIG deliver (%s:%d): sp=%p pc=%lx ra=%u\n", | ||
554 | current->comm, current->pid, frame, regs->ip, frame->pretcode); | ||
555 | #endif | ||
556 | |||
557 | return 0; | 566 | return 0; |
558 | } | 567 | } |