There is a specific kind of supply-chain paranoia that is not satisfied by verifying checksums against an upstream release artifact. It wants to know which physical machine compiled the binary, what microarchitecture it was optimized for, which version of the kernel headers were in play, and whether the build environment was the same one that produced every other binary in the deployment. It wants a forensic trail baked into the ELF binary itself — not in a log file that can be deleted, not in a database that can be altered, but in a .note section that survives strip operations, filesystem copies, and package manager reinstallations.
BTC.sh (Build Tool Chain) is a single 1300-line Bash script that does this. It builds a complete cross-compilation toolchain — binutils, two-stage GCC, C library (glibc or musl), kernel headers, libxcrypt, and an optional kernel binary — inside a ramfs mount, stamps every produced binary with forensic provenance, and packages the result as a golden image tarball with a machine-readable JSON manifest. It is the compiler forge that feeds sorcery-go's Cauldron and Fester's distributed build nodes. This post explains how it works, how to use its output with five different build systems, and what the fingerprinting strategy actually buys you.
+ +BTC.sh builds inside a ramfs cleanroom — a volatile filesystem mounted at /usr/src/DCOSNET-{LABEL}-cleanroom/ that is created fresh on every invocation and unmounted after packaging. This is not an aesthetic preference. Building on ramfs eliminates I/O wear on SSDs during multi-hour LTO builds (GCC Stage 2 with Link-Time Optimization on 28 threads can run for 45 minutes), guarantees a pristine environment with no stale files from previous runs, and ensures that the build cannot be contaminated by artifacts from the host filesystem. The cleanroom path encodes the full system identity: for a native haswell build, it becomes /usr/src/DCOSNET-HASWELL-AVX2-LTO-cleanroom/ — the microarchitecture, ISA tier, and optimization mode are all in the directory name.
The upstream version matrix is defined as a flat set of variables near the top of the script, one per package. As of BTC 0.4.1, the current matrix targets these upstream releases:
+ +| Package | Version | Upstream |
|---|---|---|
| Linux Kernel | 7.1 | cdn.kernel.org |
| Binutils | 2.46.1 | ftp.gnu.org |
| GCC | 15.3.0 | ftp.gnu.org |
| Glibc | 2.43 | ftp.gnu.org |
| Musl | 1.2.6 | musl.libc.org |
| GMP | 6.3.0 | ftp.gnu.org |
| MPFR | 4.2.2 | ftp.gnu.org |
| MPC | 1.4.0 | ftp.gnu.org |
| libxcrypt | 4.5.2 | github.com/besser82 |
All source URLs are centralized in a single Bash associative array called A_SRC_URL, keyed by package name. This is the authoritative source of truth — change a URL here and every download, checksum, and decompress operation follows. The array maps each key to its canonical upstream mirror, constructing the filename from the version variable: ${v_binutils}.tar.xz resolves to binutils-2.46.1.tar.xz and fetches from ftp.gnu.org/gnu/binutils/. The download function, f_download(), iterates this array and fetches each tarball with wget -nc (no-clobber, idempotent — safe to re-run). Every file is then validated with _archive_sane(), which runs tar -tf on the downloaded archive to confirm it is not truncated or corrupt. Files that fail validation are deleted and re-fetched automatically. Per-file md5 and sha512 checksums are written to ${LOGS}/checksums/ for audit trails.
The target registry is a Bash associative array called BTC_TARGETS where each key is a target identifier and each value is a pipe-delimited specification string containing eleven fields: architecture, CPU, microarchitecture march, ISA tier, ABI, C library, endianness, family, human-readable description, minimum kernel version, and GCC-extra configure flags. The table-driven design follows PEP 868's pattern for dispatch tables and MISRA C's preference for data over control flow — the build logic never contains hardcoded architecture strings, only lookups into this registry.
The nineteen targets span five families:
+ +| Family | Targets | ISA Tier | C Library |
|---|---|---|---|
| Intel HEDT/Server | haswell, haswell-ep, skylake, skylake-x, skylake-server | AVX2 / AVX512 | glibc |
| AMD Ryzen/EPYC | znver1, znver2, znver3, znver4 | AVX2 / AVX512 | glibc |
| AMD APU (mobile) | apu-zn1, apu-zn2, apu-zn3, apu-zn4 | AVX2 | glibc |
| Intel Atom (embedded) | silvermont, goldmont, tremont, sierraforest | SSE4.2 | glibc |
| Embedded | mipselr2, armv7, tilegx | MIPS32 / NEON / TILE | musl |
Target selection uses a step-down dispatch in f_silicon_probe(). If you invoke BTC.sh skylake-x, it resolves the target directly from the registry. If you invoke BTC.sh with no arguments or --native, it runs gcc -march=native -Q --help=target to probe the host CPU's microarchitecture, matches the result against the registry, and falls back to haswell if the probed architecture is not registered (Broadwell, for example, maps to Haswell). This probing is deterministic — the same hardware always produces the same target selection, which matters for reproducible builds.
Each target maps to a custom GCC triple: not the stock x86_64-pc-linux-gnu, but x86_64-dcosnet-linux-gnu. The dcosnet vendor string is deliberate — it prevents the BTC-forged toolchain from colliding with any system-installed compiler, makes the triple identifiable in readelf and file output, and follows the GNU convention that the vendor field is a namespace for distribution-specific toolchains. For musl targets, the triple becomes mipsel-dcosnet-linux-musl or arm-dcosnet-linux-musleabihf, encoding the C library directly into the triple.
The forge executes a linear, ordered sequence — there are no concurrent build phases and no dependency resolution at runtime, because the dependency order of a bootstrap toolchain is deterministic and fixed. The sequence, implemented in f_main(), is:
f_setup — Mount the ramfs cleanroom, create the sysroot directory hierarchy (bin/, usr/, lib/, include/), and symlink lib64/lib to lib for multilib compatibility.f_download — Fetch all upstream source tarballs via A_SRC_URL, validate each with _archive_sane(), and write checksum manifests.f_sig_init — Initialize the forensic signature tier (cluster, TPM, or poly). This runs before any compilation so that the signature token is available to every subsequent f_stamp_binary() call.f_binutils — Build binutils (assembler, linker, object tools) for the target triple. This is the first package built because GCC Stage 1 needs a cross-assembler and cross-linker.f_kernel_headers — Install kernel headers into the sysroot's usr/include/. These headers define the kernel ABI that the C library and all user-space code will be compiled against.f_gcc_p1 — Build GCC Stage 1 (C compiler only, no C++ or libstdc++). GMP, MPFR, and MPC are decompressed and nested inside the GCC source tree as gmp/, mpfr/, mpc/ for build isolation. Architecture-specific patches are applied here — on x86_64, the dynamic linker path in gcc/config/i386/t-linux64 is rewritten from lib64 to lib to match the sysroot layout.f_clib — Build the C library. For glibc targets, this runs the full glibc configure/make/install into the sysroot. For musl targets, it builds musl as a static+shared combo. The dispatch is driven by the BTC_T_CLIB field from the target registry — no conditional logic in the build function itself.f_libxcrypt — Build libxcrypt (extended crypt library for bcrypt, scrypt, yescrypt). Skipped entirely for musl targets since musl has built-in crypt support. This is gated by a simple check: if BTC_T_CLIB == "musl", print a skip message and return.f_gcc_p2 — Build GCC Stage 2 (full compiler: C, C++, Fortran, with LTO, PIE, and Stack Smashing Protection enabled). This stage links against the just-built C library, so every binary it produces is natively bound to the target's runtime. GCC is configured with --with-arch={march}, --with-cpu={march}, --enable-lto, --enable-default-pie, --enable-default-ssp, and the architecture-specific extra flags from the target registry.f_kernel_binary — Cross-compile a kernel binary for the target architecture. The appropriate defconfig is selected per-arch (multi_v7_defconfig for ARM, malta_defconfig for MIPS, tilegx_defconfig for Tile-Gx, plain defconfig for x86_64). Enterprise hardening flags are injected (CONFIG_MODULES=n, CONFIG_KALLSYMS=n, CONFIG_DEBUG_FS=n), the kernel is stamped with CONFIG_LOCALVERSION=-dcosnet-{LABEL}, and cross-compiled with ARCH={arch} CROSS_COMPILE={triple}-. After the build, every binary in the sysroot is stamped with f_stamp_binary().f_package — Package the entire sysroot as a golden image tarball ({SYS_LABEL}-toolchain-golden.tar.xz) with a JSON manifest sidecar containing the full build metadata.Every build function logs its configure and make output to timestamped files under ${LOGS}/, making it possible to reconstruct the exact build sequence after the fact. A tmux dashboard provides live build progress if the script is run inside a tmux session.
Every ELF binary produced by the forge — compilers, assemblers, linkers, kernel image, and every binary in the sysroot — receives two layers of forensic identification through f_stamp_binary(). This function is called in a find loop that walks ${NEWROOT}/bin/ and ${NEWROOT}/usr/bin/, so nothing escapes stamping.
.note.BTC)The first layer injects an ELF NOTE section named .note.BTC into each binary. This is done by assembling a small object file with a .note section containing structured key-value pairs, then using objcopy --add-section to merge it into the target binary. The note payload contains: the organization identifier (DCOSNET), the kernel version used for headers (K:${v_linux}), the target microarchitecture ID (Arch:${BTC_T_ID}), the full system label (Label:${SYS_LABEL}), the forge log filename (Forge:${log_base}), the active signature tier (SigTier:${BTC_SIG_TIER}), and the cryptographic signature token (Sig:${BTC_SIG_TOKEN}).
This data is readable at any time with readelf -n /path/to/binary. It survives strip operations because objcopy --strip-unneeded is applied after the note section is injected, and note sections are not stripped by default. It survives package manager reinstallations because the package was built with the note already embedded. It survives filesystem copies because it is in the ELF binary, not in a sidecar file. The assembly source is straightforward:
.section .note.BTC,"a",@note
+.long 2f - 1f /* namesz */
+.long 4f - 3f /* descsz */
+.long 1 /* type */
+1: .asciz "DCOSNET" /* owner */
+2: .align 4
+3: .ascii "Org: dcos.net|K:linux-7.1|Arch:haswell|Label:DCOSNET-HASWELL-AVX2-LTO|..."
+4: .align 4
+
+The second layer writes four extended attributes on every stamped binary using setfattr: user.btc.identity (the full system label and tier), user.btc.hash (the SHA-256 hash of the binary contents), user.btc.sig.tier (the active signature tier name), and user.btc.sig.token (the cryptographic token). These attributes are queryable with getfattr -d /path/to/binary and persist independently of the ELF file — they survive renames, hardlinks (on the same filesystem), and are preserved by cp --preserve=xattr. They are lost by cp without attribute preservation, by tar archives that do not store xattrs, and by filesystems that do not support extended attributes (notably, some tmpfs configurations and older FAT32 mounts).
The dual-layer approach provides defense in depth. The ELF NOTE is tamper-evident within the binary itself — any modification to the binary changes its SHA-256 hash, which a verification step can detect. The xattrs provide a second, independent verification channel at the filesystem level. If the ELF NOTE is present but the xattr hash does not match the file's current SHA-256, something modified the binary after stamping. If the xattrs are missing entirely, the binary was copied without attribute preservation. This is not a cryptographic signature scheme — there is no asymmetric key involved — but it is a practical, zero-dependency provenance system that works on any Linux system with objcopy and setfattr.
After stamping, f_stamp_binary() extracts debug symbols into a separate .debug file stored under ${BTC_ARCHIVE}/symbols/${SYS_LABEL}/, then strips the binary with --strip-unneeded. The debug symbols link back to the original binary path via the debug link section. This means you get full debug info for GDB without bloating the production binary, and the debug symbol files are also stamped and stored centrally.
The SigTier and Sig fields in the forensic stamp are populated by f_sig_init(), which implements a three-tier identity system. The tier selection follows a strict priority: cluster-join overrides TPM, TPM overrides poly, and poly is the default. This is not a negotiation — it is a deterministic cascade that runs once at the start of the build and produces a single signature token that is folded into every binary.
A cluster deployment shares a single identity token across multiple build machines. When BTC.sh --join-cluster=TOKEN skylake-x is invoked, the provided token is written to ${BTC_ARCHIVE}/.btc-cluster-token and adopted as BTC_SIG_TOKEN. On subsequent builds, the file is detected automatically — f_sig_init() checks for the cluster token file before falling through to TPM or poly — and the same token is reused. This means that every binary produced by any machine in the cluster carries the same Sig: field, making it possible to identify cluster membership by inspecting a single binary with readelf -n.
The token itself is an arbitrary string provided by the operator. In a Fester-managed cluster, this token is typically distributed via the cluster configuration and stored in each node's /opt/BTC/ directory. sorcery-go's pkg/cluster/cluster.go reads the BTC manifest to extract the tier and token for cluster-wide provenance queries.
TPM-bound signatures tie the forge identity to the physical hardware. When BTC.sh --tpm-seal is invoked, f_sig_init() calls f_tpm_pcr_digest(), which attempts to read Platform Configuration Registers (PCRs) 0 through 7 — the registers that cover BIOS, firmware, bootloader, and early boot configuration — from the system's TPM. For TPM 2.0, it uses tpm2_pcrread sha256:0,1,2,3,4,5,6,7 and hashes the output to produce a 256-bit digest. For TPM 1.2, it reads /sys/class/tpm/tpm0/pcrs and hashes the file contents. The resulting digest is prefixed with tpm: and stored as the signature token.
This creates a hardware-bound identity: the same BTC.sh build run on different physical machines (even identical models) will produce different signature tokens because the PCR state includes platform-specific firmware measurements. If the BIOS is flashed, the secure boot state changes, or the TPM is cleared, the PCR digest will change and subsequent builds will produce a different token — making it possible to detect hardware state changes by comparing the Sig: field across binaries. TPM sealing is restricted to singular deployments (one target per machine) because the PCR state is a single global value, not per-target.
The poly tier is the default when no cluster token is provided and --tpm-seal is not specified. It generates a random 128-bit hex string via openssl rand -hex 16 and writes it to ${BTC_ARCHIVE}/.btc-salt. On subsequent builds, the existing salt file is read and reused — the token is write-once, never re-rolled. This means that two independent machines running the same BTC.sh skylake-x build will produce forensically distinct toolchains: the binaries will be bit-identical (same GCC, same flags, same source), but the Sig: field in the ELF NOTE will differ, making it possible to determine which physical machine produced any given binary.
The poly tier is the simplest identity layer, but it is sufficient for most deployments. It answers the question "which machine built this?" without requiring any hardware support or cluster coordination. The salt file persists under /opt/BTC/, so it survives reboots and rebuilds.
The golden image produced by BTC.sh is a self-contained sysroot — it includes the cross-compiler, linker, assembler, C library headers, kernel headers, and (optionally) a kernel binary. The JSON manifest sidecar describes every property of the toolchain: target triple, microarchitecture, ISA tier, optimization flags, C library version, and signature metadata. This manifest is how external build systems discover and configure the toolchain. The following sections describe five integration patterns, each grounded in how real distributions consume cross-compilers.
+ +Gentoo's cross-compilation support revolves around the CROSS_COMPILE environment variable and the crossdev utility. A BTC-forged toolchain integrates by pointing Gentoo's CBUILD, CHOST, CTARGET, CC, CXX, AR, NM, RANLIB, and STRIP variables at the BTC sysroot. The golden image tarball is extracted to a stable path (e.g., /opt/btc/skylake-x/), and the target triple from the manifest (x86_64-dcosnet-linux-gnu) is used as CTARGET. Gentoo's make.conf entries for the cross-build would look like this:
ROOT="/opt/btc/skylake-x/"
+CBUILD="x86_64-pc-linux-gnu"
+CHOST="x86_64-dcosnet-linux-gnu"
+CC="${ROOT}/bin/x86_64-dcosnet-linux-gnu-gcc"
+CXX="${ROOT}/bin/x86_64-dcosnet-linux-gnu-g++"
+AR="${ROOT}/bin/x86_64-dcosnet-linux-gnu-ar"
+NM="${ROOT}/bin/x86_64-dcosnet-linux-gnu-nm"
+RANLIB="${ROOT}/bin/x86_64-dcosnet-linux-gnu-ranlib"
+STRIP="${ROOT}/bin/x86_64-dcosnet-linux-gnu-strip"
+CFLAGS="-O2 -march=skylake-avx512 -mtune=skylake-avx512 -pipe"
+CXXFLAGS="${CFLAGS}"
+LDFLAGS="-Wl,-O2 -Wl,--as-needed"
+PKG_CONFIG_SYSROOT_DIR="${ROOT}"
+PKG_CONFIG_LIBDIR="${ROOT}/usr/lib/pkgconfig:${ROOT}/usr/share/pkgconfig"
+
+The BTC toolchain's advantage over crossdev is microarchitecture specificity. crossdev builds a generic x86_64-pc-linux-gnu toolchain — it does not distinguish between Skylake and Haswell, between AVX512 and AVX2. A BTC-forged Skylake-X toolchain defaults to -march=skylake-avx512 at the compiler level, so every package built with it (without explicit CFLAGS overrides) is optimized for that specific microarchitecture. For Gentoo users building for specific hardware — a fleet of Skylake-SP servers, or a cluster of Zen4 EPYC nodes — this eliminates the need to maintain per-architecture make.conf fragments. The compiler does the right thing by default.
Source Mage is the direct ancestor of sorcery-go's spell format. Integration with BTC.sh operates through sorcery-go's pkg/toolchain/btc.go module, which probes for the golden image tarball, validates its .note.BTC section with readelf -n, and parses the forensic stamp into a BTCStamp struct. When sorcery-go's Cauldron builds a spell for a specific architecture, it uses the BTC stamp's target triple and ISA tier to configure the build environment automatically — CC, CXX, CFLAGS, and LDFLAGS are all derived from the stamp.
For standalone Source Mage installations (without sorcery-go), the integration is manual but straightforward. The golden image is extracted to a path like /opt/btc/, and Source Mage's CAST_ARGS or spell-level CONFIGURE scripts set the cross-compiler variables. The BTC manifest JSON can be parsed with jshn or jq to extract the target triple and optimization flags. Because Source Mage spells are just Bash scripts, they can source the manifest directly:
BTC_MANIFEST="/opt/btc/DCOSNET-SKYLAKE-X-AVX512-LTO-manifest.json"
+TARGET_TRIPLE=$(jq -r .target_triple "$BTC_MANIFEST")
+MARCH=$(jq -r .target_march "$BTC_MANIFEST")
+export CC="/opt/btc/DCOSNET-SKYLAKE-X-AVX512-LTO/bin/${TARGET_TRIPLE}-gcc"
+export CFLAGS="-O2 -march=${MARCH} -mtune=${MARCH} -pipe"
+
+Lunar Linux uses a Bash-based module system where each package has a BUILD script that runs in a chrooted environment. The cross-compilation entry point is the CROSS_COMPILE variable, which Lunar's build engine prefixes onto tool names. A BTC-forged toolchain integrates by setting the compiler path and flags in Lunar's lunar.conf or per-module overrides. The key difference from Gentoo is that Lunar's build isolation is stronger — each module builds in its own chroot — so the sysroot must be fully self-contained, which the BTC golden image is by design.
The integration pattern is to extract the golden image to a known location, set HOST and HOST_PREFIX in the lunar configuration, and let the module build system discover the cross-compiler. The BTC manifest provides the triple prefix, and the ELF NOTE stamping means that every binary Lunar produces can be traced back to the BTC forge that built the compiler — even if the compiler was installed months ago and the build logs have been rotated.
LEDE and OpenWrt are the primary consumers of embedded cross-compilers. They expect a standard {triple}- prefixed toolchain in staging_dir/toolchain-{arch}/ and use ARCH={arch} CROSS_COMPILE={triple}- as Make variables passed to every make invocation. BTC.sh's target registry includes LEDE-relevant targets directly: mipselr2 (MIPS32R2 little-endian, matching the MALTA reference platform used by most LEDE router profiles), armv7 (ARMv7-A hard-float NEON, covering RPi 2/3 32-bit, BeagleBone, Odroid, and virtually every Cortex-A SoC), and the Intel Atom family (silvermont, goldmont, tremont, sierraforest) for x86_64 embedded gateways and routers.
Integration with OpenWrt's build system (openwrt/Makefile and rules.mk) is done by overriding CONFIG_TARGET_OPTERON paths or by symlinking the BTC sysroot into staging_dir/. The .config fragment for a MIPS LEDE build using a BTC-forged toolchain would set:
CONFIG_TARGET_ARCH="mipsel"
+CONFIG_TARGET_OPTERON=""
+CONFIG_TOOLCHAIN_ROOT="/opt/btc/DCOSNET-MIPSELR2-MIPS32-LTO"
+CONFIG_TOOLCHAIN_PREFIX="mipsel-dcosnet-linux-musl-"
+CROSS_COMPILE="${CONFIG_TOOLCHAIN_ROOT}/bin/${CONFIG_TOOLCHAIN_PREFIX}"
+
+BTC.sh's musl targets are particularly relevant here — OpenWrt moved to musl as its default C library years ago, and the mipselr2 and armv7 targets produce musl-based toolchains that match OpenWrt's expectations. The forensic stamping provides an additional benefit in the embedded context: when a firmware image is deployed to a router, the .note.BTC section in every binary on the filesystem makes it possible to audit which toolchain produced the firmware, which is valuable for supply-chain verification and compliance audits.
For projects that are not distribution-specific — standalone C/C++ projects, embedded firmware builds, or CI/CD pipelines — the BTC toolchain integrates through standard environment variables. The golden image is extracted, and the PATH, CC, CXX, CFLAGS, and LDFLAGS are set to point at the BTC sysroot. The manifest JSON provides all the metadata needed for automation:
#!/bin/bash
+SYSROOT="/opt/btc/DCOSNET-ZNVER4-AVX512-LTO"
+MANIFEST="${SYSROOT%/*}/${SYSROOT##*/}-manifest.json"
+
+TRIPLE=$(jq -r .target_triple "$MANIFEST")
+MARCH=$(jq -r .target_march "$MANIFEST")
+CLIB=$(jq -r .clib "$MANIFEST")
+
+export PATH="${SYSROOT}/bin:${PATH}"
+export CC="${TRIPLE}-gcc"
+export CXX="${TRIPLE}-g++"
+export CFLAGS="-O2 -march=${MARCH} -mtune=${MARCH} -pipe"
+export CXXFLAGS="${CFLAGS}"
+export PKG_CONFIG_SYSROOT_DIR="${SYSROOT}"
+export PKG_CONFIG_LIBDIR="${SYSROOT}/usr/lib/pkgconfig"
+
+make CROSS_COMPILE="${TRIPLE}-" ARCH=$(jq -r .target_arch "$MANIFEST")
+
+The BTC manifest also includes the integration keys for sorcery-go and Fester, making it possible for automated systems to discover and configure the toolchain without human intervention. The integrations.sorcery-go block specifies the environment variables that sorcery-go expects (SORCERY_GO_BTC_PATH, SORCERY_GO_BTC_ROOT, SORCERY_GO_BTC_SYS_LABEL), and the integrations.fester block specifies the YAML configuration keys that Fester uses to enable BTC toolchain support on a per-node basis.
The three-tier identity system and dual-layer forensic stamping are not security features in the cryptographic sense — they do not prevent an attacker from modifying a binary, and they do not provide integrity verification through digital signatures. What they provide is supply-chain provenance: the ability to answer, with high confidence, questions about the origin and consistency of a binary artifact. The specific security properties are:
+ +Given any binary produced by a BTC-forged toolchain, readelf -n reveals the exact build machine (via the signature tier and token), the target microarchitecture, the kernel version used for headers, and the system label. This makes it possible to trace a binary back to the specific BTC invocation that produced it. In a cluster deployment, the shared cluster token identifies which cluster produced the binary. In a TPM-sealed deployment, the PCR digest identifies the specific physical machine and its firmware state at build time. In a poly deployment, the per-machine salt identifies the specific host.
The user.btc.hash xattr records the SHA-256 hash of the binary at stamp time. By recomputing the hash and comparing it to the stored value, a verification script can detect any post-stamping modification to the binary. This catches both accidental corruption (bit rot, truncated copies) and deliberate tampering (modified binaries, injected code). The verification is trivial: sha256sum /path/to/binary | awk '{print $1}' compared against getfattr -n user.btc.hash --only-values /path/to/binary. If they differ, the binary has been modified since it left the forge.
In a multi-node deployment where all machines use the same cluster token, the Sig: field in the ELF NOTE provides a quick cluster-membership test. Any binary from the cluster will carry the same token. A binary with a different (or missing) token either came from outside the cluster, was built before the machine joined the cluster, or was built with a different toolchain entirely. This is particularly useful in Fester-managed clusters, where nodes may join and leave over time — the signature token provides a persistent identity that survives node churn.
The TPM tier provides a hardware-bound identity that changes if the platform configuration changes. PCR registers 0-7 cover the BIOS, firmware, bootloader configuration, and secure boot state. If any of these change — a BIOS update, a firmware flash, a secure boot key rotation — the PCR digest will differ, and the next BTC build will produce a different signature token. This provides a passive detection mechanism: by comparing the Sig: fields across binaries built at different times, an operator can determine whether the underlying hardware state changed between builds, without needing to separately audit the TPM state.
The JSON manifest sidecar provides a machine-readable record of every build parameter: package versions, target triple, optimization flags, C library choice, signature tier, and token. When combined with the per-binary ELF NOTE data and the checksum manifests from f_download(), this creates a complete audit trail from upstream source tarball to final binary. An auditor can verify that the binutils version in the manifest matches the checksum on disk, that the GCC flags match the expected microarchitecture, and that every binary in the sysroot carries the expected .note.BTC section. This is not a formal SBOM (Software Bill of Materials) in the SPDX or CycloneDX sense, but it contains the same information in a format that is directly queryable from the binaries themselves.
BTC.sh provides three utility functions that form the acquire-and-package lifecycle. f_download() fetches and validates upstream source tarballs. f_decompress() auto-detects the compression format from the file extension and dispatches to the appropriate tool: tar -axf for xz, tar -xzf for gzip, tar -xjf for bzip2, tar -axf for lzip, tar -x -I lrzip for lrzip, and unzip for zip archives. It accepts either a bare filename (looked up in SOURCE_CACHE) or an absolute path, making it usable both during the build sequence and for ad-hoc operations. f_compress() provides the inverse operation, stepping down through a USE_COMPRESSOR variable to select the final packaging algorithm — xz (maximum, default), gzip, bzip2, lz, or lrzip.
The decompression function is called at every point in the build sequence where source extraction is needed — binutils, kernel headers, GCC (twice, for each stage), glibc, musl, libxcrypt, and the support libraries (GMP, MPFR, MPC). Each call is a single line: f_decompress "${v_binutils}.tar.xz". The function resolves the file from the source cache, changes to the ramfs cleanroom, and extracts. There are no hardcoded tar commands anywhere in the build functions — every extraction goes through f_decompress(), which means adding support for a new compression format requires changing exactly one case branch.
The JSON manifest is the integration contract. It is written at the end of f_package() and contains every piece of metadata that an external system needs to configure the toolchain: the target triple, the microarchitecture march string, the ISA tier, the C library and its version, the full CFLAGS and LDFLAGS used during the build, the signature tier and token, the paths to the forensic stamp locations (both ELF NOTE and xattr names), and explicit integration keys for sorcery-go and Fester. The manifest filename encodes the system label: DCOSNET-SKYLAKE-X-AVX512-LTO-manifest.json.
Sorcery-go's pkg/toolchain/btc.go reads this manifest to populate its BTCStamp struct. Fester's backend/toolchain/btc.py reads it to configure per-node build environments. A standalone user can jq it to extract whatever they need. The manifest is the reason the golden image is not just a tarball — it is a self-describing artifact that carries its own configuration documentation.
BTC.sh is developed by dcos.net and released under AGPL-3.0-or-later. The reference implementation discussed here is version 0.4.1. Source Mage GNU/Linux is developed at sourcemage.org under its own project governance. Gentoo, Lunar Linux, LEDE, and OpenWrt are the respective trademarks of their communities.
+ + \ No newline at end of file diff --git a/cleanup.sh b/cleanup.sh new file mode 100755 index 0000000..1b06ac4 --- /dev/null +++ b/cleanup.sh @@ -0,0 +1,10 @@ +# On target: +cd /opt/BTC +rm -rf BTC-0.4.1 +umount -l /usr/src 2>/dev/null || true +rm -rf /usr/src/DCOSNET-HASWELL-AVX2-LTO-cleanroom +rm -rf logs/DCOSNET-HASWELL-AVX2-LTO +# Upload the fixed BTC.sh from download/, then: +mkdir -p BTC-0.4.1 +cp BTC.sh BTC-0.4.1/ +cd BTC-0.4.1 && ./BTC.sh \ No newline at end of file