# DF-0021 — PoC

`kmalloc_shift.c` — kernel module demonstrating the signed-int overflow in the
oversized `kmalloc` size reconstruction (`*kup << PAGE_SHIFT`).

## The bug

`btokup()` returns `int *` (`vm_page->ku_pagecnt` is `int`). Three sites
reconstruct the oversized size as `*kup << PAGE_SHIFT`
(`kern_slaballoc.c:1202`, `:1432`, `:1261`). Both operands are `int`, so the
shift is a **32-bit signed** shift that overflows for any oversized allocation
whose pagecount `*kup >= 2^19`, i.e. any `kmalloc() >= 2 GiB`. The wrapped
value drives `krealloc`'s `bcopy` length, `_kfree`'s `kmem_slab_free` /
`vm_map_remove` range, and `kmalloc_usable_size`'s return → OOB read / bad
kmem removal range / wrong usable-size accounting.

**Latent:** no unprivileged kernel interface is known to issue a ≥2 GiB
`kmalloc` (most large-buffer paths use `kmem_alloc`/`contigmalloc`). On x86_64
pc64 the per-type `ks_limit` (~KvaSize/10) permits it, so any future/unaudited
caller that requests ≥2 GiB via `kmalloc` activates it.

## Build

```
cc -I/sys -DKERNEL -c findings/poc/DF-0021/kmalloc_shift.c
ld -r kmalloc_shift.o -o kmalloc_shift.ko
```

## Run (root, disposable VM with ≥~2 GiB free KVA)

```
kldload ./kmalloc_shift.ko
```

## Expected output (bug present)

On `krealloc(p, 4 GiB)` the line-1202 `osize` wraps (INT_MIN sign-extended),
`bcopy` reads 4 GiB from a 2 GiB object → read-OOB (info leak of neighboring
kmem or page-fault panic); the subsequent `kfree` feeds a wrapped size into
`kmem_slab_free` → `vm_map_remove` bogus range (panic / vm_map corruption).
