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;