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

oce_img_flashing_required bcmp's the image CRC at a fixed ~1.31 MB offset with no fw->datasize check β€” sibling OOB-read site missed by DF-1573

Summary

The crc offset is computed from constants and bcmp'd against fw->data without any bounds check, BEFORE the image-size gate at :389. A ~4KB crafted image that passes the build/imageid/cookie checks makes the kernel read ~1.3MB past the firmware allocation. Guard-page replica on the guest (read at +1310892 -> SIGSEGV). Datasize-plumbing fix (3 hunks, syntax-validated).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4385 Β· 11 files
FileTypeDescriptionSize
README.md β€” 1.5 KB ↓ raw
VERDICT.md β€” 3.2 KB ↓ raw
trigger.c β€” 2.0 KB view raw
build.sh β€” 88 B view raw
run.sh β€” 89 B view raw
run.log β€” 136 B view raw
hw_probe.log β€” 34 B view raw
fix.diff β€” 1.4 KB view raw
env.txt β€” 478 B view raw
manifest.json β€” 793 B view raw
verdict.json β€” 2.3 KB view raw

DF-4385 β€” oce_img_flashing_required reads 4 bytes at a fixed ~1.31 MB firmware offset with no bounds check

  • File: sys/dev/netif/oce/oce_sysctl.c:449-472 (called from :334)
  • Class: CWE-125 out-of-bounds read (kernel), firmware-image-shaped
  • Threat model: root writes hw.oceN.fw_upgrade=<name>; the referenced image was registered via firmware_get(). The image bytes are attacker- controlled if the file placed in /boot/kernel is hostile. Sibling of DF-1573 (which enumerated sites 257, 263, 265-273, 297, 322, 515 β€” this site was missed).

Build / run

No Emulex NIC on the verification guest (run.log: 0 19a2: PCI devices, no hw.oce sysctl tree), so the kernel path is hardware-gated. The pack contains:

  • trigger.c β€” host-independent replica of the exact arithmetic (crc_offset = hdrs_size + img_offset + img_size - 4) showing the read lands ~1.31 MB into an image that may be a few KB, plus the OOB fault demonstration via mmap guard page.
  • run.sh β€” guest hardware-gating probe (produces run.log).
  • fix.diff β€” targeted fix (pass fw->datasize in, validate before bcmp).

Expected

./trigger (on any UNIX-y host with cc): prints the computed read offset, then SIGSEGV: OOB read when the CRC read crosses the guard page β€” proving the kernel would read past the firmware buffer on a truncated-but-cookie- valid image. On the audit guest without oce hardware the path is dormant; the demonstration is the replica + source trace in VERDICT.md.

VERDICT.md
↓ download raw

DF-4385 VERDICT

Finding

oce_img_flashing_required() computes the CRC location of an image component from constants plus the parsed header sizes and reads 4 bytes there without ever consulting fw->datasize:

Caller: oce_be3_flashdata() case IMG_REDBOOT (:334) passes img_offset=262144, img_size=1048576, hdrs_size=bin_offset β€” so the read address is fw->data + bin_offset + 1310716. The image-size gate that would have caught this (:389, p + size > fw->data + fw->datasize) executes only after the switch β€” i.e. after oce_img_flashing_required() has already read.

Reachability: root writes hw.oceN.fw_upgrade=<image> (oce_sys_fwupgrade, :208); firmware_get() must resolve the name (registered from /boot/kernel). Every prior gate is satisfiable with a tiny crafted file: build[0]=='3' + one image_hdr with imageid==1 (:265-273) + a 32-byte cookie match anywhere after the headers (:297-303). A 4 KB file passes all three, then the driver reads at +1.31 MB β€” ~1.3 MB past the end of the firmware malloc() allocation (kernel heap OOB read; page-granular fault possible if the walk crosses an unmapped boundary).

Relationship to DF-1573 (do-not-re-report boundary)

DF-1573 enumerated its sites precisely: 257, 263, 265-273, 297, 322 (BE3 flash path) and 515 (Lancer size -= data_written). oce_img_flashing_required (449-472) is a separate function executing before every gate DF-1573 relies on, and is not in that list. This is the missed sibling site, not a re-derivation.

Verification (Phase V)

Kernel-path reproduction is hardware-gated: this guest has no Emulex oce(4) device (hw_probe.log: zero 19a2: PCI devices, no hw.oce sysctl tree), so hw.oceN.fw_upgrade does not exist to write. Demonstrated instead:

  • trigger.c β€” exact-arithmetic replica with a guard page: on the guest, bcmp at fw->data + 1310892 into a 4096-byte readable region faults (run.log: Segmentation fault, exit 139). This proves the primitive: the kernel dereference is ~1.3 MB past the allocation.
  • fix.diff (3 hunks: prototype, call site, definition) passes git apply --check against the pristine tree, and the patched oce_sysctl.c syntax-checks cleanly with the guest's kernel toolchain (cc 8.3 -nostdinc, kernel include set, 0 errors).

Bottom line

Real, code-certain, sibling-site OOB read on the root-only firmware upgrade path β€” same severity class as DF-1573 (Low: requires root + hostile image file, defense-in-depth against malicious firmware). Fix is one bounds check; fix.diff is line-accurate and compile-validated. Full runtime PoC requires an Emulex BE3 adapter.

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_testable
baseline no→ patch + rebuild →patched clean

not_testable at runtime (no oce NIC on guest); fix.diff (3 hunks) git-apply --check OK against pristine sys/ and syntax-validated with the guest kernel toolchain (0 errors).

fix.diff; guest cc -fsyntax-only of patched oce_sysctl.c: 0 errors.
↓ fix.diffDragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 x86_64

Confirmed kernel references

Detail

Evidence (decisive lines)

run.log (guest: read at +1310892 of 4096-byte image -> SIGSEGV), trigger.c (exact arithmetic replica), VERDICT.md (path:line trace), fix.diff (git apply --check OK, syntax-validated on guest toolchain)

PoC changes

n/a - pass-2 finding authored fresh; replica written for this pack

Verified recommended fix

pass fw->datasize into oce_img_flashing_required and reject hdrs_size+img_offset+img_size > fw_datasize before the bcmp

Verdict

oce_img_flashing_required (oce_sysctl.c:449-472) bcmp's 4 bytes at fw->data + bin_offset + 262144 + 1048576 - 4 with no fw->datasize check, executing before the size gate at :389; a ~4KB cookie-valid hostile image makes the kernel read ~1.3MB past the firmware allocation. Sibling site missed by DF-1573 (which enumerated 257/263/265-273/297/322/515 only). Kernel-path run is hardware-gated (no 19a2: PCI device on guest, hw_probe.log); primitive proven by guard-page replica (SIGSEGV exit 139, run.log) and source trace. Root-only + hostile-file threat model: Low, defense-in-depth.