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

vniocattach_file missing positive vn_size check -> signed integer overflow and bogus disk geometry

Summary

Swap-backed attach validates vn_size>0 (:617) but file-backed attach does NOT. vn.c:559-560 if(vio->vn_size) vn->sc_size=vio->vn_size*PAGE_SIZE/vn->sc_secsize. vn_size int64_t PAGE_SIZE int signed multiplication overflows for large magnitudes. Negative vn_size negative product divided by 512 negative quotient reinterpreted as huge u_int64 in sc_size. Bogus sc_size published as disk media size used to derive cylinder geometry with truncation to u_int. Contrast swap path guards vn_size<=0 EDOM. SYSCAP_RESTRICTEDROOT gated root-only. Impact logic/DoS bogus capacity geometry garbage not memory corruption. [VERIFIED pass2: reproduced LIVE no rig - VNIOCATTACH vn_size -1 succeeds and diskinfo publishes size 0xfffffffffffff000 through the disk layer; range-guard fix compile-validated in vn module]

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2527 Β· 8 files
FileTypeDescriptionSize
README.md β€” 944 B ↓ raw
VERDICT.md β€” 1.9 KB ↓ raw
build.sh β€” 99 B view raw
run.log β€” 184 B view raw
env.txt β€” 963 B view raw
fix.diff β€” 1.7 KB view raw
manifest.json β€” 625 B view raw
verdict.json β€” 2.4 KB view raw

DF-2527 -- vniocattach_file missing vn_size validation (negative/huge -> bogus geometry)

Verification used the shared rig tree at /root/rigs on the audit guest (see manifest). The rig for this finding: None (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

./vn_size -1 /root/vnfile; diskinfo /dev/vn3

Expected

run.log: attach vn_size=-1 OK -> /dev/vn3; diskinfo size=0xfffffffffffff000.

Fix validation

fix.diff rejects vn_size < 0 or > INT64_MAX/PAGE_SIZE with EDOM (mirrors the swap-path guard); vn module compiled clean with the fix.

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

VERDICT.md
↓ download raw

DF-2527 verdict -- vniocattach_file missing vn_size validation (negative/huge -> bogus geometry)

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

LIVE reproduction on the stock kernel through the real ioctl path (no rig): a root VNIOCATTACH with vn_size = -1 pages succeeded and diskinfo /dev/vn3 reported size=0xfffffffffffff000 (17179869184.00 GB) - the sign-extended -1*PAGE_SIZE/512 quotient published as the media size (vn.c:559-560 computes vn->sc_size = vio->vn_size * PAGE_SIZE / sc_secsize with only an if(vio->vn_size) guard; the swap path validates <= 0 at :617, the file path does not). d_media_blocks=0xfffffffffffffff8 propagates through the disk layer (diskinfo renders the bogus capacity; d_ncylinders truncates to u_int per the finding). SYSCAP_RESTRICTEDROOT-gated: root-only as filed. Fix (range-check like the swap path) compile-validated in the vn module build; a patched-kernel live A/B was out of scope for this batch (vn is compiled into the stock kernel) - the fix is the same guard the swap path has proven for years.

Evidence (decisive lines)

attach vn_size=-1 (pages): OK -> /dev/vn3 vn3: covering /root/vnfile on #B255:0x0, inode 96874 /dev/vn3 blksize=512 offset=0x000000000000 size=0xfffffffffffff000 17179869184.00 GB

Exploit chain / privesc assessment

root-only logic/DoS: bogus capacity published (partitioning/data-corruption surprises); no memory corruption.

Fix + A/B

fix.diff rejects vn_size < 0 or > INT64_MAX/PAGE_SIZE with EDOM (mirrors the swap-path guard); vn module compiled clean with the fix.

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-2527

Confirmed kernel references

Detail

Exploit chain

root-only logic/DoS: bogus capacity published (partitioning/data-corruption surprises); no memory corruption.

Evidence (decisive lines)

run.log: attach vn_size=-1 OK -> /dev/vn3; diskinfo size=0xfffffffffffff000.

PoC changes

live guest test program (vn_size.c) issuing the real ioctl.

Verified recommended fix

range-check vn_size (0 < vn_size <= INT64_MAX/PAGE_SIZE) in the file path

Verdict

LIVE reproduction on the stock kernel through the real ioctl path (no rig): a root VNIOCATTACH with vn_size = -1 pages succeeded and diskinfo /dev/vn3 reported size=0xfffffffffffff000 (17179869184.00 GB) - the sign-extended -1*PAGE_SIZE/512 quotient published as the media size (vn.c:559-560 computes vn->sc_size = vio->vn_size * PAGE_SIZE / sc_secsize with only an if(vio->vn_size) guard; the swap path validates <= 0 at :617, the file path does not). d_media_blocks=0xfffffffffffffff8 propagates through the disk layer (diskinfo renders the bogus capacity; d_ncylinders truncates to u_int per the finding). SYSCAP_RESTRICTEDROOT-gated: root-only as filed. Fix (range-check like the swap path) compile-validated in the vn module build; a patched-kernel live A/B was out of scope for this batch (vn is compiled into the stock kernel) - the fix is the same guard the swap path has proven for years.