diff --git a/.github/workflows/php73-sury.yml b/.github/workflows/php73-sury.yml new file mode 100644 index 0000000..05a125b --- /dev/null +++ b/.github/workflows/php73-sury.yml @@ -0,0 +1,32 @@ +name: Validate PHP 7.3 Sury backport + +on: + pull_request: + paths: + - php-apache/7.3/** + - .github/workflows/php73-sury.yml + workflow_dispatch: + +permissions: + contents: read + +jobs: + compatibility: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f + - name: Build patched image + uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 + with: + context: ./php-apache/7.3 + target: php-apache + platforms: linux/amd64 + load: true + tags: devitools/php-apache:7.3 + cache-from: type=gha,scope=php73-compatibility + cache-to: type=gha,mode=max,scope=php73-compatibility + - name: Verify compatibility and security behavior + run: python3 php-apache/7.3/.scripts/smoke.py devitools/php-apache:7.3 diff --git a/README.md b/README.md index 3c447d8..2bbe1bd 100644 --- a/README.md +++ b/README.md @@ -15,3 +15,7 @@ $ sudo ln -s $(pwd)/build.sh /usr/bin/dbr ```shell $ dbr vue 3.0.0 ``` + +## PHP 7.3 com Apache + +[`devitools/php-apache:7.3`](php-apache/7.3/README.md): substituta de compatibilidade para `webdevops/php-apache:7.3`, com backports do pacote-fonte Surý para CVE-2026-109618 e CVE-2026-109619. Consulte as instruções de build, validação e as limitações de suporte antes de migrar. diff --git a/php-apache/7.3/.scripts/build-php.sh b/php-apache/7.3/.scripts/build-php.sh new file mode 100644 index 0000000..f99ea14 --- /dev/null +++ b/php-apache/7.3/.scripts/build-php.sh @@ -0,0 +1,33 @@ +set -euxo pipefail + +php -r '$m = get_loaded_extensions(); sort($m); file_put_contents("/tmp/upstream-modules.json", json_encode($m));' +php-config --configure-options > /tmp/configure-options +sed -i 's|http://deb.debian.org/debian|http://archive.debian.org/debian|g; s|http://security.debian.org/debian-security|http://archive.debian.org/debian-security|g' /etc/apt/sources.list +apt-get -o Acquire::Check-Valid-Until=false update +apt-get install -y --no-install-recommends $PHPIZE_DEPS patch \ + libargon2-dev libcurl4-openssl-dev libedit-dev libonig-dev \ + libreadline-dev libsodium-dev libsqlite3-dev libssl-dev libxml2-dev zlib1g-dev + +mkdir -p /security /tmp/sury /usr/src/php /patched +curl -fsSL "https://packages.sury.org/php/pool/main/p/php7.3/php7.3_${SURY_SOURCE_VERSION}.debian.tar.xz" -o /tmp/sury.tar.xz +printf '%s %s\n' "$SURY_SOURCE_SHA256" /tmp/sury.tar.xz | sha256sum -c - +tar -xJf /tmp/sury.tar.xz -C /tmp/sury +printf '%s %s\n' 166eaccde933381da9516a2b70ad0f447d7cec4b603d07b9a916032b215b90cc /usr/src/php.tar.xz | sha256sum -c - +tar -xJf /usr/src/php.tar.xz -C /usr/src/php --strip-components=1 +cd /usr/src/php +for name in 0079-Introduce-max_multipart_body_parts-INI.patch 0107-backport-ZSTR_MAX_LEN.patch 0139-Avoid-state-corruption-via-bailout.patch; do + patch --batch --fuzz=0 -p1 < "/tmp/sury/debian/patches/$name" + cp "/tmp/sury/debian/patches/$name" /security/ +done +cp /tmp/sury/debian/changelog /security/sury-changelog +cp /tmp/upstream-modules.json /security/upstream-modules.json +printf '%s\n' "$SURY_SOURCE_VERSION" > /security/source-version +printf '%s\n' "$SURY_SOURCE_SHA256" > /security/source-sha256 +export CFLAGS="$PHP_CFLAGS" CPPFLAGS="$PHP_CPPFLAGS" LDFLAGS="$PHP_LDFLAGS" +read -r -a configure_options < /tmp/configure-options +./configure "${configure_options[@]}" --enable-opcache=shared +make -j"$BUILD_JOBS" +make install INSTALL_ROOT=/patched +rm -rf /patched/usr/local/etc /patched/usr/local/php /patched/usr/local/var +cp /tmp/configure-options /security/upstream-configure-options +/patched/usr/local/bin/php -n -r 'exit(PHP_VERSION === "7.3.33" ? 0 : 1);' diff --git a/php-apache/7.3/.scripts/smoke.py b/php-apache/7.3/.scripts/smoke.py new file mode 100644 index 0000000..19f73f6 --- /dev/null +++ b/php-apache/7.3/.scripts/smoke.py @@ -0,0 +1,125 @@ +import json +import pathlib +import subprocess +import sys +import tempfile +import time +import urllib.error +import urllib.request + +image = sys.argv[1] if len(sys.argv) > 1 else "devitools/php-apache:7.3" + + +def docker(*args, check=True): + return subprocess.run(["docker", *args], check=check, text=True, capture_output=True) + + +def require(condition, message): + if not condition: + raise RuntimeError(message) + + +with tempfile.TemporaryDirectory(prefix="php73-sury-") as directory: + root = pathlib.Path(directory) + app = root / "app" + app.mkdir() + app.joinpath("index.php").write_text(''' PHP_VERSION, + 'sapi' => PHP_SAPI, + 'memory_limit' => ini_get('memory_limit'), + 'mounted' => ini_get('precision'), + 'upload_progress' => ini_get('session.upload_progress.enabled'), + 'multipart_limit' => ini_get('max_multipart_body_parts'), + 'sqlite' => $db->query('SELECT 42')->fetchColumn(), + 'gd' => strlen($png) > 0, + 'mbstring' => mb_strlen('á', 'UTF-8'), + 'modules' => $modules, + 'post' => $_POST, + 'files' => count($_FILES), +]); +''') + app.joinpath("oom.php").write_text(''' /usr/local/etc/php/conf.d/zz-security.ini \ + && php /usr/local/share/php-security/verify.php \ + && php-fpm -t + +LABEL org.opencontainers.image.title="PHP 7.3 Apache with Sury security backports" \ + org.opencontainers.image.source="https://github.com/devitools/dockerfile" \ + devitools.php.security-fixes="CVE-2026-109618,CVE-2026-109619" \ + devitools.php.patch-source="Sury php7.3 7.3.33-35" diff --git a/php-apache/7.3/README.md b/php-apache/7.3/README.md new file mode 100644 index 0000000..a33b81d --- /dev/null +++ b/php-apache/7.3/README.md @@ -0,0 +1,46 @@ +# PHP 7.3 Apache compatibility image + +`devitools/php-apache:7.3` replaces the public `webdevops/php-apache:7.3` image for existing linux/amd64 deployments. The existing build-images workflow publishes this tag after merge to main. This directory deliberately does not define a `latest` alias. + +## Security patch provenance + +The original image is pinned to `sha256:aec98f365a8f9e35ff354ac1c0893ba15141807557f40f31f02fea6ed540c43b`. Its PHP is compiled under `/usr/local`, not managed by Debian packages. Installing Sury binary packages alongside it would leave the PHP used by FPM unchanged. + +Instead, the builder downloads the checksum-pinned Debian source package `php7.3_7.3.33-35+0~20261021.144+debian12~1.gbpecf76f.debian.tar.xz` from [Sury](https://packages.sury.org/php/pool/main/p/php7.3/). It applies these unmodified patches to the checksum-pinned upstream PHP 7.3.33 source included in the original image: + +- `0079-Introduce-max_multipart_body_parts-INI.patch`: the multipart limit prerequisite assumed by the later backport. +- `0107-backport-ZSTR_MAX_LEN.patch`: the string-length definitions required by the later backport. +- `0139-Avoid-state-corruption-via-bailout.patch`: Sury's backport for CVE-2026-109618 and CVE-2026-109619. + +The build reuses the original configure options and compiler flags, rebuilds CLI, FPM, sodium and OPcache, and installs binaries and headers under the original paths. Existing additional extensions are inherited unchanged. The `/usr/src/php.tar.xz` archive is also replaced with the patched source for downstream `docker-php-ext-install` builds; the obsolete upstream archive signature is removed. Only these three patches are applied; this image does **not** contain every other fix from Sury revision 35 and does not install Sury binary `.deb` packages. PHP still reports 7.3.33, so `php -v` alone does not identify the fix and version-only scanners may continue to flag these CVEs. Use the recorded patch provenance and behavioral test results when assessing this image. + +The source revision, checksum, patches, Sury changelog and original extension inventory are recorded in `/usr/local/share/php-security/`. Build tools and archived Debian repositories are confined to the builder stage. + +`session.upload_progress.enabled=0` is set in `/usr/local/etc/php/conf.d/zz-security.ini`, following the [PHP advisory of October 23, 2026](https://www.php.net/archive/2026.php). Keep this setting disabled in custom configuration, including mounted INI files. + +## Compatibility + +The final stage inherits the original image, preserving: + +- `/opt/docker` entrypoint, service scripts, Supervisor, Apache and FPM configuration. +- `/app`, the `application` user (UID/GID 1000), exposed ports and volume behavior. +- `WEB_DOCUMENT_ROOT`, `WEB_ALIAS_DOMAIN`, `PHP_*`, `PHP_DISMOD`, `php.*`, `fpm.pool.*`, `fpm.global.*`, and other original environment handling. +- Existing `/opt/docker/etc/php/php.ini`, `/usr/local/etc/php/conf.d`, Apache and FPM configuration mounts. +- The exact loaded extension names from the pinned original image, including ionCube, vips, amqp, redis, memcached, mongodb and imagick. The build fails if extension parity is lost. + +Third-party extensions retain their original versions. Application-specific behavior, encoded ionCube applications and downstream images that compile additional extensions still require staging validation. Rebuild downstream extensions against the updated headers when possible. + +The security backport terminates a worker immediately on PHP memory exhaustion rather than attempting unsafe cleanup; shutdown callbacks may not run after OOM. The added multipart limit defaults to `max_input_vars + max_file_uploads` and can reject unusually large multipart requests. Review applications that depend on either behavior. + +## Build and validate + +```sh +docker build --platform linux/amd64 -t devitools/php-apache:7.3 php-apache/7.3 +python3 php-apache/7.3/.scripts/smoke.py devitools/php-apache:7.3 +``` + +Build-time checks verify the PHP version, complete extension-name parity, multipart prerequisite, upload progress setting and FPM configuration syntax. Apache configuration syntax is checked by the smoke test after the entrypoint renders its templates. The smoke test starts the normal entrypoint, exercises HTTP through Apache/FPM with a custom document root and PHP environment values, verifies representative extensions, checks configuration mounts and module disabling, and verifies that OOM skips unsafe shutdown callbacks and FPM can serve a subsequent request. + +For deployment, change only the image reference in your Compose service and retain its environment, mounts, ports and other settings. Recreate the containers; pulling a new image does not update running workers. + +PHP 7.3 and Debian Buster remain end of life. This is a narrowly scoped compatibility bridge for the two named CVEs, not a fully maintained operating system or PHP distribution. Plan migration to a supported PHP branch. diff --git a/php-apache/7.3/variants.yaml b/php-apache/7.3/variants.yaml new file mode 100644 index 0000000..28479fa --- /dev/null +++ b/php-apache/7.3/variants.yaml @@ -0,0 +1,3 @@ +- target: php-apache + suffix: "" + platforms: linux/amd64