build: enable builds with libpathrs

pathrs-lite supports transparently switching to libpathrs.so as the
backend with the "libpathrs" build tag. In order to make this work
properly with our CI and release build scripts, we we need to have a
similar setup as with we do with libseccomp.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
This commit is contained in:
Aleksa Sarai
2026-02-03 21:31:12 +01:00
parent b58e342758
commit 8689e50cbe
6 changed files with 213 additions and 26 deletions
+20 -8
View File
@@ -1,6 +1,7 @@
ARG GO_VERSION=1.25 ARG GO_VERSION=1.25
ARG BATS_VERSION=v1.12.0 ARG BATS_VERSION=v1.12.0
ARG LIBSECCOMP_VERSION=2.6.0 ARG LIBSECCOMP_VERSION=2.6.0
ARG LIBPATHRS_VERSION=0.2.4
FROM golang:${GO_VERSION}-trixie FROM golang:${GO_VERSION}-trixie
ARG DEBIAN_FRONTEND=noninteractive ARG DEBIAN_FRONTEND=noninteractive
@@ -9,10 +10,13 @@ ARG CRIU_REPO=https://download.opensuse.org/repositories/devel:/tools:/criu/Debi
RUN KEYFILE=/usr/share/keyrings/criu-repo-keyring.gpg; \ RUN KEYFILE=/usr/share/keyrings/criu-repo-keyring.gpg; \
wget -nv $CRIU_REPO/Release.key -O- | gpg --dearmor > "$KEYFILE" \ wget -nv $CRIU_REPO/Release.key -O- | gpg --dearmor > "$KEYFILE" \
&& echo "deb [signed-by=$KEYFILE] $CRIU_REPO/ /" > /etc/apt/sources.list.d/criu.list \ && echo "deb [signed-by=$KEYFILE] $CRIU_REPO/ /" > /etc/apt/sources.list.d/criu.list \
&& dpkg --add-architecture i386 \ && printf "%s\n" i386 armel armhf arm64 ppc64el s390x riscv64 | xargs -t -n1 -- dpkg --add-architecture \
&& apt-get update \ && apt-get update \
&& apt-get install -y --no-install-recommends \ && apt-get install -y --no-install-recommends \
build-essential \ build-essential \
cargo \
cargo-auditable \
clang \
criu \ criu \
gcc \ gcc \
gcc-multilib \ gcc-multilib \
@@ -22,6 +26,7 @@ RUN KEYFILE=/usr/share/keyrings/criu-repo-keyring.gpg; \
iptables \ iptables \
jq \ jq \
kmod \ kmod \
lld \
pkg-config \ pkg-config \
python3-minimal \ python3-minimal \
sshfs \ sshfs \
@@ -29,13 +34,13 @@ RUN KEYFILE=/usr/share/keyrings/criu-repo-keyring.gpg; \
uidmap \ uidmap \
iproute2 \ iproute2 \
&& apt-get install -y --no-install-recommends \ && apt-get install -y --no-install-recommends \
libc-dev:i386 libgcc-s1:i386 \ libc-dev:i386 libgcc-s1:i386 gcc-i686-linux-gnu libstd-rust-dev:i386 \
gcc-aarch64-linux-gnu libc-dev-arm64-cross \ gcc-aarch64-linux-gnu libc-dev-arm64-cross libstd-rust-dev:arm64 \
gcc-arm-linux-gnueabi libc-dev-armel-cross \ gcc-arm-linux-gnueabi libc-dev-armel-cross libstd-rust-dev:armel \
gcc-arm-linux-gnueabihf libc-dev-armhf-cross \ gcc-arm-linux-gnueabihf libc-dev-armhf-cross libstd-rust-dev:armhf \
gcc-powerpc64le-linux-gnu libc-dev-ppc64el-cross \ gcc-powerpc64le-linux-gnu libc-dev-ppc64el-cross libstd-rust-dev:ppc64el \
gcc-s390x-linux-gnu libc-dev-s390x-cross \ gcc-s390x-linux-gnu libc-dev-s390x-cross libstd-rust-dev:s390x \
gcc-riscv64-linux-gnu libc-dev-riscv64-cross \ gcc-riscv64-linux-gnu libc-dev-riscv64-cross libstd-rust-dev:riscv64 \
&& apt-get clean \ && apt-get clean \
&& rm -rf /var/cache/apt /var/lib/apt/lists/* /etc/apt/sources.list.d/*.list && rm -rf /var/cache/apt /var/lib/apt/lists/* /etc/apt/sources.list.d/*.list
@@ -64,6 +69,13 @@ RUN mkdir -p $DYLIB_DIR \
&& /tmp/script/build-seccomp.sh "$LIBSECCOMP_VERSION" $DYLIB_DIR $RELEASE_ARCHES && /tmp/script/build-seccomp.sh "$LIBSECCOMP_VERSION" $DYLIB_DIR $RELEASE_ARCHES
ENV LIBSECCOMP_VERSION=$LIBSECCOMP_VERSION ENV LIBSECCOMP_VERSION=$LIBSECCOMP_VERSION
# install libpathrs
ARG LIBPATHRS_VERSION
COPY script/build-libpathrs.sh /tmp/script/
RUN mkdir -p $DYLIB_DIR \
&& /tmp/script/build-libpathrs.sh "$LIBPATHRS_VERSION" $DYLIB_DIR $RELEASE_ARCHES
ENV LIBPATHRS_VERSION=$LIBPATHRS_VERSION
ENV LD_LIBRARY_PATH=$DYLIB_DIR/lib ENV LD_LIBRARY_PATH=$DYLIB_DIR/lib
ENV PKG_CONFIG_PATH=$DYLIB_DIR/lib/pkgconfig ENV PKG_CONFIG_PATH=$DYLIB_DIR/lib/pkgconfig
+151
View File
@@ -0,0 +1,151 @@
#!/bin/bash
# Copyright (C) 2026 Open Containers Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -xEeuo pipefail
# shellcheck source=./script/lib.sh
source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
PLATFORM="$(get_platform)"
declare -A GOARCH_TO_RUST_TARGET=(
["386"]=i686-unknown-linux-gnu
["amd64"]=x86_64-unknown-linux-gnu
["arm64"]=aarch64-unknown-linux-gnu
["armel"]=armv5te-unknown-linux-gnueabi
["armhf"]=armv7-unknown-linux-gnueabihf
["ppc64le"]=powerpc64le-unknown-linux-gnu
["s390x"]=s390x-unknown-linux-gnu
["riscv64"]=riscv64gc-unknown-linux-gnu
)
declare -A RUST_TARGET_TO_CC=(
["i686-unknown-linux-gnu"]="i686-${PLATFORM}-gcc"
["x86_64-unknown-linux-gnu"]="x86_64-${PLATFORM}-gcc"
["aarch64-unknown-linux-gnu"]="aarch64-${PLATFORM}-gcc"
["armv5te-unknown-linux-gnueabi"]="arm-${PLATFORM}eabi-gcc"
["armv7-unknown-linux-gnueabihf"]="arm-${PLATFORM}eabihf-gcc"
["powerpc64le-unknown-linux-gnu"]="powerpc64le-${PLATFORM}-gcc"
["s390x-unknown-linux-gnu"]="s390x-${PLATFORM}-gcc"
["riscv64gc-unknown-linux-gnu"]="riscv64-${PLATFORM}-gcc"
)
# sha256 checksums for libpathrs release tarballs.
declare -A LIBPATHRS_SHA256=(
["0.2.4"]=45aca68e698b844fae0cf7c459bc441519b0e7b48397caa7d3936cfc68d73f77
)
function generate_cargo_config() {
for rust_target in "${GOARCH_TO_RUST_TARGET[@]}"; do
local target_gcc="${RUST_TARGET_TO_CC[$rust_target]}"
# Based on <https://wiki.debian.org/Rust#Crosscompiling>.
cat <<-EOF
[target.$rust_target]
linker = "$target_gcc"
rustflags = ["-L", "$(rustc --print sysroot)/lib/rustlib/$rust_target/lib"]
EOF
done
}
# Due to libpathrs being MPLv2/LGPLv3 we must include its sources, so
# download, install and build against it.
# Parameters:
# $1 -- libpathrs version to download and build.
# $2 -- destination directory.
# $@ -- additional architectures to cross-compile for (optional)
function build_libpathrs() {
local ver="$1"
shift
local dest="$1"
shift
local go_arches=("$@")
local tar="libpathrs-${ver}.tar.xz"
# Download, check, and extract.
wget "https://github.com/cyphar/libpathrs/releases/download/v${ver}/${tar}"{,.asc}
sha256sum --strict --check - <<<"${LIBPATHRS_SHA256[${ver}]} *${tar}"
local srcdir
srcdir="$(mktemp -d)"
tar xf "$tar" -C "$srcdir"
pushd "$srcdir/libpathrs-$ver" || return
# Use cargo-auditable if available.
if cargo auditable --version &>/dev/null; then
export CARGO="cargo auditable"
fi
local extra_cargo_flags=("--locked")
# If we are being asked to install this in a system library directory
# (i.e., --prefix=/usr or something similar), the correct place to put
# libpathrs.so depends very strongly on the distro we are running on, and
# detecting this in a generic way is quite difficult.
#
# The simplest solution is to use a disto-packaged binary to detect where
# libc.so is installed and use the same import path, so we look at
# /proc/self/maps and parse out the parent directory of the libc.so being
# used.
local native_libdir libdir=
native_libdir="$(awk '$NF ~ /\/libc\>.*\.so/ { print $NF; }' /proc/self/maps |
sort -u | head -n1 | xargs dirname)"
if [[ "$native_libdir" == "$dest/"* ]]; then
libdir="$native_libdir"
fi
# Install native version for Dockerfile builds.
make \
EXTRA_CARGO_FLAGS="${extra_cargo_flags[*]}" \
release
./install.sh \
--prefix="$dest" \
--libdir="$libdir"
cargo clean
local cargo_config
cargo_config="$(mktemp --tmpdir runc-libpathrs-cargo.toml.XXXXXX)"
# shellcheck disable=SC2064 # We want to resolve the path here.
trap "rm -f '$cargo_config'" EXIT
# Only use the cross-compile config when we actually need to cross-compile.
# RedHat-based distros insist on calling their targets "$ARCH-redhat-linux"
# which breaks our above logic, but we don't ever need to cross-compile on
# RedHat distros so we can ignore this.
generate_cargo_config >"$cargo_config"
extra_cargo_flags+=("--config=$cargo_config")
for go_arch in "${go_arches[@]}"; do
local rust_target="${GOARCH_TO_RUST_TARGET[$go_arch]}"
make \
EXTRA_CARGO_FLAGS="${extra_cargo_flags[*]} --target=$rust_target" \
release
./install.sh \
--rust-target="$rust_target" \
--prefix="$dest/$go_arch"
cargo clean
done
# Place the source tarball to $dest/src.
popd || return
mkdir -p "$dest"/src
mv "$tar"{,.asc} "$dest"/src
}
if [ $# -lt 2 ]; then
echo "Usage: $0 <version> <dest-dir> [<extra-arch> ...]" >&2
exit 1
fi
build_libpathrs "$@"
+1 -1
View File
@@ -60,7 +60,7 @@ function build_libseccomp() {
# Place the source tarball to $dest/src. # Place the source tarball to $dest/src.
popd || return popd || return
mkdir "$dest"/src mkdir -p "$dest"/src
mv "$tar"{,.asc} "$dest"/src mv "$tar"{,.asc} "$dest"/src
} }
+30 -15
View File
@@ -1,41 +1,56 @@
#!/bin/bash #!/bin/bash
# get_platform computes the platform section of target triples on this OS.
function get_platform() {
# Fedora doesn't have ID_LIKE and only has ID=fedora, so we need to
# construct a fake ID_LIKE to treat AlmaLinux and Fedora the same way.
local ID_LIKE
# shellcheck source=/etc/os-release disable=SC1091 # outside our sources
ID_LIKE="$(
source /etc/os-release
echo "${ID:-} ${ID_LIKE:-}"
)"
local PLATFORM
case "$ID_LIKE" in
*suse*)
PLATFORM=suse-linux
;;
*rhel* | *fedora* | *centos*)
PLATFORM=redhat-linux
;;
*)
PLATFORM=linux-gnu
;;
esac
echo "$PLATFORM"
}
# set_cross_vars sets a few environment variables used for cross-compiling, # set_cross_vars sets a few environment variables used for cross-compiling,
# based on the architecture specified in $1. # based on the architecture specified in $1.
function set_cross_vars() { function set_cross_vars() {
GOARCH="$1" # default, may be overridden below GOARCH="$1" # default, may be overridden below
unset GOARM unset GOARM
PLATFORM=linux-gnu PLATFORM="$(get_platform)"
# openSUSE has a custom PLATFORM [[ "$PLATFORM" == *suse* ]] && is_suse=1
if grep -iq "ID_LIKE=.*suse" /etc/os-release; then
PLATFORM=suse-linux
is_suse=1
fi
case $1 in case "$1" in
386) 386)
# Always use the 64-bit compiler to build the 386 binary, which works # Always use the 64-bit compiler to build the 386 binary, which works
# for the more common cross-build method for x86 (namely, the # for the more common cross-build method for x86 (namely, the
# equivalent of dpkg --add-architecture). # equivalent of dpkg --add-architecture).
local cpu_type local cpu_type
if [ -v is_suse ]; then if [ -v is_suse ]; then
# There is no x86_64-suse-linux-gcc, so use the native one.
HOST=
cpu_type=i586 cpu_type=i586
else else
HOST=x86_64-${PLATFORM}
cpu_type=i686 cpu_type=i686
fi fi
HOST=x86_64-${PLATFORM}
CFLAGS="-m32 -march=$cpu_type ${CFLAGS[*]}" CFLAGS="-m32 -march=$cpu_type ${CFLAGS[*]}"
;; ;;
amd64) amd64)
if [ -n "${is_suse:-}" ]; then
# There is no x86_64-suse-linux-gcc, so use the native one.
HOST=
else
HOST=x86_64-${PLATFORM} HOST=x86_64-${PLATFORM}
fi
;; ;;
arm64) arm64)
HOST=aarch64-${PLATFORM} HOST=aarch64-${PLATFORM}
+4 -1
View File
@@ -20,6 +20,7 @@ set -e
# Project-specific options and functions. In *theory* you shouldn't need to # Project-specific options and functions. In *theory* you shouldn't need to
# touch anything else in this script in order to use this elsewhere. # touch anything else in this script in order to use this elsewhere.
: "${LIBSECCOMP_VERSION:=2.6.0}" : "${LIBSECCOMP_VERSION:=2.6.0}"
: "${LIBPATHRS_VERSION:=0.2.4}"
project="runc" project="runc"
root="$(readlink -f "$(dirname "${BASH_SOURCE[0]}")/..")" root="$(readlink -f "$(dirname "${BASH_SOURCE[0]}")/..")"
@@ -48,6 +49,8 @@ function build_project() {
dylibdir="$(mktemp -d)" dylibdir="$(mktemp -d)"
# Download and build libseccomp. # Download and build libseccomp.
"$root/script/build-seccomp.sh" "$LIBSECCOMP_VERSION" "$dylibdir" "${arches[@]}" "$root/script/build-seccomp.sh" "$LIBSECCOMP_VERSION" "$dylibdir" "${arches[@]}"
# Download and build libpathrs.
"$root/script/build-libpathrs.sh" "$LIBPATHRS_VERSION" "$dylibdir" "${arches[@]}"
fi fi
# For reproducible builds, add these to EXTRA_LDFLAGS: # For reproducible builds, add these to EXTRA_LDFLAGS:
@@ -84,7 +87,7 @@ function build_project() {
exit 1 exit 1
fi fi
# Copy libseccomp source tarball. # Copy dylib source tarballs.
cp "$dylibdir"/src/* "$builddir" cp "$dylibdir"/src/* "$builddir"
} }
+6
View File
@@ -112,6 +112,9 @@ tmp_seccomp_gpgflags=("--homedir=$tmp_gpgdir" "--no-default-keyring" "--keyring=
gpg "${tmp_seccomp_gpgflags[@]}" --recv-keys 0x47A68FCE37C7D7024FD65E11356CE62C2B524099 gpg "${tmp_seccomp_gpgflags[@]}" --recv-keys 0x47A68FCE37C7D7024FD65E11356CE62C2B524099
gpg "${tmp_seccomp_gpgflags[@]}" --recv-keys 0x7100AADFAE6E6E940D2E0AD655E45A5AE8CA7C8A gpg "${tmp_seccomp_gpgflags[@]}" --recv-keys 0x7100AADFAE6E6E940D2E0AD655E45A5AE8CA7C8A
tmp_libpathrs_gpgflags=("--homedir=$tmp_gpgdir" "--no-default-keyring" "--keyring=libpathrs.keyring" "--keyserver=keys.openpgp.org")
gpg "${tmp_libpathrs_gpgflags[@]}" --recv-keys 0xC9C370B246B09F6DBCFC744C34401015D1D2D386
gpg "${gpgflags[@]}" --clear-sign <<<"[This is test text used for $project release scripts. $(date --rfc-email)]" | gpg "${gpgflags[@]}" --clear-sign <<<"[This is test text used for $project release scripts. $(date --rfc-email)]" |
gpg "${tmp_runc_gpgflags[@]}" --verify || bail "Signing key ${keyid:-DEFAULT} is not in trusted $project.keyring list!" gpg "${tmp_runc_gpgflags[@]}" --verify || bail "Signing key ${keyid:-DEFAULT} is not in trusted $project.keyring list!"
@@ -156,4 +159,7 @@ gpg "${tmp_runc_gpgflags[@]}" --verify "$project.$hashcmd"
# Verify seccomp tarball. # Verify seccomp tarball.
gpg "${tmp_seccomp_gpgflags[@]}" --verify libseccomp*.asc gpg "${tmp_seccomp_gpgflags[@]}" --verify libseccomp*.asc
# Verify libpathrs tarball.
gpg "${tmp_libpathrs_gpgflags[@]}" --verify libpathrs*.asc
popd popd