From dd2fec5a41a8dc57976c80a72e523cccd88c51f1 Mon Sep 17 00:00:00 2001 From: cproudlock Date: Wed, 18 Feb 2026 11:20:00 -0500 Subject: [PATCH] Blancco PXE boot via Ubuntu kernel switch_root Blancco's own kernel freezes on Dell Precision towers during PXE boot. Workaround: boot Ubuntu kernel via GRUB chainload, download Blancco's 666MB squashfs rootfs + 132MB kernel modules over HTTP, mount overlay filesystem, and switch_root into Blancco's userspace. - Add blancco-init.sh: custom initramfs init script for switch_root approach - Add blancco-preferences.xml: pre-configured with network share for reports - Update playbook: build initramfs, deploy Ubuntu kernel/modules, config - Update prepare-boot-tools.sh: add HTTP modules to GRUB EFI build - Add UEFI HTTP Boot support to dnsmasq config - iPXE menu chains to grubx64.efi (replaces sanboot of ISO) Co-Authored-By: Claude Opus 4.6 --- playbook/blancco-init.sh | 162 +++++++++++++ playbook/blancco-preferences.xml | 378 +++++++++++++++++++++++++++++++ playbook/pxe_server_setup.yml | 102 +++++++-- prepare-boot-tools.sh | 2 +- 4 files changed, 626 insertions(+), 18 deletions(-) create mode 100644 playbook/blancco-init.sh create mode 100644 playbook/blancco-preferences.xml diff --git a/playbook/blancco-init.sh b/playbook/blancco-init.sh new file mode 100644 index 0000000..0cc27cb --- /dev/null +++ b/playbook/blancco-init.sh @@ -0,0 +1,162 @@ +#!/bin/sh +# Blancco PXE Loader - init script for custom initramfs +# Boot chain: iPXE -> GRUB EFI -> Ubuntu kernel + this initramfs -> switch_root to Blancco +# +# Blancco's own kernel freezes on Dell Precision towers during PXE boot. +# Workaround: boot Ubuntu kernel, download Blancco rootfs (squashfs), mount +# overlay filesystem, and switch_root into Blancco's userspace. + +export PATH=/bin:/sbin + +echo "" +echo "============================================" +echo " Blancco PXE loader" +echo "============================================" +echo "" + +mount -t proc proc /proc +mount -t sysfs sysfs /sys +mount -t devtmpfs devtmpfs /dev 2>/dev/null +mkdir -p /tmp /run + +echo "[1/4] Loading NIC drivers..." +for mod in /lib/modules/*.ko; do + insmod $mod 2>/dev/null +done +sleep 2 + +echo " Waiting for network interface..." +IFACE="" +COUNT=0 +while [ $COUNT -lt 30 ]; do + for i in /sys/class/net/*; do + ifname="${i##*/}" + if [ "$ifname" != "lo" ] && [ -d "$i" ]; then + IFACE=$ifname + break 2 + fi + done + COUNT=$((COUNT + 1)) + sleep 1 + echo -n "." +done +echo "" + +if [ -z "$IFACE" ]; then + echo "ERROR: No network interface found!" + exec sh +fi + +echo " Interface: $IFACE" +ip link set $IFACE up +sleep 2 + +SERVER=10.9.100.1 +ifconfig $IFACE 10.9.100.250 netmask 255.255.255.0 up +sleep 1 +echo " IP: 10.9.100.250" + +echo "[2/4] Downloading Blancco rootfs (666MB)..." +wget -O /tmp/airootfs.sfs http://$SERVER/blancco/arch/x86_64/airootfs.sfs 2>&1 +if [ ! -s /tmp/airootfs.sfs ]; then + echo "ERROR: Failed to download rootfs!" + exec sh +fi +echo " OK ($(wc -c < /tmp/airootfs.sfs) bytes)" + +echo "[3/4] Mounting rootfs..." +mkdir -p /run/lower /run/upper /run/work /run/newroot + +losetup /dev/loop0 /tmp/airootfs.sfs +mount -t squashfs -o ro /dev/loop0 /run/lower +if [ $? -ne 0 ]; then + echo "ERROR: squashfs mount failed!" + exec sh +fi + +insmod /lib/modules/overlay.ko 2>/dev/null +mount -t tmpfs -o size=50% tmpfs /run/upper +mkdir -p /run/upper/upper /run/upper/work + +mount -t overlay overlay -o lowerdir=/run/lower,upperdir=/run/upper/upper,workdir=/run/upper/work /run/newroot +if [ $? -ne 0 ]; then + echo "ERROR: overlay mount failed!" + exec sh +fi + +echo "[4/5] Installing kernel modules (132MB)..." +wget -O /tmp/kmod.tar.gz http://$SERVER/blancco/kmod.tar.gz 2>&1 +if [ -s /tmp/kmod.tar.gz ]; then + cd /run/newroot + gunzip -c /tmp/kmod.tar.gz | tar xf - + rm -f /tmp/kmod.tar.gz + cd / + echo " OK" +else + echo " WARNING: Failed to download kernel modules" +fi + +echo "[5/6] Switching root to Blancco..." +mkdir -p /run/newroot/run /run/newroot/proc /run/newroot/sys /run/newroot/dev /run/newroot/tmp + +echo "[6/6] Downloading Blancco config..." +wget -O /run/newroot/albus/config.xml http://$SERVER/blancco/config-clean.xml 2>&1 +wget -O /run/newroot/albus/preferences.xml http://$SERVER/blancco/preferences.xml 2>&1 +if [ -s /run/newroot/albus/config.xml ]; then + echo " config.xml: $(wc -c < /run/newroot/albus/config.xml) bytes" +else + echo " WARNING: Failed to download config.xml" +fi +if [ -s /run/newroot/albus/preferences.xml ]; then + cp -f /run/newroot/albus/preferences.xml /run/newroot/albus/preferences.save + echo " preferences.xml: $(wc -c < /run/newroot/albus/preferences.xml) bytes" +else + echo " WARNING: Failed to download preferences.xml" +fi + +# Pre-configure X.org to use modesetting driver (generic KMS, works with all GPUs) +mkdir -p /run/newroot/etc/X11/xorg.conf.d +echo " X.org: forcing modesetting driver" +cat > /run/newroot/etc/X11/xorg.conf.d/20-failsafeDriver.conf << 'XEOF' +Section "Device" + Identifier "Failsafe Video Device" + Driver "modesetting" +EndSection +XEOF + +# Enable SSH for remote debugging +echo " Enabling SSH (root:blancco)..." +sed -i 's/^#*PermitRootLogin.*/PermitRootLogin yes/' /run/newroot/etc/ssh/sshd_config 2>/dev/null +cat > /run/newroot/etc/rc.local << 'RCEOF' +#!/bin/bash +echo 'root:blancco' | chpasswd +ssh-keygen -A 2>/dev/null +IFACE=$(ls /sys/class/net/ | grep -v lo | head -1) +ip addr add 10.9.100.250/24 dev "$IFACE" 2>/dev/null +/usr/bin/sshd +RCEOF +chmod +x /run/newroot/etc/rc.local + +ln -sf /usr/lib/systemd/system/rc-local.service /run/newroot/etc/systemd/system/multi-user.target.wants/rc-local.service 2>/dev/null +cat > /run/newroot/etc/systemd/system/pxe-debug.service << 'SVCEOF' +[Unit] +Description=PXE Debug SSH +After=systemd-networkd.service +Wants=systemd-networkd.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/etc/rc.local + +[Install] +WantedBy=multi-user.target +SVCEOF +ln -sf /etc/systemd/system/pxe-debug.service /run/newroot/etc/systemd/system/multi-user.target.wants/pxe-debug.service + +mount --move /proc /run/newroot/proc +mount --move /sys /run/newroot/sys +mount --move /dev /run/newroot/dev + +echo " Starting Blancco..." +exec switch_root /run/newroot /sbin/init diff --git a/playbook/blancco-preferences.xml b/playbook/blancco-preferences.xml new file mode 100644 index 0000000..780d0c7 --- /dev/null +++ b/playbook/blancco-preferences.xml @@ -0,0 +1,378 @@ + + + + + + 7 + 14 + 0 + + WrE8qdGzoKMVy403SVha6O6JOdYlerKbbjyLSWo20NI= + + + workflow + auto + semi + manual + + + battery + cpu + memory + motherboard + battery_discharge + bios_logo + cpu_stress + display + keyboard + microphone + network + optical_devices + sound + pointing_devices + sim_presence + speaker + touchscreen + usb_ports + webcam + wifi + + + us + be + br + ca + ch + ch_fr + cn + de + dk + es + fi + fr + gb + hu + it + jp + kr + latam + nl + no + pl + pt + ru + se + sk + + + en_US + de_DE + es_ES + fr_FR + hu_HU + it_IT + ja_JP + ko_KR + pl_PL + pt_BR + ru_RU + sk_SK + zh_CN + zh_TW + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + true + false + false +
+ + + + + +
+ + false + false + + peap + tls + + + + + + blancco + blancco + + 10.9.100.1 + blancco-reports + + smb + + + + + + + + + + + + + + 20 + true + + + + false + 50 + false + false + false + false + interrupt + false + true + true + 10 + + + + + false + false + false + true + true + true + true + true + true + true + true + true + true + true + true + true + true + + + false + 67000 + + + true + + + false + ntfs + + + false + + + false + true + true + + + false + 30 + + + false + 80 + 443 + + memory + cpu + battery + battery_discharge + display + keyboard + pointing_devices + webcam + + + + bios + bios + Enterprise Volume Edition + + Drive Eraser + + + + 2025-03-10 + + + + General Electric Company + + + + + + + local + list + false + true + true + standard + + false + false + false + + 30 + false + + + false + + false + 5 + + 30 + true + + + 0 + false + + 100 + + 0 + false + + + false + true + true + 80 + + 70 + + false + false + false + + + + + + custom_field_1 + GERITM Number + + + + custom_field_2 + Device Name + + + + custom_field_3 + Device Serial Number + + + + custom_field_4 + Version + EVE_20250310 + + + + + false + true + + xml + + 0 + true + + false + + + false + + + false + + + WPA-PSK + 0 + + + true + false + false + false + + + false + false + + + false + false + + + false + + + false + viewer + + 5900 + + + + +
+
+ diff --git a/playbook/pxe_server_setup.yml b/playbook/pxe_server_setup.yml index 8d99b81..5bd3ee5 100644 --- a/playbook/pxe_server_setup.yml +++ b/playbook/pxe_server_setup.yml @@ -136,7 +136,13 @@ dhcp-option=6,8.8.8.8 enable-tftp tftp-root={{ tftp_dir }} + # HTTP Boot clients (UEFI) identify with vendor class "HTTPClient" + dhcp-vendorclass=set:httpboot,HTTPClient + dhcp-option-force=tag:httpboot,60,"HTTPClient" + dhcp-option-force=tag:httpboot,66,"" + dhcp-boot=tag:httpboot,http://10.9.100.1/blancco/grubx64.efi dhcp-boot=ipxe.efi + log-dhcp - name: "Create TFTP directory" file: @@ -445,24 +451,86 @@ - blancco - memtest - - name: "Create TFTP blancco directory for GRUB boot" - file: - path: "{{ tftp_dir }}/blancco" - state: directory - mode: '0755' + # --- Blancco PXE boot via Ubuntu kernel + switch_root --- + # Blancco's own kernel freezes on Dell Precision towers. Workaround: + # Boot Ubuntu kernel, download Blancco rootfs, overlay mount, switch_root. - - name: "Symlink Blancco boot files to TFTP (GRUB loads via TFTP)" - file: - src: "{{ web_root }}/blancco/{{ item }}" - dest: "{{ tftp_dir }}/blancco/{{ item }}" - state: link - force: yes - loop: - - vmlinuz-bde-linux - - intel-ucode.img - - amd-ucode.img - - config.img - - initramfs-bde-linux.img + - name: "Build Blancco PXE initramfs" + shell: | + set -e + WORK=$(mktemp -d) + mkdir -p "$WORK"/{bin,lib/modules,lib64,sbin,usr/share/udhcpc} + + # Busybox (static) + cp /bin/busybox "$WORK/bin/" 2>/dev/null || apt-get install -y busybox-static >/dev/null && cp /bin/busybox "$WORK/bin/" + for cmd in sh awk cat chmod echo grep gunzip ifconfig ip ln losetup ls mkdir mknod mount reboot route sed sleep switch_root tar udhcpc umount wget cpio; do + ln -sf busybox "$WORK/bin/$cmd" + done + + # NIC drivers (common server NICs) + KVER=$(uname -r) + KMOD="/lib/modules/$KVER/kernel/drivers/net/ethernet" + for drv in intel/e1000e/e1000e.ko.zst intel/igb/igb.ko.zst broadcom/tg3.ko.zst broadcom/bnx2.ko.zst broadcom/bnxt/bnxt_en.ko.zst broadcom/b44.ko.zst; do + if [ -f "$KMOD/$drv" ]; then + zstd -d "$KMOD/$drv" -o "$WORK/lib/modules/$(basename ${drv%.zst})" 2>/dev/null + fi + done + + # Overlay module + OVMOD="/lib/modules/$KVER/kernel/fs/overlayfs/overlay.ko.zst" + if [ -f "$OVMOD" ]; then + zstd -d "$OVMOD" -o "$WORK/lib/modules/overlay.ko" 2>/dev/null + fi + + # Init script + cp "{{ usb_root }}/playbook/blancco-init.sh" "$WORK/init" + chmod +x "$WORK/init" + + # Build CPIO + cd "$WORK" + find . | cpio -o -H newc 2>/dev/null | gzip > "{{ web_root }}/blancco/kexec-initrd.img" + rm -rf "$WORK" + echo "Built kexec-initrd.img: $(stat -c %s '{{ web_root }}/blancco/kexec-initrd.img') bytes" + args: + creates: "{{ web_root }}/blancco/kexec-initrd.img" + + - name: "Copy Ubuntu kernel for Blancco PXE boot" + copy: + src: "/boot/vmlinuz-{{ ansible_kernel }}" + dest: "{{ web_root }}/blancco/vmlinuz-ubuntu" + remote_src: yes + mode: '0644' + + - name: "Build Ubuntu kernel modules tarball for Blancco" + shell: | + set -e + KVER=$(uname -r) + tar czf "{{ web_root }}/blancco/kmod.tar.gz" -C / "lib/modules/$KVER" + echo "Built kmod.tar.gz: $(du -h '{{ web_root }}/blancco/kmod.tar.gz' | cut -f1)" + args: + creates: "{{ web_root }}/blancco/kmod.tar.gz" + + - name: "Deploy Blancco config and preferences (null-stripped)" + shell: | + # Strip null bytes from config.img files and deploy + if [ -f "{{ web_root }}/blancco/config.img" ]; then + WORK=$(mktemp -d) + cd "$WORK" + cpio -id < "{{ web_root }}/blancco/config.img" 2>/dev/null + tr -d '\000' < config.xml > "{{ web_root }}/blancco/config-clean.xml" + rm -rf "$WORK" + fi + # Deploy preferences from playbook (pre-configured with network share) + cp "{{ usb_root }}/playbook/blancco-preferences.xml" "{{ web_root }}/blancco/preferences.xml" + args: + creates: "{{ web_root }}/blancco/config-clean.xml" + + - name: "Create Samba user for Blancco reports" + shell: | + id blancco 2>/dev/null || useradd -r -s /usr/sbin/nologin blancco + echo -e "blancco\nblancco" | smbpasswd -a -s blancco 2>/dev/null + args: + creates: /etc/samba/smbpasswd - name: "Check for WinPE deployment content on USB" stat: diff --git a/prepare-boot-tools.sh b/prepare-boot-tools.sh index 29c862b..6110b9e 100755 --- a/prepare-boot-tools.sh +++ b/prepare-boot-tools.sh @@ -248,7 +248,7 @@ PYEOF grub-mkstandalone \ --format=x86_64-efi \ --output="$OUT_DIR/blancco/grubx64.efi" \ - --modules="linux normal echo net efinet tftp chain sleep" \ + --modules="linux normal echo net efinet http tftp chain sleep all_video efi_gop" \ "boot/grub/grub.cfg=$GRUB_CFG" 2>/dev/null echo " Built grubx64.efi ($(du -h "$OUT_DIR/blancco/grubx64.efi" | cut -f1))" else