From fff1ade5bd7576b053b6bbc9c9b72c2572092c06 Mon Sep 17 00:00:00 2001
From: Waldemar Brodkorb <wbx@uclibc-ng.org>
Date: Wed, 6 Jul 2016 08:16:59 +0200
Subject: [PATCH] Revert "sparc: Harden signal return frame checks."

This reverts commit 1fda90c39d8ef6acbedfd3cd9bd710a5bcc490c3.

Signed-off-by: Waldemar Brodkorb <wbx@uclibc-ng.org>
---
 arch/sparc/kernel/signal32.c   |   46 ++++++++++++++--------------------------
 arch/sparc/kernel/signal_32.c  |   41 +++++++++++++----------------------
 arch/sparc/kernel/signal_64.c  |   31 ++++++++++-----------------
 arch/sparc/kernel/sigutil_32.c |    9 +-------
 arch/sparc/kernel/sigutil_64.c |   10 ++-------
 5 files changed, 45 insertions(+), 92 deletions(-)

diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c
index 77655f0..4eed773 100644
--- a/arch/sparc/kernel/signal32.c
+++ b/arch/sparc/kernel/signal32.c
@@ -138,24 +138,12 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
 	return 0;
 }
 
-/* Checks if the fp is valid.  We always build signal frames which are
- * 16-byte aligned, therefore we can always enforce that the restore
- * frame has that property as well.
- */
-static bool invalid_frame_pointer(void __user *fp, int fplen)
-{
-	if ((((unsigned long) fp) & 15) ||
-	    ((unsigned long)fp) > 0x100000000ULL - fplen)
-		return true;
-	return false;
-}
-
 void do_sigreturn32(struct pt_regs *regs)
 {
 	struct signal_frame32 __user *sf;
 	compat_uptr_t fpu_save;
 	compat_uptr_t rwin_save;
-	unsigned int psr, ufp;
+	unsigned int psr;
 	unsigned pc, npc;
 	sigset_t set;
 	compat_sigset_t seta;
@@ -170,16 +158,11 @@ void do_sigreturn32(struct pt_regs *regs)
 	sf = (struct signal_frame32 __user *) regs->u_regs[UREG_FP];
 
 	/* 1. Make sure we are not getting garbage from the user */
-	if (invalid_frame_pointer(sf, sizeof(*sf)))
-		goto segv;
-
-	if (get_user(ufp, &sf->info.si_regs.u_regs[UREG_FP]))
-		goto segv;
-
-	if (ufp & 0x7)
+	if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
+	    (((unsigned long) sf) & 3))
 		goto segv;
 
