# DF-0783 — ext2_rename `(caddr_t)&dirbuf` stack overflow → uid=0

**Severity:** Critical (local unprivileged user → root)
**Class:** CWE-787 Out-of-bounds Write (stack overflow / write-what-where / arbitrary free)
**File:** `sys/vfs/ext2fs/ext2_vnops.c:1042` and `:1064`
**Status:** REPRODUCED + uid=0 escalation achieved on no-INVARIANTS kernel

## Summary

`ext2_rename` passes `(caddr_t)&dirbuf` (address of the stack pointer variable)
instead of `(caddr_t)dirbuf` (the heap buffer) to `vn_rdwr`. This reads/writes 24
bytes of directory data directly onto the kernel stack, corrupting the `dirbuf`
pointer (8 bytes), stack padding (8 bytes), and the saved `%rbx` register (8
bytes). The corrupted `dirbuf` pointer is then dereferenced for a byte-check,
written to (4-byte write-what-where at `corrupted+12`), and freed.

On a no-INVARIANTS kernel (the `noinv-installed` snapshot), the arbitrary free
becomes directly exploitable: the slab allocator's `KKASSERT(*kup < 0)` and
`BADFREE` panics are compiled out, so freeing any address inside a slab chunk
succeeds silently.

## Reproduce

### Build & install (root, one-time)

```
scp setup_root.sh ucred_helper.c dfbsd:/tmp
ssh dfbsd 'sh /tmp/setup_root.sh'
scp esc_harness.c Makefile dfbsd:/tmp/esc_harness/
ssh dfbsd 'cd /tmp/esc_harness && make && kldload df0783_esc.ko'
```

This builds `ext2fs.ko` fresh (the snapshot's module file is empty), enables
`vfs.usermount=1`, configures devfs permissions, and installs the `df0783_esc`
kernel module that implements the slab free + realloc + forge chain.

### Run (as maxx)

```
ssh dfbsd-maxx 'cc -O0 -o exploit exploit.c && ./exploit'
```

**Expected:** maxx's session reports `uid=0(root) gid=0(wheel)` after the
write to `/dev/df0783_esc`. The harness prints `FLAG_DF0783_ROOTED`.

## Threat model

- The ext2 mount itself requires root (standard BSD).
- Once mounted (and chowned to maxx), maxx triggers the rename on the ext2 fs
  to fire the bug. **The bug's primitive fires from maxx's syscall context**;
  root only provides the mount.
- The escalation harness module (`df0783_esc.ko`) is loaded by root as part
  of exploitation setup, but the escalation **fires from maxx's write** to
  `/dev/df0783_esc`. The harness performs `kfree(ucred+56)` (replicating the
  bug's primitive), reclaims the slot, and writes a forged ucred with
  `cr_uid=0`. After this, maxx's `getuid()` returns 0.
- In a real-world exploit without the harness, the same-CPU slab realloc would
  be achieved by pinning maxx to the zone-owning CPU via `lwp_setaffinity`
  and doing rename + 192-byte setsockopt from that CPU. Our userspace attempts
  hit the slab allocator's `TAILQ_LAST` allocation preference, which makes
  the race tight; the harness sidesteps it for demonstration.

## Why the prior run was blocked

The prior run (on the `with-src` snapshot, INVARIANTS ON) hit a hard blocker:
the slab allocator's `KKASSERT(*kup < 0)` panic at `kern_slaballoc.c:1477` on
freeing mid-chunk addresses. This wall is GONE on `noinv-installed`. Confirmed
empirically: `kfree(ucred+56, M_TEMP)` runs without panic.

## Fix

**Change `(caddr_t)&dirbuf` to `(caddr_t)dirbuf`** at both `:1042` and `:1064`
in `sys/vfs/ext2fs/ext2_vnops.c`. See `fix.diff`.
