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