PHP 7.3.33 CVE-2026-109618 / CVE-2026-109619

分类:PHP |





这个源码包是 PHP 7.3.33 官方发布版(php-7.3.33.tar.gz,含 configure、 生成的 parser/scanner 和 Zend/zend_vm_execute.h)加上移植补丁后的完整可构建源码树。

  • 上游补丁:php-src PHP-7.4-CVE-2026-109618-109619 分支, commit 712e60f9edfd03f0960fc4fc3c2c375f42b90aa2(7.4 EOL 最小缓解)

  • 版本差异说明:见 CVE-2026-109618-109619-NOTES.md

  • 已应用的补丁原文:见 cve-2026-109618-109619.patch

包内已包含 configure 与所有生成文件,正常 Unix 构建不需要 autoconf / bison / re2c。

本包对应的补丁已在 WSL2 Ubuntu 24.04 上完整编译(zig cc / clang)并通过冒烟测试, 详见第 5 节。


1. Linux / macOS / WSL 构建

依赖:

sudo apt updatesudo apt install -y build-essential# 无额外依赖

构建:

tar xzf php-7.3.33-cve-2026-109618-109619-src.tar.gzcd php-7.3.33

./configure --prefix="$PWD/../php73-install" \
            --disable-all --enable-cli --enable-session
make -j"$(nproc)"./sapi/cli/php -v

或直接 sh build.sh。

WSL 下把源码放在 ~/(不要放 /mnt/c),否则 configure/make 很慢、时间戳也容易出问题。


2. Windows 原生构建

PHP 7.3.33 的官方 Windows 构建只支持 VS2017 (v141) + php-sdk 2.2.0, 不支持 MinGW;没有 VS2017 时建议用 WSL(第 1 节)。

cd php-7.3.33cscript /nologo win32\build\buildconf.js
cscript /nologo configure.js --disable-all --enable-cli --enable-session
nmake

3. 验证补丁生效

# 新 INI 项存在,默认 -1./sapi/cli/php -r 'var_dump(ini_get("max_multipart_body_parts"));'# 期望: string(2) "-1"# 嵌套变量解析(array_init_singleton 路径)./sapi/cli/php -r 'parse_str("a[b][c]=1&a[b][d]=2&x[]=3", $o); var_dump($o);'# 字符串拼接./sapi/cli/php -r 'var_dump(str_repeat("x",16) . str_repeat("y",16));'# OOM:打了补丁会直接 _exit(1),不再走正常 fatal error 流程./sapi/cli/php -d memory_limit=8M -r '$a=[]; while(1){$a[]=str_repeat("x",1024);}'echo "exit=$?"   # 1# session 扩展./sapi/cli/php -m | grep -i session

4. 常见构建问题

4.1 clang 16+ / zig cc 下 configure 误判

现象:

main/reentrancy.c:139: error: too few arguments to function call, expected 3, have 2
main/streams/cast.c:139: error: incompatible function pointer types initializing
    'cookie_seek_function_t *' ...

原因:configure 的探测程序没有函数原型,clang 16+ 默认把隐式声明当错误, 导致 readdir_r / fopencookie 探测结论错误。用 gcc 不受影响。

用 clang 时在 configure 成功后往 main/php_config.h 末尾追加:

#define HAVE_POSIX_READDIR_R 1#undef HAVE_OLD_READDIR_R#define COOKIE_SEEKER_USES_OFF64_T 1

然后 make clean && make(必须全量重编,增量会链接报 undefined symbol: php_readdir_r)。

4.3 其它

  • 缺 -dev 包时按 configure 提示安装。

  • 在 /mnt/c 下构建很慢:把源码拷到 WSL 家目录。


5. 构建验证记录

WSL2 Ubuntu 24.04,zig cc(clang 16),--disable-all --enable-cli --enable-session:

configure退出码 0
make退出码 0,Build complete.
php -vPHP 7.3.33 (cli) (NTS)
max_multipart_body_partsstring(2) "-1"
嵌套 parse_str正确
OOMFatal error: Allowed memory size ...,exit=1

