svn commit: r360901 - stable/12/sys/riscv/riscv

John Baldwin jhb at FreeBSD.org
Mon May 11 16:14:21 UTC 2020


Author: jhb
Date: Mon May 11 16:14:20 2020
New Revision: 360901
URL: https://svnweb.freebsd.org/changeset/base/360901

Log:
  MFC 356840,357344: Add stricter checks on user changes to SSTATUS.
  
  356840:
  Check for invalid sstatus values in set_mcontext().
  
  Previously, this check was only in sys_sigreturn() which meant that
  user applications could write invalid values to the register via
  setcontext() or swapcontext().
  
  357344:
  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().

Modified:
  stable/12/sys/riscv/riscv/machdep.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/riscv/riscv/machdep.c
==============================================================================
--- stable/12/sys/riscv/riscv/machdep.c	Mon May 11 15:38:44 2020	(r360900)
+++ stable/12/sys/riscv/riscv/machdep.c	Mon May 11 16:14:20 2020	(r360901)
@@ -365,6 +365,19 @@ set_mcontext(struct thread *td, mcontext_t *mcp)
 
 	tf = td->td_frame;
 
+	/*
+	 * 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 ^ 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));
 	memcpy(tf->tf_s, mcp->mc_gpregs.gp_s, sizeof(tf->tf_s));
 	memcpy(tf->tf_a, mcp->mc_gpregs.gp_a, sizeof(tf->tf_a));
@@ -416,7 +429,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) {
@@ -426,6 +444,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();
@@ -520,21 +539,11 @@ struct sigreturn_args {
 int
 sys_sigreturn(struct thread *td, struct sigreturn_args *uap)
 {
-	uint64_t sstatus;
 	ucontext_t uc;
 	int error;
 
 	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.
-	 * Supervisor interrupts in user mode are always enabled.
-	 */
-	sstatus = uc.uc_mcontext.mc_gpregs.gp_sstatus;
-	if ((sstatus & SSTATUS_SPP) != 0)
-		return (EINVAL);
 
 	error = set_mcontext(td, &uc.uc_mcontext);
 	if (error != 0)


More information about the svn-src-all mailing list