⬢ DragonFlyBSD Kernel Audit
DF-5801 / fix.diff
← back to finding ↓ download raw
--- a/sys/vm/vm_page.c
+++ b/sys/vm/vm_page.c
@@ -3908,6 +3908,29 @@
 	int first_bit;
 	int last_bit;
 
+	/*
+	 * Sanitize the range unconditionally.  The KASSERT below is
+	 * compiled out in release builds (INVARIANTS off, see
+	 * sys/sys/systm.h), which leaves this function executing
+	 * `(2 << last_bit) - (1 << first_bit)' on unvalidated caller
+	 * input: shift UB for negative or oversized arguments, and
+	 * masks with bits >= 8 that silently over-mark the uint8_t
+	 * m->valid / m->dirty fields when OR'd in by the setter family
+	 * (vm_page_set_valid, vm_page_set_validclean,
+	 * vm_page_set_validdirty, vm_page_clear_dirty,
+	 * vm_page_set_invalid) and confuse int-sized consumers
+	 * (e.g. the "m->dirty & vm_page_bits(...)" test in
+	 * kern/vfs_bio.c).
+	 */
+	if (base < 0)
+		base = 0;
+	else if (base > PAGE_SIZE)
+		base = PAGE_SIZE;
+	if (size < 0)
+		size = 0;
+	else if (size > PAGE_SIZE - base)
+		size = PAGE_SIZE - base;
+
 	KASSERT(
 	    base + size <= PAGE_SIZE,
 	    ("vm_page_bits: illegal base/size %d/%d", base, size)