mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-28 17:41:50 +00:00
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:
commit
a215032725
17 changed files with 391 additions and 768 deletions
|
@ -337,10 +337,4 @@ pointer which points to one of:
|
||||||
entry->insn. It is used to distinguish page faults from machine
|
entry->insn. It is used to distinguish page faults from machine
|
||||||
check.
|
check.
|
||||||
|
|
||||||
3) ``int ex_handler_ext(const struct exception_table_entry *fixup)``
|
|
||||||
This case is used for uaccess_err ... we need to set a flag
|
|
||||||
in the task structure. Before the handler functions existed this
|
|
||||||
case was handled by adding a large offset to the fixup to tag
|
|
||||||
it as special.
|
|
||||||
|
|
||||||
More functions can easily be added.
|
More functions can easily be added.
|
||||||
|
|
|
@ -2490,7 +2490,7 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry_ctx *ent
|
||||||
/* 32-bit process in 64-bit kernel. */
|
/* 32-bit process in 64-bit kernel. */
|
||||||
unsigned long ss_base, cs_base;
|
unsigned long ss_base, cs_base;
|
||||||
struct stack_frame_ia32 frame;
|
struct stack_frame_ia32 frame;
|
||||||
const void __user *fp;
|
const struct stack_frame_ia32 __user *fp;
|
||||||
|
|
||||||
if (!test_thread_flag(TIF_IA32))
|
if (!test_thread_flag(TIF_IA32))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2501,18 +2501,12 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry_ctx *ent
|
||||||
fp = compat_ptr(ss_base + regs->bp);
|
fp = compat_ptr(ss_base + regs->bp);
|
||||||
pagefault_disable();
|
pagefault_disable();
|
||||||
while (entry->nr < entry->max_stack) {
|
while (entry->nr < entry->max_stack) {
|
||||||
unsigned long bytes;
|
|
||||||
frame.next_frame = 0;
|
|
||||||
frame.return_address = 0;
|
|
||||||
|
|
||||||
if (!valid_user_frame(fp, sizeof(frame)))
|
if (!valid_user_frame(fp, sizeof(frame)))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
bytes = __copy_from_user_nmi(&frame.next_frame, fp, 4);
|
if (__get_user(frame.next_frame, &fp->next_frame))
|
||||||
if (bytes != 0)
|
|
||||||
break;
|
break;
|
||||||
bytes = __copy_from_user_nmi(&frame.return_address, fp+4, 4);
|
if (__get_user(frame.return_address, &fp->return_address))
|
||||||
if (bytes != 0)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
perf_callchain_store(entry, cs_base + frame.return_address);
|
perf_callchain_store(entry, cs_base + frame.return_address);
|
||||||
|
@ -2533,7 +2527,7 @@ void
|
||||||
perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs)
|
perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct stack_frame frame;
|
struct stack_frame frame;
|
||||||
const unsigned long __user *fp;
|
const struct stack_frame __user *fp;
|
||||||
|
|
||||||
if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
|
if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
|
||||||
/* TODO: We don't support guest os callchain now */
|
/* TODO: We don't support guest os callchain now */
|
||||||
|
@ -2546,7 +2540,7 @@ perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs
|
||||||
if (regs->flags & (X86_VM_MASK | PERF_EFLAGS_VM))
|
if (regs->flags & (X86_VM_MASK | PERF_EFLAGS_VM))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fp = (unsigned long __user *)regs->bp;
|
fp = (void __user *)regs->bp;
|
||||||
|
|
||||||
perf_callchain_store(entry, regs->ip);
|
perf_callchain_store(entry, regs->ip);
|
||||||
|
|
||||||
|
@ -2558,19 +2552,12 @@ perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs
|
||||||
|
|
||||||
pagefault_disable();
|
pagefault_disable();
|
||||||
while (entry->nr < entry->max_stack) {
|
while (entry->nr < entry->max_stack) {
|
||||||
unsigned long bytes;
|
|
||||||
|
|
||||||
frame.next_frame = NULL;
|
|
||||||
frame.return_address = 0;
|
|
||||||
|
|
||||||
if (!valid_user_frame(fp, sizeof(frame)))
|
if (!valid_user_frame(fp, sizeof(frame)))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
bytes = __copy_from_user_nmi(&frame.next_frame, fp, sizeof(*fp));
|
if (__get_user(frame.next_frame, &fp->next_frame))
|
||||||
if (bytes != 0)
|
|
||||||
break;
|
break;
|
||||||
bytes = __copy_from_user_nmi(&frame.return_address, fp + 1, sizeof(*fp));
|
if (__get_user(frame.return_address, &fp->return_address))
|
||||||
if (bytes != 0)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
perf_callchain_store(entry, frame.return_address);
|
perf_callchain_store(entry, frame.return_address);
|
||||||
|
|
|
@ -36,70 +36,56 @@
|
||||||
#include <asm/sighandling.h>
|
#include <asm/sighandling.h>
|
||||||
#include <asm/smap.h>
|
#include <asm/smap.h>
|
||||||
|
|
||||||
|
static inline void reload_segments(struct sigcontext_32 *sc)
|
||||||
|
{
|
||||||
|
unsigned int cur;
|
||||||
|
|
||||||
|
savesegment(gs, cur);
|
||||||
|
if ((sc->gs | 0x03) != cur)
|
||||||
|
load_gs_index(sc->gs | 0x03);
|
||||||
|
savesegment(fs, cur);
|
||||||
|
if ((sc->fs | 0x03) != cur)
|
||||||
|
loadsegment(fs, sc->fs | 0x03);
|
||||||
|
savesegment(ds, cur);
|
||||||
|
if ((sc->ds | 0x03) != cur)
|
||||||
|
loadsegment(ds, sc->ds | 0x03);
|
||||||
|
savesegment(es, cur);
|
||||||
|
if ((sc->es | 0x03) != cur)
|
||||||
|
loadsegment(es, sc->es | 0x03);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do a signal return; undo the signal stack.
|
* Do a signal return; undo the signal stack.
|
||||||
*/
|
*/
|
||||||
#define loadsegment_gs(v) load_gs_index(v)
|
|
||||||
#define loadsegment_fs(v) loadsegment(fs, v)
|
|
||||||
#define loadsegment_ds(v) loadsegment(ds, v)
|
|
||||||
#define loadsegment_es(v) loadsegment(es, v)
|
|
||||||
|
|
||||||
#define get_user_seg(seg) ({ unsigned int v; savesegment(seg, v); v; })
|
|
||||||
#define set_user_seg(seg, v) loadsegment_##seg(v)
|
|
||||||
|
|
||||||
#define COPY(x) { \
|
|
||||||
get_user_ex(regs->x, &sc->x); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define GET_SEG(seg) ({ \
|
|
||||||
unsigned short tmp; \
|
|
||||||
get_user_ex(tmp, &sc->seg); \
|
|
||||||
tmp; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define COPY_SEG_CPL3(seg) do { \
|
|
||||||
regs->seg = GET_SEG(seg) | 3; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define RELOAD_SEG(seg) { \
|
|
||||||
unsigned int pre = (seg) | 3; \
|
|
||||||
unsigned int cur = get_user_seg(seg); \
|
|
||||||
if (pre != cur) \
|
|
||||||
set_user_seg(seg, pre); \
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ia32_restore_sigcontext(struct pt_regs *regs,
|
static int ia32_restore_sigcontext(struct pt_regs *regs,
|
||||||
struct sigcontext_32 __user *sc)
|
struct sigcontext_32 __user *usc)
|
||||||
{
|
{
|
||||||
unsigned int tmpflags, err = 0;
|
struct sigcontext_32 sc;
|
||||||
u16 gs, fs, es, ds;
|
|
||||||
void __user *buf;
|
|
||||||
u32 tmp;
|
|
||||||
|
|
||||||
/* Always make any pending restarted system calls return -EINTR */
|
/* Always make any pending restarted system calls return -EINTR */
|
||||||
current->restart_block.fn = do_no_restart_syscall;
|
current->restart_block.fn = do_no_restart_syscall;
|
||||||
|
|
||||||
get_user_try {
|
if (unlikely(copy_from_user(&sc, usc, sizeof(sc))))
|
||||||
gs = GET_SEG(gs);
|
return -EFAULT;
|
||||||
fs = GET_SEG(fs);
|
|
||||||
ds = GET_SEG(ds);
|
|
||||||
es = GET_SEG(es);
|
|
||||||
|
|
||||||
COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
|
/* Get only the ia32 registers. */
|
||||||
COPY(dx); COPY(cx); COPY(ip); COPY(ax);
|
regs->bx = sc.bx;
|
||||||
/* Don't touch extended registers */
|
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;
|
||||||
|
|
||||||
COPY_SEG_CPL3(cs);
|
/* Get CS/SS and force CPL3 */
|
||||||
COPY_SEG_CPL3(ss);
|
regs->cs = sc.cs | 0x03;
|
||||||
|
regs->ss = sc.ss | 0x03;
|
||||||
|
|
||||||
get_user_ex(tmpflags, &sc->flags);
|
regs->flags = (regs->flags & ~FIX_EFLAGS) | (sc.flags & FIX_EFLAGS);
|
||||||
regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
|
/* disable syscall checks */
|
||||||
/* disable syscall checks */
|
regs->orig_ax = -1;
|
||||||
regs->orig_ax = -1;
|
|
||||||
|
|
||||||
get_user_ex(tmp, &sc->fpstate);
|
|
||||||
buf = compat_ptr(tmp);
|
|
||||||
} get_user_catch(err);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reload fs and gs if they have changed in the signal
|
* Reload fs and gs if they have changed in the signal
|
||||||
|
@ -107,14 +93,8 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
|
||||||
* the handler, but does not clobber them at least in the
|
* the handler, but does not clobber them at least in the
|
||||||
* normal case.
|
* normal case.
|
||||||
*/
|
*/
|
||||||
RELOAD_SEG(gs);
|
reload_segments(&sc);
|
||||||
RELOAD_SEG(fs);
|
return fpu__restore_sig(compat_ptr(sc.fpstate), 1);
|
||||||
RELOAD_SEG(ds);
|
|
||||||
RELOAD_SEG(es);
|
|
||||||
|
|
||||||
err |= fpu__restore_sig(buf, 1);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
COMPAT_SYSCALL_DEFINE0(sigreturn)
|
COMPAT_SYSCALL_DEFINE0(sigreturn)
|
||||||
|
@ -126,10 +106,7 @@ COMPAT_SYSCALL_DEFINE0(sigreturn)
|
||||||
if (!access_ok(frame, sizeof(*frame)))
|
if (!access_ok(frame, sizeof(*frame)))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
if (__get_user(set.sig[0], &frame->sc.oldmask)
|
if (__get_user(set.sig[0], &frame->sc.oldmask)
|
||||||
|| (_COMPAT_NSIG_WORDS > 1
|
|| __get_user(((__u32 *)&set)[1], &frame->extramask[0]))
|
||||||
&& __copy_from_user((((char *) &set.sig) + 4),
|
|
||||||
&frame->extramask,
|
|
||||||
sizeof(frame->extramask))))
|
|
||||||
goto badframe;
|
goto badframe;
|
||||||
|
|
||||||
set_current_blocked(&set);
|
set_current_blocked(&set);
|
||||||
|
@ -153,7 +130,7 @@ COMPAT_SYSCALL_DEFINE0(rt_sigreturn)
|
||||||
|
|
||||||
if (!access_ok(frame, sizeof(*frame)))
|
if (!access_ok(frame, sizeof(*frame)))
|
||||||
goto badframe;
|
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;
|
goto badframe;
|
||||||
|
|
||||||
set_current_blocked(&set);
|
set_current_blocked(&set);
|
||||||
|
@ -175,44 +152,51 @@ badframe:
|
||||||
* Set up a signal frame.
|
* Set up a signal frame.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int ia32_setup_sigcontext(struct sigcontext_32 __user *sc,
|
#define get_user_seg(seg) ({ unsigned int v; savesegment(seg, v); v; })
|
||||||
void __user *fpstate,
|
|
||||||
struct pt_regs *regs, unsigned int mask)
|
static __always_inline int
|
||||||
|
__unsafe_setup_sigcontext32(struct sigcontext_32 __user *sc,
|
||||||
|
void __user *fpstate,
|
||||||
|
struct pt_regs *regs, unsigned int mask)
|
||||||
{
|
{
|
||||||
int err = 0;
|
unsafe_put_user(get_user_seg(gs), (unsigned int __user *)&sc->gs, Efault);
|
||||||
|
unsafe_put_user(get_user_seg(fs), (unsigned int __user *)&sc->fs, Efault);
|
||||||
|
unsafe_put_user(get_user_seg(ds), (unsigned int __user *)&sc->ds, Efault);
|
||||||
|
unsafe_put_user(get_user_seg(es), (unsigned int __user *)&sc->es, Efault);
|
||||||
|
|
||||||
put_user_try {
|
unsafe_put_user(regs->di, &sc->di, Efault);
|
||||||
put_user_ex(get_user_seg(gs), (unsigned int __user *)&sc->gs);
|
unsafe_put_user(regs->si, &sc->si, Efault);
|
||||||
put_user_ex(get_user_seg(fs), (unsigned int __user *)&sc->fs);
|
unsafe_put_user(regs->bp, &sc->bp, Efault);
|
||||||
put_user_ex(get_user_seg(ds), (unsigned int __user *)&sc->ds);
|
unsafe_put_user(regs->sp, &sc->sp, Efault);
|
||||||
put_user_ex(get_user_seg(es), (unsigned int __user *)&sc->es);
|
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);
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
|
||||||
put_user_ex(regs->di, &sc->di);
|
unsafe_put_user(ptr_to_compat(fpstate), &sc->fpstate, Efault);
|
||||||
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);
|
|
||||||
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);
|
|
||||||
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);
|
|
||||||
|
|
||||||
put_user_ex(ptr_to_compat(fpstate), &sc->fpstate);
|
/* non-iBCS2 extensions.. */
|
||||||
|
unsafe_put_user(mask, &sc->oldmask, Efault);
|
||||||
|
unsafe_put_user(current->thread.cr2, &sc->cr2, Efault);
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* non-iBCS2 extensions.. */
|
Efault:
|
||||||
put_user_ex(mask, &sc->oldmask);
|
return -EFAULT;
|
||||||
put_user_ex(current->thread.cr2, &sc->cr2);
|
|
||||||
} put_user_catch(err);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define unsafe_put_sigcontext32(sc, fp, regs, set, label) \
|
||||||
|
do { \
|
||||||
|
if (__unsafe_setup_sigcontext32(sc, fp, regs, set->sig[0])) \
|
||||||
|
goto label; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Determine which stack to use..
|
* Determine which stack to use..
|
||||||
*/
|
*/
|
||||||
|
@ -252,8 +236,7 @@ int ia32_setup_frame(int sig, struct ksignal *ksig,
|
||||||
{
|
{
|
||||||
struct sigframe_ia32 __user *frame;
|
struct sigframe_ia32 __user *frame;
|
||||||
void __user *restorer;
|
void __user *restorer;
|
||||||
int err = 0;
|
void __user *fp = NULL;
|
||||||
void __user *fpstate = NULL;
|
|
||||||
|
|
||||||
/* copy_to_user optimizes that into a single 8 byte store */
|
/* copy_to_user optimizes that into a single 8 byte store */
|
||||||
static const struct {
|
static const struct {
|
||||||
|
@ -266,22 +249,7 @@ int ia32_setup_frame(int sig, struct ksignal *ksig,
|
||||||
0x80cd, /* int $0x80 */
|
0x80cd, /* int $0x80 */
|
||||||
};
|
};
|
||||||
|
|
||||||
frame = get_sigframe(ksig, regs, sizeof(*frame), &fpstate);
|
frame = get_sigframe(ksig, regs, sizeof(*frame), &fp);
|
||||||
|
|
||||||
if (!access_ok(frame, sizeof(*frame)))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
if (__put_user(sig, &frame->sig))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
if (_COMPAT_NSIG_WORDS > 1) {
|
|
||||||
if (__copy_to_user(frame->extramask, &set->sig[1],
|
|
||||||
sizeof(frame->extramask)))
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ksig->ka.sa.sa_flags & SA_RESTORER) {
|
if (ksig->ka.sa.sa_flags & SA_RESTORER) {
|
||||||
restorer = ksig->ka.sa.sa_restorer;
|
restorer = ksig->ka.sa.sa_restorer;
|
||||||
|
@ -294,19 +262,20 @@ int ia32_setup_frame(int sig, struct ksignal *ksig,
|
||||||
restorer = &frame->retcode;
|
restorer = &frame->retcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
put_user_try {
|
if (!user_access_begin(frame, sizeof(*frame)))
|
||||||
put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* These are actually not used anymore, but left because some
|
|
||||||
* gdb versions depend on them as a marker.
|
|
||||||
*/
|
|
||||||
put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
|
|
||||||
} put_user_catch(err);
|
|
||||||
|
|
||||||
if (err)
|
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
|
unsafe_put_user(sig, &frame->sig, Efault);
|
||||||
|
unsafe_put_sigcontext32(&frame->sc, fp, regs, set, Efault);
|
||||||
|
unsafe_put_user(set->sig[1], &frame->extramask[0], Efault);
|
||||||
|
unsafe_put_user(ptr_to_compat(restorer), &frame->pretcode, Efault);
|
||||||
|
/*
|
||||||
|
* These are actually not used anymore, but left because some
|
||||||
|
* gdb versions depend on them as a marker.
|
||||||
|
*/
|
||||||
|
unsafe_put_user(*((u64 *)&code), (u64 __user *)frame->retcode, Efault);
|
||||||
|
user_access_end();
|
||||||
|
|
||||||
/* Set up registers for signal handler */
|
/* Set up registers for signal handler */
|
||||||
regs->sp = (unsigned long) frame;
|
regs->sp = (unsigned long) frame;
|
||||||
regs->ip = (unsigned long) ksig->ka.sa.sa_handler;
|
regs->ip = (unsigned long) ksig->ka.sa.sa_handler;
|
||||||
|
@ -323,6 +292,9 @@ int ia32_setup_frame(int sig, struct ksignal *ksig,
|
||||||
regs->ss = __USER32_DS;
|
regs->ss = __USER32_DS;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Efault:
|
||||||
|
user_access_end();
|
||||||
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
|
int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
|
||||||
|
@ -330,10 +302,9 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
|
||||||
{
|
{
|
||||||
struct rt_sigframe_ia32 __user *frame;
|
struct rt_sigframe_ia32 __user *frame;
|
||||||
void __user *restorer;
|
void __user *restorer;
|
||||||
int err = 0;
|
void __user *fp = NULL;
|
||||||
void __user *fpstate = NULL;
|
|
||||||
|
|
||||||
/* __copy_to_user optimizes that into a single 8 byte store */
|
/* unsafe_put_user optimizes that into a single 8 byte store */
|
||||||
static const struct {
|
static const struct {
|
||||||
u8 movl;
|
u8 movl;
|
||||||
u32 val;
|
u32 val;
|
||||||
|
@ -346,44 +317,40 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
|
|
||||||
frame = get_sigframe(ksig, regs, sizeof(*frame), &fpstate);
|
frame = get_sigframe(ksig, regs, sizeof(*frame), &fp);
|
||||||
|
|
||||||
if (!access_ok(frame, sizeof(*frame)))
|
if (!user_access_begin(frame, sizeof(*frame)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
put_user_try {
|
unsafe_put_user(sig, &frame->sig, Efault);
|
||||||
put_user_ex(sig, &frame->sig);
|
unsafe_put_user(ptr_to_compat(&frame->info), &frame->pinfo, Efault);
|
||||||
put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
|
unsafe_put_user(ptr_to_compat(&frame->uc), &frame->puc, Efault);
|
||||||
put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
|
|
||||||
|
|
||||||
/* Create the ucontext. */
|
/* Create the ucontext. */
|
||||||
if (static_cpu_has(X86_FEATURE_XSAVE))
|
if (static_cpu_has(X86_FEATURE_XSAVE))
|
||||||
put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
|
unsafe_put_user(UC_FP_XSTATE, &frame->uc.uc_flags, Efault);
|
||||||
else
|
else
|
||||||
put_user_ex(0, &frame->uc.uc_flags);
|
unsafe_put_user(0, &frame->uc.uc_flags, Efault);
|
||||||
put_user_ex(0, &frame->uc.uc_link);
|
unsafe_put_user(0, &frame->uc.uc_link, Efault);
|
||||||
compat_save_altstack_ex(&frame->uc.uc_stack, regs->sp);
|
unsafe_compat_save_altstack(&frame->uc.uc_stack, regs->sp, Efault);
|
||||||
|
|
||||||
if (ksig->ka.sa.sa_flags & SA_RESTORER)
|
if (ksig->ka.sa.sa_flags & SA_RESTORER)
|
||||||
restorer = ksig->ka.sa.sa_restorer;
|
restorer = ksig->ka.sa.sa_restorer;
|
||||||
else
|
else
|
||||||
restorer = current->mm->context.vdso +
|
restorer = current->mm->context.vdso +
|
||||||
vdso_image_32.sym___kernel_rt_sigreturn;
|
vdso_image_32.sym___kernel_rt_sigreturn;
|
||||||
put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
|
unsafe_put_user(ptr_to_compat(restorer), &frame->pretcode, Efault);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Not actually used anymore, but left because some gdb
|
* Not actually used anymore, but left because some gdb
|
||||||
* versions need it.
|
* versions need it.
|
||||||
*/
|
*/
|
||||||
put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
|
unsafe_put_user(*((u64 *)&code), (u64 __user *)frame->retcode, Efault);
|
||||||
} put_user_catch(err);
|
unsafe_put_sigcontext32(&frame->uc.uc_mcontext, fp, regs, set, Efault);
|
||||||
|
unsafe_put_user(*(__u64 *)set, (__u64 *)&frame->uc.uc_sigmask, Efault);
|
||||||
|
user_access_end();
|
||||||
|
|
||||||
err |= __copy_siginfo_to_user32(&frame->info, &ksig->info, false);
|
if (__copy_siginfo_to_user32(&frame->info, &ksig->info, false))
|
||||||
err |= ia32_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;
|
return -EFAULT;
|
||||||
|
|
||||||
/* Set up registers for signal handler */
|
/* Set up registers for signal handler */
|
||||||
|
@ -402,4 +369,7 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
|
||||||
regs->ss = __USER32_DS;
|
regs->ss = __USER32_DS;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Efault:
|
||||||
|
user_access_end();
|
||||||
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,9 +138,6 @@
|
||||||
# define _ASM_EXTABLE_FAULT(from, to) \
|
# define _ASM_EXTABLE_FAULT(from, to) \
|
||||||
_ASM_EXTABLE_HANDLE(from, to, ex_handler_fault)
|
_ASM_EXTABLE_HANDLE(from, to, ex_handler_fault)
|
||||||
|
|
||||||
# define _ASM_EXTABLE_EX(from, to) \
|
|
||||||
_ASM_EXTABLE_HANDLE(from, to, ex_handler_ext)
|
|
||||||
|
|
||||||
# define _ASM_NOKPROBE(entry) \
|
# define _ASM_NOKPROBE(entry) \
|
||||||
.pushsection "_kprobe_blacklist","aw" ; \
|
.pushsection "_kprobe_blacklist","aw" ; \
|
||||||
_ASM_ALIGN ; \
|
_ASM_ALIGN ; \
|
||||||
|
@ -166,9 +163,6 @@
|
||||||
# define _ASM_EXTABLE_FAULT(from, to) \
|
# define _ASM_EXTABLE_FAULT(from, to) \
|
||||||
_ASM_EXTABLE_HANDLE(from, to, ex_handler_fault)
|
_ASM_EXTABLE_HANDLE(from, to, ex_handler_fault)
|
||||||
|
|
||||||
# define _ASM_EXTABLE_EX(from, to) \
|
|
||||||
_ASM_EXTABLE_HANDLE(from, to, ex_handler_ext)
|
|
||||||
|
|
||||||
/* For C file, we already have NOKPROBE_SYMBOL macro */
|
/* For C file, we already have NOKPROBE_SYMBOL macro */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -541,7 +541,6 @@ struct thread_struct {
|
||||||
mm_segment_t addr_limit;
|
mm_segment_t addr_limit;
|
||||||
|
|
||||||
unsigned int sig_on_uaccess_err:1;
|
unsigned int sig_on_uaccess_err:1;
|
||||||
unsigned int uaccess_err:1; /* uaccess failed */
|
|
||||||
|
|
||||||
/* Floating point and extended processor state */
|
/* Floating point and extended processor state */
|
||||||
struct fpu fpu;
|
struct fpu fpu;
|
||||||
|
|
|
@ -33,11 +33,7 @@ struct sigframe_ia32 {
|
||||||
* legacy application accessing/modifying it.
|
* legacy application accessing/modifying it.
|
||||||
*/
|
*/
|
||||||
struct _fpstate_32 fpstate_unused;
|
struct _fpstate_32 fpstate_unused;
|
||||||
#ifdef CONFIG_IA32_EMULATION
|
unsigned int extramask[1];
|
||||||
unsigned int extramask[_COMPAT_NSIG_WORDS-1];
|
|
||||||
#else /* !CONFIG_IA32_EMULATION */
|
|
||||||
unsigned long extramask[_NSIG_WORDS-1];
|
|
||||||
#endif /* CONFIG_IA32_EMULATION */
|
|
||||||
char retcode[8];
|
char retcode[8];
|
||||||
/* fp state follows here */
|
/* fp state follows here */
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,9 +14,6 @@
|
||||||
X86_EFLAGS_CF | X86_EFLAGS_RF)
|
X86_EFLAGS_CF | X86_EFLAGS_RF)
|
||||||
|
|
||||||
void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
|
void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
|
||||||
int setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
|
|
||||||
struct pt_regs *regs, unsigned long mask);
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_X86_X32_ABI
|
#ifdef CONFIG_X86_X32_ABI
|
||||||
asmlinkage long sys32_x32_rt_sigreturn(void);
|
asmlinkage long sys32_x32_rt_sigreturn(void);
|
||||||
|
|
|
@ -193,23 +193,12 @@ __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
|
||||||
: : "A" (x), "r" (addr) \
|
: : "A" (x), "r" (addr) \
|
||||||
: : label)
|
: : label)
|
||||||
|
|
||||||
#define __put_user_asm_ex_u64(x, addr) \
|
|
||||||
asm volatile("\n" \
|
|
||||||
"1: movl %%eax,0(%1)\n" \
|
|
||||||
"2: movl %%edx,4(%1)\n" \
|
|
||||||
"3:" \
|
|
||||||
_ASM_EXTABLE_EX(1b, 2b) \
|
|
||||||
_ASM_EXTABLE_EX(2b, 3b) \
|
|
||||||
: : "A" (x), "r" (addr))
|
|
||||||
|
|
||||||
#define __put_user_x8(x, ptr, __ret_pu) \
|
#define __put_user_x8(x, ptr, __ret_pu) \
|
||||||
asm volatile("call __put_user_8" : "=a" (__ret_pu) \
|
asm volatile("call __put_user_8" : "=a" (__ret_pu) \
|
||||||
: "A" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx")
|
: "A" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx")
|
||||||
#else
|
#else
|
||||||
#define __put_user_goto_u64(x, ptr, label) \
|
#define __put_user_goto_u64(x, ptr, label) \
|
||||||
__put_user_goto(x, ptr, "q", "", "er", label)
|
__put_user_goto(x, ptr, "q", "", "er", label)
|
||||||
#define __put_user_asm_ex_u64(x, addr) \
|
|
||||||
__put_user_asm_ex(x, addr, "q", "", "er")
|
|
||||||
#define __put_user_x8(x, ptr, __ret_pu) __put_user_x(8, x, ptr, __ret_pu)
|
#define __put_user_x8(x, ptr, __ret_pu) __put_user_x(8, x, ptr, __ret_pu)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -289,31 +278,6 @@ do { \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/*
|
|
||||||
* This doesn't do __uaccess_begin/end - the exception handling
|
|
||||||
* around it must do that.
|
|
||||||
*/
|
|
||||||
#define __put_user_size_ex(x, ptr, size) \
|
|
||||||
do { \
|
|
||||||
__chk_user_ptr(ptr); \
|
|
||||||
switch (size) { \
|
|
||||||
case 1: \
|
|
||||||
__put_user_asm_ex(x, ptr, "b", "b", "iq"); \
|
|
||||||
break; \
|
|
||||||
case 2: \
|
|
||||||
__put_user_asm_ex(x, ptr, "w", "w", "ir"); \
|
|
||||||
break; \
|
|
||||||
case 4: \
|
|
||||||
__put_user_asm_ex(x, ptr, "l", "k", "ir"); \
|
|
||||||
break; \
|
|
||||||
case 8: \
|
|
||||||
__put_user_asm_ex_u64((__typeof__(*ptr))(x), ptr); \
|
|
||||||
break; \
|
|
||||||
default: \
|
|
||||||
__put_user_bad(); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
#define __get_user_asm_u64(x, ptr, retval, errret) \
|
#define __get_user_asm_u64(x, ptr, retval, errret) \
|
||||||
({ \
|
({ \
|
||||||
|
@ -335,12 +299,9 @@ do { \
|
||||||
"i" (errret), "0" (retval)); \
|
"i" (errret), "0" (retval)); \
|
||||||
})
|
})
|
||||||
|
|
||||||
#define __get_user_asm_ex_u64(x, ptr) (x) = __get_user_bad()
|
|
||||||
#else
|
#else
|
||||||
#define __get_user_asm_u64(x, ptr, retval, errret) \
|
#define __get_user_asm_u64(x, ptr, retval, errret) \
|
||||||
__get_user_asm(x, ptr, retval, "q", "", "=r", errret)
|
__get_user_asm(x, ptr, retval, "q", "", "=r", errret)
|
||||||
#define __get_user_asm_ex_u64(x, ptr) \
|
|
||||||
__get_user_asm_ex(x, ptr, "q", "", "=r")
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define __get_user_size(x, ptr, size, retval, errret) \
|
#define __get_user_size(x, ptr, size, retval, errret) \
|
||||||
|
@ -378,53 +339,6 @@ do { \
|
||||||
: "=r" (err), ltype(x) \
|
: "=r" (err), ltype(x) \
|
||||||
: "m" (__m(addr)), "i" (errret), "0" (err))
|
: "m" (__m(addr)), "i" (errret), "0" (err))
|
||||||
|
|
||||||
#define __get_user_asm_nozero(x, addr, err, itype, rtype, ltype, errret) \
|
|
||||||
asm volatile("\n" \
|
|
||||||
"1: mov"itype" %2,%"rtype"1\n" \
|
|
||||||
"2:\n" \
|
|
||||||
".section .fixup,\"ax\"\n" \
|
|
||||||
"3: mov %3,%0\n" \
|
|
||||||
" jmp 2b\n" \
|
|
||||||
".previous\n" \
|
|
||||||
_ASM_EXTABLE_UA(1b, 3b) \
|
|
||||||
: "=r" (err), ltype(x) \
|
|
||||||
: "m" (__m(addr)), "i" (errret), "0" (err))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This doesn't do __uaccess_begin/end - the exception handling
|
|
||||||
* around it must do that.
|
|
||||||
*/
|
|
||||||
#define __get_user_size_ex(x, ptr, size) \
|
|
||||||
do { \
|
|
||||||
__chk_user_ptr(ptr); \
|
|
||||||
switch (size) { \
|
|
||||||
case 1: \
|
|
||||||
__get_user_asm_ex(x, ptr, "b", "b", "=q"); \
|
|
||||||
break; \
|
|
||||||
case 2: \
|
|
||||||
__get_user_asm_ex(x, ptr, "w", "w", "=r"); \
|
|
||||||
break; \
|
|
||||||
case 4: \
|
|
||||||
__get_user_asm_ex(x, ptr, "l", "k", "=r"); \
|
|
||||||
break; \
|
|
||||||
case 8: \
|
|
||||||
__get_user_asm_ex_u64(x, ptr); \
|
|
||||||
break; \
|
|
||||||
default: \
|
|
||||||
(x) = __get_user_bad(); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define __get_user_asm_ex(x, addr, itype, rtype, ltype) \
|
|
||||||
asm volatile("1: mov"itype" %1,%"rtype"0\n" \
|
|
||||||
"2:\n" \
|
|
||||||
".section .fixup,\"ax\"\n" \
|
|
||||||
"3:xor"itype" %"rtype"0,%"rtype"0\n" \
|
|
||||||
" jmp 2b\n" \
|
|
||||||
".previous\n" \
|
|
||||||
_ASM_EXTABLE_EX(1b, 3b) \
|
|
||||||
: ltype(x) : "m" (__m(addr)))
|
|
||||||
|
|
||||||
#define __put_user_nocheck(x, ptr, size) \
|
#define __put_user_nocheck(x, ptr, size) \
|
||||||
({ \
|
({ \
|
||||||
__label__ __pu_label; \
|
__label__ __pu_label; \
|
||||||
|
@ -480,29 +394,6 @@ struct __large_struct { unsigned long buf[100]; };
|
||||||
retval = __put_user_failed(x, addr, itype, rtype, ltype, errret); \
|
retval = __put_user_failed(x, addr, itype, rtype, ltype, errret); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define __put_user_asm_ex(x, addr, itype, rtype, ltype) \
|
|
||||||
asm volatile("1: mov"itype" %"rtype"0,%1\n" \
|
|
||||||
"2:\n" \
|
|
||||||
_ASM_EXTABLE_EX(1b, 2b) \
|
|
||||||
: : ltype(x), "m" (__m(addr)))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* uaccess_try and catch
|
|
||||||
*/
|
|
||||||
#define uaccess_try do { \
|
|
||||||
current->thread.uaccess_err = 0; \
|
|
||||||
__uaccess_begin(); \
|
|
||||||
barrier();
|
|
||||||
|
|
||||||
#define uaccess_try_nospec do { \
|
|
||||||
current->thread.uaccess_err = 0; \
|
|
||||||
__uaccess_begin_nospec(); \
|
|
||||||
|
|
||||||
#define uaccess_catch(err) \
|
|
||||||
__uaccess_end(); \
|
|
||||||
(err) |= (current->thread.uaccess_err ? -EFAULT : 0); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* __get_user - Get a simple variable from user space, with less checking.
|
* __get_user - Get a simple variable from user space, with less checking.
|
||||||
* @x: Variable to store result.
|
* @x: Variable to store result.
|
||||||
|
@ -552,28 +443,6 @@ struct __large_struct { unsigned long buf[100]; };
|
||||||
#define __put_user(x, ptr) \
|
#define __put_user(x, ptr) \
|
||||||
__put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
|
__put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
|
||||||
|
|
||||||
/*
|
|
||||||
* {get|put}_user_try and catch
|
|
||||||
*
|
|
||||||
* get_user_try {
|
|
||||||
* get_user_ex(...);
|
|
||||||
* } get_user_catch(err)
|
|
||||||
*/
|
|
||||||
#define get_user_try uaccess_try_nospec
|
|
||||||
#define get_user_catch(err) uaccess_catch(err)
|
|
||||||
|
|
||||||
#define get_user_ex(x, ptr) do { \
|
|
||||||
unsigned long __gue_val; \
|
|
||||||
__get_user_size_ex((__gue_val), (ptr), (sizeof(*(ptr)))); \
|
|
||||||
(x) = (__force __typeof__(*(ptr)))__gue_val; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define put_user_try uaccess_try
|
|
||||||
#define put_user_catch(err) uaccess_catch(err)
|
|
||||||
|
|
||||||
#define put_user_ex(x, ptr) \
|
|
||||||
__put_user_size_ex((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
|
|
||||||
|
|
||||||
extern unsigned long
|
extern unsigned long
|
||||||
copy_from_user_nmi(void *to, const void __user *from, unsigned long n);
|
copy_from_user_nmi(void *to, const void __user *from, unsigned long n);
|
||||||
extern __must_check long
|
extern __must_check long
|
||||||
|
@ -694,15 +563,6 @@ extern struct movsl_mask {
|
||||||
# include <asm/uaccess_64.h>
|
# include <asm/uaccess_64.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* We rely on the nested NMI work to allow atomic faults from the NMI path; the
|
|
||||||
* nested NMI paths are careful to preserve CR2.
|
|
||||||
*
|
|
||||||
* Caller must use pagefault_enable/disable, or run in interrupt context,
|
|
||||||
* and also do a uaccess_ok() check
|
|
||||||
*/
|
|
||||||
#define __copy_from_user_nmi __copy_from_user_inatomic
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The "unsafe" user accesses aren't really "unsafe", but the naming
|
* The "unsafe" user accesses aren't really "unsafe", but the naming
|
||||||
* is a big fat warning: you have to not only do the access_ok()
|
* is a big fat warning: you have to not only do the access_ok()
|
||||||
|
|
|
@ -23,33 +23,6 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n)
|
||||||
static __always_inline unsigned long
|
static __always_inline unsigned long
|
||||||
raw_copy_from_user(void *to, const void __user *from, unsigned long n)
|
raw_copy_from_user(void *to, const void __user *from, unsigned long n)
|
||||||
{
|
{
|
||||||
if (__builtin_constant_p(n)) {
|
|
||||||
unsigned long ret;
|
|
||||||
|
|
||||||
switch (n) {
|
|
||||||
case 1:
|
|
||||||
ret = 0;
|
|
||||||
__uaccess_begin_nospec();
|
|
||||||
__get_user_asm_nozero(*(u8 *)to, from, ret,
|
|
||||||
"b", "b", "=q", 1);
|
|
||||||
__uaccess_end();
|
|
||||||
return ret;
|
|
||||||
case 2:
|
|
||||||
ret = 0;
|
|
||||||
__uaccess_begin_nospec();
|
|
||||||
__get_user_asm_nozero(*(u16 *)to, from, ret,
|
|
||||||
"w", "w", "=r", 2);
|
|
||||||
__uaccess_end();
|
|
||||||
return ret;
|
|
||||||
case 4:
|
|
||||||
ret = 0;
|
|
||||||
__uaccess_begin_nospec();
|
|
||||||
__get_user_asm_nozero(*(u32 *)to, from, ret,
|
|
||||||
"l", "k", "=r", 4);
|
|
||||||
__uaccess_end();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return __copy_user_ll(to, (__force const void *)from, n);
|
return __copy_user_ll(to, (__force const void *)from, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,117 +65,13 @@ copy_to_user_mcsafe(void *to, const void *from, unsigned len)
|
||||||
static __always_inline __must_check unsigned long
|
static __always_inline __must_check unsigned long
|
||||||
raw_copy_from_user(void *dst, const void __user *src, unsigned long size)
|
raw_copy_from_user(void *dst, const void __user *src, unsigned long size)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
return copy_user_generic(dst, (__force void *)src, size);
|
||||||
|
|
||||||
if (!__builtin_constant_p(size))
|
|
||||||
return copy_user_generic(dst, (__force void *)src, size);
|
|
||||||
switch (size) {
|
|
||||||
case 1:
|
|
||||||
__uaccess_begin_nospec();
|
|
||||||
__get_user_asm_nozero(*(u8 *)dst, (u8 __user *)src,
|
|
||||||
ret, "b", "b", "=q", 1);
|
|
||||||
__uaccess_end();
|
|
||||||
return ret;
|
|
||||||
case 2:
|
|
||||||
__uaccess_begin_nospec();
|
|
||||||
__get_user_asm_nozero(*(u16 *)dst, (u16 __user *)src,
|
|
||||||
ret, "w", "w", "=r", 2);
|
|
||||||
__uaccess_end();
|
|
||||||
return ret;
|
|
||||||
case 4:
|
|
||||||
__uaccess_begin_nospec();
|
|
||||||
__get_user_asm_nozero(*(u32 *)dst, (u32 __user *)src,
|
|
||||||
ret, "l", "k", "=r", 4);
|
|
||||||
__uaccess_end();
|
|
||||||
return ret;
|
|
||||||
case 8:
|
|
||||||
__uaccess_begin_nospec();
|
|
||||||
__get_user_asm_nozero(*(u64 *)dst, (u64 __user *)src,
|
|
||||||
ret, "q", "", "=r", 8);
|
|
||||||
__uaccess_end();
|
|
||||||
return ret;
|
|
||||||
case 10:
|
|
||||||
__uaccess_begin_nospec();
|
|
||||||
__get_user_asm_nozero(*(u64 *)dst, (u64 __user *)src,
|
|
||||||
ret, "q", "", "=r", 10);
|
|
||||||
if (likely(!ret))
|
|
||||||
__get_user_asm_nozero(*(u16 *)(8 + (char *)dst),
|
|
||||||
(u16 __user *)(8 + (char __user *)src),
|
|
||||||
ret, "w", "w", "=r", 2);
|
|
||||||
__uaccess_end();
|
|
||||||
return ret;
|
|
||||||
case 16:
|
|
||||||
__uaccess_begin_nospec();
|
|
||||||
__get_user_asm_nozero(*(u64 *)dst, (u64 __user *)src,
|
|
||||||
ret, "q", "", "=r", 16);
|
|
||||||
if (likely(!ret))
|
|
||||||
__get_user_asm_nozero(*(u64 *)(8 + (char *)dst),
|
|
||||||
(u64 __user *)(8 + (char __user *)src),
|
|
||||||
ret, "q", "", "=r", 8);
|
|
||||||
__uaccess_end();
|
|
||||||
return ret;
|
|
||||||
default:
|
|
||||||
return copy_user_generic(dst, (__force void *)src, size);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static __always_inline __must_check unsigned long
|
static __always_inline __must_check unsigned long
|
||||||
raw_copy_to_user(void __user *dst, const void *src, unsigned long size)
|
raw_copy_to_user(void __user *dst, const void *src, unsigned long size)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
return copy_user_generic((__force void *)dst, src, size);
|
||||||
|
|
||||||
if (!__builtin_constant_p(size))
|
|
||||||
return copy_user_generic((__force void *)dst, src, size);
|
|
||||||
switch (size) {
|
|
||||||
case 1:
|
|
||||||
__uaccess_begin();
|
|
||||||
__put_user_asm(*(u8 *)src, (u8 __user *)dst,
|
|
||||||
ret, "b", "b", "iq", 1);
|
|
||||||
__uaccess_end();
|
|
||||||
return ret;
|
|
||||||
case 2:
|
|
||||||
__uaccess_begin();
|
|
||||||
__put_user_asm(*(u16 *)src, (u16 __user *)dst,
|
|
||||||
ret, "w", "w", "ir", 2);
|
|
||||||
__uaccess_end();
|
|
||||||
return ret;
|
|
||||||
case 4:
|
|
||||||
__uaccess_begin();
|
|
||||||
__put_user_asm(*(u32 *)src, (u32 __user *)dst,
|
|
||||||
ret, "l", "k", "ir", 4);
|
|
||||||
__uaccess_end();
|
|
||||||
return ret;
|
|
||||||
case 8:
|
|
||||||
__uaccess_begin();
|
|
||||||
__put_user_asm(*(u64 *)src, (u64 __user *)dst,
|
|
||||||
ret, "q", "", "er", 8);
|
|
||||||
__uaccess_end();
|
|
||||||
return ret;
|
|
||||||
case 10:
|
|
||||||
__uaccess_begin();
|
|
||||||
__put_user_asm(*(u64 *)src, (u64 __user *)dst,
|
|
||||||
ret, "q", "", "er", 10);
|
|
||||||
if (likely(!ret)) {
|
|
||||||
asm("":::"memory");
|
|
||||||
__put_user_asm(4[(u16 *)src], 4 + (u16 __user *)dst,
|
|
||||||
ret, "w", "w", "ir", 2);
|
|
||||||
}
|
|
||||||
__uaccess_end();
|
|
||||||
return ret;
|
|
||||||
case 16:
|
|
||||||
__uaccess_begin();
|
|
||||||
__put_user_asm(*(u64 *)src, (u64 __user *)dst,
|
|
||||||
ret, "q", "", "er", 16);
|
|
||||||
if (likely(!ret)) {
|
|
||||||
asm("":::"memory");
|
|
||||||
__put_user_asm(1[(u64 *)src], 1 + (u64 __user *)dst,
|
|
||||||
ret, "q", "", "er", 8);
|
|
||||||
}
|
|
||||||
__uaccess_end();
|
|
||||||
return ret;
|
|
||||||
default:
|
|
||||||
return copy_user_generic((__force void *)dst, src, size);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static __always_inline __must_check
|
static __always_inline __must_check
|
||||||
|
|
|
@ -47,24 +47,6 @@
|
||||||
#include <asm/sigframe.h>
|
#include <asm/sigframe.h>
|
||||||
#include <asm/signal.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
|
#ifdef CONFIG_X86_64
|
||||||
/*
|
/*
|
||||||
* If regs->ss will cause an IRET fault, change it. Otherwise leave it
|
* 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))
|
ar != (AR_DPL3 | AR_S | AR_P | AR_TYPE_RWDATA_EXPDOWN))
|
||||||
regs->ss = __USER_DS;
|
regs->ss = __USER_DS;
|
||||||
}
|
}
|
||||||
|
# define CONTEXT_COPY_SIZE offsetof(struct sigcontext, reserved1)
|
||||||
|
#else
|
||||||
|
# define CONTEXT_COPY_SIZE sizeof(struct sigcontext)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int restore_sigcontext(struct pt_regs *regs,
|
static int restore_sigcontext(struct pt_regs *regs,
|
||||||
struct sigcontext __user *sc,
|
struct sigcontext __user *usc,
|
||||||
unsigned long uc_flags)
|
unsigned long uc_flags)
|
||||||
{
|
{
|
||||||
unsigned long buf_val;
|
struct sigcontext sc;
|
||||||
void __user *buf;
|
|
||||||
unsigned int tmpflags;
|
|
||||||
unsigned int err = 0;
|
|
||||||
|
|
||||||
/* Always make any pending restarted system calls return -EINTR */
|
/* Always make any pending restarted system calls return -EINTR */
|
||||||
current->restart_block.fn = do_no_restart_syscall;
|
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
|
#ifdef CONFIG_X86_32
|
||||||
set_user_gs(regs, GET_SEG(gs));
|
set_user_gs(regs, sc.gs);
|
||||||
COPY_SEG(fs);
|
regs->fs = sc.fs;
|
||||||
COPY_SEG(es);
|
regs->es = sc.es;
|
||||||
COPY_SEG(ds);
|
regs->ds = sc.ds;
|
||||||
#endif /* CONFIG_X86_32 */
|
#endif /* CONFIG_X86_32 */
|
||||||
|
|
||||||
COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
|
regs->bx = sc.bx;
|
||||||
COPY(dx); COPY(cx); COPY(ip); COPY(ax);
|
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
|
#ifdef CONFIG_X86_64
|
||||||
COPY(r8);
|
regs->r8 = sc.r8;
|
||||||
COPY(r9);
|
regs->r9 = sc.r9;
|
||||||
COPY(r10);
|
regs->r10 = sc.r10;
|
||||||
COPY(r11);
|
regs->r11 = sc.r11;
|
||||||
COPY(r12);
|
regs->r12 = sc.r12;
|
||||||
COPY(r13);
|
regs->r13 = sc.r13;
|
||||||
COPY(r14);
|
regs->r14 = sc.r14;
|
||||||
COPY(r15);
|
regs->r15 = sc.r15;
|
||||||
#endif /* CONFIG_X86_64 */
|
#endif /* CONFIG_X86_64 */
|
||||||
|
|
||||||
COPY_SEG_CPL3(cs);
|
/* Get CS/SS and force CPL3 */
|
||||||
COPY_SEG_CPL3(ss);
|
regs->cs = sc.cs | 0x03;
|
||||||
|
regs->ss = sc.ss | 0x03;
|
||||||
|
|
||||||
get_user_ex(tmpflags, &sc->flags);
|
regs->flags = (regs->flags & ~FIX_EFLAGS) | (sc.flags & FIX_EFLAGS);
|
||||||
regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
|
/* disable syscall checks */
|
||||||
regs->orig_ax = -1; /* disable syscall checks */
|
regs->orig_ax = -1;
|
||||||
|
|
||||||
get_user_ex(buf_val, &sc->fpstate);
|
|
||||||
buf = (void __user *)buf_val;
|
|
||||||
} get_user_catch(err);
|
|
||||||
|
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
/*
|
/*
|
||||||
|
@ -149,70 +136,78 @@ static int restore_sigcontext(struct pt_regs *regs,
|
||||||
force_valid_ss(regs);
|
force_valid_ss(regs);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
err |= fpu__restore_sig(buf, IS_ENABLED(CONFIG_X86_32));
|
return fpu__restore_sig((void __user *)sc.fpstate,
|
||||||
|
IS_ENABLED(CONFIG_X86_32));
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
struct pt_regs *regs, unsigned long mask)
|
||||||
{
|
{
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
put_user_try {
|
|
||||||
|
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
put_user_ex(get_user_gs(regs), (unsigned int __user *)&sc->gs);
|
unsafe_put_user(get_user_gs(regs),
|
||||||
put_user_ex(regs->fs, (unsigned int __user *)&sc->fs);
|
(unsigned int __user *)&sc->gs, Efault);
|
||||||
put_user_ex(regs->es, (unsigned int __user *)&sc->es);
|
unsafe_put_user(regs->fs, (unsigned int __user *)&sc->fs, Efault);
|
||||||
put_user_ex(regs->ds, (unsigned int __user *)&sc->ds);
|
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 */
|
#endif /* CONFIG_X86_32 */
|
||||||
|
|
||||||
put_user_ex(regs->di, &sc->di);
|
unsafe_put_user(regs->di, &sc->di, Efault);
|
||||||
put_user_ex(regs->si, &sc->si);
|
unsafe_put_user(regs->si, &sc->si, Efault);
|
||||||
put_user_ex(regs->bp, &sc->bp);
|
unsafe_put_user(regs->bp, &sc->bp, Efault);
|
||||||
put_user_ex(regs->sp, &sc->sp);
|
unsafe_put_user(regs->sp, &sc->sp, Efault);
|
||||||
put_user_ex(regs->bx, &sc->bx);
|
unsafe_put_user(regs->bx, &sc->bx, Efault);
|
||||||
put_user_ex(regs->dx, &sc->dx);
|
unsafe_put_user(regs->dx, &sc->dx, Efault);
|
||||||
put_user_ex(regs->cx, &sc->cx);
|
unsafe_put_user(regs->cx, &sc->cx, Efault);
|
||||||
put_user_ex(regs->ax, &sc->ax);
|
unsafe_put_user(regs->ax, &sc->ax, Efault);
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
put_user_ex(regs->r8, &sc->r8);
|
unsafe_put_user(regs->r8, &sc->r8, Efault);
|
||||||
put_user_ex(regs->r9, &sc->r9);
|
unsafe_put_user(regs->r9, &sc->r9, Efault);
|
||||||
put_user_ex(regs->r10, &sc->r10);
|
unsafe_put_user(regs->r10, &sc->r10, Efault);
|
||||||
put_user_ex(regs->r11, &sc->r11);
|
unsafe_put_user(regs->r11, &sc->r11, Efault);
|
||||||
put_user_ex(regs->r12, &sc->r12);
|
unsafe_put_user(regs->r12, &sc->r12, Efault);
|
||||||
put_user_ex(regs->r13, &sc->r13);
|
unsafe_put_user(regs->r13, &sc->r13, Efault);
|
||||||
put_user_ex(regs->r14, &sc->r14);
|
unsafe_put_user(regs->r14, &sc->r14, Efault);
|
||||||
put_user_ex(regs->r15, &sc->r15);
|
unsafe_put_user(regs->r15, &sc->r15, Efault);
|
||||||
#endif /* CONFIG_X86_64 */
|
#endif /* CONFIG_X86_64 */
|
||||||
|
|
||||||
put_user_ex(current->thread.trap_nr, &sc->trapno);
|
unsafe_put_user(current->thread.trap_nr, &sc->trapno, Efault);
|
||||||
put_user_ex(current->thread.error_code, &sc->err);
|
unsafe_put_user(current->thread.error_code, &sc->err, Efault);
|
||||||
put_user_ex(regs->ip, &sc->ip);
|
unsafe_put_user(regs->ip, &sc->ip, Efault);
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
|
unsafe_put_user(regs->cs, (unsigned int __user *)&sc->cs, Efault);
|
||||||
put_user_ex(regs->flags, &sc->flags);
|
unsafe_put_user(regs->flags, &sc->flags, Efault);
|
||||||
put_user_ex(regs->sp, &sc->sp_at_signal);
|
unsafe_put_user(regs->sp, &sc->sp_at_signal, Efault);
|
||||||
put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);
|
unsafe_put_user(regs->ss, (unsigned int __user *)&sc->ss, Efault);
|
||||||
#else /* !CONFIG_X86_32 */
|
#else /* !CONFIG_X86_32 */
|
||||||
put_user_ex(regs->flags, &sc->flags);
|
unsafe_put_user(regs->flags, &sc->flags, Efault);
|
||||||
put_user_ex(regs->cs, &sc->cs);
|
unsafe_put_user(regs->cs, &sc->cs, Efault);
|
||||||
put_user_ex(0, &sc->gs);
|
unsafe_put_user(0, &sc->gs, Efault);
|
||||||
put_user_ex(0, &sc->fs);
|
unsafe_put_user(0, &sc->fs, Efault);
|
||||||
put_user_ex(regs->ss, &sc->ss);
|
unsafe_put_user(regs->ss, &sc->ss, Efault);
|
||||||
#endif /* CONFIG_X86_32 */
|
#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.. */
|
/* non-iBCS2 extensions.. */
|
||||||
put_user_ex(mask, &sc->oldmask);
|
unsafe_put_user(mask, &sc->oldmask, Efault);
|
||||||
put_user_ex(current->thread.cr2, &sc->cr2);
|
unsafe_put_user(current->thread.cr2, &sc->cr2, Efault);
|
||||||
} put_user_catch(err);
|
return 0;
|
||||||
|
Efault:
|
||||||
return err;
|
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.
|
* Set up a signal frame.
|
||||||
*/
|
*/
|
||||||
|
@ -312,26 +307,16 @@ __setup_frame(int sig, struct ksignal *ksig, sigset_t *set,
|
||||||
{
|
{
|
||||||
struct sigframe __user *frame;
|
struct sigframe __user *frame;
|
||||||
void __user *restorer;
|
void __user *restorer;
|
||||||
int err = 0;
|
void __user *fp = NULL;
|
||||||
void __user *fpstate = 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;
|
return -EFAULT;
|
||||||
|
|
||||||
if (__put_user(sig, &frame->sig))
|
unsafe_put_user(sig, &frame->sig, Efault);
|
||||||
return -EFAULT;
|
unsafe_put_sigcontext(&frame->sc, fp, regs, set, Efault);
|
||||||
|
unsafe_put_user(set->sig[1], &frame->extramask[0], 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (current->mm->context.vdso)
|
if (current->mm->context.vdso)
|
||||||
restorer = current->mm->context.vdso +
|
restorer = current->mm->context.vdso +
|
||||||
vdso_image_32.sym___kernel_sigreturn;
|
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;
|
restorer = ksig->ka.sa.sa_restorer;
|
||||||
|
|
||||||
/* Set up to return from userspace. */
|
/* 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
|
* 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
|
* reasons and because gdb uses it as a signature to notice
|
||||||
* signal handler stack frames.
|
* signal handler stack frames.
|
||||||
*/
|
*/
|
||||||
err |= __put_user(*((u64 *)&retcode), (u64 *)frame->retcode);
|
unsafe_put_user(*((u64 *)&retcode), (u64 *)frame->retcode, Efault);
|
||||||
|
user_access_end();
|
||||||
if (err)
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
/* Set up registers for signal handler */
|
/* Set up registers for signal handler */
|
||||||
regs->sp = (unsigned long)frame;
|
regs->sp = (unsigned long)frame;
|
||||||
|
@ -368,6 +351,10 @@ __setup_frame(int sig, struct ksignal *ksig, sigset_t *set,
|
||||||
regs->cs = __USER_CS;
|
regs->cs = __USER_CS;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
Efault:
|
||||||
|
user_access_end();
|
||||||
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __setup_rt_frame(int sig, struct ksignal *ksig,
|
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;
|
struct rt_sigframe __user *frame;
|
||||||
void __user *restorer;
|
void __user *restorer;
|
||||||
int err = 0;
|
void __user *fp = NULL;
|
||||||
void __user *fpstate = 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;
|
return -EFAULT;
|
||||||
|
|
||||||
put_user_try {
|
unsafe_put_user(sig, &frame->sig, Efault);
|
||||||
put_user_ex(sig, &frame->sig);
|
unsafe_put_user(&frame->info, &frame->pinfo, Efault);
|
||||||
put_user_ex(&frame->info, &frame->pinfo);
|
unsafe_put_user(&frame->uc, &frame->puc, Efault);
|
||||||
put_user_ex(&frame->uc, &frame->puc);
|
|
||||||
|
|
||||||
/* Create the ucontext. */
|
/* Create the ucontext. */
|
||||||
if (static_cpu_has(X86_FEATURE_XSAVE))
|
if (static_cpu_has(X86_FEATURE_XSAVE))
|
||||||
put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
|
unsafe_put_user(UC_FP_XSTATE, &frame->uc.uc_flags, Efault);
|
||||||
else
|
else
|
||||||
put_user_ex(0, &frame->uc.uc_flags);
|
unsafe_put_user(0, &frame->uc.uc_flags, Efault);
|
||||||
put_user_ex(0, &frame->uc.uc_link);
|
unsafe_put_user(0, &frame->uc.uc_link, Efault);
|
||||||
save_altstack_ex(&frame->uc.uc_stack, regs->sp);
|
unsafe_save_altstack(&frame->uc.uc_stack, regs->sp, Efault);
|
||||||
|
|
||||||
/* Set up to return from userspace. */
|
/* Set up to return from userspace. */
|
||||||
restorer = current->mm->context.vdso +
|
restorer = current->mm->context.vdso +
|
||||||
vdso_image_32.sym___kernel_rt_sigreturn;
|
vdso_image_32.sym___kernel_rt_sigreturn;
|
||||||
if (ksig->ka.sa.sa_flags & SA_RESTORER)
|
if (ksig->ka.sa.sa_flags & SA_RESTORER)
|
||||||
restorer = ksig->ka.sa.sa_restorer;
|
restorer = ksig->ka.sa.sa_restorer;
|
||||||
put_user_ex(restorer, &frame->pretcode);
|
unsafe_put_user(restorer, &frame->pretcode, Efault);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is movl $__NR_rt_sigreturn, %ax ; int $0x80
|
* This is movl $__NR_rt_sigreturn, %ax ; int $0x80
|
||||||
*
|
*
|
||||||
* WE DO NOT USE IT ANY MORE! It's only left here for historical
|
* 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
|
* reasons and because gdb uses it as a signature to notice
|
||||||
* signal handler stack frames.
|
* signal handler stack frames.
|
||||||
*/
|
*/
|
||||||
put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode);
|
unsafe_put_user(*((u64 *)&rt_retcode), (u64 *)frame->retcode, Efault);
|
||||||
} put_user_catch(err);
|
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);
|
if (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)
|
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
/* Set up registers for signal handler */
|
/* Set up registers for signal handler */
|
||||||
|
@ -434,6 +416,9 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig,
|
||||||
regs->cs = __USER_CS;
|
regs->cs = __USER_CS;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Efault:
|
||||||
|
user_access_end();
|
||||||
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
#else /* !CONFIG_X86_32 */
|
#else /* !CONFIG_X86_32 */
|
||||||
static unsigned long frame_uc_flags(struct pt_regs *regs)
|
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;
|
struct rt_sigframe __user *frame;
|
||||||
void __user *fp = NULL;
|
void __user *fp = NULL;
|
||||||
unsigned long uc_flags;
|
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);
|
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;
|
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 (ksig->ka.sa.sa_flags & SA_SIGINFO) {
|
||||||
if (copy_siginfo_to_user(&frame->info, &ksig->info))
|
if (copy_siginfo_to_user(&frame->info, &ksig->info))
|
||||||
return -EFAULT;
|
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 */
|
/* Set up registers for signal handler */
|
||||||
regs->di = sig;
|
regs->di = sig;
|
||||||
/* In case the signal handler was declared without prototypes */
|
/* 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);
|
force_valid_ss(regs);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
Efault:
|
||||||
|
user_access_end();
|
||||||
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_X86_32 */
|
#endif /* CONFIG_X86_32 */
|
||||||
|
|
||||||
|
@ -541,45 +521,34 @@ static int x32_setup_rt_frame(struct ksignal *ksig,
|
||||||
struct rt_sigframe_x32 __user *frame;
|
struct rt_sigframe_x32 __user *frame;
|
||||||
unsigned long uc_flags;
|
unsigned long uc_flags;
|
||||||
void __user *restorer;
|
void __user *restorer;
|
||||||
int err = 0;
|
void __user *fp = NULL;
|
||||||
void __user *fpstate = NULL;
|
|
||||||
|
|
||||||
frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fpstate);
|
if (!(ksig->ka.sa.sa_flags & SA_RESTORER))
|
||||||
|
|
||||||
if (!access_ok(frame, sizeof(*frame)))
|
|
||||||
return -EFAULT;
|
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 (ksig->ka.sa.sa_flags & SA_SIGINFO) {
|
||||||
if (__copy_siginfo_to_user32(&frame->info, &ksig->info, true))
|
if (__copy_siginfo_to_user32(&frame->info, &ksig->info, true))
|
||||||
return -EFAULT;
|
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 */
|
/* Set up registers for signal handler */
|
||||||
regs->sp = (unsigned long) frame;
|
regs->sp = (unsigned long) frame;
|
||||||
regs->ip = (unsigned long) ksig->ka.sa.sa_handler;
|
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 */
|
#endif /* CONFIG_X86_X32_ABI */
|
||||||
|
|
||||||
return 0;
|
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)))
|
if (!access_ok(frame, sizeof(*frame)))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
if (__get_user(set.sig[0], &frame->sc.oldmask) || (_NSIG_WORDS > 1
|
if (__get_user(set.sig[0], &frame->sc.oldmask) ||
|
||||||
&& __copy_from_user(&set.sig[1], &frame->extramask,
|
__get_user(set.sig[1], &frame->extramask[0]))
|
||||||
sizeof(frame->extramask))))
|
|
||||||
goto badframe;
|
goto badframe;
|
||||||
|
|
||||||
set_current_blocked(&set);
|
set_current_blocked(&set);
|
||||||
|
@ -645,7 +618,7 @@ SYSCALL_DEFINE0(rt_sigreturn)
|
||||||
frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long));
|
frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long));
|
||||||
if (!access_ok(frame, sizeof(*frame)))
|
if (!access_ok(frame, sizeof(*frame)))
|
||||||
goto badframe;
|
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;
|
goto badframe;
|
||||||
if (__get_user(uc_flags, &frame->uc.uc_flags))
|
if (__get_user(uc_flags, &frame->uc.uc_flags))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
|
@ -870,7 +843,7 @@ asmlinkage long sys32_x32_rt_sigreturn(void)
|
||||||
|
|
||||||
if (!access_ok(frame, sizeof(*frame)))
|
if (!access_ok(frame, sizeof(*frame)))
|
||||||
goto badframe;
|
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;
|
goto badframe;
|
||||||
if (__get_user(uc_flags, &frame->uc.uc_flags))
|
if (__get_user(uc_flags, &frame->uc.uc_flags))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
|
|
|
@ -96,7 +96,8 @@ struct stack_frame_user {
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
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;
|
int ret;
|
||||||
|
|
||||||
|
@ -105,7 +106,8 @@ copy_stack_frame(const void __user *fp, struct stack_frame_user *frame)
|
||||||
|
|
||||||
ret = 1;
|
ret = 1;
|
||||||
pagefault_disable();
|
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;
|
ret = 0;
|
||||||
pagefault_enable();
|
pagefault_enable();
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,6 @@ void save_v86_state(struct kernel_vm86_regs *regs, int retval)
|
||||||
struct task_struct *tsk = current;
|
struct task_struct *tsk = current;
|
||||||
struct vm86plus_struct __user *user;
|
struct vm86plus_struct __user *user;
|
||||||
struct vm86 *vm86 = current->thread.vm86;
|
struct vm86 *vm86 = current->thread.vm86;
|
||||||
long err = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This gets called from entry.S with interrupts disabled, but
|
* 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);
|
set_flags(regs->pt.flags, VEFLAGS, X86_EFLAGS_VIF | vm86->veflags_mask);
|
||||||
user = vm86->user_vm86;
|
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 vm86plus_struct) :
|
||||||
sizeof(struct vm86_struct))) {
|
sizeof(struct vm86_struct)))
|
||||||
pr_alert("could not access userspace vm86 info\n");
|
goto Efault;
|
||||||
do_exit(SIGSEGV);
|
|
||||||
}
|
|
||||||
|
|
||||||
put_user_try {
|
unsafe_put_user(regs->pt.bx, &user->regs.ebx, Efault_end);
|
||||||
put_user_ex(regs->pt.bx, &user->regs.ebx);
|
unsafe_put_user(regs->pt.cx, &user->regs.ecx, Efault_end);
|
||||||
put_user_ex(regs->pt.cx, &user->regs.ecx);
|
unsafe_put_user(regs->pt.dx, &user->regs.edx, Efault_end);
|
||||||
put_user_ex(regs->pt.dx, &user->regs.edx);
|
unsafe_put_user(regs->pt.si, &user->regs.esi, Efault_end);
|
||||||
put_user_ex(regs->pt.si, &user->regs.esi);
|
unsafe_put_user(regs->pt.di, &user->regs.edi, Efault_end);
|
||||||
put_user_ex(regs->pt.di, &user->regs.edi);
|
unsafe_put_user(regs->pt.bp, &user->regs.ebp, Efault_end);
|
||||||
put_user_ex(regs->pt.bp, &user->regs.ebp);
|
unsafe_put_user(regs->pt.ax, &user->regs.eax, Efault_end);
|
||||||
put_user_ex(regs->pt.ax, &user->regs.eax);
|
unsafe_put_user(regs->pt.ip, &user->regs.eip, Efault_end);
|
||||||
put_user_ex(regs->pt.ip, &user->regs.eip);
|
unsafe_put_user(regs->pt.cs, &user->regs.cs, Efault_end);
|
||||||
put_user_ex(regs->pt.cs, &user->regs.cs);
|
unsafe_put_user(regs->pt.flags, &user->regs.eflags, Efault_end);
|
||||||
put_user_ex(regs->pt.flags, &user->regs.eflags);
|
unsafe_put_user(regs->pt.sp, &user->regs.esp, Efault_end);
|
||||||
put_user_ex(regs->pt.sp, &user->regs.esp);
|
unsafe_put_user(regs->pt.ss, &user->regs.ss, Efault_end);
|
||||||
put_user_ex(regs->pt.ss, &user->regs.ss);
|
unsafe_put_user(regs->es, &user->regs.es, Efault_end);
|
||||||
put_user_ex(regs->es, &user->regs.es);
|
unsafe_put_user(regs->ds, &user->regs.ds, Efault_end);
|
||||||
put_user_ex(regs->ds, &user->regs.ds);
|
unsafe_put_user(regs->fs, &user->regs.fs, Efault_end);
|
||||||
put_user_ex(regs->fs, &user->regs.fs);
|
unsafe_put_user(regs->gs, &user->regs.gs, Efault_end);
|
||||||
put_user_ex(regs->gs, &user->regs.gs);
|
unsafe_put_user(vm86->screen_bitmap, &user->screen_bitmap, Efault_end);
|
||||||
|
|
||||||
put_user_ex(vm86->screen_bitmap, &user->screen_bitmap);
|
user_access_end();
|
||||||
} put_user_catch(err);
|
|
||||||
if (err) {
|
|
||||||
pr_alert("could not access userspace vm86 info\n");
|
|
||||||
do_exit(SIGSEGV);
|
|
||||||
}
|
|
||||||
|
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
tsk->thread.sp0 = vm86->saved_sp0;
|
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);
|
lazy_load_gs(vm86->regs32.gs);
|
||||||
|
|
||||||
regs->pt.ax = retval;
|
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)
|
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 kernel_vm86_regs vm86regs;
|
||||||
struct pt_regs *regs = current_pt_regs();
|
struct pt_regs *regs = current_pt_regs();
|
||||||
unsigned long err = 0;
|
unsigned long err = 0;
|
||||||
|
struct vm86_struct v;
|
||||||
|
|
||||||
err = security_mmap_addr(0);
|
err = security_mmap_addr(0);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -278,39 +278,32 @@ static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus)
|
||||||
if (vm86->saved_sp0)
|
if (vm86->saved_sp0)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
if (!access_ok(user_vm86, plus ?
|
if (copy_from_user(&v, user_vm86,
|
||||||
sizeof(struct vm86_struct) :
|
offsetof(struct vm86_struct, int_revectored)))
|
||||||
sizeof(struct vm86plus_struct)))
|
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
memset(&vm86regs, 0, sizeof(vm86regs));
|
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);
|
vm86regs.pt.bx = v.regs.ebx;
|
||||||
get_user_ex(vm86->screen_bitmap, &user_vm86->screen_bitmap);
|
vm86regs.pt.cx = v.regs.ecx;
|
||||||
get_user_ex(vm86->cpu_type, &user_vm86->cpu_type);
|
vm86regs.pt.dx = v.regs.edx;
|
||||||
} get_user_catch(err);
|
vm86regs.pt.si = v.regs.esi;
|
||||||
if (err)
|
vm86regs.pt.di = v.regs.edi;
|
||||||
return err;
|
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,
|
if (copy_from_user(&vm86->int_revectored,
|
||||||
&user_vm86->int_revectored,
|
&user_vm86->int_revectored,
|
||||||
|
|
|
@ -400,7 +400,7 @@ retry_walk:
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
ptep_user = (pt_element_t __user *)((void *)host_addr + offset);
|
ptep_user = (pt_element_t __user *)((void *)host_addr + offset);
|
||||||
if (unlikely(__copy_from_user(&pte, ptep_user, sizeof(pte))))
|
if (unlikely(__get_user(pte, ptep_user)))
|
||||||
goto error;
|
goto error;
|
||||||
walker->ptep_user[walker->level - 1] = ptep_user;
|
walker->ptep_user[walker->level - 1] = ptep_user;
|
||||||
|
|
||||||
|
|
|
@ -80,18 +80,6 @@ __visible bool ex_handler_uaccess(const struct exception_table_entry *fixup,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ex_handler_uaccess);
|
EXPORT_SYMBOL(ex_handler_uaccess);
|
||||||
|
|
||||||
__visible bool ex_handler_ext(const struct exception_table_entry *fixup,
|
|
||||||
struct pt_regs *regs, int trapnr,
|
|
||||||
unsigned long error_code,
|
|
||||||
unsigned long fault_addr)
|
|
||||||
{
|
|
||||||
/* Special hack for uaccess_err */
|
|
||||||
current->thread.uaccess_err = 1;
|
|
||||||
regs->ip = ex_fixup_addr(fixup);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(ex_handler_ext);
|
|
||||||
|
|
||||||
__visible bool ex_handler_rdmsr_unsafe(const struct exception_table_entry *fixup,
|
__visible bool ex_handler_rdmsr_unsafe(const struct exception_table_entry *fixup,
|
||||||
struct pt_regs *regs, int trapnr,
|
struct pt_regs *regs, int trapnr,
|
||||||
unsigned long error_code,
|
unsigned long error_code,
|
||||||
|
|
|
@ -483,12 +483,13 @@ extern void __user *compat_alloc_user_space(unsigned long len);
|
||||||
|
|
||||||
int compat_restore_altstack(const compat_stack_t __user *uss);
|
int compat_restore_altstack(const compat_stack_t __user *uss);
|
||||||
int __compat_save_altstack(compat_stack_t __user *, unsigned long);
|
int __compat_save_altstack(compat_stack_t __user *, unsigned long);
|
||||||
#define compat_save_altstack_ex(uss, sp) do { \
|
#define unsafe_compat_save_altstack(uss, sp, label) do { \
|
||||||
compat_stack_t __user *__uss = uss; \
|
compat_stack_t __user *__uss = uss; \
|
||||||
struct task_struct *t = current; \
|
struct task_struct *t = current; \
|
||||||
put_user_ex(ptr_to_compat((void __user *)t->sas_ss_sp), &__uss->ss_sp); \
|
unsafe_put_user(ptr_to_compat((void __user *)t->sas_ss_sp), \
|
||||||
put_user_ex(t->sas_ss_flags, &__uss->ss_flags); \
|
&__uss->ss_sp, label); \
|
||||||
put_user_ex(t->sas_ss_size, &__uss->ss_size); \
|
unsafe_put_user(t->sas_ss_flags, &__uss->ss_flags, label); \
|
||||||
|
unsafe_put_user(t->sas_ss_size, &__uss->ss_size, label); \
|
||||||
if (t->sas_ss_flags & SS_AUTODISARM) \
|
if (t->sas_ss_flags & SS_AUTODISARM) \
|
||||||
sas_ss_reset(t); \
|
sas_ss_reset(t); \
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
|
@ -444,12 +444,12 @@ void signals_init(void);
|
||||||
int restore_altstack(const stack_t __user *);
|
int restore_altstack(const stack_t __user *);
|
||||||
int __save_altstack(stack_t __user *, unsigned long);
|
int __save_altstack(stack_t __user *, unsigned long);
|
||||||
|
|
||||||
#define save_altstack_ex(uss, sp) do { \
|
#define unsafe_save_altstack(uss, sp, label) do { \
|
||||||
stack_t __user *__uss = uss; \
|
stack_t __user *__uss = uss; \
|
||||||
struct task_struct *t = current; \
|
struct task_struct *t = current; \
|
||||||
put_user_ex((void __user *)t->sas_ss_sp, &__uss->ss_sp); \
|
unsafe_put_user((void __user *)t->sas_ss_sp, &__uss->ss_sp, label); \
|
||||||
put_user_ex(t->sas_ss_flags, &__uss->ss_flags); \
|
unsafe_put_user(t->sas_ss_flags, &__uss->ss_flags, label); \
|
||||||
put_user_ex(t->sas_ss_size, &__uss->ss_size); \
|
unsafe_put_user(t->sas_ss_size, &__uss->ss_size, label); \
|
||||||
if (t->sas_ss_flags & SS_AUTODISARM) \
|
if (t->sas_ss_flags & SS_AUTODISARM) \
|
||||||
sas_ss_reset(t); \
|
sas_ss_reset(t); \
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue