Commit 978727ca authored by Al Viro's avatar Al Viro

x86: get rid of get_user_ex() in ia32_restore_sigcontext()

Just do copyin into a local struct and be done with that - we are
on a shallow stack here.

[reworked by tglx, removing the macro horrors while we are touching that]
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent c63aad69
......@@ -36,85 +36,65 @@
#include <asm/sighandling.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.
*/
#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,
struct sigcontext_32 __user *sc)
struct sigcontext_32 __user *usc)
{
unsigned int tmpflags, err = 0;
u16 gs, fs, es, ds;
void __user *buf;
u32 tmp;
struct sigcontext_32 sc;
/* Always make any pending restarted system calls return -EINTR */
current->restart_block.fn = do_no_restart_syscall;
get_user_try {
gs = GET_SEG(gs);
fs = GET_SEG(fs);
ds = GET_SEG(ds);
es = GET_SEG(es);
COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
COPY(dx); COPY(cx); COPY(ip); COPY(ax);
/* Don't touch extended registers */
COPY_SEG_CPL3(cs);
COPY_SEG_CPL3(ss);
if (unlikely(copy_from_user(&sc, usc, sizeof(sc))))
return -EFAULT;
get_user_ex(tmpflags, &sc->flags);
regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
/* Get only the ia32 registers. */
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;
/* Get CS/SS and force CPL3 */
regs->cs = sc.cs | 0x03;
regs->ss = sc.ss | 0x03;
regs->flags = (regs->flags & ~FIX_EFLAGS) | (sc.flags & FIX_EFLAGS);
/* disable syscall checks */
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
* handler. This does not handle long fs/gs base changes in
* the handler, but does not clobber them at least in the
* normal case.
*/
RELOAD_SEG(gs);
RELOAD_SEG(fs);
RELOAD_SEG(ds);
RELOAD_SEG(es);
err |= fpu__restore_sig(buf, 1);
return err;
reload_segments(&sc);
return fpu__restore_sig(compat_ptr(sc.fpstate), 1);
}
COMPAT_SYSCALL_DEFINE0(sigreturn)
......@@ -172,6 +152,8 @@ COMPAT_SYSCALL_DEFINE0(rt_sigreturn)
* Set up a signal frame.
*/
#define get_user_seg(seg) ({ unsigned int v; savesegment(seg, v); v; })
static int ia32_setup_sigcontext(struct sigcontext_32 __user *sc,
void __user *fpstate,
struct pt_regs *regs, unsigned int mask)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment