From 52a77a2871f0229ce700bf9f38fedad8f0374028 Mon Sep 17 00:00:00 2001 From: Wei Date: Thu, 25 Jun 2026 20:27:07 +0800 Subject: [PATCH] fix(convert): support GCP-style images with a separate ESP grub.cfg and vendor kernels Two issues prevented cryptpilot-convert from producing a bootable image on GCP Ubuntu cloud images: 1. Stale ESP grub.cfg. GCP images keep a full, firmware-read grub.cfg on the EFI System Partition (/boot/efi/EFI//grub.cfg), while convert only regenerates the boot-partition copy (/boot/grub/grub.cfg). After convert the ESP copy still references the pre-conversion kernel, so the firmware boots a stale (often already-removed) kernel and fails with "vmlinuz-... not found" / "*.mod not found". Propagate the regenerated grub.cfg and the grub module directory to each separate ESP grub.cfg. This is a no-op when there is no separate ESP copy, and skips the case where grub-mkconfig already wrote straight to the ESP (e.g. the alinux symlink), detected with -ef. 2. zram kernel-module detection hard-coded "-generic". On images whose only kernel is a cloud-vendor flavor (e.g. -gcp, -aws) the detection returned empty and aborted with "Could not determine kernel version". Select the highest-versioned installed vmlinuz regardless of flavor, matching the kernel chosen for the initrd later. Verified end-to-end on a GCP Ubuntu 24.04 image converted with a -gcp kernel: the ESP grub.cfg and module set become byte-equivalent to a known-bootable image, and zram detection resolves the -gcp kernel. --- cryptpilot-convert.sh | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/cryptpilot-convert.sh b/cryptpilot-convert.sh index e964372..5141a84 100755 --- a/cryptpilot-convert.sh +++ b/cryptpilot-convert.sh @@ -443,9 +443,14 @@ install_zram_module_if_needed() { if [ -x "${rootfs_mount_point}/usr/bin/apt-get" ] && [ -x "${rootfs_mount_point}/usr/bin/dpkg" ]; then log::info "Detecting Ubuntu-like system, attempting to install zram kernel modules" - # Find the kernel version from the currently installed kernel image + # Find the kernel version from the installed kernel image. Pick the + # highest-versioned vmlinuz regardless of flavor (e.g. -generic, -gcp, -aws) + # so cloud-vendor kernels are handled too; this matches the kernel selected + # for the initrd later (ls /boot/vmlinuz-* | sort -V | tail -1). The previous + # hard-coded "-generic" match returned empty on vendor-kernel-only images and + # aborted with "Could not determine kernel version". local kernel_version - kernel_version=$(chroot "${rootfs_mount_point}" bash -c "dpkg -l | grep -oP 'linux-image-\K[0-9.-]+-generic' | head -n1") + kernel_version=$(chroot "${rootfs_mount_point}" bash -c "ls /boot/vmlinuz-* 2>/dev/null | sed 's#.*/vmlinuz-##' | grep -v rescue | sort -V | tail -n1") if [ -z "$kernel_version" ]; then log::error "Could not determine kernel version, zram module installation failed" @@ -996,6 +1001,33 @@ if [ "${uki:-false}" = false ]; then update-grub || true fi fi + + # Some images keep a *separate*, full grub.cfg on the EFI System Partition that + # the firmware reads directly (e.g. GCP Ubuntu cloud images read + # /boot/efi/EFI//grub.cfg, while the steps above only refreshed the + # boot-partition copy at /boot/grub/grub.cfg). On such layouts a kernel or + # cmdline change here never reaches the partition the firmware boots from, so it + # boots a stale (often already-removed) kernel and fails with + # "vmlinuz-... not found" / "*.mod not found". Propagate the regenerated + # grub.cfg and grub module directory to each such ESP copy. No-op when there is + # no separate ESP grub.cfg, or when grub-mkconfig already wrote straight to the + # ESP (e.g. the alinux symlink case, detected via -ef). + if [ -n "${grub2_cfg:-}" ] && [ -f "$grub2_cfg" ] && [ -d /boot/efi/EFI ]; then + boot_grub_dir=$(dirname "$grub2_cfg") + for esp_grub_cfg in /boot/efi/EFI/*/grub.cfg; do + [ -f "$esp_grub_cfg" ] || continue + [ "$grub2_cfg" -ef "$esp_grub_cfg" ] && continue + echo "Syncing regenerated grub.cfg to ESP: $esp_grub_cfg" + cp -f "$grub2_cfg" "$esp_grub_cfg" + esp_grub_dir=$(dirname "$esp_grub_cfg") + for moddir in x86_64-efi arm64-efi i386-efi; do + if [ -d "$boot_grub_dir/$moddir" ]; then + rm -rf "$esp_grub_dir/$moddir" + cp -a "$boot_grub_dir/$moddir" "$esp_grub_dir/$moddir" + fi + done + done + fi echo "Cleaning up package manager cache..." if command -v yum >/dev/null 2>&1; then yum clean all