| .. | .. |
|---|
| 25 | 25 | #include <linux/user-return-notifier.h> |
|---|
| 26 | 26 | #include <linux/uprobes.h> |
|---|
| 27 | 27 | #include <linux/context_tracking.h> |
|---|
| 28 | +#include <linux/entry-common.h> |
|---|
| 28 | 29 | #include <linux/syscalls.h> |
|---|
| 29 | 30 | |
|---|
| 30 | 31 | #include <asm/processor.h> |
|---|
| .. | .. |
|---|
| 37 | 38 | #include <asm/vm86.h> |
|---|
| 38 | 39 | |
|---|
| 39 | 40 | #ifdef CONFIG_X86_64 |
|---|
| 41 | +#include <linux/compat.h> |
|---|
| 40 | 42 | #include <asm/proto.h> |
|---|
| 41 | 43 | #include <asm/ia32_unistd.h> |
|---|
| 42 | 44 | #endif /* CONFIG_X86_64 */ |
|---|
| 43 | 45 | |
|---|
| 44 | 46 | #include <asm/syscall.h> |
|---|
| 45 | | -#include <asm/syscalls.h> |
|---|
| 46 | | - |
|---|
| 47 | 47 | #include <asm/sigframe.h> |
|---|
| 48 | 48 | #include <asm/signal.h> |
|---|
| 49 | | - |
|---|
| 50 | | -#define COPY(x) do { \ |
|---|
| 51 | | - get_user_ex(regs->x, &sc->x); \ |
|---|
| 52 | | -} while (0) |
|---|
| 53 | | - |
|---|
| 54 | | -#define GET_SEG(seg) ({ \ |
|---|
| 55 | | - unsigned short tmp; \ |
|---|
| 56 | | - get_user_ex(tmp, &sc->seg); \ |
|---|
| 57 | | - tmp; \ |
|---|
| 58 | | -}) |
|---|
| 59 | | - |
|---|
| 60 | | -#define COPY_SEG(seg) do { \ |
|---|
| 61 | | - regs->seg = GET_SEG(seg); \ |
|---|
| 62 | | -} while (0) |
|---|
| 63 | | - |
|---|
| 64 | | -#define COPY_SEG_CPL3(seg) do { \ |
|---|
| 65 | | - regs->seg = GET_SEG(seg) | 3; \ |
|---|
| 66 | | -} while (0) |
|---|
| 67 | 49 | |
|---|
| 68 | 50 | #ifdef CONFIG_X86_64 |
|---|
| 69 | 51 | /* |
|---|
| .. | .. |
|---|
| 92 | 74 | ar != (AR_DPL3 | AR_S | AR_P | AR_TYPE_RWDATA_EXPDOWN)) |
|---|
| 93 | 75 | regs->ss = __USER_DS; |
|---|
| 94 | 76 | } |
|---|
| 77 | +# define CONTEXT_COPY_SIZE offsetof(struct sigcontext, reserved1) |
|---|
| 78 | +#else |
|---|
| 79 | +# define CONTEXT_COPY_SIZE sizeof(struct sigcontext) |
|---|
| 95 | 80 | #endif |
|---|
| 96 | 81 | |
|---|
| 97 | 82 | static int restore_sigcontext(struct pt_regs *regs, |
|---|
| 98 | | - struct sigcontext __user *sc, |
|---|
| 83 | + struct sigcontext __user *usc, |
|---|
| 99 | 84 | unsigned long uc_flags) |
|---|
| 100 | 85 | { |
|---|
| 101 | | - unsigned long buf_val; |
|---|
| 102 | | - void __user *buf; |
|---|
| 103 | | - unsigned int tmpflags; |
|---|
| 104 | | - unsigned int err = 0; |
|---|
| 86 | + struct sigcontext sc; |
|---|
| 105 | 87 | |
|---|
| 106 | 88 | /* Always make any pending restarted system calls return -EINTR */ |
|---|
| 107 | 89 | current->restart_block.fn = do_no_restart_syscall; |
|---|
| 108 | 90 | |
|---|
| 109 | | - get_user_try { |
|---|
| 91 | + if (copy_from_user(&sc, usc, CONTEXT_COPY_SIZE)) |
|---|
| 92 | + return -EFAULT; |
|---|
| 110 | 93 | |
|---|
| 111 | 94 | #ifdef CONFIG_X86_32 |
|---|
| 112 | | - set_user_gs(regs, GET_SEG(gs)); |
|---|
| 113 | | - COPY_SEG(fs); |
|---|
| 114 | | - COPY_SEG(es); |
|---|
| 115 | | - COPY_SEG(ds); |
|---|
| 95 | + set_user_gs(regs, sc.gs); |
|---|
| 96 | + regs->fs = sc.fs; |
|---|
| 97 | + regs->es = sc.es; |
|---|
| 98 | + regs->ds = sc.ds; |
|---|
| 116 | 99 | #endif /* CONFIG_X86_32 */ |
|---|
| 117 | 100 | |
|---|
| 118 | | - COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); |
|---|
| 119 | | - COPY(dx); COPY(cx); COPY(ip); COPY(ax); |
|---|
| 101 | + regs->bx = sc.bx; |
|---|
| 102 | + regs->cx = sc.cx; |
|---|
| 103 | + regs->dx = sc.dx; |
|---|
| 104 | + regs->si = sc.si; |
|---|
| 105 | + regs->di = sc.di; |
|---|
| 106 | + regs->bp = sc.bp; |
|---|
| 107 | + regs->ax = sc.ax; |
|---|
| 108 | + regs->sp = sc.sp; |
|---|
| 109 | + regs->ip = sc.ip; |
|---|
| 120 | 110 | |
|---|
| 121 | 111 | #ifdef CONFIG_X86_64 |
|---|
| 122 | | - COPY(r8); |
|---|
| 123 | | - COPY(r9); |
|---|
| 124 | | - COPY(r10); |
|---|
| 125 | | - COPY(r11); |
|---|
| 126 | | - COPY(r12); |
|---|
| 127 | | - COPY(r13); |
|---|
| 128 | | - COPY(r14); |
|---|
| 129 | | - COPY(r15); |
|---|
| 112 | + regs->r8 = sc.r8; |
|---|
| 113 | + regs->r9 = sc.r9; |
|---|
| 114 | + regs->r10 = sc.r10; |
|---|
| 115 | + regs->r11 = sc.r11; |
|---|
| 116 | + regs->r12 = sc.r12; |
|---|
| 117 | + regs->r13 = sc.r13; |
|---|
| 118 | + regs->r14 = sc.r14; |
|---|
| 119 | + regs->r15 = sc.r15; |
|---|
| 130 | 120 | #endif /* CONFIG_X86_64 */ |
|---|
| 131 | 121 | |
|---|
| 132 | | - COPY_SEG_CPL3(cs); |
|---|
| 133 | | - COPY_SEG_CPL3(ss); |
|---|
| 122 | + /* Get CS/SS and force CPL3 */ |
|---|
| 123 | + regs->cs = sc.cs | 0x03; |
|---|
| 124 | + regs->ss = sc.ss | 0x03; |
|---|
| 134 | 125 | |
|---|
| 135 | | - get_user_ex(tmpflags, &sc->flags); |
|---|
| 136 | | - regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); |
|---|
| 137 | | - regs->orig_ax = -1; /* disable syscall checks */ |
|---|
| 138 | | - |
|---|
| 139 | | - get_user_ex(buf_val, &sc->fpstate); |
|---|
| 140 | | - buf = (void __user *)buf_val; |
|---|
| 141 | | - } get_user_catch(err); |
|---|
| 126 | + regs->flags = (regs->flags & ~FIX_EFLAGS) | (sc.flags & FIX_EFLAGS); |
|---|
| 127 | + /* disable syscall checks */ |
|---|
| 128 | + regs->orig_ax = -1; |
|---|
| 142 | 129 | |
|---|
| 143 | 130 | #ifdef CONFIG_X86_64 |
|---|
| 144 | 131 | /* |
|---|
| .. | .. |
|---|
| 149 | 136 | force_valid_ss(regs); |
|---|
| 150 | 137 | #endif |
|---|
| 151 | 138 | |
|---|
| 152 | | - err |= fpu__restore_sig(buf, IS_ENABLED(CONFIG_X86_32)); |
|---|
| 153 | | - |
|---|
| 154 | | - force_iret(); |
|---|
| 155 | | - |
|---|
| 156 | | - return err; |
|---|
| 139 | + return fpu__restore_sig((void __user *)sc.fpstate, |
|---|
| 140 | + IS_ENABLED(CONFIG_X86_32)); |
|---|
| 157 | 141 | } |
|---|
| 158 | 142 | |
|---|
| 159 | | -int setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, |
|---|
| 143 | +static __always_inline int |
|---|
| 144 | +__unsafe_setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, |
|---|
| 160 | 145 | struct pt_regs *regs, unsigned long mask) |
|---|
| 161 | 146 | { |
|---|
| 162 | | - int err = 0; |
|---|
| 163 | | - |
|---|
| 164 | | - put_user_try { |
|---|
| 165 | | - |
|---|
| 166 | 147 | #ifdef CONFIG_X86_32 |
|---|
| 167 | | - put_user_ex(get_user_gs(regs), (unsigned int __user *)&sc->gs); |
|---|
| 168 | | - put_user_ex(regs->fs, (unsigned int __user *)&sc->fs); |
|---|
| 169 | | - put_user_ex(regs->es, (unsigned int __user *)&sc->es); |
|---|
| 170 | | - put_user_ex(regs->ds, (unsigned int __user *)&sc->ds); |
|---|
| 148 | + unsafe_put_user(get_user_gs(regs), |
|---|
| 149 | + (unsigned int __user *)&sc->gs, Efault); |
|---|
| 150 | + unsafe_put_user(regs->fs, (unsigned int __user *)&sc->fs, Efault); |
|---|
| 151 | + unsafe_put_user(regs->es, (unsigned int __user *)&sc->es, Efault); |
|---|
| 152 | + unsafe_put_user(regs->ds, (unsigned int __user *)&sc->ds, Efault); |
|---|
| 171 | 153 | #endif /* CONFIG_X86_32 */ |
|---|
| 172 | 154 | |
|---|
| 173 | | - put_user_ex(regs->di, &sc->di); |
|---|
| 174 | | - put_user_ex(regs->si, &sc->si); |
|---|
| 175 | | - put_user_ex(regs->bp, &sc->bp); |
|---|
| 176 | | - put_user_ex(regs->sp, &sc->sp); |
|---|
| 177 | | - put_user_ex(regs->bx, &sc->bx); |
|---|
| 178 | | - put_user_ex(regs->dx, &sc->dx); |
|---|
| 179 | | - put_user_ex(regs->cx, &sc->cx); |
|---|
| 180 | | - put_user_ex(regs->ax, &sc->ax); |
|---|
| 155 | + unsafe_put_user(regs->di, &sc->di, Efault); |
|---|
| 156 | + unsafe_put_user(regs->si, &sc->si, Efault); |
|---|
| 157 | + unsafe_put_user(regs->bp, &sc->bp, Efault); |
|---|
| 158 | + unsafe_put_user(regs->sp, &sc->sp, Efault); |
|---|
| 159 | + unsafe_put_user(regs->bx, &sc->bx, Efault); |
|---|
| 160 | + unsafe_put_user(regs->dx, &sc->dx, Efault); |
|---|
| 161 | + unsafe_put_user(regs->cx, &sc->cx, Efault); |
|---|
| 162 | + unsafe_put_user(regs->ax, &sc->ax, Efault); |
|---|
| 181 | 163 | #ifdef CONFIG_X86_64 |
|---|
| 182 | | - put_user_ex(regs->r8, &sc->r8); |
|---|
| 183 | | - put_user_ex(regs->r9, &sc->r9); |
|---|
| 184 | | - put_user_ex(regs->r10, &sc->r10); |
|---|
| 185 | | - put_user_ex(regs->r11, &sc->r11); |
|---|
| 186 | | - put_user_ex(regs->r12, &sc->r12); |
|---|
| 187 | | - put_user_ex(regs->r13, &sc->r13); |
|---|
| 188 | | - put_user_ex(regs->r14, &sc->r14); |
|---|
| 189 | | - put_user_ex(regs->r15, &sc->r15); |
|---|
| 164 | + unsafe_put_user(regs->r8, &sc->r8, Efault); |
|---|
| 165 | + unsafe_put_user(regs->r9, &sc->r9, Efault); |
|---|
| 166 | + unsafe_put_user(regs->r10, &sc->r10, Efault); |
|---|
| 167 | + unsafe_put_user(regs->r11, &sc->r11, Efault); |
|---|
| 168 | + unsafe_put_user(regs->r12, &sc->r12, Efault); |
|---|
| 169 | + unsafe_put_user(regs->r13, &sc->r13, Efault); |
|---|
| 170 | + unsafe_put_user(regs->r14, &sc->r14, Efault); |
|---|
| 171 | + unsafe_put_user(regs->r15, &sc->r15, Efault); |
|---|
| 190 | 172 | #endif /* CONFIG_X86_64 */ |
|---|
| 191 | 173 | |
|---|
| 192 | | - put_user_ex(current->thread.trap_nr, &sc->trapno); |
|---|
| 193 | | - put_user_ex(current->thread.error_code, &sc->err); |
|---|
| 194 | | - put_user_ex(regs->ip, &sc->ip); |
|---|
| 174 | + unsafe_put_user(current->thread.trap_nr, &sc->trapno, Efault); |
|---|
| 175 | + unsafe_put_user(current->thread.error_code, &sc->err, Efault); |
|---|
| 176 | + unsafe_put_user(regs->ip, &sc->ip, Efault); |
|---|
| 195 | 177 | #ifdef CONFIG_X86_32 |
|---|
| 196 | | - put_user_ex(regs->cs, (unsigned int __user *)&sc->cs); |
|---|
| 197 | | - put_user_ex(regs->flags, &sc->flags); |
|---|
| 198 | | - put_user_ex(regs->sp, &sc->sp_at_signal); |
|---|
| 199 | | - put_user_ex(regs->ss, (unsigned int __user *)&sc->ss); |
|---|
| 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); |
|---|
| 200 | 182 | #else /* !CONFIG_X86_32 */ |
|---|
| 201 | | - put_user_ex(regs->flags, &sc->flags); |
|---|
| 202 | | - put_user_ex(regs->cs, &sc->cs); |
|---|
| 203 | | - put_user_ex(0, &sc->gs); |
|---|
| 204 | | - put_user_ex(0, &sc->fs); |
|---|
| 205 | | - put_user_ex(regs->ss, &sc->ss); |
|---|
| 183 | + unsafe_put_user(regs->flags, &sc->flags, Efault); |
|---|
| 184 | + unsafe_put_user(regs->cs, &sc->cs, Efault); |
|---|
| 185 | + unsafe_put_user(0, &sc->gs, Efault); |
|---|
| 186 | + unsafe_put_user(0, &sc->fs, Efault); |
|---|
| 187 | + unsafe_put_user(regs->ss, &sc->ss, Efault); |
|---|
| 206 | 188 | #endif /* CONFIG_X86_32 */ |
|---|
| 207 | 189 | |
|---|
| 208 | | - put_user_ex(fpstate, &sc->fpstate); |
|---|
| 190 | + unsafe_put_user(fpstate, (unsigned long __user *)&sc->fpstate, Efault); |
|---|
| 209 | 191 | |
|---|
| 210 | | - /* non-iBCS2 extensions.. */ |
|---|
| 211 | | - put_user_ex(mask, &sc->oldmask); |
|---|
| 212 | | - put_user_ex(current->thread.cr2, &sc->cr2); |
|---|
| 213 | | - } put_user_catch(err); |
|---|
| 214 | | - |
|---|
| 215 | | - return err; |
|---|
| 192 | + /* non-iBCS2 extensions.. */ |
|---|
| 193 | + unsafe_put_user(mask, &sc->oldmask, Efault); |
|---|
| 194 | + unsafe_put_user(current->thread.cr2, &sc->cr2, Efault); |
|---|
| 195 | + return 0; |
|---|
| 196 | +Efault: |
|---|
| 197 | + return -EFAULT; |
|---|
| 216 | 198 | } |
|---|
| 199 | + |
|---|
| 200 | +#define unsafe_put_sigcontext(sc, fp, regs, set, label) \ |
|---|
| 201 | +do { \ |
|---|
| 202 | + if (__unsafe_setup_sigcontext(sc, fp, regs, set->sig[0])) \ |
|---|
| 203 | + goto label; \ |
|---|
| 204 | +} while(0); |
|---|
| 205 | + |
|---|
| 206 | +#define unsafe_put_sigmask(set, frame, label) \ |
|---|
| 207 | + unsafe_put_user(*(__u64 *)(set), \ |
|---|
| 208 | + (__u64 __user *)&(frame)->uc.uc_sigmask, \ |
|---|
| 209 | + label) |
|---|
| 217 | 210 | |
|---|
| 218 | 211 | /* |
|---|
| 219 | 212 | * Set up a signal frame. |
|---|
| .. | .. |
|---|
| 241 | 234 | void __user **fpstate) |
|---|
| 242 | 235 | { |
|---|
| 243 | 236 | /* Default to using normal stack */ |
|---|
| 237 | + bool nested_altstack = on_sig_stack(regs->sp); |
|---|
| 238 | + bool entering_altstack = false; |
|---|
| 244 | 239 | unsigned long math_size = 0; |
|---|
| 245 | 240 | unsigned long sp = regs->sp; |
|---|
| 246 | 241 | unsigned long buf_fx = 0; |
|---|
| 247 | | - int onsigstack = on_sig_stack(sp); |
|---|
| 248 | | - struct fpu *fpu = ¤t->thread.fpu; |
|---|
| 242 | + int ret; |
|---|
| 249 | 243 | |
|---|
| 250 | 244 | /* redzone */ |
|---|
| 251 | 245 | if (IS_ENABLED(CONFIG_X86_64)) |
|---|
| .. | .. |
|---|
| 253 | 247 | |
|---|
| 254 | 248 | /* This is the X/Open sanctioned signal stack switching. */ |
|---|
| 255 | 249 | if (ka->sa.sa_flags & SA_ONSTACK) { |
|---|
| 256 | | - if (sas_ss_flags(sp) == 0) |
|---|
| 250 | + /* |
|---|
| 251 | + * This checks nested_altstack via sas_ss_flags(). Sensible |
|---|
| 252 | + * programs use SS_AUTODISARM, which disables that check, and |
|---|
| 253 | + * programs that don't use SS_AUTODISARM get compatible. |
|---|
| 254 | + */ |
|---|
| 255 | + if (sas_ss_flags(sp) == 0) { |
|---|
| 257 | 256 | sp = current->sas_ss_sp + current->sas_ss_size; |
|---|
| 257 | + entering_altstack = true; |
|---|
| 258 | + } |
|---|
| 258 | 259 | } else if (IS_ENABLED(CONFIG_X86_32) && |
|---|
| 259 | | - !onsigstack && |
|---|
| 260 | + !nested_altstack && |
|---|
| 260 | 261 | regs->ss != __USER_DS && |
|---|
| 261 | 262 | !(ka->sa.sa_flags & SA_RESTORER) && |
|---|
| 262 | 263 | ka->sa.sa_restorer) { |
|---|
| 263 | 264 | /* This is the legacy signal stack switching. */ |
|---|
| 264 | 265 | sp = (unsigned long) ka->sa.sa_restorer; |
|---|
| 266 | + entering_altstack = true; |
|---|
| 265 | 267 | } |
|---|
| 266 | 268 | |
|---|
| 267 | | - if (fpu->initialized) { |
|---|
| 268 | | - sp = fpu__alloc_mathframe(sp, IS_ENABLED(CONFIG_X86_32), |
|---|
| 269 | | - &buf_fx, &math_size); |
|---|
| 270 | | - *fpstate = (void __user *)sp; |
|---|
| 271 | | - } |
|---|
| 269 | + sp = fpu__alloc_mathframe(sp, IS_ENABLED(CONFIG_X86_32), |
|---|
| 270 | + &buf_fx, &math_size); |
|---|
| 271 | + *fpstate = (void __user *)sp; |
|---|
| 272 | 272 | |
|---|
| 273 | 273 | sp = align_sigframe(sp - frame_size); |
|---|
| 274 | 274 | |
|---|
| .. | .. |
|---|
| 276 | 276 | * If we are on the alternate signal stack and would overflow it, don't. |
|---|
| 277 | 277 | * Return an always-bogus address instead so we will die with SIGSEGV. |
|---|
| 278 | 278 | */ |
|---|
| 279 | | - if (onsigstack && !likely(on_sig_stack(sp))) |
|---|
| 279 | + if (unlikely((nested_altstack || entering_altstack) && |
|---|
| 280 | + !__on_sig_stack(sp))) { |
|---|
| 281 | + |
|---|
| 282 | + if (show_unhandled_signals && printk_ratelimit()) |
|---|
| 283 | + pr_info("%s[%d] overflowed sigaltstack\n", |
|---|
| 284 | + current->comm, task_pid_nr(current)); |
|---|
| 285 | + |
|---|
| 280 | 286 | return (void __user *)-1L; |
|---|
| 287 | + } |
|---|
| 281 | 288 | |
|---|
| 282 | 289 | /* save i387 and extended state */ |
|---|
| 283 | | - if (fpu->initialized && |
|---|
| 284 | | - copy_fpstate_to_sigframe(*fpstate, (void __user *)buf_fx, math_size) < 0) |
|---|
| 290 | + ret = copy_fpstate_to_sigframe(*fpstate, (void __user *)buf_fx, math_size); |
|---|
| 291 | + if (ret < 0) |
|---|
| 285 | 292 | return (void __user *)-1L; |
|---|
| 286 | 293 | |
|---|
| 287 | 294 | return (void __user *)sp; |
|---|
| .. | .. |
|---|
| 316 | 323 | { |
|---|
| 317 | 324 | struct sigframe __user *frame; |
|---|
| 318 | 325 | void __user *restorer; |
|---|
| 319 | | - int err = 0; |
|---|
| 320 | | - void __user *fpstate = NULL; |
|---|
| 326 | + void __user *fp = NULL; |
|---|
| 321 | 327 | |
|---|
| 322 | | - frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fpstate); |
|---|
| 328 | + frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fp); |
|---|
| 323 | 329 | |
|---|
| 324 | | - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
|---|
| 330 | + if (!user_access_begin(frame, sizeof(*frame))) |
|---|
| 325 | 331 | return -EFAULT; |
|---|
| 326 | 332 | |
|---|
| 327 | | - if (__put_user(sig, &frame->sig)) |
|---|
| 328 | | - return -EFAULT; |
|---|
| 329 | | - |
|---|
| 330 | | - if (setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0])) |
|---|
| 331 | | - return -EFAULT; |
|---|
| 332 | | - |
|---|
| 333 | | - if (_NSIG_WORDS > 1) { |
|---|
| 334 | | - if (__copy_to_user(&frame->extramask, &set->sig[1], |
|---|
| 335 | | - sizeof(frame->extramask))) |
|---|
| 336 | | - return -EFAULT; |
|---|
| 337 | | - } |
|---|
| 338 | | - |
|---|
| 333 | + unsafe_put_user(sig, &frame->sig, Efault); |
|---|
| 334 | + unsafe_put_sigcontext(&frame->sc, fp, regs, set, Efault); |
|---|
| 335 | + unsafe_put_user(set->sig[1], &frame->extramask[0], Efault); |
|---|
| 339 | 336 | if (current->mm->context.vdso) |
|---|
| 340 | 337 | restorer = current->mm->context.vdso + |
|---|
| 341 | 338 | vdso_image_32.sym___kernel_sigreturn; |
|---|
| .. | .. |
|---|
| 345 | 342 | restorer = ksig->ka.sa.sa_restorer; |
|---|
| 346 | 343 | |
|---|
| 347 | 344 | /* Set up to return from userspace. */ |
|---|
| 348 | | - err |= __put_user(restorer, &frame->pretcode); |
|---|
| 345 | + unsafe_put_user(restorer, &frame->pretcode, Efault); |
|---|
| 349 | 346 | |
|---|
| 350 | 347 | /* |
|---|
| 351 | 348 | * This is popl %eax ; movl $__NR_sigreturn, %eax ; int $0x80 |
|---|
| .. | .. |
|---|
| 354 | 351 | * reasons and because gdb uses it as a signature to notice |
|---|
| 355 | 352 | * signal handler stack frames. |
|---|
| 356 | 353 | */ |
|---|
| 357 | | - err |= __put_user(*((u64 *)&retcode), (u64 *)frame->retcode); |
|---|
| 358 | | - |
|---|
| 359 | | - if (err) |
|---|
| 360 | | - return -EFAULT; |
|---|
| 354 | + unsafe_put_user(*((u64 *)&retcode), (u64 *)frame->retcode, Efault); |
|---|
| 355 | + user_access_end(); |
|---|
| 361 | 356 | |
|---|
| 362 | 357 | /* Set up registers for signal handler */ |
|---|
| 363 | 358 | regs->sp = (unsigned long)frame; |
|---|
| .. | .. |
|---|
| 372 | 367 | regs->cs = __USER_CS; |
|---|
| 373 | 368 | |
|---|
| 374 | 369 | return 0; |
|---|
| 370 | + |
|---|
| 371 | +Efault: |
|---|
| 372 | + user_access_end(); |
|---|
| 373 | + return -EFAULT; |
|---|
| 375 | 374 | } |
|---|
| 376 | 375 | |
|---|
| 377 | 376 | static int __setup_rt_frame(int sig, struct ksignal *ksig, |
|---|
| .. | .. |
|---|
| 379 | 378 | { |
|---|
| 380 | 379 | struct rt_sigframe __user *frame; |
|---|
| 381 | 380 | void __user *restorer; |
|---|
| 382 | | - int err = 0; |
|---|
| 383 | | - void __user *fpstate = NULL; |
|---|
| 381 | + void __user *fp = NULL; |
|---|
| 384 | 382 | |
|---|
| 385 | | - frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fpstate); |
|---|
| 383 | + frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fp); |
|---|
| 386 | 384 | |
|---|
| 387 | | - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
|---|
| 385 | + if (!user_access_begin(frame, sizeof(*frame))) |
|---|
| 388 | 386 | return -EFAULT; |
|---|
| 389 | 387 | |
|---|
| 390 | | - put_user_try { |
|---|
| 391 | | - put_user_ex(sig, &frame->sig); |
|---|
| 392 | | - put_user_ex(&frame->info, &frame->pinfo); |
|---|
| 393 | | - put_user_ex(&frame->uc, &frame->puc); |
|---|
| 388 | + unsafe_put_user(sig, &frame->sig, Efault); |
|---|
| 389 | + unsafe_put_user(&frame->info, &frame->pinfo, Efault); |
|---|
| 390 | + unsafe_put_user(&frame->uc, &frame->puc, Efault); |
|---|
| 394 | 391 | |
|---|
| 395 | | - /* Create the ucontext. */ |
|---|
| 396 | | - if (boot_cpu_has(X86_FEATURE_XSAVE)) |
|---|
| 397 | | - put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags); |
|---|
| 398 | | - else |
|---|
| 399 | | - put_user_ex(0, &frame->uc.uc_flags); |
|---|
| 400 | | - put_user_ex(0, &frame->uc.uc_link); |
|---|
| 401 | | - save_altstack_ex(&frame->uc.uc_stack, regs->sp); |
|---|
| 392 | + /* Create the ucontext. */ |
|---|
| 393 | + if (static_cpu_has(X86_FEATURE_XSAVE)) |
|---|
| 394 | + unsafe_put_user(UC_FP_XSTATE, &frame->uc.uc_flags, Efault); |
|---|
| 395 | + else |
|---|
| 396 | + unsafe_put_user(0, &frame->uc.uc_flags, Efault); |
|---|
| 397 | + unsafe_put_user(0, &frame->uc.uc_link, Efault); |
|---|
| 398 | + unsafe_save_altstack(&frame->uc.uc_stack, regs->sp, Efault); |
|---|
| 402 | 399 | |
|---|
| 403 | | - /* Set up to return from userspace. */ |
|---|
| 404 | | - restorer = current->mm->context.vdso + |
|---|
| 405 | | - vdso_image_32.sym___kernel_rt_sigreturn; |
|---|
| 406 | | - if (ksig->ka.sa.sa_flags & SA_RESTORER) |
|---|
| 407 | | - restorer = ksig->ka.sa.sa_restorer; |
|---|
| 408 | | - put_user_ex(restorer, &frame->pretcode); |
|---|
| 400 | + /* Set up to return from userspace. */ |
|---|
| 401 | + restorer = current->mm->context.vdso + |
|---|
| 402 | + vdso_image_32.sym___kernel_rt_sigreturn; |
|---|
| 403 | + if (ksig->ka.sa.sa_flags & SA_RESTORER) |
|---|
| 404 | + restorer = ksig->ka.sa.sa_restorer; |
|---|
| 405 | + unsafe_put_user(restorer, &frame->pretcode, Efault); |
|---|
| 409 | 406 | |
|---|
| 410 | | - /* |
|---|
| 411 | | - * This is movl $__NR_rt_sigreturn, %ax ; int $0x80 |
|---|
| 412 | | - * |
|---|
| 413 | | - * WE DO NOT USE IT ANY MORE! It's only left here for historical |
|---|
| 414 | | - * reasons and because gdb uses it as a signature to notice |
|---|
| 415 | | - * signal handler stack frames. |
|---|
| 416 | | - */ |
|---|
| 417 | | - put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode); |
|---|
| 418 | | - } put_user_catch(err); |
|---|
| 407 | + /* |
|---|
| 408 | + * This is movl $__NR_rt_sigreturn, %ax ; int $0x80 |
|---|
| 409 | + * |
|---|
| 410 | + * WE DO NOT USE IT ANY MORE! It's only left here for historical |
|---|
| 411 | + * reasons and because gdb uses it as a signature to notice |
|---|
| 412 | + * signal handler stack frames. |
|---|
| 413 | + */ |
|---|
| 414 | + unsafe_put_user(*((u64 *)&rt_retcode), (u64 *)frame->retcode, Efault); |
|---|
| 415 | + unsafe_put_sigcontext(&frame->uc.uc_mcontext, fp, regs, set, Efault); |
|---|
| 416 | + unsafe_put_sigmask(set, frame, Efault); |
|---|
| 417 | + user_access_end(); |
|---|
| 419 | 418 | |
|---|
| 420 | | - err |= copy_siginfo_to_user(&frame->info, &ksig->info); |
|---|
| 421 | | - err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, |
|---|
| 422 | | - regs, set->sig[0]); |
|---|
| 423 | | - err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
|---|
| 424 | | - |
|---|
| 425 | | - if (err) |
|---|
| 419 | + if (copy_siginfo_to_user(&frame->info, &ksig->info)) |
|---|
| 426 | 420 | return -EFAULT; |
|---|
| 427 | 421 | |
|---|
| 428 | 422 | /* Set up registers for signal handler */ |
|---|
| .. | .. |
|---|
| 438 | 432 | regs->cs = __USER_CS; |
|---|
| 439 | 433 | |
|---|
| 440 | 434 | return 0; |
|---|
| 435 | +Efault: |
|---|
| 436 | + user_access_end(); |
|---|
| 437 | + return -EFAULT; |
|---|
| 441 | 438 | } |
|---|
| 442 | 439 | #else /* !CONFIG_X86_32 */ |
|---|
| 443 | 440 | static unsigned long frame_uc_flags(struct pt_regs *regs) |
|---|
| .. | .. |
|---|
| 461 | 458 | struct rt_sigframe __user *frame; |
|---|
| 462 | 459 | void __user *fp = NULL; |
|---|
| 463 | 460 | unsigned long uc_flags; |
|---|
| 464 | | - int err = 0; |
|---|
| 461 | + |
|---|
| 462 | + /* x86-64 should always use SA_RESTORER. */ |
|---|
| 463 | + if (!(ksig->ka.sa.sa_flags & SA_RESTORER)) |
|---|
| 464 | + return -EFAULT; |
|---|
| 465 | 465 | |
|---|
| 466 | 466 | frame = get_sigframe(&ksig->ka, regs, sizeof(struct rt_sigframe), &fp); |
|---|
| 467 | + uc_flags = frame_uc_flags(regs); |
|---|
| 467 | 468 | |
|---|
| 468 | | - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
|---|
| 469 | + if (!user_access_begin(frame, sizeof(*frame))) |
|---|
| 469 | 470 | return -EFAULT; |
|---|
| 471 | + |
|---|
| 472 | + /* Create the ucontext. */ |
|---|
| 473 | + unsafe_put_user(uc_flags, &frame->uc.uc_flags, Efault); |
|---|
| 474 | + unsafe_put_user(0, &frame->uc.uc_link, Efault); |
|---|
| 475 | + unsafe_save_altstack(&frame->uc.uc_stack, regs->sp, Efault); |
|---|
| 476 | + |
|---|
| 477 | + /* Set up to return from userspace. If provided, use a stub |
|---|
| 478 | + already in userspace. */ |
|---|
| 479 | + unsafe_put_user(ksig->ka.sa.sa_restorer, &frame->pretcode, Efault); |
|---|
| 480 | + unsafe_put_sigcontext(&frame->uc.uc_mcontext, fp, regs, set, Efault); |
|---|
| 481 | + unsafe_put_sigmask(set, frame, Efault); |
|---|
| 482 | + user_access_end(); |
|---|
| 470 | 483 | |
|---|
| 471 | 484 | if (ksig->ka.sa.sa_flags & SA_SIGINFO) { |
|---|
| 472 | 485 | if (copy_siginfo_to_user(&frame->info, &ksig->info)) |
|---|
| 473 | 486 | return -EFAULT; |
|---|
| 474 | 487 | } |
|---|
| 475 | | - |
|---|
| 476 | | - uc_flags = frame_uc_flags(regs); |
|---|
| 477 | | - |
|---|
| 478 | | - put_user_try { |
|---|
| 479 | | - /* Create the ucontext. */ |
|---|
| 480 | | - put_user_ex(uc_flags, &frame->uc.uc_flags); |
|---|
| 481 | | - put_user_ex(0, &frame->uc.uc_link); |
|---|
| 482 | | - save_altstack_ex(&frame->uc.uc_stack, regs->sp); |
|---|
| 483 | | - |
|---|
| 484 | | - /* Set up to return from userspace. If provided, use a stub |
|---|
| 485 | | - already in userspace. */ |
|---|
| 486 | | - /* x86-64 should always use SA_RESTORER. */ |
|---|
| 487 | | - if (ksig->ka.sa.sa_flags & SA_RESTORER) { |
|---|
| 488 | | - put_user_ex(ksig->ka.sa.sa_restorer, &frame->pretcode); |
|---|
| 489 | | - } else { |
|---|
| 490 | | - /* could use a vstub here */ |
|---|
| 491 | | - err |= -EFAULT; |
|---|
| 492 | | - } |
|---|
| 493 | | - } put_user_catch(err); |
|---|
| 494 | | - |
|---|
| 495 | | - err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]); |
|---|
| 496 | | - err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
|---|
| 497 | | - |
|---|
| 498 | | - if (err) |
|---|
| 499 | | - return -EFAULT; |
|---|
| 500 | 488 | |
|---|
| 501 | 489 | /* Set up registers for signal handler */ |
|---|
| 502 | 490 | regs->di = sig; |
|---|
| .. | .. |
|---|
| 534 | 522 | force_valid_ss(regs); |
|---|
| 535 | 523 | |
|---|
| 536 | 524 | return 0; |
|---|
| 525 | + |
|---|
| 526 | +Efault: |
|---|
| 527 | + user_access_end(); |
|---|
| 528 | + return -EFAULT; |
|---|
| 537 | 529 | } |
|---|
| 538 | 530 | #endif /* CONFIG_X86_32 */ |
|---|
| 531 | + |
|---|
| 532 | +#ifdef CONFIG_X86_X32_ABI |
|---|
| 533 | +static int x32_copy_siginfo_to_user(struct compat_siginfo __user *to, |
|---|
| 534 | + const struct kernel_siginfo *from) |
|---|
| 535 | +{ |
|---|
| 536 | + struct compat_siginfo new; |
|---|
| 537 | + |
|---|
| 538 | + copy_siginfo_to_external32(&new, from); |
|---|
| 539 | + if (from->si_signo == SIGCHLD) { |
|---|
| 540 | + new._sifields._sigchld_x32._utime = from->si_utime; |
|---|
| 541 | + new._sifields._sigchld_x32._stime = from->si_stime; |
|---|
| 542 | + } |
|---|
| 543 | + if (copy_to_user(to, &new, sizeof(struct compat_siginfo))) |
|---|
| 544 | + return -EFAULT; |
|---|
| 545 | + return 0; |
|---|
| 546 | +} |
|---|
| 547 | + |
|---|
| 548 | +int copy_siginfo_to_user32(struct compat_siginfo __user *to, |
|---|
| 549 | + const struct kernel_siginfo *from) |
|---|
| 550 | +{ |
|---|
| 551 | + if (in_x32_syscall()) |
|---|
| 552 | + return x32_copy_siginfo_to_user(to, from); |
|---|
| 553 | + return __copy_siginfo_to_user32(to, from); |
|---|
| 554 | +} |
|---|
| 555 | +#endif /* CONFIG_X86_X32_ABI */ |
|---|
| 539 | 556 | |
|---|
| 540 | 557 | static int x32_setup_rt_frame(struct ksignal *ksig, |
|---|
| 541 | 558 | compat_sigset_t *set, |
|---|
| .. | .. |
|---|
| 545 | 562 | struct rt_sigframe_x32 __user *frame; |
|---|
| 546 | 563 | unsigned long uc_flags; |
|---|
| 547 | 564 | void __user *restorer; |
|---|
| 548 | | - int err = 0; |
|---|
| 549 | | - void __user *fpstate = NULL; |
|---|
| 565 | + void __user *fp = NULL; |
|---|
| 550 | 566 | |
|---|
| 551 | | - frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fpstate); |
|---|
| 552 | | - |
|---|
| 553 | | - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
|---|
| 567 | + if (!(ksig->ka.sa.sa_flags & SA_RESTORER)) |
|---|
| 554 | 568 | return -EFAULT; |
|---|
| 555 | 569 | |
|---|
| 556 | | - if (ksig->ka.sa.sa_flags & SA_SIGINFO) { |
|---|
| 557 | | - if (__copy_siginfo_to_user32(&frame->info, &ksig->info, true)) |
|---|
| 558 | | - return -EFAULT; |
|---|
| 559 | | - } |
|---|
| 570 | + frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fp); |
|---|
| 560 | 571 | |
|---|
| 561 | 572 | uc_flags = frame_uc_flags(regs); |
|---|
| 562 | 573 | |
|---|
| 563 | | - put_user_try { |
|---|
| 564 | | - /* Create the ucontext. */ |
|---|
| 565 | | - put_user_ex(uc_flags, &frame->uc.uc_flags); |
|---|
| 566 | | - put_user_ex(0, &frame->uc.uc_link); |
|---|
| 567 | | - compat_save_altstack_ex(&frame->uc.uc_stack, regs->sp); |
|---|
| 568 | | - put_user_ex(0, &frame->uc.uc__pad0); |
|---|
| 569 | | - |
|---|
| 570 | | - if (ksig->ka.sa.sa_flags & SA_RESTORER) { |
|---|
| 571 | | - restorer = ksig->ka.sa.sa_restorer; |
|---|
| 572 | | - } else { |
|---|
| 573 | | - /* could use a vstub here */ |
|---|
| 574 | | - restorer = NULL; |
|---|
| 575 | | - err |= -EFAULT; |
|---|
| 576 | | - } |
|---|
| 577 | | - put_user_ex(restorer, &frame->pretcode); |
|---|
| 578 | | - } put_user_catch(err); |
|---|
| 579 | | - |
|---|
| 580 | | - err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, |
|---|
| 581 | | - regs, set->sig[0]); |
|---|
| 582 | | - err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
|---|
| 583 | | - |
|---|
| 584 | | - if (err) |
|---|
| 574 | + if (!user_access_begin(frame, sizeof(*frame))) |
|---|
| 585 | 575 | return -EFAULT; |
|---|
| 576 | + |
|---|
| 577 | + /* Create the ucontext. */ |
|---|
| 578 | + unsafe_put_user(uc_flags, &frame->uc.uc_flags, Efault); |
|---|
| 579 | + unsafe_put_user(0, &frame->uc.uc_link, Efault); |
|---|
| 580 | + unsafe_compat_save_altstack(&frame->uc.uc_stack, regs->sp, Efault); |
|---|
| 581 | + unsafe_put_user(0, &frame->uc.uc__pad0, Efault); |
|---|
| 582 | + restorer = ksig->ka.sa.sa_restorer; |
|---|
| 583 | + unsafe_put_user(restorer, (unsigned long __user *)&frame->pretcode, Efault); |
|---|
| 584 | + unsafe_put_sigcontext(&frame->uc.uc_mcontext, fp, regs, set, Efault); |
|---|
| 585 | + unsafe_put_sigmask(set, frame, Efault); |
|---|
| 586 | + user_access_end(); |
|---|
| 587 | + |
|---|
| 588 | + if (ksig->ka.sa.sa_flags & SA_SIGINFO) { |
|---|
| 589 | + if (x32_copy_siginfo_to_user(&frame->info, &ksig->info)) |
|---|
| 590 | + return -EFAULT; |
|---|
| 591 | + } |
|---|
| 586 | 592 | |
|---|
| 587 | 593 | /* Set up registers for signal handler */ |
|---|
| 588 | 594 | regs->sp = (unsigned long) frame; |
|---|
| .. | .. |
|---|
| 601 | 607 | #endif /* CONFIG_X86_X32_ABI */ |
|---|
| 602 | 608 | |
|---|
| 603 | 609 | return 0; |
|---|
| 610 | +#ifdef CONFIG_X86_X32_ABI |
|---|
| 611 | +Efault: |
|---|
| 612 | + user_access_end(); |
|---|
| 613 | + return -EFAULT; |
|---|
| 614 | +#endif |
|---|
| 604 | 615 | } |
|---|
| 605 | 616 | |
|---|
| 606 | 617 | /* |
|---|
| .. | .. |
|---|
| 615 | 626 | |
|---|
| 616 | 627 | frame = (struct sigframe __user *)(regs->sp - 8); |
|---|
| 617 | 628 | |
|---|
| 618 | | - if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
|---|
| 629 | + if (!access_ok(frame, sizeof(*frame))) |
|---|
| 619 | 630 | goto badframe; |
|---|
| 620 | | - if (__get_user(set.sig[0], &frame->sc.oldmask) || (_NSIG_WORDS > 1 |
|---|
| 621 | | - && __copy_from_user(&set.sig[1], &frame->extramask, |
|---|
| 622 | | - sizeof(frame->extramask)))) |
|---|
| 631 | + if (__get_user(set.sig[0], &frame->sc.oldmask) || |
|---|
| 632 | + __get_user(set.sig[1], &frame->extramask[0])) |
|---|
| 623 | 633 | goto badframe; |
|---|
| 624 | 634 | |
|---|
| 625 | 635 | set_current_blocked(&set); |
|---|
| .. | .. |
|---|
| 647 | 657 | unsigned long uc_flags; |
|---|
| 648 | 658 | |
|---|
| 649 | 659 | frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long)); |
|---|
| 650 | | - if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
|---|
| 660 | + if (!access_ok(frame, sizeof(*frame))) |
|---|
| 651 | 661 | goto badframe; |
|---|
| 652 | | - if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) |
|---|
| 662 | + if (__get_user(*(__u64 *)&set, (__u64 __user *)&frame->uc.uc_sigmask)) |
|---|
| 653 | 663 | goto badframe; |
|---|
| 654 | 664 | if (__get_user(uc_flags, &frame->uc.uc_flags)) |
|---|
| 655 | 665 | goto badframe; |
|---|
| .. | .. |
|---|
| 693 | 703 | sigset_t *set = sigmask_to_save(); |
|---|
| 694 | 704 | compat_sigset_t *cset = (compat_sigset_t *) set; |
|---|
| 695 | 705 | |
|---|
| 696 | | - /* |
|---|
| 697 | | - * Increment event counter and perform fixup for the pre-signal |
|---|
| 698 | | - * frame. |
|---|
| 699 | | - */ |
|---|
| 706 | + /* Perform fixup for the pre-signal frame. */ |
|---|
| 700 | 707 | rseq_signal_deliver(ksig, regs); |
|---|
| 701 | 708 | |
|---|
| 702 | 709 | /* Set up the stack frame */ |
|---|
| .. | .. |
|---|
| 735 | 742 | regs->ax = -EINTR; |
|---|
| 736 | 743 | break; |
|---|
| 737 | 744 | } |
|---|
| 738 | | - /* fallthrough */ |
|---|
| 745 | + fallthrough; |
|---|
| 739 | 746 | case -ERESTARTNOINTR: |
|---|
| 740 | 747 | regs->ax = regs->orig_ax; |
|---|
| 741 | 748 | regs->ip -= 2; |
|---|
| .. | .. |
|---|
| 768 | 775 | /* |
|---|
| 769 | 776 | * Ensure the signal handler starts with the new fpu state. |
|---|
| 770 | 777 | */ |
|---|
| 771 | | - if (fpu->initialized) |
|---|
| 772 | | - fpu__clear(fpu); |
|---|
| 778 | + fpu__clear_user_states(fpu); |
|---|
| 773 | 779 | } |
|---|
| 774 | 780 | signal_setup_done(failed, ksig, stepping); |
|---|
| 775 | 781 | } |
|---|
| .. | .. |
|---|
| 792 | 798 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
|---|
| 793 | 799 | * mistake. |
|---|
| 794 | 800 | */ |
|---|
| 795 | | -void do_signal(struct pt_regs *regs) |
|---|
| 801 | +void arch_do_signal_or_restart(struct pt_regs *regs, bool has_signal) |
|---|
| 796 | 802 | { |
|---|
| 797 | 803 | struct ksignal ksig; |
|---|
| 798 | 804 | |
|---|
| 799 | | - if (get_signal(&ksig)) { |
|---|
| 805 | + if (has_signal && get_signal(&ksig)) { |
|---|
| 800 | 806 | /* Whee! Actually deliver the signal. */ |
|---|
| 801 | 807 | handle_signal(&ksig, regs); |
|---|
| 802 | 808 | return; |
|---|
| .. | .. |
|---|
| 841 | 847 | pr_cont("\n"); |
|---|
| 842 | 848 | } |
|---|
| 843 | 849 | |
|---|
| 844 | | - force_sig(SIGSEGV, me); |
|---|
| 850 | + force_sig(SIGSEGV); |
|---|
| 845 | 851 | } |
|---|
| 846 | 852 | |
|---|
| 847 | 853 | #ifdef CONFIG_X86_X32_ABI |
|---|
| 848 | | -asmlinkage long sys32_x32_rt_sigreturn(void) |
|---|
| 854 | +COMPAT_SYSCALL_DEFINE0(x32_rt_sigreturn) |
|---|
| 849 | 855 | { |
|---|
| 850 | 856 | struct pt_regs *regs = current_pt_regs(); |
|---|
| 851 | 857 | struct rt_sigframe_x32 __user *frame; |
|---|
| .. | .. |
|---|
| 854 | 860 | |
|---|
| 855 | 861 | frame = (struct rt_sigframe_x32 __user *)(regs->sp - 8); |
|---|
| 856 | 862 | |
|---|
| 857 | | - if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
|---|
| 863 | + if (!access_ok(frame, sizeof(*frame))) |
|---|
| 858 | 864 | goto badframe; |
|---|
| 859 | | - if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) |
|---|
| 865 | + if (__get_user(set.sig[0], (__u64 __user *)&frame->uc.uc_sigmask)) |
|---|
| 860 | 866 | goto badframe; |
|---|
| 861 | 867 | if (__get_user(uc_flags, &frame->uc.uc_flags)) |
|---|
| 862 | 868 | goto badframe; |
|---|