@@ -48,6 +48,17 @@ RUN set -eux; \
4848 find /deps -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true; \
4949 find /deps -type f -name '*.pyc' -delete 2>/dev/null || true; \
5050 find /deps -name '*.so*' -exec strip --strip-unneeded {} + 2>/dev/null || true
51+ # Patch pip's user_agent() — the original probes platform/distro/libc/ssl
52+ # which triggers buddy allocator corruption in unikraft's memory manager.
53+ RUN python3 -c "\
54+ import re, pathlib, sys; \
55+ p = pathlib.Path('/usr/local/lib/python3.12/site-packages/pip/_internal/network/session.py'); \
56+ src = p.read_text(); \
57+ patched = re.sub(r'(def user_agent\(\) [^:]*:).*?(\n (?:def |class ))', \
58+ r'\1\n return \" pip/hyperlight\"\n\n\2 ', src, count=1, flags=re.DOTALL); \
59+ assert patched != src, 'pip user_agent() regex did not match — pip version changed?'; \
60+ p.write_text(patched)" && \
61+ python3 -c "from pip._internal.network.session import user_agent; assert user_agent() == 'pip/hyperlight'"
5162
5263# Stage 2: build hl_pydriver against the SAME Python 3.12-from-source
5364# that produces local-python-base, so the glibc/libpython3.12.so ABI
@@ -70,11 +81,47 @@ FROM ${BASE} AS rootfs
7081COPY --from=deps /deps /usr/local/lib/python3.12/site-packages
7182COPY --from=driver-build /src/hl_pydriver /bin/hl_pydriver
7283COPY pydoc_stub.py /usr/local/lib/python3.12/pydoc.py
84+ # pip for in-guest package installation (vfork+execve subprocess)
85+ COPY --from=deps /usr/local/lib/python3.12/site-packages/pip /usr/local/lib/python3.12/site-packages/pip
86+ COPY --from=deps /usr/local/lib/python3.12/ensurepip /usr/local/lib/python3.12/ensurepip
87+ # stdlib modules needed by pip but missing from python-base
88+ COPY --from=deps /usr/local/lib/python3.12/xmlrpc /usr/local/lib/python3.12/xmlrpc
89+ COPY --from=deps /usr/local/lib/python3.12/zipapp.py /usr/local/lib/python3.12/zipapp.py
90+ # DNS-over-TCP resolver and pip target path (vfork subprocess support)
91+ COPY rootfs/usr/local/lib/python3.12/sitecustomize.py /usr/local/lib/python3.12/sitecustomize.py
92+ COPY rootfs/etc/pip.conf /etc/pip.conf
93+
94+ # Stage 3b: build static PIE busybox (elfloader only supports ET_DYN).
95+ FROM debian:bookworm-slim AS utils-build
96+ RUN apt-get update && apt-get install -y --no-install-recommends \
97+ gcc libc6-dev make wget bzip2 ca-certificates && \
98+ rm -rf /var/lib/apt/lists/*
99+ RUN wget -q https://busybox.net/downloads/busybox-1.36.1.tar.bz2 && \
100+ tar xf busybox-1.36.1.tar.bz2 && cd busybox-1.36.1 && \
101+ make defconfig && \
102+ sed -i 's/CONFIG_TC=y/# CONFIG_TC is not set/' .config && \
103+ sed -i 's/# CONFIG_STATIC is not set/CONFIG_STATIC=y/' .config && \
104+ sed -i 's|CONFIG_EXTRA_CFLAGS=""|CONFIG_EXTRA_CFLAGS="-fPIE -fPIC"|' .config && \
105+ make -j$(nproc) && \
106+ gcc -fPIE -fPIC -static-pie -o /busybox \
107+ -Wl,--sort-common -Wl,--sort-section -Wl,alignment \
108+ -Wl,--start-group \
109+ applets/built-in.o \
110+ $(find . -name 'lib.a' -path './*/lib.a' | sort) \
111+ -Wl,--end-group \
112+ -lm -lresolv && \
113+ strip /busybox
73114
74115# Stage 4: pack CPIO.
75116FROM alpine:3.20 AS cpio
76117RUN apk add --no-cache cpio findutils ca-certificates
77118COPY --from=rootfs / /rootfs/
119+ COPY --from=utils-build /busybox /rootfs/bin/busybox
120+ RUN cd /rootfs && for cmd in sh cat ls cp mv rm mkdir rmdir ln head tail wc \
121+ grep sed awk sort uniq tr cut tee xargs find test basename dirname \
122+ env which id whoami uname hostname date sleep echo true; do \
123+ ln -sf busybox bin/$cmd; \
124+ done
78125
79126# DNS configuration for glibc's getaddrinfo
80127RUN mkdir -p /rootfs/etc && \
0 commit comments