Skip to content

Instantly share code, notes, and snippets.

@VirgilMing
Created July 13, 2026 07:26
Show Gist options
  • Select an option

  • Save VirgilMing/ed60c97cb5ae7d6b1578539b7b6db9d6 to your computer and use it in GitHub Desktop.

Select an option

Save VirgilMing/ed60c97cb5ae7d6b1578539b7b6db9d6 to your computer and use it in GitHub Desktop.
Supplementary FAT32 ESP corruption evidence for systemd/systemd#42979

systemd-boot v261.1 random-seed / FAT32 ESP corruption evidence

This is supplementary material for systemd/systemd#42979.

It deliberately does not include the 1 GiB ESP image, raw /loader/random-seed contents, root UUIDs, partition UUIDs, BCD data, or other disk identifiers. The raw image is preserved locally and can be shared privately if a maintainer needs it.

System

Field Value
Distribution Arch Linux
Userspace systemd 261.1-1
Actual ESP bootloader systemd-boot 261.1-1-arch
ESP 1 GiB FAT32, Type #1 entry, mounted at /boot
Firmware ASUS TUF Z370-PLUS GAMING, AMI BIOS 3004 (2021-07-12); EFI reports American Megatrends 5.12
Secure Boot disabled

The actual ESP EFI/systemd/systemd-bootx64.efi and the installed v261.1 binary have matching SHA-256:

381138394a62da6f003f720619d0dadcffc779c71d40a466f6709f997a2b0256

The tested entry is conventional Type #1:

linux /vmlinuz-linux
initrd /intel-ucode.img
initrd /initramfs-linux.img

Preserved image

The image was acquired from a Live USB before repair:

image size: 1073741824 bytes
SHA-256: 05a92527ea122e34d88322d80223d0f3411345f44f2625c41fbfbeac66f368ee

It is a bare FAT32 filesystem image, not a complete disk image.

fsck.fat result

See fsck-fat-vn.txt. Its essential findings are:

/vmlinuz-linux: first cluster 19 is free; size 17072640; chain length 0
/loader/random-seed: first cluster 17 is free; size 32; chain length 0
4060 allocated-but-unused clusters (16629760 bytes)

Independent FAT/data-area reconstruction

The two FAT copies are byte-identical:

FAT1 SHA-256 = FAT2 SHA-256 =
c6b71965bfede2eb04fbc6841b31acbc567c0b89346de81640f822807fdffbf0

Geometry:

bytes/sector: 512
bytes/cluster: 4096
FAT entries/sector: 128
FAT1 starts at sector 4110
FAT2 starts at sector 6151
data area starts at sector 8192

At capture time:

directory entry /loader/random-seed: start cluster 17, size 32, FAT[17] = 0
directory entry /vmlinuz-linux:     start cluster 19, size 17072640, FAT[19] = 0
FAT[19] through FAT[127]:           all zero/free (109 clusters)
orphan chain:                       head 4243, 4060 clusters, ends at EOC

The kernel needs ceil(17072640 / 4096) = 4169 clusters. Reconstructing it as:

clusters 19..127 (109 clusters)
followed by the 4060-cluster orphan chain beginning at 4243

produces:

reconstructed size:   17072640
reconstructed SHA256: d08cdac081fd40bb8e0660a6690fc8e3685068f4299a69206a2e86a5b8e09c7b
reference SHA256:     d08cdac081fd40bb8e0660a6690fc8e3685068f4299a69206a2e86a5b8e09c7b
byte mismatches:      0

The reference is usr/lib/modules/7.1.3-arch1-1/vmlinuz from the installed Arch linux package. This rules out kernel-file content corruption: the data is intact but its FAT allocation metadata is not.

Evidence of a previous identical occurrence

The image contains FSCK0000.REC (one cluster) and FSCK0001.REC (4,060 clusters), produced by a previous fsck.fat -a repair.

The first 16,626,176 meaningful bytes of FSCK0001.REC have SHA-256:

