Author: jhb
Date: Fri Jan 31 19:00:48 2020
New Revision: 357344
URL: https://svnweb.freebsd.org/changeset/base/357344

Log:
  Add stricter checks on user changes to SSTATUS.
  
  Rather than trying to blacklist which bits userland can't write to via
  sigreturn() or setcontext(), only permit changes to whitelisted bits.
  
  - Permit arbitrary writes to bits in the user-writable USTATUS
    register that shadows SSTATUS.
  
  - Ignore changes in write-only bits maintained by the CPU.
  
  - Ignore the user-supplied value of the FS field used to track
    floating point state and instead set it to a value matching the
    actions taken by set_fpcontext().
  
  Discussed with:       mhorne
  MFC after:    2 weeks
  Sponsored by: DARPA
  Differential Revision:        https://reviews.freebsd.org/D23338

Modified:
  head/sys/riscv/riscv/machdep.c

Modified: head/sys/riscv/riscv/machdep.c
==============================================================================
--- head/sys/riscv/riscv/machdep.c      Fri Jan 31 18:55:21 2020        
(r357343)
+++ head/sys/riscv/riscv/machdep.c      Fri Jan 31 19:00:48 2020        
(r357344)
@@ -368,11 +368,16 @@ set_mcontext(struct thread *td, mcontext_t *mcp)
        tf = td->td_frame;
 
        /*
-        * Make sure the processor mode has not been tampered with and
-        * interrupts have not been disabled.
-        * Supervisor interrupts in user mode are always enabled.
+        * Permit changes to the USTATUS bits of SSTATUS.
+        *
+        * Ignore writes to read-only bits (SD, XS).
+        *
+        * Ignore writes to the FS field as set_fpcontext() will set
+        * it explicitly.
         */
-       if ((mcp->mc_gpregs.gp_sstatus & SSTATUS_SPP) != 0)
+       if (((mcp->mc_gpregs.gp_sstatus ^ tf->tf_sstatus) &
+           ~(SSTATUS_SD | SSTATUS_XS_MASK | SSTATUS_FS_MASK | SSTATUS_UPIE |
+           SSTATUS_UIE)) != 0)
                return (EINVAL);
 
        memcpy(tf->tf_t, mcp->mc_gpregs.gp_t, sizeof(tf->tf_t));
@@ -426,7 +431,12 @@ set_fpcontext(struct thread *td, mcontext_t *mcp)
 {
 #ifdef FPE
        struct pcb *curpcb;
+#endif
 
+       td->td_frame->tf_sstatus &= ~SSTATUS_FS_MASK;
+       td->td_frame->tf_sstatus |= SSTATUS_FS_OFF;
+
+#ifdef FPE
        critical_enter();
 
        if ((mcp->mc_flags & _MC_FP_VALID) != 0) {
@@ -436,6 +446,7 @@ set_fpcontext(struct thread *td, mcontext_t *mcp)
                    sizeof(mcp->mc_fpregs));
                curpcb->pcb_fcsr = mcp->mc_fpregs.fp_fcsr;
                curpcb->pcb_fpflags = mcp->mc_fpregs.fp_flags & PCB_FP_USERMASK;
+               td->td_frame->tf_sstatus |= SSTATUS_FS_CLEAN;
        }
 
        critical_exit();
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to