set_video_mode() return value ignored in warp_saver(): on failure vid aliases the stale 32KB text window and the 64000-byte bzero (plus every star write) overruns it by 32KB into 0xC0000+ (DF-5114 twin)
Summary
The exact DF-5114 twin pass 1 missed here: on mode-set failure vid captures the text window and the 64KB bzero + star writes overrun 32KB into the ROM shadow. Latent (init validated the same check at load; no in-tree divergence producer). Check-and-return-EAGAIN fix (the splash layer already retries EAGAIN).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5197 Β· 3 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 3.1 KB | β raw | |
| verdict.json | β | 3.1 KB | view raw | |
| manifest.json | β | 1.1 KB | view raw |
DF-5197 β warp_saver ignores set_video_mode() failure: stale 32KB text va_window would take a 64KB bzero + star writes 32KB past it (DF-5114 twin)
File: sys/dev/misc/syscons/warp/warp_saver.c:85-95
What
if (blanked <= 0) {
crit_enter();
set_video_mode(adp, M_VGA_CG320); /* :87 β return value ignored */
load_palette(adp, warp_pal);
...
vid = (u_char *)adp->va_window; /* :93 */
crit_exit();
bzero(vid, SCRW*SCRH); /* :95 β 64000 bytes */
}
set_video_mode() (fbreg.h:120-121) dispatches to vga_set_mode()
(sys/dev/video/fb/vga.c:997) which can fail β prologue(adp,
V_ADP_MODECHANGE, ENODEV) (adapter without mode-change / being
detached) or vga_get_info(...) β EINVAL. On failure it returns
before update_adapter_info(), so adp->va_window still describes
the text mode: CGA_BUF_BASE = 0xB8000 with CGA_BUF_SIZE = 0x8000
(32KB) (sys/dev/video/fb/vgareg.h:37-38, vga.c:274-275). warp_saver
then:
bzero(vid, 64000)clears 0xB8000..0xC7BFF β 32,000 bytes past the 32KB text window, into 0xC0000-0xC7C00 (video-BIOS ROM-shadow region on BIOS systems: writes fault or are silently dropped depending on platform);- every subsequent
warp_update()tick writes star pixels anywhere in [0,64000] of that same stale window.
Contrast with a successful switch: va_window = 0xA0000, window size GRAPHICS_BUF_SIZE = 0x10000 (64KB) (vga.c:581, vgareg.h:43-44), where 64000 bytes fit.
This is the exact twin of DF-5114 (dragon_saver.c:194,
set_video_mode(adp, VIDEO_MODE); ignored), which pass 1 graded
Info / latent: warp_init() already verified get_mode_info(adp,
M_VGA_CG320) == 0 at module load (warp_saver.c:114-117), and
vga_set_mode() re-runs the same vga_get_info() β so the failure
requires adapter state to diverge between load and first blank
(detach, V_ADP_MODECHANGE cleared). No in-tree path produces the
trigger today; hence Info, not higher.
Fix (infrastructure-compatible)
scsplash_saver() already handles EAGAIN from the splash layer
(sys/dev/misc/syscons/syscons.c:2564-2567: restores saver mode, touches
the saver timestamp, retries later). Return it:
--- a/sys/dev/misc/syscons/warp/warp_saver.c
+++ b/sys/dev/misc/syscons/warp/warp_saver.c
@@ -83,8 +83,11 @@ warp_saver(video_adapter_t *adp, int blank)
if (blank) {
/* switch to graphics mode */
if (blanked <= 0) {
crit_enter();
- set_video_mode(adp, M_VGA_CG320);
+ if (set_video_mode(adp, M_VGA_CG320) != 0) {
+ crit_exit();
+ return EAGAIN; /* scsplash_saver() retries later */
+ }
load_palette(adp, warp_pal);
blanked stays 0 and vid is not captured, so no stale-window state
is committed.
Why untested (Phase V skipped)
Info / latent finding per contract (and consistent with DF-5114's grading): there is no in-tree producer of the failure after a successful init-time get_mode_info, so a guest PoC cannot reach the bad path without artificially patching the kernel (which would test the patch, not the tree). The one-line code-shape defect is certain by inspection; the trigger is speculative.
Fix verification
not_testableFix validation not applicable: no reproducible baseline exists in the unmodified tree (latent trigger); the 4-line fix is inspection-verified against the existing EAGAIN retry path in scsplash_saver().
See README.md 'Fix' section for the diff and the syscons.c:2564-267 EAGAIN consumer citation.
Confirmed kernel references
Detail
Evidence (decisive lines)
warp_saver.c:87 (ignored return), :93 (vid capture), :95 (bzero 64000); vga.c:997-1005 (failure paths return before update_adapter_info at :581); vgareg.h:37-38 (CGA_BUF 0xB8000/32KB) vs :43-44 (GRAPHICS_BUF 0xA0000/64KB); twin: dragon_saver.c:194 (DF-5114); consumer that would absorb the fix: syscons.c:2564-2567 (splash EAGAIN handling)
PoC changes
n/a β no PoC built: the failure path has no in-tree producer after a successful init-time get_mode_info; forcing it would require patching the kernel under test.
Verified recommended fix
warp_saver.c:87: check set_video_mode() return; on failure return EAGAIN before capturing vid/blanked (scsplash_saver already retries on EAGAIN, syscons.c:2564-2567).
Verdict
warp_saver() ignores the return of set_video_mode(adp, M_VGA_CG320) (warp_saver.c:87). vga_set_mode() (vga.c:997) can fail via prologue(ENODEV)/get_info(EINVAL) and returns before update_adapter_info(), leaving adp->va_window describing the 32KB text window (0xB8000/0x8000, vgareg.h:37-38). On that path warp_saver captures vid=adp->va_window (:93) and bzero()s 64000 bytes (:95) β 32,000 bytes past the text window into 0xC0000+ (video-BIOS ROM shadow) β and every warp_update() tick then writes star pixels into the stale window. Exact twin of DF-5114 (dragon_saver.c:194). Latent: warp_init() already validated get_mode_info(M_VGA_CG320)==0 at load (:114-117) and vga_set_mode re-runs the same check, so no in-tree path produces the failure between load and first blank. Info severity to match DF-5114; guest PoC skipped per contract (Low/Info hardening) β a reproducible trigger does not exist in the unmodified tree.
No comments yet.