-	if (__get_user(pc, &sf->info.si_regs.pc) ||
+	if (get_user(pc, &sf->info.si_regs.pc) ||
 	    __get_user(npc, &sf->info.si_regs.npc))
 		goto segv;
 
@@ -244,7 +227,7 @@ segv:
 asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
 {
 	struct rt_signal_frame32 __user *sf;
-	unsigned int psr, pc, npc, ufp;
+	unsigned int psr, pc, npc;
 	compat_uptr_t fpu_save;
 	compat_uptr_t rwin_save;
 	sigset_t set;
@@ -259,16 +242,11 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
 	sf = (struct rt_signal_frame32 __user *) regs->u_regs[UREG_FP];
 
 	/* 1. Make sure we are not getting garbage from the user */
-	if (invalid_frame_pointer(sf, sizeof(*sf)))
+	if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
+	    (((unsigned long) sf) & 3))
 		goto segv;
 
-	if (get_user(ufp, &sf->regs.u_regs[UREG_FP]))
-		goto segv;
-
-	if (ufp & 0x7)
-		goto segv;
-
-	if (__get_user(pc, &sf->regs.pc) ||
+	if (get_user(pc, &sf->regs.pc) || 
 	    __get_user(npc, &sf->regs.npc))
 		goto segv;
 
@@ -329,6 +307,14 @@ segv:
 	force_sig(SIGSEGV, current);
 }
 
+/* Checks if the fp is valid */
+static int invalid_frame_pointer(void __user *fp, int fplen)
+{
+	if ((((unsigned long) fp) & 7) || ((unsigned long)fp) > 0x100000000ULL - fplen)
+		return 1;
+	return 0;
+}
+
 static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)
 {
 	unsigned long sp;
diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c
index c3c12ef..52aa5e4 100644
--- a/arch/sparc/kernel/signal_32.c
+++ b/arch/sparc/kernel/signal_32.c
@@ -60,22 +60,10 @@ struct rt_signal_frame {
 #define SF_ALIGNEDSZ  (((sizeof(struct signal_frame) + 7) & (~7)))
 #define RT_ALIGNEDSZ  (((sizeof(struct rt_signal_frame) + 7) & (~7)))
 
-/* Checks if the fp is valid.  We always build signal frames which are
- * 16-byte aligned, therefore we can always enforce that the restore
- * frame has that property as well.
- */
-static inline bool invalid_frame_pointer(void __user *fp, int fplen)
-{
-	if ((((unsigned long) fp) & 15) || !__access_ok((unsigned long)fp, fplen))
-		return true;
-
-	return false;
-}
-
 asmlinkage void do_sigreturn(struct pt_regs *regs)
 {
-	unsigned long up_psr, pc, npc, ufp;
 	struct signal_frame __user *sf;
+	unsigned long up_psr, pc, npc;
 	sigset_t set;
 	__siginfo_fpu_t __user *fpu_save;
 	__siginfo_rwin_t __user *rwin_save;
@@ -89,13 +77,10 @@ asmlinkage void do_sigreturn(struct pt_regs *regs)
 	sf = (struct signal_frame __user *) regs->u_regs[UREG_FP];
 
 	/* 1. Make sure we are not getting garbage from the user */
-	if (!invalid_frame_pointer(sf, sizeof(*sf)))
-		goto segv_and_exit;
-
-	if (get_user(ufp, &sf->info.si_regs.u_regs[UREG_FP]))
+	if (!access_ok(VERIFY_READ, sf, sizeof(*sf)))
 		goto segv_and_exit;
 
-	if (ufp & 0x7)
+	if (((unsigned long) sf) & 3)
 		goto segv_and_exit;
 
 	err = __get_user(pc,  &sf->info.si_regs.pc);
@@ -142,7 +127,7 @@ segv_and_exit:
 asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
 {
 	struct rt_signal_frame __user *sf;
-	unsigned int psr, pc, npc, ufp;
+	unsigned int psr, pc, npc;
 	__siginfo_fpu_t __user *fpu_save;
 	__siginfo_rwin_t __user *rwin_save;
 	sigset_t set;
@@ -150,13 +135,8 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
 
 	synchronize_user_stack();
 	sf = (struct rt_signal_frame __user *) regs->u_regs[UREG_FP];
-	if (!invalid_frame_pointer(sf, sizeof(*sf)))
-		goto segv;
-
-	if (get_user(ufp, &sf->regs.u_regs[UREG_FP]))
-		goto segv;
-
-	if (ufp & 0x7)
+	if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
+	    (((unsigned long) sf) & 0x03))
 		goto segv;
 
 	err = __get_user(pc, &sf->regs.pc);
@@ -198,6 +178,15 @@ segv:
 	force_sig(SIGSEGV, current);
 }
 
+/* Checks if the fp is valid */
+static inline int invalid_frame_pointer(void __user *fp, int fplen)
+{
+	if ((((unsigned long) fp) & 7) || !__access_ok((unsigned long)fp, fplen))
+		return 1;
+
+	return 0;
+}
+
 static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)
 {
 	unsigned long sp = regs->u_regs[UREG_FP];
diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c
index 5ee930c..39aaec1 100644
--- a/arch/sparc/kernel/signal_64.c
+++ b/arch/sparc/kernel/signal_64.c
@@ -234,17 +234,6 @@ do_sigsegv:
 	goto out;
 }
 
-/* Checks if the fp is valid.  We always build rt signal frames which
- * are 16-byte aligned, therefore we can always enforce that the
- * restore frame has that property as well.
- */
-static bool invalid_frame_pointer(void __user *fp)
-{
-	if (((unsigned long) fp) & 15)
-		return true;
-	return false;
-}
-
 struct rt_signal_frame {
 	struct sparc_stackf	ss;
 	siginfo_t		info;
@@ -257,8 +246,8 @@ struct rt_signal_frame {
 
 void do_rt_sigreturn(struct pt_regs *regs)
 {
-	unsigned long tpc, tnpc, tstate, ufp;
 	struct rt_signal_frame __user *sf;
+	unsigned long tpc, tnpc, tstate;
 	__siginfo_fpu_t __user *fpu_save;
 	__siginfo_rwin_t __user *rwin_save;
 	sigset_t set;
@@ -272,16 +261,10 @@ void do_rt_sigreturn(struct pt_regs *regs)
 		(regs->u_regs [UREG_FP] + STACK_BIAS);
 
 	/* 1. Make sure we are not getting garbage from the user */
-	if (invalid_frame_pointer(sf))
-		goto segv;
-
-	if (get_user(ufp, &sf->regs.u_regs[UREG_FP]))
+	if (((unsigned long) sf) & 3)
 		goto segv;
 
-	if ((ufp + STACK_BIAS) & 0x7)
-		goto segv;
-
-	err = __get_user(tpc, &sf->regs.tpc);
+	err = get_user(tpc, &sf->regs.tpc);
 	err |= __get_user(tnpc, &sf->regs.tnpc);
 	if (test_thread_flag(TIF_32BIT)) {
 		tpc &= 0xffffffff;
@@ -325,6 +308,14 @@ segv:
 	force_sig(SIGSEGV, current);
 }
 
+/* Checks if the fp is valid */
+static int invalid_frame_pointer(void __user *fp)
+{
+	if (((unsigned long) fp) & 15)
+		return 1;
+	return 0;
+}
+
 static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)
 {
 	unsigned long sp = regs->u_regs[UREG_FP] + STACK_BIAS;
diff --git a/arch/sparc/kernel/sigutil_32.c b/arch/sparc/kernel/sigutil_32.c
index e5fe8ce..0f6eebe 100644
--- a/arch/sparc/kernel/sigutil_32.c
+++ b/arch/sparc/kernel/sigutil_32.c
@@ -48,10 +48,6 @@ int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
 int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
 {
 	int err;
-
-	if (((unsigned long) fpu) & 3)
-		return -EFAULT;
-
 #ifdef CONFIG_SMP
 	if (test_tsk_thread_flag(current, TIF_USEDFPU))
 		regs->psr &= ~PSR_EF;
@@ -101,10 +97,7 @@ int restore_rwin_state(__siginfo_rwin_t __user *rp)
 	struct thread_info *t = current_thread_info();
 	int i, wsaved, err;
 
-	if (((unsigned long) rp) & 3)
-		return -EFAULT;
-
-	get_user(wsaved, &rp->wsaved);
+	__get_user(wsaved, &rp->wsaved);
 	if (wsaved > NSWINS)
 		return -EFAULT;
 
diff --git a/arch/sparc/kernel/sigutil_64.c b/arch/sparc/kernel/sigutil_64.c
index 36aadcb..387834a 100644
--- a/arch/sparc/kernel/sigutil_64.c
+++ b/arch/sparc/kernel/sigutil_64.c
@@ -37,10 +37,7 @@ int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
 	unsigned long fprs;
 	int err;
 
-	if (((unsigned long) fpu) & 7)
-		return -EFAULT;
-
-	err = get_user(fprs, &fpu->si_fprs);
+	err = __get_user(fprs, &fpu->si_fprs);
 	fprs_write(0);
 	regs->tstate &= ~TSTATE_PEF;
 	if (fprs & FPRS_DL)
@@ -75,10 +72,7 @@ int restore_rwin_state(__siginfo_rwin_t __user *rp)
 	struct thread_info *t = current_thread_info();
 	int i, wsaved, err;
 
-	if (((unsigned long) rp) & 7)
-		return -EFAULT;
-
-	get_user(wsaved, &rp->wsaved);
+	__get_user(wsaved, &rp->wsaved);
 	if (wsaved > NSWINS)
 		return -EFAULT;
 
-- 
1.7.10.4