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

select_tuner() bounds the tuners[] dispatch index on the upper side only β€” a negative tuner type would install an out-of-bounds TUNER pointer that consumers dereference (hardening)

Summary

'if (tuner_type < Bt848_MAX_TUNER)' accepts any negative value; tuners[-1] would be stored and later dereferenced for pllControl/bandAddrs and a %s name print - a wild kernel read. All current callers pass provably non-negative values (exhaustive enumeration in the pack), so impact is currently unreachable: defense-in-depth for any future caller or enabled override. Add-the-lower-bound fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4361 Β· 4 files
FileTypeDescriptionSize
README.md β€” 2.7 KB ↓ raw
VERDICT.md β€” 2.1 KB ↓ raw
verdict.json β€” 2.1 KB view raw
manifest.json β€” 542 B view raw

DF-4361 β€” select_tuner() checks only the upper bound of tuner_type β†’ negative index would walk tuners[] OOB (hardening; all current callers proven safe)

File: sys/dev/video/bktr/bktr_tuner.c (pass 2) Severity: Info (defense-in-depth) Β· Confidence: certain (defect certain, impact currently unreachable)

What

sys/dev/video/bktr/bktr_tuner.c:709  void select_tuner( bktr_ptr_t bktr, int tuner_type ) {
sys/dev/video/bktr/bktr_tuner.c:710      if (tuner_type < Bt848_MAX_TUNER) {     /* only UPPER bound */
sys/dev/video/bktr/bktr_tuner.c:711          bktr->card.tuner = &tuners[ tuner_type ];
sys/dev/video/bktr/bktr_tuner.c:712      } else {
sys/dev/video/bktr/bktr_tuner.c:713          bktr->card.tuner = NULL;
sys/dev/video/bktr/bktr_tuner.c:714      }

tuners[] is exactly 16 entries (bktr_tuner.c:119-280; NO_TUNER=0 … LG_TPI8PSB12P_PAL=15, Bt848_MAX_TUNER == 16, bktr_tuner.h:65). A negative tuner_type passes the check and stores &tuners[-1] (or further back). Consumers then dereference it: - tuner->pllControl[band] / tuner->bandAddrs[band] (bktr_tuner.c:825-826, 884-885) - bktr->card.tuner->name in the attach printout (bktr_card.c:1343-1344) β†’ %s on a wild char * read from out-of-bounds rodata β†’ potential kernel fault.

Caller enumeration (why Info, not higher)

Every reachable caller passes a provably non-negative value: 1. Boot tunable: masked bt848_tuner & 0xff (bktr_os.c:470, bktr_card.c:906) β†’ 0..255; β‰₯16 β†’ NULL. (Root-controlled anyway.) 2. BKTR_OVERRIDE_TUNER path β€” compile-time constant, not defined in the build. 3. Signature-table dispatch: single entry {5, 9, …} β†’ tuner=9 (bktr_card.c:395-398, 862). 4. GPIO/EEPROM derivation: tuner_format <= 9 gating 10-entry constant tables (bktr_card.c:1128-1152), switch (((INL(...)>>10)-1)&7) (bktr_card.c:920-928) β€” all enum constants. So the OOB is currently unreachable; the defect is the missing lower-bound in a dispatch function that any future caller (or a future table entry typo'd negative) would turn into a wild read. Classic CWE-129 hardening.

Fix

--- a/sys/dev/video/bktr/bktr_tuner.c
+++ b/sys/dev/video/bktr/bktr_tuner.c
@@ -709,7 +709,7 @@ void    select_tuner( bktr_ptr_t bktr, int tuner_type ) {
-   if (tuner_type < Bt848_MAX_TUNER) {
+   if (tuner_type >= 0 && tuner_type < Bt848_MAX_TUNER) {
        bktr->card.tuner = &tuners[ tuner_type ];

Verification status

untested β€” requires Brooktree PCI hardware to reach any of this at runtime; the audit guest has no Brooktree/0x109e PCI device (pciconf -l clean), so /dev/bktr* never appears and select_tuner cannot execute there. Static caller enumeration above is exhaustive for this tree.

VERDICT.md
↓ download raw

VERDICT β€” DF-4361

status: untested (hardening finding; hardware-gated path) Β· impact: none demonstrated β€” defect is real but currently unreachable with an out-of-range value Β· confidence: certain.

Reproduced?

No, by design of the finding: select_tuner() lacks the lower-bound half of its range check (bktr_tuner.c:710), so a negative tuner_type would store &tuners[negative] into bktr->card.tuner, which consumers dereference (tuner->pllControl[] / tuner->bandAddrs[] bktr_tuner.c:825-826, 884-885; card.tuner->name %s printout bktr_card.c:1343-1344). An exhaustive caller enumeration for this tree shows every reachable call site passes a provably non-negative value:

  1. boot tunable path β€” masked bt848_tuner & 0xff (bktr_os.c:470, bktr_card.c:905-907);
  2. compile-time BKTR_OVERRIDE_TUNER β€” not defined in any build file;
  3. signature-table dispatch β€” single entry {card=5, tuner=9} (bktr_card.c:395-398, 862);
  4. EEPROM/GPIO derivation β€” tuner_format <= 9 into 10-entry constant tables and &7-masked GPIO switch (bktr_card.c:920-928, 1128-1152).

Hence Info (defense-in-depth), not a higher severity: the memory-unsafe half of the index check is missing in a dispatch function where a future caller, table typo, or config change (BKTR_OVERRIDE_TUNER) immediately converts it into a wild kernel read.

Runtime exercise would additionally require Brooktree PCI hardware: the audit guest (DragonFly 6.5-DEVELOPMENT x86_64, QEMU/KVM) has no 0x109e PCI device (pciconf), so /dev/bktr* never appears and select_tuner cannot run there.

Fix validation

not_testable β€” path needs the PCI card; the fix is a one-sided bound addition (tuner_type >= 0 &&) with no behavior change for any currently-valid value.

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.

(No fix.diff for this item: documented recommendation only - see Fix above.)

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

not_testable β€” needs Brooktree PCI hardware; fix is a pure lower-bound addition with no behavior change for valid values

fix diff in README.md
per-fix-DF-4361

Confirmed kernel references

Detail

Evidence (decisive lines)

README.md (code excerpt bktr_tuner.c:709-715 + full caller enumeration with path:line); VERDICT.md; guest pciconf shows no 0x109e device

PoC changes

none β€” no PoC seed; static verification only (hardware-gated path)

Verified recommended fix

Add the missing lower bound in select_tuner: if (tuner_type >= 0 && tuner_type < Bt848_MAX_TUNER)

Verdict

select_tuner() bounds-checks only the upper end (tuner_type < Bt848_MAX_TUNER) of the tuners[] dispatch index; a negative type would set bktr->card.tuner = &tuners[negative], dereferenced later for pllControl/bandAddrs and a %s name printout β€” a wild kernel read. Exhaustive caller enumeration (masked boot tunable, compile-time override undefined, constant signature/EEPROM tables) proves every current call site non-negative, so this is a defense-in-depth hardening finding (Info). Path additionally requires Brooktree PCI hardware, absent from the audit guest.