PHP 7.3.33 CVE-2026-109618 / CVE-2026-109619
这个源码包是 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分支, commit712e60f9edfd03f0960fc4fc3c2c375f42b90aa2(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 -v | PHP 7.3.33 (cli) (NTS) |
max_multipart_body_parts | string(2) "-1" |
嵌套 parse_str | 正确 |
| OOM | Fatal error: Allowed memory size ...,exit=1 |
6. 必须知道的行为变化
OOM = 进程立即退出:
memory_limit耗尽直接_exit(1),不执行 shutdown 函数、 不输出 fatal error 页面,只在 stderr 打一行。这是上游 7.4 EOL 补丁的取舍。session upload progress 被源码级关闭:
session.upload_progress.*不再产生数据。新增 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.33 | php-7.0-CVE-2026-109618-109619.patch | 17 | ✅ | ✅ | ✅ |
| 7.1.33 | php-7.1-CVE-2026-109618-109619.patch | 17 | ✅ | ✅ | ✅ |
| 7.2.34 | php-7.2-CVE-2026-109618-109619.patch | 17 | ✅ | ✅ | ✅(已装在 192.168.11.62) |
| 7.3.33 | php-7.3-CVE-2026-109618-109619.patch | 18 | ✅ | ✅ | ✅ |
冒烟内容: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_stack | zend_stack | zend_stack | zend_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.patch | 30,743 B | 6beb4998a5a9d204cb927d25d372a6abd75d2912a3d50b389e5e3931994b9c49 |
php-7.1-CVE-2026-109618-109619.patch | 33,824 B | f1c17a278c028b4eedfa6480c013fbaf645ace25881b0d281beede20d2a56b48 |
php-7.2-CVE-2026-109618-109619.patch | 45,313 B | ccab1deaa0cbf8a0d89818e1009604220b3c29931e633137407c0686cc6f6e00 |
php-7.3-CVE-2026-109618-109619.patch | 39,688 B | 31b38840401312d46ccfadd538c1ace9114e35558262b4fece7f5aa48bacae95 |
补丁均以官方发布版源码(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-devdeb 解包到用户目录 后通过(HAVE_CRYPT未定义会导致password.c为空、链接失败);这是环境依赖, 与补丁无关。
5. 注意事项(四个版本相同)
OOM = 进程立即退出:
memory_limit耗尽直接_exit(1),不跑 shutdown 函数、不输出 fatal error 页面,只在 stderr 打一行。这是上游 7.4 EOL 补丁的取舍。session upload progress 被源码级关闭:
session.upload_progress.*不再生效。新增 INI
max_multipart_body_parts,默认-1=max_input_vars + max_file_uploads(默认 1020)。7.0–7.3 均已 EOL,补丁只是缓解;能升级到受支持版本请优先升级。
补丁未覆盖扩展自身仍使用
zend_error_noreturn/zend_bailout的路径。7.0/7.1 的
--enable-session