跳转到主要内容

crayonxiaoxin

Debian 10 上更新 PHP 7.4 以修复 CVE-2026-109618

2026 年 10 月,PHP 公布了 CVE-2026-109618 和 CVE-2026-109619。8.2 及以上有正式安全版本,7.4 没有。生产环境如果还停在 7.4,包管理器和源码编译的验收方式不一样,用错标志会把没修好的程序当成已经修好。

问题背景

官方点版本是 8.5.12、8.4.27、8.3.36、8.2.35。7.4、8.0、8.1 只有安全补丁分支。7.4 的分支在 php/php-src 上,名字是 PHP-7.4-CVE-2026-109618-109619,修复提交的说明是 “Avoid state corruption via bailout”。

Ubuntu 24.04 如果本来就用 Ondřej Surý 的 PHP 源,候选包要升到 7.4.33-31。7.4.33-30 不包含这次修复。升级后 php -v 仍然显示 7.4.33,构建日期会变成 2026-10-21 前后。只升级已经安装的 php7.4* 和 Apache 模块,不要做整机 full-upgrade,并保留现有 php.ini。Apache 要 restart,reload 卸不掉已经加载的解释器。

Debian 10 上常见的情况是原来的第三方 PHP 源已经关闭,装不上新包,也不能把 Ubuntu 的 deb 硬装上去。这时把上述分支编译到单独前缀,例如 /usr/local/php-7.4-patched,再切换 Apache 模块和 update-alternatives。旧的 /usr/bin/php7.4 留着,方便退回。

不要用 max_multipart_body_parts 当证据

这次 7.4 补丁会限制 multipart 分段,并在内存分配失败时直接退出,避免 bailout 把解释器状态弄坏。配置项 max_multipart_body_parts 看起来像补丁标志,但它在 2023 年就因为另一个 multipart 限制(CVE-2023-0662)进过 7.4 的第三方包。一台 2023 年编译的 7.4.33,php -n -i 里已经有这个名字。

git 构建的版本号是 7.4.34-dev,因为分支在修复提交之前就把版本抬到了下一个开发号。只看 php -v 也不能证明修复提交在二进制里。

这次补丁新增的符号是 zend_mm_safe_error_ex。命令行程序和 Apache 模块都要查,而且 Apache 进程的内存映射里要出现新的 .so。两个 SAPI 的模块名都叫 php7_module,不能同时加载。

grep -a -F zend_mm_safe_error_ex /usr/local/php-7.4-patched/bin/php
grep -a -F zend_mm_safe_error_ex /usr/lib/apache2/modules/libphp7.4-patched.so
grep libphp7.4-patched.so /proc/$(pgrep -o apache2)/maps

旧的发行版二进制里不应出现这个符号。Swoole 会挂钩 Zend 内存管理,必须用原来的版本、对着新的 phpize 重编。扩展 API 号仍是 20190902,并不能说明可以继续用旧的 .so。

升级脚本自己会在中途退出

set -euo pipefail 下面如果写成:

cand=$(apt-cache policy "$pkg" | awk '/Candidate:/ {print $2; exit}')

awk 提前退出会向 apt-cache 发 SIGPIPE。pipefail 让整条管道失败,赋值又会触发 set -e,脚本在打印原因之前就退出。应先把命令输出收进变量,再用 here-string 交给 awk。

Debian 10 的 Bash 5.0 还有一个解析问题:函数的最后一条命令如果是 here-document,紧跟着的 } 会报 syntax error near unexpected token '}'。用法说明改成 printf 即可。日志重定向放在全部函数定义之后,语法错误不会和管道日志缠在一起。

libzip 版本对不上就不要降级

Debian 10 的 libzip-dev 依赖 libzip4 (= 1.5.1-4)。机器上如果已经装着更新的 libzip,例如 1.7.3,apt 会直接拒绝,整次安装都不会进行。不要为了编译把头文件包硬装上,那会把正在使用的库降回去。单独把同一版本的 libzip 编到一个不进系统动态库搜索路径的前缀,再用 PKG_CONFIG_PATH 指给 PHP 的 ./configure。

新 PHP 连不上 MySQL

WordPress 出现 Error establishing a database connection,而页面又不是缺少 MySQL 扩展,说明 mysqli 在,连接参数不对。发行版 PHP 把 socket 编成 /var/run/mysqld/mysqld.sock。php.ini 里 mysqli.default_socket 留空表示用编译时的默认值。自行编译的默认值通常是 /tmp/mysql.sock。DB_HOST 为 localhost 时走的是 socket。

sock=$(/usr/bin/php7.4 -r 'echo ini_get("mysqli.default_socket");')
printf '%s\n' \
  "mysqli.default_socket=${sock}" \
  "pdo_mysql.default_socket=${sock}" \
  > /usr/local/php-7.4-patched/etc/conf.d/20-mysql-socket.ini
systemctl restart apache2

命令行和 Apache 各用一份 php.ini,避免常驻进程继承网页的 memory_limit 和 max_execution_time。

总结

7.4 这次没有官方小版本。Ubuntu 上看包版本是不是 7.4.33-31,Debian 上看二进制里有没有 zend_mm_safe_error_ex,并且确认 Apache 进程加载的是新模块。编译时不要降级已经在用的库,切换后把原来的 MySQL socket 显式写进新配置。

讨论

还没有留言,来留下第一条评论吧!

留下足迹