# DF-0879 — Unbounded CE continuation chain in cd9660_rrip_loop

## Finding

`cd9660_rrip_loop()` in `sys/vfs/isofs/cd9660/cd9660_rrip.c` follows the
Rock Ridge SUSP CE (Continuation Entry) chain without bounding the chain
depth and without cycle detection.  A crafted ISO9660 image whose CE
entries form a cycle (e.g. a CE continuation block whose SUSP area again
contains a CE pointing back to the same block) causes the parser to loop
forever inside the kernel, hanging the mount syscall and the CPU it runs
on — a local denial of service.

## How to reproduce

```sh
./build.sh                      # builds make_iso, generates cyclic.iso
# as root on the DragonFlyBSD guest:
sh run.sh                       # mounts cyclic.iso → hangs on unpatched kernel
```

The `run.sh` wrapper uses `vnconfig` to create a vnode disk from
`cyclic.iso`, then runs `mount_cd9660 -o ro /dev/vnNc /mnt`.

### Expected behavior

- **Unpatched kernel (bug present):** `mount_cd9660` never returns.  The
  kernel spins in `cd9660_rrip_loop()` re-reading the cyclic CE block.
  The calling process is unkillable (stuck in kernel I/O / the loop).
  The guest becomes sluggish or unresponsive.  The ssh session used for
  the mount eventually times out / drops.

- **Fixed kernel:** `mount_cd9660` fails promptly (the bounded-depth check
  aborts the CE chain) and returns an error to userspace.  The guest
  continues normally.

## PoC components

| File          | Purpose                                              |
|---------------|------------------------------------------------------|
| `make_iso.c`  | C program that writes a minimal crafted ISO9660 image with a self-referential CE chain |
| `cyclic.iso`  | Generated crafted image (20 sectors, 40960 bytes)   |
| `build.sh`    | Builds `make_iso` and generates `cyclic.iso`         |
| `run.sh`      | Mounts `cyclic.iso` as root via `vnconfig`+`mount_cd9660` |

## Trigger path (kernel source)

1. `cd9660_mount` → `cd9660_vfsops.c:472` calls `cd9660_rrip_offset(rootp, isomp)`
2. `cd9660_rrip_offset` (`cd9660_rrip.c:702`) checks for SP entry, then calls
   `cd9660_rrip_loop(isodir, &analyze, rrip_table_extref)` at line 719
3. `cd9660_rrip_loop` (`cd9660_rrip.c:469`) enters `while(1)` at line 503
4. CE entries are processed by `cd9660_rrip_cont` (`cd9660_rrip.c:429`) which
   stores the continuation block/offset/length
5. At line 544: termination only if `fields == 0 || iso_ce_len == 0`
6. At lines 550-555: bounds check only validates block < volume_space_size
   and offset+len <= logical_block_size — **no depth limit, no cycle detection**
7. At lines 560-572: reads the CE block and loops back to step 3

## Impact

**Denial of Service.** An attacker who can cause a crafted ISO9660 image to
be mounted (e.g. distributed as an installer image, auto-mounted USB, or
provided to a service that inspects ISO images) can hang the kernel
indefinitely.  The mount syscall never returns and the CPU spins in kernel
context.

## Preconditions

- Mounting a filesystem image requires root privilege (or
  `vfs.usermount=1` with a user-owned device — a plausible admin setup
  for unprivileged ISO inspection).
- Realistic scenario: an admin mounts an untrusted ISO image (installer,
  driver CD, downloaded image), or an automounter/auto-preview service
  does so on behalf of a user.
