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

high_sierra flag is sticky β€” type confusion when descriptors are mixed in crafted ISO

Summary

cd9660_vfsops.c:334-340 high_sierra=1 inside loop when any descriptor matches Sierra id. Never reset. :347-349 pri and pri_sierra set to SAME buffer. :396-417 high_sierra?pri_sierra->FIELD:pri->FIELD reads standard PVD at Sierra offsets. Crafted ISO: pre-PVD descriptor bytes 10-14=CDROM then standard PVD at next sector. high_sierra sticky=1. logical_block_size from path_table_size bytes volume_space_size from unused3 bytes root_extent from volume_set_id bytes. All bread device-bounded no OOB in this file but attacker-chosen metadata drives downstream parsing. Fix: else high_sierra=0 when current descriptor matches ISO_STANDARD_ID.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-0853 Β· 14 files
FileTypeDescriptionSize
make_crafted_iso.c trigger-source Builds a 100-sector crafted ISO: Sierra decoy descriptor sets high_sierra=1; subsequent Standard PVD is then parsed at Sierra offsets 6.1 KB view raw
build.sh build-script cc -O2 -o make_crafted_iso make_crafted_iso.c 188 B view raw
run.sh run-script Generate ISO, vnconfig, mount -t cd9660, observe dmesg for 'cd9660: High Sierra Format' 1.3 KB view raw
build.log build-log ISO-generator compile output, CC_EXIT=0 10 B view raw
run.log run-log Patched-kernel decisive run: MOUNT_RC=0, high-sierra-count=0 354 B view raw
run.baseline.log run-log Unpatched #0 baseline: MOUNT_RC=0, 'cd9660: High Sierra Format' printed, count=1 630 B view raw
fix_build.log build-log Full nativekernel build of single-fix kernel, NK_DONE rc=0 5.6 MB ↓ download
panic.txt panic-signature N/A -- no panic; type confusion only (CWE-704) 453 B view raw
env.txt environment uname, cc version, sysctls 274 B view raw
fix.diff suggested-fix Reset high_sierra=0 when descriptor matches ISO_STANDARD_ID (else branch). git-apply-able, single hunk. 395 B view raw
VERDICT.md verdict Full narrative: mechanism, reproduction, fix validation 6.5 KB ↓ raw
README.md readme Folder overview, build/run/expected, threat model 4.2 KB ↓ raw
../fix_build_combined.log build-log Combined 41-finding kernel build (rc=0, -Werror clean) 5.6 MB ↓ download
../fix_build_summary.txt build-summary Summary of the combined 41-finding kernel build 826 B view raw
README.md readme Folder overview, build/run/expected, threat model
↓ download raw

DF-0853 β€” PoC evidence pack

Bug

sys/vfs/isofs/cd9660/cd9660_vfsops.c iso_mountfs(): the high_sierra flag is set to 1 whenever any volume descriptor matches the Sierra id ("CDROM") at :340 but is never reset when a later descriptor matches the Standard ISO9660 id ("CD001"). The flag is then consulted at :342 (to pick vdp->type vs vdp->type_sierra) and at :396-417 (to pick pri vs pri_sierra field offsets). Since pri and pri_sierra are both casts of the same buffer (:347-349), reading the wrong one parses a Standard ISO9660 PVD at Sierra offsets β€” classic type confusion. The kernel then logs cd9660: High Sierra Format (:503) and sets iso_ftype = ISO_FTYPE_HIGH_SIERRA for an image whose actual primary descriptor is Standard ISO9660.

Reachability / threat model

  • mount -t cd9660 requires either VREAD on the device node or SYSCAP_RESTRICTEDROOT (cd9660_vfsops.c:235-243). With vfs.usermount=1 and a root-created, attacker-owned image attached via vnconfig, an unprivileged user can reach this path β€” i.e. the realistic "admin handed the user a mountable ISO" precondition. The bug is independent of privilege: the type confusion fires whenever the crafted image is parsed.
  • No memory-corruption primitive is acquired: all bread()s are device-bounded and the bcopy(rootp, isomp->root, 34) stays inside the 2048-byte descriptor buffer. The damage is misinterpretation of metadata (wrong logical_block_size, volume_space_size, root_extent, root_size, and iso_ftype), which then drives different downstream parsing routines in cd9660_vnops.c.

PoC

make_crafted_iso.c emits a 100-sector image: - sector 16 β€” Sierra decoy: id_sierra="CDROM" β†’ sets high_sierra=1; type_sierra=3 β†’ switch default-case, not primary, not end. - sector 17 β€” Standard ISO9660 PVD: id="CD001" β†’ standard match, does not touch high_sierra; system_id[0]=1 so the sticky vdp->type_sierra read returns ISO_VD_PRIMARY. Bytes 136-137 are forced to 0x00 0x08 so the Sierra-cast logical_block_size decodes to 2048, passing the DEV_BSIZE..MAXBSIZE power-of-2 validation at :401 and letting the mount succeed. - sector 18 β€” Standard VD_END: system_id[0]=255 so type_sierra read returns ISO_VD_END, exits the loop.

