From 83297d9360b4107509baf7e2444eecee05809dc4 Mon Sep 17 00:00:00 2001 From: IanM Date: Wed, 21 Oct 2026 14:52:56 +0100 Subject: [PATCH] fix: build FPM images on patched PHP 8.3.36 / 8.5.12 from source PHP 8.3.36 and 8.5.12 fix CVE-2026-109618 and CVE-2026-109619 (PHP2Shell, unauthenticated RCE), but the official php:8.x images have not caught up yet. Until they do, rebuild PHP from the php.net source release over the existing base image. The base image already records how it was built: php-config gives the configure flags, PHP_CFLAGS and friends the compiler flags, and /usr/src/php.tar.xz the source. bin/php-from-source swaps in the new tarball (verified against its pinned sha256) and repeats that build. Replacing the tarball matters as much as the binaries: docker-php-ext-install compiles gd, intl and the other bundled extensions from it. The step runs before any extension or pecl builds so they compile against the patched PHP, and adds back the -dev libraries the base image purged after its own build. It is a no-op once the base image is at or past the pinned version, so it retires itself when the official images update. --- bin/php-from-source | 83 +++++++++++++++++++++++++++++++++++++++ fpm/8.3/Dockerfile.apache | 15 +++++++ fpm/8.3/Dockerfile.cli | 15 +++++++ fpm/8.5/Dockerfile.apache | 15 +++++++ fpm/8.5/Dockerfile.cli | 15 +++++++ 5 files changed, 143 insertions(+) create mode 100755 bin/php-from-source diff --git a/bin/php-from-source b/bin/php-from-source new file mode 100755 index 0000000..54b50e3 --- /dev/null +++ b/bin/php-from-source @@ -0,0 +1,83 @@ +#!/bin/sh +# Rebuilds PHP from a php.net source release over the official php:* base image. +# +# Used when a security release is out on php.net but the official Docker images +# have not caught up yet. The base image already records everything needed to +# reproduce its own build: the configure flags (php-config), the compiler flags +# (PHP_CFLAGS etc.) and the source tarball (/usr/src/php.tar.xz). This script +# swaps in the new tarball and repeats that build with the same flags. +# +# Usage: php-from-source .tar.xz> +# +# It is a no-op once the base image is already at or past , so the +# pinned values can stay in the Dockerfiles until the next bump or removal. +# +# Must run before any docker-php-ext-install or pecl install: the bundled +# extensions are compiled from /usr/src/php.tar.xz, and pecl extensions must be +# built against the new headers. +# +# Build dependencies the base image purged after its own build must already be +# installed: libargon2-dev libcurl4-openssl-dev libonig-dev libreadline-dev +# libsodium-dev libsqlite3-dev libssl-dev libxml2-dev zlib1g-dev. +set -e + +VERSION="$1" +SHA256="$2" + +if [ -z "$VERSION" ] || [ -z "$SHA256" ]; then + echo "usage: php-from-source " >&2 + exit 1 +fi + +# shellcheck disable=SC2016 # $argv is PHP, not shell +if php -r 'exit(version_compare(PHP_VERSION, $argv[1], ">=") ? 0 : 1);' "$VERSION"; then + echo "Base image already has PHP $(php -r 'echo PHP_VERSION;'), not rebuilding for ${VERSION}" + exit 0 +fi + +echo "Rebuilding PHP $(php -r 'echo PHP_VERSION;') -> ${VERSION} from source" + +cd /usr/src +curl -fsSL -o php.tar.xz.new "https://www.php.net/distributions/php-${VERSION}.tar.xz" +echo "${SHA256} *php.tar.xz.new" | sha256sum -c - +mv php.tar.xz.new php.tar.xz +# The old signature no longer matches; nothing reads it, so drop it rather than +# leave a misleading file behind. +rm -f php.tar.xz.asc + +# php-config prints the original configure line followed by unquoted +# environment assignments (build_alias=..., PHP_UNAME=Linux - Docker, ...). +# Only the flags before build_alias are configure options. +CONFIGURE_OPTIONS="$(php-config --configure-options | sed 's/ build_alias=.*//')" + +export \ + CFLAGS="$PHP_CFLAGS" \ + CPPFLAGS="$PHP_CPPFLAGS" \ + LDFLAGS="$PHP_LDFLAGS" \ + PHP_BUILD_PROVIDER='https://github.com/docker-library/php' \ + PHP_UNAME='Linux - Docker' + +docker-php-source extract +cd /usr/src/php +# shellcheck disable=SC2086 # word splitting of the configure flags is intended +./configure $CONFIGURE_OPTIONS +make -j "$(nproc)" +find . -type f -name '*.a' -delete +make install +find /usr/local -type f -perm '/0111' -exec sh -c 'strip --strip-all "$@" || :' -- '{}' + +make clean +cd / +docker-php-source delete + +# Fail the build rather than ship an image that still runs the old PHP. +INSTALLED="$(php -r 'echo PHP_VERSION;')" +if [ "$INSTALLED" != "$VERSION" ]; then + echo "ERROR: expected PHP ${VERSION} after rebuild, found ${INSTALLED}" >&2 + exit 1 +fi +if command -v php-fpm > /dev/null && ! php-fpm -v | grep -q "PHP ${VERSION} "; then + echo "ERROR: php-fpm does not report PHP ${VERSION}" >&2 + exit 1 +fi + +php -v diff --git a/fpm/8.3/Dockerfile.apache b/fpm/8.3/Dockerfile.apache index 32b6af1..203dd2c 100644 --- a/fpm/8.3/Dockerfile.apache +++ b/fpm/8.3/Dockerfile.apache @@ -48,11 +48,26 @@ RUN apt-get -y update && apt-get -y upgrade && ACCEPT_EULA=Y && apt-get install imagemagick \ ghostscript \ libavif-dev \ + libargon2-dev \ + libcurl4-openssl-dev \ + libreadline-dev \ + libsodium-dev \ + libsqlite3-dev \ libmaxminddb0 \ libmaxminddb-dev && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* +# PHP 8.3.36 fixes CVE-2026-109618 and CVE-2026-109619 (PHP2Shell). Rebuild PHP +# from the php.net source release until the official php:8.3-fpm image +# carries it; php-from-source does nothing once it does. Keep this before +# the extension builds below, which compile against the rebuilt PHP. +ARG PHP_SOURCE_VERSION=8.3.36 +ARG PHP_SOURCE_SHA256=dd54693aa334c5c4d72e9aee96b082c2473750a18a6c1d105789c93a3b1692fd +COPY bin/php-from-source /usr/local/bin/php-from-source +RUN chmod +x /usr/local/bin/php-from-source && \ + php-from-source "$PHP_SOURCE_VERSION" "$PHP_SOURCE_SHA256" + # PHP extensions, separated for QEMU build purposes RUN docker-php-ext-configure gd --with-freetype --with-webp --with-jpeg --with-avif RUN docker-php-ext-install gd diff --git a/fpm/8.3/Dockerfile.cli b/fpm/8.3/Dockerfile.cli index f5dc136..c0385d7 100644 --- a/fpm/8.3/Dockerfile.cli +++ b/fpm/8.3/Dockerfile.cli @@ -47,11 +47,26 @@ RUN apt-get -y update && apt-get -y upgrade && ACCEPT_EULA=Y && apt-get install imagemagick \ ghostscript \ libavif-dev \ + libargon2-dev \ + libcurl4-openssl-dev \ + libreadline-dev \ + libsodium-dev \ + libsqlite3-dev \ libmaxminddb0 \ libmaxminddb-dev && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* +# PHP 8.3.36 fixes CVE-2026-109618 and CVE-2026-109619 (PHP2Shell). Rebuild PHP +# from the php.net source release until the official php:8.3-cli image +# carries it; php-from-source does nothing once it does. Keep this before +# the extension builds below, which compile against the rebuilt PHP. +ARG PHP_SOURCE_VERSION=8.3.36 +ARG PHP_SOURCE_SHA256=dd54693aa334c5c4d72e9aee96b082c2473750a18a6c1d105789c93a3b1692fd +COPY bin/php-from-source /usr/local/bin/php-from-source +RUN chmod +x /usr/local/bin/php-from-source && \ + php-from-source "$PHP_SOURCE_VERSION" "$PHP_SOURCE_SHA256" + # PHP extensions, separated for QEMU build purposes RUN docker-php-ext-configure gd --with-freetype --with-webp --with-jpeg --with-avif RUN docker-php-ext-install gd diff --git a/fpm/8.5/Dockerfile.apache b/fpm/8.5/Dockerfile.apache index 8171b95..f5397e4 100644 --- a/fpm/8.5/Dockerfile.apache +++ b/fpm/8.5/Dockerfile.apache @@ -48,11 +48,26 @@ RUN apt-get -y update && apt-get -y upgrade && ACCEPT_EULA=Y && apt-get install imagemagick \ ghostscript \ libavif-dev \ + libargon2-dev \ + libcurl4-openssl-dev \ + libreadline-dev \ + libsodium-dev \ + libsqlite3-dev \ libmaxminddb0 \ libmaxminddb-dev && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* +# PHP 8.5.12 fixes CVE-2026-109618 and CVE-2026-109619 (PHP2Shell). Rebuild PHP +# from the php.net source release until the official php:8.5-fpm image +# carries it; php-from-source does nothing once it does. Keep this before +# the extension builds below, which compile against the rebuilt PHP. +ARG PHP_SOURCE_VERSION=8.5.12 +ARG PHP_SOURCE_SHA256=08bc2eba2a588654ade1357174aa646b761556c862dda0678345ee29ed481209 +COPY bin/php-from-source /usr/local/bin/php-from-source +RUN chmod +x /usr/local/bin/php-from-source && \ + php-from-source "$PHP_SOURCE_VERSION" "$PHP_SOURCE_SHA256" + # PHP extensions, separated for QEMU build purposes RUN docker-php-ext-configure gd --with-freetype --with-webp --with-jpeg --with-avif RUN docker-php-ext-install gd diff --git a/fpm/8.5/Dockerfile.cli b/fpm/8.5/Dockerfile.cli index 3a17b2a..2b7f4a2 100644 --- a/fpm/8.5/Dockerfile.cli +++ b/fpm/8.5/Dockerfile.cli @@ -47,11 +47,26 @@ RUN apt-get -y update && apt-get -y upgrade && ACCEPT_EULA=Y && apt-get install imagemagick \ ghostscript \ libavif-dev \ + libargon2-dev \ + libcurl4-openssl-dev \ + libreadline-dev \ + libsodium-dev \ + libsqlite3-dev \ libmaxminddb0 \ libmaxminddb-dev && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* +# PHP 8.5.12 fixes CVE-2026-109618 and CVE-2026-109619 (PHP2Shell). Rebuild PHP +# from the php.net source release until the official php:8.5-cli image +# carries it; php-from-source does nothing once it does. Keep this before +# the extension builds below, which compile against the rebuilt PHP. +ARG PHP_SOURCE_VERSION=8.5.12 +ARG PHP_SOURCE_SHA256=08bc2eba2a588654ade1357174aa646b761556c862dda0678345ee29ed481209 +COPY bin/php-from-source /usr/local/bin/php-from-source +RUN chmod +x /usr/local/bin/php-from-source && \ + php-from-source "$PHP_SOURCE_VERSION" "$PHP_SOURCE_SHA256" + # PHP extensions, separated for QEMU build purposes RUN docker-php-ext-configure gd --with-freetype --with-webp --with-jpeg --with-avif RUN docker-php-ext-install gd