DragonFlyBSD Kernel Audit
DF-1096 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/platform/pc64/x86_64/npx.c b/sys/platform/pc64/x86_64/npx.c
--- a/sys/platform/pc64/x86_64/npx.c
+++ b/sys/platform/pc64/x86_64/npx.c
@@ -423,6 +423,33 @@
 				    td->td_proc->p_comm,
 				    td->td_savefpu->sv_xmm.sv_env.en_mxcsr);
 		}
+		/*
+		 * Sanitize the XSAVE header that lives at byte offset 512 of
+		 * the save area.  The bytes were just bcopy()'d from user
+		 * memory and are otherwise passed verbatim to XRSTOR, which
+		 * raises #GP if XCOMP_BV has bit 63 set (compacted format)
+		 * together with any bit not present in XCR0, or if XSTATE_BV
+		 * has bits outside XCR0.  A #GP inside npxdna()/npxdna_quick()
+		 * runs at gd_intr_nesting_level > 0 and panics the kernel.
+		 * Force the standard (non-compacted) XSAVE form by clearing
+		 * XCOMP_BV, and restrict XSTATE_BV to features actually
+		 * enabled in XCR0.
+		 */
+		if (cpu_xsave) {
+			struct xstate_hdr *hdr =
+			    &td->td_savefpu->sv_ymm64.sv_xstate.sx_hd;
+			if ((hdr->xstate_bv & ~npx_xcr0_mask) ||
+			    hdr->xstate_xcomp_bv != 0) {
+				krateprintf(&badfprate,
+				    "pid %d (%s) signal return from user: "
+				    "illegal XSAVE header bv=%016llx xcomp=%016llx\n",
+				    td->td_proc->p_pid, td->td_proc->p_comm,
+				    (unsigned long long)hdr->xstate_bv,
+				    (unsigned long long)hdr->xstate_xcomp_bv);
+				hdr->xstate_bv &= npx_xcr0_mask;
+				hdr->xstate_xcomp_bv = 0;
+			}
+		}
 		td->td_flags |= TDF_USINGFP;
 		break;
 	}