| .. | .. |
|---|
| 21 | 21 | #include <linux/personality.h> |
|---|
| 22 | 22 | #include <linux/compat.h> |
|---|
| 23 | 23 | #include <linux/binfmts.h> |
|---|
| 24 | +#include <linux/syscalls.h> |
|---|
| 24 | 25 | #include <asm/ucontext.h> |
|---|
| 25 | 26 | #include <linux/uaccess.h> |
|---|
| 26 | 27 | #include <asm/fpu/internal.h> |
|---|
| .. | .. |
|---|
| 35 | 36 | #include <asm/sighandling.h> |
|---|
| 36 | 37 | #include <asm/smap.h> |
|---|
| 37 | 38 | |
|---|
| 39 | +static inline void reload_segments(struct sigcontext_32 *sc) |
|---|
| 40 | +{ |
|---|
| 41 | + unsigned int cur; |
|---|
| 42 | + |
|---|
| 43 | + savesegment(gs, cur); |
|---|
| 44 | + if ((sc->gs | 0x03) != cur) |
|---|
| 45 | + load_gs_index(sc->gs | 0x03); |
|---|
| 46 | + savesegment(fs, cur); |
|---|
| 47 | + if ((sc->fs | 0x03) != cur) |
|---|
| 48 | + loadsegment(fs, sc->fs | 0x03); |
|---|
| 49 | + savesegment(ds, cur); |
|---|
| 50 | + if ((sc->ds | 0x03) != cur) |
|---|
| 51 | + loadsegment(ds, sc->ds | 0x03); |
|---|
| 52 | + savesegment(es, cur); |
|---|
| 53 | + if ((sc->es | 0x03) != cur) |
|---|
| 54 | + loadsegment(es, sc->es | 0x03); |
|---|
| 55 | +} |
|---|
| 56 | + |
|---|
| 38 | 57 | /* |
|---|
| 39 | 58 | * Do a signal return; undo the signal stack. |
|---|
| 40 | 59 | */ |
|---|
| 41 | | -#define loadsegment_gs(v) load_gs_index(v) |
|---|
| 42 | | -#define loadsegment_fs(v) loadsegment(fs, v) |
|---|
| 43 | | -#define loadsegment_ds(v) loadsegment(ds, v) |
|---|
| 44 | | -#define loadsegment_es(v) loadsegment(es, v) |
|---|
| 45 | | - |
|---|
| 46 | | -#define get_user_seg(seg) ({ unsigned int v; savesegment(seg, v); v; }) |
|---|
| 47 | | -#define set_user_seg(seg, v) loadsegment_##seg(v) |
|---|
| 48 | | - |
|---|
| 49 | | -#define COPY(x) { \ |
|---|
| 50 | | - get_user_ex(regs->x, &sc->x); \ |
|---|
| 51 | | -} |
|---|
| 52 | | - |
|---|
| 53 | | -#define GET_SEG(seg) ({ \ |
|---|
| 54 | | - unsigned short tmp; \ |
|---|
| 55 | | - get_user_ex(tmp, &sc->seg); \ |
|---|
| 56 | | - tmp; \ |
|---|
| 57 | | -}) |
|---|
| 58 | | - |
|---|
| 59 | | -#define COPY_SEG_CPL3(seg) do { \ |
|---|
| 60 | | - regs->seg = GET_SEG(seg) | 3; \ |
|---|
| 61 | | -} while (0) |
|---|
| 62 | | - |
|---|
| 63 | | -#define RELOAD_SEG(seg) { \ |
|---|
| 64 | | - unsigned int pre = (seg) | 3; \ |
|---|
| 65 | | - unsigned int cur = get_user_seg(seg); \ |
|---|
| 66 | | - if (pre != cur) \ |
|---|
| 67 | | - set_user_seg(seg, pre); \ |
|---|
| 68 | | -} |
|---|
| 69 | | - |
|---|
| 70 | 60 | static int ia32_restore_sigcontext(struct pt_regs *regs, |
|---|
| 71 | | - struct sigcontext_32 __user *sc) |
|---|
| 61 | + struct sigcontext_32 __user *usc) |
|---|
| 72 | 62 | { |
|---|
| 73 | | - unsigned int tmpflags, err = 0; |
|---|
| 74 | | - u16 gs, fs, es, ds; |
|---|
| 75 | | - void __user *buf; |
|---|
| 76 | | - u32 tmp; |
|---|
| 63 | + struct sigcontext_32 sc; |
|---|
| 77 | 64 | |
|---|
| 78 | 65 | /* Always make any pending restarted system calls return -EINTR */ |
|---|
| 79 | 66 | current->restart_block.fn = do_no_restart_syscall; |
|---|
| 80 | 67 | |
|---|
| 81 | | - get_user_try { |
|---|
| 82 | | - gs = GET_SEG(gs); |
|---|
| 83 | | - fs = GET_SEG(fs); |
|---|
| 84 | | - ds = GET_SEG(ds); |
|---|
| 85 | | - es = GET_SEG(es); |
|---|
| 68 | + if (unlikely(copy_from_user(&sc, usc, sizeof(sc)))) |
|---|
| 69 | + return -EFAULT; |
|---|
| 86 | 70 | |
|---|
| 87 | | - COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); |
|---|
| 88 | | - COPY(dx); COPY(cx); COPY(ip); COPY(ax); |
|---|
| 89 | | - /* Don't touch extended registers */ |
|---|
| 71 | + /* Get only the ia32 registers. */ |
|---|
| 72 | + regs->bx = sc.bx; |
|---|
| 73 | + regs->cx = sc.cx; |
|---|
| 74 | + regs->dx = sc.dx; |
|---|
| 75 | + regs->si = sc.si; |
|---|
| 76 | + regs->di = sc.di; |
|---|
| 77 | + regs->bp = sc.bp; |
|---|
| 78 | + regs->ax = sc.ax; |
|---|
| 79 | + regs->sp = sc.sp; |
|---|
| 80 | + regs->ip = sc.ip; |
|---|
| 90 | 81 | |
|---|
| 91 | | - COPY_SEG_CPL3(cs); |
|---|
| 92 | | - COPY_SEG_CPL3(ss); |
|---|
| 82 | + /* Get CS/SS and force CPL3 */ |
|---|
| 83 | + regs->cs = sc.cs | 0x03; |
|---|
| 84 | + regs->ss = sc.ss | 0x03; |
|---|
| 93 | 85 | |
|---|
| 94 | | - get_user_ex(tmpflags, &sc->flags); |
|---|
| 95 | | - regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); |
|---|
| 96 | | - /* disable syscall checks */ |
|---|
| 97 | | - regs->orig_ax = -1; |
|---|
| 98 | | - |
|---|
| 99 | | - get_user_ex(tmp, &sc->fpstate); |
|---|
| 100 | | - buf = compat_ptr(tmp); |
|---|
| 101 | | - } get_user_catch(err); |
|---|
| 86 | + regs->flags = (regs->flags & ~FIX_EFLAGS) | (sc.flags & FIX_EFLAGS); |
|---|
| 87 | + /* disable syscall checks */ |
|---|
| 88 | + regs->orig_ax = -1; |
|---|
| 102 | 89 | |
|---|
| 103 | 90 | /* |
|---|
| 104 | 91 | * Reload fs and gs if they have changed in the signal |
|---|
| .. | .. |
|---|
| 106 | 93 | * the handler, but does not clobber them at least in the |
|---|
| 107 | 94 | * normal case. |
|---|
| 108 | 95 | */ |
|---|
| 109 | | - RELOAD_SEG(gs); |
|---|
| 110 | | - RELOAD_SEG(fs); |
|---|
| 111 | | - RELOAD_SEG(ds); |
|---|
| 112 | | - RELOAD_SEG(es); |
|---|
| 113 | | - |
|---|
| 114 | | - err |= fpu__restore_sig(buf, 1); |
|---|
| 115 | | - |
|---|
| 116 | | - force_iret(); |
|---|
| 117 | | - |
|---|
| 118 | | - return err; |
|---|
| 96 | + reload_segments(&sc); |
|---|
| 97 | + return fpu__restore_sig(compat_ptr(sc.fpstate), 1); |
|---|
| 119 | 98 | } |
|---|
| 120 | 99 | |
|---|
| 121 | | -asmlinkage long sys32_sigreturn(const struct pt_regs *__unused) |
|---|
| 100 | +COMPAT_SYSCALL_DEFINE0(sigreturn) |
|---|
| 122 | 101 | { |
|---|
| 123 | 102 | struct pt_regs *regs = current_pt_regs(); |
|---|
| 124 | 103 | struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8); |
|---|
| 125 | 104 | sigset_t set; |
|---|
| 126 | 105 | |
|---|
| 127 | | - if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
|---|
| 106 | + if (!access_ok(frame, sizeof(*frame))) |
|---|
| 128 | 107 | goto badframe; |
|---|
| 129 | 108 | if (__get_user(set.sig[0], &frame->sc.oldmask) |
|---|
| 130 | | - || (_COMPAT_NSIG_WORDS > 1 |
|---|
| 131 | | - && __copy_from_user((((char *) &set.sig) + 4), |
|---|
| 132 | | - &frame->extramask, |
|---|
| 133 | | - sizeof(frame->extramask)))) |
|---|
| 109 | + || __get_user(((__u32 *)&set)[1], &frame->extramask[0])) |
|---|
| 134 | 110 | goto badframe; |
|---|
| 135 | 111 | |
|---|
| 136 | 112 | set_current_blocked(&set); |
|---|
| .. | .. |
|---|
| 144 | 120 | return 0; |
|---|
| 145 | 121 | } |
|---|
| 146 | 122 | |
|---|
| 147 | | -asmlinkage long sys32_rt_sigreturn(const struct pt_regs *__unused) |
|---|
| 123 | +COMPAT_SYSCALL_DEFINE0(rt_sigreturn) |
|---|
| 148 | 124 | { |
|---|
| 149 | 125 | struct pt_regs *regs = current_pt_regs(); |
|---|
| 150 | 126 | struct rt_sigframe_ia32 __user *frame; |
|---|
| .. | .. |
|---|
| 152 | 128 | |
|---|
| 153 | 129 | frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4); |
|---|
| 154 | 130 | |
|---|
| 155 | | - if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
|---|
| 131 | + if (!access_ok(frame, sizeof(*frame))) |
|---|
| 156 | 132 | goto badframe; |
|---|
| 157 | | - if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) |
|---|
| 133 | + if (__get_user(set.sig[0], (__u64 __user *)&frame->uc.uc_sigmask)) |
|---|
| 158 | 134 | goto badframe; |
|---|
| 159 | 135 | |
|---|
| 160 | 136 | set_current_blocked(&set); |
|---|
| .. | .. |
|---|
| 176 | 152 | * Set up a signal frame. |
|---|
| 177 | 153 | */ |
|---|
| 178 | 154 | |
|---|
| 179 | | -static int ia32_setup_sigcontext(struct sigcontext_32 __user *sc, |
|---|
| 180 | | - void __user *fpstate, |
|---|
| 181 | | - struct pt_regs *regs, unsigned int mask) |
|---|
| 155 | +#define get_user_seg(seg) ({ unsigned int v; savesegment(seg, v); v; }) |
|---|
| 156 | + |
|---|
| 157 | +static __always_inline int |
|---|
| 158 | +__unsafe_setup_sigcontext32(struct sigcontext_32 __user *sc, |
|---|
| 159 | + void __user *fpstate, |
|---|
| 160 | + struct pt_regs *regs, unsigned int mask) |
|---|
| 182 | 161 | { |
|---|
| 183 | | - int err = 0; |
|---|
| 162 | + unsafe_put_user(get_user_seg(gs), (unsigned int __user *)&sc->gs, Efault); |
|---|
| 163 | + unsafe_put_user(get_user_seg(fs), (unsigned int __user *)&sc->fs, Efault); |
|---|
| 164 | + unsafe_put_user(get_user_seg(ds), (unsigned int __user *)&sc->ds, Efault); |
|---|
| 165 | + unsafe_put_user(get_user_seg(es), (unsigned int __user *)&sc->es, Efault); |
|---|
| 184 | 166 | |
|---|
| 185 | | - put_user_try { |
|---|
| 186 | | - put_user_ex(get_user_seg(gs), (unsigned int __user *)&sc->gs); |
|---|
| 187 | | - put_user_ex(get_user_seg(fs), (unsigned int __user *)&sc->fs); |
|---|
| 188 | | - put_user_ex(get_user_seg(ds), (unsigned int __user *)&sc->ds); |
|---|
| 189 | | - put_user_ex(get_user_seg(es), (unsigned int __user *)&sc->es); |
|---|
| 167 | + unsafe_put_user(regs->di, &sc->di, Efault); |
|---|
| 168 | + unsafe_put_user(regs->si, &sc->si, Efault); |
|---|
| 169 | + unsafe_put_user(regs->bp, &sc->bp, Efault); |
|---|
| 170 | + unsafe_put_user(regs->sp, &sc->sp, Efault); |
|---|
| 171 | + unsafe_put_user(regs->bx, &sc->bx, Efault); |
|---|
| 172 | + unsafe_put_user(regs->dx, &sc->dx, Efault); |
|---|
| 173 | + unsafe_put_user(regs->cx, &sc->cx, Efault); |
|---|
| 174 | + unsafe_put_user(regs->ax, &sc->ax, Efault); |
|---|
| 175 | + unsafe_put_user(current->thread.trap_nr, &sc->trapno, Efault); |
|---|
| 176 | + unsafe_put_user(current->thread.error_code, &sc->err, Efault); |
|---|
| 177 | + unsafe_put_user(regs->ip, &sc->ip, Efault); |
|---|
| 178 | + unsafe_put_user(regs->cs, (unsigned int __user *)&sc->cs, Efault); |
|---|
| 179 | + unsafe_put_user(regs->flags, &sc->flags, Efault); |
|---|
| 180 | + unsafe_put_user(regs->sp, &sc->sp_at_signal, Efault); |
|---|
| 181 | + unsafe_put_user(regs->ss, (unsigned int __user *)&sc->ss, Efault); |
|---|
| 190 | 182 | |
|---|
| 191 | | - put_user_ex(regs->di, &sc->di); |
|---|
| 192 | | - put_user_ex(regs->si, &sc->si); |
|---|
| 193 | | - put_user_ex(regs->bp, &sc->bp); |
|---|
| 194 | | - put_user_ex(regs->sp, &sc->sp); |
|---|
| 195 | | - put_user_ex(regs->bx, &sc->bx); |
|---|
| 196 | | - put_user_ex(regs->dx, &sc->dx); |
|---|
| 197 | | - put_user_ex(regs->cx, &sc->cx); |
|---|
| 198 | | - put_user_ex(regs->ax, &sc->ax); |
|---|
| 199 | | - put_user_ex(current->thread.trap_nr, &sc->trapno); |
|---|
| 200 | | - put_user_ex(current->thread.error_code, &sc->err); |
|---|
| 201 | | - put_user_ex(regs->ip, &sc->ip); |
|---|
| 202 | | - put_user_ex(regs->cs, (unsigned int __user *)&sc->cs); |
|---|
| 203 | | - put_user_ex(regs->flags, &sc->flags); |
|---|
| 204 | | - put_user_ex(regs->sp, &sc->sp_at_signal); |
|---|
| 205 | | - put_user_ex(regs->ss, (unsigned int __user *)&sc->ss); |
|---|
| 183 | + unsafe_put_user(ptr_to_compat(fpstate), &sc->fpstate, Efault); |
|---|
| 206 | 184 | |
|---|
| 207 | | - put_user_ex(ptr_to_compat(fpstate), &sc->fpstate); |
|---|
| 185 | + /* non-iBCS2 extensions.. */ |
|---|
| 186 | + unsafe_put_user(mask, &sc->oldmask, Efault); |
|---|
| 187 | + unsafe_put_user(current->thread.cr2, &sc->cr2, Efault); |
|---|
| 188 | + return 0; |
|---|
| 208 | 189 | |
|---|
| 209 | | - /* non-iBCS2 extensions.. */ |
|---|
| 210 | | - put_user_ex(mask, &sc->oldmask); |
|---|
| 211 | | - put_user_ex(current->thread.cr2, &sc->cr2); |
|---|
| 212 | | - } put_user_catch(err); |
|---|
| 213 | | - |
|---|
| 214 | | - return err; |
|---|
| 190 | +Efault: |
|---|
| 191 | + return -EFAULT; |
|---|
| 215 | 192 | } |
|---|
| 193 | + |
|---|
| 194 | +#define unsafe_put_sigcontext32(sc, fp, regs, set, label) \ |
|---|
| 195 | +do { \ |
|---|
| 196 | + if (__unsafe_setup_sigcontext32(sc, fp, regs, set->sig[0])) \ |
|---|
| 197 | + goto label; \ |
|---|
| 198 | +} while(0) |
|---|
| 216 | 199 | |
|---|
| 217 | 200 | /* |
|---|
| 218 | 201 | * Determine which stack to use.. |
|---|
| .. | .. |
|---|
| 221 | 204 | size_t frame_size, |
|---|
| 222 | 205 | void __user **fpstate) |
|---|
| 223 | 206 | { |
|---|
| 224 | | - struct fpu *fpu = ¤t->thread.fpu; |
|---|
| 225 | | - unsigned long sp; |
|---|
| 207 | + unsigned long sp, fx_aligned, math_size; |
|---|
| 226 | 208 | |
|---|
| 227 | 209 | /* Default to using normal stack */ |
|---|
| 228 | 210 | sp = regs->sp; |
|---|
| .. | .. |
|---|
| 236 | 218 | ksig->ka.sa.sa_restorer) |
|---|
| 237 | 219 | sp = (unsigned long) ksig->ka.sa.sa_restorer; |
|---|
| 238 | 220 | |
|---|
| 239 | | - if (fpu->initialized) { |
|---|
| 240 | | - unsigned long fx_aligned, math_size; |
|---|
| 241 | | - |
|---|
| 242 | | - sp = fpu__alloc_mathframe(sp, 1, &fx_aligned, &math_size); |
|---|
| 243 | | - *fpstate = (struct _fpstate_32 __user *) sp; |
|---|
| 244 | | - if (copy_fpstate_to_sigframe(*fpstate, (void __user *)fx_aligned, |
|---|
| 245 | | - math_size) < 0) |
|---|
| 246 | | - return (void __user *) -1L; |
|---|
| 247 | | - } |
|---|
| 221 | + sp = fpu__alloc_mathframe(sp, 1, &fx_aligned, &math_size); |
|---|
| 222 | + *fpstate = (struct _fpstate_32 __user *) sp; |
|---|
| 223 | + if (copy_fpstate_to_sigframe(*fpstate, (void __user *)fx_aligned, |
|---|
| 224 | + math_size) < 0) |
|---|
| 225 | + return (void __user *) -1L; |
|---|
| 248 | 226 | |
|---|
| 249 | 227 | sp -= frame_size; |
|---|
| 250 | 228 | /* Align the stack pointer according to the i386 ABI, |
|---|
| .. | .. |
|---|
| 258 | 236 | { |
|---|
| 259 | 237 | struct sigframe_ia32 __user *frame; |
|---|
| 260 | 238 | void __user *restorer; |
|---|
| 261 | | - int err = 0; |
|---|
| 262 | | - void __user *fpstate = NULL; |
|---|
| 239 | + void __user *fp = NULL; |
|---|
| 263 | 240 | |
|---|
| 264 | 241 | /* copy_to_user optimizes that into a single 8 byte store */ |
|---|
| 265 | 242 | static const struct { |
|---|
| .. | .. |
|---|
| 272 | 249 | 0x80cd, /* int $0x80 */ |
|---|
| 273 | 250 | }; |
|---|
| 274 | 251 | |
|---|
| 275 | | - frame = get_sigframe(ksig, regs, sizeof(*frame), &fpstate); |
|---|
| 276 | | - |
|---|
| 277 | | - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
|---|
| 278 | | - return -EFAULT; |
|---|
| 279 | | - |
|---|
| 280 | | - if (__put_user(sig, &frame->sig)) |
|---|
| 281 | | - return -EFAULT; |
|---|
| 282 | | - |
|---|
| 283 | | - if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0])) |
|---|
| 284 | | - return -EFAULT; |
|---|
| 285 | | - |
|---|
| 286 | | - if (_COMPAT_NSIG_WORDS > 1) { |
|---|
| 287 | | - if (__copy_to_user(frame->extramask, &set->sig[1], |
|---|
| 288 | | - sizeof(frame->extramask))) |
|---|
| 289 | | - return -EFAULT; |
|---|
| 290 | | - } |
|---|
| 252 | + frame = get_sigframe(ksig, regs, sizeof(*frame), &fp); |
|---|
| 291 | 253 | |
|---|
| 292 | 254 | if (ksig->ka.sa.sa_flags & SA_RESTORER) { |
|---|
| 293 | 255 | restorer = ksig->ka.sa.sa_restorer; |
|---|
| .. | .. |
|---|
| 300 | 262 | restorer = &frame->retcode; |
|---|
| 301 | 263 | } |
|---|
| 302 | 264 | |
|---|
| 303 | | - put_user_try { |
|---|
| 304 | | - put_user_ex(ptr_to_compat(restorer), &frame->pretcode); |
|---|
| 305 | | - |
|---|
| 306 | | - /* |
|---|
| 307 | | - * These are actually not used anymore, but left because some |
|---|
| 308 | | - * gdb versions depend on them as a marker. |
|---|
| 309 | | - */ |
|---|
| 310 | | - put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode); |
|---|
| 311 | | - } put_user_catch(err); |
|---|
| 312 | | - |
|---|
| 313 | | - if (err) |
|---|
| 265 | + if (!user_access_begin(frame, sizeof(*frame))) |
|---|
| 314 | 266 | return -EFAULT; |
|---|
| 267 | + |
|---|
| 268 | + unsafe_put_user(sig, &frame->sig, Efault); |
|---|
| 269 | + unsafe_put_sigcontext32(&frame->sc, fp, regs, set, Efault); |
|---|
| 270 | + unsafe_put_user(set->sig[1], &frame->extramask[0], Efault); |
|---|
| 271 | + unsafe_put_user(ptr_to_compat(restorer), &frame->pretcode, Efault); |
|---|
| 272 | + /* |
|---|
| 273 | + * These are actually not used anymore, but left because some |
|---|
| 274 | + * gdb versions depend on them as a marker. |
|---|
| 275 | + */ |
|---|
| 276 | + unsafe_put_user(*((u64 *)&code), (u64 __user *)frame->retcode, Efault); |
|---|
| 277 | + user_access_end(); |
|---|
| 315 | 278 | |
|---|
| 316 | 279 | /* Set up registers for signal handler */ |
|---|
| 317 | 280 | regs->sp = (unsigned long) frame; |
|---|
| .. | .. |
|---|
| 329 | 292 | regs->ss = __USER32_DS; |
|---|
| 330 | 293 | |
|---|
| 331 | 294 | return 0; |
|---|
| 295 | +Efault: |
|---|
| 296 | + user_access_end(); |
|---|
| 297 | + return -EFAULT; |
|---|
| 332 | 298 | } |
|---|
| 333 | 299 | |
|---|
| 334 | 300 | int ia32_setup_rt_frame(int sig, struct ksignal *ksig, |
|---|
| .. | .. |
|---|
| 336 | 302 | { |
|---|
| 337 | 303 | struct rt_sigframe_ia32 __user *frame; |
|---|
| 338 | 304 | void __user *restorer; |
|---|
| 339 | | - int err = 0; |
|---|
| 340 | | - void __user *fpstate = NULL; |
|---|
| 305 | + void __user *fp = NULL; |
|---|
| 341 | 306 | |
|---|
| 342 | | - /* __copy_to_user optimizes that into a single 8 byte store */ |
|---|
| 307 | + /* unsafe_put_user optimizes that into a single 8 byte store */ |
|---|
| 343 | 308 | static const struct { |
|---|
| 344 | 309 | u8 movl; |
|---|
| 345 | 310 | u32 val; |
|---|
| .. | .. |
|---|
| 352 | 317 | 0, |
|---|
| 353 | 318 | }; |
|---|
| 354 | 319 | |
|---|
| 355 | | - frame = get_sigframe(ksig, regs, sizeof(*frame), &fpstate); |
|---|
| 320 | + frame = get_sigframe(ksig, regs, sizeof(*frame), &fp); |
|---|
| 356 | 321 | |
|---|
| 357 | | - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
|---|
| 322 | + if (!user_access_begin(frame, sizeof(*frame))) |
|---|
| 358 | 323 | return -EFAULT; |
|---|
| 359 | 324 | |
|---|
| 360 | | - put_user_try { |
|---|
| 361 | | - put_user_ex(sig, &frame->sig); |
|---|
| 362 | | - put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo); |
|---|
| 363 | | - put_user_ex(ptr_to_compat(&frame->uc), &frame->puc); |
|---|
| 325 | + unsafe_put_user(sig, &frame->sig, Efault); |
|---|
| 326 | + unsafe_put_user(ptr_to_compat(&frame->info), &frame->pinfo, Efault); |
|---|
| 327 | + unsafe_put_user(ptr_to_compat(&frame->uc), &frame->puc, Efault); |
|---|
| 364 | 328 | |
|---|
| 365 | | - /* Create the ucontext. */ |
|---|
| 366 | | - if (boot_cpu_has(X86_FEATURE_XSAVE)) |
|---|
| 367 | | - put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags); |
|---|
| 368 | | - else |
|---|
| 369 | | - put_user_ex(0, &frame->uc.uc_flags); |
|---|
| 370 | | - put_user_ex(0, &frame->uc.uc_link); |
|---|
| 371 | | - compat_save_altstack_ex(&frame->uc.uc_stack, regs->sp); |
|---|
| 329 | + /* Create the ucontext. */ |
|---|
| 330 | + if (static_cpu_has(X86_FEATURE_XSAVE)) |
|---|
| 331 | + unsafe_put_user(UC_FP_XSTATE, &frame->uc.uc_flags, Efault); |
|---|
| 332 | + else |
|---|
| 333 | + unsafe_put_user(0, &frame->uc.uc_flags, Efault); |
|---|
| 334 | + unsafe_put_user(0, &frame->uc.uc_link, Efault); |
|---|
| 335 | + unsafe_compat_save_altstack(&frame->uc.uc_stack, regs->sp, Efault); |
|---|
| 372 | 336 | |
|---|
| 373 | | - if (ksig->ka.sa.sa_flags & SA_RESTORER) |
|---|
| 374 | | - restorer = ksig->ka.sa.sa_restorer; |
|---|
| 375 | | - else |
|---|
| 376 | | - restorer = current->mm->context.vdso + |
|---|
| 377 | | - vdso_image_32.sym___kernel_rt_sigreturn; |
|---|
| 378 | | - put_user_ex(ptr_to_compat(restorer), &frame->pretcode); |
|---|
| 337 | + if (ksig->ka.sa.sa_flags & SA_RESTORER) |
|---|
| 338 | + restorer = ksig->ka.sa.sa_restorer; |
|---|
| 339 | + else |
|---|
| 340 | + restorer = current->mm->context.vdso + |
|---|
| 341 | + vdso_image_32.sym___kernel_rt_sigreturn; |
|---|
| 342 | + unsafe_put_user(ptr_to_compat(restorer), &frame->pretcode, Efault); |
|---|
| 379 | 343 | |
|---|
| 380 | | - /* |
|---|
| 381 | | - * Not actually used anymore, but left because some gdb |
|---|
| 382 | | - * versions need it. |
|---|
| 383 | | - */ |
|---|
| 384 | | - put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode); |
|---|
| 385 | | - } put_user_catch(err); |
|---|
| 344 | + /* |
|---|
| 345 | + * Not actually used anymore, but left because some gdb |
|---|
| 346 | + * versions need it. |
|---|
| 347 | + */ |
|---|
| 348 | + unsafe_put_user(*((u64 *)&code), (u64 __user *)frame->retcode, Efault); |
|---|
| 349 | + unsafe_put_sigcontext32(&frame->uc.uc_mcontext, fp, regs, set, Efault); |
|---|
| 350 | + unsafe_put_user(*(__u64 *)set, (__u64 *)&frame->uc.uc_sigmask, Efault); |
|---|
| 351 | + user_access_end(); |
|---|
| 386 | 352 | |
|---|
| 387 | | - err |= __copy_siginfo_to_user32(&frame->info, &ksig->info, false); |
|---|
| 388 | | - err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate, |
|---|
| 389 | | - regs, set->sig[0]); |
|---|
| 390 | | - err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
|---|
| 391 | | - |
|---|
| 392 | | - if (err) |
|---|
| 353 | + if (__copy_siginfo_to_user32(&frame->info, &ksig->info)) |
|---|
| 393 | 354 | return -EFAULT; |
|---|
| 394 | 355 | |
|---|
| 395 | 356 | /* Set up registers for signal handler */ |
|---|
| .. | .. |
|---|
| 408 | 369 | regs->ss = __USER32_DS; |
|---|
| 409 | 370 | |
|---|
| 410 | 371 | return 0; |
|---|
| 372 | +Efault: |
|---|
| 373 | + user_access_end(); |
|---|
| 374 | + return -EFAULT; |
|---|
| 411 | 375 | } |
|---|