β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-5197

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-5197 Β· 3 files
FileTypeDescriptionSize
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_testable
baseline no→ patch + rebuild →patched clean

Fix 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.
per-fix-DF-5197

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.