#!/usr/bin/env bash # make-generic-kernel.sh # # Build a minimal Firecracker-optimized vmlinux from upstream kernel.org # sources using the vendored Firecracker config. All essential drivers # (virtio_blk, virtio_net, ext4, vsock) are compiled in — no modules, # no initramfs needed. The result boots any OCI-pulled rootfs directly. # # Usage: # scripts/make-generic-kernel.sh [--version 6.12.8] # # Output: # build/manual/generic-kernel/boot/vmlinux- # build/manual/generic-kernel/metadata.json set -euo pipefail log() { printf '[make-generic-kernel] %s\n' "$*" >&2; } SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" OUT_DIR="${BANGER_MANUAL_DIR:-$REPO_ROOT/build/manual}/generic-kernel" CONFIG="$REPO_ROOT/configs/firecracker-x86_64-6.1.config" KERNEL_VERSION="${KERNEL_VERSION:-6.12.8}" KERNEL_MAJOR="${KERNEL_VERSION%%.*}" JOBS="${JOBS:-$(nproc)}" usage() { cat <] Downloads kernel from kernel.org, applies the vendored Firecracker config, and builds a minimal vmlinux. Default version: $KERNEL_VERSION Output: $OUT_DIR/boot/vmlinux- EOF } while [[ $# -gt 0 ]]; do case "$1" in --version) KERNEL_VERSION="$2"; KERNEL_MAJOR="${KERNEL_VERSION%%.*}"; shift 2;; -h|--help) usage; exit 0;; *) log "unknown arg: $1"; exit 1;; esac done for tool in curl tar xz make gcc gpg gpgv; do command -v "$tool" >/dev/null 2>&1 || { log "missing required tool: $tool"; exit 1; } done [[ -f "$CONFIG" ]] || { log "config not found: $CONFIG"; exit 1; } # kernel.org release signing keys. Stable (Greg KH) signs most point # releases; mainline (Linus) signs .0 drops; Sasha Levin sometimes # signs longterm backports. Listing all three keeps the script # working across every release channel the user might pick. Rotations # are rare and announced; update this list if gpg complains. # # Fingerprints verified against kernel.org: # https://www.kernel.org/signature.html KERNEL_SIGNING_KEYS=( 647F28654894E3BD457199BE38DBBDC86092693E # Greg Kroah-Hartman ABAF11C65A2970B130ABE3C479BE3E4300411886 # Linus Torvalds E27E5D8A3403A2EF66873BBCDEA66FF797772CDC # Sasha Levin ) TARBALL="linux-${KERNEL_VERSION}.tar.xz" SIGNATURE="linux-${KERNEL_VERSION}.tar.sign" BASE_URL="https://cdn.kernel.org/pub/linux/kernel/v${KERNEL_MAJOR}.x" SRC_DIR="$(mktemp -d)" trap 'rm -rf "$SRC_DIR"' EXIT # Isolated GNUPGHOME so the verification step can't accidentally # trust whatever the invoking user already has in their keyring. The # trap above cleans the whole SRC_DIR, including this. GPG_HOME="$SRC_DIR/gnupg" install -d -m 0700 "$GPG_HOME" export GNUPGHOME="$GPG_HOME" log "importing kernel.org signing keys" # keyserver.ubuntu.com first: it returns keys with user IDs intact, # which gpg needs to mark the key as usable. keys.openpgp.org (the # current SKS successor) strips unverified UIDs on upload, and the # kernel.org devs haven't all completed its email verification flow, # so pulling from there returns UID-less keys that gpg then refuses # to trust. We fall back to it anyway in case ubuntu is unreachable. if ! gpg --batch --keyserver hkps://keyserver.ubuntu.com --recv-keys "${KERNEL_SIGNING_KEYS[@]}" 2>/dev/null; then log "key fetch from keyserver.ubuntu.com failed; trying keys.openpgp.org" gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "${KERNEL_SIGNING_KEYS[@]}" fi log "downloading kernel $KERNEL_VERSION from $BASE_URL/$TARBALL" curl -fSL --progress-bar -o "$SRC_DIR/$TARBALL" "$BASE_URL/$TARBALL" curl -fSL --progress-bar -o "$SRC_DIR/$SIGNATURE" "$BASE_URL/$SIGNATURE" log "verifying signature" # The .tar.sign is a detached signature over the *uncompressed* tar, # per kernel.org convention. Pipe the xz-decompressed stream into # gpg --verify so we never materialise an unverified tarball on disk. # Require VALIDSIG (the cryptographic proof — GOODSIG alone is # printed even for expired/revoked keys, VALIDSIG requires a usable # key and a mathematically valid signature). VERIFY_STATUS="$SRC_DIR/verify.status" xz -cd "$SRC_DIR/$TARBALL" | gpg --batch --status-fd 3 --verify "$SRC_DIR/$SIGNATURE" - 3>"$VERIFY_STATUS" 2>/dev/null || true if ! grep -qE '^\[GNUPG:\] VALIDSIG' "$VERIFY_STATUS"; then log "signature verification FAILED — refusing to build" log "gpg status:" cat "$VERIFY_STATUS" >&2 || true exit 1 fi log "signature OK (signed by $(awk '/^\[GNUPG:\] VALIDSIG/ {print $3}' "$VERIFY_STATUS"))" log "extracting" tar -xf "$SRC_DIR/$TARBALL" -C "$SRC_DIR" --strip-components=1 log "applying firecracker config" cp "$CONFIG" "$SRC_DIR/.config" # Adapt the 6.1 config to whatever version we're building. make olddefconfig # fills in any new symbols with defaults. make -C "$SRC_DIR" olddefconfig >/dev/null 2>&1 log "building vmlinux (jobs=$JOBS)" make -C "$SRC_DIR" -j"$JOBS" vmlinux 2>&1 | tail -5 VMLINUX="$SRC_DIR/vmlinux" if [[ ! -f "$VMLINUX" ]]; then log "vmlinux not found after build; check build output above" exit 1 fi mkdir -p "$OUT_DIR/boot" DEST="$OUT_DIR/boot/vmlinux-${KERNEL_VERSION}" cp "$VMLINUX" "$DEST" log "verifying: $(file -b "$DEST" | head -c 80)" cat > "$OUT_DIR/metadata.json" <