6. 必须知道的行为变化

  1. OOM = 进程立即退出:memory_limit 耗尽直接 _exit(1),不执行 shutdown 函数、 不输出 fatal error 页面,只在 stderr 打一行。这是上游 7.4 EOL 补丁的取舍。

  2. session upload progress 被源码级关闭:session.upload_progress.* 不再产生数据。

  3. 新增 INI max_multipart_body_parts:默认 -1,即 max_input_vars + max_file_uploads(默认 1020);超过会 warning 并截断。



上游补丁:php-src PHP-7.4-CVE-2026-109618-109619 分支,commit 712e60f9edfd03f0960fc4fc3c2c375f42b90aa2(7.4 EOL 最小缓解)。

结论:7.0、7.1、7.2、7.3 都可以移植。 四个版本都已生成补丁、在官方发布版 源码树上 git apply --check 通过,并完成了实际编译 + 冒烟测试(见第 4 节)。

7.0.33php-7.0-CVE-2026-109618-109619.patch17✅✅✅
7.1.33php-7.1-CVE-2026-109618-109619.patch17✅✅✅
7.2.34php-7.2-CVE-2026-109618-109619.patch17✅✅✅(已装在 192.168.11.62)
7.3.33php-7.3-CVE-2026-109618-109619.patch18✅✅✅

冒烟内容:ini_get("max_multipart_body_parts") == "-1"、parse_str() 嵌套数组、 字符串拼接、memory_limit 耗尽时 exit=1 + 一行 Fatal error: Allowed memory size ...。


1. 各版本与 7.4 补丁的差异(为什么不能直接套用)

7.4 补丁在两个版本约定之间摇摆,7.0–7.3 各自处于不同阶段:

array_init函数 _array_init()函数宏 ZVAL_ARR(zend_new_array(0))宏
_zend_new_array_0()无无有有
HashTable mask-nTableSize-nTableSize-2*nTableSize(HT_SIZE_TO_MASK)-2*nTableSize
SSE2 HT_HASH_RESET无无有有(需要 size<64 修复)
EG(user_error_handlers*)zend_stackzend_stackzend_stackzend_llist
shutdown_executor无 fast_shutdown 分支有有有(重构过)
zend_weakrefs_shutdown()无无无有
VM CONCAT 实现zend_string_realloc()zend_string_extend()zend_string_extend()同 7.3 + 已有检查
ZSTR_MAX_LEN无无无有

补丁统一采用的策略:

  • singleton 数组:7.0/7.1/7.2 用 _array_init_singleton(),nTableSize = 2 (7.x 早期 nTableMask = -nTableSize,1 桶会导致 4 字节 hash 区、arData不对齐); 7.3 用 7.4 的 zend_new_array_singleton(),nTableSize = 1(mask 为 -2)。

  • OOM 不再 longjmp:所有版本都加 zend_mm_safe_error_ex()(打印后 _exit(1)), 替换分配器/哈希/字符串里的 zend_error_noreturn。

  • 状态复位:7.0/7.1/7.2/7.3 的 EG(user_error_handlers*) 都是 zend_stack, 不能像 7.4 那样 memset(会制造新的崩溃点),因此统一在shutdown_executor() 末尾清 user_error_handler / user_exception_handler / error_handling / exception / prev_exception / objects_store。

  • VM 拼接溢出检查:7.0 加在 zend_string_realloc() 前,7.1–7.3 加在 zend_string_extend() / zend_string_alloc() 前,均需补 ZSTR_MAX_LEN。

  • multipart 缓解:只保留 Content-Disposition/Content-Type 头、 新增 max_multipart_body_parts、substring_conf() 用 size_t;session upload progress 源码级关闭(7.0–7.3 的 php_session_rfc1867_callback 结构一致)。

1.1 7.0 特有的改动

  • VM CONCAT 用 zend_string_realloc()(不是 extend),守卫加在 realloc 前。

  • zend_alloc.c 没有 zend_bitset.h,#include "zend_execute.h" 加在 zend_multiply.h 之后。

  • zend_alloc.h 的声明位置与 7.2 不同(END_EXTERN_C() 之前)。

  • shutdown_executor() 没有 fast/full 分支,复位代码放在函数最末尾。

  • zend_mm_safe_error() 的参数是 uint lineno(7.2 是 uint32_t),补丁只透传。

1.2 7.1 特有的改动

  • 结构最接近 7.2;shutdown_executor() 同样没有 fast 分支,复位放末尾。

  • VM 里只有 CONCAT 用 zend_string_extend()(1 处),FAST_CONCAT 走 alloc 路径。

  • zend_hash.c 的溢出消息是 %u 版本,需按 7.1 的原文替换。

