Compare commits

...
2 Commits
Author SHA1 Message Date
Sovran Systems ccef1f145f php: fix the filter tests that break the 8.5.12 build
The 8.5.12 pin in 39ed0cc/be9afb2 builds the interpreter but the system build
stopped in php-filter's checkPhase:

  FAILED TEST SUMMARY
  filter.default=encoded doesn't reach hard limit  [tests/oom_filter_default_encoded.phpt]
  filter_input() doesn't reach hard limit          [tests/oom_filter_input.phpt]
  filter_input_array() doesn't reach hard limit    [tests/oom_filter_input_array.phpt]
  make: *** [Makefile:133: test] Error 1

Not a fault in the pin. nixpkgs configures PHP with `--disable-all` and builds
every extension as a shared module, while these three tests — added by the
upstream fix for CVE-2026-109618 — deliberately spawn `php-cgi -n` with no
php.ini.  With no ini there is no shared filter module, so filter_input() is
undefined, the request never reaches the code under test, and the expected
"Allowed memory size ... exhausted" never appears.

nixpkgs shipped the remedy with the version bump in a5fc1be5b6 ("php: fix
`filter` tests", 2026-10-21 14:27 UTC), which adds the module to the child's
command line.  The pinned nixpkgs revision (7694c4f6b853, 2026-10-16) predates
it, so apply the same substitution locally.

The override has to rewrite the filter derivation inside `extensions` rather
than go through buildEnv's `packageOverrides`: that argument is threaded into
the unwrapped PHP only, while the extension set is folded from mkPhp's own
packageOverrides, so passing it there is accepted and silently ignored.

Drop this block once flake.lock is past a5fc1be5b6 — otherwise both patch the
same files and the substitution is applied twice.

Verified by evaluating both derivations against the pinned revision: the
filter derivation now carries the substitution, php-with-extensions is
8.5.12, and the 45-extension set is unchanged.
2026-10-22 20:48:38 -05:00
Sovran Systems be9afb2f53 php: pin the shared interpreter to 8.5.12 for CVE-2026-109618/-109619
PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 were released on 2026-10-21 to fix two
critical vulnerabilities in PHP itself:

  CVE-2026-109618  RCE via OOM corruption (GHSA-w8hw-w9fx-j79w)
  CVE-2026-109619  RCE via stale global state (GHSA-6wmf-4rv5-p3rp)

Both are unauthenticated RCE, CVSS v4.0 9.2, and PHP states that updating is
the only complete mitigation.  The advisories name PHP-FPM as susceptible, so
the phpfpm-nextcloud and phpfpm-wordpress pools are in scope, not just the
Apache/mod_php configuration the public write-ups focus on.

nixpkgs bumped php85 in 81513f364091c759812f716cef3c175109d07342 on the same
day, but the revision this flake pins (7694c4f6b853, 2026-10-16) predates it
and still reports php85 8.5.11 — as does the pinned nixos-26.05 rev, so
`pkgs.stable` is not a way out of this either.  Rather than pin the whole
nixpkgs input forward and freeze every other package, pin the interpreter:

  • phpSecurityFloor records the first patched 8.5.x release.
  • phpBase falls through to pkgs.php85 untouched when nixpkgs has caught up,
    so the workaround retires itself; bump the floor only upward.
  • `.override` rather than `overrideAttrs`: php85 is a makeOverridable
    buildEnv, so version/phpSrc reach generic.nix while the default extension
    set survives.  overrideAttrs would keep the new source but drop `enabled`,
    silently removing gd, intl, pdo_pgsql and the rest from both pools.

Nothing else changes: one interpreter, one extension set, one php.ini, and
every consumer (both FPM pools, the Nextcloud cron job, occ and wp-cli) still
resolves through config.sovran_systemsOS.phpPackage, so CLI and FPM stay in
lockstep at 8.5.12.

The source is php-8.5.12.tar.bz2 from php.net, hashed here.  Hydra cannot have
this exact derivation, so the first rebuild compiles PHP plus bz2, apcu, redis,
imagick and memcached locally — a one-off cost, after which it is a store path
like any other and the configuration stays reproducible.

`nixos-rebuild switch` is enough: the phpfpm units change closure and restart,
no reboot and no staged generation required.
2026-10-22 20:38:22 -05:00
+75 -8
View File
@@ -18,9 +18,42 @@
# #
# To fall back to PHP 8.4 (nixpkgs' current default `pkgs.php`) change only # To fall back to PHP 8.4 (nixpkgs' current default `pkgs.php`) change only
# the `phpBase` line below. # the `phpBase` line below.
#
# Security floor (October 2026):
# CVE-2026-109618 (RCE via OOM corruption) and CVE-2026-109619 (RCE via
# stale global state) are critical, unauthenticated flaws in PHP itself,
# CVSS v4.0 9.2 each, fixed in 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 on
# 2026-10-21. PHP-FPM is named as susceptible in both advisories, so the
# pools below are in scope; updating is the only complete mitigation.
# nixpkgs bumped php85 in 81513f364091c759812f716cef3c175109d07342 the same
# day, but the nixpkgs revision this flake pins predates it, so the floor is
# enforced here. Once flake.lock is at or past that commit the `else`
# branch below stops being taken and can be deleted.
let let
phpBase = pkgs.php85; # The first 8.5.x release that carries the fixes above. Bump only upward.
phpSecurityFloor = "8.5.12";
# php-8.5.12.tar.bz2, the same artifact and URL shape nixpkgs' own
# generic.nix fetches. Verified against php.net on 2026-10-23.
phpSourceHash = "sha256-/7YO3EN87WO1E35JhNs3moERxQBJxxFRDYuVgnfvwag=";
# `.override` (not `overrideAttrs`) on purpose: php85 is a `makeOverridable`
# buildEnv, so this threads `version`/`phpSrc` into generic.nix while
# keeping the default extension set. `overrideAttrs` would keep the new
# source but drop the extension set, which would silently strip gd, intl,
# pdo_pgsql and friends out of the pools below.
phpBase =
if lib.versionAtLeast pkgs.php85.version phpSecurityFloor then
pkgs.php85
else
pkgs.php85.override {
version = phpSecurityFloor;
phpSrc = pkgs.fetchurl {
url = "https://www.php.net/distributions/php-${phpSecurityFloor}.tar.bz2";
hash = phpSourceHash;
};
};
custom-php = phpBase.buildEnv { custom-php = phpBase.buildEnv {
# `enabled` is nixpkgs' default extension set. It already contains every # `enabled` is nixpkgs' default extension set. It already contains every
@@ -29,13 +62,47 @@ let
# xmlreader, xmlwriter, zip, zlib, pdo_pgsql, pdo_mysql, bcmath, gmp, # xmlreader, xmlwriter, zip, zlib, pdo_pgsql, pdo_mysql, bcmath, gmp,
# exif, sodium, sysvsem, pcntl, ...). OPcache is compiled into PHP >= 8.5 # exif, sodium, sysvsem, pcntl, ...). OPcache is compiled into PHP >= 8.5
# and no longer appears as a separate extension. # and no longer appears as a separate extension.
extensions = { enabled, all }: enabled ++ (with all; [ extensions = { enabled, all }:
bz2 # Nextcloud: bz2 archive support let
apcu # Nextcloud: memcache.local (apc.enable_cli=1 below is mandatory for occ + cron) # nixpkgs builds PHP with `--disable-all` and every extension as a
redis # Nextcloud: memcache.distributed / file locking once a Redis server is configured # shared module. Three of the OOM regression tests shipped with
imagick # Nextcloud: previews + theming (nixpkgs ImageMagick is built with SVG support) # 8.5.12 spawn `php-cgi -n` on purpose — no php.ini, so no shared
memcached # WordPress object-cache plugins (legacy option for Nextcloud) # module, so filter_input() is never defined and the request never
]); # reaches the code under test. php-filter's `make test` then fails
# with "doesn't reach hard limit" for oom_filter_input,
# oom_filter_input_array and oom_filter_default_encoded, and the
# whole system build stops there.
#
# Upstream nixpkgs fixes this in a5fc1be5b6 ("php: fix `filter`
# tests"), shipped alongside the 8.5.12 bump. This lock predates
# it, so apply the same substitution here; drop this once flake.lock
# is past a5fc1be5b6, since the two would otherwise both patch.
#
# Done by rewriting the filter derivation in the extension list
# rather than through buildEnv's `packageOverrides`: that argument
# only reaches the unwrapped PHP, while the extension set is folded
# from mkPhp's own packageOverrides, so it is silently ignored here.
patchFilterTests = ext:
if (ext.extensionName or "") != "filter" then
ext
else
ext.overrideAttrs (prevAttrs: {
postConfigure = (prevAttrs.postConfigure or "") + ''
substituteInPlace \
tests/oom_filter_input.phpt \
tests/oom_filter_input_array.phpt \
tests/oom_filter_default_encoded.phpt \
--replace-fail "'-n'," "'-n', '-d', 'extension=$PWD/modules/filter.so',"
'';
});
in
map patchFilterTests enabled ++ (with all; [
bz2 # Nextcloud: bz2 archive support
apcu # Nextcloud: memcache.local (apc.enable_cli=1 below is mandatory for occ + cron)
redis # Nextcloud: memcache.distributed / file locking once a Redis server is configured
imagick # Nextcloud: previews + theming (nixpkgs ImageMagick is built with SVG support)
memcached # WordPress object-cache plugins (legacy option for Nextcloud)
]);
extraConfig = '' extraConfig = ''
; ── Error handling (production) ───────────────────────────────── ; ── Error handling (production) ─────────────────────────────────