musl
Source
FROM stagex/bootstrap-stage3 AS build
ARG TARGETARCH
ARG VERSION
ADD fetch/musl-${VERSION}.tar.gz .
COPY --from=stagex/core-mimalloc / /
WORKDIR /musl-${VERSION}
ADD *.patch .
RUN --network=none <<-EOF
set -eux
ARCH=$(uname -m)
export CFLAGS="-Wformat -Werror=format-security -fstack-protector-strong -fstack-clash-protection"
export LDFLAGS="-Wl,--as-needed,-O1,--sort-common -Wl,-soname,libc.musl-${ARCH}.so.1"
patch -p1 < CVE-2025-26519.patch
# Double the amount of TLS keys from 128 (default) to 256 (default in `glibc`)
#
# When `mrustc` builds Rust 1.90.0, the `mrustc`-built `rustc` panics when ran due to running out
# of TLS keys. Unfortunately, that can't reasonably be fixed downstream in the `core-rust` package
# because this limit is defined in `libc` and compiled into the `libc` artifacts. Rust 1.90.0 also
# had issues with Termux's packaging for Android, their solution being to emulate TLS instead of
# using the `libc`'s, adding evidence of `rustc` using _more and more_ TLS keys. A `rustc`-built
# `rustc 1.90.0` didn't have these issues within StageX however, suggesting while `rustc` uses
# many TLS keys, it's `mrustc`'s compilation of it adding the overhead which is our killer blow.
#
# This should be acceptable here as a patch for greater compatibility with various
# programs/packages even if ideally, `core-rust` sorted this out on its end and this was removed
# so `core-musl` could be more stock. Note this does increase the size of a static allocation, so
# this does have a performance penalty. It shouldn't be unacceptable though as the limit in
# `glibc` is 1024. `musl` is generally much more conservative regarding thread overhead though.
sed -i -E s/"PTHREAD_KEYS_MAX[ ]+128"/"PTHREAD_KEYS_MAX 256"/ include/limits.h
# Remove the existing allocator
rm -rf src/malloc
rm src/legacy/valloc.c
rm src/string/strdup.c
rm src/string/strndup.c
# Stub the `mallocng` folder so `musl` doesn't realize it's been removed
mkdir -p src/malloc/mallocng
# Stub the APIs `musl` requires but `mimalloc` doesn't provide
# These are constants which trigger some conditional branches re: assumptions made
echo "int __malloc_replaced = 1;" >> src/malloc/mallocng/stub.c
echo "int __aligned_alloc_replaced = 1;" >> src/malloc/mallocng/stub.c
# This allows a `mmap`'d page to be given to the allocator for use, which isn't possible with `mimalloc`
# TODO: Should we do _something_ with these pointers, like unmap the page?
echo "void __malloc_donate(char *a, char *b) {}" >> src/malloc/mallocng/stub.c
# Link in `mimalloc`
MIMALLOC_O=$(find /usr/lib -name mimalloc-secure.o)
# Strip the `mimalloc` files linked in to only what's required and what we're replacing in `musl`
KEEP="malloc __libc_malloc malloc_usable_size"
KEEP="$KEEP calloc __libc_calloc"
KEEP="$KEEP realloc __libc_realloc"
KEEP="$KEEP free __libc_free"
KEEP="$KEEP aligned_alloc memalign posix_memalign"
KEEP="$KEEP reallocarray"
KEEP="$KEEP valloc strdup strndup"
for symbol in $(nm -f just-symbols $MIMALLOC_O); do
EMPTY_IF_NOT_PRESENT=$(echo " $KEEP " | grep " $symbol " || true)
if [ "$EMPTY_IF_NOT_PRESENT" = "" ]; then
# This `strip` may not work if this symbol is still relied upon in a relocation
strip --strip-symbol="$symbol" $MIMALLOC_O || true
fi
done
# For whatever reason, this adds `mimalloc`'s object file only to the shared object...
export LDFLAGS="$LDFLAGS -Wl,--push-state,--whole-archive,$MIMALLOC_O,--pop-state"
./configure \
--prefix=/usr \
--sysconfdir=/etc \
--mandir=/usr/share/man \
--infodir=/usr/share/info \
--localstatedir=/var \
--enable-optimize
make -j "$(nproc)"
make DESTDIR=/rootfs install
mkdir -p /rootfs/usr/bin /rootfs/usr/lib
rm -rf /rootfs/lib
ln -sf /usr/lib/ld-musl-${ARCH}.so.1 /rootfs/usr/bin/ldd
mv -f /rootfs/usr/lib/libc.so /rootfs/usr/lib/ld-musl-${ARCH}.so.1
ln -sf ld-musl-${ARCH}.so.1 /rootfs/usr/lib/libc.musl-${ARCH}.so.1
ln -sf /usr/lib/ld-musl-${ARCH}.so.1 /rootfs/usr/lib/libc.so
# Manually add `mimalloc`'s static archive to the static `libc`
ar r /rootfs/usr/lib/libc.a $MIMALLOC_O
# `mimalloc` also depends on `__popcountdi2` from `libgcc` or `compiler-rt`.
# Frustratingly, `mimalloc` only does this if it detects GCC and assumes it can rely on it.
# It doesn't allow disabling it for those who use GCC but don't want to require `libgcc`.
# Thankfully, that also means this block of code should disappear if built by LLVM.
mkdir c_runtime
cd c_runtime
ar x $(find /usr/lib -type f -name libgcc.a)
for file in $(ls); do
if [ ! "$(nm -f just-symbols $file | grep __popcountdi2)" = "" ]; then
ar r /rootfs/usr/lib/libc.a $file
break
fi
done
EOF
FROM stagex/core-filesystem AS package
COPY --from=build /rootfs/ /Copied to clipboard!