# DF-0889 — hpmp leaked in hpfs_mountfs failed-mount path

**Severity:** Medium (memory exhaustion / local DoS)
**Class:** resource leak / memory leak
**File:** `sys/vfs/hpfs/hpfs_vfsops.c`

## The bug (line-accurate trace)

`hpfs_mountfs()` allocates the per-mount structure early:

    262: 	hpmp = kmalloc(sizeof(struct hpfsmount), M_HPFSMNT, M_WAITOK | M_ZERO);

…and then runs several operations that can fail and `goto failed`:

    265-267   bread(SuperBlock) error        -> goto failed
    272-274   bread(SpareBlock) error        -> goto failed
    282-285   SuperBlock magic mismatch      -> goto failed   (EINVAL)
    287-290   SpareBlock magic mismatch      -> goto failed   (EINVAL)
    301-303   hpfs_bminit() error            -> goto failed
    305-308   hpfs_cpinit() error            -> goto failed
    312-316   hpfs_root() error              -> goto failed

The cleanup label is:

    328: failed:
    329:     if (bp) brelse(bp);
    331:     mp->mnt_data = NULL;
    332:     dev->si_mountpoint = NULL;
    333:     vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
    334:     VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NULL);
    335:     vn_unlock(devvp);
    336:     return (error);

`failed:` releases the buffer, clears `mnt_data` and `si_mountpoint`, and
closes the device — but **never calls `kfree(hpmp, M_HPFSMNT)`**. Every failed
mount attempt after the kmalloc at line 262 therefore leaks one
`struct hpfsmount` (several KB each — contains `struct sublock`, `struct
spblock`, two 0x80-byte tables, `struct netexport`, etc.).

## Reachability

The most direct trigger is an HPFS mount whose backing image fails the
SuperBlock/SpareBlock magic check (lines 282/287). Each attempt:

1. mounts the device (opens devvp, reads SuperBlock + SpareBlock)
2. fails the magic check (`goto failed`)
3. leaks `hpmp`

Repeated attempts → unbounded `M_HPFSMNT` growth → kernel memory exhaustion
DoS.

Threat model:
- `vfs.usermount=1` (configurable sysctl) + an attacker-owned vnode/MD device
  → fully unprivileged.
- Root auto-mounting attacker-supplied media (USB / image) — every failed
  mount attempt leaks.
- Default `vfs.usermount=0` requires root (or a privileged mount helper), but
  the leak is unconditional on the failed-mount path.

## Reproduce

```sh
./build.sh    # nothing to compile — pure-shell harness
./run.sh      # kldloads hpfs.ko, runs N failed mounts, prints vmstat -m delta
```

Expected on the unpatched kernel: `M_HPFSMNT` count grows by ~N (one `hpmp`
leaked per failed mount). On the fixed kernel: `M_HPFSMNT` count stays at 0
(failed mount returns EINVAL with no allocation leaked).
