From fff1ade5bd7576b053b6bbc9c9b72c2572092c06 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb 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 --- 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