64-bit file-offset truncation family beyond DF-0833: udf_read's int offset, and udf_strategy/udf_bmap passing off_t bio_offset/loffset into udf_bmap_internal's uint32_t parameter
Summary
udf_bmap_internal takes uint32_t offset (:1066) while its callers hold 64-bit file offsets: udf_strategy truncates bio->bio_offset (off_t) at :812-813 and udf_bmap truncates a_loffset at :845; udf_read additionally narrows uio->uio_offset into the int 'offset' at :399 (independent of DF-0833's inf_len truncation). For files >4GB (dual-layer UDF video media), reads/mmap fetch data from offset mod 2^32 - cross-region data disclosure within the volume and wrong data; udf_read can also feed a negative offset into the bmap walk (fails EINVAL or wraps). Correctness/limited-disclosure impact; FreeBSD's udf_bmap_internal takes off_t. Not PoC-verified (needs >4GB sparse layout for marginal Low payoff); code path plain from source. Fix: widen to off_t through the chain. [VERIFIED pass2: empirically unreachable proven with crafted 5.37GB-extent image - int fsize truncation gates reads at 2^31 and mmap of ANY udf file is EINVAL since udf never calls vinitvmio; latent width bug documented]
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3105 Β· 10 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 347 B | β raw | |
| VERDICT.md | β | 1.5 KB | β raw | |
| df3105.udf | β | 8.0 MB | β download | |
| df3105_craft.py | β | 2.1 KB | view raw | |
| df3105c.c | β | 829 B | view raw | |
| env.txt | β | 248 B | view raw | |
| fix.diff | β | 167 B | view raw | |
| manifest.json | β | 652 B | view raw | |
| run.log | β | 382 B | view raw | |
| verdict.json | β | 1.9 KB | view raw |
DF-3105 - 64-bit file-offset truncation family: udf_read int offset; udf_bmap/strategy off_t into uint32 param
Severity Low | verdict: not_reproduced | impact: none
Reproduce
Sources in this directory; build with cc -O2 -o <bin> <src> -pthread on the guest.
See VERDICT.md for the full narrative and run.log for the decisive output.
DF-3105 verification
Kernel: DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64
Empirically refuted as unreachable on the current tree, with a crafted >4GB image proving both gates. A UDF image with a 5.37GB file (5x0x3FFFF000 extents + 8KB, markers 0xBB/0x55/0xCC placed) mounts fine and stat reports the full 64-bit size (5368696832), but: (1) read() at offsets >= 2^31 never reaches udf_bmap_internal - the int fsize truncation (udf_read :396, DF-0833 territory) clamps the loop first (pread at 0x100000000 returns 0/EOF silently); (2) mmap of ANY UDF file returns EINVAL because the filesystem never calls vinitvmio - vp->v_object stays NULL and vm_mmap.c:271 rejects (verified with mmap at offset 0). With the only two callers (udf_read path gated below 2^31 by the int fsize, mmap disabled entirely) unable to present an offset >= 2^32, the uint32 parameter truncation at udf_bmap_internal:1066 is dead on DragonFly today. The width bug is real latent code (FreeBSD takes off_t).
Kernel references
- sys/vfs/udf/udf_vnops.c:399
- sys/vfs/udf/udf_vnops.c:845
- sys/vfs/udf/udf_vnops.c:1066
- sys/vm/vm_mmap.c:271
Fix
See fix.diff.
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_testableConfirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md + run.log + sources
PoC changes
adjusted from finding sketch to guest syscall/layout reality
Verified recommended fix
diff: widen udf_bmap_internal/udf_readatoffset to off_t and fix the int fsize in udf_read (overlaps DF-0833); add vinitvmio in udf_vget if mmap support is intended.
Verdict
Empirically refuted as unreachable on the current tree, with a crafted >4GB image proving both gates. A UDF image with a 5.37GB file (5x0x3FFFF000 extents + 8KB, markers 0xBB/0x55/0xCC placed) mounts fine and stat reports the full 64-bit size (5368696832), but: (1) read() at offsets >= 2^31 never reaches udf_bmap_internal - the int fsize truncation (udf_read :396, DF-0833 territory) clamps the loop first (pread at 0x100000000 returns 0/EOF silently); (2) mmap of ANY UDF file returns EINVAL because the filesystem never calls vinitvmio - vp->v_object stays NULL and vm_mmap.c:271 rejects (verified with mmap at offset 0). With the only two callers (udf_read path gated below 2^31 by the int fsize, mmap disabled entirely) unable to present an offset >= 2^32, the uint32 parameter truncation at udf_bmap_internal:1066 is dead on DragonFly today. The width bug is real latent code (FreeBSD takes off_t).
No comments yet.