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

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
Loading
Loading
Loading
Loading
+44 −62
Original line number Diff line number Diff line
@@ -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 @@ badframe:
 * 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)