DF-2622 console evidence (verbatim from the QEMU serial console + ssh runs) === [A] STOCK kernel #0 -- run_2622.sh (root, direct mount(2) via mnt2622) === $ ./mnt2622 '@' /mnt/h2x -> mount FAILED errno=2 $ ./mnt2622 '' /mnt/h2x -> mount FAILED errno=2 console: hammer2_mount: devstr="@" hammer2_mount: device="" label="DATA" rdonly=0 hammer2_mount: PFS label "DATA" not found hammer2_mount: devstr="" hammer2_mount: device="" label="DATA" rdonly=0 hammer2_mount: PFS label "DATA" not found # For volume="@": strchr finds '@' at devstr[0], label[1]==0 -> *label='\0' # -> devstr becomes "" and label==devstr -> slice=label[-1]=devstr[-1] # READS ONE BYTE BELOW the devstr[MNAMELEN] stack array (vfsops.c:1020). # For volume="": label==NULL -> label=devstr+0 -> same OOB read. # The byte decides the printed label: 'a'->BOOT, 'd'->ROOT, else DATA # (~1.6-bit oracle of the stack byte printed to the console). === [B] INSTRUMENTED kernel #1 -- same two triggers === DF2622: label=0xfffff80116c0dda0 devstr=0xfffff80116c0dda0 devstr="" label==devstr=1 devstr[-1]=00 (OUT-OF-BOUNDS byte below devstr[]) hammer2_mount: device="" label="DATA" rdonly=0 DF2622: label=0xfffff80116c0dda0 devstr=0xfffff80116c0dda0 devstr="" label==devstr=1 devstr[-1]=ff (OUT-OF-BOUNDS byte below devstr[]) hammer2_mount: device="" label="DATA" rdonly=0 # NOTE: the byte below devstr[] was 0x00 in the first call and 0xff in the # second -- it is live stack garbage below the array, varying with the # call's stack history. Neither value is 'a'/'d' so both prints chose # DATA, but had the stale byte been 0x61/0x64 the console label (and the # PFS the mount then searches for) would flip to BOOT/ROOT. # In-bounds reference captures from the same hooks: DF2622: label=0xffffffff817ad5af devstr=0xffffffff817ad5a8 devstr="vbd0s1d" label==devstr=0 devstr[-1]=ff (in-bounds last char of device string) # boot root mount: label=devstr+7 -> label[-1]='d' -> label=ROOT (correct) DF2622: label=0xfffff80118422da8 devstr=0xfffff80118422da0 devstr="/dev/vn0" label==devstr=0 devstr[-1]=00 (in-bounds last char of device string) # mount "/dev/vn0@": label=devstr+8 -> label[-1]='0' -> DATA (correct) === [C] FIX kernel #2 -- same triggers === hammer2_mount: devstr="@" hammer2_mount: device="" label="DATA" rdonly=0 hammer2_mount: devstr="" hammer2_mount: device="" label="DATA" rdonly=0 # Identical user-visible behavior (default label DATA, mount still fails # ENOENT because the device string is empty), but slice is now assigned # 0 when label==devstr -- devstr[-1] is never dereferenced.