# DF-3179 — tmpfs dirent zone keeps the default malloc limit; tmpfs_alloc_dirent panics when it is reached (unprivileged, default /tmp)

## What

`tmpfs_mount()` (sys/vfs/tmpfs/tmpfs_vfsops.c:200-207) creates three
per-mount malloc zones and raises ONLY the node zone limit:

```c
kmalloc_create_obj(&tmp->tm_node_zone, "tmpfs node", sizeof(struct tmpfs_node));
kmalloc_create_obj(&tmp->tm_dirent_zone, "tmpfs dirent", sizeof(struct tmpfs_dirent));
kmalloc_create(&tmp->tm_name_zone, "tmpfs name zone");

kmalloc_obj_raise_limit(tmp->tm_node_zone,
			sizeof(struct tmpfs_node) * tmp->tm_nodes_max);
```

The dirent zone (and name zone) keep the malloc default limit
`ks_limit = kmem_lim_size()/10` (= RAM/10 — sys/kern/kern_slaballoc.c:371-372;
390 MB on the 4 GB test guest).

`tmpfs_alloc_dirent()` (sys/vfs/tmpfs/tmpfs_subr.c:306-307) allocates the
dirent with `M_WAITOK` and **no `M_NULLOK`**, and the allocator hard-panics
when a zone limit is exceeded without `M_NULLOK`:

```c
panic("%s: malloc limit exceeded", type->ks_shortdesc);   /* kern_slaballoc.c:877,
                                                             kern_kmalloc.c:706 */
```

`tmpfs_nlink()` (sys/vfs/tmpfs/tmpfs_vnops.c:1170-1241) has no dirent budget
check — only per-node `LINK_MAX` — so `link(2)` adds a 128-byte dirent (plus
a short name) per call while consuming **zero** tmpfs nodes and zero pages.
Neither `tm_nodes_max` nor `tm_pages_max` can stop it.

## Impact

Any local user can panic the kernel from the default-boot `/tmp` tmpfs with
a plain `link()` flood (no `vfs.usermount`, no privileges, no mount syscall):

```
panic: tmpfs dirent: malloc limit exceeded
cpuid = 4
_kmalloc_obj() at _kmalloc_obj+0x758
tmpfs_alloc_dirent() at tmpfs_alloc_dirent+0x38
tmpfs_nlink() at tmpfs_nlink+0x11a
vop_nlink() at vop_nlink+0x57
kern_link() at kern_link+0x252
```

Threshold on the guest: (RAM/10)/128 B ≈ 3,194,880 dirents (panic observed
between 3.0M and 3.2M links, ~90 s). With `vfs.usermount=1` the same
mechanism is available on any number of attacker-created mounts; root can
also trigger it on any tmpfs via ordinary file creation when
`nodes_max > (RAM/10)/sizeof(tmpfs_dirent)`.

## Reproduce

```
build.sh    # cc -O2 -o linkflood linkflood.c   (in guest)
run.sh      # as an unprivileged user: mkdir /tmp/df3179 && ./linkflood /tmp/df3179
```

Expected: guest panics with `panic: tmpfs dirent: malloc limit exceeded`
once ~RAM/10/128 links have been created; see `run.log` + `panic.txt`.

## Fix

`fix.diff` (validated in-guest):
1. tmpfs_vfsops.c: raise the dirent and name zone limits with the node
   budget, exactly like the node zone.
2. tmpfs_subr.c: `tmpfs_alloc_dirent` allocates with `M_NULLOK` and
   returns `ENOSPC` on exhaustion (matching the name allocation directly
   below it) — degrades cleanly instead of panicking regardless of limits.

With the fix, the same flood terminates with `link(): No space left on
device` and the guest stays up (see VERDICT.md fix section).
