MP_ReadOtherFunPciEConfigSpace never reads RE_CSIDR (constant 0xffffffff return) -> NULL CMAC bus_space handle dereference at re(4) attach on RTL8168FP/RTL8117, plus PCIe config RMW clobbering on all CSIAR users
Summary
The CSIAR config-space read helper performs the completion handshake and then returns its initialized-to-0xffffffff local without ever reading the RE_CSIDR data register - a dropped line in the vendor-driver port; every consumer sees 0xffffffff. Chain: re.c:4456 reads 0xffffffff -> bit0 set -> bus_space_map skipped -> re_cmac_handle=NULL -> re_exit_oob calls Dash2DisableTxRx for MACFG_70-72 whose !re_dash guard is commented out -> RE_CMAC_WRITE_1 on handle NULL offset 0xF9 -> *(volatile u_int8_t *)0xF9 -> kernel page fault at attach (boot-time panic with the card installed). Collateral: all 14 live RMW consumers in re_hw_start_unlock operate on 0xffffffff and write all-ones into NIC PCIe config dwords, misconfiguring common 8168 chips and silencing UE error reporting (0xF108). Vulnerable functions confirmed compiled into the stock /boot/kernel/if_re.ko (nm proof). Hardware-gated (not unpriv-triggerable); virtio-only guest -> honest not_reproduced with a mechanical source-proof harness (ALL CHAIN LINKS VERIFIED) + kldload check. Architectural fact established: on DragonFly this 32k-line file compiles only the rtl_* register back-end (entire data path is #ifndef __DragonFly__ dead code; if_re.c is the live driver).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3570 Β· 10 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.4 KB | β raw | |
| VERDICT.md | β | 5.8 KB | β raw | |
| trigger.c | β | 1.7 KB | view raw | |
| proof.sh | β | 1.7 KB | view raw | |
| proof.log | β | 4.2 KB | view raw | |
| run.log | β | 1.0 KB | view raw | |
| env.txt | β | 256 B | view raw | |
| fix.diff | β | 1.5 KB | view raw | |
| manifest.json | β | 1.6 KB | view raw | |
| verdict.json | β | 4.5 KB | view raw |
DF-3570 β MP_ReadOtherFunPciEConfigSpace never reads RE_CSIDR (constant 0xffffffff return) => NULL CMAC bus_space handle dereference (kernel panic) at re(4) attach on RTL8168FP/RTL8117, plus silent PCIe-config clobbering on every chip using the CSIAR read-modify-write paths.
Build / Run
Nothing to compile from userland. The fault is deterministic at device attach. On a machine with an RTL8168FP / RTL8117 (MACFG_70/71/72):
# kldload if_re # or boot with the device present
Expected (unpatched): kernel page fault in Dash2DisableTx during rtl_exit_oob, before any interface registers. The serial console shows a panic with fault address 0xf9/0xf8/0xfb.
What IS verified in this pack (no such hardware on the audit guest)
./proof.sh # mechanical re-derivation of every chain link from sys/
Guest (audit target) facts
dfbsd-qemu/vm.sh run_root 'pciconf -l' # -> virtio only, NO_REALTEK_HW
nm /boot/kernel/if_re.ko # -> Dash2DisableTx,
# MP_ReadOtherFunPciEConfigSpace,
# rtl_* back-end all present
# in the shipped module
So the vulnerable code is compiled into the stock kernel module; the audit guest simply has no Realtek NIC to drive it. Status: not_testable (hardware absent), source-proven (see VERDICT.md).
DF-3570 β VERDICT
Status: not_testable (audit guest has virtio-net only; no Realtek
silicon). Source-level proof: complete and mechanical (proof.log).
The vulnerable code is confirmed compiled into the stock if_re.ko shipped
on the guest (nm evidence in env.txt), and the guest loads the module
without error β there is simply no 10ec:8168 device to trigger attach.
Root cause (one dropped line)
MP_ReadOtherFunPciEConfigSpace() β sys/dev/netif/re/re.c:31163-31192 β
performs the CSIAR config-space read handshake and then:
u_int32_t RetVal = 0xffffffff; /* :31171 */
...
do { DELAY(100); ReadDone = CSR_READ_4(sc, RE_CSIAR); Timeout++; }
while (((ReadDone & 0x80000000) == 0) && (Timeout < WaitCount));
DELAY(50);
return RetVal; /* :31191 β never reads RE_CSIDR */
RetVal is never assigned the contents of RE_CSIDR (0x64), so every
call returns the constant 0xffffffff. The write twin
(MP_WriteOtherFunPciEConfigSpace, :31132-31161) does use RE_CSIDR
(:31148), which makes the omission unambiguous β a porting drop of the
upstream RetVal = RTL_R32(PCI_CSIDR); line.
Impact chain 1 β NULL CMAC handle => attach-time kernel panic
- re.c:4413-4417 β
HwSuppDashVer = 3for MACFG_70/71/72 (RTL8168FP / RTL8117 family). - re.c:4448-4449 β
sc->re_dash = re_check_dash(sc)(OCP 0x128 bit0). - re.c:4456 β
CmacMemPhysAddress = MP_ReadOtherFunPciEConfigSpace(sc,0,0xf018)== 0xffffffff (constant). - re.c:4457 β
if (!(CmacMemPhysAddress & BIT_0))is FALSE for 0xffffffff, so the whole mapping block (:4458-4473) incl.bus_space_map()(:4468) is skipped andre_mapped_cmac_handlestays NULL (softc is bzeroed by if_re.c's attach). This holds for DASH and non-DASH SKUs alike β for non-DASH SKUs theif (sc->re_dash)gate (:4451) skips mapping anyway. - re.c:4484-4489 β for MACFG_70/71/72 the softc unconditionally does
sc->re_cmac_handle = sc->re_mapped_cmac_handle(NULL) andsc->re_cmac_tag = sc->re_mapped_cmac_tag(0). - if_re.c:772 β attach calls
rtl_exit_oob(sc)β re.c:3588-3596 β for MACFG_61/62/67/70/71/72 βDash2DisableTxRx(sc). - re.c:3445-3453 β
Dash2DisableTx(): theif (!sc->re_dash) return;guard is commented out (:3447), andHW_DASH_SUPPORT_TYPE_3(sc)is true for MACFG_70-72, so it executesRE_CMAC_WRITE_1(sc, RE_CMAC_IBCR2, RE_CMAC_READ_1(sc, RE_CMAC_IBCR2) & ~BIT_0). - On DragonFly the CMAC macros (re_dragonfly.h:43-54) are raw
bus_space_*calls, and x86_64bus_space_read_1(sys/cpu/x86_64/include/bus_dma.h:135-141) is*(volatile u_int8_t *)(handle + offset)for memory tags β read/write of virtual address 0xF9/0xF8/0xFB β kernel page fault at attach, before the interface exists. Deterministic for every MACFG_70/71/72 device; boot with the card, or devd/kldload with it present.
Impact chain 2 β PCIe config-space clobbering (all CSIAR RMW users)
Live read-modify-write consumers of the broken read all receive 0xffffffff:
- re.c:3891-3893 (re_hw_init): writes 0xffffffff to config 0xF108 (PCIE uncorrectable-error mask) β masks all UE reporting for the NIC.
- re.c:5765, 5806, 5938, 5982, 6059, 6125, 6227, 6318, 6383, 6470, 6585,
6598, 6792, 6952 (re_hw_start_unlock, per-MACFG branches for
8168C/D/E/V): e.g.
Data32 = 0xffffffff & 0xC0FFFFFF | (0x3F<<24)= 0xffffffff β the "preserve bits 23:0" intent of the RMW is defeated and the NIC's config dword is written all-ones (clock-gating / max-payload related setup). - re.c:7414 (re_hw_start_unlock_8125): DASH descriptor-format select made from garbage.
Reliability/functional misconfiguration of the device; no kernel memory corruption.
Threat model / severity
- The panic is NOT triggerable by an unprivileged local user β it fires deterministically when the driver attaches to MACFG_70-72 silicon (device present at boot, devd autoload, or explicit kldload by root). Severity therefore Low ("requires specific hardware"), but certain: with an RTL8117/8168FP installed, the machine panics during re(4) attach.
- The config clobbering affects common 8168 chips but stays inside the device's own config space.
- No info leak, no privilege boundary crossed, no remote reach.
Why not reproduced on the guest
pciconf -l on the audit QEMU guest shows only virtio devices
(NO_REALTEK_HW). The RTL8168FP MMIO/CSIAR registers cannot be driven, so
the path cannot execute. kldload if_re succeeds and is a no-op (no
matching PCI ID). Honest classification: not_testable / hardware absent,
not false_positive β the chain is source-proven link by link (proof.log)
and the vulnerable functions are present in the shipped module binary
(env.txt).
Fix (fix.diff)
- Restore the dropped data-register read:
RetVal = CSR_READ_4(sc, RE_CSIDR);after the handshake inMP_ReadOtherFunPciEConfigSpace. - Defense in depth for the NULL-handle deref, so a DASH detection mistake
can never fault the kernel: bail out of
Dash2DisableTx/Dash2DisableRxwhensc->re_cmac_handle == 0, and skip the CMAC path inre_init_software_variable's MACFG_70-72 assignment if unmapped.
Fix validation: not_testable β validating the runtime effect requires RTL8168FP hardware (panic present before patch, gone after). The patch is two-line plus guards, compile-checkable by inspection against the write twin at :31148; no kernel build was performed on the guest for this Low-severity, hardware-gated finding (fix_status=not_testable).
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 restores the RE_CSIDR read (mirrors the write path at re.c:31148) and adds NULL-handle guards so Dash2* can never fault through an unmapped CMAC window. Runtime before/after validation requires RTL8168FP/RTL8117 hardware which the audit guest does not have (virtio-net only); validation was therefore not possible and is recorded as not_testable rather than claimed.
fix.diff (git-apply-able vs sys/dev/netif/re/re.c); VERDICT.md 'Fix' section; proof.log chain link [1] would flip to FAIL once the read is restored (guard built into proof.sh).
Confirmed kernel references
Detail
Evidence (decisive lines)
proof.log (mechanical re-derivation of every chain link; ALL CHAIN LINKS VERIFIED); run.log + env.txt (guest uname 6.5-DEVELOPMENT, pciconf virtio-only, nm shows MP_ReadOtherFunPciEConfigSpace/Dash2DisableTx/re_rar_set/rtl_set_eaddr in shipped if_re.ko); VERDICT.md (full narrative with path:line); fix.diff (restore RetVal = CSR_READ_4(sc, RE_CSIDR); NULL-handle guards in Dash2*/MACFG_70-72 assignment)
PoC changes
No runnable PoC exists for userland (fault is at device attach); trigger.c documents the trigger; proof.sh replaces the runtime PoC with a mechanical source-proof harness; guest evidence limited to module symbol presence + kldload per the orchestrator's hardware-unreachability guidance.
Verified recommended fix
Add the dropped data-register read (RetVal = CSR_READ_4(sc, RE_CSIDR)) in MP_ReadOtherFunPciEConfigSpace and guard Dash2DisableTx/Rx plus the MACFG_70-72 cmac assignment against a NULL re_cmac_handle.
Verdict
Not runtime-reproducible on the audit guest (virtio-net only, NO_REALTEK_HW in env.txt/run.log); recorded honestly instead of fabricated. Source-level proof is complete and mechanical: MP_ReadOtherFunPciEConfigSpace (re.c:31163-31192) initializes RetVal=0xffffffff at :31171 and returns it at :31191 without ever reading the RE_CSIDR data register (the write twin uses it at :31148), so every caller gets the constant 0xffffffff. Consequence 1 (panic): re_init_software_variable:4456-4457 sees bit0 set in 0xffffffff, skips bus_space_map(:4468); for MACFG_70/71/72 (RTL8168FP/RTL8117, HwSuppDashVer=3 per :4413-4417) re_cmac_handle is assigned the NULL re_mapped_cmac_handle at :4487 (also NULL for non-DASH SKUs since mapping is gated by sc->re_dash at :4451); re_exit_oob:3588-3596 then calls Dash2DisableTxRx at attach (if_re.c:772), whose !re_dash guard is commented out (:3447), producing RE_CMAC_READ_1/WRITE_1 on bus_space handle NULL at offset 0xF8/0xF9/0xFB β on x86_64 that is (volatile u_int8_t )(0+0xF9) (bus_dma.h:135-141) β a deterministic NULL-page kernel fault at driver attach on that silicon. Consequence 2 (misconfiguration): all live CSIAR read-modify-write consumers (re.c:3891-3893; 14 sites in re_hw_start_unlock incl. 5765/5806/.../6952; 7414 in re_hw_start_unlock_8125) RMW with 0xffffffff, clobbering NIC PCIe config dwords meant to be partially preserved (e.g. 5765-5768 yields 0xffffffff). nm proves the vulnerable functions are compiled into the stock /boot/kernel/if_re.ko on the guest and kldload if_re succeeds (no device match). Severity Low: hardware-gated, not unprivileged-user-triggerable; real-world effect is a boot-time panic on machines with an RTL8117/8168FP and wrong PCIe config on common 8168 chips.
No comments yet.