Author: andrew
Date: Thu Nov 23 17:40:40 2017
New Revision: 326137
URL: https://svnweb.freebsd.org/changeset/base/326137

Log:
  Ensure we check the program state set in the trap frame on arm and arm64.
  This value may be set by userspace so we need to check it before using it.
  If this is not done correctly on exception return the kernel may continue
  in kernel mode with all registers set to a userspace controlled value. Fix
  this by moving the check into set_mcontext, and also add the missing
  sanitisation from the arm64 set_regs.
  
  Discussed with:       security-officer@
  MFC after:    3 days
  Sponsored by: DARPA, AFRL

Modified:
  head/sys/arm/arm/machdep.c
  head/sys/arm64/arm64/machdep.c
  head/sys/arm64/include/armreg.h

Modified: head/sys/arm/arm/machdep.c
==============================================================================
--- head/sys/arm/arm/machdep.c  Thu Nov 23 16:04:52 2017        (r326136)
+++ head/sys/arm/arm/machdep.c  Thu Nov 23 17:40:40 2017        (r326137)
@@ -518,7 +518,17 @@ set_mcontext(struct thread *td, mcontext_t *mcp)
        mcontext_vfp_t mc_vfp, *vfp;
        struct trapframe *tf = td->td_frame;
        const __greg_t *gr = mcp->__gregs;
+       int spsr;
 
+       /*
+        * Make sure the processor mode has not been tampered with and
+        * interrupts have not been disabled.
+        */
+       spsr = gr[_REG_CPSR];
+       if ((spsr & PSR_MODE) != PSR_USR32_MODE ||
+           (spsr & (PSR_I | PSR_F)) != 0)
+               return (EINVAL);
+
 #ifdef WITNESS
        if (mcp->mc_vfp_size != 0 && mcp->mc_vfp_size != sizeof(mc_vfp)) {
                printf("%s: %s: Malformed mc_vfp_size: %d (0x%08X)\n",
@@ -677,22 +687,16 @@ sys_sigreturn(td, uap)
        } */ *uap;
 {
        ucontext_t uc;
-       int spsr;
+       int error;
 
        if (uap == NULL)
                return (EFAULT);
        if (copyin(uap->sigcntxp, &uc, sizeof(uc)))
                return (EFAULT);
-       /*
-        * Make sure the processor mode has not been tampered with and
-        * interrupts have not been disabled.
-        */
-       spsr = uc.uc_mcontext.__gregs[_REG_CPSR];
-       if ((spsr & PSR_MODE) != PSR_USR32_MODE ||
-           (spsr & (PSR_I | PSR_F)) != 0)
-               return (EINVAL);
        /* Restore register context. */
-       set_mcontext(td, &uc.uc_mcontext);
+       error = set_mcontext(td, &uc.uc_mcontext);
+       if (error != 0)
+               return (error);
 
        /* Restore signal mask. */
        kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0);

Modified: head/sys/arm64/arm64/machdep.c
==============================================================================
--- head/sys/arm64/arm64/machdep.c      Thu Nov 23 16:04:52 2017        
(r326136)
+++ head/sys/arm64/arm64/machdep.c      Thu Nov 23 17:40:40 2017        
(r326137)
@@ -211,7 +211,8 @@ set_regs(struct thread *td, struct reg *regs)
        frame->tf_sp = regs->sp;
        frame->tf_lr = regs->lr;
        frame->tf_elr = regs->elr;
-       frame->tf_spsr = regs->spsr;
+       frame->tf_spsr &= ~PSR_FLAGS;
+       frame->tf_spsr |= regs->spsr & PSR_FLAGS;
 
        memcpy(frame->tf_x, regs->x, sizeof(frame->tf_x));
 
@@ -354,7 +355,13 @@ int
 set_mcontext(struct thread *td, mcontext_t *mcp)
 {
        struct trapframe *tf = td->td_frame;
+       uint32_t spsr;
 
+       spsr = mcp->mc_gpregs.gp_spsr;
+       if ((spsr & PSR_M_MASK) != PSR_M_EL0t ||
+           (spsr & (PSR_F | PSR_I | PSR_A | PSR_D)) != 0)
+               return (EINVAL); 
+
        memcpy(tf->tf_x, mcp->mc_gpregs.gp_x, sizeof(tf->tf_x));
 
        tf->tf_sp = mcp->mc_gpregs.gp_sp;
@@ -530,19 +537,16 @@ int
 sys_sigreturn(struct thread *td, struct sigreturn_args *uap)
 {
        ucontext_t uc;
-       uint32_t spsr;
+       int error;
 
        if (uap == NULL)
                return (EFAULT);
        if (copyin(uap->sigcntxp, &uc, sizeof(uc)))
                return (EFAULT);
 
-       spsr = uc.uc_mcontext.mc_gpregs.gp_spsr;
-       if ((spsr & PSR_M_MASK) != PSR_M_EL0t ||
-           (spsr & (PSR_F | PSR_I | PSR_A | PSR_D)) != 0)
-               return (EINVAL); 
-
-       set_mcontext(td, &uc.uc_mcontext);
+       error = set_mcontext(td, &uc.uc_mcontext);
+       if (error != 0)
+               return (error);
        set_fpcontext(td, &uc.uc_mcontext);
 
        /* Restore signal mask. */

Modified: head/sys/arm64/include/armreg.h
==============================================================================
--- head/sys/arm64/include/armreg.h     Thu Nov 23 16:04:52 2017        
(r326136)
+++ head/sys/arm64/include/armreg.h     Thu Nov 23 17:40:40 2017        
(r326137)
@@ -572,6 +572,7 @@
 #define        PSR_C           0x20000000
 #define        PSR_Z           0x40000000
 #define        PSR_N           0x80000000
+#define        PSR_FLAGS       0xf0000000
 
 /* TCR_EL1 - Translation Control Register */
 #define        TCR_ASID_16     (1 << 36)
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to