From 1fe799e35f651c36fc1c98303cf59cc70ca8a97e Mon Sep 17 00:00:00 2001 From: Panagiotis Moustafellos Date: Fri, 16 Oct 2026 15:49:05 +0300 Subject: [PATCH] fix(bundle): Take cloud-hypervisor v54.0 and the urunc that names the disk image type cloud-hypervisor v50.0 offers the virtio-net offloads by default and writes a guest's virtio-net header to the tap unchanged. That is the guest side of PwnEscape, the Linux host-kernel bug in deferred checksum completion (fixed upstream in 6785011f8b16). v54.0 turns the offloads off by default and drops a transmit chain whose header asks for an offload the guest did not negotiate. Take v54.0 from monitors-build v0.1.1. Its cloud-hypervisor matches the upstream v54.0 static binaries byte for byte on both arches. virtiofsd and firecracker are unchanged. solo5 is still v0.12.1 but was rebuilt. monitors-build changed its release naming. A release is now tagged vX.Y.Z, and its per-arch tarball is -.tar.gz. The layout inside is unchanged. The release publishes no checksums, so pin each tarball by sha256, the way cosign is pinned. v54.0 also removed disk image type autodetection and refuses a --disk without image_type. Pin urunc at 0b1ef07, the head of feat/unchanged_containers-exec-fixes, now rebased onto urunc v0.8.1. It passes image_type=raw on every --disk (urunc-dev/urunc#1117). The two pins go together: either one alone breaks a block-device rootfs on cloud-hypervisor. Signed-off-by: Panagiotis Moustafellos [ananos: take cloud-hypervisor from monitors-build v0.1.1 instead of its own release; pin urunc at 0b1ef07 for image_type=raw] Signed-off-by: Anastassios Nanos --- DESIGN.md | 2 +- README.md | 4 ++-- docs/variants.md | 4 ++-- scripts/build-bundle.sh | 41 ++++++++++++++++++++++++++++++++--------- 4 files changed, 37 insertions(+), 14 deletions(-) diff --git a/DESIGN.md b/DESIGN.md index 46c40d0..7efc0f0 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -34,7 +34,7 @@ now done and is what `install.sh` and `scripts/build-bundle.sh` produce. above are not configurable at install time. - **Why three things are built (at release).** Most components are upstream release artifacts. Three have no upstream release and are compiled in the build: urunc - (from `urunc-dev/urunc` at commit `f6d54d6`, on + (from `urunc-dev/urunc` at commit `0b1ef07`, on `feat/unchanged_containers-exec-fixes`, CGO static, so native per arch under qemu/binfmt), urunit (from `NOFireAI/urunit` at commit `71bfdee`, on `urunit_agent`, C static), and the brig `container-initrd`. The two sources are diff --git a/README.md b/README.md index 0a779cf..75479d6 100644 --- a/README.md +++ b/README.md @@ -280,11 +280,11 @@ the three that do not: | Component | Source | In the tarball | | --- | --- | --- | | brig, brigd | `brig-sh/brig` release | fetched, verified against its signed `checksums.txt` | -| urunc, containerd-shim-urunc-v2 | built from `urunc-dev/urunc` at commit `f6d54d6` (branch `feat/unchanged_containers-exec-fixes`) | CGO-static, built in a Go container | +| urunc, containerd-shim-urunc-v2 | built from `urunc-dev/urunc` at commit `0b1ef07` (branch `feat/unchanged_containers-exec-fixes`) | CGO-static, built in a Go container | | urunit | built from `NOFireAI/urunit` at commit `71bfdee` (branch `urunit_agent`) | C-static; goes into the initrd | | container-initrd | built from the above | assembled for brig, not fetched | | guest kernel | `ghcr.io/nofireai/hull-assets` | fetched by digest once its cosign signature checks out; the kernel hull and brig boot | -| monitors, virtiofsd | `urunc-dev/monitors-build` | fetched | +| monitors, virtiofsd | `urunc-dev/monitors-build` | fetched, pinned by sha256 | | containerd, runc, nerdctl, CNI | upstream releases | fetched, upstream checksums | | cosign | `sigstore/cosign` | fetched, pinned by sha256 | | oras | `oras-project/oras` | fetched, its published checksums | diff --git a/docs/variants.md b/docs/variants.md index 84cd38b..e0c5d28 100644 --- a/docs/variants.md +++ b/docs/variants.md @@ -45,7 +45,7 @@ by `build-bundle.sh` and packed into the tarball. The installer just unpacks the No urunc release publishes a binary that boots a generic container. So the build compiles one, from `urunc-dev/urunc` at the commit `build-bundle.sh` pins -(`f6d54d6`, on branch `feat/unchanged_containers-exec-fixes`), in a +(`0b1ef07`, on branch `feat/unchanged_containers-exec-fixes`), in a `golang:1.26.4` container: ```console @@ -171,7 +171,7 @@ refuses a stock binary, rather than printing a table of zeroes. 3. Settled: the guest kernel is fetched from `hull-assets`, by the same tags hull uses, and checked against its signature; the runtime is built from `urunc-dev/urunc` at a pinned commit - (`f6d54d6`, on `feat/unchanged_containers-exec-fixes`); and the initrd is + (`0b1ef07`, on `feat/unchanged_containers-exec-fixes`); and the initrd is built for brig from `NOFireAI/urunit` at a pinned commit (`71bfdee`, on `urunit_agent`) plus urunc's own `packaging/container-initrd`, so its agent matches the shim. Both pins are commits because a branch tip moves with every diff --git a/scripts/build-bundle.sh b/scripts/build-bundle.sh index 9d70e9d..0e56ba5 100755 --- a/scripts/build-bundle.sh +++ b/scripts/build-bundle.sh @@ -109,14 +109,16 @@ BRIG_REPO="${BRIG_REPO:-brig-sh/brig}" # build log and *_PINNED=false in pins.env. An unset *_REF takes the pin # below, which is why these use ${VAR-default} and not ${VAR:-default}. # -# urunc: feat/unchanged_containers plus the two urunit-agent exec fixes, -# urunc-dev/urunc#1059 and #1060, a commit that sizes a container boot's vCPUs -# from the container's CPU limit, and one that boots arm64 guests on -# cloud-hypervisor's virtio console. The agent in the initrd is built from this +# urunc: feat/unchanged_containers on top of urunc v0.8.1, plus the two +# urunit-agent exec fixes, urunc-dev/urunc#1059 and #1060. It also carries a +# commit that sizes a container boot's vCPUs from the container's CPU limit, +# one that boots arm64 guests on cloud-hypervisor's virtio console, and one +# that passes image_type=raw on every --disk (urunc-dev/urunc#1117), which +# cloud-hypervisor v54.0 requires. The agent in the initrd is built from this # checkout too. URUNC_REPO="${URUNC_REPO:-urunc-dev/urunc}" URUNC_BRANCH_DEFAULT=feat/unchanged_containers-exec-fixes -URUNC_REF_DEFAULT=f6d54d661c7ff08fffaf7defca39d9e06c60dad3 +URUNC_REF_DEFAULT=0b1ef07229d678e7cbb3f61e12a8efcdd5070a8a URUNC_GO_IMAGE="${URUNC_GO_IMAGE:-golang:1.26.4}" # urunit: the init in the initrd. What v0.1.0-rc6 to rc8 shipped. URUNIT_REPO="${URUNIT_REPO:-NOFireAI/urunit}" @@ -147,7 +149,21 @@ done # Static musl busybox for the initrd, per arch. Extracted from this image so we # do not depend on busybox.net, which publishes 1.35.0 for x86_64 only. BUSYBOX_IMAGE="${BUSYBOX_IMAGE:-busybox:1.36.1-musl}" -MONITORS_VERSION="${MONITORS_VERSION:-FC-v1.7.0_CLH-v50.0_S5-v0.12.1_VFS_-v1.13.0_QM-v10.1.1-9a44e}" +# The monitors and virtiofsd come from one monitors-build release. The release +# is tagged vX.Y.Z and names its per-arch tarball after the monitor versions it +# carries. monitors-build publishes no checksum file, so each tarball is pinned +# by sha256 the way cosign is. +# +# cloud-hypervisor has to be v54.0 or later. Earlier releases offer the +# virtio-net offloads by default and write a guest's virtio-net header to the +# tap unchanged. That is the guest side of PwnEscape, the Linux host-kernel bug +# in deferred checksum completion (fixed upstream in 6785011f8b16). v54.0 turns +# the offloads off by default and drops a transmit chain whose header asks for +# an offload the guest did not negotiate. +MONITORS_RELEASE="${MONITORS_RELEASE:-v0.1.1}" +MONITORS_VERSION="${MONITORS_VERSION:-FC-v1.7.0_CLH-v54.0_S5-v0.12.1_VFS-v1.13.0_QM-v10.1.1-9a44e}" +MONITORS_SHA_LINUX_AMD64="66a33fbbcb1e125d7c80e99249b58580ff782eb6c1cb1710c8a52e470aa1a3e9" +MONITORS_SHA_LINUX_ARM64="93c1c63437efc3d0c935a6eb3f358d28cc773f8770e4f608109c91cbdfcac2ee" CONTAINERD_VERSION="${CONTAINERD_VERSION:-v2.3.5}" RUNC_VERSION="${RUNC_VERSION:-v1.5.1}" NERDCTL_VERSION="${NERDCTL_VERSION:-v2.3.5}" @@ -1062,9 +1078,15 @@ install -m 0755 "$DL/cosign" "$STAGE/bin/cosign" info " cosign: verified against the pinned hash" # ---- the private-stack components -------------------------------------------- -m_name="release-$ARCH-$MONITORS_VERSION.tar.gz" -fetch "$GITHUB/urunc-dev/monitors-build/releases/download/$MONITORS_VERSION/$m_name" "$DL/monitors.tar.gz" -verify "$DL/monitors.tar.gz" "" "$m_name" +case "$ARCH" in + amd64) m_sha="$MONITORS_SHA_LINUX_AMD64" ;; + arm64) m_sha="$MONITORS_SHA_LINUX_ARM64" ;; +esac +m_name="$MONITORS_VERSION-$ARCH.tar.gz" +fetch "$GITHUB/urunc-dev/monitors-build/releases/download/$MONITORS_RELEASE/$m_name" "$DL/monitors.tar.gz" +m_actual="$(sha256sum "$DL/monitors.tar.gz" | awk '{print $1}')" +[ "$m_sha" = "$m_actual" ] || fatal "monitors hash mismatch for $m_name: expected $m_sha, got $m_actual" +info " monitors $MONITORS_RELEASE ($m_name): verified against the pinned hash" c_ver="${CONTAINERD_VERSION#v}" c_name="containerd-$c_ver-linux-$ARCH.tar.gz" @@ -1449,6 +1471,7 @@ RUN_DIR=$RUN_DIR ROOTLESS=$ROOTLESS ROOTLESSKIT_VERSION=$([ "$ROOTLESS" = true ] && echo "$ROOTLESSKIT_VERSION" || echo "") SLIRP4NETNS_VERSION=$([ "$ROOTLESS" = true ] && echo "$SLIRP4NETNS_VERSION" || echo "") +MONITORS_RELEASE=$MONITORS_RELEASE MONITORS_VERSION=$MONITORS_VERSION MONITORS_INSTALLED="$MONITORS" VIRTIOFSD_INSTALLED=$VIRTIOFSD