vm_contig_pg_alloc verify/alloc loops lack the vm_page_count bound — oversized size with permissive high reads one element past the end of vm_page_array
| Field | Value |
|---|---|
| ID | DF-2890 |
| Status | new |
| Severity | Low |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:L |
| CWE | CWE-125 Out-of-bounds Read |
| File | sys/vm/vm_contig.c |
| Lines | 331-332, 377, 398 |
| Area | vm |
| Confidence | likely |
| Discovered | 2026-09-02 |
| Pass | 2 (GLM 5.3 second pass) |
| Bucket | base:vm |
| Reported | pending |
| Known CVE | none |
| CVE match | novel |
Summary
The scan loop is bounded by v_page_count, but the successive-page
verify loop (for (i = start+1; i < start + size/PAGE_SIZE; i++)) and
the alloc loop have NO v_page_count bound. The only pre-check
(VM_PAGE_TO_PHYS(&pga[i]) + size) > high passes for arbitrarily huge
size with high == BUS_SPACE_MAXADDR (~0ULL), and phys+size can wrap,
defeating the clamp. A candidate free run reaching the last array
element reads pga[vm_page_count] — one element past vm_page_array —
(compare-only, no direct disclosure); each mismatch restarts at start+1,
so every start in the tail run repeats the OOB read and the scan
degenerates into an O(n²) rewalk plus three full page-queue flush
passes (long system-wide stall). No in-tree attacker-reachable caller
passes oversized size (cpuctl clamps; netmap/DRM gated) —
defense-in-depth bound + stall amplifier for buggy/coerced drivers.
Fix: reject candidates whose span cannot fit the array
(if (i + size/PAGE_SIZE > vmstats.v_page_count) break; at :308) and
harden :331 against phys+size wrap (phys > high - size after
size <= high).
Timeline
- 2026-09-02 Discovered during pass-2 audit of vm_contig.c (GLM 5.3).
No comments yet.