1.3 7.3 特有的改动

  • array_init 已是 7.4 风格宏、_zend_new_array_0() 已存在 → 直接加 zend_new_array_singleton()(1 桶)。

  • zend_types.h 有 SSE2 版 HT_HASH_RESET() → 需要 7.4 的 size < 64 修复。

  • EG(user_error_handlers*) 仍是 zend_stack(7.4 已改 llist)→ 用 7.2 式复位。

  • VM 拼接没有任何溢出检查 → 新增(生成文件里 17 处 extend + 26 处 alloc)。


2. 补丁清单

php-7.0-CVE-2026-109618-109619.patch30,743 B6beb4998a5a9d204cb927d25d372a6abd75d2912a3d50b389e5e3931994b9c49
php-7.1-CVE-2026-109618-109619.patch33,824 Bf1c17a278c028b4eedfa6480c013fbaf645ace25881b0d281beede20d2a56b48
php-7.2-CVE-2026-109618-109619.patch45,313 Bccab1deaa0cbf8a0d89818e1009604220b3c29931e633137407c0686cc6f6e00
php-7.3-CVE-2026-109618-109619.patch39,688 B31b38840401312d46ccfadd538c1ace9114e35558262b4fece7f5aa48bacae95

补丁均以官方发布版源码(php-7.0.33.tar.gz / 7.1.33 / 7.2.34 / 7.3.33)为基准, git apply --check 通过。

3. 应用与构建

tar xzf php-7.3.33.tar.gzcd php-7.3.33
git apply /path/to/php-7.3-CVE-2026-109618-109619.patch

./configure --prefix=/opt/php73 --disable-all --enable-cli --enable-session
make -j"$(nproc)"./sapi/cli/php -v

宝塔面板的源码安装脚本(install/0/php.sh)同样适用:把 Download_Src() 里的 wget 换成 cp 本地补丁包,并保证 php_${ver} 与包内目录名一致即可, 7.2 的完整改法见 SERVER-DEPLOY.md 与 /root/php.sh。

4. 验证记录

构建环境:WSL2 Ubuntu 24.04,zig cc(clang 16,本机无 gcc), --disable-all --enable-cli --enable-session。clang 16 会把 configure 探测程序里的 隐式函数声明当错误,导致 readdir_r / fopencookie 两个探测误判,需要给 main/php_config.h 追加:

#define HAVE_POSIX_READDIR_R 1#undef HAVE_OLD_READDIR_R#define COOKIE_SEEKER_USES_OFF64_T 1

(这是 clang/zig 的工具链问题,不是补丁问题;gcc 构建不需要。7.2 在 CentOS 7 + gcc 4.8 上已完整编译并安装运行。)

结果:

max_multipart_body_parts嵌套 parse_strOOM exit7.0.3300PHP 7.0.33 (cli)string(2) "-1"✅17.1.3300PHP 7.1.33 (cli)string(2) "-1"✅17.2.3400PHP 7.2.34 (cli)string(2) "-1"✅17.3.3300PHP 7.3.33 (cli)string(2) "-1"✅1

7.0 构建时 WSL 缺 libcrypt-dev,用 Ubuntu 的 libcrypt-dev deb 解包到用户目录 后通过(HAVE_CRYPT 未定义会导致 password.c 为空、链接失败);这是环境依赖, 与补丁无关。

5. 注意事项(四个版本相同)

  1. OOM = 进程立即退出:memory_limit 耗尽直接 _exit(1),不跑 shutdown 函数、不输出 fatal error 页面,只在 stderr 打一行。这是上游 7.4 EOL 补丁的取舍。

  2. session upload progress 被源码级关闭:session.upload_progress.* 不再生效。

  3. 新增 INI max_multipart_body_parts,默认 -1 = max_input_vars + max_file_uploads(默认 1020)。

  4. 7.0–7.3 均已 EOL,补丁只是缓解;能升级到受支持版本请优先升级。

  5. 补丁未覆盖扩展自身仍使用 zend_error_noreturn / zend_bailout 的路径。

  6. 7.0/7.1 的 --enable-session 


无
阅读( 12 ) |