DF-2624 console evidence (verbatim from the QEMU serial console) === [A] STOCK kernel #0 -- RO mount of craft2624.img (poison PFS "LOCAL" with filename array + blockset bytes all 0x50, inode block relocated to the tail of a 64KB window) === hammer2_mount: devstr="/dev/vn0@testvol" hammer2_mount: device="/dev/vn0" label="testvol" rdonly=1 hammer2_ondisk: "/dev/vn0" zone=0 id=0 offset=0x0000000000000000 size=0x0000000004000000 hammer2_mount: hmp=0xfffff801192e4000 pmp=0xfffff8011872d000 # Mount SUCCEEDS: hammer2_update_pmps() (vfsops.c:1552-1571) pfsallocs # EVERY PFS under the sroot, so pfsalloc() ran kstrdup() on the poison # filename with no NUL anywhere in [0x100,0x400) of the inode block at # the DIO window tail -> strlen ran off the end of the 64KB buffer. # Silent on stock (adjacent page mapped, NUL found 4 bytes past the # buffer). hammer2 pfs-list shows the poison PFS (label column reads # the on-disk name via meta.name_len=5): MASTER cd630e99-a334-11f1-a070-010000000000 PPPPP === [B] INSTRUMENTED kernel #1 -- same mount, adjacent page UNMAPPED: the kstrdup's strlen faults past the DIO buffer === Fatal trap 12: page fault while in kernel mode cpuid = 3; lapic id = 3 fault virtual address = 0xfffff80055af6000 fault code = supervisor read data, page not present ... panic: page fault ... strlen() at strlen+0x14 hammer2_pfsalloc() at hammer2_pfsalloc+0x157 boot() called on cpu#3 # Fault VA is page-granular (end of the 64KB DIO buffer that holds the # poison inode block). The instrumentation only ADDED a report AFTER # the kstrdup returns -- the faulting strlen is the stock kstrdup at # vfsops.c:495, so this panic is a stock-code behavior (memory-layout # dependent: silent overread when the adjacent page is mapped, panic # when it is not). === [C] INSTRUMENTED kernel #1 -- adjacent page mapped (retry) === DF2624: pfsalloc filename has NO NUL in 256-byte array; kstrdup result len=772 (516 bytes past array) tail bytes: 50 50 50 ... 50 # 772 = 256 (filename array) + 512 (inode blockset area at # [0x200,0x400)) + 4 bytes read PAST THE END OF THE 64KB DIO BUFFER # (the inode block sits at window offset 0xFC00, so byte 768 of the # walk is the first byte past the buffer). Those 4 adjacent-kernel- # memory bytes (plus the NUL that stopped the walk) were copied into # pmp->pfs_names[0] of the poison pmp. (The hexdump window printed # only array+96 bytes, all 0x50 filler; the past-buffer bytes are # result[768..771].) === [D] FIX kernel #2 -- same image, mounted 3 times === hammer2_pfsalloc: PFS filename not NUL-terminated (truncated to 256) hammer2_pfsalloc: PFS filename not NUL-terminated (truncated to 256) hammer2_pfsalloc: PFS filename not NUL-terminated (truncated to 256) # 3/3 mounts succeed, NO panic, warning fires each time; pfs-list # unchanged (PPPPP), testvol mount unaffected.