|
@@ -0,0 +1,295 @@
|
|
|
+diff -Nur linux-4.6.4.orig/arch/sparc/kernel/signal_32.c linux-4.6.4/arch/sparc/kernel/signal_32.c
|
|
|
+--- linux-4.6.4.orig/arch/sparc/kernel/signal_32.c 2016-07-11 18:30:07.000000000 +0200
|
|
|
++++ linux-4.6.4/arch/sparc/kernel/signal_32.c 2016-07-18 21:55:43.720763787 +0200
|
|
|
+@@ -60,22 +60,10 @@
|
|
|
+ #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 @@
|
|
|
+ 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)))
|
|
|
++ if (!access_ok(VERIFY_READ, sf, sizeof(*sf)))
|
|
|
+ goto segv_and_exit;
|
|
|
+
|
|
|
+- if (get_user(ufp, &sf->info.si_regs.u_regs[UREG_FP]))
|
|
|
+- 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 @@
|
|
|
+ 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 @@
|
|
|
+
|
|
|
+ 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 @@
|
|
|
+ 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 -Nur linux-4.6.4.orig/arch/sparc/kernel/signal32.c linux-4.6.4/arch/sparc/kernel/signal32.c
|
|
|
+--- linux-4.6.4.orig/arch/sparc/kernel/signal32.c 2016-07-11 18:30:07.000000000 +0200
|
|
|
++++ linux-4.6.4/arch/sparc/kernel/signal32.c 2016-07-18 21:56:41.807007836 +0200
|
|
|
+@@ -138,24 +138,12 @@
|
|
|
+ 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 int pc, npc;
|
|
|
+ sigset_t set;
|
|
|
+ compat_sigset_t seta;
|
|
|
+@@ -170,16 +158,11 @@
|
|
|
+ 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 @@
|
|
|
+ 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 @@
|
|
|
+ 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 @@
|
|
|
+ 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 -Nur linux-4.6.4.orig/arch/sparc/kernel/signal_64.c linux-4.6.4/arch/sparc/kernel/signal_64.c
|
|
|
+--- linux-4.6.4.orig/arch/sparc/kernel/signal_64.c 2016-07-11 18:30:07.000000000 +0200
|
|
|
++++ linux-4.6.4/arch/sparc/kernel/signal_64.c 2016-07-18 21:55:43.720763787 +0200
|
|
|
+@@ -234,17 +234,6 @@
|
|
|
+ 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 @@
|
|
|
+
|
|
|
+ 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 @@
|
|
|
+ (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 @@
|
|
|
+ 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 -Nur linux-4.6.4.orig/arch/sparc/kernel/sigutil_32.c linux-4.6.4/arch/sparc/kernel/sigutil_32.c
|
|
|
+--- linux-4.6.4.orig/arch/sparc/kernel/sigutil_32.c 2016-07-11 18:30:07.000000000 +0200
|
|
|
++++ linux-4.6.4/arch/sparc/kernel/sigutil_32.c 2016-07-18 21:55:43.720763787 +0200
|
|
|
+@@ -48,10 +48,6 @@
|
|
|
+ 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 @@
|
|
|
+ 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 -Nur linux-4.6.4.orig/arch/sparc/kernel/sigutil_64.c linux-4.6.4/arch/sparc/kernel/sigutil_64.c
|
|
|
+--- linux-4.6.4.orig/arch/sparc/kernel/sigutil_64.c 2016-07-11 18:30:07.000000000 +0200
|
|
|
++++ linux-4.6.4/arch/sparc/kernel/sigutil_64.c 2016-07-18 21:55:43.720763787 +0200
|
|
|
+@@ -37,10 +37,7 @@
|
|
|
+ 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 @@
|
|
|
+ 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;
|
|
|
+
|