# DF-3634 — Uninitialized kernel-stack variable leaked to userspace via `i915_gem_mmap_ioctl` (size==0)

## What

`i915_gem_mmap_ioctl()` (`sys/dev/drm/i915/i915_gem.c:1917`) declares
`unsigned long addr;` at line 1923 and — on the DragonFly-specific
fast-out for zero-length mappings — jumps past **every** assignment of
`addr`:

```c
1960 #ifdef __DragonFly__
1961         if (args->size == 0)
1962                 goto out;
```

The `out:` path then uses the uninitialized variable:

```c
2056 out:
2057         i915_gem_object_put(obj);
2058         if (IS_ERR((void *)addr)) {          /* uninit read #1 */
2059                 DRM_DEBUG("PTR_ERR=%ld\n", PTR_ERR((void *)addr));
2060                 return addr;                 /* garbage error code */
2061         }
2063         args->addr_ptr = (uint64_t) addr;    /* uninit read #2: 8 bytes of
                                                  stale kernel stack copied to
                                                  the ioctl args */
2067         return error;                        /* error == 0 here */
```

The ioctl returns success and hands 8 bytes of stale kernel stack back to
userspace in `args->addr_ptr`. The first real assignment of `addr` is at
line 1977 (`addr = round_page((vm_offset_t)p->p_vmspace->vm_taddr + maxtsiz + maxdsiz);`),
after the `goto out`.

## Reachability

- Ioctl `DRM_I915_GEM_MMAP` is registered `DRM_RENDER_ALLOW`
  (`sys/dev/drm/i915/i915_drv.c:3246`) — reachable from any unprivileged
  user with access to a render node / card node.
- Preconditions: an open DRM fd, one GEM handle (`DRM_I915_GEM_CREATE`,
  also RENDER_ALLOW), `flags=0`, `size=0`, any valid handle.
- No DRM_AUTH, no master, no root required.
- Repeatable without limit; the leaked slot contains whatever previous
  kernel frames left at that stack offset (kernel pointers, user pointers,
  lengths). Classic KASLR-defeat / stack-content oracle.

## Impact

Info leak of limited kernel memory (8 bytes of kernel stack per call,
unlimited calls) → Medium per the project rubric. The secondary
`return addr;` path can also turn garbage into an ioctl return code.

## Reproduce (on hardware with an Intel GPU)

```
cc -O2 -Wall -o poc_df3634 poc_df3634.c
./poc_df3634 /dev/dri/card0     # or renderD128
# expected on vulnerable hw: "ioctl ret=0 addr_ptr=0x...." non-zero,
#   varying/pointing at stale stack contents across calls with
#   different preceding syscalls
```

On this audit guest the PoC **builds cleanly** but cannot execute: the
QEMU guest is virtio-only (`vgapci0 ... chip=0x11111234` virtio-gpu,
no `/dev/dri`, no drm modules) and i915 is a PCI-driver that cannot
attach to non-Intel hardware. Verdict is therefore *inconclusive at
runtime, source-certain* — the uninit path is directly visible in the
code and requires no race.

## Fix

`fix.diff` in this directory (reject size==0 with -EINVAL, which also
restores the intended semantics; alternative minimal fix is to
initialize `addr` at declaration).