f76e46d60a32cc8bd92473a0855285c3deef4f72c80eeb15faea3e5f09e2c499

That equals the tail of the previous linux 7.1.2.arch3-1 kernel beginning at byte offset 446,464, i.e. after 109 clusters. So the previous failure also detached the same first-FAT-sector prefix of a kernel chain and left a 4,060-cluster orphan tail.

FSCK0000.REC is consistent with the previous one-cluster random-seed loss. Raw seed contents are intentionally omitted.

Timing and relation to process_random_seed()

The FAT timestamp for /loader/random-seed corresponds to the UEFI boot that failed to start Arch. There was no successful Arch userspace boot between the prior shutdown and that failure, so this write cannot come from the Linux systemd-boot-random-seed.service.

In v261.1, systemd-boot invokes process_random_seed(root_dir) before it calls the selected entry's loader:

This aligns with the observed sequence:

UEFI systemd-boot updates random-seed
→ FAT metadata is silently corrupted
→ systemd-boot then cannot open /vmlinuz-linux
→ it reports the kernel as missing

This is an attribution hypothesis, not proof that systemd intentionally manipulates the kernel's FAT chain. process_random_seed() uses EFI file operations only. The likely lower-level fault is an EFI FAT driver/cache implementation that is triggered by this I/O; the repeated first-FAT-sector pattern makes random storage corruption unlikely.

Why the usual “disable” did not isolate this path

random-seed-mode off was removed before v261.1 and is ignored. Masking systemd-boot-random-seed.service only disables the post-boot userspace update; it does not disable the EFI process_random_seed() call. Removing the file is also not a reliable v261.1 control because the bootloader can recreate it when sufficiently seeded.

Potential controlled test for another affected system

The reporter of this evidence is moving this installation to GRUB after two destructive incidents and will not run this test. For another affected system, use the diagnostic v261.1 build from the issue that skips only process_random_seed(root_dir).

  1. Start each arm from the same fsck-clean ESP state.
  2. Keep systemd-boot-random-seed.service masked and prevent Linux userspace from writing the ESP during the test.
  3. Test stock v261.1 and the skip-random-seed v261.1 binary separately.
  4. After each boot attempt, inspect the unmounted ESP from a Live USB with fsck.fat -vn; record both FAT hashes and the FAT entries for clusters 17, 19–127, and the kernel tail.

If stock v261.1 reproduces the chain loss while the otherwise-identical skip build does not, that strongly identifies UEFI random-seed I/O as the trigger. If the skip build also reproduces it, the hypothesis is substantially weakened.

fsck.fat 4.2 (2021-01-31)
Checking we can access the last sector of the filesystem
Boot sector contents:
System ID "MSDOS5.0"
Media byte 0xf8 (hard disk)
512 bytes per logical sector
4096 bytes per cluster
4110 reserved sectors
First FAT starts at byte 2104320 (sector 4110)
2 FATs, 32 bit entries
1044992 bytes per FAT (= 2041 sectors)
Root directory start at cluster 2 (arbitrary size)
Data area starts at byte 4194304 (sector 8192)
261120 data clusters (1069547520 bytes)
63 sectors/track, 255 heads
2048 hidden sectors
2097152 sectors total
/vmlinuz-linux
Contains a free cluster (19). Assuming EOF.
/vmlinuz-linux
File size is 17072640 bytes, cluster chain length is 0 bytes.
Truncating file to 0 bytes.
/loader/random-seed
Contains a free cluster (17). Assuming EOF.
/loader/random-seed
File size is 32 bytes, cluster chain length is 0 bytes.
Truncating file to 0 bytes.
Checking for unused clusters.
Reclaimed 4060 unused clusters (16629760 bytes).
Checking free cluster summary.
Free cluster summary wrong (210358 vs. really 214418)
Auto-correcting.
Leaving filesystem unchanged.
/esp-corrupt.img: 211 files, 46702/261120 clusters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment