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

daddr_t (int32) truncation of block address for >1TB MMC/SD media

Summary

mmcsd_rw and mmcsd_delete declare block/end as daddr_t which is __int32_t. For SDXC/large eMMC beyond 2^31 sectors (~1TiB at 512B) bio->bio_offset/sz silently truncates to possibly-negative 32-bit value producing wrong MMC command arguments and depending on card behavior either spurious EIO or data corruption at wrong sector. block=bio->bio_offset/sz assignment truncates to int32. cmd.arg=block reinterprets negative as uint32 0xFFFFFFFF sent to card. Affects mmcsd_delete too. [VERIFIED pass2: reproduced - daddr_t int32 truncation makes 2TiB media issue sector 0 and 4TiB issue 0x3039 wrong-sector MMC commands; reject-beyond-32-bit fix A/B EIO]

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2480 Β· 8 files
FileTypeDescriptionSize
README.md β€” 1.0 KB ↓ raw
VERDICT.md β€” 2.0 KB ↓ raw
build.sh β€” 99 B view raw
run.log β€” 488 B view raw
env.txt β€” 963 B view raw
fix.diff β€” 1.1 KB view raw
manifest.json β€” 800 B view raw
verdict.json β€” 2.3 KB view raw

DF-2480 -- mmcsd daddr_t (int32) truncation of block addresses past 1 TiB

Verification used the shared rig tree at /root/rigs on the audit guest (see manifest). The rig for this finding: dfv_mmcsd (rig.c = harness, gen.sh = verbatim extractor, dfv_*_extract.h = generated production text). The decisive outputs below were captured live on the guest during the 2026-10-24 verification session; full session logs are summarized per run.

Build

sh build.sh            # extracts verbatim driver text + builds the KLD

Run (guest, root)

kldload ./dfv_rig.ko

kldload dfv_mmcsd.ko; for i in 0 1 2 3 4; do sysctl kern.dfv_mmcsd_run=$i >/dev/null; sysctl -n kern.dfv_mmcsd_status; done

Expected

run.log: 2TiB -> cmd.arg=0x00000000 (expected 0x100000000) TRUNCATED/WRONG; 4TiB -> 0x00003039; control 0x3e8 CORRECT.

Fix validation

fix.diff switches to u64 block math and rejects beyond-32-bit blocks; A/B shows no wrong-sector command.

Verdict: reproduced / impact=corruption (see verdict.json, VERDICT.md)

VERDICT.md
↓ download raw

DF-2480 verdict -- mmcsd daddr_t (int32) truncation of block addresses past 1 TiB

status: reproduced reproduced: 1 impact: corruption confidence: certain attempts: 1 runtime_sec: 600

The verbatim mmcsd_rw/mmcsd_delete (extracted whole) assign bio->bio_offset/sz into daddr_t (= __int32_t, sys/types.h:80) block/end. Control (1000 sectors): cmd.arg correct. At exactly 1 TiB the arg still bit-matches (0x80000000). At 2 TiB the u64 block 0x100000000 arrives at the card as cmd.arg=0x00000000, and at 4 TiB+12345 sectors as 0x00003039 - the READ/WRITE/ERASE command is issued against the WRONG SECTOR (silent data corruption on >1TiB SDXC/eMMC media, or spurious EIO depending on card). mmcsd_delete shares the math (cited :534). Fix (64-bit locals + reject blocks beyond the 32-bit MMC argument with EIO) A/B: no MMC command is issued for the hostile offsets (opcode/arg unchanged, transfer skipped).

Evidence (decisive lines)

DF2480[0]: bio_offset=000000000007d000 -> u64 block=1000; cmd.arg=0x000003e8 (CORRECT) DF2480[2]: bio_offset=0000020000000000 (2048 GiB) -> u64 block=4294967296 (0x100000000); verbatim code sent cmd.arg=0x00000000 (TRUNCATED/WRONG) DF2480[3]: bio_offset=0000040000607200 -> u64 block=0x200003039; verbatim sent cmd.arg=0x00003039 (TRUNCATED/WRONG) DF2480[4]: erase path (mmcsd_delete) same math --- fixed source A/B --- DF2480[2]: cmd.opcode=0 (NO command issued - bio rejected with EIO)

Exploit chain / privesc assessment

no attacker needed - media-size correctness bug; corruption affects data at wrong sectors on large cards.

Fix + A/B

fix.diff switches to u64 block math and rejects beyond-32-bit blocks; A/B shows no wrong-sector command.

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

fixed
↓ fix.diffper-fix-DF-2480

Confirmed kernel references

Detail

Exploit chain

no attacker needed - media-size correctness bug; corruption affects data at wrong sectors on large cards.

Evidence (decisive lines)

run.log: 2TiB -> cmd.arg=0x00000000 (expected 0x100000000) TRUNCATED/WRONG; 4TiB -> 0x00003039; control 0x3e8 CORRECT.

PoC changes

MMCBUS_WAIT_FOR_REQUEST interposed to capture cmd.arg; device reports success.

Verified recommended fix

64-bit block math and reject blocks beyond the 32-bit MMC argument

Verdict

The verbatim mmcsd_rw/mmcsd_delete (extracted whole) assign bio->bio_offset/sz into daddr_t (= __int32_t, sys/types.h:80) block/end. Control (1000 sectors): cmd.arg correct. At exactly 1 TiB the arg still bit-matches (0x80000000). At 2 TiB the u64 block 0x100000000 arrives at the card as cmd.arg=0x00000000, and at 4 TiB+12345 sectors as 0x00003039 - the READ/WRITE/ERASE command is issued against the WRONG SECTOR (silent data corruption on >1TiB SDXC/eMMC media, or spurious EIO depending on card). mmcsd_delete shares the math (cited :534). Fix (64-bit locals + reject blocks beyond the 32-bit MMC argument with EIO) A/B: no MMC command is issued for the hostile offsets (opcode/arg unchanged, transfer skipped).