Build

cc -O2 -o make_crafted_iso make_crafted_iso.c

Run (as root; or as maxx with vfs.usermount=1 + chowned device)

./make_crafted_iso crafted.iso
vnconfig -c vn0 ./crafted.iso
mkdir -p /mnt/df0853
mount -t cd9660 -o ro /dev/vn0 /mnt/df0853     # rc=0, mount succeeds
dmesg | tail                                   # prints "cd9660: High Sierra Format"
umount /mnt/df0853
vnconfig -u vn0

Expected (bug present, unpatched #0)

cd9660: High Sierra Format

The kernel misclassifies a Standard ISO9660 image as High Sierra β€” observable proof of the type confusion. iso_ftype = ISO_FTYPE_HIGH_SIERRA is set despite the actual PVD being Standard.

Expected (FIXED, #1)

Mount still succeeds (the PVD is a valid Standard ISO9660 image) but no cd9660: High Sierra Format message is printed: high_sierra is correctly reset to 0 when the Standard descriptor is recognised.

Reproduce helpers

  • build.sh β€” compile the ISO generator.
  • run.sh β€” generate ISO, attach via vnconfig, mount, dump dmesg tail, unmount. Prints HIGH_SIERRA_COUNT=N so you can compare unpatched (>=1) vs patched (0).

Impact assessment

  • Class: type confusion / incorrect type conversion (CWE-704) β€” not memory corruption. No OOB, no UAF, no write primitive.
  • Ceiling: kernel misinterprets attacker-chosen ISO metadata fields (logical_block_size, volume_space_size, root_extent, root_size) at the wrong struct offsets, and selects ISO_FTYPE_HIGH_SIERRA parsing paths for a Standard ISO9660 image. In our test this manifested as ls returning ENOTDIR because root_extent was misread; no panic in 3+ runs.
  • Severity: Low (matches finding classification). Reachable from an unprivileged user only under the vfs.usermount=1 + chowned-image precondition, and yields no privilege or memory-corruption primitive β€” only metadata-driven misbehaviour on the attacker's own mount.
VERDICT.md verdict Full narrative: mechanism, reproduction, fix validation
↓ download raw

DF-0853 β€” VERDICT

Verdict: REPRODUCED (and FIX VALIDATED on a built & booted single-fix kernel).

Mechanism (trigger β†’ primitive β†’ effect)

iso_mountfs() in sys/vfs/isofs/cd9660/cd9660_vfsops.c walks the volume descriptor sequence (sectors 16..100, :326-384). For each descriptor:

/* :334-341 */
if (bcmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) != 0) {
    if (bcmp (vdp->id_sierra, ISO_SIERRA_ID,
              sizeof vdp->id) != 0) {
        error = EINVAL;
        goto out;
    } else
        high_sierra = 1;          /* <-- set but NEVER reset */
}
switch (isonum_711 (high_sierra? vdp->type_sierra: vdp->type)){
case ISO_VD_PRIMARY:
    if (pribp == NULL) {
        pribp = bp; bp = NULL;
        pri       = (struct iso_primary_descriptor *)vdp;
        pri_sierra= (struct iso_sierra_primary_descriptor *)vdp;  /* SAME buffer */
    }
    break;

high_sierra is initialised to 0 at :278 and only ever set to 1 at :340. If a Sierra-format descriptor appears anywhere in the sequence, every subsequent Standard ISO9660 descriptor is misread:

  • The type selector at :342 reads vdp->type_sierra (byte offset 8) of the Standard descriptor β€” which is actually system_id[0], an attacker-controlled byte.
  • Once such a misread selects ISO_VD_PRIMARY, pri and pri_sierra both point at the same Standard PVD buffer (:347-349).
  • The field reads at :396-417 use pri_sierra->FIELD:
  • logical_block_size reads standard PVD bytes 136-137 (inside the standard path_table_size field, BE half).
  • volume_space_size reads standard PVD bytes 88-91 (inside the standard unused3 region β€” fully attacker-controlled).
  • root_directory_record reads standard PVD bytes 180-213 (overlaps the tail of standard root_directory_record + start of volume_set_id β€” attacker-controlled root_extent, root_size).
  • iso_ftype is then set to ISO_FTYPE_HIGH_SIERRA at :504, and the kernel logs cd9660: High Sierra Format at :503 β€” the observable marker that proves the misclassification.

Reproduction (unpatched 6.5-DEVELOPMENT #0)

make_crafted_iso.c emits a 100-sector image:

Sector Content
16 Sierra decoy: id_sierra="CDROM" β†’ high_sierra=1; type_sierra=3
17 Standard PVD: id="CD001" (skips the reset path); system_id[0]=1 so the sticky type_sierra reads ISO_VD_PRIMARY; bytes 136-137 = 0x00 0x08 so the Sierra-cast logical_block_size validates to 2048.
18 Standard VD_END: system_id[0]=255 so type_sierra reads ISO_VD_END.

Mount result on the unpatched kernel (3 consecutive runs all identical):

vn0: MBR magic not found; assume a COMPATIBILITY_SLICE (s0)
cd9660: High Sierra Format            <-- TYPE CONFUSION PROOF
MOUNT_RC=0

The mount succeeds, but downstream metadata is misinterpreted: an ls of the mount point returns ENOTDIR because root_extent was read at the wrong offset. No panic in 3+ runs β€” the bug is type confusion, not memory corruption. All bread()s stay device-bounded and the 34-byte bcopy of rootp stays inside the 2048-byte descriptor buffer.

Impact

  • Class: CWE-704 Incorrect Type Conversion. Not memory corruption.
  • Reachability: mount -t cd9660 requires VREAD on the device OR SYSCAP_RESTRICTEDROOT (:235-243). With vfs.usermount=1 and a root-created, attacker-owned image attached via vnconfig, an unprivileged user reaches this path β€” the realistic "admin handed the user a mountable ISO" precondition. The bug itself is privilege-independent.
  • Ceiling: attacker-chosen ISO controls logical_block_size, volume_space_size, root_extent, root_size, and iso_ftype for the mounted filesystem, all read at the wrong struct offsets. No OOB read/write, no UAF, no privilege boundary crossed. Severity Low matches the finding.

Fix

The minimal, root-cause fix is to reset high_sierra = 0 whenever the current descriptor matches the Standard ISO9660 id:

--- a/sys/vfs/isofs/cd9660/cd9660_vfsops.c
+++ b/sys/vfs/isofs/cd9660/cd9660_vfsops.c
@@ -338,7 +338,8 @@
                goto out;
            } else
                high_sierra = 1;
-       }
+       } else
+           high_sierra = 0;
        switch (isonum_711 (high_sierra? vdp->type_sierra: vdp->type)){

Fix validation (built + booted single-fix kernel)

Step Result
Reset to with-src (unpatched #0, full src + warm obj) up
kern.version 6.5-DEVELOPMENT #0 (Thu Jul 2 06:02:54 UTC 2026)
Baseline PoC run cd9660: High Sierra Format printed; MOUNT_RC=0
Apply fix.diff (patch -p1) Hunk #1 succeeded at 338
make -j6 nativekernel KERNCONF=X86_64_GENERIC NK_DONE rc=0 (04:33:20 UTC)
Install kernel.stripped β†’ /boot/kernel/kernel + reboot kern.version = 6.5-DEVELOPMENT #1 (today)
Patched PoC run Γ—3 MOUNT_RC=0, High Sierra Format count = 0
sha256(/boot/kernel/kernel) 39174db443dffdf…e3222ad

Before/after contrast β€” decisive:

Baseline #0:

vn0: MBR magic not found; assume a COMPATIBILITY_SLICE (s0)
cd9660: High Sierra Format
=== baseline-high-sierra-count: 1 ===

Patched #1:

run1 MOUNT_RC=0
run2 MOUNT_RC=0
=== total-high-sierra-prints: 0 ===

The fix closes the bug: the same crafted ISO that triggered the misclassification on #0 produces zero High Sierra Format prints on #1, and the mount still succeeds because the Standard PVD is a valid ISO9660 image once parsed at the correct offsets.

Files

  • make_crafted_iso.c β€” ISO generator (the trigger).
  • build.sh, run.sh β€” reproduce panel scripts.
  • build.log, run.log, fix_build.log β€” full untrimmed logs.
  • panic.txt β€” N/A (no panic observed; type confusion only).
  • env.txt β€” guest environment.
  • fix.diff β€” git-apply-able single-hunk fix.
  • manifest.json β€” catalog.

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

VALIDATED: baseline prints 'High Sierra Format' (count=1); patched prints 0 (count=0). Mount still succeeds (valid ISO9660 parsed correctly).

BEFORE: count=1. AFTER: count=0.
↓ fix.diffDragonFly 6.5-DEVELOPMENT #1: Tue Jul 14 04:29:52 UTC 2026

Confirmed kernel references

Detail

Exploit chain

none -- pure type confusion (CWE-704), no write/OOB/UAF/double-free primitive. No escalation possible.

Evidence (decisive lines)

BASELINE #0: mount rc=0, dmesg 'cd9660: High Sierra Format' (count=1). PATCHED #1: 0 high-sierra prints across 3 runs (count=0).

PoC changes

Authored from scratch: make_crafted_iso.c (Sierra decoy + Standard PVD + VD_END), build.sh, run.sh, VERDICT.md, manifest.json, fix.diff.

Verified recommended fix

Add else branch at :334: when descriptor matches ISO_STANDARD_ID, reset high_sierra=0. Full git-apply-able diff in findings/poc/DF-0853/fix.diff.

Verdict

REPRODUCED. high_sierra flag sticky: set at :340 for Sierra decoy descriptor, never reset for subsequent Standard PVD. Standard ISO9660 PVD misclassified as High Sierra (cd9660: High Sierra Format logged). Type confusion reads fields at wrong struct offsets. Non-corruption: all reads device-bounded within 2048B buffer.