--- 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)