Merge branch 'next.uaccess-2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs into x86/cleanups
Pull uaccess cleanups from Al Viro: Consolidate the user access areas and get rid of uaccess_try(), user_ex() and other warts.
This commit is contained in:
@@ -47,24 +47,6 @@
|
||||
#include <asm/sigframe.h>
|
||||
#include <asm/signal.h>
|
||||
|
||||
#define COPY(x) do { \
|
||||
get_user_ex(regs->x, &sc->x); \
|
||||
} while (0)
|
||||
|
||||
#define GET_SEG(seg) ({ \
|
||||
unsigned short tmp; \
|
||||
get_user_ex(tmp, &sc->seg); \
|
||||
tmp; \
|
||||
})
|
||||
|
||||
#define COPY_SEG(seg) do { \
|
||||
regs->seg = GET_SEG(seg); \
|
||||
} while (0)
|
||||
|
||||
#define COPY_SEG_CPL3(seg) do { \
|
||||
regs->seg = GET_SEG(seg) | 3; \
|
||||
} while (0)
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
/*
|
||||
* If regs->ss will cause an IRET fault, change it. Otherwise leave it
|
||||
@@ -92,53 +74,58 @@ static void force_valid_ss(struct pt_regs *regs)
|
||||
ar != (AR_DPL3 | AR_S | AR_P | AR_TYPE_RWDATA_EXPDOWN))
|
||||
regs->ss = __USER_DS;
|
||||
}
|
||||
# define CONTEXT_COPY_SIZE offsetof(struct sigcontext, reserved1)
|
||||
#else
|
||||
# define CONTEXT_COPY_SIZE sizeof(struct sigcontext)
|
||||
#endif
|
||||
|
||||
static int restore_sigcontext(struct pt_regs *regs,
|
||||
struct sigcontext __user *sc,
|
||||
struct sigcontext __user *usc,
|
||||
unsigned long uc_flags)
|
||||
{
|
||||
unsigned long buf_val;
|
||||
void __user *buf;
|
||||
unsigned int tmpflags;
|
||||
unsigned int err = 0;
|
||||
struct sigcontext sc;
|
||||
|
||||
/* Always make any pending restarted system calls return -EINTR */
|
||||
current->restart_block.fn = do_no_restart_syscall;
|
||||
|
||||
get_user_try {
|
||||
if (copy_from_user(&sc, usc, CONTEXT_COPY_SIZE))
|
||||
return -EFAULT;
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
set_user_gs(regs, GET_SEG(gs));
|
||||
COPY_SEG(fs);
|
||||
COPY_SEG(es);
|
||||
COPY_SEG(ds);
|
||||
set_user_gs(regs, sc.gs);
|
||||
regs->fs = sc.fs;
|
||||
regs->es = sc.es;
|
||||
regs->ds = sc.ds;
|
||||
#endif /* CONFIG_X86_32 */
|
||||
|
||||
COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
|
||||
COPY(dx); COPY(cx); COPY(ip); COPY(ax);
|
||||
regs->bx = sc.bx;
|
||||
regs->cx = sc.cx;
|
||||
regs->dx = sc.dx;
|
||||
regs->si = sc.si;
|
||||
regs->di = sc.di;
|
||||
regs->bp = sc.bp;
|
||||
regs->ax = sc.ax;
|
||||
regs->sp = sc.sp;
|
||||
regs->ip = sc.ip;
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
COPY(r8);
|
||||
COPY(r9);
|
||||
COPY(r10);
|
||||
COPY(r11);
|
||||
COPY(r12);
|
||||
COPY(r13);
|
||||
COPY(r14);
|
||||
COPY(r15);
|
||||
regs->r8 = sc.r8;
|
||||
regs->r9 = sc.r9;
|
||||
regs->r10 = sc.r10;
|
||||
regs->r11 = sc.r11;
|
||||
regs->r12 = sc.r12;
|
||||
regs->r13 = sc.r13;
|
||||
regs->r14 = sc.r14;
|
||||
regs->r15 = sc.r15;
|
||||
#endif /* CONFIG_X86_64 */
|
||||
|
||||
COPY_SEG_CPL3(cs);
|
||||
COPY_SEG_CPL3(ss);
|
||||
/* Get CS/SS and force CPL3 */
|
||||
regs->cs = sc.cs | 0x03;
|
||||
regs->ss = sc.ss | 0x03;
|
||||
|
||||
get_user_ex(tmpflags, &sc->flags);
|
||||
regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
|
||||
regs->orig_ax = -1; /* disable syscall checks */
|
||||
|
||||
get_user_ex(buf_val, &sc->fpstate);
|
||||
buf = (void __user *)buf_val;
|
||||
} get_user_catch(err);
|
||||
regs->flags = (regs->flags & ~FIX_EFLAGS) | (sc.flags & FIX_EFLAGS);
|
||||
/* disable syscall checks */
|
||||
regs->orig_ax = -1;
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
/*
|
||||
@@ -149,70 +136,78 @@ static int restore_sigcontext(struct pt_regs *regs,
|
||||
force_valid_ss(regs);
|
||||
#endif
|
||||
|
||||
err |= fpu__restore_sig(buf, IS_ENABLED(CONFIG_X86_32));
|
||||
|
||||
return err;
|
||||
return fpu__restore_sig((void __user *)sc.fpstate,
|
||||
IS_ENABLED(CONFIG_X86_32));
|
||||
}
|
||||
|
||||
int setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
|
||||
static __always_inline int
|
||||
__unsafe_setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
|
||||
struct pt_regs *regs, unsigned long mask)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
put_user_try {
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
put_user_ex(get_user_gs(regs), (unsigned int __user *)&sc->gs);
|
||||
put_user_ex(regs->fs, (unsigned int __user *)&sc->fs);
|
||||
put_user_ex(regs->es, (unsigned int __user *)&sc->es);
|
||||
put_user_ex(regs->ds, (unsigned int __user *)&sc->ds);
|
||||
unsafe_put_user(get_user_gs(regs),
|
||||
(unsigned int __user *)&sc->gs, Efault);
|
||||
unsafe_put_user(regs->fs, (unsigned int __user *)&sc->fs, Efault);
|
||||
unsafe_put_user(regs->es, (unsigned int __user *)&sc->es, Efault);
|
||||
unsafe_put_user(regs->ds, (unsigned int __user *)&sc->ds, Efault);
|
||||
#endif /* CONFIG_X86_32 */
|
||||
|
||||
put_user_ex(regs->di, &sc->di);
|
||||
put_user_ex(regs->si, &sc->si);
|
||||
put_user_ex(regs->bp, &sc->bp);
|
||||
put_user_ex(regs->sp, &sc->sp);
|
||||
put_user_ex(regs->bx, &sc->bx);
|
||||
put_user_ex(regs->dx, &sc->dx);
|
||||
put_user_ex(regs->cx, &sc->cx);
|
||||
put_user_ex(regs->ax, &sc->ax);
|
||||
unsafe_put_user(regs->di, &sc->di, Efault);
|
||||
unsafe_put_user(regs->si, &sc->si, Efault);
|
||||
unsafe_put_user(regs->bp, &sc->bp, Efault);
|
||||
unsafe_put_user(regs->sp, &sc->sp, Efault);
|
||||
unsafe_put_user(regs->bx, &sc->bx, Efault);
|
||||
unsafe_put_user(regs->dx, &sc->dx, Efault);
|
||||
unsafe_put_user(regs->cx, &sc->cx, Efault);
|
||||
unsafe_put_user(regs->ax, &sc->ax, Efault);
|
||||
#ifdef CONFIG_X86_64
|
||||
put_user_ex(regs->r8, &sc->r8);
|
||||
put_user_ex(regs->r9, &sc->r9);
|
||||
put_user_ex(regs->r10, &sc->r10);
|
||||
put_user_ex(regs->r11, &sc->r11);
|
||||
put_user_ex(regs->r12, &sc->r12);
|
||||
put_user_ex(regs->r13, &sc->r13);
|
||||
put_user_ex(regs->r14, &sc->r14);
|
||||
put_user_ex(regs->r15, &sc->r15);
|
||||
unsafe_put_user(regs->r8, &sc->r8, Efault);
|
||||
unsafe_put_user(regs->r9, &sc->r9, Efault);
|
||||
unsafe_put_user(regs->r10, &sc->r10, Efault);
|
||||
unsafe_put_user(regs->r11, &sc->r11, Efault);
|
||||
unsafe_put_user(regs->r12, &sc->r12, Efault);
|
||||
unsafe_put_user(regs->r13, &sc->r13, Efault);
|
||||
unsafe_put_user(regs->r14, &sc->r14, Efault);
|
||||
unsafe_put_user(regs->r15, &sc->r15, Efault);
|
||||
#endif /* CONFIG_X86_64 */
|
||||
|
||||
put_user_ex(current->thread.trap_nr, &sc->trapno);
|
||||
put_user_ex(current->thread.error_code, &sc->err);
|
||||
put_user_ex(regs->ip, &sc->ip);
|
||||
unsafe_put_user(current->thread.trap_nr, &sc->trapno, Efault);
|
||||
unsafe_put_user(current->thread.error_code, &sc->err, Efault);
|
||||
unsafe_put_user(regs->ip, &sc->ip, Efault);
|
||||
#ifdef CONFIG_X86_32
|
||||
put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
|
||||
put_user_ex(regs->flags, &sc->flags);
|
||||
put_user_ex(regs->sp, &sc->sp_at_signal);
|
||||
put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);
|
||||
unsafe_put_user(regs->cs, (unsigned int __user *)&sc->cs, Efault);
|
||||
unsafe_put_user(regs->flags, &sc->flags, Efault);
|
||||
unsafe_put_user(regs->sp, &sc->sp_at_signal, Efault);
|
||||
unsafe_put_user(regs->ss, (unsigned int __user *)&sc->ss, Efault);
|
||||
#else /* !CONFIG_X86_32 */
|
||||
put_user_ex(regs->flags, &sc->flags);
|
||||
put_user_ex(regs->cs, &sc->cs);
|
||||
put_user_ex(0, &sc->gs);
|
||||
put_user_ex(0, &sc->fs);
|
||||
put_user_ex(regs->ss, &sc->ss);
|
||||
unsafe_put_user(regs->flags, &sc->flags, Efault);
|
||||
unsafe_put_user(regs->cs, &sc->cs, Efault);
|
||||
unsafe_put_user(0, &sc->gs, Efault);
|
||||
unsafe_put_user(0, &sc->fs, Efault);
|
||||
unsafe_put_user(regs->ss, &sc->ss, Efault);
|
||||
#endif /* CONFIG_X86_32 */
|
||||
|
||||
put_user_ex(fpstate, (unsigned long __user *)&sc->fpstate);
|
||||
unsafe_put_user(fpstate, (unsigned long __user *)&sc->fpstate, Efault);
|
||||
|
||||
/* non-iBCS2 extensions.. */
|
||||
put_user_ex(mask, &sc->oldmask);
|
||||
put_user_ex(current->thread.cr2, &sc->cr2);
|
||||
} put_user_catch(err);
|
||||
|
||||
return err;
|
||||
/* non-iBCS2 extensions.. */
|
||||
unsafe_put_user(mask, &sc->oldmask, Efault);
|
||||
unsafe_put_user(current->thread.cr2, &sc->cr2, Efault);
|
||||
return 0;
|
||||
Efault:
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
#define unsafe_put_sigcontext(sc, fp, regs, set, label) \
|
||||
do { \
|
||||
if (__unsafe_setup_sigcontext(sc, fp, regs, set->sig[0])) \
|
||||
goto label; \
|
||||
} while(0);
|
||||
|
||||
#define unsafe_put_sigmask(set, frame, label) \
|
||||
unsafe_put_user(*(__u64 *)(set), \
|
||||
(__u64 __user *)&(frame)->uc.uc_sigmask, \
|
||||
label)
|
||||
|
||||
/*
|
||||
* Set up a signal frame.
|
||||
*/
|
||||
@@ -312,26 +307,16 @@ __setup_frame(int sig, struct ksignal *ksig, sigset_t *set,
|
||||
{
|
||||
struct sigframe __user *frame;
|
||||
void __user *restorer;
|
||||
int err = 0;
|
||||
void __user *fpstate = NULL;
|
||||
void __user *fp = NULL;
|
||||
|
||||
frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fpstate);
|
||||
frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fp);
|
||||
|
||||
if (!access_ok(frame, sizeof(*frame)))
|
||||
if (!user_access_begin(frame, sizeof(*frame)))
|
||||
return -EFAULT;
|
||||
|
||||
if (__put_user(sig, &frame->sig))
|
||||
return -EFAULT;
|
||||
|
||||
if (setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
|
||||
return -EFAULT;
|
||||
|
||||
if (_NSIG_WORDS > 1) {
|
||||
if (__copy_to_user(&frame->extramask, &set->sig[1],
|
||||
sizeof(frame->extramask)))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
unsafe_put_user(sig, &frame->sig, Efault);
|
||||
unsafe_put_sigcontext(&frame->sc, fp, regs, set, Efault);
|
||||
unsafe_put_user(set->sig[1], &frame->extramask[0], Efault);
|
||||
if (current->mm->context.vdso)
|
||||
restorer = current->mm->context.vdso +
|
||||
vdso_image_32.sym___kernel_sigreturn;
|
||||
@@ -341,7 +326,7 @@ __setup_frame(int sig, struct ksignal *ksig, sigset_t *set,
|
||||
restorer = ksig->ka.sa.sa_restorer;
|
||||
|
||||
/* Set up to return from userspace. */
|
||||
err |= __put_user(restorer, &frame->pretcode);
|
||||
unsafe_put_user(restorer, &frame->pretcode, Efault);
|
||||
|
||||
/*
|
||||
* This is popl %eax ; movl $__NR_sigreturn, %eax ; int $0x80
|
||||
@@ -350,10 +335,8 @@ __setup_frame(int sig, struct ksignal *ksig, sigset_t *set,
|
||||
* reasons and because gdb uses it as a signature to notice
|
||||
* signal handler stack frames.
|
||||
*/
|
||||
err |= __put_user(*((u64 *)&retcode), (u64 *)frame->retcode);
|
||||
|
||||
if (err)
|
||||
return -EFAULT;
|
||||
unsafe_put_user(*((u64 *)&retcode), (u64 *)frame->retcode, Efault);
|
||||
user_access_end();
|
||||
|
||||
/* Set up registers for signal handler */
|
||||
regs->sp = (unsigned long)frame;
|
||||
@@ -368,6 +351,10 @@ __setup_frame(int sig, struct ksignal *ksig, sigset_t *set,
|
||||
regs->cs = __USER_CS;
|
||||
|
||||
return 0;
|
||||
|
||||
Efault:
|
||||
user_access_end();
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
static int __setup_rt_frame(int sig, struct ksignal *ksig,
|
||||
@@ -375,50 +362,45 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig,
|
||||
{
|
||||
struct rt_sigframe __user *frame;
|
||||
void __user *restorer;
|
||||
int err = 0;
|
||||
void __user *fpstate = NULL;
|
||||
void __user *fp = NULL;
|
||||
|
||||
frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fpstate);
|
||||
frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fp);
|
||||
|
||||
if (!access_ok(frame, sizeof(*frame)))
|
||||
if (!user_access_begin(frame, sizeof(*frame)))
|
||||
return -EFAULT;
|
||||
|
||||
put_user_try {
|
||||
put_user_ex(sig, &frame->sig);
|
||||
put_user_ex(&frame->info, &frame->pinfo);
|
||||
put_user_ex(&frame->uc, &frame->puc);
|
||||
unsafe_put_user(sig, &frame->sig, Efault);
|
||||
unsafe_put_user(&frame->info, &frame->pinfo, Efault);
|
||||
unsafe_put_user(&frame->uc, &frame->puc, Efault);
|
||||
|
||||
/* Create the ucontext. */
|
||||
if (static_cpu_has(X86_FEATURE_XSAVE))
|
||||
put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
|
||||
else
|
||||
put_user_ex(0, &frame->uc.uc_flags);
|
||||
put_user_ex(0, &frame->uc.uc_link);
|
||||
save_altstack_ex(&frame->uc.uc_stack, regs->sp);
|
||||
/* Create the ucontext. */
|
||||
if (static_cpu_has(X86_FEATURE_XSAVE))
|
||||
unsafe_put_user(UC_FP_XSTATE, &frame->uc.uc_flags, Efault);
|
||||
else
|
||||
unsafe_put_user(0, &frame->uc.uc_flags, Efault);
|
||||
unsafe_put_user(0, &frame->uc.uc_link, Efault);
|
||||
unsafe_save_altstack(&frame->uc.uc_stack, regs->sp, Efault);
|
||||
|
||||
/* Set up to return from userspace. */
|
||||
restorer = current->mm->context.vdso +
|
||||
vdso_image_32.sym___kernel_rt_sigreturn;
|
||||
if (ksig->ka.sa.sa_flags & SA_RESTORER)
|
||||
restorer = ksig->ka.sa.sa_restorer;
|
||||
put_user_ex(restorer, &frame->pretcode);
|
||||
/* Set up to return from userspace. */
|
||||
restorer = current->mm->context.vdso +
|
||||
vdso_image_32.sym___kernel_rt_sigreturn;
|
||||
if (ksig->ka.sa.sa_flags & SA_RESTORER)
|
||||
restorer = ksig->ka.sa.sa_restorer;
|
||||
unsafe_put_user(restorer, &frame->pretcode, Efault);
|
||||
|
||||
/*
|
||||
* This is movl $__NR_rt_sigreturn, %ax ; int $0x80
|
||||
*
|
||||
* WE DO NOT USE IT ANY MORE! It's only left here for historical
|
||||
* reasons and because gdb uses it as a signature to notice
|
||||
* signal handler stack frames.
|
||||
*/
|
||||
put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode);
|
||||
} put_user_catch(err);
|
||||
/*
|
||||
* This is movl $__NR_rt_sigreturn, %ax ; int $0x80
|
||||
*
|
||||
* WE DO NOT USE IT ANY MORE! It's only left here for historical
|
||||
* reasons and because gdb uses it as a signature to notice
|
||||
* signal handler stack frames.
|
||||
*/
|
||||
unsafe_put_user(*((u64 *)&rt_retcode), (u64 *)frame->retcode, Efault);
|
||||
unsafe_put_sigcontext(&frame->uc.uc_mcontext, fp, regs, set, Efault);
|
||||
unsafe_put_sigmask(set, frame, Efault);
|
||||
user_access_end();
|
||||
|
||||
err |= copy_siginfo_to_user(&frame->info, &ksig->info);
|
||||
err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
|
||||
regs, set->sig[0]);
|
||||
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
||||
|
||||
if (err)
|
||||
if (copy_siginfo_to_user(&frame->info, &ksig->info))
|
||||
return -EFAULT;
|
||||
|
||||
/* Set up registers for signal handler */
|
||||
@@ -434,6 +416,9 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig,
|
||||
regs->cs = __USER_CS;
|
||||
|
||||
return 0;
|
||||
Efault:
|
||||
user_access_end();
|
||||
return -EFAULT;
|
||||
}
|
||||
#else /* !CONFIG_X86_32 */
|
||||
static unsigned long frame_uc_flags(struct pt_regs *regs)
|
||||
@@ -457,43 +442,34 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig,
|
||||
struct rt_sigframe __user *frame;
|
||||
void __user *fp = NULL;
|
||||
unsigned long uc_flags;
|
||||
int err = 0;
|
||||
|
||||
/* x86-64 should always use SA_RESTORER. */
|
||||
if (!(ksig->ka.sa.sa_flags & SA_RESTORER))
|
||||
return -EFAULT;
|
||||
|
||||
frame = get_sigframe(&ksig->ka, regs, sizeof(struct rt_sigframe), &fp);
|
||||
uc_flags = frame_uc_flags(regs);
|
||||
|
||||
if (!access_ok(frame, sizeof(*frame)))
|
||||
if (!user_access_begin(frame, sizeof(*frame)))
|
||||
return -EFAULT;
|
||||
|
||||
/* Create the ucontext. */
|
||||
unsafe_put_user(uc_flags, &frame->uc.uc_flags, Efault);
|
||||
unsafe_put_user(0, &frame->uc.uc_link, Efault);
|
||||
unsafe_save_altstack(&frame->uc.uc_stack, regs->sp, Efault);
|
||||
|
||||
/* Set up to return from userspace. If provided, use a stub
|
||||
already in userspace. */
|
||||
unsafe_put_user(ksig->ka.sa.sa_restorer, &frame->pretcode, Efault);
|
||||
unsafe_put_sigcontext(&frame->uc.uc_mcontext, fp, regs, set, Efault);
|
||||
unsafe_put_sigmask(set, frame, Efault);
|
||||
user_access_end();
|
||||
|
||||
if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
|
||||
if (copy_siginfo_to_user(&frame->info, &ksig->info))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
uc_flags = frame_uc_flags(regs);
|
||||
|
||||
put_user_try {
|
||||
/* Create the ucontext. */
|
||||
put_user_ex(uc_flags, &frame->uc.uc_flags);
|
||||
put_user_ex(0, &frame->uc.uc_link);
|
||||
save_altstack_ex(&frame->uc.uc_stack, regs->sp);
|
||||
|
||||
/* Set up to return from userspace. If provided, use a stub
|
||||
already in userspace. */
|
||||
/* x86-64 should always use SA_RESTORER. */
|
||||
if (ksig->ka.sa.sa_flags & SA_RESTORER) {
|
||||
put_user_ex(ksig->ka.sa.sa_restorer, &frame->pretcode);
|
||||
} else {
|
||||
/* could use a vstub here */
|
||||
err |= -EFAULT;
|
||||
}
|
||||
} put_user_catch(err);
|
||||
|
||||
err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]);
|
||||
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
||||
|
||||
if (err)
|
||||
return -EFAULT;
|
||||
|
||||
/* Set up registers for signal handler */
|
||||
regs->di = sig;
|
||||
/* In case the signal handler was declared without prototypes */
|
||||
@@ -530,6 +506,10 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig,
|
||||
force_valid_ss(regs);
|
||||
|
||||
return 0;
|
||||
|
||||
Efault:
|
||||
user_access_end();
|
||||
return -EFAULT;
|
||||
}
|
||||
#endif /* CONFIG_X86_32 */
|
||||
|
||||
@@ -541,45 +521,34 @@ static int x32_setup_rt_frame(struct ksignal *ksig,
|
||||
struct rt_sigframe_x32 __user *frame;
|
||||
unsigned long uc_flags;
|
||||
void __user *restorer;
|
||||
int err = 0;
|
||||
void __user *fpstate = NULL;
|
||||
void __user *fp = NULL;
|
||||
|
||||
frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fpstate);
|
||||
|
||||
if (!access_ok(frame, sizeof(*frame)))
|
||||
if (!(ksig->ka.sa.sa_flags & SA_RESTORER))
|
||||
return -EFAULT;
|
||||
|
||||
frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fp);
|
||||
|
||||
uc_flags = frame_uc_flags(regs);
|
||||
|
||||
if (!user_access_begin(frame, sizeof(*frame)))
|
||||
return -EFAULT;
|
||||
|
||||
/* Create the ucontext. */
|
||||
unsafe_put_user(uc_flags, &frame->uc.uc_flags, Efault);
|
||||
unsafe_put_user(0, &frame->uc.uc_link, Efault);
|
||||
unsafe_compat_save_altstack(&frame->uc.uc_stack, regs->sp, Efault);
|
||||
unsafe_put_user(0, &frame->uc.uc__pad0, Efault);
|
||||
restorer = ksig->ka.sa.sa_restorer;
|
||||
unsafe_put_user(restorer, (unsigned long __user *)&frame->pretcode, Efault);
|
||||
unsafe_put_sigcontext(&frame->uc.uc_mcontext, fp, regs, set, Efault);
|
||||
unsafe_put_sigmask(set, frame, Efault);
|
||||
user_access_end();
|
||||
|
||||
if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
|
||||
if (__copy_siginfo_to_user32(&frame->info, &ksig->info, true))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
uc_flags = frame_uc_flags(regs);
|
||||
|
||||
put_user_try {
|
||||
/* Create the ucontext. */
|
||||
put_user_ex(uc_flags, &frame->uc.uc_flags);
|
||||
put_user_ex(0, &frame->uc.uc_link);
|
||||
compat_save_altstack_ex(&frame->uc.uc_stack, regs->sp);
|
||||
put_user_ex(0, &frame->uc.uc__pad0);
|
||||
|
||||
if (ksig->ka.sa.sa_flags & SA_RESTORER) {
|
||||
restorer = ksig->ka.sa.sa_restorer;
|
||||
} else {
|
||||
/* could use a vstub here */
|
||||
restorer = NULL;
|
||||
err |= -EFAULT;
|
||||
}
|
||||
put_user_ex(restorer, (unsigned long __user *)&frame->pretcode);
|
||||
} put_user_catch(err);
|
||||
|
||||
err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
|
||||
regs, set->sig[0]);
|
||||
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
||||
|
||||
if (err)
|
||||
return -EFAULT;
|
||||
|
||||
/* Set up registers for signal handler */
|
||||
regs->sp = (unsigned long) frame;
|
||||
regs->ip = (unsigned long) ksig->ka.sa.sa_handler;
|
||||
@@ -597,6 +566,11 @@ static int x32_setup_rt_frame(struct ksignal *ksig,
|
||||
#endif /* CONFIG_X86_X32_ABI */
|
||||
|
||||
return 0;
|
||||
#ifdef CONFIG_X86_X32_ABI
|
||||
Efault:
|
||||
user_access_end();
|
||||
return -EFAULT;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -613,9 +587,8 @@ SYSCALL_DEFINE0(sigreturn)
|
||||
|
||||
if (!access_ok(frame, sizeof(*frame)))
|
||||
goto badframe;
|
||||
if (__get_user(set.sig[0], &frame->sc.oldmask) || (_NSIG_WORDS > 1
|
||||
&& __copy_from_user(&set.sig[1], &frame->extramask,
|
||||
sizeof(frame->extramask))))
|
||||
if (__get_user(set.sig[0], &frame->sc.oldmask) ||
|
||||
__get_user(set.sig[1], &frame->extramask[0]))
|
||||
goto badframe;
|
||||
|
||||
set_current_blocked(&set);
|
||||
@@ -645,7 +618,7 @@ SYSCALL_DEFINE0(rt_sigreturn)
|
||||
frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long));
|
||||
if (!access_ok(frame, sizeof(*frame)))
|
||||
goto badframe;
|
||||
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
|
||||
if (__get_user(*(__u64 *)&set, (__u64 __user *)&frame->uc.uc_sigmask))
|
||||
goto badframe;
|
||||
if (__get_user(uc_flags, &frame->uc.uc_flags))
|
||||
goto badframe;
|
||||
@@ -870,7 +843,7 @@ asmlinkage long sys32_x32_rt_sigreturn(void)
|
||||
|
||||
if (!access_ok(frame, sizeof(*frame)))
|
||||
goto badframe;
|
||||
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
|
||||
if (__get_user(set.sig[0], (__u64 __user *)&frame->uc.uc_sigmask))
|
||||
goto badframe;
|
||||
if (__get_user(uc_flags, &frame->uc.uc_flags))
|
||||
goto badframe;
|
||||
|
@@ -96,7 +96,8 @@ struct stack_frame_user {
|
||||
};
|
||||
|
||||
static int
|
||||
copy_stack_frame(const void __user *fp, struct stack_frame_user *frame)
|
||||
copy_stack_frame(const struct stack_frame_user __user *fp,
|
||||
struct stack_frame_user *frame)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -105,7 +106,8 @@ copy_stack_frame(const void __user *fp, struct stack_frame_user *frame)
|
||||
|
||||
ret = 1;
|
||||
pagefault_disable();
|
||||
if (__copy_from_user_inatomic(frame, fp, sizeof(*frame)))
|
||||
if (__get_user(frame->next_fp, &fp->next_fp) ||
|
||||
__get_user(frame->ret_addr, &fp->ret_addr))
|
||||
ret = 0;
|
||||
pagefault_enable();
|
||||
|
||||
|
@@ -98,7 +98,6 @@ void save_v86_state(struct kernel_vm86_regs *regs, int retval)
|
||||
struct task_struct *tsk = current;
|
||||
struct vm86plus_struct __user *user;
|
||||
struct vm86 *vm86 = current->thread.vm86;
|
||||
long err = 0;
|
||||
|
||||
/*
|
||||
* This gets called from entry.S with interrupts disabled, but
|
||||
@@ -114,37 +113,30 @@ void save_v86_state(struct kernel_vm86_regs *regs, int retval)
|
||||
set_flags(regs->pt.flags, VEFLAGS, X86_EFLAGS_VIF | vm86->veflags_mask);
|
||||
user = vm86->user_vm86;
|
||||
|
||||
if (!access_ok(user, vm86->vm86plus.is_vm86pus ?
|
||||
if (!user_access_begin(user, vm86->vm86plus.is_vm86pus ?
|
||||
sizeof(struct vm86plus_struct) :
|
||||
sizeof(struct vm86_struct))) {
|
||||
pr_alert("could not access userspace vm86 info\n");
|
||||
do_exit(SIGSEGV);
|
||||
}
|
||||
sizeof(struct vm86_struct)))
|
||||
goto Efault;
|
||||
|
||||
put_user_try {
|
||||
put_user_ex(regs->pt.bx, &user->regs.ebx);
|
||||
put_user_ex(regs->pt.cx, &user->regs.ecx);
|
||||
put_user_ex(regs->pt.dx, &user->regs.edx);
|
||||
put_user_ex(regs->pt.si, &user->regs.esi);
|
||||
put_user_ex(regs->pt.di, &user->regs.edi);
|
||||
put_user_ex(regs->pt.bp, &user->regs.ebp);
|
||||
put_user_ex(regs->pt.ax, &user->regs.eax);
|
||||
put_user_ex(regs->pt.ip, &user->regs.eip);
|
||||
put_user_ex(regs->pt.cs, &user->regs.cs);
|
||||
put_user_ex(regs->pt.flags, &user->regs.eflags);
|
||||
put_user_ex(regs->pt.sp, &user->regs.esp);
|
||||
put_user_ex(regs->pt.ss, &user->regs.ss);
|
||||
put_user_ex(regs->es, &user->regs.es);
|
||||
put_user_ex(regs->ds, &user->regs.ds);
|
||||
put_user_ex(regs->fs, &user->regs.fs);
|
||||
put_user_ex(regs->gs, &user->regs.gs);
|
||||
unsafe_put_user(regs->pt.bx, &user->regs.ebx, Efault_end);
|
||||
unsafe_put_user(regs->pt.cx, &user->regs.ecx, Efault_end);
|
||||
unsafe_put_user(regs->pt.dx, &user->regs.edx, Efault_end);
|
||||
unsafe_put_user(regs->pt.si, &user->regs.esi, Efault_end);
|
||||
unsafe_put_user(regs->pt.di, &user->regs.edi, Efault_end);
|
||||
unsafe_put_user(regs->pt.bp, &user->regs.ebp, Efault_end);
|
||||
unsafe_put_user(regs->pt.ax, &user->regs.eax, Efault_end);
|
||||
unsafe_put_user(regs->pt.ip, &user->regs.eip, Efault_end);
|
||||
unsafe_put_user(regs->pt.cs, &user->regs.cs, Efault_end);
|
||||
unsafe_put_user(regs->pt.flags, &user->regs.eflags, Efault_end);
|
||||
unsafe_put_user(regs->pt.sp, &user->regs.esp, Efault_end);
|
||||
unsafe_put_user(regs->pt.ss, &user->regs.ss, Efault_end);
|
||||
unsafe_put_user(regs->es, &user->regs.es, Efault_end);
|
||||
unsafe_put_user(regs->ds, &user->regs.ds, Efault_end);
|
||||
unsafe_put_user(regs->fs, &user->regs.fs, Efault_end);
|
||||
unsafe_put_user(regs->gs, &user->regs.gs, Efault_end);
|
||||
unsafe_put_user(vm86->screen_bitmap, &user->screen_bitmap, Efault_end);
|
||||
|
||||
put_user_ex(vm86->screen_bitmap, &user->screen_bitmap);
|
||||
} put_user_catch(err);
|
||||
if (err) {
|
||||
pr_alert("could not access userspace vm86 info\n");
|
||||
do_exit(SIGSEGV);
|
||||
}
|
||||
user_access_end();
|
||||
|
||||
preempt_disable();
|
||||
tsk->thread.sp0 = vm86->saved_sp0;
|
||||
@@ -159,6 +151,13 @@ void save_v86_state(struct kernel_vm86_regs *regs, int retval)
|
||||
lazy_load_gs(vm86->regs32.gs);
|
||||
|
||||
regs->pt.ax = retval;
|
||||
return;
|
||||
|
||||
Efault_end:
|
||||
user_access_end();
|
||||
Efault:
|
||||
pr_alert("could not access userspace vm86 info\n");
|
||||
do_exit(SIGSEGV);
|
||||
}
|
||||
|
||||
static void mark_screen_rdonly(struct mm_struct *mm)
|
||||
@@ -243,6 +242,7 @@ static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus)
|
||||
struct kernel_vm86_regs vm86regs;
|
||||
struct pt_regs *regs = current_pt_regs();
|
||||
unsigned long err = 0;
|
||||
struct vm86_struct v;
|
||||
|
||||
err = security_mmap_addr(0);
|
||||
if (err) {
|
||||
@@ -278,39 +278,32 @@ static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus)
|
||||
if (vm86->saved_sp0)
|
||||
return -EPERM;
|
||||
|
||||
if (!access_ok(user_vm86, plus ?
|
||||
sizeof(struct vm86_struct) :
|
||||
sizeof(struct vm86plus_struct)))
|
||||
if (copy_from_user(&v, user_vm86,
|
||||
offsetof(struct vm86_struct, int_revectored)))
|
||||
return -EFAULT;
|
||||
|
||||
memset(&vm86regs, 0, sizeof(vm86regs));
|
||||
get_user_try {
|
||||
unsigned short seg;
|
||||
get_user_ex(vm86regs.pt.bx, &user_vm86->regs.ebx);
|
||||
get_user_ex(vm86regs.pt.cx, &user_vm86->regs.ecx);
|
||||
get_user_ex(vm86regs.pt.dx, &user_vm86->regs.edx);
|
||||
get_user_ex(vm86regs.pt.si, &user_vm86->regs.esi);
|
||||
get_user_ex(vm86regs.pt.di, &user_vm86->regs.edi);
|
||||
get_user_ex(vm86regs.pt.bp, &user_vm86->regs.ebp);
|
||||
get_user_ex(vm86regs.pt.ax, &user_vm86->regs.eax);
|
||||
get_user_ex(vm86regs.pt.ip, &user_vm86->regs.eip);
|
||||
get_user_ex(seg, &user_vm86->regs.cs);
|
||||
vm86regs.pt.cs = seg;
|
||||
get_user_ex(vm86regs.pt.flags, &user_vm86->regs.eflags);
|
||||
get_user_ex(vm86regs.pt.sp, &user_vm86->regs.esp);
|
||||
get_user_ex(seg, &user_vm86->regs.ss);
|
||||
vm86regs.pt.ss = seg;
|
||||
get_user_ex(vm86regs.es, &user_vm86->regs.es);
|
||||
get_user_ex(vm86regs.ds, &user_vm86->regs.ds);
|
||||
get_user_ex(vm86regs.fs, &user_vm86->regs.fs);
|
||||
get_user_ex(vm86regs.gs, &user_vm86->regs.gs);
|
||||
|
||||
get_user_ex(vm86->flags, &user_vm86->flags);
|
||||
get_user_ex(vm86->screen_bitmap, &user_vm86->screen_bitmap);
|
||||
get_user_ex(vm86->cpu_type, &user_vm86->cpu_type);
|
||||
} get_user_catch(err);
|
||||
if (err)
|
||||
return err;
|
||||
vm86regs.pt.bx = v.regs.ebx;
|
||||
vm86regs.pt.cx = v.regs.ecx;
|
||||
vm86regs.pt.dx = v.regs.edx;
|
||||
vm86regs.pt.si = v.regs.esi;
|
||||
vm86regs.pt.di = v.regs.edi;
|
||||
vm86regs.pt.bp = v.regs.ebp;
|
||||
vm86regs.pt.ax = v.regs.eax;
|
||||
vm86regs.pt.ip = v.regs.eip;
|
||||
vm86regs.pt.cs = v.regs.cs;
|
||||
vm86regs.pt.flags = v.regs.eflags;
|
||||
vm86regs.pt.sp = v.regs.esp;
|
||||
vm86regs.pt.ss = v.regs.ss;
|
||||
vm86regs.es = v.regs.es;
|
||||
vm86regs.ds = v.regs.ds;
|
||||
vm86regs.fs = v.regs.fs;
|
||||
vm86regs.gs = v.regs.gs;
|
||||
|
||||
vm86->flags = v.flags;
|
||||
vm86->screen_bitmap = v.screen_bitmap;
|
||||
vm86->cpu_type = v.cpu_type;
|
||||
|
||||
if (copy_from_user(&vm86->int_revectored,
|
||||
&user_vm86->int_revectored,
|
||||
|
Reference in New Issue
Block a user