probeCard() consumes uninitialized stack eeprom[256] when readEEProm() fails β uninitialized stack bytes reach console/dmesg and drive card identification (CWE-457)
Summary
probeCard declares eeprom[256] on the kernel stack; readEEProm fills it incrementally over i2c and returns -1 on the first NAK (possibly before writing anything). All four call sites ignore the return, then derive identity from and print the uninitialized bytes (subsystem ids at bootverbose AND unconditional 'card vendor unknown' prints; eeprom[0..3] unconditionally printed on the Bt848 path; the Hauppauge re-parse reads block_1 of the same never-written buffer, feeding DF-1569's walk with uninitialized offsets). Flaky-EEPROM card -> stack bytes disclosed to dmesg on every probe + nondeterministic misidentification. Same pattern/ceiling as DF-2092. memset-zero fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4377 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.9 KB | β raw | |
| VERDICT.md | β | 4.4 KB | β raw | |
| chk_bktr.c | β | 2.4 KB | view raw | |
| build.sh | β | 80 B | view raw | |
| run.sh | β | 91 B | view raw | |
| build.log | β | 446 B | view raw | |
| run.log | β | 446 B | view raw | |
| env.txt | β | 497 B | view raw | |
| fix.diff | β | 502 B | view raw | |
| manifest.json | β | 1.1 KB | view raw | |
| verdict.json | β | 2.8 KB | view raw |
DF-4377 β bktr_card.c probeCard() consumes uninitialized stack eeprom[256] when readEEProm() fails; uninitialized bytes reach console/dmesg
- File:
sys/dev/video/bktr/bktr_card.c - Class: CWE-457 (use of uninitialized memory) β kernel stack info disclosure to console/dmesg (kernleak, Low)
- Pass: 2 (GLM 5.3 re-audit)
- Verdict:
not_reproducedβ hardware-gated; the audit QEMU guest has no Bt848/878 card, so/dev/bktr*does not exist and the probe path cannot run (seerun.log). The code defect itself is certain from source.
What a maintainer needs to know
probeCard() declares u_char eeprom[256] on the kernel stack (bktr_card.c:605) and
passes it to readEEProm() ignoring the return value at four sites (:667, :794,
:1001, :1129). readEEProm() fills the buffer incrementally over the i2c bus and
returns -1 on the first NAK β everything past the failure point (or the whole array)
stays uninitialized. probeCard then derives identity data from those bytes and prints
them:
- :668-674 β
subsystem_id/subsystem_vendor_idfromeeprom[252..255]; - :676-678 β bootverbose
kprintf("subsystem 0x%04x 0x%04x"); - :757-758 β unconditional
kprintf("card vendor 0x%04x (model 0x%04x) unknown")whenever the (garbage) vendor id is not in the table; - :794-815 β Bt848 path:
eeprom[0..3]compared, then unconditionally printed (kprintf("%s: %x %x %x %x"), :814-815) when unrecognized; - :1001/:1004-1015 β Hauppauge re-parse reads
block_1[1..15]of the same buffer (feeding the DF-1569 block walk with uninitialized offsets).
Impact: a handful of uninitialized kernel-stack bytes are disclosed to the console and
dmesg on every probe with a flaky EEPROM, and the card is misidentified
nondeterministically. Requires a Bt848/878 card whose EEPROM ACKs the probe read
(locate_eeprom_address succeeds) but NAKs the sequential data read β plausible
hardware behavior (that is exactly the failure readEEProm is written to detect).
Not re-reported (pass-1/known, filed from the ioctl side or sibling files): DF-1569 (block_2/3 OOB), DF-3785 (BT848_REEPROM negative-offset heap overflow), DF-3786 (BT848_SIGNATURE unbounded count), DF-1217 (raw I2C access), DF-4361 (select_tuner bound), DF-2092 (same pattern in cxm_eeprom.c).
Build / Run / Expected
build.sh # on the DragonFly guest: cc -o chk_bktr chk_bktr.c run.sh # ./chk_bktr
Expected on hardware: probe output visible in dmesg; the uninit disclosure manifests as the "subsystem 0x⦠/ card vendor 0x⦠unknown / %x %x %x %x" lines carrying stack garbage when the EEPROM read fails mid-way.
Observed on this guest (run.log): DF-4377: /dev/bktr0 not present β EXIT=2
(target device absent β probe cannot run).
Fix
fix.diff β zero-initialize eeprom[] in probeCard() so a failed EEPROM read
yields deterministic (zero) vendor/model IDs instead of stack bytes.
DF-4377 VERDICT β not_reproduced (hardware-gated), defect certain from source
Reproduced?
No β the target hardware does not exist on the audit guest.
chk_bktr.c compiled and ran on the guest (BUILD_OK_4377, run.log); the open of
/dev/bktr0 fails with ENOENT because the QEMU guest has no Brooktree PCI device and
the bktr driver is not attached (pciconf -l | grep -c brooktree β 0, no
/dev/bktr* /dev/tuner* /dev/vbi* nodes). The vulnerable code only executes
inside probeCard() during device attach (bktr_core.c:505) or on the first open
after a hw.bt848.card/hw.bt848.tuner sysctl change (bktr_os.c:463/473) β i.e.
only on a machine with a real Bt848/Bt878 capture card.
Why the defect is certain anyway (path:line)
sys/dev/video/bktr/bktr_card.c:605βu_char eeprom[256];kernel-stack array, not initialized.bktr_card.c:420-448βreadEEProm()writesdata[x]only for bytes whose i2c read succeeded; on the firsti2cRead() == -1it returns-1with the buffer partially (or entirely) uninitialized. It can also fail at the bounds check (:433-434) or the address-set write (:437) before touching the buffer at all β in those cases nothing is initialized.- Every call site in
probeCard()ignores the return value: - :667readEEProm(bktr, 0, 256, (u_char *)&eeprom);(Bt878/879 path) - :794readEEProm(bktr, 0, 128, ...)(Bt848 Hauppauge/Osprey path) - :1001readEEProm(bktr, 0, 128, ...)(Hauppauge tuner re-parse) - :1129readEEProm(bktr, 0, 128, ...)(AVerMedia re-parse) - Uninitialized bytes are then consumed and printed:
- :668-674
subsystem_id/subsystem_vendor_idfromeeprom[252..255]; - :676-678 bootverbose print of both; - :757-758 unconditional "Warning - card vendor 0x%04x (model 0x%04x) unknown" for any garbage vendor id; - :797/:805eeprom[0..3]compared, :812-815 unconditional print of the four bytes when unrecognized; - :1004-1019block_1[1..15]of the (possibly never-written) buffer drive the Hauppauge block walk β with DF-1569's missing bounds this turns uninitialized stack into wild offsets (that specific OOB remains DF-1569's scope; the uninitialized source is this finding).
Trigger condition on hardware: locate_eeprom_address() (:525-530) must see an ACK
at 0xa0/0xac/0xae while the subsequent sequential read NAKs β i.e. exactly the
"EEPROM present but read fails" case the helper models. Then :667 returns early,
and :668-674/:676/:757 print uninitialized stack. On the :794 path the probe read at
:788 (i2cRead(PFC8582_RADDR)) succeeded, so a mid-readEEProm failure leaves
eeprom[0..3] uninitialized and :814-815 prints them.
Impact assessment
- Kernel-stack disclosure: 4-16 uninitialized bytes per probe printed to console/dmesg (readable by unprivileged users unless dmesg is restricted). Same class and ceiling as DF-2092 (cxm_eeprom.c), which was triaged Low.
- Secondary: nondeterministic card misidentification β wrong tuner/audio config (correctness, not a memory-safety primitive).
- No userland trigger exists for the uninit path itself: the BT848_REEPROM ioctl
copies the argument through a zeroed kernel buffer (
mapped_ioctl, sys/kern/sys_generic.c:674-697, bzero's IOC_OUT), so the ioctl-driven variants of readEEProm cannot disclose stack; only the probe-time kprintfs do.
Exploit chain
None β information disclosure of a few stack bytes; not a corruption primitive.
Fix validation
fix.diff (zero-init eeprom[] in probeCard) is authored against the read-only
sys/ tree and not applied; fix validation is not_testable on this guest
(no hardware to observe the disclosure before/after). The change is trivially
reviewable: it makes a failed read produce vendor id 0x0000 (prints as
"vendor 0x0000 unknown") instead of stack garbage.
Guest evidence
run.log: uname, BUILD_OK,/dev/bktr0 not present, EXIT=2, no bktr/tuner/vbi nodes,pciconf -l | grep -ci brooktree= 0.env.txt: guest identity + device-absence summary.
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
not_testablefix.diff authored (memset of eeprom[] in probeCard, read-only tree, never applied); cannot build/validate on the guest - no bktr hardware to observe the disclosure on a baseline kernel.
fix.diff in this pack; guest device-absence evidence in run.log/env.txt.
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md path:line trace; run.log shows BUILD_OK_4377 then '/dev/bktr0 not present' EXIT=2 and pciconf brooktree count 0; env.txt guest state.
PoC changes
Probe written from scratch (finding is probe-time, no seed PoC existed); added
Verified recommended fix
Zero-initialize eeprom[256] in probeCard() so failed EEPROM reads yield deterministic ids (fix.diff); alternatively honor readEEProm()'s return at all four call sites.
Verdict
probeCard() uses stack eeprom[256] uninitialized whenever readEEProm() fails (return ignored at bktr_card.c:667/794/1001/1129); garbage subsystem/model bytes are printed to console/dmesg at :676/:757/:814 and drive card selection. Not reproduced on the audit guest: no Bt848/878 hardware, /dev/bktr* absent (chk_bktr built and ran, exit 2). Defect is certain from source; manifestation is hardware-gated (EEPROM probe-ACK + read-NAK). Low-severity kernel-stack disclosure, same class as DF-2092 (cxm).
No comments yet.