# DF-0775 — PoC Evidence Pack

**Finding:** RPC reply verifier-length integer overflow corrupts XDR
cursor — wild pointer deref client kernel panic or OOB read

**Verdict:** NOT REPRODUCED (false positive for claimed impact)

## TL;DR

The signed overflow in `nfsm_rndup(i)` IS real, and `info->dpos` IS
corrupted (`dpos += INT_MIN`, jumping ~2 GiB backwards).  However, the
subsequent `nfsm_dissect()` bounds check truncates its pointer-difference
to `int`, which makes the comparison fail and routes to `nfsm_disct()`,
returning `EBADRPC`.  The claimed wild-pointer dereference (`*tl == 0`
at line 1509) is **never reached**.  No panic, no OOB read — only
`EBADRPC`, which is the same error any malformed RPC reply produces.

## Files

| File                  | Description                                           |
|-----------------------|-------------------------------------------------------|
| `malicious_server.c`  | Malicious NFS/RPC server (portmap + NFS + MOUNT)     |
| `trigger.sh`          | Mount trigger script                                  |
| `build.sh`            | Build the server                                      |
| `run.sh`              | Run the full test (server + mount + ls)               |
| `VERDICT.md`          | Full analysis with disassembly proof                   |
| `fix.diff`            | Defense-in-depth fix (bounds check on verifier length) |
| `run.log`             | Unpatched-kernel run output                            |
| `fix_run.log`         | Patched-kernel run output                              |
| `fix_build.log`       | Single-fix kernel build log                            |
| `env.txt`             | Guest environment                                      |

## How to reproduce

```sh
./build.sh                 # build the malicious server
# as root inside the guest:
./run.sh                   # start server, mount, test
```

Expected: `ls: /mnt_df0775: RPC struct is bad` (EBADRPC).  Guest stays
up.  No panic.

## Why the claimed impact doesn't manifest

See `VERDICT.md` for the full disassembly proof.  Short version:

1. `nfsm_rndup(0x7FFFFFFD)` wraps to `INT_MIN` ✓
2. `nfsm_adv(info, INT_MIN)` corrupts `info->dpos` ✓ (confirmed by
   disassembly of `nfsm_adv` @ `0xffffffff80814520`)
3. `nfsm_dissect(info, 4)` computes `int n = ptrdiff` — the 64-bit
   pointer difference (≈ 2³¹) truncates to a **negative** 32-bit int ✓
4. `bytes <= n` → `4 <= negative` → **FALSE** → routes to `nfsm_disct`
   → returns `EBADRPC` ✓ (confirmed by disassembly `cmp %esi,%ecx`)
5. The wild pointer is **never returned**, never dereferenced ✓
