Projects
home:rottame:vhosts-ng:php74
php7
Log In
Username
Password
Problem getting expanded diff: bad link: conflict in file php7.spec
×
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 14
View file
php7.changes
Changed
@@ -1,228 +1,346 @@ ------------------------------------------------------------------- -Tue Sep 3 14:47:13 UTC 2024 - Angelo Grossini <angelo@intercom.it> +Tue Oct 20 08:07:40 UTC 2026 - Petr Gajdos <pgajdos@suse.com> -- don't build mod_php +- added patches bsc#1286027 + CVE-2026-109618: memory corruption leading to RCE + CVE-2026-109619: memory corruption leading to RCE + * php7-CVE-2026-109618,109619.patch ------------------------------------------------------------------- -Thu Aug 29 09:38:34 UTC 2024 - Arjen de Korte <suse+build@de-korte.org> +Thu Oct 1 13:34:05 UTC 2026 - Petr Gajdos <pgajdos@suse.com> -- Fix build with GCC14 - -------------------------------------------------------------------- -Thu Jun 20 09:38:53 UTC 2024 - pgajdos@suse.com - -- drop unmaintained apache-rex usage +- added patches + CVE-2025-1218: Denial of Service via out-of-bounds read in mysqlnd wire protocol parser bsc#1282981 + * php7-CVE-2025-1218.patch + CVE-2026-91765: Denial of Service via unbounded recursion in SOAP parser bsc#1282875 + * php7-CVE-2026-91765.patch + CVE-2026-91766: Credential disclosure via cross-origin HTTP redirects bsc#1282876 + * php7-CVE-2026-91766.patch ------------------------------------------------------------------- -Thu Jun 20 09:37:22 UTC 2024 - pgajdos@suse.com +Wed Sep 30 13:01:41 UTC 2026 - Petr Gajdos <pgajdos@suse.com> -- security update - added patches - fix CVE-2024-2756 bsc#1222857, host/secure cookie bypass due to partial fix - + php7-CVE-2024-2756.patch - fix CVE-2024-3096 bsc#1222858, password_verify can erroneously return true, opening ATO risk - + php7-CVE-2024-3096.patch - fix CVE-2024-5458 bsc#1226073, filter bypass in filter_var FILTER_VALIDATE_URL - + php7-CVE-2024-5458.patch + CVE-2025-14181: Integer overflow to buffer overflow in soap HTTP parsing bsc#1283216 + * php7-CVE-2025-14181.patch + CVE-2026-6103: Archive entry injection via integer overflow in TAR parser bsc#1282980 + * php7-CVE-2026-6103.patch + CVE-2026-91767: Information disclosure via crafted TLS server certificate bsc#1282877 + * php7-CVE-2026-91767.patch + CVE-2026-91768: Access control bypass via partial IPv6 address comparison bsc#1282878 + * php7-CVE-2026-91768.patch + CVE-2026-91769: OpenSSL stream peer verification falls back to the Common Name whenever no `subjectAltName` matches, allowing trusted certificate impersonation bsc#1283044 + * php7-CVE-2026-91769.patch + CVE-2026-92842: Information disclosure via out-of-bounds read in stream filters bsc#1282985 + * php7-CVE-2026-92842.patch + CVE-2026-93682: Out-of-bounds read via empty HTTP redirect Location header bsc#1282986 + * php7-CVE-2026-93682.patch ------------------------------------------------------------------- -Fri May 31 13:50:46 UTC 2024 - Angelo Grossini <angelo@intercom.it> +Wed Sep 2 12:22:01 UTC 2026 - Petr Gajdos <pgajdos@suse.com> -- set session.save_path to /tmp +- backport fix for bsc#1205782 (bsc#1276531) ------------------------------------------------------------------- -Thu May 30 19:18:43 UTC 2024 - Arjen de Korte <suse+build@de-korte.org> +Fri Aug 28 07:29:46 UTC 2026 - Petr Gajdos <pgajdos@suse.com> -- Fix check for newer versions of ICU - + php7-fix-newer-versions-icu.patch +- modified patches CVE-2026-7260 bsc#1273077 + * php7-CVE-2026-7260.patch (fix the string free) ------------------------------------------------------------------- -Thu Aug 24 11:19:01 UTC 2023 - pgajdos@suse.com +Fri Jul 31 10:26:15 UTC 2026 - Petr Gajdos <pgajdos@suse.com> -- security update - added patches - fix CVE-2023-3823 bsc#1214106, XML loading external entity without being enabled - + php7-CVE-2023-3823.patch - fix CVE-2023-3824 bsc#1214103, buffer overflows in phar_dir_read() - + php7-CVE-2023-3824.patch - -------------------------------------------------------------------- -Wed Aug 16 10:33:05 UTC 2023 - Angelo Grossini <rottame@intercom.it> - -- provides php embed - -------------------------------------------------------------------- -Wed Aug 16 09:08:11 UTC 2023 - Angelo Grossini <rottame@intercom.it> - -- vhng versioning for extensions (for real) + CVE-2026-17543: SQL injection in ext-pgsql via E'...' backslash breakout bsc#1273075 + * php7-CVE-2026-17543.patch + CVE-2026-7260: Stack overflow in phar with circular symlinks bsc#1273077 + * php7-CVE-2026-7260.patch + CVE-2026-9672: Upgrade libgd bsc#1273078 + * php7-CVE-2026-9672.patch ------------------------------------------------------------------- -Wed Aug 16 09:06:21 UTC 2023 - Angelo Grossini <rottame@intercom.it> +Tue Jul 7 09:06:36 UTC 2026 - Petr Gajdos <pgajdos@suse.com> -- vhng versioning for extensions +- added patches + CVE-2026-14355: The AES-WRAP-PAD algorithm implementation in OpenSSL extension contains a buffer allocation flaw. bsc#1270351 + * php7-CVE-2026-14355.patch ------------------------------------------------------------------- -Mon Aug 7 15:11:50 UTC 2023 - Angelo Grossini <rottame@intercom.it> +Wed May 13 10:05:17 UTC 2026 - Petr Gajdos <pgajdos@suse.com> -- normalize ini filenames +- added patches + CVE-2026-6722: use-after-free in SOAP using Apache map can lead to remote code execution bsc#1264776 + * php7-CVE-2026-6722.patch + CVE-2026-6735: improper validation of the request URI within the PHP-FPM status page can lead to XSS bsc#1264775 + * php7-CVE-2026-6735.patch + CVE-2026-7258: signed `char` values passed to `ctype` functions like `isxdigit` can lead to OOB access and denial of service bsc#1264774 + * php7-CVE-2026-7258.patch + CVE-2026-7261: use-after-free due to incorrectly handled persistence of handler objects when SOAP_PERSISTENCE_SESSION is configured can lead to memory corruption, information disclosure and process crashes bsc#1264772 + * php7-CVE-2026-7261.patch + CVE-2026-7262: NULL pointer dereference caused by mistake in the SOAP decoding process when a typemap is configured can lead to a denial of service bsc#1264771 + * php7-CVE-2026-7262.patch + CVE-2026-7568: integer overflow in the `metaphone` function can lead to undefined behavior and affect the availability of the PHPprocess bsc#1264769 + * php7-CVE-2026-7568.patch ------------------------------------------------------------------- -Thu Jun 15 08:02:29 UTC 2023 - pgajdos@suse.com +Wed Jan 7 11:38:04 UTC 2026 - Petr Gajdos <pgajdos@suse.com> - security update - added patches - fix CVE-2023-3247 bsc#1212349, Missing error check and insufficient random bytes in HTTP Digest authentication for SOAP - + php7-CVE-2023-3247.patch + CVE-2025-14178 bsc#1255711, heap buffer overflow occurs in array_merge() when the total element count of packed arrays exceeds 32-bit limits or HT_MAX_SIZE + * php7-CVE-2025-14178.patch ------------------------------------------------------------------- -Thu Apr 20 21:19:59 UTC 2023 - Arjen de Korte <suse+build@de-korte.org> +Fri Jul 11 08:37:03 UTC 2025 - pgajdos@suse.com -- The %_restart_on_update macro was removed from systemd-rpm-macros. - Remove %posttrans for FPM as it wasn't working as intended anyway. - boo#1210576 +- security update +- added patches + CVE-2025-1220 bsc#1246167, unprocessed null bytes in hostnames can lead to SSRF + + php7-CVE-2025-1220.patch + CVE-2025-1735 bsc#1246146, pgsql extension does not properly handle errors within escape functions + + php7-CVE-2025-1735.patch + CVE-2025-6491 bsc#1246148, NULL pointer dereference when processing a SoapVar with a fully qualified name that is longer than 2G + + php7-CVE-2025-6491.patch ------------------------------------------------------------------- -Tue Mar 14 13:16:57 UTC 2023 - pgajdos@suse.com +Tue Mar 18 13:00:11 UTC 2025 - pgajdos@suse.com -- fix potential buffer overflow bsc#1208199 +- security update - modified patches - % php-systzdata-v19.patch (refreshed) - -------------------------------------------------------------------- -Tue Mar 7 14:13:10 UTC 2023 - Angelo Grossini <rottame@intercom.it> - -- enable imap extension + % php-php-config.patch (-p1) + % php-phpize.patch (-p1) +- added patches + fix CVE-2024-11235 bsc#1239666, Reference counting in php_request_shutdown causes Use-After-Free + + php7-CVE-2024-11235.patch + fix CVE-2025-1217 bsc#1239664, Header parser of `http` stream wrapper does not handle folded headers + + php7-CVE-2025-1217.patch + fix CVE-2025-1734 bsc#1239668, Streams HTTP wrapper does not fail for headers with invalid name and no colon + + php7-CVE-2025-1734.patch + fix CVE-2025-1736 bsc#1239670, Stream HTTP wrapper header check might omit basic auth header + + php7-CVE-2025-1736.patch + fix CVE-2025-1861 bsc#1239669, Stream HTTP wrapper truncate redirect location to 1024 bytes + + php7-CVE-2025-1861.patch + fix CVE-2025-1219 bsc#1239667, libxml streams use wrong `content-type` header when requesting a redirected resource + + php8-CVE-2025-1219.patch ------------------------------------------------------------------- -Tue Mar 7 11:32:35 UTC 2023 - Angelo Grossini <rottame@intercom.it> +Tue Nov 26 13:46:54 UTC 2024 - pgajdos@suse.com -- enable dblib extension +- security update +- added patches + fix CVE-2024-11233 bsc#1233702, single-byte buffer overread due to missing bounds check when processing input with convert.quoted-printable-decode filters + + php7-CVE-2024-11233.patch + fix CVE-2024-11234 bsc#1233703, configuring streams with a proxy and the 'request_fulluri' context option might allow for CRLF injection in URIs + + php7-CVE-2024-11234.patch + fix CVE-2024-8929 bsc#1233651, In PHP versions 8.1.* before 8.1.31, 8.2.* before 8.2.26, 8.3.* before 8.3.14, a hostile MySQL server can cause the client to disclose the content of its heap containing data from other SQL requests ... + + php7-CVE-2024-8929.patch ------------------------------------------------------------------- -Thu Feb 16 21:13:28 UTC 2023 - Arjen de Korte <suse+build@de-korte.org> +Fri Oct 11 08:55:51 UTC 2024 - pgajdos@suse.com - security update - added patches - fix CVE-2023-0567 (Password_verify() always return true with some hash) - + php7-CVE-2023-0567-a.patch and php7-CVE-2023-0567-b.patch - fix CVE-2023-0568 (1-byte array overrun in common path resolve code) - + php7-CVE-2023-0568.patch - fix CVE-2023-0662 (DOS vulnerability when parsing multipart request body) - + php7-CVE-2023-0662.patch + fix CVE-2024-8925 bsc#1231360, erroneous parsing of multipart form data in HTTP POST requests leads to legitimate data not being processed + + php7-CVE-2024-8925.patch + fix CVE-2024-8927 bsc#1231358, cgi.force_redirect configuration is bypassable due to an environment variable collision + + php7-CVE-2024-8927.patch + fix CVE-2024-9026 bsc#1231382, pollution of worker output logs in PHP-FPM + + php7-CVE-2024-9026.patch ------------------------------------------------------------------- -Mon Jan 9 16:24:09 UTC 2023 - munix9@googlemail.com +Tue Jun 11 12:09:13 UTC 2024 - pgajdos@suse.com -- Add fix-NETSNMP_DISABLE_DES.patch to solve - "error: 'usmDESPrivProtocol' undeclared" on Factory/TW +- security update +- added patches + fix CVE-2024-5458 bsc#1226073, filter bypass in filter_var FILTER_VALIDATE_URL + + php7-CVE-2024-5458.patch ------------------------------------------------------------------- -Mon Jan 9 10:29:44 UTC 2023 - pgajdos@suse.com +Fri Apr 19 08:42:51 UTC 2024 - pgajdos@suse.com - security update - added patches - fix CVE-2022-31631 bsc#1206958, Due to an integer overflow PDO:quote() may return unquoted string - + php7-CVE-2022-31631.patch + fix CVE-2024-2756 bsc#1222857, host/secure cookie bypass due to partial fix + + php7-CVE-2024-2756.patch + fix CVE-2024-3096 bsc#1222858, password_verify can erroneously return true, opening ATO risk + + php7-CVE-2024-3096.patch ------------------------------------------------------------------- -Thu Nov 10 09:57:02 UTC 2022 - pgajdos@suse.com +Tue Jan 16 15:12:00 UTC 2024 - pgajdos@suse.com -- hardcode openssl version, openssl3 will not be supported - https://www.php.net/manual/en/openssl.requirements.php +- ensure we are building against openssl-1_1 ------------------------------------------------------------------- -Thu Nov 3 10:21:36 UTC 2022 - pgajdos@suse.com +Wed Aug 23 12:52:32 UTC 2023 - pgajdos@suse.com -- version update to 7.4.33 - * This is security release that fixes an OOB read due to insufficient - input validation in imageloadfont(), and a buffer overflow in - hash_update() on long parameter. - * CVE-2022-37454 bsc#1204577, CVE-2022-31630 bsc#1204979 - https://www.php.net/ChangeLog-7.php#7.4.33 +- security update +- added patches + fix CVE-2023-3823 bsc#1214106, XML loading external entity without being enabled + + php7-CVE-2023-3823.patch + fix CVE-2023-3824 bsc#1214103, buffer overflows in phar_dir_read() + + php7-CVE-2023-3824.patch ------------------------------------------------------------------- -Thu Sep 29 10:17:46 UTC 2022 - pgajdos@suse.com +Thu Jun 15 07:53:19 UTC 2023 - pgajdos@suse.com -- version update to 7.4.32 - * This is security release that addresses an infinite recursion with specially - constructed phar files, and prevents a clash with variable name mangling for - the __Host/__Secure HTTP headers. - * CVEs fixed: CVE-2022-31628, CVE-2022-31629 - https://www.php.net/ChangeLog-7.php#7.4.32 - https://www.php.net/ChangeLog-7.php#7.4.31 +- security update +- added patches + fix CVE-2023-3247 bsc#1212349, Missing error check and insufficient random bytes in HTTP Digest authentication for SOAP + + php7-CVE-2023-3247.patch ------------------------------------------------------------------- -Fri Jun 10 04:34:52 UTC 2022 - pgajdos@suse.com +Tue Mar 21 13:09:07 UTC 2023 - pgajdos@suse.com -- version update to 7.4.30 - * This is a security release. - https://www.php.net/ChangeLog-7.php#7.4.30 +- security update +- added patches + fix CVE-2022-4900 bsc#1209537, potential buffer overflow via PHP_CLI_SERVER_WORKERS environment variable + + php7-CVE-2022-4900.patch ------------------------------------------------------------------- -Fri May 6 09:38:30 UTC 2022 - pgajdos@suse.com +Tue Mar 14 10:02:27 UTC 2023 - pgajdos@suse.com -- security update bsc#1197644 -- added patches - fix https://github.com/php/php-src/commit/771dbdb319fa7f90584f6b2cc2c54ccff570492d - + php7-signedness-php_filter_validate_domain.patch +- fix potential buffer overflow bsc#1208199 +- modified patches + % php-systzdata-v19.patch (refreshed) ------------------------------------------------------------------- -Wed Apr 20 17:49:17 UTC 2022 - pgajdos@suse.com +Mon Mar 6 09:07:34 UTC 2023 - pgajdos@suse.com -- version update to 7.4.29: - Core: - No source changes to this release. This update allows for - re-building the Windows binaries against upgraded dependencies - which have received security updates. - Date: - Updated to latest IANA timezone database (2022a). +- ensure extension=mysqlnd will be called before extension=mysqli + bsc#1205162 ------------------------------------------------------------------- -Mon Apr 11 19:36:58 UTC 2022 - pgajdos@suse.com +Fri Feb 17 11:20:37 UTC 2023 - pgajdos@suse.com -- fpm %postrans: check whether sytemctl is available +- security update +- added patches + fix CVE-2023-0568 bsc#1208366, NULL byte off-by-one in php_check_specific_open_basedir + + php7-CVE-2023-0568.patch + fix CVE-2023-0662 bsc#1208367, DoS vulnerability when parsing multipart request body + + php7-CVE-2023-0662.patch + https://github.com/php/php-src/commit/a92acbad873a05470af1a47cb785a18eadd827b5, relates to CVE-2023-0567 bsc#1208388 + + php7-crypt-possible-buffer-overread.patch ------------------------------------------------------------------- -Fri Apr 8 21:49:52 UTC 2022 - Arjen de Korte <suse+build@de-korte.org> +Mon Jan 9 12:56:18 UTC 2023 - pgajdos@suse.com -- Disable build with '-z now' as it breaks the php-mysql extension - boo#1197994 +- security update +- added patches + fix CVE-2022-31631 bsc#1206958, Due to an integer overflow PDO:quote() may return unquoted string + + php7-CVE-2022-31631.patch ------------------------------------------------------------------- -Thu Mar 31 18:42:35 UTC 2022 - Arjen de Korte <suse+build@de-korte.org> +Thu Nov 3 10:33:32 UTC 2022 - pgajdos@suse.com -- build PHP-FPM with libacl support (boo#1196870) +- version update to 7.4.33 bsc#1204577bsc#1204979 + 03 Nov 2022 + GD: + Fixed bug #81739: OOB read due to insufficient input validation in imageloadfont(). (CVE-2022-31630) + Hash: + Fixed bug #81738: buffer overflow in hash_update() on long parameter. (CVE-2022-37454) + +------------------------------------------------------------------- +Mon Oct 3 08:53:12 UTC 2022 - pgajdos@suse.com + +- version update to 7.4.32 jsc#SLE-23639 + Version 7.4.32 + 29 Sep 2022 + Core: + Fixed bug #81726: phar wrapper: DOS when using quine gzip file. (CVE-2022-31628) + Fixed bug #81727: Don't mangle HTTP variable names that clash with ones that have a specific semantic meaning. (CVE-2022-31629) + Version 7.4.30 + 09 Jun 2022 + mysqlnd: + Fixed bug #81719: mysqlnd/pdo password buffer overflow. (CVE-2022-31626) + pgsql: + Fixed bug #81720: Uninitialized array in pg_query_params(). (CVE-2022-31625) + Version 7.4.29 + 14 Apr 2022 + Core: + No source changes to this release. This update allows for re-building the Windows binaries against upgraded dependencies which have received security updates. + Date: + Updated to latest IANA timezone database (2022a). + Version 7.4.28 + 17 Feb 2022 + Filter: + Fix #81708: UAF due to php_filter_float() failing for ints (CVE-2021-21708) + Version 7.4.27 + 16 Dec 2021 + Core: + Fixed bug #81626 (Error on use static:: in __сallStatic() wrapped to Closure::fromCallable()). + FPM: + Fixed bug #81513 (Future possibility for heap overflow in FPM zlog). + GD: + Fixed bug #71316 (libpng warning from imagecreatefromstring). + OpenSSL: + Fixed bug #75725 (./configure: detecting RAND_egd). + PCRE: + Fixed bug #74604 (Out of bounds in php_pcre_replace_impl). + Standard: + Fixed bug #81618 (dns_get_record fails on FreeBSD for missing type). + Fixed bug #81659 (stream_get_contents() may unnecessarily overallocate). + Version 7.4.26 + 18 Nov 2021 + Core: + Fixed bug #81518 (Header injection via default_mimetype / default_charset). + Date: + Fixed bug #81500 (Interval serialization regression since 7.3.14 / 7.4.2). + MBString: + Fixed bug #76167 (mbstring may use pointer from some previous request). + MySQLi: + Fixed bug #81494 (Stopped unbuffered query does not throw error). + PCRE: + Fixed bug #81424 (PCRE2 10.35 JIT performance regression). + Streams: + Fixed bug #54340 (Memory corruption with user_filter). + XML: + Fixed bug #79971 (special character is breaking the path in xml function). (CVE-2021-21707) +- fixes bsc#1203867 and bsc#1203870 +- deleted patches + - php7-CVE-2021-21707.patch (upstreamed) + - php7-CVE-2021-21708.patch (upstreamed) + - php7-CVE-2022-31625.patch (upstreamed) + - php7-CVE-2022-31626.patch (upstreamed) ------------------------------------------------------------------- -Fri Feb 18 07:05:10 UTC 2022 - Arjen de Korte <suse+build@de-korte.org> +Mon Jun 20 09:14:49 UTC 2022 - pgajdos@suse.com -- updated to 7.4.28: This is a security release (CVE-2021-21708). See - https://www.php.net/ChangeLog-7.php#7.4.28 +- security update +- added patches + fix CVE-2022-31625 bsc#1200645, uninitialized pointers free in Postgres extension + + php7-CVE-2022-31625.patch ------------------------------------------------------------------- -Sun Jan 9 10:40:43 UTC 2022 - Arjen de Korte <suse+build@de-korte.org> +Fri Jun 17 12:09:36 UTC 2022 - pgajdos@suse.com -- use /tmp to store session information (boo#1194414) - % php-ini.patch +- security update +- added patches + fix CVE-2022-31626 bsc#1200628, buffer overflow via user-supplied password when using pdo_mysql extension with mysqlnd driver + + php7-CVE-2022-31626.patch ------------------------------------------------------------------- -Thu Dec 16 15:28:52 UTC 2021 - Arjen de Korte <suse+build@de-korte.org> +Fri Jun 10 09:51:47 UTC 2022 - pgajdos@suse.com -- updated to 7.4.27: This is a bug fix release. See - https://www.php.net/ChangeLog-7.php#7.4.27 +- security update +- added patches + fix CVE-2021-21707 bsc#1193041, special character breaks path in xml parsing + + php7-CVE-2021-21707.patch ------------------------------------------------------------------- -Wed Dec 1 21:44:34 UTC 2021 - Arjen de Korte <suse+build@de-korte.org> +Fri May 6 10:05:17 UTC 2022 - pgajdos@suse.com -- provide configuration for PHP-FPM out of the box (boo#1192414) -- package missing php.ini for PHP-FPM (boo#1192672) +- security update bsc#1197644 +- added patches + fix https://github.com/php/php-src/commit/771dbdb319fa7f90584f6b2cc2c54ccff570492d + + php7-signedness-php_filter_validate_domain.patch ------------------------------------------------------------------- -Thu Nov 18 13:40:56 UTC 2021 - Arjen de Korte <suse+build@de-korte.org> +Tue Feb 22 10:34:54 UTC 2022 - pgajdos@suse.com -- updated to 7.4.26: This is a security release (CVE-2021-21707) - which also contains several bug fixes. - See https://www.php.net/ChangeLog-7.php#7.4.26 +- security update +- added patches + fix CVE-2021-21708 bsc#1196252, Use after free due to php_filter_float() failing for ints + + php7-CVE-2021-21708.patch ------------------------------------------------------------------- Fri Oct 22 15:30:41 UTC 2021 - Arjen de Korte <suse+build@de-korte.org>
View file
php7.spec
Changed
@@ -1,7 +1,7 @@ # -# spec file +# spec file for package php7 # -# Copyright (c) 2024 SUSE LLC +# Copyright (c) 2021 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -105,33 +105,102 @@ Patch19: php-build-reproducible-phar.patch # https://github.com/php/php-src/commit/b3646440b1808abf0874b6f89027ce53ec5da03f Patch20: php7-gd-removed-unused-constants.patch -# https://github.com/php/php-src/commit/771dbdb319fa7f90584f6b2cc2c54ccff570492d -Patch21: php7-signedness-php_filter_validate_domain.patch # CVE-2022-31631 bsc#1206958, Due to an integer overflow PDO:quote() may return unquoted string -Patch22: php7-CVE-2022-31631.patch -# fix "error: 'usmDESPrivProtocol' undeclared" -Patch23: fix-NETSNMP_DISABLE_DES.patch -# CVE-2023-0567 - Password_verify() always return true with some hash -Patch24: php7-CVE-2023-0567-a.patch -Patch25: php7-CVE-2023-0567-b.patch -# CVE-2023-0568 - 1-byte array overrun in common path resolve code -Patch26: php7-CVE-2023-0568.patch -# CVE-2023-0662 - DOS vulnerability when parsing multipart request body -Patch27: php7-CVE-2023-0662.patch +Patch21: php7-CVE-2022-31631.patch +# CVE-2023-0568 bsc#1208366, NULL byte off-by-one in php_check_specific_open_basedir +Patch22: php7-CVE-2023-0568.patch +# https://github.com/php/php-src/commit/a92acbad873a05470af1a47cb785a18eadd827b5, relates to CVE-2023-0567 bsc#1208388 +Patch23: php7-crypt-possible-buffer-overread.patch +# CVE-2023-0662 bsc#1208367, DoS vulnerability when parsing multipart request body +Patch24: php7-CVE-2023-0662.patch +# CVE-2022-4900 bsc#1209537, potential buffer overflow via PHP_CLI_SERVER_WORKERS environment variable +Patch25: php7-CVE-2022-4900.patch # CVE-2023-3247 bsc#1212349, Missing error check and insufficient random bytes in HTTP Digest authentication for SOAP -Patch28: php7-CVE-2023-3247.patch -# CVE-2023-3823 bsc#1214106, XML loading external entity without being enabled -Patch29: php7-CVE-2023-3823.patch +Patch26: php7-CVE-2023-3247.patch # CVE-2023-3824 bsc#1214103, buffer overflows in phar_dir_read() -Patch30: php7-CVE-2023-3824.patch -# PATCH-FIX-UPSTREAM https://github.com/php/php-src/pull/14186 -Patch31: php7-fix-newer-versions-icu.patch -# CVE-2024-2756 bsc#1222857, host/secure cookie bypass due to partial fix -Patch32: php7-CVE-2024-2756.patch +Patch27: php7-CVE-2023-3824.patch +# CVE-2023-3823 bsc#1214106, XML loading external entity without being enabled +Patch28: php7-CVE-2023-3823.patch # CVE-2024-3096 bsc#1222858, password_verify can erroneously return true, opening ATO risk -Patch33: php7-CVE-2024-3096.patch +Patch29: php7-CVE-2024-3096.patch +# CVE-2024-2756 bsc#1222857, host/secure cookie bypass due to partial fix +Patch30: php7-CVE-2024-2756.patch # CVE-2024-5458 bsc#1226073, filter bypass in filter_var FILTER_VALIDATE_URL -Patch34: php7-CVE-2024-5458.patch +Patch31: php7-CVE-2024-5458.patch +# CVE-2024-8927 bsc#1231358, cgi.force_redirect configuration is bypassable due to an environment variable collision +Patch32: php7-CVE-2024-8927.patch +# CVE-2024-8925 bsc#1231360, erroneous parsing of multipart form data in HTTP POST requests leads to legitimate data not being processed +Patch33: php7-CVE-2024-8925.patch +# CVE-2024-9026 bsc#1231382, pollution of worker output logs in PHP-FPM +Patch34: php7-CVE-2024-9026.patch +# CVE-2024-11233 bsc#1233702, single-byte buffer overread due to missing bounds check when processing input with convert.quoted-printable-decode filters +Patch35: php7-CVE-2024-11233.patch +# CVE-2024-11234 bsc#1233703, configuring streams with a proxy and the 'request_fulluri' context option might allow for CRLF injection in URIs +Patch36: php7-CVE-2024-11234.patch +# CVE-2024-8929 bsc#1233651, In PHP versions 8.1.* before 8.1.31, 8.2.* before 8.2.26, 8.3.* before 8.3.14, a hostile MySQL server can cause the client to disclose the content of its heap containing data from other SQL requests ... +Patch38: php7-CVE-2024-8929.patch +# CVE-2024-11235 bsc#1239666, Reference counting in php_request_shutdown causes Use-After-Free +Patch39: php7-CVE-2024-11235.patch +# CVE-2025-1217 bsc#1239664, Header parser of `http` stream wrapper does not handle folded headers +Patch40: php7-CVE-2025-1217.patch +# CVE-2025-1734 bsc#1239668, Streams HTTP wrapper does not fail for headers with invalid name and no colon +Patch41: php7-CVE-2025-1734.patch +# CVE-2025-1861 bsc#1239669, Stream HTTP wrapper truncate redirect location to 1024 bytes +Patch42: php7-CVE-2025-1861.patch +# CVE-2025-1736 bsc#1239670, Stream HTTP wrapper header check might omit basic auth header +Patch43: php7-CVE-2025-1736.patch +# CVE-2025-1219 bsc#1239667, libxml streams use wrong `content-type` header when requesting a redirected resource +Patch44: php7-CVE-2025-1219.patch +# CVE-2025-6491 bsc#1246148, NULL pointer dereference when processing a SoapVar with a fully qualified name that is longer than 2G +Patch45: php7-CVE-2025-6491.patch +# CVE-2025-1220 bsc#1246167, unprocessed null bytes in hostnames can lead to SSRF +Patch46: php7-CVE-2025-1220.patch +# CVE-2025-1735 bsc#1246146, pgsql extension does not properly handle errors within escape functions +Patch47: php7-CVE-2025-1735.patch +# CVE-2025-14178 bsc#1255711, heap buffer overflow occurs in array_merge() when the total element count of packed arrays exceeds 32-bit limits or HT_MAX_SIZE +Patch48: php7-CVE-2025-14178.patch +# CVE-2026-7568: integer overflow in the `metaphone` function can lead to undefined behavior and affect the availability of the PHPprocess bsc#1264769 +Patch49: php7-CVE-2026-7568.patch +# CVE-2026-7261: use-after-free due to incorrectly handled persistence of handler objects when SOAP_PERSISTENCE_SESSION is configured can lead to memory corruption, information disclosure and process crashes bsc#1264772 +Patch50: php7-CVE-2026-7261.patch +# CVE-2026-6722: use-after-free in SOAP using Apache map can lead to remote code execution bsc#1264776 +Patch51: php7-CVE-2026-6722.patch +# CVE-2026-7262: NULL pointer dereference caused by mistake in the SOAP decoding process when a typemap is configured can lead to a denial of service bsc#1264771 +Patch52: php7-CVE-2026-7262.patch +# CVE-2026-7258: signed `char` values passed to `ctype` functions like `isxdigit` can lead to OOB access and denial of service bsc#1264774 +Patch53: php7-CVE-2026-7258.patch +# CVE-2026-6735: improper validation of the request URI within the PHP-FPM status page can lead to XSS bsc#1264775 +Patch54: php7-CVE-2026-6735.patch +# CVE-2026-14355: The AES-WRAP-PAD algorithm implementation in OpenSSL extension contains a buffer allocation flaw. bsc#1270351 +Patch55: php7-CVE-2026-14355.patch +# CVE-2026-17543: SQL injection in ext-pgsql via E'...' backslash breakout bsc#1273075 +Patch56: php7-CVE-2026-17543.patch +# CVE-2026-9672: Upgrade libgd bsc#1273078 +Patch57: php7-CVE-2026-9672.patch +# CVE-2026-7260: Stack overflow in phar with circular symlinks bsc#1273077 +Patch58: php7-CVE-2026-7260.patch +# CVE-2026-93682: Out-of-bounds read via empty HTTP redirect Location header bsc#1282986 +Patch59: php7-CVE-2026-93682.patch +# CVE-2026-92842: Information disclosure via out-of-bounds read in stream filters bsc#1282985 +Patch60: php7-CVE-2026-92842.patch +# CVE-2026-6103: Archive entry injection via integer overflow in TAR parser bsc#1282980 +Patch61: php7-CVE-2026-6103.patch +# CVE-2026-91768: Access control bypass via partial IPv6 address comparison bsc#1282878 +Patch62: php7-CVE-2026-91768.patch +# CVE-2026-91769: OpenSSL stream peer verification falls back to the Common Name whenever no `subjectAltName` matches, allowing trusted certificate impersonation bsc#1283044 +Patch63: php7-CVE-2026-91769.patch +# CVE-2026-91767: Information disclosure via crafted TLS server certificate bsc#1282877 +Patch64: php7-CVE-2026-91767.patch +# CVE-2026-14181: Integer overflow to buffer overflow in soap HTTP parsing bsc#1283216 +Patch65: php7-CVE-2025-14181.patch +# CVE-2026-91765: Denial of Service via unbounded recursion in SOAP parser bsc#1282875 +Patch66: php7-CVE-2026-91765.patch +# CVE-2026-91766: Credential disclosure via cross-origin HTTP redirects bsc#1282876 +Patch67: php7-CVE-2026-91766.patch +# CVE-2025-1218: Denial of Service via out-of-bounds read in mysqlnd wire protocol parser bsc#1282981 +Patch68: php7-CVE-2025-1218.patch +# CVE-2026-109618: memory corruption leading to RCE|CVE-2026-109619: memory corruption leading to RCE +Patch69: php7-CVE-2026-109618,109619.patch BuildRequires: apache-rpm-macros BuildRequires: autoconf BuildRequires: bison @@ -145,7 +214,6 @@ BuildRequires: libacl-devel BuildRequires: libapparmor-devel BuildRequires: libbz2-devel -BuildRequires: libopenssl-1_1-devel BuildRequires: libtidy-devel BuildRequires: libtiff-devel BuildRequires: libtool @@ -176,6 +244,7 @@ BuildRequires: pkgconfig(libzip) >= 0.11 BuildRequires: pkgconfig(odbc) BuildRequires: pkgconfig(oniguruma) +BuildRequires: libopenssl-1_1-devel BuildRequires: pkgconfig(sqlite3) > 3.7.4 BuildRequires: pkgconfig(zlib) >= 1.2.0.4 %if %{build_firebird} @@ -190,14 +259,18 @@ BuildRequires: pkgconfig(libargon2) %endif %if "%{flavor}" == "test" +BuildRequires: apache-rex BuildRequires: mod_php_any = %{version} BuildRequires: php-cli = %{version} BuildRequires: php-fpm = %{version} +%apache_rex_deps %endif %if "%{flavor}" == "" Requires: php-sapi = %{version} Requires: timezone +Requires(pre): group(www) +Requires(pre): user(wwwrun) Recommends: php-ctype = %{version} Recommends: php-dom = %{version} Recommends: php-iconv = %{version} @@ -364,8 +437,6 @@ BuildRequires: php = %{version} BuildRequires: pkgconfig(libsystemd) >= 209 Requires: php = %{version} -Requires: group(www) -Requires: user(wwwrun) Provides: php-fpm = %{version} Provides: php-fpm(vhng) = %{php_vhng_branch} Provides: php-sapi = %{version} @@ -1107,8 +1178,8 @@ ./buildconf --force # export flags -CFLAGS="%{optflags} -O3 -fPIE -fPIC -DPIC -D_GNU_SOURCE -fno-strict-aliasing -fpermissive" -CXXFLAGS="%{optflags} -O3 -fPIE -fPIC -DPIC -D_GNU_SOURCE -fno-strict-aliasing -fpermissive" +CFLAGS="%{optflags} -O3 -fPIE -fPIC -DPIC -D_GNU_SOURCE -fno-strict-aliasing" +CXXFLAGS="%{optflags} -O3 -fPIE -fPIC -DPIC -D_GNU_SOURCE -fno-strict-aliasing" %if %{build_firebird} CFLAGS="$CFLAGS -I/usr/include/firebird" CXXFLAGS="$CXXFLAGS -I/usr/include/firebird" @@ -1127,8 +1198,6 @@ export EXTENSION_DIR=%{extension_dir} # Fix build-cli for arm and aarch64 export LIBS=-ltinfo -# Some extensions are broken when linking with -z now -export SUSE_ZNOW=0 # build function Build() @@ -1205,9 +1274,8 @@ %if "%{flavor}" == "fpm" Build fpm \ - --enable-fpm \ - --with-fpm-acl \ --with-fpm-systemd \ + --enable-fpm \ --with-fpm-user=%{apache_user} \ --with-fpm-group=%{apache_group} \ --bindir=%{_bindir} \ @@ -1319,6 +1387,9 @@ done set -x unset NO_INTERACTION REPORT_EXIT_STATUS +# Apache HTTPD runnable examples test +%apache_rex_check -m libs mod_php-basic +%apache_rex_check -m libs -b sapi/fpm mod_proxy_fcgi-php-fpm mod_proxy_fcgi-php-fpm-auth-RewriteRule mod_proxy_fcgi-php-fpm-CGIPassAuth exit 0 %endif @@ -1365,16 +1436,12 @@ %if "%{flavor}" == "fpm" make install-binaries INSTALL_ROOT=%{buildroot} install -dm 755 %{buildroot}%{php_sysconf}/fpm -sed "s=@extdir@=%{extension_dir}=" php.ini-production > %{buildroot}%{php_sysconf}/fpm/php.ini #install fpm init script. install -D -m 0644 sapi/fpm/php-fpm.service %{buildroot}%{_unitdir}/php-fpm.service ln -s service %{buildroot}%{_sbindir}/rcphp-fpm # bug 1173786 install -d -m 0755 %{buildroot}%{_tmpfilesdir} install -m 0644 %{SOURCE12} %{buildroot}%{_tmpfilesdir}/php-fpm.conf -# bug 1192414 -mv %{buildroot}%{php_sysconf}/fpm/php-fpm.conf{.default,} -mv %{buildroot}%{php_sysconf}/fpm/php-fpm.d/www.conf{.default,} %endif %if "%{flavor}" == "" @@ -1413,6 +1480,8 @@ echo "; comment out next line to disable $ext extension in php" > %{buildroot}%{php_sysconf}/conf.d/${ini_name}.ini echo "${zend_}extension=$ext.so" >> %{buildroot}%{php_sysconf}/conf.d/${ini_name}.ini done +# directory for sessions +install -d %{buildroot}%{_localstatedir}/lib/%{php_name} # fix symlink (bnc#734176) ln -s %{_bindir}/php %{buildroot}%{_bindir}/%{php_name} # install the macros file: @@ -1422,19 +1491,21 @@ # install missing SAPI headers for embed install -d %{buildroot}%{_includedir}/%{php_name}/sapi/embed install -m 644 sapi/embed/php_embed.h %{buildroot}%{_includedir}/%{php_name}/sapi/embed/php_embed.h +# mysqlnd must be loaded before mysqli (undefined symbol: mysqlnd_global_stats) +mv %{buildroot}%{php_sysconf}/conf.d/{,20-}mysqlnd.ini %endif %if "%{flavor}" == "apache2" %post if $1 -eq 1 ; then # package is just installed - a2enmod -q %{php_name} || a2enmod %{php_name} + a2enmod %{php_name} > /dev/null fi %preun if $1 -eq 0 ; then # package will be uninstalled - a2enmod -q %{php_name} && a2enmod -d %{php_name} + a2enmod -d %{php_name} > /dev/null fi %postun @@ -1461,7 +1532,15 @@ %service_del_preun php-fpm.service %postun -%service_del_postun php-fpm.service +# do not try-restart yet as extensions may be updated too +%if 0%{?suse_version} > 1500 +%service_del_postun_without_restart php-fpm.service +%else +%service_del_postun -n php-fpm.service +%endif + +%posttrans +%_restart_on_update php-fpm.service %endif %if "%{flavor}" == "embed" @@ -1483,6 +1562,7 @@ %dir %{extension_dir} %dir %{php_sysconf} %dir %{php_sysconf}/conf.d +%attr(0755, %{apache_user}, root) %dir %{_localstatedir}/lib/%{php_name} %files cli %defattr(-, root, root) @@ -1526,9 +1606,8 @@ %{_sbindir}/php-fpm %dir %{php_sysconf}/fpm %dir %{php_sysconf}/fpm/php-fpm.d -%config(noreplace) %{php_sysconf}/fpm/php.ini -%config(noreplace) %{php_sysconf}/fpm/php-fpm.conf -%config(noreplace) %{php_sysconf}/fpm/php-fpm.d/www.conf +%config %{php_sysconf}/fpm/php-fpm.conf.default +%config %{php_sysconf}/fpm/php-fpm.d/www.conf.default %{_mandir}/man8/php-fpm.8%{?ext_man} %{_sbindir}/rcphp-fpm %dir %{_datadir}/%{php_name}/fpm @@ -1653,7 +1732,7 @@ %{extension_dir}/mysqli.so %config(noreplace) %{php_sysconf}/conf.d/*mysqli.ini %{extension_dir}/mysqlnd.so -%config(noreplace) %{php_sysconf}/conf.d/*mysqlnd.ini +%config(noreplace) %{php_sysconf}/conf.d/20-mysqlnd.ini %{extension_dir}/pdo_mysql.so %config(noreplace) %{php_sysconf}/conf.d/*pdo_mysql.ini @@ -1819,3 +1898,4 @@ %endif %changelog +
View file
fix-NETSNMP_DISABLE_DES.patch
Deleted
@@ -1,31 +0,0 @@ ---- a/ext/snmp/snmp.c -+++ b/ext/snmp/snmp.c -@@ -1225,19 +1225,22 @@ static int netsnmp_session_set_auth_prot - Set the security protocol in the snmpv3 session */ - static int netsnmp_session_set_sec_protocol(struct snmp_session *s, char *prot) - { -+#ifndef NETSNMP_DISABLE_DES - if (!strcasecmp(prot, "DES")) { - s->securityPrivProto = usmDESPrivProtocol; - s->securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN; -+ return (0); -+ } -+#endif - #ifdef HAVE_AES -- } else if (!strcasecmp(prot, "AES128") || !strcasecmp(prot, "AES")) { -+ if (!strcasecmp(prot, "AES128") || !strcasecmp(prot, "AES")) { - s->securityPrivProto = usmAESPrivProtocol; - s->securityPrivProtoLen = USM_PRIV_PROTO_AES_LEN; --#endif -- } else { -- php_error_docref(NULL, E_WARNING, "Unknown security protocol '%s'", prot); -- return (-1); -+ return (0); - } -- return (0); -+#endif -+ php_error_docref(NULL, E_WARNING, "Unknown security protocol '%s'", prot); -+ return (-1); - } - /* }}} */ -
View file
php-ini.patch
Changed
@@ -29,3 +29,12 @@ ; Maximum number of links. -1 means no limit. ; http://php.net/mysqli.max-links +@@ -1354,7 +1355,7 @@ session.save_handler = files + ; where MODE is the octal representation of the mode. Note that this + ; does not overwrite the process's umask. + ; http://php.net/session.save-path +-;session.save_path = "/tmp" ++session.save_path = "/var/lib/php7" + + ; Whether to use strict session mode. + ; Strict session mode does not accept an uninitialized session ID, and
View file
php-php-config.patch
Changed
@@ -4,7 +4,7 @@ Index: scripts/php-config.in =================================================================== ---- a/scripts/php-config.in +--- a/scripts/php-config.in.orig +++ b/scripts/php-config.in @@ -6,7 +6,7 @@ datarootdir="@datarootdir@" exec_prefix="@exec_prefix@"
View file
php-phpize.patch
Changed
@@ -5,7 +5,7 @@ Index: scripts/Makefile.frag =================================================================== ---- a/scripts/Makefile.frag +--- a/scripts/Makefile.frag.orig +++ b/scripts/Makefile.frag @@ -3,8 +3,8 @@ # Build environment install @@ -20,7 +20,7 @@ scripts/phpize.m4 \ Index: scripts/phpize.in =================================================================== ---- a/scripts/phpize.in +--- a/scripts/phpize.in.orig +++ b/scripts/phpize.in @@ -4,8 +4,8 @@ prefix='@prefix@'
View file
php7-CVE-2023-0567-a.patch -> php7-CVE-2022-4900.patch
Changed
@@ -1,142 +1,29 @@ -From c840f71524067aa474c00c3eacfb83bd860bfc8a Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= <tim@bastelstu.be> -Date: Mon, 23 Jan 2023 21:15:24 +0100 -Subject: PATCH crypt: Fix validation of malformed BCrypt hashes -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -PHP’s implementation of crypt_blowfish differs from the upstream Openwall -version by adding a “PHP Hack”, which allows one to cut short the BCrypt salt -by including a `$` character within the characters that represent the salt. - -Hashes that are affected by the “PHP Hack” may erroneously validate any -password as valid when used with `password_verify` and when comparing the -return value of `crypt()` against the input. - -The PHP Hack exists since the first version of PHP’s own crypt_blowfish -implementation that was added in 1e820eca02dcf322b41fd2fe4ed2a6b8309f8ab5. - -No clear reason is given for the PHP Hack’s existence. This commit removes it, -because BCrypt hashes containing a `$` character in their salt are not valid -BCrypt hashes. ---- - ext/standard/crypt_blowfish.c | 8 -- - .../tests/crypt/bcrypt_salt_dollar.phpt | 82 +++++++++++++++++++ - 2 files changed, 82 insertions(+), 8 deletions(-) - create mode 100644 ext/standard/tests/crypt/bcrypt_salt_dollar.phpt - -diff --git a/ext/standard/crypt_blowfish.c b/ext/standard/crypt_blowfish.c -index 3806a290aee4..351d40308089 100644 ---- a/ext/standard/crypt_blowfish.c -+++ b/ext/standard/crypt_blowfish.c -@@ -371,7 +371,6 @@ static const unsigned char BF_atoi640x60 = { - #define BF_safe_atoi64(dst, src) \ - { \ - tmp = (unsigned char)(src); \ -- if (tmp == '$') break; /* PHP hack */ \ - if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \ - tmp = BF_atoi64tmp; \ - if (tmp > 63) return -1; \ -@@ -399,13 +398,6 @@ static int BF_decode(BF_word *dst, const char *src, int size) - *dptr++ = ((c3 & 0x03) << 6) | c4; - } while (dptr < end); +Index: php-7.4.33/sapi/cli/php_cli_server.c +=================================================================== +--- php-7.4.33.orig/sapi/cli/php_cli_server.c ++++ php-7.4.33/sapi/cli/php_cli_server.c +@@ -517,13 +517,8 @@ static int sapi_cli_server_startup(sapi_ + if (php_cli_server_workers_max > 1) { + zend_long php_cli_server_worker; -- if (end - dptr == size) { -- return -1; -- } +- php_cli_server_workers = calloc( +- php_cli_server_workers_max, sizeof(pid_t)); +- if (!php_cli_server_workers) { +- php_cli_server_workers_max = 1; - -- while (dptr < end) /* PHP hack */ -- *dptr++ = 0; -- - return 0; - } +- return SUCCESS; +- } ++ php_cli_server_workers = pecalloc( ++ php_cli_server_workers_max, sizeof(pid_t), 1); + + php_cli_server_master = getpid(); + +@@ -2361,7 +2356,7 @@ static void php_cli_server_dtor(php_cli_ + !WIFSIGNALED(php_cli_server_worker_status)); + } -diff --git a/ext/standard/tests/crypt/bcrypt_salt_dollar.phpt b/ext/standard/tests/crypt/bcrypt_salt_dollar.phpt -new file mode 100644 -index 000000000000..32e335f4b087 ---- /dev/null -+++ b/ext/standard/tests/crypt/bcrypt_salt_dollar.phpt -@@ -0,0 +1,82 @@ -+--TEST-- -+bcrypt correctly rejects salts containing $ -+--FILE-- -+<?php -+for ($i = 0; $i < 23; $i++) { -+ $salt = '$2y$04$' . str_repeat('0', $i) . '$'; -+ $result = crypt("foo", $salt); -+ var_dump($salt); -+ var_dump($result); -+ var_dump($result === $salt); -+} -+?> -+--EXPECT-- -+string(8) "$2y$04$$" -+string(2) "*0" -+bool(false) -+string(9) "$2y$04$0$" -+string(2) "*0" -+bool(false) -+string(10) "$2y$04$00$" -+string(2) "*0" -+bool(false) -+string(11) "$2y$04$000$" -+string(2) "*0" -+bool(false) -+string(12) "$2y$04$0000$" -+string(2) "*0" -+bool(false) -+string(13) "$2y$04$00000$" -+string(2) "*0" -+bool(false) -+string(14) "$2y$04$000000$" -+string(2) "*0" -+bool(false) -+string(15) "$2y$04$0000000$" -+string(2) "*0" -+bool(false) -+string(16) "$2y$04$00000000$" -+string(2) "*0" -+bool(false) -+string(17) "$2y$04$000000000$" -+string(2) "*0" -+bool(false) -+string(18) "$2y$04$0000000000$" -+string(2) "*0" -+bool(false) -+string(19) "$2y$04$00000000000$" -+string(2) "*0" -+bool(false) -+string(20) "$2y$04$000000000000$" -+string(2) "*0" -+bool(false) -+string(21) "$2y$04$0000000000000$" -+string(2) "*0" -+bool(false) -+string(22) "$2y$04$00000000000000$" -+string(2) "*0" -+bool(false) -+string(23) "$2y$04$000000000000000$" -+string(2) "*0" -+bool(false) -+string(24) "$2y$04$0000000000000000$" -+string(2) "*0" -+bool(false) -+string(25) "$2y$04$00000000000000000$" -+string(2) "*0" -+bool(false) -+string(26) "$2y$04$000000000000000000$" -+string(2) "*0" -+bool(false) -+string(27) "$2y$04$0000000000000000000$" -+string(2) "*0" -+bool(false) -+string(28) "$2y$04$00000000000000000000$" -+string(2) "*0" -+bool(false) -+string(29) "$2y$04$000000000000000000000$" -+string(2) "*0" -+bool(false) -+string(30) "$2y$04$0000000000000000000000$" -+string(60) "$2y$04$000000000000000000000u2a2UpVexIt9k3FMJeAVr3c04F5tcI8K" -+bool(false) +- free(php_cli_server_workers); ++ pefree(php_cli_server_workers, 1); + } + #endif + } /* }}} */
View file
php7-CVE-2023-0568.patch
Changed
@@ -1,26 +1,8 @@ -From ec10b28d64decbc54aa1e585dce580f0bd7a5953 Mon Sep 17 00:00:00 2001 -From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> -Date: Fri, 27 Jan 2023 19:28:27 +0100 -Subject: PATCH Fix array overrun when appending slash to paths - -Fix it by extending the array sizes by one character. As the input is -limited to the maximum path length, there will always be place to append -the slash. As the php_check_specific_open_basedir() simply uses the -strings to compare against each other, no new failures related to too -long paths are introduced. -We'll let the DOM and XML case handle a potentially too long path in the -library code. ---- - ext/dom/document.c | 2 +- - ext/xmlreader/php_xmlreader.c | 2 +- - main/fopen_wrappers.c | 6 +++--- - 3 files changed, 5 insertions(+), 5 deletions(-) - -diff --git a/ext/dom/document.c b/ext/dom/document.c -index dbbabb8bffde..fa6a6377ad5c 100644 ---- a/ext/dom/document.c -+++ b/ext/dom/document.c -@@ -1174,7 +1174,7 @@ static xmlDocPtr dom_document_parser(zval *id, int mode, char *source, size_t so +Index: php-7.4.33/ext/dom/document.c +=================================================================== +--- php-7.4.33.orig/ext/dom/document.c ++++ php-7.4.33/ext/dom/document.c +@@ -1379,7 +1379,7 @@ static xmlDocPtr dom_document_parser(zva int validate, recover, resolve_externals, keep_blanks, substitute_ent; int resolved_path_len; int old_error_reporting = 0; @@ -29,11 +11,11 @@ if (id != NULL) { intern = Z_DOMOBJ_P(id); -diff --git a/ext/xmlreader/php_xmlreader.c b/ext/xmlreader/php_xmlreader.c -index ecc52aa1d6f4..d8f8105010c7 100644 ---- a/ext/xmlreader/php_xmlreader.c -+++ b/ext/xmlreader/php_xmlreader.c -@@ -1024,7 +1024,7 @@ PHP_METHOD(XMLReader, XML) +Index: php-7.4.33/ext/xmlreader/php_xmlreader.c +=================================================================== +--- php-7.4.33.orig/ext/xmlreader/php_xmlreader.c ++++ php-7.4.33/ext/xmlreader/php_xmlreader.c +@@ -1038,7 +1038,7 @@ PHP_METHOD(xmlreader, XML) xmlreader_object *intern = NULL; char *source, *uri = NULL, *encoding = NULL; int resolved_path_len, ret = 0; @@ -42,11 +24,11 @@ xmlParserInputBufferPtr inputbfr; xmlTextReaderPtr reader; -diff --git a/main/fopen_wrappers.c b/main/fopen_wrappers.c -index 39a9c82d5984..5e4a619c8fe7 100644 ---- a/main/fopen_wrappers.c -+++ b/main/fopen_wrappers.c -@@ -129,10 +129,10 @@ PHPAPI ZEND_INI_MH(OnUpdateBaseDir) +Index: php-7.4.33/main/fopen_wrappers.c +=================================================================== +--- php-7.4.33.orig/main/fopen_wrappers.c ++++ php-7.4.33/main/fopen_wrappers.c +@@ -138,10 +138,10 @@ PHPAPI ZEND_INI_MH(OnUpdateBaseDir) */ PHPAPI int php_check_specific_open_basedir(const char *basedir, const char *path) {
View file
php7-CVE-2023-0662.patch
Changed
@@ -1,27 +1,10 @@ -From 716de0cff539f46294ef70fe75d548cd66766370 Mon Sep 17 00:00:00 2001 -From: Jakub Zelenka <bukka@php.net> -Date: Thu, 19 Jan 2023 14:31:25 +0000 -Subject: PATCH Introduce max_multipart_body_parts INI - -This fixes GHSA-54hq-v5wp-fqgv DOS vulnerabality by limitting number of -parsed multipart body parts as currently all parts were always parsed. ---- - main/main.c | 1 + - main/rfc1867.c | 11 ++ - ...-54hq-v5wp-fqgv-max-body-parts-custom.phpt | 53 +++++++++ - ...54hq-v5wp-fqgv-max-body-parts-default.phpt | 54 +++++++++ - .../ghsa-54hq-v5wp-fqgv-max-file-uploads.phpt | 52 +++++++++ - sapi/fpm/tests/tester.inc | 106 +++++++++++++++--- - 6 files changed, 262 insertions(+), 15 deletions(-) - create mode 100644 sapi/fpm/tests/ghsa-54hq-v5wp-fqgv-max-body-parts-custom.phpt - create mode 100644 sapi/fpm/tests/ghsa-54hq-v5wp-fqgv-max-body-parts-default.phpt - create mode 100644 sapi/fpm/tests/ghsa-54hq-v5wp-fqgv-max-file-uploads.phpt - -diff --git a/main/main.c b/main/main.c +iff --git a/main/main.c b/main/main.c index 40684f32dc14..c58ea58bf5ac 100644 ---- a/main/main.c -+++ b/main/main.c -@@ -751,6 +751,7 @@ PHP_INI_BEGIN() +Index: php-7.4.33/main/main.c +=================================================================== +--- php-7.4.33.orig/main/main.c ++++ php-7.4.33/main/main.c +@@ -836,6 +836,7 @@ PHP_INI_BEGIN() PHP_INI_ENTRY("disable_functions", "", PHP_INI_SYSTEM, NULL) PHP_INI_ENTRY("disable_classes", "", PHP_INI_SYSTEM, NULL) PHP_INI_ENTRY("max_file_uploads", "20", PHP_INI_SYSTEM|PHP_INI_PERDIR, NULL) @@ -29,11 +12,11 @@ STD_PHP_INI_BOOLEAN("allow_url_fopen", "1", PHP_INI_SYSTEM, OnUpdateBool, allow_url_fopen, php_core_globals, core_globals) STD_PHP_INI_BOOLEAN("allow_url_include", "0", PHP_INI_SYSTEM, OnUpdateBool, allow_url_include, php_core_globals, core_globals) -diff --git a/main/rfc1867.c b/main/rfc1867.c -index b43cfae5a1e2..3086e8da3dbe 100644 ---- a/main/rfc1867.c -+++ b/main/rfc1867.c -@@ -687,6 +687,7 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */ +Index: php-7.4.33/main/rfc1867.c +=================================================================== +--- php-7.4.33.orig/main/rfc1867.c ++++ php-7.4.33/main/rfc1867.c +@@ -694,6 +694,7 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_ void *event_extra_data = NULL; unsigned int llen = 0; int upload_cnt = INI_INT("max_file_uploads"); @@ -41,7 +24,7 @@ const zend_encoding *internal_encoding = zend_multibyte_get_internal_encoding(); php_rfc1867_getword_t getword; php_rfc1867_getword_conf_t getword_conf; -@@ -708,6 +709,11 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */ +@@ -715,6 +716,11 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_ return; } @@ -53,7 +36,7 @@ /* Get the boundary */ boundary = strstr(content_type_dup, "boundary"); if (!boundary) { -@@ -792,6 +798,11 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */ +@@ -799,6 +805,11 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_ char *pair = NULL; int end = 0; @@ -65,331 +48,3 @@ while (isspace(*cd)) { ++cd; } -diff --git a/sapi/fpm/tests/ghsa-54hq-v5wp-fqgv-max-body-parts-custom.phpt b/sapi/fpm/tests/ghsa-54hq-v5wp-fqgv-max-body-parts-custom.phpt -new file mode 100644 -index 000000000000..d2239ac3c410 ---- /dev/null -+++ b/sapi/fpm/tests/ghsa-54hq-v5wp-fqgv-max-body-parts-custom.phpt -@@ -0,0 +1,53 @@ -+--TEST-- -+FPM: GHSA-54hq-v5wp-fqgv - max_multipart_body_parts ini custom value -+--SKIPIF-- -+<?php include "skipif.inc"; ?> -+--FILE-- -+<?php -+ -+require_once "tester.inc"; -+ -+$cfg = <<<EOT -+global -+error_log = {{FILE:LOG}} -+unconfined -+listen = {{ADDR}} -+pm = dynamic -+pm.max_children = 5 -+pm.start_servers = 1 -+pm.min_spare_servers = 1 -+pm.max_spare_servers = 3 -+php_admin_valuehtml_errors = false -+php_admin_valuemax_input_vars = 20 -+php_admin_valuemax_file_uploads = 5 -+php_admin_valuemax_multipart_body_parts = 10 -+php_flagdisplay_errors = On -+EOT; -+ -+$code = <<<EOT -+<?php -+var_dump(count(\$_POST)); -+EOT; -+ -+$tester = new FPM\Tester($cfg, $code); -+$tester->start(); -+$tester->expectLogStartNotices(); -+echo $tester -+ ->request(stdin: -+ 'parts' => -+ 'count' => 30, -+ -+ ) -+ ->getBody(); -+$tester->terminate(); -+$tester->close(); -+ -+?> -+--EXPECT-- -+Warning: Unknown: Multipart body parts limit exceeded 10. To increase the limit change max_multipart_body_parts in php.ini. in Unknown on line 0 -+int(10) -+--CLEAN-- -+<?php -+require_once "tester.inc"; -+FPM\Tester::clean(); -+?> -diff --git a/sapi/fpm/tests/ghsa-54hq-v5wp-fqgv-max-body-parts-default.phpt b/sapi/fpm/tests/ghsa-54hq-v5wp-fqgv-max-body-parts-default.phpt -new file mode 100644 -index 000000000000..42b5afbf9ee7 ---- /dev/null -+++ b/sapi/fpm/tests/ghsa-54hq-v5wp-fqgv-max-body-parts-default.phpt -@@ -0,0 +1,54 @@ -+--TEST-- -+FPM: GHSA-54hq-v5wp-fqgv - max_multipart_body_parts ini default -+--SKIPIF-- -+<?php include "skipif.inc"; ?> -+--FILE-- -+<?php -+ -+require_once "tester.inc"; -+ -+$cfg = <<<EOT -+global -+error_log = {{FILE:LOG}} -+unconfined -+listen = {{ADDR}} -+pm = dynamic -+pm.max_children = 5 -+pm.start_servers = 1 -+pm.min_spare_servers = 1 -+pm.max_spare_servers = 3 -+php_admin_valuehtml_errors = false -+php_admin_valuemax_input_vars = 20 -+php_admin_valuemax_file_uploads = 5 -+php_flagdisplay_errors = On -+EOT; -+ -+$code = <<<EOT -+<?php -+var_dump(count(\$_POST)); -+EOT; -+ -+$tester = new FPM\Tester($cfg, $code); -+$tester->start(); -+$tester->expectLogStartNotices(); -+echo $tester -+ ->request(stdin: -+ 'parts' => -+ 'count' => 30, -+ -+ ) -+ ->getBody(); -+$tester->terminate(); -+$tester->close(); -+ -+?> -+--EXPECT-- -+Warning: Unknown: Input variables exceeded 20. To increase the limit change max_input_vars in php.ini. in Unknown on line 0 -+ -+Warning: Unknown: Multipart body parts limit exceeded 25. To increase the limit change max_multipart_body_parts in php.ini. in Unknown on line 0 -+int(20) -+--CLEAN-- -+<?php -+require_once "tester.inc"; -+FPM\Tester::clean(); -+?> -diff --git a/sapi/fpm/tests/ghsa-54hq-v5wp-fqgv-max-file-uploads.phpt b/sapi/fpm/tests/ghsa-54hq-v5wp-fqgv-max-file-uploads.phpt -new file mode 100644 -index 000000000000..da81174c7280 ---- /dev/null -+++ b/sapi/fpm/tests/ghsa-54hq-v5wp-fqgv-max-file-uploads.phpt -@@ -0,0 +1,52 @@ -+--TEST-- -+FPM: GHSA-54hq-v5wp-fqgv - exceeding max_file_uploads -+--SKIPIF-- -+<?php include "skipif.inc"; ?> -+--FILE-- -+<?php -+ -+require_once "tester.inc"; -+ -+$cfg = <<<EOT -+global -+error_log = {{FILE:LOG}} -+unconfined -+listen = {{ADDR}} -+pm = dynamic -+pm.max_children = 5 -+pm.start_servers = 1 -+pm.min_spare_servers = 1 -+pm.max_spare_servers = 3 -+php_admin_valuehtml_errors = false -+php_admin_valuemax_file_uploads = 5 -+php_flagdisplay_errors = On -+EOT; -+ -+$code = <<<EOT -+<?php -+var_dump(count(\$_FILES)); -+EOT; -+ -+$tester = new FPM\Tester($cfg, $code); -+$tester->start(); -+$tester->expectLogStartNotices(); -+echo $tester -+ ->request(stdin: -+ 'parts' => -+ 'count' => 10, -+ 'param' => 'filename' -+ -+ ) -+ ->getBody(); -+$tester->terminate(); -+$tester->close(); -+ -+?> -+--EXPECT-- -+Warning: Maximum number of allowable file uploads has been exceeded in Unknown on line 0 -+int(5) -+--CLEAN-- -+<?php -+require_once "tester.inc"; -+FPM\Tester::clean(); -+?> -diff --git a/sapi/fpm/tests/tester.inc b/sapi/fpm/tests/tester.inc -index 6197cdba53f5..e51aa0f69143 100644 ---- a/sapi/fpm/tests/tester.inc -+++ b/sapi/fpm/tests/tester.inc -@@ -531,12 +531,16 @@ class Tester - * @param string|null $successMessage - * @param string|null $errorMessage - * @param bool $connKeepAlive -+ * @param string|null $scriptFilename -+ * @param string|null $stdin - * @return array - */ - private function getRequestParams( - string $query = '', - array $headers = , -- string $uri = null -+ string $uri = null, -+ string $scriptFilename = null, -+ ?string $stdin = null - ) { - if (is_null($uri)) { - $uri = $this->makeSourceFile(); -@@ -545,8 +549,8 @@ class Tester - $params = array_merge( - - 'GATEWAY_INTERFACE' => 'FastCGI/1.0', -- 'REQUEST_METHOD' => 'GET', -- 'SCRIPT_FILENAME' => $uri, -+ 'REQUEST_METHOD' => is_null($stdin) ? 'GET' : 'POST', -+ 'SCRIPT_FILENAME' => $scriptFilename ?: $uri, - 'SCRIPT_NAME' => $uri, - 'QUERY_STRING' => $query, - 'REQUEST_URI' => $uri . ($query ? '?'.$query : ""), -@@ -560,7 +564,7 @@ class Tester - 'SERVER_PROTOCOL' => 'HTTP/1.1', - 'DOCUMENT_ROOT' => __DIR__, - 'CONTENT_TYPE' => '', -- 'CONTENT_LENGTH' => 0 -+ 'CONTENT_LENGTH' => strlen($stdin ?? "") // Default to 0 - , - $headers - ); -@@ -571,6 +575,69 @@ class Tester - } - - /** -+ * Parse stdin and generate data for multipart config. -+ * -+ * @param array $stdin -+ * @param array $headers -+ * -+ * @return void -+ * @throws \Exception -+ */ -+ private function parseStdin(array $stdin, array &$headers) -+ { -+ $parts = $stdin'parts' ?? null; -+ if (empty($parts)) { -+ throw new \Exception('The stdin array needs to contain parts'); -+ } -+ $boundary = $stdin'boundary' ?? 'AaB03x'; -+ if ( ! isset($headers'CONTENT_TYPE')) { -+ $headers'CONTENT_TYPE' = 'multipart/form-data; boundary=' . $boundary; -+ } -+ $count = $parts'count' ?? null; -+ if ( ! is_null($count)) { -+ $dispositionType = $parts'disposition' ?? 'form-data'; -+ $dispositionParam = $parts'param' ?? 'name'; -+ $namePrefix = $parts'prefix' ?? 'f'; -+ $nameSuffix = $parts'suffix' ?? ''; -+ $value = $parts'value' ?? 'test'; -+ $parts = ; -+ for ($i = 0; $i < $count; $i++) { -+ $parts = -+ 'disposition' => $dispositionType, -+ 'param' => $dispositionParam, -+ 'name' => "$namePrefix$i$nameSuffix", -+ 'value' => $value -+ ; -+ } -+ } -+ $out = ''; -+ $nl = "\r\n"; -+ foreach ($parts as $part) { -+ if (!is_array($part)) { -+ $part = 'name' => $part; -+ } elseif ( ! isset($part'name')) { -+ throw new \Exception('Each part has to have a name'); -+ } -+ $name = $part'name'; -+ $dispositionType = $part'disposition' ?? 'form-data'; -+ $dispositionParam = $part'param' ?? 'name'; -+ $value = $part'value' ?? 'test'; -+ $partHeaders = $part'headers' ?? ; -+ -+ $out .= "--$boundary$nl"; -+ $out .= "Content-disposition: $dispositionType; $dispositionParam=\"$name\"$nl"; -+ foreach ($partHeaders as $headerName => $headerValue) { -+ $out .= "$headerName: $headerValue$nl"; -+ } -+ $out .= $nl; -+ $out .= "$value$nl"; -+ } -+ $out .= "--$boundary--$nl"; -+ -+ return $out; -+ } -+ -+ /** - * Execute request. - * - * @param string $query -@@ -580,7 +647,10 @@ class Tester - * @param string|null $successMessage - * @param string|null $errorMessage - * @param bool $connKeepAlive -+ * @param string|null $scriptFilename = null -+ * @param string|array|null $stdin = null - * @return Response -+ * @throws \Exception - */ - public function request( - string $query = '', -@@ -589,17 +659,24 @@ class Tester - string $address = null, - string $successMessage = null, - string $errorMessage = null, -- bool $connKeepAlive = false -+ bool $connKeepAlive = false, -+ string $scriptFilename = null, -+ string|array $stdin = null - ) { - if ($this->hasError()) { - return new Response(null, true); - } - -- $params = $this->getRequestParams($query, $headers, $uri); -+ if (is_array($stdin)) { -+ $stdin = $this->parseStdin($stdin, $headers); -+ } -+ -+ $params = $this->getRequestParams($query, $headers, $uri, $scriptFilename, $stdin); -+ $this->trace('Request params', $params); - - try { - $this->response = new Response( -- $this->getClient($address, $connKeepAlive)->request_data($params, false) -+ $this->getClient($address, $connKeepAlive)->request_data($params, $stdin) - ); - $this->message($successMessage); - } catch (\Exception $exception) {
View file
php7-CVE-2023-0567-b.patch -> php7-CVE-2024-11233.patch
Changed
@@ -1,37 +1,31 @@ -From a92acbad873a05470af1a47cb785a18eadd827b5 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= <tim@bastelstu.be> -Date: Mon, 23 Jan 2023 22:13:57 +0100 -Subject: PATCH crypt: Fix possible buffer overread in php_crypt() - ---- - ext/standard/crypt.c | 1 + - ext/standard/tests/password/password_bcrypt_short.phpt | 8 ++++++++ - 2 files changed, 9 insertions(+) - create mode 100644 ext/standard/tests/password/password_bcrypt_short.phpt - -diff --git a/ext/standard/crypt.c b/ext/standard/crypt.c -index 8c105cf910e8..8316c8b96063 100644 ---- a/ext/standard/crypt.c -+++ b/ext/standard/crypt.c -@@ -135,6 +135,7 @@ PHPAPI zend_string *php_crypt(const char *password, const int pass_len, const ch - } else if ( - salt0 == '$' && - salt1 == '2' && -+ salt2 != 0 && - salt3 == '$') { - char outputPHP_MAX_SALT_LEN + 1; +Index: php-7.4.33/ext/standard/filters.c +=================================================================== +--- php-7.4.33.orig/ext/standard/filters.c ++++ php-7.4.33/ext/standard/filters.c +@@ -1128,6 +1128,9 @@ static php_conv_err_t php_conv_qprint_de + } break; + + case 5: { ++ if (icnt == 0) { ++ goto out; ++ } + if (!inst->lbchars && lb_cnt == 1 && *ps == '\n') { + /* auto-detect soft line breaks, found network line break */ + lb_cnt = lb_ptr = 0; +@@ -1141,15 +1144,13 @@ static php_conv_err_t php_conv_qprint_de + /* soft line break */ + lb_cnt = lb_ptr = 0; + scan_stat = 0; +- } else if (icnt > 0) { ++ } else { + if (*ps == (unsigned char)inst->lbcharslb_cnt) { + lb_cnt++; + ps++, icnt--; + } else { + scan_stat = 6; /* no break for short-cut */ + } +- } else { +- goto out; + } + } break; -diff --git a/ext/standard/tests/password/password_bcrypt_short.phpt b/ext/standard/tests/password/password_bcrypt_short.phpt -new file mode 100644 -index 000000000000..085bc8a23904 ---- /dev/null -+++ b/ext/standard/tests/password/password_bcrypt_short.phpt -@@ -0,0 +1,8 @@ -+--TEST-- -+Test that password_hash() does not overread buffers when a short hash is passed -+--FILE-- -+<?php -+var_dump(password_verify("foo", '$2')); -+?> -+--EXPECT-- -+bool(false)
View file
php7-CVE-2024-11234.patch
Added
@@ -0,0 +1,54 @@ +From 426a6d4539ebee34879ac5de857036bb6ff0e732 Mon Sep 17 00:00:00 2001 +From: Jakub Zelenka <bukka@php.net> +Date: Fri, 8 Nov 2024 23:43:47 +0100 +Subject: PATCH Fix GHSA-c5f2-jwm7-mmq2: stream HTTP fulluri CRLF injection + +--- + ext/standard/http_fopen_wrapper.c | 18 ++++++++---- + .../tests/http/ghsa-c5f2-jwm7-mmq2.phpt | 28 +++++++++++++++++++ + 2 files changed, 40 insertions(+), 6 deletions(-) + create mode 100644 ext/standard/tests/http/ghsa-c5f2-jwm7-mmq2.phpt + +Index: php-7.4.33/ext/standard/http_fopen_wrapper.c +=================================================================== +--- php-7.4.33.orig/ext/standard/http_fopen_wrapper.c ++++ php-7.4.33/ext/standard/http_fopen_wrapper.c +@@ -186,6 +186,11 @@ static php_stream *php_stream_url_wrap_h + return NULL; + } + ++ /* Should we send the entire path in the request line, default to no. */ ++ if (context && (tmpzval = php_stream_context_get_option(context, "http", "request_fulluri")) != NULL) { ++ request_fulluri = zend_is_true(tmpzval); ++ } ++ + use_ssl = resource->scheme && (ZSTR_LEN(resource->scheme) > 4) && ZSTR_VAL(resource->scheme)4 == 's'; + /* choose default ports */ + if (use_ssl && resource->port == 0) +@@ -205,6 +210,13 @@ static php_stream *php_stream_url_wrap_h + } + } + ++ if (request_fulluri && (strchr(path, '\n') != NULL || strchr(path, '\r') != NULL)) { ++ php_stream_wrapper_log_error(wrapper, options, "HTTP wrapper full URI path does not allow CR or LF characters"); ++ php_url_free(resource); ++ zend_string_release(transport_string); ++ return NULL; ++ } ++ + if (context && (tmpzval = php_stream_context_get_option(context, wrapper->wops->label, "timeout")) != NULL) { + double d = zval_get_double(tmpzval); + #ifndef PHP_WIN32 +@@ -385,12 +397,6 @@ finish: + smart_str_appends(&req_buf, "GET "); + } + +- /* Should we send the entire path in the request line, default to no. */ +- if (!request_fulluri && context && +- (tmpzval = php_stream_context_get_option(context, "http", "request_fulluri")) != NULL) { +- request_fulluri = zend_is_true(tmpzval); +- } +- + if (request_fulluri) { + /* Ask for everything */ + smart_str_appends(&req_buf, path);
View file
php7-CVE-2024-11235.patch
Added
@@ -0,0 +1,19 @@ +Index: php-7.4.33/Zend/zend_opcode.c +=================================================================== +--- php-7.4.33.orig/Zend/zend_opcode.c ++++ php-7.4.33/Zend/zend_opcode.c +@@ -780,6 +780,14 @@ static void zend_calc_live_ranges( + opnum--; + opline--; + ++ /* SEPARATE always redeclares its op1. For the purposes of live-ranges, ++ * its declaration is irrelevant. Don't terminate the current live-range ++ * to avoid breaking special handling of COPY_TMP. */ ++ if (opline->opcode == ZEND_SEPARATE) { ++ ZEND_ASSERT(opline->op1.var == opline->result.var); ++ continue; ++ } ++ + if ((opline->result_type & (IS_TMP_VAR|IS_VAR)) && !is_fake_def(opline)) { + uint32_t var_num = EX_VAR_TO_NUM(opline->result.var) - var_offset; + /* Defs without uses can occur for two reasons: Either because the result is
View file
php7-CVE-2024-8925.patch
Added
@@ -0,0 +1,18 @@ +Index: php-7.4.33/main/rfc1867.c +=================================================================== +--- php-7.4.33.orig/main/rfc1867.c ++++ php-7.4.33/main/rfc1867.c +@@ -759,6 +759,13 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_ + boundary_len = boundary_end-boundary; + } + ++ /* Boundaries larger than FILLUNIT-strlen("\r\n--") characters lead to ++ * erroneous parsing */ ++ if (boundary_len > FILLUNIT-strlen("\r\n--")) { ++ sapi_module.sapi_error(E_WARNING, "Boundary too large in multipart/form-data POST data"); ++ return; ++ } ++ + /* Initialize the buffer */ + if (!(mbuff = multipart_buffer_new(boundary, boundary_len))) { + sapi_module.sapi_error(E_WARNING, "Unable to initialize the input buffer");
View file
php7-CVE-2024-8927.patch
Added
@@ -0,0 +1,34 @@ +Index: php-7.4.33/sapi/cgi/cgi_main.c +=================================================================== +--- php-7.4.33.orig/sapi/cgi/cgi_main.c ++++ php-7.4.33/sapi/cgi/cgi_main.c +@@ -1928,18 +1928,17 @@ int main(int argc, char *argv) + + /* check force_cgi after startup, so we have proper output */ + if (cgi && CGIG(force_redirect)) { +- /* Apache will generate REDIRECT_STATUS, +- * Netscape and redirect.so will generate HTTP_REDIRECT_STATUS. +- * redirect.so and installation instructions available from +- * http://www.koehntopp.de/php. +- * -- kk@netuse.de +- */ +- if (!getenv("REDIRECT_STATUS") && +- !getenv ("HTTP_REDIRECT_STATUS") && +- /* this is to allow a different env var to be configured +- * in case some server does something different than above */ +- (!CGIG(redirect_status_env) || !getenv(CGIG(redirect_status_env))) +- ) { ++ /* This is to allow a different environment variable to be configured ++ * in case the we cannot auto-detect which environment variable to use. ++ * Checking this first to allow user overrides in case the environment ++ * variable can be set by an untrusted party. */ ++ const char *redirect_status_env = CGIG(redirect_status_env); ++ if (!redirect_status_env) { ++ /* Apache will generate REDIRECT_STATUS. */ ++ redirect_status_env = "REDIRECT_STATUS"; ++ } ++ ++ if (!getenv(redirect_status_env)) { + zend_try { + SG(sapi_headers).http_response_code = 400; + PUTS("<b>Security Alert!</b> The PHP CGI cannot be accessed directly.\n\n\
View file
php7-CVE-2024-8929.patch
Added
@@ -0,0 +1,283 @@ +Index: php-7.4.33/ext/mysqlnd/mysqlnd_ps_codec.c +=================================================================== +--- php-7.4.33.orig/ext/mysqlnd/mysqlnd_ps_codec.c ++++ php-7.4.33/ext/mysqlnd/mysqlnd_ps_codec.c +@@ -52,11 +52,45 @@ struct st_mysqlnd_perm_bind mysqlnd_ps_f + #define MYSQLND_PS_SKIP_RESULT_W_LEN -1 + #define MYSQLND_PS_SKIP_RESULT_STR -2 + ++static inline void ps_fetch_over_read_error(const zend_uchar ** row) ++{ ++ php_error_docref(NULL, E_WARNING, "Malformed server packet. Field length pointing after the end of packet"); ++ *row = NULL; ++} ++ ++static inline int ps_fetch_is_packet_over_read_with_variable_length(const unsigned int pack_len, ++ const zend_uchar ** row, const zend_uchar *p, unsigned int length) ++{ ++ if (pack_len == 0) { ++ return 0; ++ } ++ size_t length_len = *row - p; ++ if (length_len > pack_len || length > pack_len - length_len) { ++ ps_fetch_over_read_error(row); ++ return 1; ++ } ++ return 0; ++} ++ ++static inline int ps_fetch_is_packet_over_read_with_static_length(const unsigned int pack_len, ++ const zend_uchar ** row, unsigned int length) ++{ ++ if (pack_len > 0 && length > pack_len) { ++ ps_fetch_over_read_error(row); ++ return 1; ++ } ++ return 0; ++} ++ + /* {{{ ps_fetch_from_1_to_8_bytes */ + void + ps_fetch_from_1_to_8_bytes(zval * zv, const MYSQLND_FIELD * const field, const unsigned int pack_len, + const zend_uchar ** row, unsigned int byte_count) + { ++ if (UNEXPECTED(ps_fetch_is_packet_over_read_with_static_length(pack_len, row, byte_count))) { ++ return; ++ } ++ + char tmp22; + size_t tmp_len = 0; + zend_bool is_bit = field->type == MYSQL_TYPE_BIT; +@@ -178,6 +212,11 @@ ps_fetch_float(zval * zv, const MYSQLND_ + float fval; + double dval; + DBG_ENTER("ps_fetch_float"); ++ ++ if (UNEXPECTED(ps_fetch_is_packet_over_read_with_static_length(pack_len, row, 4))) { ++ return; ++ } ++ + float4get(fval, *row); + (*row)+= 4; + DBG_INF_FMT("value=%f", fval); +@@ -200,6 +239,11 @@ ps_fetch_double(zval * zv, const MYSQLND + { + double value; + DBG_ENTER("ps_fetch_double"); ++ ++ if (UNEXPECTED(ps_fetch_is_packet_over_read_with_static_length(pack_len, row, 8))) { ++ return; ++ } ++ + float8get(value, *row); + ZVAL_DOUBLE(zv, value); + (*row)+= 8; +@@ -216,9 +260,14 @@ ps_fetch_time(zval * zv, const MYSQLND_F + struct st_mysqlnd_time t; + zend_ulong length; /* First byte encodes the length*/ + char * value; ++ const zend_uchar *p = *row; + DBG_ENTER("ps_fetch_time"); + + if ((length = php_mysqlnd_net_field_length(row))) { ++ if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) { ++ return; ++ } ++ + const zend_uchar * to = *row; + + t.time_type = MYSQLND_TIMESTAMP_TIME; +@@ -273,9 +322,14 @@ ps_fetch_date(zval * zv, const MYSQLND_F + struct st_mysqlnd_time t = {0}; + zend_ulong length; /* First byte encodes the length*/ + char * value; ++ const zend_uchar *p = *row; + DBG_ENTER("ps_fetch_date"); + + if ((length = php_mysqlnd_net_field_length(row))) { ++ if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) { ++ return; ++ } ++ + const zend_uchar * to = *row; + + t.time_type = MYSQLND_TIMESTAMP_DATE; +@@ -310,9 +364,14 @@ ps_fetch_datetime(zval * zv, const MYSQL + struct st_mysqlnd_time t; + zend_ulong length; /* First byte encodes the length*/ + char * value; ++ const zend_uchar *p = *row; + DBG_ENTER("ps_fetch_datetime"); + + if ((length = php_mysqlnd_net_field_length(row))) { ++ if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) { ++ return; ++ } ++ + const zend_uchar * to = *row; + + t.time_type = MYSQLND_TIMESTAMP_DATETIME; +@@ -371,7 +430,11 @@ ps_fetch_string(zval * zv, const MYSQLND + For now just copy, before we make it possible + to write \0 to the row buffer + */ ++ const zend_uchar *p = *row; + const zend_ulong length = php_mysqlnd_net_field_length(row); ++ if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) { ++ return; ++ } + DBG_ENTER("ps_fetch_string"); + DBG_INF_FMT("len = %lu", length); + DBG_INF("copying from the row buffer"); +@@ -387,7 +450,11 @@ ps_fetch_string(zval * zv, const MYSQLND + static void + ps_fetch_bit(zval * zv, const MYSQLND_FIELD * const field, const unsigned int pack_len, const zend_uchar ** row) + { ++ const zend_uchar *p = *row; + const zend_ulong length = php_mysqlnd_net_field_length(row); ++ if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) { ++ return; ++ } + ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, length); + } + /* }}} */ +Index: php-7.4.33/ext/mysqlnd/mysqlnd_result.c +=================================================================== +--- php-7.4.33.orig/ext/mysqlnd/mysqlnd_result.c ++++ php-7.4.33/ext/mysqlnd/mysqlnd_result.c +@@ -505,7 +505,7 @@ mysqlnd_query_read_result_set_header(MYS + if (FAIL == (ret = result->m.read_result_metadata(result, conn))) { + /* For PS, we leave them in Prepared state */ + if (!stmt && conn->current_result) { +- mnd_efree(conn->current_result); ++ conn->current_result->m.free_result(conn->current_result, TRUE); + conn->current_result = NULL; + } + DBG_ERR("Error occurred while reading metadata"); +Index: php-7.4.33/ext/mysqlnd/mysqlnd_wireprotocol.c +=================================================================== +--- php-7.4.33.orig/ext/mysqlnd/mysqlnd_wireprotocol.c ++++ php-7.4.33/ext/mysqlnd/mysqlnd_wireprotocol.c +@@ -715,7 +715,14 @@ php_mysqlnd_auth_response_read(MYSQLND_C + + /* There is a message */ + if (packet->header.size > (size_t) (p - buf) && (net_len = php_mysqlnd_net_field_length(&p))) { +- packet->message_len = MIN(net_len, buf_len - (p - begin)); ++ /* p can get past packet size when getting field length so it needs to be checked first ++ * and after that it can be checked that the net_len is not greater than the packet size */ ++ if ((p - buf) > packet->header.size || packet->header.size - (p - buf) < net_len) { ++ DBG_ERR_FMT("OK packet message length is past the packet size"); ++ php_error_docref(NULL, E_WARNING, "OK packet message length is past the packet size"); ++ DBG_RETURN(FAIL); ++ } ++ packet->message_len = net_len; + packet->message = mnd_pestrndup((char *)p, packet->message_len, FALSE); + } else { + packet->message = NULL; +@@ -1113,6 +1120,17 @@ php_mysqlnd_rset_header_read(MYSQLND_CON + BAIL_IF_NO_MORE_DATA; + /* Check for additional textual data */ + if (packet->header.size > (size_t) (p - buf) && (len = php_mysqlnd_net_field_length(&p))) { ++ /* p can get past packet size when getting field length so it needs to be checked first ++ * and after that it can be checked that the len is not greater than the packet size */ ++ if ((p - buf) > packet->header.size || packet->header.size - (p - buf) < len) { ++ size_t local_file_name_over_read = ((p - buf) - packet->header.size) + len; ++ DBG_ERR_FMT("RSET_HEADER packet additional data length is past %zu bytes the packet size", ++ local_file_name_over_read); ++ php_error_docref(NULL, E_WARNING, ++ "RSET_HEADER packet additional data length is past %zu bytes the packet size", ++ local_file_name_over_read); ++ DBG_RETURN(FAIL); ++ } + packet->info_or_local_file.s = mnd_emalloc(len + 1); + if (packet->info_or_local_file.s) { + memcpy(packet->info_or_local_file.s, p, len); +@@ -1272,22 +1290,16 @@ php_mysqlnd_rset_field_read(MYSQLND_CONN + } + + +- /* +- def could be empty, thus don't allocate on the root. +- NULL_LENGTH (0xFB) comes from COM_FIELD_LIST when the default value is NULL. +- Otherwise the string is length encoded. +- */ ++ /* COM_FIELD_LIST is no longer supported so def should not be present */ + if (packet->header.size > (size_t) (p - buf) && + (len = php_mysqlnd_net_field_length(&p)) && + len != MYSQLND_NULL_LENGTH) + { +- BAIL_IF_NO_MORE_DATA; +- DBG_INF_FMT("Def found, length %lu", len); +- meta->def = packet->memory_pool->get_chunk(packet->memory_pool, len + 1); +- memcpy(meta->def, p, len); +- meta->deflen = '\0'; +- meta->def_length = len; +- p += len; ++ DBG_ERR_FMT("Protocol error. Server sent default for unsupported field list"); ++ php_error_docref(NULL, E_WARNING, ++ "Protocol error. Server sent default for unsupported field list (mysqlnd_wireprotocol.c:%u)", ++ __LINE__); ++ DBG_RETURN(FAIL); + } + + root_ptr = meta->root = packet->memory_pool->get_chunk(packet->memory_pool, total_len); +@@ -1462,8 +1474,10 @@ php_mysqlnd_rowp_read_binary_protocol(MY + const unsigned int field_count, const MYSQLND_FIELD * const fields_metadata, + const zend_bool as_int_or_float, MYSQLND_STATS * const stats) + { +- unsigned int i; +- const zend_uchar * p = row_buffer->ptr; ++ unsigned int i, j; ++ size_t rbs = row_buffer->size; ++ const zend_uchar * rbp = row_buffer->ptr; ++ const zend_uchar * p = rbp; + const zend_uchar * null_ptr; + zend_uchar bit; + zval *current_field, *end_field, *start_field; +@@ -1496,7 +1510,21 @@ php_mysqlnd_rowp_read_binary_protocol(MY + statistic = STAT_BINARY_TYPE_FETCHED_NULL; + } else { + enum_mysqlnd_field_types type = fields_metadatai.type; +- mysqlnd_ps_fetch_functionstype.func(current_field, &fields_metadatai, 0, &p); ++ size_t row_position = p - rbp; ++ if (rbs <= row_position) { ++ for (j = 0, current_field = start_field; j < i; current_field++, j++) { ++ zval_ptr_dtor(current_field); ++ } ++ php_error_docref(NULL, E_WARNING, "Malformed server packet. No packet space left for the field"); ++ DBG_RETURN(FAIL); ++ } ++ mysqlnd_ps_fetch_functionstype.func(current_field, &fields_metadatai, rbs - row_position, &p); ++ if (p == NULL) { ++ for (j = 0, current_field = start_field; j < i; current_field++, j++) { ++ zval_ptr_dtor(current_field); ++ } ++ DBG_RETURN(FAIL); ++ } + + if (MYSQLND_G(collect_statistics)) { + switch (fields_metadatai.type) { +@@ -1553,7 +1581,7 @@ php_mysqlnd_rowp_read_text_protocol_aux( + unsigned int field_count, const MYSQLND_FIELD * fields_metadata, + zend_bool as_int_or_float, MYSQLND_STATS * stats) + { +- unsigned int i; ++ unsigned int i, j; + zval *current_field, *end_field, *start_field; + zend_uchar * p = row_buffer->ptr; + const size_t data_size = row_buffer->size; +@@ -1574,9 +1602,11 @@ php_mysqlnd_rowp_read_text_protocol_aux( + /* NULL or NOT NULL, this is the question! */ + if (len == MYSQLND_NULL_LENGTH) { + ZVAL_NULL(current_field); +- } else if ((p + len) > packet_end) { +- php_error_docref(NULL, E_WARNING, "Malformed server packet. Field length pointing "MYSQLND_SZ_T_SPEC +- " bytes after end of packet", (p + len) - packet_end - 1); ++ } else if (p > packet_end || len > packet_end - p) { ++ php_error_docref(NULL, E_WARNING, "Malformed server packet. Field length pointing after end of packet"); ++ for (j = 0, current_field = start_field; j < i; current_field++, j++) { ++ zval_ptr_dtor(current_field); ++ } + DBG_RETURN(FAIL); + } else { + #if defined(MYSQLND_STRING_TO_INT_CONVERSION)
View file
php7-CVE-2024-9026.patch
Added
@@ -0,0 +1,13 @@ +Index: php-7.4.33/sapi/fpm/fpm/fpm_stdio.c +=================================================================== +--- php-7.4.33.orig/sapi/fpm/fpm/fpm_stdio.c ++++ php-7.4.33/sapi/fpm/fpm/fpm_stdio.c +@@ -177,7 +177,7 @@ stdio_read: + if ((sizeof(FPM_STDIO_CMD_FLUSH) - cmd_pos) <= in_buf && + !memcmp(buf, &FPM_STDIO_CMD_FLUSHcmd_pos, sizeof(FPM_STDIO_CMD_FLUSH) - cmd_pos)) { + zlog_stream_finish(log_stream); +- start = cmd_pos; ++ start = sizeof(FPM_STDIO_CMD_FLUSH) - cmd_pos; + } else { + zlog_stream_str(log_stream, &FPM_STDIO_CMD_FLUSH0, cmd_pos); + }
View file
php7-CVE-2025-1217.patch
Added
@@ -0,0 +1,483 @@ +Index: php-7.4.33/ext/standard/http_fopen_wrapper.c +=================================================================== +--- php-7.4.33.orig/ext/standard/http_fopen_wrapper.c ++++ php-7.4.33/ext/standard/http_fopen_wrapper.c +@@ -30,6 +30,7 @@ + + #include <stdio.h> + #include <stdlib.h> ++#include <stdbool.h> + #include <errno.h> + #include <sys/types.h> + #include <sys/stat.h> +@@ -82,6 +83,22 @@ + #define HTTP_WRAPPER_HEADER_INIT 1 + #define HTTP_WRAPPER_REDIRECTED 2 + ++zend_string *zend_string_concat3( ++ const char *str1, size_t str1_len, ++ const char *str2, size_t str2_len, ++ const char *str3, size_t str3_len) ++{ ++ size_t len = str1_len + str2_len + str3_len; ++ zend_string *res = zend_string_alloc(len, 0); ++ ++ memcpy(ZSTR_VAL(res), str1, str1_len); ++ memcpy(ZSTR_VAL(res) + str1_len, str2, str2_len); ++ memcpy(ZSTR_VAL(res) + str1_len + str2_len, str3, str3_len); ++ ZSTR_VAL(res)len = '\0'; ++ ++ return res; ++} ++ + static inline void strip_header(char *header_bag, char *lc_header_bag, + const char *lc_header_name) + { +@@ -116,6 +133,171 @@ static zend_bool check_has_header(const + return 0; + } + ++typedef struct _php_stream_http_response_header_info { ++ php_stream_filter *transfer_encoding; ++ size_t file_size; ++ bool follow_location; ++ char locationHTTP_HEADER_BLOCK_SIZE; ++} php_stream_http_response_header_info; ++ ++static void php_stream_http_response_header_info_init( ++ php_stream_http_response_header_info *header_info) ++{ ++ header_info->transfer_encoding = NULL; ++ header_info->file_size = 0; ++ header_info->follow_location = 1; ++ header_info->location0 = '\0'; ++} ++ ++/* Trim white spaces from response header line and update its length */ ++static bool php_stream_http_response_header_trim(char *http_header_line, ++ size_t *http_header_line_length) ++{ ++ char *http_header_line_end = http_header_line + *http_header_line_length - 1; ++ while (http_header_line_end >= http_header_line && ++ (*http_header_line_end == '\n' || *http_header_line_end == '\r')) { ++ http_header_line_end--; ++ } ++ ++ /* The primary definition of an HTTP header in RFC 7230 states: ++ * > Each header field consists of a case-insensitive field name followed ++ * > by a colon (":"), optional leading whitespace, the field value, and ++ * > optional trailing whitespace. */ ++ ++ /* Strip trailing whitespace */ ++ bool space_trim = (*http_header_line_end == ' ' || *http_header_line_end == '\t'); ++ if (space_trim) { ++ do { ++ http_header_line_end--; ++ } while (http_header_line_end >= http_header_line && ++ (*http_header_line_end == ' ' || *http_header_line_end == '\t')); ++ } ++ http_header_line_end++; ++ *http_header_line_end = '\0'; ++ *http_header_line_length = http_header_line_end - http_header_line; ++ ++ return space_trim; ++} ++ ++/* Process folding headers of the current line and if there are none, parse last full response ++ * header line. It returns NULL if the last header is finished, otherwise it returns updated ++ * last header line. */ ++static zend_string *php_stream_http_response_headers_parse(php_stream *stream, ++ php_stream_context *context, int options, zend_string *last_header_line_str, ++ char *header_line, size_t *header_line_length, int response_code, ++ zval *response_header, php_stream_http_response_header_info *header_info) ++{ ++ char *last_header_line = ZSTR_VAL(last_header_line_str); ++ size_t last_header_line_length = ZSTR_LEN(last_header_line_str); ++ char *last_header_line_end = ZSTR_VAL(last_header_line_str) + ZSTR_LEN(last_header_line_str) - 1; ++ ++ /* Process non empty header line. */ ++ if (header_line && (*header_line != '\n' && *header_line != '\r')) { ++ /* Removing trailing white spaces. */ ++ if (php_stream_http_response_header_trim(header_line, header_line_length) && ++ *header_line_length == 0) { ++ /* Only spaces so treat as an empty folding header. */ ++ return last_header_line_str; ++ } ++ ++ /* Process folding headers if starting with a space or a tab. */ ++ if (header_line && (*header_line == ' ' || *header_line == '\t')) { ++ char *http_folded_header_line = header_line; ++ size_t http_folded_header_line_length = *header_line_length; ++ /* Remove the leading white spaces. */ ++ while (*http_folded_header_line == ' ' || *http_folded_header_line == '\t') { ++ http_folded_header_line++; ++ http_folded_header_line_length--; ++ } ++ /* It has to have some characters because it would get returned after the call ++ * php_stream_http_response_header_trim above. */ ++ ZEND_ASSERT(http_folded_header_line_length > 0); ++ /* Concatenate last header line, space and current header line. */ ++ zend_string *extended_header_str = zend_string_concat3( ++ last_header_line, last_header_line_length, ++ " ", 1, ++ http_folded_header_line, http_folded_header_line_length); ++ zend_string_efree(last_header_line_str); ++ last_header_line_str = extended_header_str; ++ /* Return new header line. */ ++ return last_header_line_str; ++ } ++ } ++ ++ /* Find header separator position. */ ++ char *last_header_value = memchr(last_header_line, ':', last_header_line_length); ++ if (last_header_value) { ++ last_header_value++; /* Skip ':'. */ ++ ++ /* Strip leading whitespace. */ ++ while (last_header_value < last_header_line_end ++ && (*last_header_value == ' ' || *last_header_value == '\t')) { ++ last_header_value++; ++ } ++ } else { ++ /* There is no colon. Set the value to the end of the header line, which is effectively ++ * an empty string. */ ++ last_header_value = last_header_line_end; ++ } ++ ++ bool store_header = true; ++ zval *tmpzval = NULL; ++ ++ if (!strncasecmp(last_header_line, "Location:", sizeof("Location:")-1)) { ++ /* Check if the location should be followed. */ ++ if (context && (tmpzval = php_stream_context_get_option(context, "http", "follow_location")) != NULL) { ++ header_info->follow_location = zval_is_true(tmpzval); ++ } else if (!((response_code >= 300 && response_code < 304) ++ || 307 == response_code || 308 == response_code)) { ++ /* The redirection should not be automatic if follow_location is not set and ++ * response_code not in (300, 301, 302, 303 and 307) ++ * see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.1 ++ * RFC 7238 defines 308: http://tools.ietf.org/html/rfc7238 */ ++ header_info->follow_location = 0; ++ } ++ strlcpy(header_info->location, last_header_value, sizeof(header_info->location)); ++ } else if (!strncasecmp(last_header_line, "Content-Type:", sizeof("Content-Type:")-1)) { ++ php_stream_notify_info(context, PHP_STREAM_NOTIFY_MIME_TYPE_IS, last_header_value, 0); ++ } else if (!strncasecmp(last_header_line, "Content-Length:", sizeof("Content-Length:")-1)) { ++ header_info->file_size = atoi(last_header_value); ++ php_stream_notify_file_size(context, header_info->file_size, last_header_line, 0); ++ } else if ( ++ !strncasecmp(last_header_line, "Transfer-Encoding:", sizeof("Transfer-Encoding:")-1) ++ && !strncasecmp(last_header_value, "Chunked", sizeof("Chunked")-1) ++ ) { ++ /* Create filter to decode response body. */ ++ if (!(options & STREAM_ONLY_GET_HEADERS)) { ++ zend_long decode = 1; ++ ++ if (context && (tmpzval = php_stream_context_get_option(context, "http", "auto_decode")) != NULL) { ++ decode = zend_is_true(tmpzval); ++ } ++ if (decode) { ++ if (header_info->transfer_encoding != NULL) { ++ /* Prevent a memory leak in case there are more transfer-encoding headers. */ ++ php_stream_filter_free(header_info->transfer_encoding); ++ } ++ header_info->transfer_encoding = php_stream_filter_create( ++ "dechunk", NULL, php_stream_is_persistent(stream)); ++ if (header_info->transfer_encoding != NULL) { ++ /* Do not store transfer-encoding header. */ ++ store_header = false; ++ } ++ } ++ } ++ } ++ ++ if (store_header) { ++ zval http_header; ++ ZVAL_NEW_STR(&http_header, last_header_line_str); ++ zend_hash_next_index_insert(Z_ARRVAL_P(response_header), &http_header); ++ } else { ++ zend_string_efree(last_header_line_str); ++ } ++ ++ return NULL; ++} ++ + static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, + const char *path, const char *mode, int options, zend_string **opened_path, + php_stream_context *context, int redirect_max, int flags, +@@ -128,11 +310,12 @@ static php_stream *php_stream_url_wrap_h + zend_string *tmp = NULL; + char *ua_str = NULL; + zval *ua_zval = NULL, *tmpzval = NULL, ssl_proxy_peer_name; +- char locationHTTP_HEADER_BLOCK_SIZE; + int reqok = 0; + char *http_header_line = NULL; ++ zend_string *last_header_line_str = NULL; ++ php_stream_http_response_header_info header_info; + char tmp_line128; +- size_t chunk_size = 0, file_size = 0; ++ size_t chunk_size = 0; + int eol_detect = 0; + char *transport_string; + zend_string *errstr = NULL; +@@ -143,8 +326,6 @@ static php_stream *php_stream_url_wrap_h + char *user_headers = NULL; + int header_init = ((flags & HTTP_WRAPPER_HEADER_INIT) != 0); + int redirected = ((flags & HTTP_WRAPPER_REDIRECTED) != 0); +- zend_bool follow_location = 1; +- php_stream_filter *transfer_encoding = NULL; + int response_code; + smart_str req_buf = {0}; + zend_bool custom_request_method; +@@ -657,8 +838,6 @@ finish: + /* send it */ + php_stream_write(stream, ZSTR_VAL(req_buf.s), ZSTR_LEN(req_buf.s)); + +- location0 = '\0'; +- + if (Z_ISUNDEF_P(response_header)) { + array_init(response_header); + } +@@ -736,125 +915,96 @@ finish: + } + } + +- /* read past HTTP headers */ ++ php_stream_http_response_header_info_init(&header_info); + ++ /* read past HTTP headers */ + while (!php_stream_eof(stream)) { + size_t http_header_line_length; + + if (http_header_line != NULL) { + efree(http_header_line); + } +- if ((http_header_line = php_stream_get_line(stream, NULL, 0, &http_header_line_length)) && *http_header_line != '\n' && *http_header_line != '\r') { +- char *e = http_header_line + http_header_line_length - 1; +- char *http_header_value; +- +- while (e >= http_header_line && (*e == '\n' || *e == '\r')) { +- e--; +- } +- +- /* The primary definition of an HTTP header in RFC 7230 states: +- * > Each header field consists of a case-insensitive field name followed +- * > by a colon (":"), optional leading whitespace, the field value, and +- * > optional trailing whitespace. */ +- +- /* Strip trailing whitespace */ +- while (e >= http_header_line && (*e == ' ' || *e == '\t')) { +- e--; +- } +- +- /* Terminate header line */ +- e++; +- *e = '\0'; +- http_header_line_length = e - http_header_line; +- +- http_header_value = memchr(http_header_line, ':', http_header_line_length); +- if (http_header_value) { +- http_header_value++; /* Skip ':' */ +- +- /* Strip leading whitespace */ +- while (http_header_value < e +- && (*http_header_value == ' ' || *http_header_value == '\t')) { +- http_header_value++; +- } ++ if ((http_header_line = php_stream_get_line(stream, NULL, 0, &http_header_line_length))) { ++ bool last_line; ++ if (*http_header_line == '\r') { ++ if (http_header_line1 != '\n') { ++ php_stream_close(stream); ++ stream = NULL; ++ php_stream_wrapper_log_error(wrapper, options, ++ "HTTP invalid header name (cannot start with CR character)!"); ++ goto out; ++ } ++ last_line = true; ++ } else if (*http_header_line == '\n') { ++ last_line = true; + } else { +- /* There is no colon. Set the value to the end of the header line, which is +- * effectively an empty string. */ +- http_header_value = e; ++ last_line = false; + } + +- if (!strncasecmp(http_header_line, "Location:", sizeof("Location:")-1)) { +- if (context && (tmpzval = php_stream_context_get_option(context, "http", "follow_location")) != NULL) { +- follow_location = zval_is_true(tmpzval); +- } else if (!((response_code >= 300 && response_code < 304) +- || 307 == response_code || 308 == response_code)) { +- /* we shouldn't redirect automatically +- if follow_location isn't set and response_code not in (300, 301, 302, 303 and 307) +- see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.1 +- RFC 7238 defines 308: http://tools.ietf.org/html/rfc7238 */ +- follow_location = 0; +- } +- strlcpy(location, http_header_value, sizeof(location)); +- } else if (!strncasecmp(http_header_line, "Content-Type:", sizeof("Content-Type:")-1)) { +- php_stream_notify_info(context, PHP_STREAM_NOTIFY_MIME_TYPE_IS, http_header_value, 0); +- } else if (!strncasecmp(http_header_line, "Content-Length:", sizeof("Content-Length:")-1)) { +- file_size = atoi(http_header_value); +- php_stream_notify_file_size(context, file_size, http_header_line, 0); +- } else if ( +- !strncasecmp(http_header_line, "Transfer-Encoding:", sizeof("Transfer-Encoding:")-1) +- && !strncasecmp(http_header_value, "Chunked", sizeof("Chunked")-1) +- ) { +- +- /* create filter to decode response body */ +- if (!(options & STREAM_ONLY_GET_HEADERS)) { +- zend_long decode = 1; +- +- if (context && (tmpzval = php_stream_context_get_option(context, "http", "auto_decode")) != NULL) { +- decode = zend_is_true(tmpzval); +- } +- if (decode) { +- transfer_encoding = php_stream_filter_create("dechunk", NULL, php_stream_is_persistent(stream)); +- if (transfer_encoding) { +- /* don't store transfer-encodeing header */ +- continue; +- } +- } +- } +- } +- +- { +- zval http_header; +- ZVAL_STRINGL(&http_header, http_header_line, http_header_line_length); +- zend_hash_next_index_insert(Z_ARRVAL_P(response_header), &http_header); +- } ++ if (last_header_line_str != NULL) { ++ /* Parse last header line. */ ++ last_header_line_str = php_stream_http_response_headers_parse(stream, context, ++ options, last_header_line_str, http_header_line, &http_header_line_length, ++ response_code, response_header, &header_info); ++ if (last_header_line_str != NULL) { ++ /* Folding header present so continue. */ ++ continue; ++ } ++ } else if (!last_line) { ++ /* The first line cannot start with spaces. */ ++ if (*http_header_line == ' ' || *http_header_line == '\t') { ++ php_stream_close(stream); ++ stream = NULL; ++ php_stream_wrapper_log_error(wrapper, options, ++ "HTTP invalid response format (folding header at the start)!"); ++ goto out; ++ } ++ /* Trim the first line if it is not the last line. */ ++ php_stream_http_response_header_trim(http_header_line, &http_header_line_length); ++ } ++ if (last_line) { ++ /* For the last line the last header line must be NULL. */ ++ ZEND_ASSERT(last_header_line_str == NULL); ++ break; ++ } ++ /* Save current line as the last line so it gets parsed in the next round. */ ++ last_header_line_str = zend_string_init(http_header_line, http_header_line_length, 0); + } else { + break; + } + } + +- if (!reqok || (location0 != '\0' && follow_location)) { +- if (!follow_location || (((options & STREAM_ONLY_GET_HEADERS) || ignore_errors) && redirect_max <= 1)) { ++ /* If the stream was closed early, we still want to process the last line to keep BC. */ ++ if (last_header_line_str != NULL) { ++ php_stream_http_response_headers_parse(stream, context, options, last_header_line_str, ++ NULL, NULL, response_code, response_header, &header_info); ++ } ++ ++ if (!reqok || (header_info.location0 != '\0' && header_info.follow_location)) { ++ if (!header_info.follow_location || (((options & STREAM_ONLY_GET_HEADERS) || ignore_errors) && redirect_max <= 1)) { + goto out; + } + +- if (location0 != '\0') +- php_stream_notify_info(context, PHP_STREAM_NOTIFY_REDIRECTED, location, 0); ++ if (header_info.location0 != '\0') ++ php_stream_notify_info(context, PHP_STREAM_NOTIFY_REDIRECTED, header_info.location, 0); + + php_stream_close(stream); + stream = NULL; + +- if (location0 != '\0') { ++ if (header_info.location0 != '\0') { + + char new_pathHTTP_HEADER_BLOCK_SIZE; + char loc_pathHTTP_HEADER_BLOCK_SIZE; + + *new_path='\0'; +- if (strlen(location)<8 || (strncasecmp(location, "http://", sizeof("http://")-1) && +- strncasecmp(location, "https://", sizeof("https://")-1) && +- strncasecmp(location, "ftp://", sizeof("ftp://")-1) && +- strncasecmp(location, "ftps://", sizeof("ftps://")-1))) ++ if (strlen(header_info.location) < 8 || ++ (strncasecmp(header_info.location, "http://", sizeof("http://")-1) && ++ strncasecmp(header_info.location, "https://", sizeof("https://")-1) && ++ strncasecmp(header_info.location, "ftp://", sizeof("ftp://")-1) && ++ strncasecmp(header_info.location, "ftps://", sizeof("ftps://")-1))) + { +- if (*location != '/') { +- if (*(location+1) != '\0' && resource->path) { ++ if (*header_info.location != '/') { ++ if (*(header_info.location+1) != '\0' && resource->path) { + char *s = strrchr(ZSTR_VAL(resource->path), '/'); + if (!s) { + s = ZSTR_VAL(resource->path); +@@ -870,15 +1020,17 @@ finish: + if (resource->path && + ZSTR_VAL(resource->path)0 == '/' && + ZSTR_VAL(resource->path)1 == '\0') { +- snprintf(loc_path, sizeof(loc_path) - 1, "%s%s", ZSTR_VAL(resource->path), location); ++ snprintf(loc_path, sizeof(loc_path) - 1, "%s%s", ++ ZSTR_VAL(resource->path), header_info.location); + } else { +- snprintf(loc_path, sizeof(loc_path) - 1, "%s/%s", ZSTR_VAL(resource->path), location); ++ snprintf(loc_path, sizeof(loc_path) - 1, "%s/%s", ++ ZSTR_VAL(resource->path), header_info.location); + } + } else { +- snprintf(loc_path, sizeof(loc_path) - 1, "/%s", location); ++ snprintf(loc_path, sizeof(loc_path) - 1, "/%s", header_info.location); + } + } else { +- strlcpy(loc_path, location, sizeof(loc_path)); ++ strlcpy(loc_path, header_info.location, sizeof(loc_path)); + } + if ((use_ssl && resource->port != 443) || (!use_ssl && resource->port != 80)) { + snprintf(new_path, sizeof(new_path) - 1, "%s://%s:%d%s", ZSTR_VAL(resource->scheme), ZSTR_VAL(resource->host), resource->port, loc_path); +@@ -886,7 +1038,7 @@ finish: + snprintf(new_path, sizeof(new_path) - 1, "%s://%s%s", ZSTR_VAL(resource->scheme), ZSTR_VAL(resource->host), loc_path); + } + } else { +- strlcpy(new_path, location, sizeof(new_path)); ++ strlcpy(new_path, header_info.location, sizeof(new_path)); + } + + php_url_free(resource); +@@ -939,7 +1091,7 @@ out: + if (header_init) { + ZVAL_COPY(&stream->wrapperdata, response_header); + } +- php_stream_notify_progress_init(context, 0, file_size); ++ php_stream_notify_progress_init(context, 0, header_info.file_size); + + /* Restore original chunk size now that we're done with headers */ + if (options & STREAM_WILL_CAST) +@@ -955,12 +1107,8 @@ out: + /* restore mode */ + strlcpy(stream->mode, mode, sizeof(stream->mode)); + +- if (transfer_encoding) { +- php_stream_filter_append(&stream->readfilters, transfer_encoding); +- } +- } else { +- if (transfer_encoding) { +- php_stream_filter_free(transfer_encoding); ++ if (header_info.transfer_encoding) { ++ php_stream_filter_append(&stream->readfilters, header_info.transfer_encoding); + } + } +
View file
php7-CVE-2025-1218.patch
Added
@@ -0,0 +1,1027 @@ +From 114dbb74368e6a6cd6e48ddb4a76dbe8728b84e2 Mon Sep 17 00:00:00 2001 +From: Jakub Zelenka <bukka@php.net> +Date: Sun, 12 Jul 2026 23:37:54 +0200 +Subject: PATCH Fix GHSA-r6x9-5r99-36j7: Various packet overreads in mysqlnd + wireprotocol + +Co-authored-by: Nora Dossche <7771979+ndossche@users.noreply.github.com> +Index: php-7.4.33/ext/mysqlnd/mysqlnd_ps.c +=================================================================== +--- php-7.4.33.orig/ext/mysqlnd/mysqlnd_ps.c ++++ php-7.4.33/ext/mysqlnd/mysqlnd_ps.c +@@ -373,6 +373,9 @@ mysqlnd_stmt_prepare_read_eof(MYSQLND_ST + if (FAIL == (ret = PACKET_READ(conn, &fields_eof))) { + if (stmt->result) { + stmt->result->m.free_result_contents(stmt->result); ++ /* The memset() below resets the statement, so release what it still owns first. */ ++ conn->m->free_reference(conn); ++ mnd_efree(stmt->execute_cmd_buffer.buffer); + /* XXX: This will crash, because we will null also the methods. + But seems it happens in extreme cases or doesn't. Should be fixed by exporting a function + (from mysqlnd_driver.c?) to do the reset. +Index: php-7.4.33/ext/mysqlnd/mysqlnd_ps_codec.c +=================================================================== +--- php-7.4.33.orig/ext/mysqlnd/mysqlnd_ps_codec.c ++++ php-7.4.33/ext/mysqlnd/mysqlnd_ps_codec.c +@@ -65,7 +65,9 @@ static inline int ps_fetch_is_packet_ove + return 0; + } + size_t length_len = *row - p; +- if (length_len > pack_len || length > pack_len - length_len) { ++ /* This assert should never fire, otherwise we invoked UB earlier */ ++ ZEND_ASSERT(length_len <= pack_len); ++ if (length > pack_len - length_len) { + ps_fetch_over_read_error(row); + return 1; + } +@@ -159,6 +161,18 @@ ps_fetch_from_1_to_8_bytes(zval * zv, co + } + /* }}} */ + ++/* The declared length has to cover the fixed offsets that the field type reads. */ ++static inline zend_bool ps_fetch_is_length_too_short(const zend_uchar ** row, const zend_ulong length, ++ const unsigned int min_length) ++{ ++ if (UNEXPECTED(length < min_length)) { ++ php_error_docref(NULL, E_WARNING, "Malformed server packet. Field length is too short for the field type"); ++ *row = NULL; ++ return 1; ++ } ++ return 0; ++} ++ + + /* {{{ ps_fetch_null */ + static void +@@ -263,11 +277,15 @@ ps_fetch_time(zval * zv, const MYSQLND_F + const zend_uchar *p = *row; + DBG_ENTER("ps_fetch_time"); + +- if ((length = php_mysqlnd_net_field_length(row))) { ++ if ((length = php_mysqlnd_net_field_length(row, pack_len))) { + if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) { + return; + } + ++ if (UNEXPECTED(ps_fetch_is_length_too_short(row, length, 8))) { ++ return; ++ } ++ + const zend_uchar * to = *row; + + t.time_type = MYSQLND_TIMESTAMP_TIME; +@@ -277,7 +295,7 @@ ps_fetch_time(zval * zv, const MYSQLND_F + t.hour = (unsigned int) to5; + t.minute = (unsigned int) to6; + t.second = (unsigned int) to7; +- t.second_part = (length > 8) ? (zend_ulong) sint4korr(to+8) : 0; ++ t.second_part = (length >= 12) ? (zend_ulong) sint4korr(to+8) : 0; + t.year = t.month= 0; + if (t.day) { + /* Convert days to hours at once */ +@@ -325,11 +343,15 @@ ps_fetch_date(zval * zv, const MYSQLND_F + const zend_uchar *p = *row; + DBG_ENTER("ps_fetch_date"); + +- if ((length = php_mysqlnd_net_field_length(row))) { ++ if ((length = php_mysqlnd_net_field_length(row, pack_len))) { + if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) { + return; + } + ++ if (UNEXPECTED(ps_fetch_is_length_too_short(row, length, 4))) { ++ return; ++ } ++ + const zend_uchar * to = *row; + + t.time_type = MYSQLND_TIMESTAMP_DATE; +@@ -341,7 +363,7 @@ ps_fetch_date(zval * zv, const MYSQLND_F + t.month = (unsigned int) to2; + t.day = (unsigned int) to3; + +- (*row)+= length; ++ (*row) += length; + } else { + memset(&t, 0, sizeof(t)); + t.time_type = MYSQLND_TIMESTAMP_DATE; +@@ -367,11 +389,15 @@ ps_fetch_datetime(zval * zv, const MYSQL + const zend_uchar *p = *row; + DBG_ENTER("ps_fetch_datetime"); + +- if ((length = php_mysqlnd_net_field_length(row))) { ++ if ((length = php_mysqlnd_net_field_length(row, pack_len))) { + if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) { + return; + } + ++ if (UNEXPECTED(ps_fetch_is_length_too_short(row, length, 4))) { ++ return; ++ } ++ + const zend_uchar * to = *row; + + t.time_type = MYSQLND_TIMESTAMP_DATETIME; +@@ -381,16 +407,16 @@ ps_fetch_datetime(zval * zv, const MYSQL + t.month = (unsigned int) to2; + t.day = (unsigned int) to3; + +- if (length > 4) { ++ if (length >= 7) { + t.hour = (unsigned int) to4; + t.minute = (unsigned int) to5; + t.second = (unsigned int) to6; + } else { + t.hour = t.minute = t.second= 0; + } +- t.second_part = (length > 7) ? (zend_ulong) sint4korr(to+7) : 0; ++ t.second_part = (length >= 11) ? (zend_ulong) sint4korr(to+7) : 0; + +- (*row)+= length; ++ (*row) += length; + } else { + memset(&t, 0, sizeof(t)); + t.time_type = MYSQLND_TIMESTAMP_DATETIME; +@@ -431,7 +457,7 @@ ps_fetch_string(zval * zv, const MYSQLND + to write \0 to the row buffer + */ + const zend_uchar *p = *row; +- const zend_ulong length = php_mysqlnd_net_field_length(row); ++ const zend_ulong length = php_mysqlnd_net_field_length(row, pack_len); + if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) { + return; + } +@@ -451,7 +477,7 @@ static void + ps_fetch_bit(zval * zv, const MYSQLND_FIELD * const field, const unsigned int pack_len, const zend_uchar ** row) + { + const zend_uchar *p = *row; +- const zend_ulong length = php_mysqlnd_net_field_length(row); ++ const zend_ulong length = php_mysqlnd_net_field_length(row, pack_len); + if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) { + return; + } +Index: php-7.4.33/ext/mysqlnd/mysqlnd_wireprotocol.c +=================================================================== +--- php-7.4.33.orig/ext/mysqlnd/mysqlnd_wireprotocol.c ++++ php-7.4.33/ext/mysqlnd/mysqlnd_wireprotocol.c +@@ -26,11 +26,18 @@ + #include "mysqlnd_statistics.h" + #include "mysqlnd_debug.h" + +-#define BAIL_IF_NO_MORE_DATA \ +- if (UNEXPECTED((size_t)(p - begin) > packet->header.size)) { \ ++#define BAIL_PREMATURE_END do { \ + php_error_docref(NULL, E_WARNING, "Premature end of data (mysqlnd_wireprotocol.c:%u)", __LINE__); \ + goto premature_end; \ +- } \ ++ } while (0) ++ ++/* Bail out unless the packet still has the required number of bytes left to read. */ ++#define BAIL_IF_NOT_ENOUGH_DATA_EX(min_required_bytes) \ ++ if (UNEXPECTED((size_t)(p - begin) + (min_required_bytes) > packet->header.size)) { \ ++ BAIL_PREMATURE_END; \ ++ } ++ ++#define BAIL_IF_NOT_ENOUGH_DATA BAIL_IF_NOT_ENOUGH_DATA_EX(1) + + + static const char *unknown_sqlstate= "HY000"; +@@ -92,10 +99,14 @@ static enum_mysqlnd_collected_stats pack + /* {{{ php_mysqlnd_net_field_length + Get next field's length */ + zend_ulong +-php_mysqlnd_net_field_length(const zend_uchar **packet) ++php_mysqlnd_net_field_length(const zend_uchar **packet, size_t remaining_size) + { + register const zend_uchar *p= (const zend_uchar *)*packet; + ++ if (UNEXPECTED(remaining_size == 0)) { ++ return MYSQLND_INVALID_NET_FIELD_LENGTH; ++ } ++ + if (*p < 251) { + (*packet)++; + return (zend_ulong) *p; +@@ -106,14 +117,23 @@ php_mysqlnd_net_field_length(const zend_ + (*packet)++; + return MYSQLND_NULL_LENGTH; + case 252: +- (*packet) += 3; +- return (zend_ulong) uint2korr(p+1); ++ if (EXPECTED(remaining_size >= 3)) { ++ (*packet) += 3; ++ return (zend_ulong) uint2korr(p+1); ++ } ++ return MYSQLND_INVALID_NET_FIELD_LENGTH; + case 253: +- (*packet) += 4; +- return (zend_ulong) uint3korr(p+1); ++ if (EXPECTED(remaining_size >= 4)) { ++ (*packet) += 4; ++ return (zend_ulong) uint3korr(p+1); ++ } ++ return MYSQLND_INVALID_NET_FIELD_LENGTH; + default: +- (*packet) += 9; +- return (zend_ulong) uint4korr(p+1); ++ if (EXPECTED(remaining_size >= 9)) { ++ (*packet) += 9; ++ return (zend_ulong) uint4korr(p+1); ++ } ++ return MYSQLND_INVALID_NET_FIELD_LENGTH; + } + } + /* }}} */ +@@ -121,29 +141,56 @@ php_mysqlnd_net_field_length(const zend_ + + /* {{{ php_mysqlnd_net_field_length_ll + Get next field's length */ +-uint64_t +-php_mysqlnd_net_field_length_ll(const zend_uchar **packet) ++MYSQLND_OPTIONAL_UINT64_T ++php_mysqlnd_net_field_length_ll(const zend_uchar **packet, size_t remaining_size) + { + register const zend_uchar *p = (zend_uchar *)*packet; + ++ MYSQLND_OPTIONAL_UINT64_T result; ++ result.has_value = 0; ++ result.value = 0; ++ ++ if (UNEXPECTED(remaining_size == 0)) { ++ return result; ++ } ++ + if (*p < 251) { + (*packet)++; +- return (uint64_t) *p; ++ result.value = (uint64_t) *p; ++ result.has_value = 1; ++ return result; + } + + switch (*p) { + case 251: + (*packet)++; +- return (uint64_t) MYSQLND_NULL_LENGTH; ++ result.value = MYSQLND_NULL_LENGTH; ++ result.has_value = 1; ++ return result; ++ + case 252: +- (*packet) += 3; +- return (uint64_t) uint2korr(p + 1); ++ if (EXPECTED(remaining_size >= 3)) { ++ (*packet) += 3; ++ result.value = (uint64_t) uint2korr(p+1); ++ result.has_value = 1; ++ } ++ return result; ++ + case 253: +- (*packet) += 4; +- return (uint64_t) uint3korr(p + 1); ++ if (EXPECTED(remaining_size >= 4)) { ++ (*packet) += 4; ++ result.value = (uint64_t) uint3korr(p+1); ++ result.has_value = 1; ++ } ++ return result; ++ + default: +- (*packet) += 9; +- return (uint64_t) uint8korr(p + 1); ++ if (EXPECTED(remaining_size >= 9)) { ++ (*packet) += 9; ++ result.value = uint8korr(p+1); ++ result.has_value = 1; ++ } ++ return result; + } + } + /* }}} */ +@@ -339,22 +386,14 @@ php_mysqlnd_greet_read(MYSQLND_CONN_DATA + if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, sizeof(buf), "greeting", PROT_GREET_PACKET)) { + DBG_RETURN(FAIL); + } +- BAIL_IF_NO_MORE_DATA; ++ BAIL_IF_NOT_ENOUGH_DATA; + + packet->authentication_plugin_data.s = packet->intern_auth_plugin_data; + packet->authentication_plugin_data.l = sizeof(packet->intern_auth_plugin_data); + +- if (packet->header.size < sizeof(buf)) { +- /* +- Null-terminate the string, so strdup can work even if the packets have a string at the end, +- which is not ASCIIZ +- */ +- bufpacket->header.size = '\0'; +- } +- + packet->protocol_version = uint1korr(p); + p++; +- BAIL_IF_NO_MORE_DATA; ++ BAIL_IF_NOT_ENOUGH_DATA; + + if (ERROR_MARKER == packet->protocol_version) { + php_mysqlnd_read_error_from_line(p, packet->header.size - 1, +@@ -372,39 +411,38 @@ php_mysqlnd_greet_read(MYSQLND_CONN_DATA + DBG_RETURN(PASS); + } + +- packet->server_version = estrdup((char *)p); +- p+= strlen(packet->server_version) + 1; /* eat the '\0' */ +- BAIL_IF_NO_MORE_DATA; ++ /* This server version string MUST be NUL terminated, search for a NUL byte in the remaining space. */ ++ const char *version_nul_byte = memchr(p, '\0', packet->header.size - (p - begin)); ++ if (!version_nul_byte) { ++ BAIL_PREMATURE_END; ++ } ++ packet->server_version = estrndup((char *) p, version_nul_byte - (const char *) p); ++ p = (unsigned char *) version_nul_byte + 1; /* eat the '\0' */ ++ ++ BAIL_IF_NOT_ENOUGH_DATA_EX(4 + SCRAMBLE_LENGTH_323 + 1 + 2 + 1 + 2 + 13); + + packet->thread_id = uint4korr(p); + p+=4; +- BAIL_IF_NO_MORE_DATA; + + memcpy(packet->authentication_plugin_data.s, p, SCRAMBLE_LENGTH_323); + p+= SCRAMBLE_LENGTH_323; +- BAIL_IF_NO_MORE_DATA; + + /* pad1 */ + p++; +- BAIL_IF_NO_MORE_DATA; + + packet->server_capabilities = uint2korr(p); + p+= 2; +- BAIL_IF_NO_MORE_DATA; + DBG_INF_FMT("4.1 server_caps=%u\n", (uint32_t) packet->server_capabilities); + + packet->charset_no = uint1korr(p); + p++; +- BAIL_IF_NO_MORE_DATA; + + packet->server_status = uint2korr(p); + p+= 2; +- BAIL_IF_NO_MORE_DATA; + + /* pad2 */ + pad_start = p; + p+= 13; +- BAIL_IF_NO_MORE_DATA; + + if ((size_t) (p - buf) < packet->header.size) { + /* auth_plugin_data is split into two parts */ +@@ -426,6 +464,9 @@ php_mysqlnd_greet_read(MYSQLND_CONN_DATA + /* And a length of the server scramble in one byte */ + packet->authentication_plugin_data.l = uint1korr(pad_start + 2); + if (packet->authentication_plugin_data.l > SCRAMBLE_LENGTH) { ++ /* the rest of the scramble has to be in the packet */ ++ BAIL_IF_NOT_ENOUGH_DATA_EX(packet->authentication_plugin_data.l - SCRAMBLE_LENGTH); ++ + /* more data*/ + char * new_auth_plugin_data = emalloc(packet->authentication_plugin_data.l); + +@@ -439,7 +480,9 @@ php_mysqlnd_greet_read(MYSQLND_CONN_DATA + } + + if (packet->server_capabilities & CLIENT_PLUGIN_AUTH) { +- BAIL_IF_NO_MORE_DATA; ++ /* This is actually checked above and it needs to pass to set extended server capabilities ++ * so it should never bail. */ ++ BAIL_IF_NOT_ENOUGH_DATA; + /* The server is 5.5.x and supports authentication plugins */ + packet->auth_protocol = estrdup((char *)p); + p+= strlen(packet->auth_protocol) + 1; /* eat the '\0' */ +@@ -454,9 +497,8 @@ php_mysqlnd_greet_read(MYSQLND_CONN_DATA + + DBG_RETURN(PASS); + premature_end: +- DBG_ERR_FMT("GREET packet %d bytes shorter than expected", p - begin - packet->header.size); +- php_error_docref(NULL, E_WARNING, "GREET packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected", +- p - begin - packet->header.size); ++ DBG_ERR_FMT("GREET packet shorter than expected"); ++ php_error_docref(NULL, E_WARNING, "GREET packet shorter than expected"); + DBG_RETURN(FAIL); + } + /* }}} */ +@@ -661,7 +703,7 @@ php_mysqlnd_auth_response_read(MYSQLND_C + if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "OK", PROT_OK_PACKET)) { + DBG_RETURN(FAIL); + } +- BAIL_IF_NO_MORE_DATA; ++ BAIL_IF_NOT_ENOUGH_DATA; + + /* + zero-terminate the buffer for safety. We are sure there is place for the \0 +@@ -672,7 +714,7 @@ php_mysqlnd_auth_response_read(MYSQLND_C + /* Should be always 0x0 or ERROR_MARKER for error */ + packet->response_code = uint1korr(p); + p++; +- BAIL_IF_NO_MORE_DATA; ++ BAIL_IF_NOT_ENOUGH_DATA; + + if (ERROR_MARKER == packet->response_code) { + php_mysqlnd_read_error_from_line(p, packet->header.size - 1, +@@ -684,9 +726,14 @@ php_mysqlnd_auth_response_read(MYSQLND_C + if (0xFE == packet->response_code) { + /* Authentication Switch Response */ + if (packet->header.size > (size_t) (p - buf)) { +- packet->new_auth_protocol = mnd_pestrdup((char *)p, FALSE); +- packet->new_auth_protocol_len = strlen(packet->new_auth_protocol); +- p+= packet->new_auth_protocol_len + 1; /* +1 for the \0 */ ++ /* The plugin name MUST be NUL terminated, search for a NUL byte in the remaining space. */ ++ const char *auth_protocol_nul_byte = memchr(p, '\0', packet->header.size - (p - buf)); ++ if (!auth_protocol_nul_byte) { ++ BAIL_PREMATURE_END; ++ } ++ packet->new_auth_protocol_len = auth_protocol_nul_byte - (const char *) p; ++ packet->new_auth_protocol = mnd_pestrndup((char *) p, packet->new_auth_protocol_len, FALSE); ++ p = (zend_uchar *) auth_protocol_nul_byte + 1; /* eat the '\0' */ + + packet->new_auth_protocol_data_len = packet->header.size - (size_t) (p - buf); + if (packet->new_auth_protocol_data_len) { +@@ -697,27 +744,37 @@ php_mysqlnd_auth_response_read(MYSQLND_C + DBG_INF_FMT("Server salt : %d%.*s", packet->new_auth_protocol_data_len, packet->new_auth_protocol_data_len, packet->new_auth_protocol_data); + } + } else { +- zend_ulong net_len; + /* Everything was fine! */ +- packet->affected_rows = php_mysqlnd_net_field_length_ll(&p); +- BAIL_IF_NO_MORE_DATA; ++ zend_ulong net_len; ++ MYSQLND_OPTIONAL_UINT64_T len_ll; + +- packet->last_insert_id = php_mysqlnd_net_field_length_ll(&p); +- BAIL_IF_NO_MORE_DATA; ++ len_ll = php_mysqlnd_net_field_length_ll(&p, packet->header.size - (p - begin)); ++ if (UNEXPECTED(!len_ll.has_value)) { ++ BAIL_PREMATURE_END; ++ } ++ packet->affected_rows = len_ll.value; ++ ++ len_ll = php_mysqlnd_net_field_length_ll(&p, packet->header.size - (p - begin)); ++ if (UNEXPECTED(!len_ll.has_value)) { ++ BAIL_PREMATURE_END; ++ } ++ packet->last_insert_id = len_ll.value; ++ ++ BAIL_IF_NOT_ENOUGH_DATA_EX(4); + + packet->server_status = uint2korr(p); + p+= 2; +- BAIL_IF_NO_MORE_DATA; + + packet->warning_count = uint2korr(p); + p+= 2; +- BAIL_IF_NO_MORE_DATA; + + /* There is a message */ +- if (packet->header.size > (size_t) (p - buf) && (net_len = php_mysqlnd_net_field_length(&p))) { +- /* p can get past packet size when getting field length so it needs to be checked first +- * and after that it can be checked that the net_len is not greater than the packet size */ +- if ((p - buf) > packet->header.size || packet->header.size - (p - buf) < net_len) { ++ if (packet->header.size > (size_t) (p - buf) && (net_len = php_mysqlnd_net_field_length(&p, packet->header.size - (p - begin)))) { ++ /* In older versions of mysqlnd we had to perform an extra check because reading the field length ++ * could overread the OK packet. Now reading the length won't go out of bounds and we only have ++ * to check whether the message length is in bounds. */ ++ ZEND_ASSERT((p - buf) <= packet->header.size); ++ if (packet->header.size - (p - buf) < net_len) { + DBG_ERR_FMT("OK packet message length is past the packet size"); + php_error_docref(NULL, E_WARNING, "OK packet message length is past the packet size"); + DBG_RETURN(FAIL); +@@ -736,9 +793,8 @@ php_mysqlnd_auth_response_read(MYSQLND_C + + DBG_RETURN(PASS); + premature_end: +- DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin - packet->header.size); +- php_error_docref(NULL, E_WARNING, "AUTH_RESPONSE packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected", +- p - begin - packet->header.size); ++ DBG_ERR_FMT("OK packet shorter than expected"); ++ php_error_docref(NULL, E_WARNING, "AUTH_RESPONSE packet shorter than expected"); + DBG_RETURN(FAIL); + } + /* }}} */ +@@ -831,12 +887,12 @@ php_mysqlnd_ok_read(MYSQLND_CONN_DATA * + if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "OK", PROT_OK_PACKET)) { + DBG_RETURN(FAIL); + } +- BAIL_IF_NO_MORE_DATA; ++ BAIL_IF_NOT_ENOUGH_DATA; + + /* Should be always 0x0 or ERROR_MARKER for error */ + packet->field_count = uint1korr(p); + p++; +- BAIL_IF_NO_MORE_DATA; ++ BAIL_IF_NOT_ENOUGH_DATA; + + if (ERROR_MARKER == packet->field_count) { + php_mysqlnd_read_error_from_line(p, packet->header.size - 1, +@@ -846,22 +902,33 @@ php_mysqlnd_ok_read(MYSQLND_CONN_DATA * + DBG_RETURN(PASS); + } + /* Everything was fine! */ +- packet->affected_rows = php_mysqlnd_net_field_length_ll(&p); +- BAIL_IF_NO_MORE_DATA; ++ MYSQLND_OPTIONAL_UINT64_T len_ll; ++ ++ len_ll = php_mysqlnd_net_field_length_ll(&p, packet->header.size - (p - begin)); ++ if (UNEXPECTED(!len_ll.has_value)) { ++ BAIL_PREMATURE_END; ++ } ++ packet->affected_rows = len_ll.value; ++ ++ len_ll = php_mysqlnd_net_field_length_ll(&p, packet->header.size - (p - begin)); ++ if (UNEXPECTED(!len_ll.has_value)) { ++ BAIL_PREMATURE_END; ++ } ++ packet->last_insert_id = len_ll.value; + +- packet->last_insert_id = php_mysqlnd_net_field_length_ll(&p); +- BAIL_IF_NO_MORE_DATA; ++ BAIL_IF_NOT_ENOUGH_DATA_EX(4); + + packet->server_status = uint2korr(p); + p+= 2; +- BAIL_IF_NO_MORE_DATA; + + packet->warning_count = uint2korr(p); + p+= 2; +- BAIL_IF_NO_MORE_DATA; + + /* There is a message */ +- if (packet->header.size > (size_t) (p - buf) && (net_len = php_mysqlnd_net_field_length(&p))) { ++ if (packet->header.size > (size_t) (p - buf) && (net_len = php_mysqlnd_net_field_length(&p, packet->header.size - (p - begin)))) { ++ if (UNEXPECTED(net_len == MYSQLND_INVALID_NET_FIELD_LENGTH)) { ++ BAIL_PREMATURE_END; ++ } + packet->message_len = MIN(net_len, buf_len - (p - begin)); + packet->message = mnd_pestrndup((char *)p, packet->message_len, FALSE); + } else { +@@ -873,13 +940,10 @@ php_mysqlnd_ok_read(MYSQLND_CONN_DATA * + packet->affected_rows, packet->last_insert_id, packet->server_status, + packet->warning_count); + +- BAIL_IF_NO_MORE_DATA; +- + DBG_RETURN(PASS); + premature_end: +- DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin - packet->header.size); +- php_error_docref(NULL, E_WARNING, "OK packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected", +- p - begin - packet->header.size); ++ DBG_ERR_FMT("OK packet shorter than expected"); ++ php_error_docref(NULL, E_WARNING, "OK packet shorter than expected"); + DBG_RETURN(FAIL); + } + /* }}} */ +@@ -924,12 +988,12 @@ php_mysqlnd_eof_read(MYSQLND_CONN_DATA * + if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "EOF", PROT_EOF_PACKET)) { + DBG_RETURN(FAIL); + } +- BAIL_IF_NO_MORE_DATA; ++ BAIL_IF_NOT_ENOUGH_DATA; + + /* Should be always EODATA_MARKER */ + packet->field_count = uint1korr(p); + p++; +- BAIL_IF_NO_MORE_DATA; ++ BAIL_IF_NOT_ENOUGH_DATA; + + if (ERROR_MARKER == packet->field_count) { + php_mysqlnd_read_error_from_line(p, packet->header.size - 1, +@@ -945,28 +1009,25 @@ php_mysqlnd_eof_read(MYSQLND_CONN_DATA * + according to the Docs@Forge!!! + */ + if (packet->header.size > 1) { ++ BAIL_IF_NOT_ENOUGH_DATA_EX(4); ++ + packet->warning_count = uint2korr(p); + p+= 2; +- BAIL_IF_NO_MORE_DATA; + + packet->server_status = uint2korr(p); + p+= 2; +- BAIL_IF_NO_MORE_DATA; + } else { + packet->warning_count = 0; + packet->server_status = 0; + } + +- BAIL_IF_NO_MORE_DATA; +- + DBG_INF_FMT("EOF packet: fields=%u status=%u warnings=%u", + packet->field_count, packet->server_status, packet->warning_count); + + DBG_RETURN(PASS); + premature_end: +- DBG_ERR_FMT("EOF packet %d bytes shorter than expected", p - begin - packet->header.size); +- php_error_docref(NULL, E_WARNING, "EOF packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected", +- p - begin - packet->header.size); ++ DBG_ERR_FMT("EOF packet shorter than expected"); ++ php_error_docref(NULL, E_WARNING, "EOF packet shorter than expected"); + DBG_RETURN(FAIL); + } + /* }}} */ +@@ -1056,13 +1117,14 @@ php_mysqlnd_rset_header_read(MYSQLND_CON + const zend_uchar * p = buf; + const zend_uchar * const begin = buf; + size_t len; ++ MYSQLND_OPTIONAL_UINT64_T len_ll; + + DBG_ENTER("php_mysqlnd_rset_header_read"); + + if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "resultset header", PROT_RSET_HEADER_PACKET)) { + DBG_RETURN(FAIL); + } +- BAIL_IF_NO_MORE_DATA; ++ BAIL_IF_NOT_ENOUGH_DATA; + + /* + Don't increment. First byte is ERROR_MARKER on error, but otherwise is starting byte +@@ -1071,7 +1133,7 @@ php_mysqlnd_rset_header_read(MYSQLND_CON + if (ERROR_MARKER == *p) { + /* Error */ + p++; +- BAIL_IF_NO_MORE_DATA; ++ BAIL_IF_NOT_ENOUGH_DATA; + php_mysqlnd_read_error_from_line(p, packet->header.size - 1, + packet->error_info.error, sizeof(packet->error_info.error), + &packet->error_info.error_no, packet->error_info.sqlstate +@@ -1079,8 +1141,11 @@ php_mysqlnd_rset_header_read(MYSQLND_CON + DBG_RETURN(PASS); + } + +- packet->field_count = php_mysqlnd_net_field_length(&p); +- BAIL_IF_NO_MORE_DATA; ++ zend_ulong field_count = php_mysqlnd_net_field_length(&p, packet->header.size - (p - begin)); ++ if (UNEXPECTED(field_count == MYSQLND_INVALID_NET_FIELD_LENGTH)) { ++ BAIL_PREMATURE_END; ++ } ++ packet->field_count = field_count; + + switch (packet->field_count) { + case MYSQLND_NULL_LENGTH: +@@ -1088,7 +1153,7 @@ php_mysqlnd_rset_header_read(MYSQLND_CON + /* + First byte in the packet is the field count. + Thus, the name is size - 1. And we add 1 for a trailing \0. +- Because we have BAIL_IF_NO_MORE_DATA before the switch, we are guaranteed ++ Because we have BAIL_IF_NOT_ENOUGH_DATA before the switch, we are guaranteed + that packet->header.size is > 0. Which means that len can't underflow, that + would lead to 0 byte allocation but 2^32 or 2^64 bytes copied. + */ +@@ -1105,24 +1170,34 @@ php_mysqlnd_rset_header_read(MYSQLND_CON + break; + case 0x00: + DBG_INF("UPSERT"); +- packet->affected_rows = php_mysqlnd_net_field_length_ll(&p); +- BAIL_IF_NO_MORE_DATA; + +- packet->last_insert_id = php_mysqlnd_net_field_length_ll(&p); +- BAIL_IF_NO_MORE_DATA; ++ len_ll = php_mysqlnd_net_field_length_ll(&p, packet->header.size - (p - begin)); ++ if (UNEXPECTED(!len_ll.has_value)) { ++ BAIL_PREMATURE_END; ++ } ++ packet->affected_rows = len_ll.value; ++ ++ len_ll = php_mysqlnd_net_field_length_ll(&p, packet->header.size - (p - begin)); ++ if (UNEXPECTED(!len_ll.has_value)) { ++ BAIL_PREMATURE_END; ++ } ++ packet->last_insert_id = len_ll.value; ++ ++ BAIL_IF_NOT_ENOUGH_DATA_EX(4); + + packet->server_status = uint2korr(p); + p+=2; +- BAIL_IF_NO_MORE_DATA; + + packet->warning_count = uint2korr(p); + p+=2; +- BAIL_IF_NO_MORE_DATA; ++ ++ len = php_mysqlnd_net_field_length(&p, packet->header.size - (p - begin)); ++ + /* Check for additional textual data */ +- if (packet->header.size > (size_t) (p - buf) && (len = php_mysqlnd_net_field_length(&p))) { +- /* p can get past packet size when getting field length so it needs to be checked first +- * and after that it can be checked that the len is not greater than the packet size */ +- if ((p - buf) > packet->header.size || packet->header.size - (p - buf) < len) { ++ if (len && len != MYSQLND_INVALID_NET_FIELD_LENGTH) { ++ /* This checks both whether reading the len was successful ++ * and that the len is not greater than the packet size */ ++ if (packet->header.size - (p - buf) < len) { + size_t local_file_name_over_read = ((p - buf) - packet->header.size) + len; + DBG_ERR_FMT("RSET_HEADER packet additional data length is past %zu bytes the packet size", + local_file_name_over_read); +@@ -1150,13 +1225,11 @@ php_mysqlnd_rset_header_read(MYSQLND_CON + /* Result set */ + break; + } +- BAIL_IF_NO_MORE_DATA; + + DBG_RETURN(ret); + premature_end: +- DBG_ERR_FMT("RSET_HEADER packet %d bytes shorter than expected", p - begin - packet->header.size); +- php_error_docref(NULL, E_WARNING, "RSET_HEADER packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected", +- p - begin - packet->header.size); ++ DBG_ERR_FMT("RSET_HEADER packet shorter than expected"); ++ php_error_docref(NULL, E_WARNING, "RSET_HEADER packet shorter than expected"); + DBG_RETURN(FAIL); + } + /* }}} */ +@@ -1177,8 +1250,8 @@ void php_mysqlnd_rset_header_free_mem(vo + /* }}} */ + + #define READ_RSET_FIELD(field_name) do { \ +- len = php_mysqlnd_net_field_length(&p); \ +- if (UNEXPECTED(len == MYSQLND_NULL_LENGTH)) { \ ++ zend_ulong len = php_mysqlnd_net_field_length(&p, packet->header.size - (p - begin)); \ ++ if (UNEXPECTED(len > packet->header.size - (p - begin))) { \ + goto faulty_or_fake; \ + } else if (len != 0) { \ + meta->field_name = (const char *)p; \ +@@ -1222,11 +1295,11 @@ php_mysqlnd_rset_field_read(MYSQLND_CONN + DBG_RETURN(PASS); + } + +- BAIL_IF_NO_MORE_DATA; ++ BAIL_IF_NOT_ENOUGH_DATA; + if (ERROR_MARKER == *p) { + /* Error */ + p++; +- BAIL_IF_NO_MORE_DATA; ++ BAIL_IF_NOT_ENOUGH_DATA; + php_mysqlnd_read_error_from_line(p, packet->header.size - 1, + packet->error_info.error, sizeof(packet->error_info.error), + &packet->error_info.error_no, packet->error_info.sqlstate +@@ -1291,9 +1364,8 @@ php_mysqlnd_rset_field_read(MYSQLND_CONN + + + /* COM_FIELD_LIST is no longer supported so def should not be present */ +- if (packet->header.size > (size_t) (p - buf) && +- (len = php_mysqlnd_net_field_length(&p)) && +- len != MYSQLND_NULL_LENGTH) ++ len = php_mysqlnd_net_field_length(&p, packet->header.size - (p - begin)); ++ if (len < MYSQLND_INVALID_NET_FIELD_LENGTH) + { + DBG_ERR_FMT("Protocol error. Server sent default for unsupported field list"); + php_error_docref(NULL, E_WARNING, +@@ -1361,9 +1433,8 @@ faulty_or_fake: + " The server is faulty"); + DBG_RETURN(FAIL); + premature_end: +- DBG_ERR_FMT("RSET field packet %d bytes shorter than expected", p - begin - packet->header.size); +- php_error_docref(NULL, E_WARNING, "Result set field packet "MYSQLND_SZ_T_SPEC" bytes " +- "shorter than expected", p - begin - packet->header.size); ++ DBG_ERR_FMT("RSET field packet shorter than expected"); ++ php_error_docref(NULL, E_WARNING, "Result set field packet shorter than expected"); + DBG_RETURN(FAIL); + } + /* }}} */ +@@ -1597,12 +1668,12 @@ php_mysqlnd_rowp_read_text_protocol_aux( + + for (i = 0, current_field = start_field; current_field < end_field; current_field++, i++) { + /* php_mysqlnd_net_field_length() call should be after *this_field_len_pos = p; */ +- const zend_ulong len = php_mysqlnd_net_field_length((const zend_uchar **) &p); ++ zend_ulong len = php_mysqlnd_net_field_length((const zend_uchar **) &p, packet_end - p); + + /* NULL or NOT NULL, this is the question! */ + if (len == MYSQLND_NULL_LENGTH) { + ZVAL_NULL(current_field); +- } else if (p > packet_end || len > packet_end - p) { ++ } else if (len > packet_end - p) { + php_error_docref(NULL, E_WARNING, "Malformed server packet. Field length pointing after end of packet"); + for (j = 0, current_field = start_field; j < i; current_field++, j++) { + zval_ptr_dtor(current_field); +@@ -1816,7 +1887,8 @@ php_mysqlnd_rowp_read(MYSQLND_CONN_DATA + } else if (EODATA_MARKER == *p && data_size < 8) { /* EOF */ + packet->eof = TRUE; + p++; +- if (data_size > 1) { ++ /* the marker is followed by 2 bytes of warnings and 2 bytes of status */ ++ if (data_size >= 5) { + packet->warning_count = uint2korr(p); + p += 2; + packet->server_status = uint2korr(p); +@@ -1951,12 +2023,12 @@ php_mysqlnd_prepare_read(MYSQLND_CONN_DA + if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "prepare", PROT_PREPARE_RESP_PACKET)) { + DBG_RETURN(FAIL); + } +- BAIL_IF_NO_MORE_DATA; ++ BAIL_IF_NOT_ENOUGH_DATA; + + data_size = packet->header.size; + packet->error_code = uint1korr(p); + p++; +- BAIL_IF_NO_MORE_DATA; ++ BAIL_IF_NOT_ENOUGH_DATA; + + if (ERROR_MARKER == packet->error_code) { + php_mysqlnd_read_error_from_line(p, data_size - 1, +@@ -1976,23 +2048,23 @@ php_mysqlnd_prepare_read(MYSQLND_CONN_DA + DBG_RETURN(FAIL); + } + ++ BAIL_IF_NOT_ENOUGH_DATA_EX(8); ++ + packet->stmt_id = uint4korr(p); + p += 4; +- BAIL_IF_NO_MORE_DATA; + + /* Number of columns in result set */ + packet->field_count = uint2korr(p); + p += 2; +- BAIL_IF_NO_MORE_DATA; + + packet->param_count = uint2korr(p); + p += 2; +- BAIL_IF_NO_MORE_DATA; + + if (data_size > 9) { ++ BAIL_IF_NOT_ENOUGH_DATA_EX(3); ++ + /* 0x0 filler sent by the server for 5.0+ clients */ + p++; +- BAIL_IF_NO_MORE_DATA; + + packet->warning_count = uint2korr(p); + } +@@ -2000,13 +2072,10 @@ php_mysqlnd_prepare_read(MYSQLND_CONN_DA + DBG_INF_FMT("Prepare packet read: stmt_id=%u fields=%u params=%u", + packet->stmt_id, packet->field_count, packet->param_count); + +- BAIL_IF_NO_MORE_DATA; +- + DBG_RETURN(PASS); + premature_end: +- DBG_ERR_FMT("PREPARE packet %d bytes shorter than expected", p - begin - packet->header.size); +- php_error_docref(NULL, E_WARNING, "PREPARE packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected", +- p - begin - packet->header.size); ++ DBG_ERR_FMT("PREPARE packet shorter than expected"); ++ php_error_docref(NULL, E_WARNING, "PREPARE packet shorter than expected"); + DBG_RETURN(FAIL); + } + /* }}} */ +@@ -2033,7 +2102,7 @@ php_mysqlnd_chg_user_read(MYSQLND_CONN_D + if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "change user response", PROT_CHG_USER_RESP_PACKET)) { + DBG_RETURN(FAIL); + } +- BAIL_IF_NO_MORE_DATA; ++ BAIL_IF_NOT_ENOUGH_DATA; + + /* + Don't increment. First byte is ERROR_MARKER on error, but otherwise is starting byte +@@ -2058,11 +2127,16 @@ php_mysqlnd_chg_user_read(MYSQLND_CONN_D + packet->error_info.sqlstate + ); + } +- BAIL_IF_NO_MORE_DATA; ++ BAIL_IF_NOT_ENOUGH_DATA; + if (packet->response_code == 0xFE && packet->header.size > (size_t) (p - buf)) { +- packet->new_auth_protocol = mnd_pestrdup((char *)p, FALSE); +- packet->new_auth_protocol_len = strlen(packet->new_auth_protocol); +- p+= packet->new_auth_protocol_len + 1; /* +1 for the \0 */ ++ /* The plugin name MUST be NUL terminated, search for a NUL byte in the remaining space. */ ++ const char *auth_protocol_nul_byte = memchr(p, '\0', packet->header.size - (p - buf)); ++ if (!auth_protocol_nul_byte) { ++ BAIL_PREMATURE_END; ++ } ++ packet->new_auth_protocol_len = auth_protocol_nul_byte - (const char *) p; ++ packet->new_auth_protocol = mnd_pestrndup((char *) p, packet->new_auth_protocol_len, FALSE); ++ p = (zend_uchar *) auth_protocol_nul_byte + 1; /* eat the '\0' */ + packet->new_auth_protocol_data_len = packet->header.size - (size_t) (p - buf); + if (packet->new_auth_protocol_data_len) { + packet->new_auth_protocol_data = mnd_emalloc(packet->new_auth_protocol_data_len); +@@ -2074,9 +2148,8 @@ php_mysqlnd_chg_user_read(MYSQLND_CONN_D + + DBG_RETURN(PASS); + premature_end: +- DBG_ERR_FMT("CHANGE_USER packet %d bytes shorter than expected", p - begin - packet->header.size); +- php_error_docref(NULL, E_WARNING, "CHANGE_USER packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected", +- p - begin - packet->header.size); ++ DBG_ERR_FMT("CHANGE_USER packet shorter than expected"); ++ php_error_docref(NULL, E_WARNING, "CHANGE_USER packet shorter than expected"); + DBG_RETURN(FAIL); + } + /* }}} */ +@@ -2146,10 +2219,10 @@ php_mysqlnd_sha256_pk_request_response_r + if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, sizeof(buf), "SHA256_PK_REQUEST_RESPONSE", PROT_SHA256_PK_REQUEST_RESPONSE_PACKET)) { + DBG_RETURN(FAIL); + } +- BAIL_IF_NO_MORE_DATA; ++ BAIL_IF_NOT_ENOUGH_DATA; + + p++; +- BAIL_IF_NO_MORE_DATA; ++ BAIL_IF_NOT_ENOUGH_DATA; + + packet->public_key_len = packet->header.size - (p - buf); + packet->public_key = mnd_emalloc(packet->public_key_len + 1); +@@ -2159,9 +2232,8 @@ php_mysqlnd_sha256_pk_request_response_r + DBG_RETURN(PASS); + + premature_end: +- DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin - packet->header.size); +- php_error_docref(NULL, E_WARNING, "SHA256_PK_REQUEST_RESPONSE packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected", +- p - begin - packet->header.size); ++ DBG_ERR_FMT("OK packet shorter than expected"); ++ php_error_docref(NULL, E_WARNING, "SHA256_PK_REQUEST_RESPONSE packet shorter than expected"); + DBG_RETURN(FAIL); + } + /* }}} */ +@@ -2223,11 +2295,11 @@ php_mysqlnd_cached_sha2_result_read(MYSQ + if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, sizeof(buf), "PROT_CACHED_SHA2_RESULT_PACKET", PROT_CACHED_SHA2_RESULT_PACKET)) { + DBG_RETURN(FAIL); + } +- BAIL_IF_NO_MORE_DATA; ++ BAIL_IF_NOT_ENOUGH_DATA; + + packet->response_code = uint1korr(p); + p++; +- BAIL_IF_NO_MORE_DATA; ++ BAIL_IF_NOT_ENOUGH_DATA; + + if (ERROR_MARKER == packet->response_code) { + php_mysqlnd_read_error_from_line(p, packet->header.size - 1, +@@ -2239,9 +2311,14 @@ php_mysqlnd_cached_sha2_result_read(MYSQ + if (0xFE == packet->response_code) { + /* Authentication Switch Response */ + if (packet->header.size > (size_t) (p - buf)) { +- packet->new_auth_protocol = mnd_pestrdup((char *)p, FALSE); +- packet->new_auth_protocol_len = strlen(packet->new_auth_protocol); +- p+= packet->new_auth_protocol_len + 1; /* +1 for the \0 */ ++ /* The plugin name MUST be NUL terminated, search for a NUL byte in the remaining space. */ ++ const char *auth_protocol_nul_byte = memchr(p, '\0', packet->header.size - (p - buf)); ++ if (!auth_protocol_nul_byte) { ++ BAIL_PREMATURE_END; ++ } ++ packet->new_auth_protocol_len = auth_protocol_nul_byte - (const char *) p; ++ packet->new_auth_protocol = mnd_pestrndup((char *) p, packet->new_auth_protocol_len, FALSE); ++ p = (zend_uchar *) auth_protocol_nul_byte + 1; /* eat the '\0' */ + + packet->new_auth_protocol_data_len = packet->header.size - (size_t) (p - buf); + if (packet->new_auth_protocol_data_len) { +@@ -2258,20 +2335,27 @@ php_mysqlnd_cached_sha2_result_read(MYSQ + DBG_ERR_FMT("Unexpected response code %d", packet->response_code); + } + +- /* This is not really the response code, but we reuse the field. */ ++ BAIL_IF_NOT_ENOUGH_DATA; ++ ++ /* This is not really the response code, but we reuse the field. This should be either 0x03 if ++ * fast auth is used or 0x04 if full auth should be done. */ + packet->response_code = uint1korr(p); +- p++; +- BAIL_IF_NO_MORE_DATA; + +- packet->result = uint1korr(p); +- BAIL_IF_NO_MORE_DATA; ++ /* This should be removed in master and it is really kept for just in case scenario that should ++ * never happen because mysql-server sends only byte that is stored above. The result seems not ++ * to be used so there is not much point to set it in any case. */ ++ if (UNEXPECTED((size_t)(p - begin) + 2 <= packet->header.size)) { ++ p++; ++ packet->result = uint1korr(p); ++ } else { ++ packet->result = 0; ++ } + + DBG_RETURN(PASS); + + premature_end: +- DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin - packet->header.size); +- php_error_docref(NULL, E_WARNING, "SHA256_PK_REQUEST_RESPONSE packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected", +- p - begin - packet->header.size); ++ DBG_ERR_FMT("OK packet shorter than expected"); ++ php_error_docref(NULL, E_WARNING, "SHA256_PK_REQUEST_RESPONSE packet shorter than expected"); + DBG_RETURN(FAIL); + } + +Index: php-7.4.33/ext/mysqlnd/mysqlnd_wireprotocol.h +=================================================================== +--- php-7.4.33.orig/ext/mysqlnd/mysqlnd_wireprotocol.h ++++ php-7.4.33/ext/mysqlnd/mysqlnd_wireprotocol.h +@@ -299,9 +299,19 @@ typedef struct st_mysqlnd_packet_cached_ + unsigned int error_no; + } MYSQLND_PACKET_CACHED_SHA2_RESULT; + ++/* The following structure implements an optional value, ++ * which forces the caller to check if the value was correctly read, for safety reasons. */ + ++typedef struct st_mysqlnd_optional_uint64_t { ++ uint64_t value; ++ zend_bool has_value; ++} MYSQLND_OPTIONAL_UINT64_T; + +-zend_ulong php_mysqlnd_net_field_length(const zend_uchar **packet); ++/* must not be equal to MYSQLND_NULL_LENGTH, but larger than 2**24 */ ++#define MYSQLND_INVALID_NET_FIELD_LENGTH ((zend_ulong) -2) ++ ++/* Returns MYSQLND_INVALID_NET_FIELD_LENGTH on error */ ++zend_ulong php_mysqlnd_net_field_length(const zend_uchar **packet, size_t remaining_size); + zend_uchar * php_mysqlnd_net_store_length(zend_uchar *packet, const uint64_t length); + size_t php_mysqlnd_net_store_length_size(uint64_t length); +
View file
php7-CVE-2025-1219.patch
Added
@@ -0,0 +1,89 @@ +Index: php-7.4.33/ext/libxml/libxml.c +=================================================================== +--- php-7.4.33.orig/ext/libxml/libxml.c ++++ php-7.4.33/ext/libxml/libxml.c +@@ -420,42 +420,53 @@ php_libxml_input_buffer_create_filename( + if (Z_TYPE(s->wrapperdata) == IS_ARRAY) { + zval *header; + +- ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL(s->wrapperdata), header) { ++ /* Scan backwards: The header array might contain the headers for multiple responses, if ++ * a redirect was followed. ++ */ ++ ZEND_HASH_REVERSE_FOREACH_VAL_IND(Z_ARRVAL(s->wrapperdata), header) { + const char buf = "Content-Type:"; +- if (Z_TYPE_P(header) == IS_STRING && +- !zend_binary_strncasecmp(Z_STRVAL_P(header), Z_STRLEN_P(header), buf, sizeof(buf)-1, sizeof(buf)-1)) { +- char *needle = estrdup("charset="); +- char *haystack = estrndup(Z_STRVAL_P(header), Z_STRLEN_P(header)); +- char *encoding = php_stristr(haystack, needle, Z_STRLEN_P(header), sizeof("charset=")-1); ++ if (Z_TYPE_P(header) == IS_STRING) { ++ /* If no colon is found in the header, we assume it's the HTTP status line and bail out. */ ++ char *colon = memchr(Z_STRVAL_P(header), ':', Z_STRLEN_P(header)); ++ char *space = memchr(Z_STRVAL_P(header), ' ', Z_STRLEN_P(header)); ++ if (colon == NULL || space < colon) { ++ break; ++ } ++ ++ if (!zend_binary_strncasecmp(Z_STRVAL_P(header), Z_STRLEN_P(header), buf, sizeof(buf)-1, sizeof(buf)-1)) { ++ char *needle = estrdup("charset="); ++ char *haystack = estrndup(Z_STRVAL_P(header), Z_STRLEN_P(header)); ++ char *encoding = php_stristr(haystack, needle, Z_STRLEN_P(header), sizeof("charset=")-1); + +- if (encoding) { +- char *end; ++ if (encoding) { ++ char *end; + +- encoding += sizeof("charset=")-1; +- if (*encoding == '"') { +- encoding++; +- } +- end = strchr(encoding, ';'); +- if (end == NULL) { +- end = encoding + strlen(encoding); +- } +- end--; /* end == encoding-1 isn't a buffer underrun */ +- while (*end == ' ' || *end == '\t') { +- end--; +- } +- if (*end == '"') { +- end--; +- } +- if (encoding >= end) continue; +- *(end+1) = '\0'; +- enc = xmlParseCharEncoding(encoding); +- if (enc <= XML_CHAR_ENCODING_NONE) { +- enc = XML_CHAR_ENCODING_NONE; ++ encoding += sizeof("charset=")-1; ++ if (*encoding == '"') { ++ encoding++; ++ } ++ end = strchr(encoding, ';'); ++ if (end == NULL) { ++ end = encoding + strlen(encoding); ++ } ++ end--; /* end == encoding-1 isn't a buffer underrun */ ++ while (*end == ' ' || *end == '\t') { ++ end--; ++ } ++ if (*end == '"') { ++ end--; ++ } ++ if (encoding >= end) continue; ++ *(end+1) = '\0'; ++ enc = xmlParseCharEncoding(encoding); ++ if (enc <= XML_CHAR_ENCODING_NONE) { ++ enc = XML_CHAR_ENCODING_NONE; ++ } + } ++ efree(haystack); ++ efree(needle); ++ break; /* found content-type */ + } +- efree(haystack); +- efree(needle); +- break; /* found content-type */ + } + } ZEND_HASH_FOREACH_END(); + }
View file
php7-CVE-2025-1220.patch
Added
@@ -0,0 +1,89 @@ +From 27e67cc3712ce0bc94fd4b2bfbb7155d89ec52d6 Mon Sep 17 00:00:00 2001 +From: Jakub Zelenka <bukka@php.net> +Date: Thu, 10 Apr 2025 15:15:36 +0200 +Subject: PATCH Fix GHSA-3cr5-j632-f35r: Null byte in hostnames + +This fixes stream_socket_client() and fsockopen(). + +Specifically it adds a check to parse_ip_address_ex and it also makes +sure that the \0 is not ignored in fsockopen() hostname formatting. +--- + ext/standard/fsock.c | 27 +++++++++++++++++-- + .../tests/network/ghsa-3cr5-j632-f35r.phpt | 21 +++++++++++++++ + .../tests/streams/ghsa-3cr5-j632-f35r.phpt | 26 ++++++++++++++++++ + main/streams/xp_socket.c | 9 ++++--- + 4 files changed, 78 insertions(+), 5 deletions(-) + create mode 100644 ext/standard/tests/network/ghsa-3cr5-j632-f35r.phpt + create mode 100644 ext/standard/tests/streams/ghsa-3cr5-j632-f35r.phpt + +Index: php-7.4.33/ext/standard/fsock.c +=================================================================== +--- php-7.4.33.orig/ext/standard/fsock.c ++++ php-7.4.33/ext/standard/fsock.c +@@ -25,6 +25,28 @@ + #include "php_network.h" + #include "file.h" + ++static size_t php_fsockopen_format_host_port(char **message, const char *prefix, size_t prefix_len, ++ const char *host, size_t host_len, zend_long port) ++{ ++ char portbuf32; ++ int portlen = snprintf(portbuf, sizeof(portbuf), ":" ZEND_LONG_FMT, port); ++ size_t total_len = prefix_len + host_len + portlen; ++ ++ char *result = emalloc(total_len + 1); ++ ++ if (prefix_len > 0) { ++ memcpy(result, prefix, prefix_len); ++ } ++ memcpy(result + prefix_len, host, host_len); ++ memcpy(result + prefix_len + host_len, portbuf, portlen); ++ ++ resulttotal_len = '\0'; ++ ++ *message = result; ++ ++ return total_len; ++} ++ + /* {{{ php_fsockopen() */ + + static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent) +@@ -59,11 +81,12 @@ static void php_fsockopen_stream(INTERNA + ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); + + if (persistent) { +- spprintf(&hashkey, 0, "pfsockopen__%s:" ZEND_LONG_FMT, host, port); ++ php_fsockopen_format_host_port(&hashkey, "pfsockopen__", strlen("pfsockopen__"), host, ++ host_len, port); + } + + if (port > 0) { +- hostname_len = spprintf(&hostname, 0, "%s:" ZEND_LONG_FMT, host, port); ++ hostname_len = php_fsockopen_format_host_port(&hostname, "", 0, host, host_len, port); + } else { + hostname_len = host_len; + hostname = host; +Index: php-7.4.33/main/streams/xp_socket.c +=================================================================== +--- php-7.4.33.orig/main/streams/xp_socket.c ++++ php-7.4.33/main/streams/xp_socket.c +@@ -580,12 +580,15 @@ static inline char *parse_ip_address_ex( + char *colon; + char *host = NULL; + +-#ifdef HAVE_IPV6 +- char *p; ++ if (memchr(str, '\0', str_len)) { ++ *err = strpprintf(0, "The hostname must not contain null bytes", str); ++ return NULL; ++ } + ++#ifdef HAVE_IPV6 + if (*(str) == '' && str_len > 1) { + /* IPV6 notation to specify raw address with port (i.e. fe80::1:80) */ +- p = memchr(str + 1, '', str_len - 2); ++ char *p = memchr(str + 1, '', str_len - 2); + if (!p || *(p + 1) != ':') { + if (get_err) { + *err = strpprintf(0, "Failed to parse IPv6 address \"%s\"", str);
View file
php7-CVE-2025-14178.patch
Added
@@ -0,0 +1,25 @@ +Index: php-7.4.33/ext/standard/array.c +=================================================================== +--- php-7.4.33.orig/ext/standard/array.c ++++ php-7.4.33/ext/standard/array.c +@@ -3813,7 +3813,7 @@ static zend_always_inline void php_array + int argc, i; + zval *src_entry; + HashTable *src, *dest; +- uint32_t count = 0; ++ uint64_t count = 0; + + ZEND_PARSE_PARAMETERS_START(0, -1) + Z_PARAM_VARIADIC('+', args, argc) +@@ -3833,6 +3833,11 @@ static zend_always_inline void php_array + count += zend_hash_num_elements(Z_ARRVAL_P(arg)); + } + ++ if (UNEXPECTED(count >= HT_MAX_SIZE)) { ++ zend_throw_error(NULL, "The total number of elements must be lower than %u", HT_MAX_SIZE); ++ RETURN_NULL(); ++ } ++ + if (argc == 2) { + zval *ret = NULL; +
View file
php7-CVE-2025-14181.patch
Added
@@ -0,0 +1,83 @@ +From e01f6fad9f4d10d3cda37a07f6e5d1619944dafc Mon Sep 17 00:00:00 2001 +From: Nora Dossche <7771979+ndossche@users.noreply.github.com> +Date: Sun, 13 Sep 2026 18:30:55 +0200 +Subject: PATCH Fix GHSA-cj93-vc83-wgqv + +Co-authored-by: Jakub Zelenka <bukka@php.net> +--- + ext/soap/php_http.c | 19 ++- + ext/soap/tests/bugs/GHSA-cj93-vc83-wgqv.phpt | 155 +++++++++++++++++++ + 2 files changed, 167 insertions(+), 7 deletions(-) + create mode 100644 ext/soap/tests/bugs/GHSA-cj93-vc83-wgqv.phpt + +Index: php-7.4.33/ext/soap/php_http.c +=================================================================== +--- php-7.4.33.orig/ext/soap/php_http.c ++++ php-7.4.33/ext/soap/php_http.c +@@ -1135,7 +1135,7 @@ try_again: + char *t = ZSTR_VAL(phpurl->path); + char *p = strrchr(t, '/'); + if (p) { +- zend_string *s = zend_string_alloc((p - t) + ZSTR_LEN(new_url->path) + 2, 0); ++ zend_string *s = zend_string_safe_alloc(1, p - t, ZSTR_LEN(new_url->path) + 2, 0); + strncpy(ZSTR_VAL(s), t, (p - t) + 1); + ZSTR_VAL(s)(p - t) + 1 = 0; + strcat(ZSTR_VAL(s), ZSTR_VAL(new_url->path)); +@@ -1428,7 +1428,8 @@ static zend_string* get_http_body(php_st + { + zend_string *http_buf = NULL; + char *header; +- int header_close = close, header_chunked = 0, header_length = 0, http_buf_size = 0; ++ int header_close = close, header_chunked = 0, header_length = 0; ++ size_t http_buf_size = 0; + + if (!close) { + header = get_http_header_value(headers, "Connection: "); +@@ -1458,14 +1459,14 @@ static zend_string* get_http_body(php_st + done = FALSE; + + while (!done) { +- int buf_size = 0; ++ unsigned int buf_size = 0; + + php_stream_gets(stream, headerbuf, sizeof(headerbuf)); + if (sscanf(headerbuf, "%x", &buf_size) > 0 ) { + if (buf_size > 0) { + size_t len_size = 0; + +- if (http_buf_size + buf_size + 1 < 0) { ++ if (buf_size >= ZSTR_MAX_LEN - http_buf_size) { + if (http_buf) { + zend_string_release_ex(http_buf, 0); + } +@@ -1473,7 +1474,7 @@ static zend_string* get_http_body(php_st + } + + if (http_buf) { +- http_buf = zend_string_realloc(http_buf, http_buf_size + buf_size, 0); ++ http_buf = zend_string_safe_realloc(http_buf, 1, http_buf_size, buf_size, 0); + } else { + http_buf = zend_string_alloc(buf_size, 0); + } +@@ -1532,7 +1533,7 @@ static zend_string* get_http_body(php_st + } + + } else if (header_length) { +- if (header_length < 0 || header_length >= INT_MAX) { ++ if (header_length < 0 || header_length >= ZSTR_MAX_LEN) { + return NULL; + } + http_buf = zend_string_alloc(header_length, 0); +@@ -1547,7 +1548,11 @@ static zend_string* get_http_body(php_st + do { + ssize_t len_read; + if (http_buf) { +- http_buf = zend_string_realloc(http_buf, http_buf_size + 4096, 0); ++ if (UNEXPECTED(http_buf_size >= ZSTR_MAX_LEN - 4096)) { ++ zend_string_efree(http_buf); ++ return NULL; ++ } ++ http_buf = zend_string_realloc(http_buf, http_buf_size + 4096, 0); + } else { + http_buf = zend_string_alloc(4096, 0); + }
View file
php7-CVE-2025-1734.patch
Added
@@ -0,0 +1,126 @@ +From 0548c4c1756724a89ef8310709419b08aadb2b3b Mon Sep 17 00:00:00 2001 +From: Jakub Zelenka <bukka@php.net> +Date: Sun, 19 Jan 2025 17:49:53 +0100 +Subject: PATCH Fix GHSA-pcmh-g36c-qc44: http headers without colon +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The header line must contain colon otherwise it is invalid and it needs +to fail. + +Reviewed-by: Tim Düsterhus <tim@tideways-gmbh.com> +--- + ext/standard/http_fopen_wrapper.c | 51 ++++++++++++++----- + ext/standard/tests/http/bug47021.phpt | 22 ++++---- + ext/standard/tests/http/bug75535.phpt | 4 +- + .../tests/http/ghsa-pcmh-g36c-qc44-001.phpt | 51 +++++++++++++++++++ + .../tests/http/ghsa-pcmh-g36c-qc44-002.phpt | 51 +++++++++++++++++++ + 5 files changed, 154 insertions(+), 25 deletions(-) + create mode 100644 ext/standard/tests/http/ghsa-pcmh-g36c-qc44-001.phpt + create mode 100644 ext/standard/tests/http/ghsa-pcmh-g36c-qc44-002.phpt + +Index: php-7.4.33/ext/standard/http_fopen_wrapper.c +=================================================================== +--- php-7.4.33.orig/ext/standard/http_fopen_wrapper.c ++++ php-7.4.33/ext/standard/http_fopen_wrapper.c +@@ -136,6 +136,7 @@ static zend_bool check_has_header(const + typedef struct _php_stream_http_response_header_info { + php_stream_filter *transfer_encoding; + size_t file_size; ++ bool error; + bool follow_location; + char locationHTTP_HEADER_BLOCK_SIZE; + } php_stream_http_response_header_info; +@@ -145,6 +146,7 @@ static void php_stream_http_response_hea + { + header_info->transfer_encoding = NULL; + header_info->file_size = 0; ++ header_info->error = false; + header_info->follow_location = 1; + header_info->location0 = '\0'; + } +@@ -182,10 +184,11 @@ static bool php_stream_http_response_hea + /* Process folding headers of the current line and if there are none, parse last full response + * header line. It returns NULL if the last header is finished, otherwise it returns updated + * last header line. */ +-static zend_string *php_stream_http_response_headers_parse(php_stream *stream, +- php_stream_context *context, int options, zend_string *last_header_line_str, +- char *header_line, size_t *header_line_length, int response_code, +- zval *response_header, php_stream_http_response_header_info *header_info) ++static zend_string *php_stream_http_response_headers_parse(php_stream_wrapper *wrapper, ++ php_stream *stream, php_stream_context *context, int options, ++ zend_string *last_header_line_str, char *header_line, size_t *header_line_length, ++ int response_code, zval *response_header, ++ php_stream_http_response_header_info *header_info) + { + char *last_header_line = ZSTR_VAL(last_header_line_str); + size_t last_header_line_length = ZSTR_LEN(last_header_line_str); +@@ -227,6 +230,19 @@ static zend_string *php_stream_http_resp + /* Find header separator position. */ + char *last_header_value = memchr(last_header_line, ':', last_header_line_length); + if (last_header_value) { ++ /* Verify there is no space in header name */ ++ char *last_header_name = last_header_line + 1; ++ while (last_header_name < last_header_value) { ++ if (*last_header_name == ' ' || *last_header_name == '\t') { ++ header_info->error = true; ++ php_stream_wrapper_log_error(wrapper, options, ++ "HTTP invalid response format (space in header name)!"); ++ zend_string_efree(last_header_line_str); ++ return NULL; ++ } ++ ++last_header_name; ++ } ++ + last_header_value++; /* Skip ':'. */ + + /* Strip leading whitespace. */ +@@ -235,9 +251,12 @@ static zend_string *php_stream_http_resp + last_header_value++; + } + } else { +- /* There is no colon. Set the value to the end of the header line, which is effectively +- * an empty string. */ +- last_header_value = last_header_line_end; ++ /* There is no colon which means invalid response so error. */ ++ header_info->error = true; ++ php_stream_wrapper_log_error(wrapper, options, ++ "HTTP invalid response format (no colon in header line)!"); ++ zend_string_efree(last_header_line_str); ++ return NULL; + } + + bool store_header = true; +@@ -943,10 +962,16 @@ finish: + + if (last_header_line_str != NULL) { + /* Parse last header line. */ +- last_header_line_str = php_stream_http_response_headers_parse(stream, context, +- options, last_header_line_str, http_header_line, &http_header_line_length, +- response_code, response_header, &header_info); +- if (last_header_line_str != NULL) { ++ last_header_line_str = php_stream_http_response_headers_parse(wrapper, stream, ++ context, options, last_header_line_str, http_header_line, ++ &http_header_line_length, response_code, response_header, &header_info); ++ if (EXPECTED(last_header_line_str == NULL)) { ++ if (UNEXPECTED(header_info.error)) { ++ php_stream_close(stream); ++ stream = NULL; ++ goto out; ++ } ++ } else { + /* Folding header present so continue. */ + continue; + } +@@ -976,8 +1001,8 @@ finish: + + /* If the stream was closed early, we still want to process the last line to keep BC. */ + if (last_header_line_str != NULL) { +- php_stream_http_response_headers_parse(stream, context, options, last_header_line_str, +- NULL, NULL, response_code, response_header, &header_info); ++ php_stream_http_response_headers_parse(wrapper, stream, context, options, ++ last_header_line_str, NULL, NULL, response_code, response_header, &header_info); + } + + if (!reqok || (header_info.location0 != '\0' && header_info.follow_location)) {
View file
php7-CVE-2025-1735.patch
Added
@@ -0,0 +1,354 @@ +From a2cdff5583ad2bfe9a27fba71e2b1fc423296dc0 Mon Sep 17 00:00:00 2001 +From: Jakub Zelenka <bukka@php.net> +Date: Tue, 4 Mar 2025 17:23:01 +0100 +Subject: PATCH Fix GHSA-hrwm-9436-5mv3: pgsql escaping no error checks + +This adds error checks for escape function is pgsql and pdo_pgsql +extensions. It prevents possibility of storing not properly escaped +data which could potentially lead to some security issues. +--- + ext/pdo_pgsql/pgsql_driver.c | 10 +- + ext/pdo_pgsql/tests/ghsa-hrwm-9436-5mv3.phpt | 24 ++++ + ext/pgsql/pgsql.c | 126 ++++++++++++++++--- + ext/pgsql/tests/ghsa-hrwm-9436-5mv3.phpt | 64 ++++++++++ + 4 files changed, 203 insertions(+), 21 deletions(-) + create mode 100644 ext/pdo_pgsql/tests/ghsa-hrwm-9436-5mv3.phpt + create mode 100644 ext/pgsql/tests/ghsa-hrwm-9436-5mv3.phpt + +Index: php-7.4.33/ext/pdo_pgsql/pgsql_driver.c +=================================================================== +--- php-7.4.33.orig/ext/pdo_pgsql/pgsql_driver.c ++++ php-7.4.33/ext/pdo_pgsql/pgsql_driver.c +@@ -323,11 +323,15 @@ static int pgsql_handle_quoter(pdo_dbh_t + unsigned char *escaped; + pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data; + size_t tmp_len; ++ int err; + + switch (paramtype) { + case PDO_PARAM_LOB: + /* escapedlen returned by PQescapeBytea() accounts for trailing 0 */ + escaped = PQescapeByteaConn(H->server, (unsigned char *)unquoted, unquotedlen, &tmp_len); ++ if (escaped == NULL) { ++ return NULL; ++ } + *quotedlen = tmp_len + 1; + *quoted = emalloc(*quotedlen + 1); + memcpy((*quoted)+1, escaped, *quotedlen-2); +@@ -339,7 +343,11 @@ static int pgsql_handle_quoter(pdo_dbh_t + default: + *quoted = safe_emalloc(2, unquotedlen, 3); + (*quoted)0 = '\''; +- *quotedlen = PQescapeStringConn(H->server, *quoted + 1, unquoted, unquotedlen, NULL); ++ *quotedlen = PQescapeStringConn(H->server, *quoted + 1, unquoted, unquotedlen, &err); ++ if (err) { ++ efree(quoted); ++ return NULL; ++ } + (*quoted)*quotedlen + 1 = '\''; + (*quoted)*quotedlen + 2 = '\0'; + *quotedlen += 2; +Index: php-7.4.33/ext/pgsql/pgsql.c +=================================================================== +--- php-7.4.33.orig/ext/pgsql/pgsql.c ++++ php-7.4.33/ext/pgsql/pgsql.c +@@ -4393,10 +4393,16 @@ PHP_FUNCTION(pg_escape_string) + to = zend_string_safe_alloc(ZSTR_LEN(from), 2, 0, 0); + #ifdef HAVE_PQESCAPE_CONN + if (link) { ++ int err; + if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) { + RETURN_FALSE; + } +- ZSTR_LEN(to) = PQescapeStringConn(pgsql, ZSTR_VAL(to), ZSTR_VAL(from), ZSTR_LEN(from), NULL); ++ ZSTR_LEN(to) = PQescapeStringConn(pgsql, ZSTR_VAL(to), ZSTR_VAL(from), ZSTR_LEN(from), &err); ++ if (err) { ++ zend_argument_value_error(ZEND_NUM_ARGS(), "Escaping string failed"); ++ zend_string_efree(to); ++ RETURN_THROWS(); ++ } + } else + #endif + { +@@ -4446,6 +4452,11 @@ PHP_FUNCTION(pg_escape_bytea) + #endif + to = (char *)PQescapeBytea((unsigned char*)from, from_len, &to_len); + ++ if (to == NULL) { ++ zend_argument_value_error(ZEND_NUM_ARGS(), "Escape failure"); ++ RETURN_THROWS(); ++ } ++ + RETVAL_STRINGL(to, to_len-1); /* to_len includes additional '\0' */ + PQfreemem(to); + } +@@ -5529,7 +5540,7 @@ PHP_PGSQL_API int php_pgsql_meta_data(PG + char *escaped; + smart_str querystr = {0}; + size_t new_len; +- int i, num_rows; ++ int i, num_rows, err; + zval elem; + + if (!*table_name) { +@@ -5570,7 +5581,14 @@ PHP_PGSQL_API int php_pgsql_meta_data(PG + "WHERE a.attnum > 0 AND c.relname = '"); + } + escaped = (char *)safe_emalloc(strlen(tmp_name2), 2, 1); +- new_len = PQescapeStringConn(pg_link, escaped, tmp_name2, strlen(tmp_name2), NULL); ++ new_len = PQescapeStringConn(pg_link, escaped, tmp_name2, strlen(tmp_name2), &err); ++ if (err) { ++ php_error_docref(NULL, E_WARNING, "Escaping table name '%s' failed", table_name); ++ efree(src); ++ efree(escaped); ++ smart_str_free(&querystr); ++ return FAILURE; ++ } + if (new_len) { + smart_str_appendl(&querystr, escaped, new_len); + } +@@ -5578,7 +5596,14 @@ PHP_PGSQL_API int php_pgsql_meta_data(PG + + smart_str_appends(&querystr, "' AND n.nspname = '"); + escaped = (char *)safe_emalloc(strlen(tmp_name), 2, 1); +- new_len = PQescapeStringConn(pg_link, escaped, tmp_name, strlen(tmp_name), NULL); ++ new_len = PQescapeStringConn(pg_link, escaped, tmp_name, strlen(tmp_name), &err); ++ if (err) { ++ php_error_docref(NULL, E_WARNING, "Escaping table namespace '%s' failed", table_name); ++ efree(src); ++ efree(escaped); ++ smart_str_free(&querystr); ++ return FAILURE; ++ } + if (new_len) { + smart_str_appendl(&querystr, escaped, new_len); + } +@@ -5850,7 +5875,7 @@ PHP_PGSQL_API int php_pgsql_convert(PGco + { + zend_string *field = NULL; + zval meta, *def, *type, *not_null, *has_default, *is_enum, *val, new_val; +- int err = 0, skip_field; ++ int err = 0, escape_err = 0, skip_field; + php_pgsql_data_type data_type; + + assert(pg_link != NULL); +@@ -6101,10 +6126,16 @@ PHP_PGSQL_API int php_pgsql_convert(PGco + /* PostgreSQL ignores \0 */ + str = zend_string_alloc(Z_STRLEN_P(val) * 2, 0); + /* better to use PGSQLescapeLiteral since PGescapeStringConn does not handle special \ */ +- ZSTR_LEN(str) = PQescapeStringConn(pg_link, ZSTR_VAL(str), Z_STRVAL_P(val), Z_STRLEN_P(val), NULL); +- str = zend_string_truncate(str, ZSTR_LEN(str), 0); +- ZVAL_NEW_STR(&new_val, str); +- php_pgsql_add_quotes(&new_val, 1); ++ ZSTR_LEN(str) = PQescapeStringConn(pg_link, ZSTR_VAL(str), ++ Z_STRVAL_P(val), Z_STRLEN_P(val), &escape_err); ++ if (escape_err) { ++ err = 1; ++ } else { ++ str = zend_string_truncate(str, ZSTR_LEN(str), 0); ++ ZVAL_NEW_STR(&new_val, str); ++ php_pgsql_add_quotes(&new_val, 1); ++ } ++ + } + break; + +@@ -6126,7 +6157,15 @@ PHP_PGSQL_API int php_pgsql_convert(PGco + } + PGSQL_CONV_CHECK_IGNORE(); + if (err) { +- php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field)); ++ if (escape_err) { ++ php_error_docref(NULL, E_NOTICE, ++ "String value escaping failed for PostgreSQL '%s' (%s)", ++ Z_STRVAL_P(type), ZSTR_VAL(field)); ++ } else { ++ php_error_docref(NULL, E_NOTICE, ++ "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", ++ Z_STRVAL_P(type), ZSTR_VAL(field)); ++ } + } + break; + +@@ -6406,6 +6445,12 @@ PHP_PGSQL_API int php_pgsql_convert(PGco + #else + tmp = PQescapeBytea(Z_STRVAL_P(val), (unsigned char *)Z_STRLEN_P(val), &to_len); + #endif ++ if (tmp == NULL) { ++ php_error_docref(NULL, E_NOTICE, "Escaping value failed for %s field (%s)", Z_STRVAL_P(type), ZSTR_VAL(field)); ++ err = 1; ++ break; ++ } ++ + ZVAL_STRINGL(&new_val, (char *)tmp, to_len - 1); /* PQescapeBytea's to_len includes additional '\0' */ + PQfreemem(tmp); + php_pgsql_add_quotes(&new_val, 1); +@@ -6488,6 +6533,12 @@ PHP_PGSQL_API int php_pgsql_convert(PGco + zend_hash_update(Z_ARRVAL_P(result), field, &new_val); + } else { + char *escaped = PGSQLescapeIdentifier(pg_link, ZSTR_VAL(field), ZSTR_LEN(field)); ++ if (escaped == NULL) { ++ /* This cannot fail because of invalid string but only due to failed memory allocation */ ++ php_error_docref(NULL, E_NOTICE, "Escaping field '%s' failed", ZSTR_VAL(field)); ++ err = 1; ++ break; ++ } + add_assoc_zval(result, escaped, &new_val); + PGSQLfree(escaped); + } +@@ -6566,7 +6617,7 @@ static int do_exec(smart_str *querystr, + } + /* }}} */ + +-static inline void build_tablename(smart_str *querystr, PGconn *pg_link, const char *table) /* {{{ */ ++static inline int build_tablename(smart_str *querystr, PGconn *pg_link, const char *table) /* {{{ */ + { + size_t table_len = strlen(table); + +@@ -6577,6 +6628,10 @@ static inline void build_tablename(smart + smart_str_appendl(querystr, table, len); + } else { + char *escaped = PGSQLescapeIdentifier(pg_link, table, len); ++ if (escaped == NULL) { ++ php_error_docref(NULL, E_NOTICE, "Failed to escape table name '%s'", table); ++ return FAILURE; ++ } + smart_str_appends(querystr, escaped); + PGSQLfree(escaped); + } +@@ -6589,11 +6644,17 @@ static inline void build_tablename(smart + smart_str_appendl(querystr, after_dot, len); + } else { + char *escaped = PGSQLescapeIdentifier(pg_link, after_dot, len); ++ if (escaped == NULL) { ++ php_error_docref(NULL, E_NOTICE, "Failed to escape table name '%s'", table); ++ return FAILURE; ++ } + smart_str_appendc(querystr, '.'); + smart_str_appends(querystr, escaped); + PGSQLfree(escaped); + } + } ++ ++ return SUCCESS; + } + /* }}} */ + +@@ -6615,7 +6676,9 @@ PHP_PGSQL_API int php_pgsql_insert(PGcon + ZVAL_UNDEF(&converted); + if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0) { + smart_str_appends(&querystr, "INSERT INTO "); +- build_tablename(&querystr, pg_link, table); ++ if (build_tablename(&querystr, pg_link, table) == FAILURE) { ++ goto cleanup; ++ } + smart_str_appends(&querystr, " DEFAULT VALUES"); + + goto no_values; +@@ -6631,7 +6694,9 @@ PHP_PGSQL_API int php_pgsql_insert(PGcon + } + + smart_str_appends(&querystr, "INSERT INTO "); +- build_tablename(&querystr, pg_link, table); ++ if (build_tablename(&querystr, pg_link, table) == FAILURE) { ++ goto cleanup; ++ } + smart_str_appends(&querystr, " ("); + + ZEND_HASH_FOREACH_STR_KEY(Z_ARRVAL_P(var_array), fld) { +@@ -6641,6 +6706,10 @@ PHP_PGSQL_API int php_pgsql_insert(PGcon + } + if (opt & PGSQL_DML_ESCAPE) { + tmp = PGSQLescapeIdentifier(pg_link, ZSTR_VAL(fld), ZSTR_LEN(fld) + 1); ++ if (tmp == NULL) { ++ php_error_docref(NULL, E_NOTICE, "Failed to escape field '%s'", ZSTR_VAL(fld)); ++ goto cleanup; ++ } + smart_str_appends(&querystr, tmp); + PGSQLfree(tmp); + } else { +@@ -6652,15 +6721,19 @@ PHP_PGSQL_API int php_pgsql_insert(PGcon + smart_str_appends(&querystr, ") VALUES ("); + + /* make values string */ +- ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(var_array), val) { ++ ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(var_array), fld, val) { + /* we can avoid the key_type check here, because we tested it in the other loop */ + switch (Z_TYPE_P(val)) { + case IS_STRING: + if (opt & PGSQL_DML_ESCAPE) { +- size_t new_len; +- char *tmp; +- tmp = (char *)safe_emalloc(Z_STRLEN_P(val), 2, 1); +- new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), NULL); ++ int error; ++ char *tmp = safe_emalloc(Z_STRLEN_P(val), 2, 1); ++ size_t new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), &error); ++ if (error) { ++ php_error_docref(NULL, E_NOTICE, "Failed to escape field '%s' value", ZSTR_VAL(fld)); ++ efree(tmp); ++ goto cleanup; ++ } + smart_str_appendc(&querystr, '\''); + smart_str_appendl(&querystr, tmp, new_len); + smart_str_appendc(&querystr, '\''); +@@ -6810,6 +6883,10 @@ static inline int build_assignment_strin + } + if (opt & PGSQL_DML_ESCAPE) { + char *tmp = PGSQLescapeIdentifier(pg_link, ZSTR_VAL(fld), ZSTR_LEN(fld) + 1); ++ if (tmp == NULL) { ++ php_error_docref(NULL, E_NOTICE, "Failed to escape field '%s'", ZSTR_VAL(fld)); ++ return -1; ++ } + smart_str_appends(querystr, tmp); + PGSQLfree(tmp); + } else { +@@ -6824,8 +6901,14 @@ static inline int build_assignment_strin + switch (Z_TYPE_P(val)) { + case IS_STRING: + if (opt & PGSQL_DML_ESCAPE) { ++ int error; + char *tmp = (char *)safe_emalloc(Z_STRLEN_P(val), 2, 1); +- size_t new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), NULL); ++ size_t new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), &error); ++ if (error) { ++ php_error_docref(NULL, E_NOTICE, "Failed to escape field '%s' value", ZSTR_VAL(fld)); ++ efree(tmp); ++ return -1; ++ } + smart_str_appendc(querystr, '\''); + smart_str_appendl(querystr, tmp, new_len); + smart_str_appendc(querystr, '\''); +@@ -6894,7 +6977,9 @@ PHP_PGSQL_API int php_pgsql_update(PGcon + } + + smart_str_appends(&querystr, "UPDATE "); +- build_tablename(&querystr, pg_link, table); ++ if (build_tablename(&querystr, pg_link, table) == FAILURE) { ++ goto cleanup; ++ } + smart_str_appends(&querystr, " SET "); + + if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(var_array), 0, ",", 1, opt)) +@@ -6992,7 +7077,9 @@ PHP_PGSQL_API int php_pgsql_delete(PGcon + } + + smart_str_appends(&querystr, "DELETE FROM "); +- build_tablename(&querystr, pg_link, table); ++ if (build_tablename(&querystr, pg_link, table) == FAILURE) { ++ goto cleanup; ++ } + smart_str_appends(&querystr, " WHERE "); + + if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt)) +@@ -7130,7 +7217,9 @@ PHP_PGSQL_API int php_pgsql_result2array + } + + smart_str_appends(&querystr, "SELECT * FROM "); +- build_tablename(&querystr, pg_link, table); ++ if (build_tablename(&querystr, pg_link, table) == FAILURE) { ++ goto cleanup; ++ } + smart_str_appends(&querystr, " WHERE "); + + if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt))
View file
php7-CVE-2025-1736.patch
Added
@@ -0,0 +1,13 @@ +Index: php-7.4.33/ext/standard/http_fopen_wrapper.c +=================================================================== +--- php-7.4.33.orig/ext/standard/http_fopen_wrapper.c ++++ php-7.4.33/ext/standard/http_fopen_wrapper.c +@@ -126,7 +126,7 @@ static inline void strip_header(char *he + static zend_bool check_has_header(const char *headers, const char *header) { + const char *s = headers; + while ((s = strstr(s, header))) { +- if (s == headers || *(s-1) == '\n') { ++ if (s == headers || (*(s-1) == '\n' && *(s-2) == '\r')) { + return 1; + } + s++;
View file
php7-CVE-2025-1861.patch
Added
@@ -0,0 +1,215 @@ +From ac1a054bb3eb5994a199e8b18cca28cbabf5943e Mon Sep 17 00:00:00 2001 +From: Jakub Zelenka <bukka@php.net> +Date: Tue, 4 Mar 2025 09:01:34 +0100 +Subject: PATCH Fix GHSA-52jp-hrpf-2jff: http redirect location truncation + +It converts the allocation of location to be on heap instead of stack +and errors if the location length is greater than 8086 bytes. +--- + ext/standard/http_fopen_wrapper.c | 87 ++++++++++++------- + .../tests/http/ghsa-52jp-hrpf-2jff-001.phpt | 58 +++++++++++++ + .../tests/http/ghsa-52jp-hrpf-2jff-002.phpt | 55 ++++++++++++ + 3 files changed, 168 insertions(+), 32 deletions(-) + create mode 100644 ext/standard/tests/http/ghsa-52jp-hrpf-2jff-001.phpt + create mode 100644 ext/standard/tests/http/ghsa-52jp-hrpf-2jff-002.phpt + +Index: php-7.4.33/ext/standard/http_fopen_wrapper.c +=================================================================== +--- php-7.4.33.orig/ext/standard/http_fopen_wrapper.c ++++ php-7.4.33/ext/standard/http_fopen_wrapper.c +@@ -70,15 +70,16 @@ + + #include "php_fopen_wrappers.h" + +-#define HTTP_HEADER_BLOCK_SIZE 1024 +-#define PHP_URL_REDIRECT_MAX 20 +-#define HTTP_HEADER_USER_AGENT 1 +-#define HTTP_HEADER_HOST 2 +-#define HTTP_HEADER_AUTH 4 +-#define HTTP_HEADER_FROM 8 +-#define HTTP_HEADER_CONTENT_LENGTH 16 +-#define HTTP_HEADER_TYPE 32 +-#define HTTP_HEADER_CONNECTION 64 ++#define HTTP_HEADER_BLOCK_SIZE 1024 ++#define HTTP_HEADER_MAX_LOCATION_SIZE 8182 /* 8192 - 10 (size of "Location: ") */ ++#define PHP_URL_REDIRECT_MAX 20 ++#define HTTP_HEADER_USER_AGENT 1 ++#define HTTP_HEADER_HOST 2 ++#define HTTP_HEADER_AUTH 4 ++#define HTTP_HEADER_FROM 8 ++#define HTTP_HEADER_CONTENT_LENGTH 16 ++#define HTTP_HEADER_TYPE 32 ++#define HTTP_HEADER_CONNECTION 64 + + #define HTTP_WRAPPER_HEADER_INIT 1 + #define HTTP_WRAPPER_REDIRECTED 2 +@@ -138,17 +139,15 @@ typedef struct _php_stream_http_response + size_t file_size; + bool error; + bool follow_location; +- char locationHTTP_HEADER_BLOCK_SIZE; ++ char *location; ++ size_t location_len; + } php_stream_http_response_header_info; + + static void php_stream_http_response_header_info_init( + php_stream_http_response_header_info *header_info) + { +- header_info->transfer_encoding = NULL; +- header_info->file_size = 0; +- header_info->error = false; ++ memset(header_info, 0, sizeof(php_stream_http_response_header_info)); + header_info->follow_location = 1; +- header_info->location0 = '\0'; + } + + /* Trim white spaces from response header line and update its length */ +@@ -274,7 +273,22 @@ static zend_string *php_stream_http_resp + * RFC 7238 defines 308: http://tools.ietf.org/html/rfc7238 */ + header_info->follow_location = 0; + } +- strlcpy(header_info->location, last_header_value, sizeof(header_info->location)); ++ size_t last_header_value_len = strlen(last_header_value); ++ if (last_header_value_len > HTTP_HEADER_MAX_LOCATION_SIZE) { ++ header_info->error = true; ++ php_stream_wrapper_log_error(wrapper, options, ++ "HTTP Location header size is over the limit of %d bytes", ++ HTTP_HEADER_MAX_LOCATION_SIZE); ++ zend_string_efree(last_header_line_str); ++ return NULL; ++ } ++ if (header_info->location_len == 0) { ++ header_info->location = emalloc(last_header_value_len + 1); ++ } else if (header_info->location_len <= last_header_value_len) { ++ header_info->location = erealloc(header_info->location, last_header_value_len + 1); ++ } ++ header_info->location_len = last_header_value_len; ++ memcpy(header_info->location, last_header_value, last_header_value_len + 1); + } else if (!strncasecmp(last_header_line, "Content-Type:", sizeof("Content-Type:")-1)) { + php_stream_notify_info(context, PHP_STREAM_NOTIFY_MIME_TYPE_IS, last_header_value, 0); + } else if (!strncasecmp(last_header_line, "Content-Length:", sizeof("Content-Length:")-1)) { +@@ -557,6 +571,8 @@ finish: + } + } + ++ php_stream_http_response_header_info_init(&header_info); ++ + if (stream == NULL) + goto out; + +@@ -934,8 +950,6 @@ finish: + } + } + +- php_stream_http_response_header_info_init(&header_info); +- + /* read past HTTP headers */ + while (!php_stream_eof(stream)) { + size_t http_header_line_length; +@@ -1005,29 +1019,28 @@ finish: + last_header_line_str, NULL, NULL, response_code, response_header, &header_info); + } + +- if (!reqok || (header_info.location0 != '\0' && header_info.follow_location)) { ++ if (!reqok || (header_info.location != NULL && header_info.follow_location)) { + if (!header_info.follow_location || (((options & STREAM_ONLY_GET_HEADERS) || ignore_errors) && redirect_max <= 1)) { + goto out; + } + +- if (header_info.location0 != '\0') ++ if (header_info.location != NULL) + php_stream_notify_info(context, PHP_STREAM_NOTIFY_REDIRECTED, header_info.location, 0); + + php_stream_close(stream); + stream = NULL; + +- if (header_info.location0 != '\0') { ++ if (header_info.location != NULL) { + +- char new_pathHTTP_HEADER_BLOCK_SIZE; +- char loc_pathHTTP_HEADER_BLOCK_SIZE; ++ char *new_path = NULL; + +- *new_path='\0'; + if (strlen(header_info.location) < 8 || + (strncasecmp(header_info.location, "http://", sizeof("http://")-1) && + strncasecmp(header_info.location, "https://", sizeof("https://")-1) && + strncasecmp(header_info.location, "ftp://", sizeof("ftp://")-1) && + strncasecmp(header_info.location, "ftps://", sizeof("ftps://")-1))) + { ++ char *loc_path = NULL; + if (*header_info.location != '/') { + if (*(header_info.location+1) != '\0' && resource->path) { + char *s = strrchr(ZSTR_VAL(resource->path), '/'); +@@ -1045,31 +1058,35 @@ finish: + if (resource->path && + ZSTR_VAL(resource->path)0 == '/' && + ZSTR_VAL(resource->path)1 == '\0') { +- snprintf(loc_path, sizeof(loc_path) - 1, "%s%s", +- ZSTR_VAL(resource->path), header_info.location); ++ spprintf(&loc_path, 0, "%s%s", ZSTR_VAL(resource->path), header_info.location); + } else { +- snprintf(loc_path, sizeof(loc_path) - 1, "%s/%s", +- ZSTR_VAL(resource->path), header_info.location); ++ spprintf(&loc_path, 0, "%s/%s", ZSTR_VAL(resource->path), header_info.location); + } + } else { +- snprintf(loc_path, sizeof(loc_path) - 1, "/%s", header_info.location); ++ spprintf(&loc_path, 0, "/%s", header_info.location); + } + } else { +- strlcpy(loc_path, header_info.location, sizeof(loc_path)); ++ loc_path = header_info.location; ++ header_info.location = NULL; + } + if ((use_ssl && resource->port != 443) || (!use_ssl && resource->port != 80)) { +- snprintf(new_path, sizeof(new_path) - 1, "%s://%s:%d%s", ZSTR_VAL(resource->scheme), ZSTR_VAL(resource->host), resource->port, loc_path); ++ spprintf(&new_path, 0, "%s://%s:%d%s", ZSTR_VAL(resource->scheme), ++ ZSTR_VAL(resource->host), resource->port, loc_path); + } else { +- snprintf(new_path, sizeof(new_path) - 1, "%s://%s%s", ZSTR_VAL(resource->scheme), ZSTR_VAL(resource->host), loc_path); ++ spprintf(&new_path, 0, "%s://%s%s", ZSTR_VAL(resource->scheme), ++ ZSTR_VAL(resource->host), loc_path); + } ++ efree(loc_path); + } else { +- strlcpy(new_path, header_info.location, sizeof(new_path)); ++ new_path = header_info.location; ++ header_info.location = NULL; + } + + php_url_free(resource); + /* check for invalid redirection URLs */ + if ((resource = php_url_parse(new_path)) == NULL) { + php_stream_wrapper_log_error(wrapper, options, "Invalid redirect URL! %s", new_path); ++ efree(new_path); + goto out; + } + +@@ -1081,6 +1098,7 @@ finish: + while (s < e) { \ + if (iscntrl(*s)) { \ + php_stream_wrapper_log_error(wrapper, options, "Invalid redirect URL! %s", new_path); \ ++ efree(new_path); \ + goto out; \ + } \ + s++; \ +@@ -1096,6 +1114,7 @@ finish: + stream = php_stream_url_wrap_http_ex( + wrapper, new_path, mode, options, opened_path, context, + --redirect_max, HTTP_WRAPPER_REDIRECTED, response_header STREAMS_CC); ++ efree(new_path); + } else { + php_stream_wrapper_log_error(wrapper, options, "HTTP request failed! %s", tmp_line); + } +@@ -1108,6 +1127,10 @@ out: + efree(http_header_line); + } + ++ if (header_info.location != NULL) { ++ efree(header_info.location); ++ } ++ + if (resource) { + php_url_free(resource); + }
View file
php7-CVE-2025-6491.patch
Added
@@ -0,0 +1,44 @@ +From 0298837252fda06e0f86be3dfe91f166f45e85d4 Mon Sep 17 00:00:00 2001 +From: Ahmed Lekssays <lekssaysahmed@gmail.com> +Date: Tue, 3 Jun 2025 09:00:55 +0000 +Subject: PATCH Fix GHSA-453j-q27h-5p8x + +Libxml versions prior to 2.13 cannot correctly handle a call to +xmlNodeSetName() with a name longer than 2G. It will leave the node +object in an invalid state with a NULL name. This later causes a NULL +pointer dereference when using the name during message serialization. + +To solve this, implement a workaround that resets the name to the +sentinel name if this situation arises. + +Versions of libxml of 2.13 and higher are not affected. + +This can be exploited if a SoapVar is created with a fully qualified +name that is longer than 2G. This would be possible if some application +code uses a namespace prefix from an untrusted source like from a remote +SOAP service. + +Co-authored-by: Niels Dossche <7771979+nielsdos@users.noreply.github.com> +--- + ext/soap/soap.c | 6 ++-- + ext/soap/tests/soap_qname_crash.phpt | 48 ++++++++++++++++++++++++++++ + 2 files changed, 52 insertions(+), 2 deletions(-) + create mode 100644 ext/soap/tests/soap_qname_crash.phpt + +Index: php-7.4.33/ext/soap/soap.c +=================================================================== +--- php-7.4.33.orig/ext/soap/soap.c ++++ php-7.4.33/ext/soap/soap.c +@@ -4457,8 +4457,10 @@ static xmlNodePtr serialize_zval(zval *v + } + xmlParam = master_to_xml(enc, val, style, parent); + zval_ptr_dtor(&defval); +- if (!strcmp((char*)xmlParam->name, "BOGUS")) { +- xmlNodeSetName(xmlParam, BAD_CAST(paramName)); ++ if (xmlParam != NULL) { ++ if (xmlParam->name == NULL || strcmp((char*)xmlParam->name, "BOGUS") == 0) { ++ xmlNodeSetName(xmlParam, BAD_CAST(paramName)); ++ } + } + return xmlParam; + }
View file
php7-CVE-2026-109618,109619.patch
Added
@@ -0,0 +1,936 @@ +From 712e60f9edfd03f0960fc4fc3c2c375f42b90aa2 Mon Sep 17 00:00:00 2001 +From: Arnaud Le Blanc <arnaud.lb@gmail.com> +Date: Sun, 18 Oct 2026 20:09:54 +0200 +Subject: PATCH Avoid state corruption via bailout + +Minimal mitigation for EOL version. + +Fix GHSA-w8hw-w9fx-j79w (CVE-2026-109618) +Fix GHSA-6wmf-4rv5-p3rp (CVE-2026-109619) + +Co-authored-by: Ilija Tovilo <ilija.tovilo@me.com> +--- + Zend/zend_API.h | 1 + + Zend/zend_alloc.c | 68 ++++++++++++++++++++--------- + Zend/zend_alloc.h | 2 + + Zend/zend_execute_API.c | 13 ++++++ + Zend/zend_hash.c | 13 ++++-- + Zend/zend_hash.h | 1 + + Zend/zend_llist.c | 2 + + Zend/zend_multiply.h | 4 +- + Zend/zend_strtod.c | 4 +- + Zend/zend_types.h | 26 +++++++----- + Zend/zend_vm_def.h | 11 ++++- + Zend/zend_vm_execute.h | 94 +++++++++++++++++++++++++++++++++++++---- + ext/session/session.c | 2 +- + main/SAPI.c | 5 +++ + main/main.c | 6 +++ + main/php_variables.c | 8 ++-- + main/rfc1867.c | 39 ++++++++++++++--- + 17 files changed, 240 insertions(+), 59 deletions(-) + +Index: php-7.4.33/Zend/zend_API.h +=================================================================== +--- php-7.4.33.orig/Zend/zend_API.h ++++ php-7.4.33/Zend/zend_API.h +@@ -380,6 +380,7 @@ ZEND_API char *zend_get_type_by_const(in + + #define array_init(arg) ZVAL_ARR((arg), zend_new_array(0)) + #define array_init_size(arg, size) ZVAL_ARR((arg), zend_new_array(size)) ++#define array_init_singleton(arg) ZVAL_ARR((arg), zend_new_array_singleton()) + ZEND_API int object_init(zval *arg); + ZEND_API int object_init_ex(zval *arg, zend_class_entry *ce); + ZEND_API int object_and_properties_init(zval *arg, zend_class_entry *ce, HashTable *properties); +Index: php-7.4.33/Zend/zend_alloc.c +=================================================================== +--- php-7.4.33.orig/Zend/zend_alloc.c ++++ php-7.4.33/Zend/zend_alloc.c +@@ -57,6 +57,7 @@ + #include "zend_operators.h" + #include "zend_multiply.h" + #include "zend_bitset.h" ++#include "zend_execute.h" + #include <signal.h> + + #ifdef HAVE_UNISTD_H +@@ -363,7 +364,42 @@ static ZEND_COLD ZEND_NORETURN void zend + #if ZEND_DEBUG && defined(HAVE_KILL) && defined(HAVE_GETPID) + kill(getpid(), SIGSEGV); + #endif +- exit(1); ++ _exit(1); ++} ++ ++ZEND_API ZEND_COLD ZEND_NORETURN void zend_mm_safe_error_ex(const char *format, ...) ++{ ++ zend_string *script_filename = NULL; ++ uint32_t script_lineno = 0; ++ ++ if (zend_is_executing()) { ++ script_filename = zend_get_executed_filename_ex(); ++ script_lineno = zend_get_executed_lineno(); ++ } else if (zend_is_compiling()) { ++ script_filename = zend_get_compiled_filename(); ++ script_lineno = zend_get_compiled_lineno(); ++ } ++ ++ va_list args; ++ va_start(args, format); ++ ++ char buf1024; ++ vsnprintf(buf, sizeof(buf), format, args); ++ ++ va_end(args); ++ ++ fprintf(stderr, ++ "\nFatal error: %s in %s on line %d\n", ++ buf, ++ script_filename ? ZSTR_VAL(script_filename) : "Unknown", ++ script_lineno); ++ ++ /* See http://support.microsoft.com/kb/190351 */ ++# ifdef ZEND_WIN32 ++ fflush(stderr); ++# endif ++ ++ _exit(1); + } + + static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap, +@@ -375,22 +411,14 @@ static ZEND_COLD ZEND_NORETURN void zend + #endif + size_t size) + { ++ (void) heap; + +- heap->overflow = 1; +- zend_try { +- zend_error_noreturn(E_ERROR, +- format, +- limit, +-#if ZEND_DEBUG +- filename, +- lineno, +-#endif +- size); +- } zend_catch { +- } zend_end_try(); +- heap->overflow = 0; +- zend_bailout(); +- exit(1); ++ zend_mm_safe_error_ex(format, limit, ++#if ZEND_DEBUG ++ filename, ++ lineno, ++#endif ++ size); + } + + #ifdef _WIN32 +@@ -1318,7 +1346,7 @@ static zend_always_inline void *zend_mm_ + size = MAX(size, 1); + size = ZEND_MM_ALIGNED_SIZE(size) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info)); + if (UNEXPECTED(size < real_size)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))); + return NULL; + } + #endif +@@ -1762,7 +1790,7 @@ static void *zend_mm_alloc_huge(zend_mm_ + void *ptr; + + if (UNEXPECTED(new_size < size)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", size, alignment); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu + %zu)", size, alignment); + } + + #if ZEND_MM_LIMIT +@@ -2617,7 +2645,7 @@ ZEND_API char* ZEND_FASTCALL _estrdup(co + + length = strlen(s); + if (UNEXPECTED(length + 1 == 0)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); + } + p = (char *) _emalloc(length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + memcpy(p, s, length+1); +@@ -2629,7 +2657,7 @@ ZEND_API char* ZEND_FASTCALL _estrndup(c + char *p; + + if (UNEXPECTED(length + 1 == 0)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); + } + p = (char *) _emalloc(length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + memcpy(p, s, length); +@@ -2643,7 +2671,7 @@ ZEND_API char* ZEND_FASTCALL zend_strndu + char *p; + + if (UNEXPECTED(length + 1 == 0)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (1 * %zu + 1)", length); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (1 * %zu + 1)", length); + } + p = (char *) malloc(length + 1); + if (UNEXPECTED(p == NULL)) { +@@ -2974,7 +3002,7 @@ ZEND_API zend_mm_heap *zend_mm_startup_e + static ZEND_COLD ZEND_NORETURN void zend_out_of_memory(void) + { + fprintf(stderr, "Out of memory\n"); +- exit(1); ++ _exit(1); + } + + ZEND_API void * __zend_malloc(size_t len) +Index: php-7.4.33/Zend/zend_alloc.h +=================================================================== +--- php-7.4.33.orig/Zend/zend_alloc.h ++++ php-7.4.33/Zend/zend_alloc.h +@@ -402,6 +402,8 @@ static void apc_init_heap(void) + size_t zend_mm_globals_size(void); + #endif + ++ZEND_API ZEND_COLD ZEND_NORETURN void zend_mm_safe_error_ex(const char *format, ...); ++ + END_EXTERN_C() + + #endif +Index: php-7.4.33/Zend/zend_execute_API.c +=================================================================== +--- php-7.4.33.orig/Zend/zend_execute_API.c ++++ php-7.4.33/Zend/zend_execute_API.c +@@ -337,10 +337,21 @@ void shutdown_executor(void) /* {{{ */ + gc_collect_cycles(); + } + #endif ++ } else { ++ /* may be used by zend_error_zstr_at before init_executor */ ++ ZVAL_UNDEF(&EG(user_error_handler)); ++ ZVAL_UNDEF(&EG(user_exception_handler)); ++ memset(&EG(user_error_handlers_error_reporting), 0, sizeof(EG(user_error_handlers_error_reporting))); ++ memset(&EG(user_error_handlers), 0, sizeof(EG(user_error_handlers))); ++ memset(&EG(user_exception_handlers), 0, sizeof(EG(user_exception_handlers))); + } + + zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown); + ++ /* may be used by zend_error_zstr_at before init_executor */ ++ EG(error_handling) = EH_NORMAL; ++ EG(exception) = NULL; ++ + zend_weakrefs_shutdown(); + + zend_try { +@@ -357,6 +368,8 @@ void shutdown_executor(void) /* {{{ */ + zend_hash_discard(EG(function_table), EG(persistent_functions_count)); + zend_hash_discard(EG(class_table), EG(persistent_classes_count)); + zend_cleanup_internal_classes(); ++ EG(objects_store).object_buckets = NULL; ++ EG(objects_store).top = 1; + } else { + zend_vm_stack_destroy(); + +Index: php-7.4.33/Zend/zend_hash.c +=================================================================== +--- php-7.4.33.orig/Zend/zend_hash.c ++++ php-7.4.33/Zend/zend_hash.c +@@ -97,7 +97,7 @@ static zend_always_inline uint32_t zend_ + if (nSize <= HT_MIN_SIZE) { + return HT_MIN_SIZE; + } else if (UNEXPECTED(nSize >= HT_MAX_SIZE)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket)); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket)); + } + + #if defined(ZEND_WIN32) +@@ -251,6 +251,13 @@ ZEND_API HashTable* ZEND_FASTCALL _zend_ + return ht; + } + ++ZEND_API HashTable* ZEND_FASTCALL zend_new_array_singleton(void) ++{ ++ HashTable *ht = _zend_new_array_0(); ++ ht->nTableSize = 1; ++ return ht; ++} ++ + ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t nSize) + { + HashTable *ht = emalloc(sizeof(HashTable)); +@@ -282,7 +289,7 @@ static void ZEND_FASTCALL zend_hash_pack + { + HT_ASSERT_RC1(ht); + if (ht->nTableSize >= HT_MAX_SIZE) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket)); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket)); + } + ht->nTableSize += ht->nTableSize; + HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_SIZE_EX(ht->nTableSize, HT_MIN_MASK), HT_USED_SIZE(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)); +@@ -1164,7 +1171,7 @@ static void ZEND_FASTCALL zend_hash_do_r + pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT); + zend_hash_rehash(ht); + } else { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket)); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket)); + } + } + +Index: php-7.4.33/Zend/zend_hash.h +=================================================================== +--- php-7.4.33.orig/Zend/zend_hash.h ++++ php-7.4.33/Zend/zend_hash.h +@@ -296,6 +296,7 @@ ZEND_API int ZEND_FASTCALL zend_hash_reh + #endif + + ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void); ++ZEND_API HashTable* ZEND_FASTCALL zend_new_array_singleton(void); + ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t size); + ZEND_API HashTable* ZEND_FASTCALL zend_new_pair(zval *val1, zval *val2); + ZEND_API uint32_t zend_array_count(HashTable *ht); +Index: php-7.4.33/Zend/zend_llist.c +=================================================================== +--- php-7.4.33.orig/Zend/zend_llist.c ++++ php-7.4.33/Zend/zend_llist.c +@@ -112,6 +112,8 @@ ZEND_API void zend_llist_destroy(zend_ll + current = next; + } + ++ l->head = NULL; ++ l->tail = NULL; + l->count = 0; + } + +Index: php-7.4.33/Zend/zend_multiply.h +=================================================================== +--- php-7.4.33.orig/Zend/zend_multiply.h ++++ php-7.4.33/Zend/zend_multiply.h +@@ -321,7 +321,7 @@ static zend_always_inline size_t zend_sa + size_t ret = zend_safe_address(nmemb, size, offset, &overflow); + + if (UNEXPECTED(overflow)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); ++ zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); + return 0; + } + return ret; +@@ -334,7 +334,7 @@ static zend_always_inline size_t zend_sa + size_t ret = zend_safe_address(nmemb, size, offset, &overflow); + + if (UNEXPECTED(overflow)) { +- zend_error_noreturn(E_ERROR, "Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset); ++ zend_mm_safe_error_ex("Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset); + return 0; + } + return ret; +Index: php-7.4.33/Zend/zend_strtod.c +=================================================================== +--- php-7.4.33.orig/Zend/zend_strtod.c ++++ php-7.4.33/Zend/zend_strtod.c +@@ -603,7 +603,7 @@ Balloc + rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); + if (!rv) { + FREE_DTOA_LOCK(0); +- zend_error_noreturn(E_ERROR, "Balloc() failed to allocate memory"); ++ zend_mm_safe_error_ex("Balloc() failed to allocate memory"); + } + #else + len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) +@@ -616,7 +616,7 @@ Balloc + rv = (Bigint*)MALLOC(len*sizeof(double)); + if (!rv) { + FREE_DTOA_LOCK(0); +- zend_error_noreturn(E_ERROR, "Balloc() failed to allocate memory"); ++ zend_mm_safe_error_ex("Balloc() failed to allocate memory"); + } + #endif + rv->k = k; +Index: php-7.4.33/Zend/zend_types.h +=================================================================== +--- php-7.4.33.orig/Zend/zend_types.h ++++ php-7.4.33/Zend/zend_types.h +@@ -330,17 +330,21 @@ struct _zend_array { + # define HT_HASH_RESET(ht) do { \ + char *p = (char*)&HT_HASH(ht, (ht)->nTableMask); \ + size_t size = HT_HASH_SIZE((ht)->nTableMask); \ +- __m128i xmm0 = _mm_setzero_si128(); \ +- xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); \ +- ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \ +- do { \ +- _mm_storeu_si128((__m128i*)p, xmm0); \ +- _mm_storeu_si128((__m128i*)(p+16), xmm0); \ +- _mm_storeu_si128((__m128i*)(p+32), xmm0); \ +- _mm_storeu_si128((__m128i*)(p+48), xmm0); \ +- p += 64; \ +- size -= 64; \ +- } while (size != 0); \ ++ if (UNEXPECTED(size < 64)) { \ ++ memset(p, HT_INVALID_IDX, size); \ ++ } else { \ ++ __m128i xmm0 = _mm_setzero_si128(); \ ++ xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); \ ++ ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \ ++ do { \ ++ _mm_storeu_si128((__m128i*)p, xmm0); \ ++ _mm_storeu_si128((__m128i*)(p+16), xmm0); \ ++ _mm_storeu_si128((__m128i*)(p+32), xmm0); \ ++ _mm_storeu_si128((__m128i*)(p+48), xmm0); \ ++ p += 64; \ ++ size -= 64; \ ++ } while (size != 0); \ ++ } \ + } while (0) + #else + # define HT_HASH_RESET(ht) \ +Index: php-7.4.33/Zend/zend_vm_def.h +=================================================================== +--- php-7.4.33.orig/Zend/zend_vm_def.h ++++ php-7.4.33/Zend/zend_vm_def.h +@@ -417,7 +417,7 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TM + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -426,6 +426,9 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TM + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -3210,6 +3213,9 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -3217,6 +3223,9 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +Index: php-7.4.33/Zend/zend_vm_execute.h +=================================================================== +--- php-7.4.33.orig/Zend/zend_vm_execute.h ++++ php-7.4.33/Zend/zend_vm_execute.h +@@ -5631,6 +5631,9 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_ + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -5638,6 +5641,9 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_ + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -7491,6 +7497,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -7498,6 +7507,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -7900,7 +7912,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -7909,6 +7921,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -9952,6 +9967,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -9959,6 +9977,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -10361,7 +10382,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -10370,6 +10391,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -13928,6 +13952,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -13935,6 +13962,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -14681,7 +14711,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -14690,6 +14720,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -15353,7 +15386,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -15362,6 +15395,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -16107,6 +16143,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -16114,6 +16153,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -17040,7 +17082,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -17049,6 +17091,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -17401,6 +17446,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -17408,6 +17456,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -38348,7 +38399,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -38357,6 +38408,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -40727,7 +40781,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -40736,6 +40790,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -41849,6 +41906,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -41856,6 +41916,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -44132,6 +44195,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -44139,6 +44205,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -46857,7 +46926,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + size_t len = ZSTR_LEN(op1_str); + + if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { +- zend_error_noreturn(E_ERROR, "Integer overflow in memory allocation"); ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); + } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -46866,6 +46935,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +@@ -49268,6 +49340,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + !ZSTR_IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) { + size_t len = ZSTR_LEN(op1_str); + ++ if (UNEXPECTED(len > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + ZVAL_NEW_STR(EX_VAR(opline->result.var), str); +@@ -49275,6 +49350,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FAST + zend_string_release_ex(op2_str, 0); + } + } else { ++ if (UNEXPECTED(ZSTR_LEN(op1_str) > ZSTR_MAX_LEN - ZSTR_LEN(op2_str))) { ++ zend_mm_safe_error_ex("Integer overflow in memory allocation"); ++ } + str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); + memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); + memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); +Index: php-7.4.33/ext/session/session.c +=================================================================== +--- php-7.4.33.orig/ext/session/session.c ++++ php-7.4.33/ext/session/session.c +@@ -3174,7 +3174,7 @@ static int php_session_rfc1867_callback( + if (php_session_rfc1867_orig_callback) { + retval = php_session_rfc1867_orig_callback(event, event_data, extra); + } +- if (!PS(rfc1867_enabled)) { ++ if (!PS(rfc1867_enabled) || true) { + return retval; + } + +Index: php-7.4.33/main/SAPI.c +=================================================================== +--- php-7.4.33.orig/main/SAPI.c ++++ php-7.4.33/main/SAPI.c +@@ -509,18 +509,23 @@ SAPI_API void sapi_deactivate(void) + } + if (SG(request_info).auth_user) { + efree(SG(request_info).auth_user); ++ SG(request_info).auth_user = NULL; + } + if (SG(request_info).auth_password) { + efree(SG(request_info).auth_password); ++ SG(request_info).auth_password = NULL; + } + if (SG(request_info).auth_digest) { + efree(SG(request_info).auth_digest); ++ SG(request_info).auth_digest = NULL; + } + if (SG(request_info).content_type_dup) { + efree(SG(request_info).content_type_dup); ++ SG(request_info).content_type_dup = NULL; + } + if (SG(request_info).current_user) { + efree(SG(request_info).current_user); ++ SG(request_info).current_user = NULL; + } + if (sapi_module.deactivate) { + sapi_module.deactivate(); +Index: php-7.4.33/main/main.c +=================================================================== +--- php-7.4.33.orig/main/main.c ++++ php-7.4.33/main/main.c +@@ -1961,6 +1961,8 @@ void php_request_shutdown(void *dummy) + + for (i=0; i<NUM_TRACK_VARS; i++) { + zval_ptr_dtor(&PG(http_globals)i); ++ /* May be accessed before php_request_startup() */ ++ ZVAL_UNDEF(&PG(http_globals)i); + } + } zend_end_try(); + +@@ -2013,6 +2015,9 @@ void php_request_shutdown(void *dummy) + #ifdef HAVE_DTRACE + DTRACE_REQUEST_SHUTDOWN(SAFE_FILENAME(SG(request_info).path_translated), SAFE_FILENAME(SG(request_info).request_uri), (char *)SAFE_FILENAME(SG(request_info).request_method)); + #endif /* HAVE_DTRACE */ ++ ++ /* May be accessed before php_request_startup() */ ++ PG(modules_activated) = 0; + } + /* }}} */ + +Index: php-7.4.33/main/php_variables.c +=================================================================== +--- php-7.4.33.orig/main/php_variables.c ++++ php-7.4.33/main/php_variables.c +@@ -219,7 +219,7 @@ PHPAPI void php_register_variable_ex(cha + } + + if (!index) { +- array_init(&gpc_element); ++ array_init_singleton(&gpc_element); + if ((gpc_element_p = zend_hash_next_index_insert(symtable1, &gpc_element)) == NULL) { + zend_array_destroy(Z_ARR(gpc_element)); + zval_ptr_dtor_nogc(val); +@@ -236,7 +236,7 @@ PHPAPI void php_register_variable_ex(cha + gpc_element_p = zend_symtable_str_find(symtable1, index, index_len); + if (!gpc_element_p) { + zval tmp; +- array_init(&tmp); ++ array_init_singleton(&tmp); + gpc_element_p = zend_symtable_str_update_ind(symtable1, index, index_len, &tmp); + } else { + if (Z_TYPE_P(gpc_element_p) == IS_INDIRECT) { +@@ -244,7 +244,7 @@ PHPAPI void php_register_variable_ex(cha + } + if (Z_TYPE_P(gpc_element_p) != IS_ARRAY) { + zval_ptr_dtor_nogc(gpc_element_p); +- array_init(gpc_element_p); ++ array_init_singleton(gpc_element_p); + } else { + SEPARATE_ARRAY(gpc_element_p); + } +@@ -442,7 +442,7 @@ SAPI_API SAPI_TREAT_DATA_FUNC(php_defaul + case PARSE_POST: + case PARSE_GET: + case PARSE_COOKIE: +- array_init(&array); ++ array_init_singleton(&array); + switch (arg) { + case PARSE_POST: + zval_ptr_dtor_nogc(&PG(http_globals)TRACK_VARS_POST); +Index: php-7.4.33/main/rfc1867.c +=================================================================== +--- php-7.4.33.orig/main/rfc1867.c ++++ php-7.4.33/main/rfc1867.c +@@ -397,6 +397,14 @@ static int find_boundary(multipart_buffe + return 0; + } + ++static zend_bool php_mime_should_save_hdr(const char *name) ++{ ++ return !strcasecmp(name, "Content-Disposition") ++ || !strcasecmp(name, "Content-Type"); ++} ++ ++static char *php_mime_get_hdr_value(zend_llist header, char *key); ++ + /* parse headers */ + static int multipart_buffer_headers(multipart_buffer *self, zend_llist *header) + { +@@ -437,10 +445,16 @@ static int multipart_buffer_headers(mult + } + + *value = '\0'; +- do { value++; } while (isspace((unsigned char)*value)); + +- key = estrdup(line); +- smart_string_appends(&buf_value, value); ++ /* Keep only headers we use, and ignore duplicates */ ++ if (!php_mime_should_save_hdr(line) ++ || php_mime_get_hdr_value(*header, line)) { ++ key = NULL; ++ } else { ++ key = estrdup(line); ++ do { value++; } while (isspace((unsigned char)*value)); ++ smart_string_appends(&buf_value, value); ++ } + } else if (buf_value.c) { /* If no ':' on the line, add to previous line */ + smart_string_appends(&buf_value, line); + } else { +@@ -514,11 +528,11 @@ static char *php_ap_getword(const zend_e + return res; + } + +-static char *substring_conf(char *start, int len, char quote) ++static char *substring_conf(char *start, size_t len, char quote) + { + char *result = emalloc(len + 1); + char *resp = result; +- int i; ++ size_t i; + + for (i = 0; i < len && starti != quote; ++i) { + if (starti == '\\' && (starti + 1 == '\\' || (quote && starti + 1 == quote))) { +@@ -546,14 +560,14 @@ static char *php_ap_getword_conf(const z + char quote = *str; + + str++; +- return substring_conf(str, (int)strlen(str), quote); ++ return substring_conf(str, strlen(str), quote); + } else { + char *strend = str; + + while (*strend && !isspace((unsigned char)*strend)) { + ++strend; + } +- return substring_conf(str, strend - str, 0); ++ return substring_conf(str, (size_t)(strend - str), 0); + } + } + +
View file
php7-CVE-2026-14355.patch
Added
@@ -0,0 +1,49 @@ +From 169226847426368c62992af43c2c39b0fdbff4d5 Mon Sep 17 00:00:00 2001 +From: David Carlier <devnexen@gmail.com> +Date: Fri, 29 May 2026 21:44:14 +0100 +Subject: PATCH ext/openssl: openssl_encrypt() zend mm heap overflow on + AES-WRAP-PAD mode. + +Fix #22186 + +close GH-22187 +--- + NEWS | 4 ++++ + ext/openssl/openssl.c | 17 +++++++++++++++-- + ext/openssl/tests/gh22186.phpt | 32 ++++++++++++++++++++++++++++++++ + 3 files changed, 51 insertions(+), 2 deletions(-) + create mode 100644 ext/openssl/tests/gh22186.phpt + +Index: php-7.4.33/ext/openssl/openssl.c +=================================================================== +--- php-7.4.33.orig/ext/openssl/openssl.c ++++ php-7.4.33/ext/openssl/openssl.c +@@ -6670,6 +6670,7 @@ static int php_openssl_cipher_update(con + char *aad, size_t aad_len, int enc) /* {{{ */ + { + int i = 0; ++ size_t outlen = data_len + EVP_CIPHER_block_size(cipher_type); + + if (mode->is_single_run_aead && !EVP_CipherUpdate(cipher_ctx, NULL, &i, NULL, (int)data_len)) { + php_openssl_store_errors(); +@@ -6683,7 +6684,19 @@ static int php_openssl_cipher_update(con + return FAILURE; + } + +- *poutbuf = zend_string_alloc((int)data_len + EVP_CIPHER_block_size(cipher_type), 0); ++#ifdef EVP_CIPH_WRAP_MODE ++ if ((EVP_CIPHER_mode(cipher_type)) == EVP_CIPH_WRAP_MODE) { ++ /* ++ * RFC 5649 wrap-with-padding rounds the input up to the block size ++ * and prepends an integrity block, we reserve one extra block. ++ * See EVP_EncryptUpdate(3): wrap mode may write up to ++ * inl + cipher_block_size bytes. ++ */ ++ outlen += EVP_CIPHER_block_size(cipher_type); ++ } ++#endif ++ ++ *poutbuf = zend_string_alloc(outlen, 0); + + if (!EVP_CipherUpdate(cipher_ctx, (unsigned char*)ZSTR_VAL(*poutbuf), + &i, (unsigned char *)data, (int)data_len)) {
View file
php7-CVE-2026-17543.patch
Added
@@ -0,0 +1,34 @@ +From ab048bd83b578119cf81b456526d50498421d617 Mon Sep 17 00:00:00 2001 +From: Ilija Tovilo <ilija.tovilo@me.com> +Date: Mon, 27 Jul 2026 16:49:38 +0200 +Subject: PATCH Fix SQL injection in ext-pgsql via E'...' backslash breakout + +php_pgsql_add_quotes() quotes the string with E'...', but PQescapeStringConn() +does not escape \ unless standard_conforming_strings is off. +PQescapeStringConn() is meant to be used with '', so do that instead. + +Fixes GHSA-7qpv-r5mr-78m4 +--- + ext/pgsql/pgsql.c | 3 +- + ext/pgsql/tests/10pg_convert_9.phpt | 18 +++++- + ext/pgsql/tests/10pg_convert_json_array.phpt | 4 +- + ext/pgsql/tests/12pg_insert_9.phpt | 2 +- + ext/pgsql/tests/14pg_update_9.phpt | 2 +- + ext/pgsql/tests/GHSA-7qpv-r5mr-78m4.phpt | 58 ++++++++++++++++++++ + ext/pgsql/tests/bug64609.phpt | 2 +- + ext/pgsql/tests/bug68638.phpt | 2 +- + 8 files changed, 81 insertions(+), 10 deletions(-) + create mode 100644 ext/pgsql/tests/GHSA-7qpv-r5mr-78m4.phpt + +Index: php-7.4.33/ext/pgsql/pgsql.c +=================================================================== +--- php-7.4.33.orig/ext/pgsql/pgsql.c ++++ php-7.4.33/ext/pgsql/pgsql.c +@@ -5839,7 +5839,6 @@ static int php_pgsql_add_quotes(zval *sr + assert(Z_TYPE_P(src) == IS_STRING); + assert(should_free == 1 || should_free == 0); + +- smart_str_appendc(&str, 'E'); + smart_str_appendc(&str, '\''); + smart_str_appendl(&str, Z_STRVAL_P(src), Z_STRLEN_P(src)); + smart_str_appendc(&str, '\'');
View file
php7-CVE-2026-6103.patch
Added
@@ -0,0 +1,154 @@ +From 0994e2e887cd993866b5e4d7dba2fade5caeefec Mon Sep 17 00:00:00 2001 +From: Jakub Zelenka <bukka@php.net> +Date: Sun, 13 Sep 2026 22:37:00 +0200 +Subject: PATCH Fix GHSA-j3wh-g957-2m85: phar tar entry injection + +Reject entry sizes that cannot be parsed or represented, and skip the data +blocks of every entry type that carries data. Both left the stream on +attacker controlled data that was then parsed as a tar header. +--- + ext/phar/phar_internal.h | 5 + + ext/phar/tar.c | 80 +++++++++++++++- + .../tar/GHSA-j3wh-g957-2m85-longlink.phpt | 50 ++++++++++ + .../tests/tar/GHSA-j3wh-g957-2m85-size.phpt | 92 +++++++++++++++++++ + .../tar/GHSA-j3wh-g957-2m85-typeflag.phpt | 79 ++++++++++++++++ + 5 files changed, 301 insertions(+), 5 deletions(-) + create mode 100644 ext/phar/tests/tar/GHSA-j3wh-g957-2m85-longlink.phpt + create mode 100644 ext/phar/tests/tar/GHSA-j3wh-g957-2m85-size.phpt + create mode 100644 ext/phar/tests/tar/GHSA-j3wh-g957-2m85-typeflag.phpt + +Index: php-7.4.33/ext/phar/phar_internal.h +=================================================================== +--- php-7.4.33.orig/ext/phar/phar_internal.h ++++ php-7.4.33/ext/phar/phar_internal.h +@@ -113,8 +113,13 @@ + #define TAR_FILE '0' + #define TAR_LINK '1' + #define TAR_SYMLINK '2' ++#define TAR_CHAR '3' ++#define TAR_BLOCK '4' + #define TAR_DIR '5' ++#define TAR_FIFO '6' + #define TAR_NEW '8' ++#define TAR_LONGLINK 'K' ++#define TAR_LONGNAME 'L' + #define TAR_GLOBAL_HDR 'g' + #define TAR_FILE_HDR 'x' + +Index: php-7.4.33/ext/phar/tar.c +=================================================================== +--- php-7.4.33.orig/ext/phar/tar.c ++++ php-7.4.33/ext/phar/tar.c +@@ -37,6 +37,52 @@ static uint32_t phar_tar_number(char *bu + } + /* }}} */ + ++static zend_bool phar_tar_type_has_data(char typeflag) ++{ ++ switch (typeflag) { ++ case TAR_LINK: ++ case TAR_SYMLINK: ++ case TAR_CHAR: ++ case TAR_BLOCK: ++ case TAR_DIR: ++ case TAR_FIFO: ++ return 0; ++ default: ++ return 1; ++ } ++} ++ ++static zend_bool phar_tar_size(const char *buf, size_t len, uint32_t *result) ++{ ++ uint64_t num = 0; ++ size_t i = 0; ++ ++ while (i < len && bufi == ' ') { ++ ++i; ++ } ++ ++ /* GNU base-256 encoding is only used for sizes that do not fit the octal field */ ++ if (i < len && (((unsigned char) bufi) & 0x80)) { ++ return 0; ++ } ++ ++ while (i < len && bufi >= '0' && bufi <= '7') { ++ num = num * 8 + (bufi - '0'); ++ ++i; ++ } ++ ++ while (i < len && (bufi == ' ' || bufi == '\0')) { ++ ++i; ++ } ++ ++ if (i != len || num > UINT32_MAX - 511) { ++ return 0; ++ } ++ ++ *result = (uint32_t) num; ++ return 1; ++} ++ + /* adapted from format_octal() in libarchive + * + * Copyright (c) 2003-2009 Tim Kientzle +@@ -280,8 +326,32 @@ int phar_parse_tarfile(php_stream* fp, c + } + } + +- size = entry.uncompressed_filesize = entry.compressed_filesize = +- phar_tar_number(hdr->size, sizeof(hdr->size)); ++ if (!phar_tar_size(hdr->size, sizeof(hdr->size), &size)) { ++ if (error) { ++ spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (invalid entry size)", fname); ++ } ++ if (last_was_longlink) { ++ pefree(entry.filename, myphar->is_persistent); ++ } ++ php_stream_close(fp); ++ phar_destroy_phar_data(myphar); ++ return FAILURE; ++ } ++ entry.uncompressed_filesize = entry.compressed_filesize = size; ++ ++ /* GNU long link names are not supported, so refuse the record instead of ++ * registering it as an entry and dropping the link target of the entry that follows */ ++ if (hdr->typeflag == TAR_LONGLINK) { ++ if (error) { ++ spprintf(error, 4096, "phar error: \"%s\" is a tar file with an unsupported GNU long link entry", fname); ++ } ++ if (last_was_longlink) { ++ pefree(entry.filename, myphar->is_persistent); ++ } ++ php_stream_close(fp); ++ phar_destroy_phar_data(myphar); ++ return FAILURE; ++ } + + /* skip global/file headers (pax) */ + if (!old && (hdr->typeflag == TAR_GLOBAL_HDR || hdr->typeflag == TAR_FILE_HDR)) { +@@ -369,13 +439,13 @@ bail: + goto bail; + } + +- if (!last_was_longlink && hdr->typeflag == 'L') { ++ if (!last_was_longlink && hdr->typeflag == TAR_LONGNAME) { + last_was_longlink = 1; + /* support the ././@LongLink system for storing long filenames */ + entry.filename_len = entry.uncompressed_filesize; + + /* Check for overflow - bug 61065 */ +- if (entry.filename_len == UINT_MAX || entry.filename_len == 0) { ++ if (entry.filename_len == 0 || entry.filename_len > totalsize) { + if (error) { + spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (invalid entry size)", fname); + } +@@ -585,7 +655,7 @@ bail: + + size = (size+511)&~511; + +- if (((hdr->typeflag == '\0') || (hdr->typeflag == TAR_FILE)) && size > 0) { ++ if (phar_tar_type_has_data(hdr->typeflag) && size > 0) { + next: + /* this is not good enough - seek succeeds even on truncated tars */ + php_stream_seek(fp, size, SEEK_CUR);
View file
php7-CVE-2026-6722.patch
Added
@@ -0,0 +1,35 @@ +From aee3b3ac9b816b0def1c462695b483b49a83148e Mon Sep 17 00:00:00 2001 +From: Ilija Tovilo <ilija.tovilo@me.com> +Date: Sun, 3 May 2026 19:56:53 +0200 +Subject: PATCH GHSA-85c2-q967-79q5: soap Fix stale SOAP_GLOBAL(ref_map) + pointer with Apache Map + +Fixes GHSA-85c2-q967-79q5 +Fixes CVE-2026-6722 +--- + ext/soap/php_encoding.c | 3 +- + ext/soap/tests/GHSA-85c2-q967-79q5.phpt | 61 +++++++++++++++++++++++++ + 2 files changed, 63 insertions(+), 1 deletion(-) + create mode 100644 ext/soap/tests/GHSA-85c2-q967-79q5.phpt + +Index: php-7.4.33/ext/soap/php_encoding.c +=================================================================== +--- php-7.4.33.orig/ext/soap/php_encoding.c ++++ php-7.4.33/ext/soap/php_encoding.c +@@ -367,6 +367,7 @@ static zend_bool soap_check_xml_ref(zval + static void soap_add_xml_ref(zval *data, xmlNodePtr node) + { + if (SOAP_GLOBAL(ref_map)) { ++ Z_TRY_ADDREF_P(data); + zend_hash_index_update(SOAP_GLOBAL(ref_map), (zend_ulong)node, data); + } + } +@@ -3428,7 +3429,7 @@ void encode_reset_ns() + } else { + SOAP_GLOBAL(ref_map) = emalloc(sizeof(HashTable)); + } +- zend_hash_init(SOAP_GLOBAL(ref_map), 0, NULL, NULL, 0); ++ zend_hash_init(SOAP_GLOBAL(ref_map), 0, NULL, ZVAL_PTR_DTOR, 0); + } + + void encode_finish()
View file
php7-CVE-2026-6735.patch
Added
@@ -0,0 +1,76 @@ +From 99a5ad7441de9914246c7863adb6997396008b9d Mon Sep 17 00:00:00 2001 +From: Jakub Zelenka <bukka@php.net> +Date: Sun, 3 May 2026 20:01:41 +0200 +Subject: PATCH GHSA-7qg2-v9fj-4mwv: fpm XSS within status endpoint + +Fixes GHSA-7qg2-v9fj-4mwv +Fixes CVE-2026-6735 +--- + sapi/fpm/fpm/fpm_status.c | 34 +++++++++++-- + .../tests/ghsa-7qg2-v9fj-4mwv-status-xss.phpt | 48 +++++++++++++++++++ + 2 files changed, 78 insertions(+), 4 deletions(-) + create mode 100644 sapi/fpm/tests/ghsa-7qg2-v9fj-4mwv-status-xss.phpt + +Index: php-7.4.33/sapi/fpm/fpm/fpm_status.c +=================================================================== +--- php-7.4.33.orig/sapi/fpm/fpm/fpm_status.c ++++ php-7.4.33/sapi/fpm/fpm/fpm_status.c +@@ -483,8 +483,8 @@ int fpm_status_handle_request(void) /* { + if (full_syntax) { + unsigned int i; + int first; +- zend_string *tmp_query_string; +- char *query_string; ++ zend_string *tmp_query_string, *tmp_request_uri_string; ++ char *query_string, *request_uri_string; + struct timeval duration, now; + #ifdef HAVE_FPM_LQ + float cpu; +@@ -511,13 +511,27 @@ int fpm_status_handle_request(void) /* { + } + } + ++ request_uri_string = NULL; ++ tmp_request_uri_string = NULL; ++ if (proc.request_uri0 != '\0') { ++ if (encode) { ++ tmp_request_uri_string = php_escape_html_entities_ex( ++ (const unsigned char *) proc.request_uri, ++ strlen(proc.request_uri), 1, ENT_DISALLOWED | ENT_HTML_DOC_XML1 | ENT_COMPAT, ++ NULL, /* double_encode */ 1); ++ request_uri_string = ZSTR_VAL(tmp_request_uri_string); ++ } else { ++ request_uri_string = proc.request_uri; ++ } ++ } ++ + query_string = NULL; + tmp_query_string = NULL; + if (proc.query_string0 != '\0') { + if (!encode) { + query_string = proc.query_string; + } else { +- tmp_query_string = php_escape_html_entities_ex((unsigned char *)proc.query_string, strlen(proc.query_string), 1, ENT_HTML_IGNORE_ERRORS & ENT_COMPAT, NULL, 1); ++ tmp_query_string = php_escape_html_entities_ex((unsigned char *)proc.query_string, strlen(proc.query_string), 1, ENT_DISALLOWED | ENT_HTML_DOC_XML1 | ENT_COMPAT, NULL, 1); + query_string = ZSTR_VAL(tmp_query_string); + } + } +@@ -545,7 +559,7 @@ int fpm_status_handle_request(void) /* { + proc.requests, + duration.tv_sec * 1000000UL + duration.tv_usec, + proc.request_method0 != '\0' ? proc.request_method : "-", +- proc.request_uri0 != '\0' ? proc.request_uri : "-", ++ request_uri_string ? request_uri_string : "-", + query_string ? "?" : "", + query_string ? query_string : "", + proc.content_length, +@@ -558,6 +572,9 @@ int fpm_status_handle_request(void) /* { + PUTS(buffer); + efree(buffer); + ++ if (tmp_request_uri_string) { ++ zend_string_free(tmp_request_uri_string); ++ } + if (tmp_query_string) { + zend_string_free(tmp_query_string); + }
View file
php7-CVE-2026-7258.patch
Added
@@ -0,0 +1,1588 @@ +From a38418777f65780d9d622197677e90567690fc07 Mon Sep 17 00:00:00 2001 +From: Ilija Tovilo <ilija.tovilo@me.com> +Date: Sun, 3 May 2026 20:03:18 +0200 +Subject: PATCH GHSA-m8rr-4c36-8gq4: Consistently pass unsigned char to + ctype.h functions + +Fixes GHSA-m8rr-4c36-8gq4 +Fixes CVE-2026-7258 +--- + Zend/zend_compile.c | 2 +- + Zend/zend_ini.c | 6 +++--- + Zend/zend_operators.c | 8 ++++---- + Zend/zend_virtual_cwd.c | 10 +++++----- + Zend/zend_virtual_cwd.h | 2 +- + ext/com_dotnet/com_extension.c | 4 ++-- + ext/date/lib/parse_date.c | 10 +++++----- + ext/date/lib/parse_date.re | 10 +++++----- + ext/date/lib/parse_iso_intervals.c | 4 ++-- + ext/date/lib/parse_iso_intervals.re | 4 ++-- + ext/date/lib/timelib.c | 2 +- + ext/filter/logical_filters.c | 10 +++++----- + ext/ftp/ftp.c | 10 +++++----- + ext/gd/libgd/gd_xbm.c | 2 +- + ext/imap/php_imap.c | 2 +- + ext/intl/locale/locale_methods.c | 2 +- + ext/mbstring/mbstring.c | 4 ++-- + ext/mbstring/php_mbregex.c | 2 +- + ext/pcre/php_pcre.c | 4 ++-- + ext/pdo/pdo.c | 2 +- + ext/pdo/pdo_sql_parser.re | 2 +- + ext/pdo/pdo_stmt.c | 2 +- + ext/standard/dl.c | 2 +- + ext/standard/exec.c | 2 +- + ext/standard/file.c | 2 +- + ext/standard/filters.c | 2 +- + ext/standard/formatted_print.c | 8 ++++---- + ext/standard/ftp_fopen_wrapper.c | 12 ++++++------ + ext/standard/html.c | 4 ++-- + ext/standard/math.c | 6 +++--- + ext/standard/metaphone.c | 18 ++++++++--------- + ext/standard/quot_print.c | 8 ++++---- + ext/standard/scanf.c | 10 +++++----- + ext/standard/soundex.c | 2 +- + ext/standard/string.c | 14 +++++++------- + ext/standard/strnatcmp.c | 30 ++++++++++++++--------------- + ext/standard/type.c | 2 +- + ext/standard/url.c | 20 +++++++++---------- + ext/standard/url_scanner_ex.re | 6 +++--- + ext/standard/versioning.c | 16 +++++++-------- + main/SAPI.c | 6 +++--- + main/fopen_wrappers.c | 6 +++--- + main/php_ini.c | 2 +- + main/php_ini_builder.c | 2 +- + main/php_variables.c | 4 ++-- + main/rfc1867.c | 12 ++++++------ + main/snprintf.c | 14 +++++++------- + main/spprintf.c | 14 +++++++------- + main/streams/streams.c | 4 ++-- + main/streams/transports.c | 2 +- + sapi/cli/php_cli_server.c | 2 +- + sapi/fpm/fpm/fpm_conf.c | 4 ++-- + sapi/litespeed/lsapi_main.c | 4 ++-- + sapi/litespeed/lsapilib.c | 6 +++--- + sapi/phpdbg/phpdbg_cmd.c | 4 ++-- + sapi/phpdbg/phpdbg_prompt.c | 2 +- + sapi/phpdbg/phpdbg_utils.c | 10 +++++----- + win32/sendmail.c | 6 +++--- + 58 files changed, 186 insertions(+), 186 deletions(-) + +Index: php-7.4.33/Zend/zend_compile.c +=================================================================== +--- php-7.4.33.orig/Zend/zend_compile.c ++++ php-7.4.33/Zend/zend_compile.c +@@ -1772,7 +1772,7 @@ ZEND_API size_t zend_dirname(char *path, + /* Note that on Win32 CWD is per drive (heritage from CP/M). + * This means dirname("c:foo") maps to "c:." or "c:" - which means CWD on C: drive. + */ +- if ((2 <= len) && isalpha((int)((unsigned char *)path)0) && (':' == path1)) { ++ if ((2 <= len) && isalpha((unsigned char)path0) && (':' == path1)) { + /* Skip over the drive spec (if any) so as not to change */ + path += 2; + len_adjust += 2; +Index: php-7.4.33/Zend/zend_operators.c +=================================================================== +--- php-7.4.33.orig/Zend/zend_operators.c ++++ php-7.4.33/Zend/zend_operators.c +@@ -2804,8 +2804,8 @@ ZEND_API int ZEND_FASTCALL zend_binary_s + + len = MIN(len1, len2); + while (len--) { +- c1 = zend_tolower((int)*(unsigned char *)s1++); +- c2 = zend_tolower((int)*(unsigned char *)s2++); ++ c1 = zend_tolower((unsigned char)*(s1++)); ++ c2 = zend_tolower((unsigned char)*(s2++)); + if (c1 != c2) { + return c1 - c2; + } +@@ -2825,8 +2825,8 @@ ZEND_API int ZEND_FASTCALL zend_binary_s + } + len = MIN(length, MIN(len1, len2)); + while (len--) { +- c1 = zend_tolower((int)*(unsigned char *)s1++); +- c2 = zend_tolower((int)*(unsigned char *)s2++); ++ c1 = zend_tolower((unsigned char)*(s1++)); ++ c2 = zend_tolower((unsigned char)*(s2++)); + if (c1 != c2) { + return c1 - c2; + } +Index: php-7.4.33/Zend/zend_virtual_cwd.c +=================================================================== +--- php-7.4.33.orig/Zend/zend_virtual_cwd.c ++++ php-7.4.33/Zend/zend_virtual_cwd.c +@@ -201,7 +201,7 @@ void virtual_cwd_main_cwd_init(uint8_t r + main_cwd_state.cwd_length = strlen(cwd); + #ifdef ZEND_WIN32 + if (main_cwd_state.cwd_length >= 2 && cwd1 == ':') { +- cwd0 = toupper(cwd0); ++ cwd0 = toupper((unsigned char)cwd0); + } + #endif + main_cwd_state.cwd = strdup(cwd); +@@ -279,7 +279,7 @@ CWD_API char *virtual_getcwd_ex(size_t * + *length = state->cwd_length+1; + retval = (char *) emalloc(*length+1); + memcpy(retval, state->cwd, *length); +- retval0 = toupper(retval0); ++ retval0 = toupper((unsigned char)retval0); + retval*length-1 = DEFAULT_SLASH; + retval*length = '\0'; + return retval; +@@ -1120,7 +1120,7 @@ CWD_API int virtual_file_ex(cwd_state *s + if (resolved_pathstart == 0) { + goto verify; + } +- resolved_pathstart = toupper(resolved_pathstart); ++ resolved_pathstart = toupper((unsigned char)resolved_pathstart); + start++; + } + resolved_pathstart++ = DEFAULT_SLASH; +@@ -1128,13 +1128,13 @@ CWD_API int virtual_file_ex(cwd_state *s + if (resolved_pathstart == 0) { + goto verify; + } +- resolved_pathstart = toupper(resolved_pathstart); ++ resolved_pathstart = toupper((unsigned char)resolved_pathstart); + start++; + } + resolved_pathstart++ = DEFAULT_SLASH; + } else if (IS_ABSOLUTE_PATH(resolved_path, path_length)) { + /* skip DRIVE name */ +- resolved_path0 = toupper(resolved_path0); ++ resolved_path0 = toupper((unsigned char)resolved_path0); + resolved_path2 = DEFAULT_SLASH; + start = 3; + } +Index: php-7.4.33/Zend/zend_virtual_cwd.h +=================================================================== +--- php-7.4.33.orig/Zend/zend_virtual_cwd.h ++++ php-7.4.33/Zend/zend_virtual_cwd.h +@@ -84,7 +84,7 @@ typedef unsigned short mode_t; + #define IS_UNC_PATH(path, len) \ + (len >= 2 && IS_SLASH(path0) && IS_SLASH(path1)) + #define IS_ABSOLUTE_PATH(path, len) \ +- (len >= 2 && (/* is local */isalpha(path0) && path1 == ':' || /* is UNC */IS_SLASH(path0) && IS_SLASH(path1))) ++ (len >= 2 && (/* is local */isalpha((unsigned char)(path)0) && path1 == ':' || /* is UNC */IS_SLASH(path0) && IS_SLASH(path1))) + + #else + #ifdef HAVE_DIRENT_H +Index: php-7.4.33/ext/com_dotnet/com_extension.c +=================================================================== +--- php-7.4.33.orig/ext/com_dotnet/com_extension.c ++++ php-7.4.33/ext/com_dotnet/com_extension.c +@@ -241,11 +241,11 @@ static PHP_INI_MH(OnTypeLibFileUpdate) + } + + /* Remove leading/training white spaces on search_string */ +- while (isspace(*typelib_name)) {/* Ends on '\0' in worst case */ ++ while (isspace((unsigned char)*typelib_name)) {/* Ends on '\0' in worst case */ + typelib_name ++; + } + ptr = typelib_name + strlen(typelib_name) - 1; +- while ((ptr != typelib_name) && isspace(*ptr)) { ++ while ((ptr != typelib_name) && isspace((unsigned char)*ptr)) { + *ptr = '\0'; + ptr--; + } +Index: php-7.4.33/ext/date/lib/parse_date.re +=================================================================== +--- php-7.4.33.orig/ext/date/lib/parse_date.re ++++ php-7.4.33/ext/date/lib/parse_date.re +@@ -477,7 +477,7 @@ static timelib_sll timelib_get_nr(char * + + static void timelib_skip_day_suffix(char **ptr) + { +- if (isspace(**ptr)) { ++ if (isspace((unsigned char)**ptr)) { + return; + } + if (!timelib_strncasecmp(*ptr, "nd", 2) || !timelib_strncasecmp(*ptr, "rd", 2) ||!timelib_strncasecmp(*ptr, "st", 2) || !timelib_strncasecmp(*ptr, "th", 2)) { +@@ -742,7 +742,7 @@ static timelib_long timelib_parse_tz_cor + char *begin = *ptr, *end; + timelib_long tmp; + +- while (isdigit(**ptr) || **ptr == ':') { ++ while (isdigit((unsigned char)**ptr) || **ptr == ':') { + ++*ptr; + } + end = *ptr; +@@ -784,7 +784,7 @@ static timelib_long timelib_parse_tz_min + } + + ++*ptr; +- while (isdigit(**ptr)) { ++ while (isdigit((unsigned char)**ptr)) { + ++*ptr; + } + +@@ -1837,10 +1837,10 @@ timelib_time* timelib_strtotime(char *s, + in.errors->error_messages = NULL; + + if (len > 0) { +- while (isspace(*s) && s < e) { ++ while (isspace((unsigned char)*s) && s < e) { + s++; + } +- while (isspace(*e) && e > s) { ++ while (isspace((unsigned char)*e) && e > s) { + e--; + } + } +Index: php-7.4.33/ext/date/lib/parse_iso_intervals.re +=================================================================== +--- php-7.4.33.orig/ext/date/lib/parse_iso_intervals.re ++++ php-7.4.33/ext/date/lib/parse_iso_intervals.re +@@ -341,10 +341,10 @@ void timelib_strtointerval(char *s, size + in.errors->error_messages = NULL; + + if (len > 0) { +- while (isspace(*s) && s < e) { ++ while (isspace((unsigned char)*s) && s < e) { + s++; + } +- while (isspace(*e) && e > s) { ++ while (isspace((unsigned char)*e) && e > s) { + e--; + } + } +Index: php-7.4.33/ext/date/lib/timelib.c +=================================================================== +--- php-7.4.33.orig/ext/date/lib/timelib.c ++++ php-7.4.33/ext/date/lib/timelib.c +@@ -123,7 +123,7 @@ void timelib_time_tz_abbr_update(timelib + TIMELIB_TIME_FREE(tm->tz_abbr); + tm->tz_abbr = timelib_strdup(tz_abbr); + for (i = 0; i < tz_abbr_len; i++) { +- tm->tz_abbri = toupper(tz_abbri); ++ tm->tz_abbri = toupper((unsigned char)tz_abbri); + } + } + +Index: php-7.4.33/ext/filter/logical_filters.c +=================================================================== +--- php-7.4.33.orig/ext/filter/logical_filters.c ++++ php-7.4.33/ext/filter/logical_filters.c +@@ -519,21 +519,21 @@ static int _php_filter_validate_domain(c + } + + /* First char must be alphanumeric */ +- if(*s == '.' || (hostname && !isalnum((int)*(unsigned char *)s))) { ++ if(*s == '.' || (hostname && !isalnum((unsigned char)*s))) { + return 0; + } + + while (s < e) { + if (*s == '.') { + /* The first and the last character of a label must be alphanumeric */ +- if (*(s + 1) == '.' || (hostname && (!isalnum((int)*(unsigned char *)(s - 1)) || !isalnum((int)*(unsigned char *)(s + 1))))) { ++ if (*(s + 1) == '.' || (hostname && (!isalnum((unsigned char)s-1) || !isalnum((unsigned char)s1)))) { + return 0; + } + + /* Reset label length counter */ + i = 1; + } else { +- if (i > 63 || (hostname && *s != '-' && !isalnum((int)*(unsigned char *)s))) { ++ if (i > 63 || (hostname && *s != '-' && !isalnum((unsigned char)*s))) { + return 0; + } + +@@ -560,9 +560,9 @@ static int is_userinfo_valid(zend_string + const char *valid = "-._~!$&'()*+,;=:"; + const char *p = ZSTR_VAL(str); + while (p - ZSTR_VAL(str) < ZSTR_LEN(str)) { +- if (isalpha(*p) || isdigit(*p) || strchr(valid, *p)) { ++ if (isalpha((unsigned char)*p) || isdigit((unsigned char)*p) || strchr(valid, *p)) { + p++; +- } else if (*p == '%' && p - ZSTR_VAL(str) <= ZSTR_LEN(str) - 3 && isdigit(*(p+1)) && isxdigit(*(p+2))) { ++ } else if (*p == '%' && p - ZSTR_VAL(str) <= ZSTR_LEN(str) - 3 && isdigit((unsigned char)p1) && isxdigit((unsigned char)p2)) { + p += 3; + } else { + return 0; +Index: php-7.4.33/ext/ftp/ftp.c +=================================================================== +--- php-7.4.33.orig/ext/ftp/ftp.c ++++ php-7.4.33/ext/ftp/ftp.c +@@ -513,7 +513,7 @@ ftp_raw(ftpbuf_t *ftp, const char *cmd, + array_init(return_value); + while (ftp_readline(ftp)) { + add_next_index_string(return_value, ftp->inbuf); +- if (isdigit(ftp->inbuf0) && isdigit(ftp->inbuf1) && isdigit(ftp->inbuf2) && ftp->inbuf3 == ' ') { ++ if (isdigit((unsigned char)ftp->inbuf0) && isdigit((unsigned char)ftp->inbuf1) && isdigit((unsigned char)ftp->inbuf2) && ftp->inbuf3 == ' ') { + return; + } + } +@@ -867,7 +867,7 @@ ftp_pasv(ftpbuf_t *ftp, int pasv) + return 0; + } + /* parse out the IP and port */ +- for (ptr = ftp->inbuf; *ptr && !isdigit(*ptr); ptr++); ++ for (ptr = ftp->inbuf; *ptr && !isdigit((unsigned char)*ptr); ptr++); + n = sscanf(ptr, "%lu,%lu,%lu,%lu,%lu,%lu", &b0, &b1, &b2, &b3, &b4, &b5); + if (n != 6) { + return 0; +@@ -1178,7 +1178,7 @@ ftp_mdtm(ftpbuf_t *ftp, const char *path + return -1; + } + /* parse out the timestamp */ +- for (ptr = ftp->inbuf; *ptr && !isdigit(*ptr); ptr++); ++ for (ptr = ftp->inbuf; *ptr && !isdigit((unsigned char)*ptr); ptr++); + n = sscanf(ptr, "%4u%2u%2u%2u%2u%2u", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec); + if (n != 6) { + return -1; +@@ -1382,13 +1382,13 @@ ftp_getresp(ftpbuf_t *ftp) + } + + /* Break out when the end-tag is found */ +- if (isdigit(ftp->inbuf0) && isdigit(ftp->inbuf1) && isdigit(ftp->inbuf2) && ftp->inbuf3 == ' ') { ++ if (isdigit((unsigned char)ftp->inbuf0) && isdigit((unsigned char)ftp->inbuf1) && isdigit((unsigned char)ftp->inbuf2) && ftp->inbuf3 == ' ') { + break; + } + } + + /* translate the tag */ +- if (!isdigit(ftp->inbuf0) || !isdigit(ftp->inbuf1) || !isdigit(ftp->inbuf2)) { ++ if (!isdigit((unsigned char)ftp->inbuf0) || !isdigit((unsigned char)ftp->inbuf1) || !isdigit((unsigned char)ftp->inbuf2)) { + return 0; + } + +Index: php-7.4.33/ext/gd/libgd/gd_xbm.c +=================================================================== +--- php-7.4.33.orig/ext/gd/libgd/gd_xbm.c ++++ php-7.4.33/ext/gd/libgd/gd_xbm.c +@@ -193,7 +193,7 @@ void gdImageXbmCtx(gdImagePtr image, cha + } else { + for (i=0; i<l; i++) { + /* only in C-locale isalnum() would work */ +- if (!isupper(namei) && !islower(namei) && !isdigit(namei)) { ++ if (!isupper((unsigned char)namei) && !islower((unsigned char)namei) && !isdigit((unsigned char)namei)) { + namei = '_'; + } + } +Index: php-7.4.33/ext/imap/php_imap.c +=================================================================== +--- php-7.4.33.orig/ext/imap/php_imap.c ++++ php-7.4.33/ext/imap/php_imap.c +@@ -2808,7 +2808,7 @@ PHP_FUNCTION(imap_utf8) + #define SPECIAL(c) ((c) <= 0x1f || (c) >= 0x7f) + + /* validate a modified-base64 character */ +-#define B64CHAR(c) (isalnum(c) || (c) == '+' || (c) == ',') ++#define B64CHAR(c) (isalnum((unsigned char)(c)) || (c) == '+' || (c) == ',') + + /* map the low 64 bits of `n' to the modified-base64 characters */ + #define B64(n) ("ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ +Index: php-7.4.33/ext/intl/locale/locale_methods.c +=================================================================== +--- php-7.4.33.orig/ext/intl/locale/locale_methods.c ++++ php-7.4.33/ext/intl/locale/locale_methods.c +@@ -1216,7 +1216,7 @@ static int strToMatch(const char* str ,c + if( *str == '-' ){ + *retstr = '_'; + } else { +- *retstr = tolower(*str); ++ *retstr = tolower((unsigned char)*str); + } + str++; + retstr++; +Index: php-7.4.33/ext/mbstring/mbstring.c +=================================================================== +--- php-7.4.33.orig/ext/mbstring/mbstring.c ++++ php-7.4.33/ext/mbstring/mbstring.c +@@ -1176,7 +1176,7 @@ static char *php_mb_rfc1867_getword(cons + + static char *php_mb_rfc1867_getword_conf(const zend_encoding *encoding, char *str) /* {{{ */ + { +- while (*str && isspace(*(unsigned char *)str)) { ++ while (*str && isspace((unsigned char)*str)) { + ++str; + } + +@@ -1192,7 +1192,7 @@ static char *php_mb_rfc1867_getword_conf + } else { + char *strend = str; + +- while (*strend && !isspace(*(unsigned char *)strend)) { ++ while (*strend && !isspace((unsigned char)*strend)) { + ++strend; + } + return php_mb_rfc1867_substring_conf(encoding, str, strend - str, 0); +Index: php-7.4.33/ext/mbstring/php_mbregex.c +=================================================================== +--- php-7.4.33.orig/ext/mbstring/php_mbregex.c ++++ php-7.4.33/ext/mbstring/php_mbregex.c +@@ -777,7 +777,7 @@ static inline void mb_regex_substitute( + continue; + } + if (name_end0 == delim) break; +- if (maybe_num && !isdigit(name_end0)) maybe_num = 0; ++ if (maybe_num && !isdigit((unsigned char)name_end0)) maybe_num = 0; + name_end++; + } + p = name_end + 1; +Index: php-7.4.33/ext/pcre/php_pcre.c +=================================================================== +--- php-7.4.33.orig/ext/pcre/php_pcre.c ++++ php-7.4.33/ext/pcre/php_pcre.c +@@ -622,7 +622,7 @@ PHPAPI pcre_cache_entry* pcre_get_compil + + /* Parse through the leading whitespace, and display a warning if we + get to the end without encountering a delimiter. */ +- while (isspace((int)*(unsigned char *)p)) p++; ++ while (isspace((unsigned char)*p)) p++; + if (*p == 0) { + if (key != regex) { + zend_string_release_ex(key, 0); +@@ -636,7 +636,7 @@ PHPAPI pcre_cache_entry* pcre_get_compil + /* Get the delimiter and display a warning if it is alphanumeric + or a backslash. */ + delimiter = *p++; +- if (isalnum((int)*(unsigned char *)&delimiter) || delimiter == '\\') { ++ if (isalnum((unsigned char)delimiter) || delimiter == '\\') { + if (key != regex) { + zend_string_release_ex(key, 0); + } +Index: php-7.4.33/ext/pdo/pdo.c +=================================================================== +--- php-7.4.33.orig/ext/pdo/pdo.c ++++ php-7.4.33/ext/pdo/pdo.c +@@ -262,7 +262,7 @@ PDO_API int php_pdo_parse_data_source(co + } + } + +- while (i < data_source_len && isspace(data_sourcei)) { ++ while (i < data_source_len && isspace((unsigned char)data_sourcei)) { + i++; + } + +Index: php-7.4.33/ext/pdo/pdo_sql_parser.re +=================================================================== +--- php-7.4.33.orig/ext/pdo/pdo_sql_parser.re ++++ php-7.4.33/ext/pdo/pdo_sql_parser.re +@@ -111,7 +111,7 @@ PDO_API int pdo_parse_params(pdo_stmt_t + + if (t == PDO_PARSER_BIND) { + ptrdiff_t len = s.cur - s.tok; +- if ((inquery < (s.cur - len)) && isalnum(*(s.cur - len - 1))) { ++ if ((inquery < (s.cur - len)) && isalnum((unsigned char)s.cur-len - 1)) { + continue; + } + query_type |= PDO_PLACEHOLDER_NAMED; +Index: php-7.4.33/ext/pdo/pdo_stmt.c +=================================================================== +--- php-7.4.33.orig/ext/pdo/pdo_stmt.c ++++ php-7.4.33/ext/pdo/pdo_stmt.c +@@ -210,7 +210,7 @@ int pdo_stmt_describe_columns(pdo_stmt_t + switch (stmt->dbh->desired_case) { + case PDO_CASE_UPPER: + while (*s != '\0') { +- *s = toupper(*s); ++ *s = toupper((unsigned char)*s); + s++; + } + break; +Index: php-7.4.33/ext/standard/dl.c +=================================================================== +--- php-7.4.33.orig/ext/standard/dl.c ++++ php-7.4.33/ext/standard/dl.c +@@ -85,7 +85,7 @@ PHPAPI void *php_load_shlib(char *path, + size_t i = strlen(err); + (*errp)=estrdup(err); + php_win32_error_msg_free(err); +- while (i > 0 && isspace((*errp)i-1)) { (*errp)i-1 = '\0'; i--; } ++ while (i > 0 && isspace((unsigned char)(*errp)i-1)) { (*errp)i-1 = '\0'; i--; } + } else { + (*errp) = estrdup("<No message>"); + } +Index: php-7.4.33/ext/standard/file.c +=================================================================== +--- php-7.4.33.orig/ext/standard/file.c ++++ php-7.4.33/ext/standard/file.c +@@ -2118,7 +2118,7 @@ PHPAPI void php_fgetcsv(php_stream *stre + inc_len = (bptr < limit ? (*bptr == '\0' ? 1 : php_mblen(bptr, limit - bptr)): 0); + if (inc_len == 1) { + char *tmp = bptr; +- while ((*tmp != delimiter) && isspace((int)*(unsigned char *)tmp)) { ++ while ((*tmp != delimiter) && isspace((unsigned char)*tmp)) { + tmp++; + } + if (*tmp == enclosure) { +Index: php-7.4.33/ext/standard/filters.c +=================================================================== +--- php-7.4.33.orig/ext/standard/filters.c ++++ php-7.4.33/ext/standard/filters.c +@@ -1090,7 +1090,7 @@ static php_conv_err_t php_conv_qprint_de + goto out; + } + +- if (!isxdigit((int) *ps)) { ++ if (!isxdigit(*ps)) { + err = PHP_CONV_ERR_INVALID_SEQ; + goto out; + } +Index: php-7.4.33/ext/standard/formatted_print.c +=================================================================== +--- php-7.4.33.orig/ext/standard/formatted_print.c ++++ php-7.4.33/ext/standard/formatted_print.c +@@ -440,13 +440,13 @@ php_formatted_print(zval *z_format, zval + + PRINTF_DEBUG(("sprintf: first looking at '%c', inpos=%d\n", + *format, format - Z_STRVAL_P(z_format))); +- if (isalpha((int)*format)) { ++ if (isalpha((unsigned char)*format)) { + width = precision = 0; + argnum = currarg++; + } else { + /* first look for argnum */ + temppos = format; +- while (isdigit((int)*temppos)) temppos++; ++ while (isdigit((unsigned char)*temppos)) temppos++; + if (*temppos == '$') { + argnum = php_sprintf_getnumber(&format, &format_len); + +@@ -489,7 +489,7 @@ php_formatted_print(zval *z_format, zval + + + /* after modifiers comes width */ +- if (isdigit((int)*format)) { ++ if (isdigit((unsigned char)*format)) { + PRINTF_DEBUG(("sprintf: getting width\n")); + if ((width = php_sprintf_getnumber(&format, &format_len)) < 0) { + efree(result); +@@ -507,7 +507,7 @@ php_formatted_print(zval *z_format, zval + format++; + format_len--; + PRINTF_DEBUG(("sprintf: getting precision\n")); +- if (isdigit((int)*format)) { ++ if (isdigit((unsigned char)*format)) { + if ((precision = php_sprintf_getnumber(&format, &format_len)) < 0) { + efree(result); + php_error_docref(NULL, E_WARNING, "Precision must be greater than zero and less than %d", INT_MAX); +Index: php-7.4.33/ext/standard/ftp_fopen_wrapper.c +=================================================================== +--- php-7.4.33.orig/ext/standard/ftp_fopen_wrapper.c ++++ php-7.4.33/ext/standard/ftp_fopen_wrapper.c +@@ -81,8 +81,8 @@ static inline int get_ftp_result(php_str + { + buffer0 = '\0'; /* in case read fails to read anything */ + while (php_stream_gets(stream, buffer, buffer_size-1) && +- !(isdigit((int) buffer0) && isdigit((int) buffer1) && +- isdigit((int) buffer2) && buffer3 == ' ')); ++ !(isdigit((unsigned char)buffer0) && isdigit((unsigned char)buffer1) && ++ isdigit((unsigned char)buffer2) && buffer3 == ' ')); + return strtol(buffer, NULL, 10); + } + /* }}} */ +@@ -234,7 +234,7 @@ static php_stream *php_ftp_fopen_connect + #define PHP_FTP_CNTRL_CHK(val, val_len, err_msg) { \ + unsigned char *s = (unsigned char *) val, *e = (unsigned char *) s + val_len; \ + while (s < e) { \ +- if (iscntrl(*s)) { \ ++ if (iscntrl((unsigned char)*s)) { \ + php_stream_wrapper_log_error(wrapper, options, err_msg, val); \ + goto connect_errexit; \ + } \ +@@ -346,14 +346,14 @@ static unsigned short php_fopen_do_pasv( + /* parse pasv command (129, 80, 95, 25, 13, 221) */ + tpath = tmp_line; + /* skip over the "227 Some message " part */ +- for (tpath += 4; *tpath && !isdigit((int) *tpath); tpath++); ++ for (tpath += 4; *tpath && !isdigit((unsigned char)*tpath); tpath++); + if (!*tpath) { + return 0; + } + /* skip over the host ip, to get the port */ + hoststart = tpath; + for (i = 0; i < 4; i++) { +- for (; isdigit((int) *tpath); tpath++); ++ for (; isdigit((unsigned char)*tpath); tpath++); + if (*tpath != ',') { + return 0; + } +@@ -838,7 +838,7 @@ static int php_stream_ftp_url_stat(php_s + struct tm tm, tmbuf, *gmt; + time_t stamp; + +- while ((size_t)(p - tmp_line) < sizeof(tmp_line) && !isdigit(*p)) { ++ while ((size_t)(p - tmp_line) < sizeof(tmp_line) && !isdigit((unsigned char)*p)) { + p++; + } + +Index: php-7.4.33/ext/standard/html.c +=================================================================== +--- php-7.4.33.orig/ext/standard/html.c ++++ php-7.4.33/ext/standard/html.c +@@ -753,8 +753,8 @@ static inline int process_numeric_entity + + /* strtol allows whitespace and other stuff in the beginning + * we're not interested */ +- if ((hexadecimal && !isxdigit(**buf)) || +- (!hexadecimal && !isdigit(**buf))) { ++ if ((hexadecimal && !isxdigit((unsigned char)**buf)) || ++ (!hexadecimal && !isdigit((unsigned char)**buf))) { + return FAILURE; + } + +Index: php-7.4.33/ext/standard/math.c +=================================================================== +--- php-7.4.33.orig/ext/standard/math.c ++++ php-7.4.33/ext/standard/math.c +@@ -863,9 +863,9 @@ PHPAPI int _php_math_basetozval(zval *ar + e = s + Z_STRLEN_P(arg); + + /* Skip leading whitespace */ +- while (s < e && isspace(*s)) s++; ++ while (s < e && isspace((unsigned char)*s)) s++; + /* Skip trailing whitespace */ +- while (s < e && isspace(*(e-1))) e--; ++ while (s < e && isspace((unsigned char)e-1)) e--; + + if (e - s >= 2) { + if (base == 16 && s0 == '0' && (s1 == 'x' || s1 == 'X')) s += 2; +@@ -1160,7 +1160,7 @@ PHPAPI zend_string *_php_math_number_for + tmpbuf = strpprintf(0, "%.*F", dec, d); + if (tmpbuf == NULL) { + return NULL; +- } else if (!isdigit((int)ZSTR_VAL(tmpbuf)0)) { ++ } else if (!isdigit((unsigned char)ZSTR_VAL(tmpbuf)0)) { + return tmpbuf; + } + +Index: php-7.4.33/ext/standard/metaphone.c +=================================================================== +--- php-7.4.33.orig/ext/standard/metaphone.c ++++ php-7.4.33/ext/standard/metaphone.c +@@ -83,7 +83,7 @@ static const char _codes26 = + }; + + +-#define ENCODE(c) (isalpha(c) ? _codes((toupper(c)) - 'A') : 0) ++#define ENCODE(c) (isalpha((unsigned char)(c)) ? _codes((toupper((unsigned char)(c))) - 'A') : 0) + + #define isvowel(c) (ENCODE(c) & 1) /* AEIOU */ + +@@ -107,17 +107,17 @@ static const char _codes26 = + * accesssing the array directly... */ + + /* Look at the next letter in the word */ +-#define Next_Letter (toupper(wordw_idx+1)) ++#define Next_Letter (toupper((unsigned char)wordw_idx+1)) + /* Look at the current letter in the word */ +-#define Curr_Letter (toupper(wordw_idx)) ++#define Curr_Letter (toupper((unsigned char)wordw_idx)) + /* Go N letters back. */ +-#define Look_Back_Letter(n) (w_idx >= n ? toupper(wordw_idx-n) : '\0') ++#define Look_Back_Letter(n) (w_idx >= n ? toupper((unsigned char)wordw_idx-n) : '\0') + /* Previous letter. I dunno, should this return null on failure? */ + #define Prev_Letter (Look_Back_Letter(1)) + /* Look two letters down. It makes sure you don't walk off the string. */ +-#define After_Next_Letter (Next_Letter != '\0' ? toupper(wordw_idx+2) \ ++#define After_Next_Letter (Next_Letter != '\0' ? toupper((unsigned char)wordw_idx+2) \ + : '\0') +-#define Look_Ahead_Letter(n) (toupper(Lookahead((char *) word+w_idx, n))) ++#define Look_Ahead_Letter(n) (toupper((unsigned char)Lookahead((char *) word+w_idx, n))) + + + /* Allows us to safely look ahead an arbitrary # of letters */ +@@ -161,7 +161,7 @@ static char Lookahead(char *word, size_t + #define Phone_Len (p_idx) + + /* Note is a letter is a 'break' in the word */ +-#define Isbreak(c) (!isalpha(c)) ++#define Isbreak(c) (!isalpha((unsigned char)(c))) + + /* {{{ metaphone + */ +@@ -196,7 +196,7 @@ static int metaphone(unsigned char *word + + /*-- The first phoneme has to be processed specially. --*/ + /* Find our first letter */ +- for (; !isalpha(Curr_Letter); w_idx++) { ++ for (; !isalpha((unsigned char)Curr_Letter); w_idx++) { + /* On the off chance we were given nothing but crap... */ + if (Curr_Letter == '\0') { + End_Phoned_Word +@@ -280,7 +280,7 @@ static int metaphone(unsigned char *word + */ + + /* Ignore non-alphas */ +- if (!isalpha(Curr_Letter)) ++ if (!isalpha((unsigned char)Curr_Letter)) + continue; + + /* Drop duplicates, except CC */ +Index: php-7.4.33/ext/standard/quot_print.c +=================================================================== +--- php-7.4.33.orig/ext/standard/quot_print.c ++++ php-7.4.33/ext/standard/quot_print.c +@@ -219,11 +219,11 @@ PHP_FUNCTION(quoted_printable_decode) + switch (str_ini) { + case '=': + if (str_ini + 1 && str_ini + 2 && +- isxdigit((int) str_ini + 1) && +- isxdigit((int) str_ini + 2)) ++ isxdigit((unsigned char)str_ini + 1) && ++ isxdigit((unsigned char)str_ini + 2)) + { +- ZSTR_VAL(str_out)j++ = (php_hex2int((int) str_ini + 1) << 4) +- + php_hex2int((int) str_ini + 2); ++ ZSTR_VAL(str_out)j++ = (php_hex2int((unsigned char)str_ini + 1) << 4) ++ + php_hex2int((unsigned char)str_ini + 2); + i += 3; + } else /* check for soft line break according to RFC 2045*/ { + k = 1; +Index: php-7.4.33/ext/standard/scanf.c +=================================================================== +--- php-7.4.33.orig/ext/standard/scanf.c ++++ php-7.4.33/ext/standard/scanf.c +@@ -345,7 +345,7 @@ PHPAPI int ValidateFormat(char *format, + goto xpgCheckDone; + } + +- if ( isdigit( (int)*ch ) ) { ++ if ( isdigit( (unsigned char)*ch ) ) { + /* + * Check for an XPG3-style %n$ specification. Note: there + * must not be a mixture of XPG3 specs and non-XPG3 specs +@@ -664,9 +664,9 @@ PHPAPI int php_sscanf_internal( char *st + /* + * If we see whitespace in the format, skip whitespace in the string. + */ +- if ( isspace( (int)*ch ) ) { ++ if ( isspace( (unsigned char)*ch ) ) { + sch = *string; +- while ( isspace( (int)sch ) ) { ++ while ( isspace( (unsigned char)sch ) ) { + if (*string == '\0') { + goto done; + } +@@ -817,7 +817,7 @@ literal: + if (!(flags & SCAN_NOSKIP)) { + while (*string != '\0') { + sch = *string; +- if (! isspace((int)sch) ) { ++ if (! isspace((unsigned char)sch) ) { + break; + } + string++; +@@ -843,7 +843,7 @@ literal: + end = string; + while (*end != '\0') { + sch = *end; +- if ( isspace( (int)sch ) ) { ++ if ( isspace( (unsigned char)sch ) ) { + break; + } + end++; +Index: php-7.4.33/ext/standard/soundex.c +=================================================================== +--- php-7.4.33.orig/ext/standard/soundex.c ++++ php-7.4.33/ext/standard/soundex.c +@@ -74,7 +74,7 @@ PHP_FUNCTION(soundex) + /* BUG: should also map here accented letters used in non */ + /* English words or names (also found in English text!): */ + /* esstsett, thorn, n-tilde, c-cedilla, s-caron, ... */ +- code = toupper((int)(unsigned char)stri); ++ code = toupper((unsigned char)stri); + if (code >= 'A' && code <= 'Z') { + if (_small == 0) { + /* remember first valid char */ +Index: php-7.4.33/ext/standard/string.c +=================================================================== +--- php-7.4.33.orig/ext/standard/string.c ++++ php-7.4.33/ext/standard/string.c +@@ -3773,9 +3773,9 @@ PHPAPI void php_stripcslashes(zend_strin + case 'f': *target++='\f'; nlen--; break; + case '\\': *target++='\\'; nlen--; break; + case 'x': +- if (source+1 < end && isxdigit((int)(*(source+1)))) { ++ if (source+1 < end && isxdigit((unsigned char)source1)) { + numtmp0 = *++source; +- if (source+1 < end && isxdigit((int)(*(source+1)))) { ++ if (source+1 < end && isxdigit((unsigned char)source1)) { + numtmp1 = *++source; + numtmp2 = '\0'; + nlen-=3; +@@ -4636,7 +4636,7 @@ static void php_hebrev(INTERNAL_FUNCTION + + do { + if (block_type == _HEB_BLOCK_TYPE_HEB) { +- while ((isheb((int)*(tmp+1)) || _isblank((int)*(tmp+1)) || ispunct((int)*(tmp+1)) || (int)*(tmp+1)=='\n' ) && block_end<str_len-1) { ++ while ((isheb((int)*(tmp+1)) || _isblank((int)*(tmp+1)) || ispunct((unsigned char)tmp1) || (int)*(tmp+1)=='\n' ) && block_end<str_len-1) { + tmp++; + block_end++; + block_length++; +@@ -4686,7 +4686,7 @@ static void php_hebrev(INTERNAL_FUNCTION + block_end++; + block_length++; + } +- while ((_isblank((int)*tmp) || ispunct((int)*tmp)) && *tmp!='/' && *tmp!='-' && block_end > block_start) { ++ while ((_isblank((int)*tmp) || ispunct((unsigned char)*tmp)) && *tmp!='/' && *tmp!='-' && block_end > block_start) { + tmp--; + block_end--; + } +@@ -5113,7 +5113,7 @@ int php_tag_find(char *tag, size_t len, + done =1; + break; + default: +- if (!isspace((int)c)) { ++ if (!isspace((unsigned char)c)) { + if (state == 0) { + state=1; + } +@@ -5215,7 +5215,7 @@ state_0: + if (in_q) { + break; + } +- if (isspace(*(p + 1)) && !allow_tag_spaces) { ++ if (isspace((unsigned char)p1) && !allow_tag_spaces) { + *(rp++) = c; + break; + } +@@ -5262,7 +5262,7 @@ state_1: + if (in_q) { + break; + } +- if (isspace(*(p + 1)) && !allow_tag_spaces) { ++ if (isspace((unsigned char)p1) && !allow_tag_spaces) { + goto reg_char_1; + } + depth++; +Index: php-7.4.33/ext/standard/strnatcmp.c +=================================================================== +--- php-7.4.33.orig/ext/standard/strnatcmp.c ++++ php-7.4.33/ext/standard/strnatcmp.c +@@ -41,12 +41,12 @@ compare_right(char const **a, char const + both numbers to know that they have the same magnitude, so we + remember it in BIAS. */ + for(;; (*a)++, (*b)++) { +- if ((*a == aend || !isdigit((int)(unsigned char)**a)) && +- (*b == bend || !isdigit((int)(unsigned char)**b))) ++ if ((*a == aend || !isdigit((unsigned char)**a)) && ++ (*b == bend || !isdigit((unsigned char)**b))) + return bias; +- else if (*a == aend || !isdigit((int)(unsigned char)**a)) ++ else if (*a == aend || !isdigit((unsigned char)**a)) + return -1; +- else if (*b == bend || !isdigit((int)(unsigned char)**b)) ++ else if (*b == bend || !isdigit((unsigned char)**b)) + return +1; + else if (**a < **b) { + if (!bias) +@@ -69,12 +69,12 @@ compare_left(char const **a, char const + /* Compare two left-aligned numbers: the first to have a + different value wins. */ + for(;; (*a)++, (*b)++) { +- if ((*a == aend || !isdigit((int)(unsigned char)**a)) && +- (*b == bend || !isdigit((int)(unsigned char)**b))) ++ if ((*a == aend || !isdigit((unsigned char)**a)) && ++ (*b == bend || !isdigit((unsigned char)**b))) + return 0; +- else if (*a == aend || !isdigit((int)(unsigned char)**a)) ++ else if (*a == aend || !isdigit((unsigned char)**a)) + return -1; +- else if (*b == bend || !isdigit((int)(unsigned char)**b)) ++ else if (*b == bend || !isdigit((unsigned char)**b)) + return +1; + else if (**a < **b) + return -1; +@@ -107,27 +107,27 @@ PHPAPI int strnatcmp_ex(char const *a, s + ca = *ap; cb = *bp; + + /* skip over leading zeros */ +- while (leading && ca == '0' && (ap+1 < aend) && isdigit((int)(unsigned char)*(ap+1))) { ++ while (leading && ca == '0' && (ap+1 < aend) && isdigit((unsigned char)ap1)) { + ca = *++ap; + } + +- while (leading && cb == '0' && (bp+1 < bend) && isdigit((int)(unsigned char)*(bp+1))) { ++ while (leading && cb == '0' && (bp+1 < bend) && isdigit((unsigned char)bp1)) { + cb = *++bp; + } + + leading = 0; + + /* Skip consecutive whitespace */ +- while (isspace((int)(unsigned char)ca)) { ++ while (isspace(ca)) { + ca = *++ap; + } + +- while (isspace((int)(unsigned char)cb)) { ++ while (isspace(cb)) { + cb = *++bp; + } + + /* process run of digits */ +- if (isdigit((int)(unsigned char)ca) && isdigit((int)(unsigned char)cb)) { ++ if (isdigit(ca) && isdigit(cb)) { + fractional = (ca == '0' || cb == '0'); + + if (fractional) +@@ -151,8 +151,8 @@ PHPAPI int strnatcmp_ex(char const *a, s + } + + if (fold_case) { +- ca = toupper((int)(unsigned char)ca); +- cb = toupper((int)(unsigned char)cb); ++ ca = toupper(ca); ++ cb = toupper(cb); + } + + if (ca < cb) +Index: php-7.4.33/ext/standard/type.c +=================================================================== +--- php-7.4.33.orig/ext/standard/type.c ++++ php-7.4.33/ext/standard/type.c +@@ -121,7 +121,7 @@ PHP_FUNCTION(intval) + char *strval = Z_STRVAL_P(num); + size_t strlen = Z_STRLEN_P(num); + +- while (isspace(*strval) && strlen) { ++ while (isspace((unsigned char)*strval) && strlen) { + strval++; + strlen--; + } +Index: php-7.4.33/ext/standard/url.c +=================================================================== +--- php-7.4.33.orig/ext/standard/url.c ++++ php-7.4.33/ext/standard/url.c +@@ -124,7 +124,7 @@ PHPAPI php_url *php_url_parse_ex2(char c + p = s; + while (p < e) { + /* scheme = 1* lowalpha | digit | "+" | "-" | "." */ +- if (!isalpha(*p) && !isdigit(*p) && *p != '+' && *p != '.' && *p != '-') { ++ if (!isalpha((unsigned char)*p) && !isdigit((unsigned char)*p) && *p != '+' && *p != '.' && *p != '-') { + if (e + 1 < ue && e < binary_strcspn(s, ue, "?#")) { + goto parse_port; + } else if (s + 1 < ue && *s == '/' && *(s + 1) == '/') { /* relative-scheme URL */ +@@ -153,7 +153,7 @@ PHPAPI php_url *php_url_parse_ex2(char c + * correctly parse things like a.com:80 + */ + p = e + 1; +- while (p < ue && isdigit(*p)) { ++ while (p < ue && isdigit((unsigned char)*p)) { + p++; + } + +@@ -193,7 +193,7 @@ PHPAPI php_url *php_url_parse_ex2(char c + p = e + 1; + pp = p; + +- while (pp < ue && pp - p < 6 && isdigit(*pp)) { ++ while (pp < ue && pp - p < 6 && isdigit((unsigned char)*pp)) { + pp++; + } + +@@ -434,12 +434,12 @@ static int php_htoi(char *s) + int value; + int c; + +- c = ((unsigned char *)s)0; ++ c = (unsigned char)s0; + if (isupper(c)) + c = tolower(c); + value = (c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10) * 16; + +- c = ((unsigned char *)s)1; ++ c = (unsigned char)s1; + if (isupper(c)) + c = tolower(c); + value += c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10; +@@ -553,8 +553,8 @@ PHPAPI size_t php_url_decode(char *str, + if (*data == '+') { + *dest = ' '; + } +- else if (*data == '%' && len >= 2 && isxdigit((int) *(data + 1)) +- && isxdigit((int) *(data + 2))) { ++ else if (*data == '%' && len >= 2 && isxdigit((unsigned char) *(data + 1)) ++ && isxdigit((unsigned char) *(data + 2))) { + #ifndef CHARSET_EBCDIC + *dest = (char) php_htoi(data + 1); + #else +@@ -649,8 +649,8 @@ PHPAPI size_t php_raw_url_decode(char *s + char *data = str; + + while (len--) { +- if (*data == '%' && len >= 2 && isxdigit((int) *(data + 1)) +- && isxdigit((int) *(data + 2))) { ++ if (*data == '%' && len >= 2 && isxdigit((unsigned char) *(data + 1)) ++ && isxdigit((unsigned char) *(data + 2))) { + #ifndef CHARSET_EBCDIC + *dest = (char) php_htoi(data + 1); + #else +@@ -716,7 +716,7 @@ no_name_header: + c = *p; + *p = '\0'; + s = p + 1; +- while (isspace((int)*(unsigned char *)s)) { ++ while (isspace((unsigned char)*s)) { + s++; + } + +Index: php-7.4.33/ext/standard/url_scanner_ex.re +=================================================================== +--- php-7.4.33.orig/ext/standard/url_scanner_ex.re ++++ php-7.4.33/ext/standard/url_scanner_ex.re +@@ -87,7 +87,7 @@ static int php_ini_on_update_tags(zend_i + + *val++ = '\0'; + for (q = key; *q; q++) { +- *q = tolower(*q); ++ *q = tolower((unsigned char)*q); + } + keylen = q - key; + str = zend_string_init(key, keylen, 1); +@@ -136,7 +136,7 @@ static int php_ini_on_update_hosts(zend_ + char *q; + + for (q = key; *q; q++) { +- *q = tolower(*q); ++ *q = tolower((unsigned char)*q); + } + keylen = q - key; + if (keylen > 0) { +@@ -456,7 +456,7 @@ static inline void handle_tag(STD_PARA) + } + smart_str_appendl(&ctx->tag, start, YYCURSOR - start); + for (i = 0; i < ZSTR_LEN(ctx->tag.s); i++) +- ZSTR_VAL(ctx->tag.s)i = tolower((int)(unsigned char)ZSTR_VAL(ctx->tag.s)i); ++ ZSTR_VAL(ctx->tag.s)i = tolower((unsigned char)ZSTR_VAL(ctx->tag.s)i); + /* intentionally using str_find here, in case the hash value is set, but the string val is changed later */ + if ((ctx->lookup_data = zend_hash_str_find_ptr(ctx->tags, ZSTR_VAL(ctx->tag.s), ZSTR_LEN(ctx->tag.s))) != NULL) { + ok = 1; +Index: php-7.4.33/ext/standard/versioning.c +=================================================================== +--- php-7.4.33.orig/ext/standard/versioning.c ++++ php-7.4.33/ext/standard/versioning.c +@@ -47,8 +47,8 @@ php_canonicalize_version(const char *ver + * s/(^\d\.)(^\D\.)/$1.$2/g; + * s/(^\D\.)(^\d\.)/$1.$2/g; + */ +-#define isdig(x) (isdigit(x)&&(x)!='.') +-#define isndig(x) (!isdigit(x)&&(x)!='.') ++#define isdig(x) (isdigit((unsigned char)(x))&&(x)!='.') ++#define isndig(x) (!isdigit((unsigned char)(x))&&(x)!='.') + #define isspecialver(x) ((x)=='-'||(x)=='_'||(x)=='+') + + lq = *(q - 1); +@@ -61,7 +61,7 @@ php_canonicalize_version(const char *ver + *q++ = '.'; + } + *q++ = *p; +- } else if (!isalnum(*p)) { ++ } else if (!isalnum((unsigned char)*p)) { + if (lq != '.') { + *q++ = '.'; + } +@@ -154,17 +154,17 @@ php_version_compare(const char *orig_ver + if ((n2 = strchr(p2, '.')) != NULL) { + *n2 = '\0'; + } +- if (isdigit(*p1) && isdigit(*p2)) { ++ if (isdigit((unsigned char)*p1) && isdigit((unsigned char)*p2)) { + /* compare element numerically */ + l1 = strtol(p1, NULL, 10); + l2 = strtol(p2, NULL, 10); + compare = ZEND_NORMALIZE_BOOL(l1 - l2); +- } else if (!isdigit(*p1) && !isdigit(*p2)) { ++ } else if (!isdigit((unsigned char)*p1) && !isdigit((unsigned char)*p2)) { + /* compare element names */ + compare = compare_special_version_forms(p1, p2); + } else { + /* mix of names and numbers */ +- if (isdigit(*p1)) { ++ if (isdigit((unsigned char)*p1)) { + compare = compare_special_version_forms("#N#", p2); + } else { + compare = compare_special_version_forms(p1, "#N#"); +@@ -182,13 +182,13 @@ php_version_compare(const char *orig_ver + } + if (compare == 0) { + if (n1 != NULL) { +- if (isdigit(*p1)) { ++ if (isdigit((unsigned char)*p1)) { + compare = 1; + } else { + compare = php_version_compare(p1, "#N#"); + } + } else if (n2 != NULL) { +- if (isdigit(*p2)) { ++ if (isdigit((unsigned char)*p2)) { + compare = -1; + } else { + compare = php_version_compare("#N#", p2); +Index: php-7.4.33/main/SAPI.c +=================================================================== +--- php-7.4.33.orig/main/SAPI.c ++++ php-7.4.33/main/SAPI.c +@@ -195,7 +195,7 @@ static void sapi_read_post_data(void) + *p = 0; + break; + default: +- *p = tolower(*p); ++ *p = tolower((unsigned char)*p); + break; + } + } +@@ -704,10 +704,10 @@ SAPI_API int sapi_header_op(sapi_header_ + header_line = estrndup(header_line, header_line_len); + + /* cut off trailing spaces, linefeeds and carriage-returns */ +- if (header_line_len && isspace(header_lineheader_line_len-1)) { ++ if (header_line_len && isspace((unsigned char)header_lineheader_line_len - 1)) { + do { + header_line_len--; +- } while(header_line_len && isspace(header_lineheader_line_len-1)); ++ } while(header_line_len && isspace((unsigned char)header_lineheader_line_len - 1)); + header_lineheader_line_len='\0'; + } + +Index: php-7.4.33/main/fopen_wrappers.c +=================================================================== +--- php-7.4.33.orig/main/fopen_wrappers.c ++++ php-7.4.33/main/fopen_wrappers.c +@@ -493,7 +493,7 @@ PHPAPI zend_string *php_resolve_path(con + } + + /* Don't resolve paths which contain protocol (except of file://) */ +- for (p = filename; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++); ++ for (p = filename; isalnum((unsigned char)*p) || *p == '+' || *p == '-' || *p == '.'; p++); + if ((*p == ':') && (p - filename > 1) && (p1 == '/') && (p2 == '/')) { + wrapper = php_stream_locate_url_wrapper(filename, &actual_path, STREAM_OPEN_FOR_INCLUDE); + if (wrapper == &php_plain_files_wrapper) { +@@ -529,7 +529,7 @@ PHPAPI zend_string *php_resolve_path(con + /* Check for stream wrapper */ + int is_stream_wrapper = 0; + +- for (p = ptr; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++); ++ for (p = ptr; isalnum((unsigned char)*p) || *p == '+' || *p == '-' || *p == '.'; p++); + if ((*p == ':') && (p - ptr > 1) && (p1 == '/') && (p2 == '/')) { + /* .:// or ..:// is not a stream wrapper */ + if (p-1 != '.' || p-2 != '.' || p - 2 != ptr) { +@@ -598,7 +598,7 @@ PHPAPI zend_string *php_resolve_path(con + actual_path = trypath; + + /* Check for stream wrapper */ +- for (p = trypath; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++); ++ for (p = trypath; isalnum((unsigned char)*p) || *p == '+' || *p == '-' || *p == '.'; p++); + if ((*p == ':') && (p - trypath > 1) && (p1 == '/') && (p2 == '/')) { + wrapper = php_stream_locate_url_wrapper(trypath, &actual_path, STREAM_OPEN_FOR_INCLUDE); + if (!wrapper) { +Index: php-7.4.33/main/php_ini.c +=================================================================== +--- php-7.4.33.orig/main/php_ini.c ++++ php-7.4.33/main/php_ini.c +@@ -42,7 +42,7 @@ + char *tmp = path; \ + while (*tmp) { \ + if (*tmp == '\\') *tmp = '/'; \ +- else *tmp = tolower(*tmp); \ ++ else *tmp = tolower((unsigned char)*tmp); \ + tmp++; \ + } \ + } +Index: php-7.4.33/main/php_variables.c +=================================================================== +--- php-7.4.33.orig/main/php_variables.c ++++ php-7.4.33/main/php_variables.c +@@ -196,7 +196,7 @@ PHPAPI void php_register_variable_ex(cha + + ip++; + index_s = ip; +- if (isspace(*ip)) { ++ if (isspace((unsigned char)*ip)) { + ip++; + } + if (*ip=='') { +@@ -513,7 +513,7 @@ SAPI_API SAPI_TREAT_DATA_FUNC(php_defaul + + if (arg == PARSE_COOKIE) { + /* Remove leading spaces from cookie names, needed for multi-cookie header where ; can be followed by a space */ +- while (isspace(*var)) { ++ while (isspace((unsigned char)*var)) { + var++; + } + if (var == val || *var == '\0') { +Index: php-7.4.33/main/rfc1867.c +=================================================================== +--- php-7.4.33.orig/main/rfc1867.c ++++ php-7.4.33/main/rfc1867.c +@@ -421,7 +421,7 @@ static int multipart_buffer_headers(mult + } + + /* space in the beginning means same header */ +- if (!isspace(line0)) { ++ if (!isspace((unsigned char)line0)) { + value = strchr(line, ':'); + } + +@@ -437,7 +437,7 @@ static int multipart_buffer_headers(mult + } + + *value = '\0'; +- do { value++; } while (isspace(*value)); ++ do { value++; } while (isspace((unsigned char)*value)); + + key = estrdup(line); + smart_string_appends(&buf_value, value); +@@ -534,7 +534,7 @@ static char *substring_conf(char *start, + + static char *php_ap_getword_conf(const zend_encoding *encoding, char *str) + { +- while (*str && isspace(*str)) { ++ while (*str && isspace((unsigned char)*str)) { + ++str; + } + +@@ -550,7 +550,7 @@ static char *php_ap_getword_conf(const z + } else { + char *strend = str; + +- while (*strend && !isspace(*strend)) { ++ while (*strend && !isspace((unsigned char)*strend)) { + ++strend; + } + return substring_conf(str, strend - str, 0); +@@ -817,7 +817,7 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_ + goto fileupload_done; + } + +- while (isspace(*cd)) { ++ while (isspace((unsigned char)*cd)) { + ++cd; + } + +@@ -825,7 +825,7 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_ + { + char *key = NULL, *word = pair; + +- while (isspace(*cd)) { ++ while (isspace((unsigned char)*cd)) { + ++cd; + } + +Index: php-7.4.33/main/snprintf.c +=================================================================== +--- php-7.4.33.orig/main/snprintf.c ++++ php-7.4.33/main/snprintf.c +@@ -391,7 +391,7 @@ PHPAPI char * php_conv_fp(register char + /* + * Check for Infinity and NaN + */ +- if (isalpha((int)*p)) { ++ if (isalpha((unsigned char)*p)) { + *len = strlen(p); + memcpy(buf, p, *len + 1); + *is_negative = FALSE; +@@ -538,11 +538,11 @@ typedef struct buf_area buffy; + #define NUM( c ) ( c - '0' ) + + #define STR_TO_DEC( str, num ) \ +- num = NUM( *str++ ) ; \ +- while ( isdigit((int)*str ) ) \ ++ num = NUM( *(str)++ ) ; \ ++ while ( isdigit((unsigned char)*(str) ) ) \ + { \ + num *= 10 ; \ +- num += NUM( *str++ ) ; \ ++ num += NUM( *(str)++ ) ; \ + } + + /* +@@ -646,7 +646,7 @@ static int format_converter(register buf + /* + * Try to avoid checking for flags, width or precision + */ +- if (isascii((int)*fmt) && !islower((int)*fmt)) { ++ if (isascii((unsigned char)*fmt) && !islower((unsigned char)*fmt)) { + /* + * Recognize flags: -, #, BLANK, + + */ +@@ -668,7 +668,7 @@ static int format_converter(register buf + /* + * Check if a width was specified + */ +- if (isdigit((int)*fmt)) { ++ if (isdigit((unsigned char)*fmt)) { + STR_TO_DEC(fmt, min_width); + adjust_width = YES; + } else if (*fmt == '*') { +@@ -688,7 +688,7 @@ static int format_converter(register buf + if (*fmt == '.') { + adjust_precision = YES; + fmt++; +- if (isdigit((int)*fmt)) { ++ if (isdigit((unsigned char)*fmt)) { + STR_TO_DEC(fmt, precision); + } else if (*fmt == '*') { + precision = va_arg(ap, int); +Index: php-7.4.33/main/spprintf.c +=================================================================== +--- php-7.4.33.orig/main/spprintf.c ++++ php-7.4.33/main/spprintf.c +@@ -152,12 +152,12 @@ + #define NUM(c) (c - '0') + + #define STR_TO_DEC(str, num) do { \ +- num = NUM(*str++); \ +- while (isdigit((int)*str)) { \ ++ num = NUM(*(str)++); \ ++ while (isdigit((unsigned char)*(str))) {\ + num *= 10; \ +- num += NUM(*str++); \ ++ num += NUM(*(str)++); \ + if (num >= INT_MAX / 10) { \ +- while (isdigit((int)*str++)); \ ++ while (isdigit((unsigned char)*(str)++)); \ + break; \ + } \ + } \ +@@ -246,7 +246,7 @@ static void xbuf_format_converter(void * + /* + * Try to avoid checking for flags, width or precision + */ +- if (isascii((int)*fmt) && !islower((int)*fmt)) { ++ if (isascii((unsigned char)*fmt) && !islower((unsigned char)*fmt)) { + /* + * Recognize flags: -, #, BLANK, + + */ +@@ -268,7 +268,7 @@ static void xbuf_format_converter(void * + /* + * Check if a width was specified + */ +- if (isdigit((int)*fmt)) { ++ if (isdigit((unsigned char)*fmt)) { + STR_TO_DEC(fmt, min_width); + adjust_width = YES; + } else if (*fmt == '*') { +@@ -288,7 +288,7 @@ static void xbuf_format_converter(void * + if (*fmt == '.') { + adjust_precision = YES; + fmt++; +- if (isdigit((int)*fmt)) { ++ if (isdigit((unsigned char)*fmt)) { + STR_TO_DEC(fmt, precision); + } else if (*fmt == '*') { + precision = va_arg(ap, int); +Index: php-7.4.33/main/streams/streams.c +=================================================================== +--- php-7.4.33.orig/main/streams/streams.c ++++ php-7.4.33/main/streams/streams.c +@@ -1750,7 +1750,7 @@ static inline int php_stream_wrapper_sch + unsigned int i; + + for(i = 0; i < protocol_len; i++) { +- if (!isalnum((int)protocoli) && ++ if (!isalnum((unsigned char)protocoli) && + protocoli != '+' && + protocoli != '-' && + protocoli != '.') { +@@ -1830,7 +1830,7 @@ PHPAPI php_stream_wrapper *php_stream_lo + return (php_stream_wrapper*)((options & STREAM_LOCATE_WRAPPERS_ONLY) ? NULL : &php_plain_files_wrapper); + } + +- for (p = path; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++) { ++ for (p = path; isalnum((unsigned char)*p) || *p == '+' || *p == '-' || *p == '.'; p++) { + n++; + } + +Index: php-7.4.33/main/streams/transports.c +=================================================================== +--- php-7.4.33.orig/main/streams/transports.c ++++ php-7.4.33/main/streams/transports.c +@@ -95,7 +95,7 @@ PHPAPI php_stream *_php_stream_xport_cre + } + } + +- for (p = name; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++) { ++ for (p = name; isalnum((unsigned char)*p) || *p == '+' || *p == '-' || *p == '.'; p++) { + n++; + } + +Index: php-7.4.33/sapi/cli/php_cli_server.c +=================================================================== +--- php-7.4.33.orig/sapi/cli/php_cli_server.c ++++ php-7.4.33/sapi/cli/php_cli_server.c +@@ -668,7 +668,7 @@ static int sapi_cli_server_register_entr + if (keyi == '-') { + keyi = '_'; + } else { +- keyi = toupper(keyi); ++ keyi = toupper((unsigned char)keyi); + } + } + spprintf(&real_key, 0, "%s_%s", "HTTP", key); +Index: php-7.4.33/sapi/fpm/fpm/fpm_conf.c +=================================================================== +--- php-7.4.33.orig/sapi/fpm/fpm/fpm_conf.c ++++ php-7.4.33/sapi/fpm/fpm/fpm_conf.c +@@ -875,7 +875,7 @@ static int fpm_conf_process_all_pools() + } + + for (i = 0; i < strlen(status); i++) { +- if (!isalnum(statusi) && statusi != '/' && statusi != '-' && statusi != '_' && statusi != '.' && statusi != '~') { ++ if (!isalnum((unsigned char)statusi) && statusi != '/' && statusi != '-' && statusi != '_' && statusi != '.' && statusi != '~') { + zlog(ZLOG_ERROR, "pool %s the status path '%s' must contain only the following characters 'alphanum/_-.~'", wp->config->name, status); + return -1; + } +@@ -898,7 +898,7 @@ static int fpm_conf_process_all_pools() + } + + for (i = 0; i < strlen(ping); i++) { +- if (!isalnum(pingi) && pingi != '/' && pingi != '-' && pingi != '_' && pingi != '.' && pingi != '~') { ++ if (!isalnum((unsigned char)pingi) && pingi != '/' && pingi != '-' && pingi != '_' && pingi != '.' && pingi != '~') { + zlog(ZLOG_ERROR, "pool %s the ping path '%s' must containt only the following characters 'alphanum/_-.~'", wp->config->name, ping); + return -1; + } +Index: php-7.4.33/sapi/litespeed/lsapi_main.c +=================================================================== +--- php-7.4.33.orig/sapi/litespeed/lsapi_main.c ++++ php-7.4.33/sapi/litespeed/lsapi_main.c +@@ -1738,12 +1738,12 @@ PHP_FUNCTION(litespeed_response_headers) + len = p - h->header; + if (p && len > 0 && len < LSAPI_RESP_HTTP_HEADER_MAX) { + memmove( headerBuf, h->header, len ); +- while( len > 0 && (isspace( headerBuflen-1)) ) { ++ while( len > 0 && (isspace((unsigned char)headerBuflen - 1)) ) { + --len; + } + headerBuflen = 0; + if ( len ) { +- while( isspace(*++p)); ++ while(isspace((unsigned char)*++p)); + add_assoc_string_ex(return_value, headerBuf, len, p); + } + } +Index: php-7.4.33/sapi/litespeed/lsapilib.c +=================================================================== +--- php-7.4.33.orig/sapi/litespeed/lsapilib.c ++++ php-7.4.33/sapi/litespeed/lsapilib.c +@@ -2199,7 +2199,7 @@ static char * GetHeaderVar( LSAPI_Reques + + while(( pKey < pKeyEnd )&&( *p )) + { +- char ch = toupper( *pKey ); ++ char ch = toupper( (unsigned char)*pKey ); + if ((ch != *p )||(( *p == '_' )&&( ch != '-'))) + break; + ++p; ++pKey; +@@ -2383,7 +2383,7 @@ int LSAPI_ForeachHeader_r( LSAPI_Request + if ( ch == '-' ) + *p++ = '_'; + else +- *p++ = toupper( ch ); ++ *p++ = toupper( (unsigned char)ch ); + } + *p = 0; + keyLen += 5; +@@ -2628,7 +2628,7 @@ int LSAPI_ParseSockAddr( const char * pB + if ( !pBind ) + return -1; + +- while( isspace( *pBind ) ) ++ while(isspace( (unsigned char)*pBind ) ) + ++pBind; + + strncpy(achAddr, pBind, 255); +Index: php-7.4.33/sapi/phpdbg/phpdbg_cmd.c +=================================================================== +--- php-7.4.33.orig/sapi/phpdbg/phpdbg_cmd.c ++++ php-7.4.33/sapi/phpdbg/phpdbg_cmd.c +@@ -785,9 +785,9 @@ PHPDBG_API char *phpdbg_read_input(char + #endif + } + +- if (buffer && isspace(*buffer)) { ++ if (buffer && isspace((unsigned char)*buffer)) { + char *trimmed = buffer; +- while (isspace(*trimmed)) ++ while (isspace((unsigned char)*trimmed)) + trimmed++; + + trimmed = estrdup(trimmed); +Index: php-7.4.33/sapi/phpdbg/phpdbg_prompt.c +=================================================================== +--- php-7.4.33.orig/sapi/phpdbg/phpdbg_prompt.c ++++ php-7.4.33/sapi/phpdbg/phpdbg_prompt.c +@@ -221,7 +221,7 @@ static void phpdbg_line_init(char *cmd, + + state->line++; + +- while (cmd_len > 0L && isspace(cmdcmd_len-1)) { ++ while (cmd_len > 0L && isspace((unsigned char)cmdcmd_len-1)) { + cmd_len--; + } + +Index: php-7.4.33/sapi/phpdbg/phpdbg_utils.c +=================================================================== +--- php-7.4.33.orig/sapi/phpdbg/phpdbg_utils.c ++++ php-7.4.33/sapi/phpdbg/phpdbg_utils.c +@@ -85,10 +85,10 @@ PHPDBG_API int phpdbg_is_numeric(const c + return 0; + + for (; *str; str++) { +- if (isspace(*str) || *str == '-') { ++ if (isspace((unsigned char)*str) || *str == '-') { + continue; + } +- return isdigit(*str); ++ return isdigit((unsigned char)*str); + } + return 0; + } /* }}} */ +@@ -99,7 +99,7 @@ PHPDBG_API int phpdbg_is_empty(const cha + return 1; + + for (; *str; str++) { +- if (isspace(*str)) { ++ if (isspace((unsigned char)*str)) { + continue; + } + return 0; +@@ -202,12 +202,12 @@ PHPDBG_API char *phpdbg_trim(const char + const char *p = str; + char *new = NULL; + +- while (p && isspace(*p)) { ++ while (p && isspace((unsigned char)*p)) { + ++p; + --len; + } + +- while (*p && isspace(*(p + len -1))) { ++ while (*p && isspace((unsigned char)plen - 1)) { + --len; + } + +Index: php-7.4.33/win32/sendmail.c +=================================================================== +--- php-7.4.33.orig/win32/sendmail.c ++++ php-7.4.33/win32/sendmail.c +@@ -57,7 +57,7 @@ + efree(response); \ + } \ + } +-#define SMTP_SKIP_SPACE(str) { while (isspace(*str)) { str++; } } ++#define SMTP_SKIP_SPACE(str) { while (isspace((unsigned char)*(str))) { (str)++; } } + + + char seps = " ,\t\n"; +@@ -724,7 +724,7 @@ static int PostHeader(char *RPath, char + headers_lc_len = strlen(headers_lc); + + for (i = 0; i < headers_lc_len; i++) { +- headers_lci = tolower(headers_lci); ++ headers_lci = tolower((unsigned char)headers_lci); + } + } + +@@ -852,7 +852,7 @@ return 0; + + /* Resolve the servers IP */ + /* +- if (!isdigit(PW32G(mail_host)0)||!gethostbyname(PW32G(mail_host))) ++ if (!isdigit((unsigned char)PW32G(mail_host)0)||!gethostbyname(PW32G(mail_host))) + { + return (FAILED_TO_RESOLVE_HOST); + }
View file
php7-CVE-2026-7260.patch
Added
@@ -0,0 +1,93 @@ +From 2e0fa0a44441d74bf8cc4e1ce1c8af9cd4209f52 Mon Sep 17 00:00:00 2001 +From: Jakub Zelenka <bukka@php.net> +Date: Sun, 3 May 2026 19:26:31 +0200 +Subject: PATCH Fix GHSA-vc5h-9ppw-p5f3: phar circular symlink crash + +Prevents infinite recursion in phar_get_link_source. +--- + .../tests/tar/files/circular_symlinks.tar | Bin 0 -> 10240 bytes + .../tar/files/circular_symlinks_long.tar | Bin 0 -> 215040 bytes + .../tests/tar/files/circular_symlinks_rho.tar | Bin 0 -> 10240 bytes + .../ghsa-vc5h-9ppw-p5f3-symlink-circular.phpt | 27 ++++++++++ + ext/phar/util.c | 51 ++++++++++++++---- + 5 files changed, 67 insertions(+), 11 deletions(-) + create mode 100644 ext/phar/tests/tar/files/circular_symlinks.tar + create mode 100644 ext/phar/tests/tar/files/circular_symlinks_long.tar + create mode 100644 ext/phar/tests/tar/files/circular_symlinks_rho.tar + create mode 100644 ext/phar/tests/tar/ghsa-vc5h-9ppw-p5f3-symlink-circular.phpt + +Index: php-7.4.33/ext/phar/util.c +=================================================================== +--- php-7.4.33.orig/ext/phar/util.c ++++ php-7.4.33/ext/phar/util.c +@@ -57,30 +57,59 @@ static char *phar_get_link_location(phar + } + /* }}} */ + +-phar_entry_info *phar_get_link_source(phar_entry_info *entry) /* {{{ */ ++static phar_entry_info *phar_follow_one_link(phar_entry_info *entry) + { + phar_entry_info *link_entry; + char *link; + +- if (!entry->link) { +- return entry; +- } +- + link = phar_get_link_location(entry); + if (NULL != (link_entry = zend_hash_str_find_ptr(&(entry->phar->manifest), entry->link, strlen(entry->link))) || + NULL != (link_entry = zend_hash_str_find_ptr(&(entry->phar->manifest), link, strlen(link)))) { + if (link != entry->link) { + efree(link); + } +- return phar_get_link_source(link_entry); +- } else { +- if (link != entry->link) { +- efree(link); ++ return link_entry; ++ } ++ ++ if (link != entry->link) { ++ efree(link); ++ } ++ return NULL; ++} ++ ++phar_entry_info *phar_get_link_source(phar_entry_info *entry) ++{ ++ phar_entry_info *slow, *fast; ++ ++ if (!entry->link) { ++ return entry; ++ } ++ ++ /* ++ * Use Floyd's cycle detection algorithm to follow the symlink chain without unbounded ++ * recursion. Each entry has at most one outgoing link, so if a cycle exists the fast pointer ++ * will eventually meet the slow one. Otherwise the fast pointer reaches the end first. ++ */ ++ slow = fast = entry; ++ while (1) { ++ fast = phar_follow_one_link(fast); ++ if (!fast || !fast->link) { ++ return fast; ++ } ++ fast = phar_follow_one_link(fast); ++ if (!fast || !fast->link) { ++ return fast; ++ } ++ ++ /* no need to check slow as it's always behind */ ++ slow = phar_follow_one_link(slow); ++ ++ if (slow == fast) { ++ /* circular symlink chain */ ++ return NULL; + } +- return NULL; + } + } +-/* }}} */ + + /* retrieve a phar_entry_info's current file pointer for reading contents */ + php_stream *phar_get_efp(phar_entry_info *entry, int follow_links) /* {{{ */
View file
php7-CVE-2026-7261.patch
Added
@@ -0,0 +1,42 @@ +From db2a7f9348fd5dda5fd162061786a664c417bf5b Mon Sep 17 00:00:00 2001 +From: Ilija Tovilo <ilija.tovilo@me.com> +Date: Sun, 3 May 2026 19:57:16 +0200 +Subject: PATCH GHSA-m33r-qmcv-p97q: soap Fix use-after-free after header + parsing failure with SOAP_PERSISTENCE_SESSION + +Fixes GHSA-m33r-qmcv-p97q +Fixes CVE-2026-7261 +--- + ext/soap/soap.c | 12 ++++- + ext/soap/tests/GHSA-m33r-qmcv-p97q.phpt | 58 +++++++++++++++++++++++++ + 2 files changed, 68 insertions(+), 2 deletions(-) + create mode 100644 ext/soap/tests/GHSA-m33r-qmcv-p97q.phpt + +Index: php-7.4.33/ext/soap/soap.c +=================================================================== +--- php-7.4.33.orig/ext/soap/soap.c ++++ php-7.4.33/ext/soap/soap.c +@@ -1807,13 +1807,21 @@ PHP_METHOD(SoapServer, handle) + php_output_discard(); + soap_server_fault_ex(function, &h->retval, h); + efree(fn_name); +- if (service->type == SOAP_CLASS && soap_obj) {zval_ptr_dtor(soap_obj);} ++ if (service->type == SOAP_CLASS && soap_obj) { ++ if (service->soap_class.persistence != SOAP_PERSISTENCE_SESSION) { ++ zval_ptr_dtor(soap_obj); ++ } ++ } + goto fail; + } else if (EG(exception)) { + php_output_discard(); + _soap_server_exception(service, function, ZEND_THIS); + efree(fn_name); +- if (service->type == SOAP_CLASS && soap_obj) {zval_ptr_dtor(soap_obj);} ++ if (service->type == SOAP_CLASS && soap_obj) { ++ if (service->soap_class.persistence != SOAP_PERSISTENCE_SESSION) { ++ zval_ptr_dtor(soap_obj); ++ } ++ } + goto fail; + } + } else if (h->mustUnderstand) {
View file
php7-CVE-2026-7262.patch
Added
@@ -0,0 +1,27 @@ +From 79551ab8b1a97760c739e372f9bc359619f3554d Mon Sep 17 00:00:00 2001 +From: Ilija Tovilo <ilija.tovilo@me.com> +Date: Sat, 25 Apr 2026 00:44:37 +0200 +Subject: PATCH GHSA-hmxp-6pc4-f3vv: soap Fix broken Apache map value NULL + check + +Fixes GHSA-hmxp-6pc4-f3vv +Fixes CVE-2026-7262 +--- + ext/soap/php_encoding.c | 2 +- + ext/soap/tests/GHSA-hmxp-6pc4-f3vv.phpt | 39 +++++++++++++++++++++++++ + 2 files changed, 40 insertions(+), 1 deletion(-) + create mode 100644 ext/soap/tests/GHSA-hmxp-6pc4-f3vv.phpt + +Index: php-7.4.33/ext/soap/php_encoding.c +=================================================================== +--- php-7.4.33.orig/ext/soap/php_encoding.c ++++ php-7.4.33/ext/soap/php_encoding.c +@@ -2706,7 +2706,7 @@ static zval *to_zval_map(zval *ret, enco + } + + xmlValue = get_node(item->children, "value"); +- if (!xmlKey) { ++ if (!xmlValue) { + soap_error0(E_ERROR, "Encoding: Can't decode apache map, missing value"); + } +
View file
php7-CVE-2026-7568.patch
Added
@@ -0,0 +1,40 @@ +From 47def8ce1db1fdbffcfc1f5bb11877a0e22d4b32 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= <tim@tideways-gmbh.com> +Date: Sun, 3 May 2026 20:02:57 +0200 +Subject: PATCH GHSA-96wq-48vp-hh57: metaphone Fix signed integer overflow + of char array offset + +Fixes GHSA-96wq-48vp-hh57 +Fixes CVE-2026-7568 +--- + ext/standard/metaphone.c | 6 +++--- + ext/standard/tests/GHSA-96wq-48vp-hh57.phpt | 22 +++++++++++++++++++++ + 2 files changed, 25 insertions(+), 3 deletions(-) + create mode 100644 ext/standard/tests/GHSA-96wq-48vp-hh57.phpt + +Index: php-7.4.33/ext/standard/metaphone.c +=================================================================== +--- php-7.4.33.orig/ext/standard/metaphone.c ++++ php-7.4.33/ext/standard/metaphone.c +@@ -122,10 +122,10 @@ static const char _codes26 = + + /* Allows us to safely look ahead an arbitrary # of letters */ + /* I probably could have just used strlen... */ +-static char Lookahead(char *word, int how_far) ++static char Lookahead(char *word, size_t how_far) + { + char letter_ahead = '\0'; /* null by default */ +- int idx; ++ size_t idx; + for (idx = 0; wordidx != '\0' && idx < how_far; idx++); + /* Edge forward in the string... */ + +@@ -167,7 +167,7 @@ static char Lookahead(char *word, int ho + */ + static int metaphone(unsigned char *word, size_t word_len, zend_long max_phonemes, zend_string **phoned_word, int traditional) + { +- int w_idx = 0; /* point in the phonization we're at. */ ++ size_t w_idx = 0; /* point in the phonization we're at. */ + size_t p_idx = 0; /* end of the phoned phrase */ + size_t max_buffer_len = 0; /* maximum length of the destination buffer */ +
View file
php7-CVE-2026-91765.patch
Added
@@ -0,0 +1,241 @@ +From 3655b79c7bfa90db004d75a3b282ed0f538f4836 Mon Sep 17 00:00:00 2001 +From: Alexandre Daubois <alex.daubois@gmail.com> +Date: Thu, 17 Sep 2026 08:09:08 +0200 +Subject: PATCH Fix GHSA-rgrp-mwpx-f6rm: unbounded recursion in ext/soap XML + parsing and decoding + +--- + ext/soap/php_encoding.c | 7 ++ + ext/soap/php_soap.h | 3 + + ext/soap/php_xml.c | 102 ++++++++++++++---- + ext/soap/soap.c | 1 + + .../tests/GHSA-rgrp-mwpx-f6rm-href-chain.phpt | 47 ++++++++ + .../tests/GHSA-rgrp-mwpx-f6rm-href-cycle.phpt | 43 ++++++++ + ext/soap/tests/GHSA-rgrp-mwpx-f6rm.phpt | 89 +++++++++++++++ + 7 files changed, 272 insertions(+), 20 deletions(-) + create mode 100644 ext/soap/tests/GHSA-rgrp-mwpx-f6rm-href-chain.phpt + create mode 100644 ext/soap/tests/GHSA-rgrp-mwpx-f6rm-href-cycle.phpt + create mode 100644 ext/soap/tests/GHSA-rgrp-mwpx-f6rm.phpt + +Index: php-7.4.33/ext/soap/php_encoding.c +=================================================================== +--- php-7.4.33.orig/ext/soap/php_encoding.c ++++ php-7.4.33/ext/soap/php_encoding.c +@@ -558,7 +558,12 @@ static zval *master_to_zval_int(zval *re + } + } + if (encode->to_zval) { ++ if (SOAP_GLOBAL(decode_depth) >= SOAP_MAX_DECODE_DEPTH) { ++ soap_error0(E_ERROR, "Encoding: Nesting level too deep"); ++ } ++ SOAP_GLOBAL(decode_depth)++; + ret = encode->to_zval(ret, &encode->details, data); ++ SOAP_GLOBAL(decode_depth)--; + } + return ret; + } +@@ -3424,6 +3429,7 @@ void encode_reset_ns() + { + SOAP_GLOBAL(cur_uniq_ns) = 0; + SOAP_GLOBAL(cur_uniq_ref) = 0; ++ SOAP_GLOBAL(decode_depth) = 0; + if (SOAP_GLOBAL(ref_map)) { + zend_hash_destroy(SOAP_GLOBAL(ref_map)); + } else { +@@ -3436,6 +3442,7 @@ void encode_finish() + { + SOAP_GLOBAL(cur_uniq_ns) = 0; + SOAP_GLOBAL(cur_uniq_ref) = 0; ++ SOAP_GLOBAL(decode_depth) = 0; + if (SOAP_GLOBAL(ref_map)) { + zend_hash_destroy(SOAP_GLOBAL(ref_map)); + efree(SOAP_GLOBAL(ref_map)); +Index: php-7.4.33/ext/soap/php_soap.h +=================================================================== +--- php-7.4.33.orig/ext/soap/php_soap.h ++++ php-7.4.33/ext/soap/php_soap.h +@@ -152,6 +152,8 @@ struct _soapService { + #define SOAP_SSL_METHOD_SSLv3 2 + #define SOAP_SSL_METHOD_SSLv23 3 + ++#define SOAP_MAX_XML_DEPTH 2048 ++#define SOAP_MAX_DECODE_DEPTH (SOAP_MAX_XML_DEPTH * 2) + + ZEND_BEGIN_MODULE_GLOBALS(soap) + HashTable defEncNs; /* mapping of default namespaces to prefixes */ +@@ -177,6 +179,7 @@ ZEND_BEGIN_MODULE_GLOBALS(soap) + HashTable wsdl_cache; + int cur_uniq_ref; + HashTable *ref_map; ++ unsigned int decode_depth; + ZEND_END_MODULE_GLOBALS(soap) + + #ifdef ZTS +Index: php-7.4.33/ext/soap/php_xml.c +=================================================================== +--- php-7.4.33.orig/ext/soap/php_xml.c ++++ php-7.4.33/ext/soap/php_xml.c +@@ -37,36 +37,72 @@ static int is_blank(const xmlChar* str) + return 1; + } + +-/* removes all empty text, comments and other insignoficant nodes */ ++/* removes all empty text, comments and other insignoficant nodes. ++ * Iterative because recursion overflows the stack on a deep document. */ + static void cleanup_xml_node(xmlNodePtr node) + { +- xmlNodePtr trav; +- xmlNodePtr del = NULL; ++ xmlNodePtr parent = node; ++ xmlNodePtr trav = node->children; + +- trav = node->children; + while (trav != NULL) { +- if (del != NULL) { +- xmlUnlinkNode(del); +- xmlFreeNode(del); +- del = NULL; +- } ++ xmlNodePtr next = trav->next; ++ + if (trav->type == XML_TEXT_NODE) { + if (is_blank(trav->content)) { +- del = trav; ++ xmlUnlinkNode(trav); ++ xmlFreeNode(trav); + } + } else if ((trav->type != XML_ELEMENT_NODE) && + (trav->type != XML_CDATA_SECTION_NODE)) { +- del = trav; ++ xmlUnlinkNode(trav); ++ xmlFreeNode(trav); + } else if (trav->children != NULL) { +- cleanup_xml_node(trav); ++ parent = trav; ++ trav = trav->children; ++ continue; + } +- trav = trav->next; ++ ++ while (next == NULL) { ++ if (parent == node) { ++ return; ++ } ++ next = parent->next; ++ parent = parent->parent; ++ } ++ trav = next; + } +- if (del != NULL) { +- xmlUnlinkNode(del); +- xmlFreeNode(del); ++} ++ ++#if LIBXML_VERSION < 21300 ++static int is_nesting_too_deep(xmlNodePtr node) ++{ ++ xmlNodePtr trav = node->children; ++ unsigned int depth = 0; ++ ++ while (trav != NULL) { ++ /* An entity reference borrows its declaration as child list, and that ++ * declaration hangs off the DTD, so descending leaves the document. */ ++ if (trav->children != NULL && ++ trav->type != XML_ENTITY_REF_NODE && ++ trav->type != XML_DTD_NODE) { ++ if (++depth > SOAP_MAX_XML_DEPTH) { ++ return TRUE; ++ } ++ trav = trav->children; ++ continue; ++ } ++ while (trav->next == NULL) { ++ trav = trav->parent; ++ if (trav == node) { ++ return FALSE; ++ } ++ depth--; ++ } ++ trav = trav->next; + } ++ return FALSE; + } ++#endif + + static void soap_ignorableWhitespace(void *ctx, const xmlChar *ch, int len) + { +@@ -124,6 +160,15 @@ xmlDocPtr soap_xmlParseFile(const char * + */ + + if (ret) { ++#if LIBXML_VERSION < 21300 ++ if (is_nesting_too_deep((xmlNodePtr)ret)) { ++ /* php_sdl.c reports xmlGetLastError() as the reason, and libxml2 did ++ * not fail here, so drop the error an earlier parse left behind. */ ++ xmlResetLastError(); ++ xmlFreeDoc(ret); ++ return NULL; ++ } ++#endif + cleanup_xml_node((xmlNodePtr)ret); + } + return ret; +@@ -171,6 +216,13 @@ xmlDocPtr soap_xmlParseMemory(const void + xmlCleanupParser(); + */ + ++#if LIBXML_VERSION < 21300 ++ if (ret && is_nesting_too_deep((xmlNodePtr)ret)) { ++ xmlFreeDoc(ret); ++ ret = NULL; ++ } ++#endif ++ + /* + if (ret) { + cleanup_xml_node((xmlNodePtr)ret); +@@ -293,6 +345,8 @@ xmlNodePtr get_node_with_attribute_ex(xm + + xmlNodePtr get_node_with_attribute_recursive_ex(xmlNodePtr node, char *name, char *name_ns, char *attribute, char *value, char *attr_ns) + { ++ unsigned int depth = 0; ++ + while (node != NULL) { + if (node_is_equal_ex(node, name, name_ns)) { + xmlAttrPtr attr = get_attribute_ex(node->properties, attribute, attr_ns); +@@ -300,11 +354,19 @@ xmlNodePtr get_node_with_attribute_recur + return node; + } + } +- if (node->children != NULL) { +- xmlNodePtr tmp = get_node_with_attribute_recursive_ex(node->children, name, name_ns, attribute, value, attr_ns); +- if (tmp) { +- return tmp; ++ if (node->children != NULL && ++ node->type != XML_ENTITY_REF_NODE && ++ node->type != XML_DTD_NODE) { ++ node = node->children; ++ depth++; ++ continue; ++ } ++ while (node->next == NULL) { ++ if (depth == 0) { ++ return NULL; + } ++ node = node->parent; ++ depth--; + } + node = node->next; + } +Index: php-7.4.33/ext/soap/soap.c +=================================================================== +--- php-7.4.33.orig/ext/soap/soap.c ++++ php-7.4.33/ext/soap/soap.c +@@ -579,6 +579,7 @@ static void php_soap_init_globals(zend_s + soap_globals->soap_version = SOAP_1_1; + soap_globals->mem_cache = NULL; + soap_globals->ref_map = NULL; ++ soap_globals->decode_depth = 0; + } + + PHP_MSHUTDOWN_FUNCTION(soap)
View file
php7-CVE-2026-91766.patch
Added
@@ -0,0 +1,184 @@ +From 5af9465ca890be679033d5fb0dc89b6ea071326b Mon Sep 17 00:00:00 2001 +From: Alexandre Daubois <alex.daubois@gmail.com> +Date: Mon, 14 Sep 2026 09:12:03 +0200 +Subject: PATCH Fix GHSA-fpwc-w8rq-cr92: strip credentials from user headers + on cross-origin redirects + +Authorization, Cookie and Proxy-Authorization set through the http context +were forwarded verbatim when follow_location sent the request to another +origin. They are now stripped from the user header bag whenever the +redirect target differs in scheme, host or port, including when the header +name is repeated or the bag uses malformed line endings. + +Co-authored-by: Jakub Zelenka <bukka@php.net> +--- + ext/standard/http_fopen_wrapper.c | 109 +++++++++--- + ext/standard/tests/http/bug61548.phpt | 2 - + .../tests/http/ghsa-fpwc-w8rq-cr92.phpt | 159 ++++++++++++++++++ + 3 files changed, 248 insertions(+), 22 deletions(-) + create mode 100644 ext/standard/tests/http/ghsa-fpwc-w8rq-cr92.phpt + +Index: php-7.4.33/ext/standard/http_fopen_wrapper.c +=================================================================== +--- php-7.4.33.orig/ext/standard/http_fopen_wrapper.c ++++ php-7.4.33/ext/standard/http_fopen_wrapper.c +@@ -83,6 +83,8 @@ + + #define HTTP_WRAPPER_HEADER_INIT 1 + #define HTTP_WRAPPER_REDIRECTED 2 ++#define HTTP_WRAPPER_STRIP_AUTH 8 ++ + + zend_string *zend_string_concat3( + const char *str1, size_t str1_len, +@@ -99,27 +101,68 @@ zend_string *zend_string_concat3( + + return res; + } ++static char *next_header_line(char *line) ++{ ++ while (*line != '\0' && *line != '\r' && *line != '\n') { ++ line++; ++ } ++ if (*line == '\r') { ++ line++; ++ } ++ if (*line == '\n') { ++ line++; ++ } ++ ++ return line; ++} + ++/* Removes every line whose header name matches, along with the folded ++ * continuation lines carrying the rest of its value. Neither a repeated header ++ * nor an occurrence of the name inside another header's value may leave the real ++ * header behind, as that would defeat HTTP_WRAPPER_STRIP_AUTH. */ + static inline void strip_header(char *header_bag, char *lc_header_bag, + const char *lc_header_name) + { +- char *lc_header_start = strstr(lc_header_bag, lc_header_name); +- if (lc_header_start +- && (lc_header_start == lc_header_bag || *(lc_header_start-1) == '\n') +- ) { +- char *header_start = header_bag + (lc_header_start - lc_header_bag); +- char *lc_eol = strchr(lc_header_start, '\n'); ++ size_t name_len = strlen(lc_header_name); ++ char *lc_line = lc_header_bag; + +- if (lc_eol) { +- char *eol = header_start + (lc_eol - lc_header_start); +- size_t eollen = strlen(lc_eol); ++ while (*lc_line != '\0') { ++ if (strncmp(lc_line, lc_header_name, name_len) != 0) { ++ lc_line = next_header_line(lc_line); ++ continue; ++ } + +- memmove(lc_header_start, lc_eol+1, eollen); +- memmove(header_start, eol+1, eollen); +- } else { +- *lc_header_start = '\0'; +- *header_start = '\0'; ++ /* the whitespace RFC 7230 forbids before the colon is tolerated by some ++ * servers, so it must not hide the header from us either */ ++ const char *lc_colon = lc_line + name_len; ++ while (*lc_colon == ' ' || *lc_colon == '\t') { ++ lc_colon++; ++ } ++ ++ if (*lc_colon != ':') { ++ lc_line = next_header_line(lc_line); ++ continue; ++ } ++ ++ char *lc_next = next_header_line(lc_line); ++ while (*lc_next == ' ' || *lc_next == '\t') { ++ lc_next = next_header_line(lc_next); ++ } ++ ++ if (*lc_next == '\0') { ++ /* drop the preceding line break too, or the one appended after the bag ++ * would close the header block early */ ++ while (lc_line > lc_header_bag ++ && (*(lc_line - 1) == '\r' || *(lc_line - 1) == '\n')) { ++ --lc_line; ++ } + } ++ ++ size_t tail_len = strlen(lc_next) + 1; ++ char *line = header_bag + (lc_line - lc_header_bag); ++ ++ memmove(line, header_bag + (lc_next - lc_header_bag), tail_len); ++ memmove(lc_line, lc_next, tail_len); + } + } + +@@ -688,8 +731,23 @@ finish: + + if (!header_init) { + /* strip POST headers on redirect */ +- strip_header(user_headers, t, "content-length:"); +- strip_header(user_headers, t, "content-type:"); ++ strip_header(user_headers, t, "content-length"); ++ strip_header(user_headers, t, "content-type"); ++ } ++ ++ if (flags & HTTP_WRAPPER_STRIP_AUTH) { ++ strip_header(user_headers, t, "authorization"); ++ strip_header(user_headers, t, "cookie"); ++ if (!use_proxy) { ++ strip_header(user_headers, t, "proxy-authorization"); ++ } ++ } ++ ++ if (*user_headers == '\0') { ++ /* everything got stripped, keeping the empty bag would append a ++ * stray CRLF and end the header block early */ ++ efree(user_headers); ++ user_headers = NULL; + } + + if (check_has_header(t, "user-agent:")) { +@@ -1082,14 +1140,22 @@ finish: + header_info.location = NULL; + } + +- php_url_free(resource); +- /* check for invalid redirection URLs */ +- if ((resource = php_url_parse(new_path)) == NULL) { ++ php_url *new_resource = php_url_parse(new_path); ++ if (new_resource == NULL) { + php_stream_wrapper_log_error(wrapper, options, "Invalid redirect URL! %s", new_path); + efree(new_path); + goto out; + } + ++ int default_port = use_ssl ? 443 : 80; ++ bool same_origin = zend_string_equals_ci(resource->scheme, new_resource->scheme) ++ && zend_string_equals_ci(resource->host, new_resource->host) ++ && (resource->port ? resource->port : default_port) ++ == (new_resource->port ? new_resource->port : default_port); ++ ++ php_url_free(resource); ++ resource = new_resource; ++ + #define CHECK_FOR_CNTRL_CHARS(val) { \ + if (val) { \ + unsigned char *s, *e; \ +@@ -1111,9 +1177,14 @@ finish: + CHECK_FOR_CNTRL_CHARS(resource->pass); + CHECK_FOR_CNTRL_CHARS(resource->path); + } ++ ++ int new_flags = HTTP_WRAPPER_REDIRECTED | (flags & HTTP_WRAPPER_STRIP_AUTH); ++ if (!same_origin) { ++ new_flags |= HTTP_WRAPPER_STRIP_AUTH; ++ } + stream = php_stream_url_wrap_http_ex( + wrapper, new_path, mode, options, opened_path, context, +- --redirect_max, HTTP_WRAPPER_REDIRECTED, response_header STREAMS_CC); ++ --redirect_max, new_flags, response_header STREAMS_CC); + efree(new_path); + } else { + php_stream_wrapper_log_error(wrapper, options, "HTTP request failed! %s", tmp_line);
View file
php7-CVE-2026-91767.patch
Added
@@ -0,0 +1,37 @@ +From 78cc82b37a340840c6fbff676f513eb4e3d96533 Mon Sep 17 00:00:00 2001 +From: Jakub Zelenka <bukka@php.net> +Date: Mon, 10 Aug 2026 14:15:35 +0200 +Subject: PATCH Fix GHSA-xr7j-rvgx-xq5p: OOB read in + php_openssl_matches_wildcard_name() + +The memchr() length underflowed when the wildcard prefix and suffix +overlapped in the subject name (e.g. CN "a*aaaa" against peer name "aaaa"). +--- + ext/openssl/tests/GHSA-xr7j-rvgx-xq5p.phpt | 67 ++++++++++++++++++++++ + ext/openssl/xp_ssl.c | 5 +- + 2 files changed, 69 insertions(+), 3 deletions(-) + create mode 100644 ext/openssl/tests/GHSA-xr7j-rvgx-xq5p.phpt + +Index: php-7.4.33/ext/openssl/xp_ssl.c +=================================================================== +--- php-7.4.33.orig/ext/openssl/xp_ssl.c ++++ php-7.4.33/ext/openssl/xp_ssl.c +@@ -389,8 +389,7 @@ static zend_bool php_openssl_x509_finger + static zend_bool php_openssl_matches_wildcard_name(const char *subjectname, const char *certname) /* {{{ */ + { + char *wildcard = NULL; +- ptrdiff_t prefix_len; +- size_t suffix_len, subject_len; ++ size_t prefix_len, suffix_len, subject_len; + + if (strcasecmp(subjectname, certname) == 0) { + return 1; +@@ -409,7 +408,7 @@ static zend_bool php_openssl_matches_wil + + suffix_len = strlen(wildcard + 1); + subject_len = strlen(subjectname); +- if (suffix_len <= subject_len) { ++ if (suffix_len + prefix_len <= subject_len) { + /* 2) suffix must match + * 3) no . between prefix and suffix + **/
View file
php7-CVE-2026-91768.patch
Added
@@ -0,0 +1,27 @@ +From dcdfcf86fcf7f42fa98dd3d000f310ebdad41965 Mon Sep 17 00:00:00 2001 +From: Alexandre Daubois <alex.daubois@gmail.com> +Date: Tue, 25 Aug 2026 11:23:52 +0200 +Subject: PATCH Fix GHSA-62xp-839h-2637: FastCGI allowed_clients compared + only 96 bits of IPv6 addresses + +--- + main/fastcgi.c | 2 +- + ...a-62xp-839h-2637-ipv6-allowed-clients.phpt | 52 +++++++++++++++++++ + ...xp-839h-2637-v4mapped-allowed-clients.phpt | 52 +++++++++++++++++++ + 3 files changed, 105 insertions(+), 1 deletion(-) + create mode 100644 sapi/fpm/tests/ghsa-62xp-839h-2637-ipv6-allowed-clients.phpt + create mode 100644 sapi/fpm/tests/ghsa-62xp-839h-2637-v4mapped-allowed-clients.phpt + +Index: php-7.4.33/main/fastcgi.c +=================================================================== +--- php-7.4.33.orig/main/fastcgi.c ++++ php-7.4.33/main/fastcgi.c +@@ -1343,7 +1343,7 @@ static int fcgi_is_allowed() { + if (client_sa.sa.sa_family == AF_INET6) { + for (i = 0; allowed_clientsi.sa.sa_family ; i++) { + if (allowed_clientsi.sa.sa_family == AF_INET6 +- && !memcmp(&client_sa.sa_inet6.sin6_addr, &allowed_clientsi.sa_inet6.sin6_addr, 12)) { ++ && !memcmp(&client_sa.sa_inet6.sin6_addr, &allowed_clientsi.sa_inet6.sin6_addr, sizeof(client_sa.sa_inet6.sin6_addr))) { + return 1; + } + #ifdef IN6_IS_ADDR_V4MAPPED
View file
php7-CVE-2026-91769.patch
Added
@@ -0,0 +1,97 @@ +From 0bb308eb4cf699e707efbcf97ffb70e46a176be7 Mon Sep 17 00:00:00 2001 +From: Jakub Zelenka <bukka@php.net> +Date: Mon, 10 Aug 2026 22:25:55 +0200 +Subject: PATCH Fix GHSA-vvx9-73fr-5jjx: do not fall back to CN if the cert + has a service ID + +RFC 6125 6.4.4 forbids matching CN-ID if the certificate presents a DNS-ID, +SRV-ID or URI-ID. Falling back allowed a CA that validated only one of those +identities to leave an unvalidated CN to be matched as a host name. + +IP-ID is left out as it is out of scope of RFC 6125 and suppressing CN there +would break IP-only SAN certificates. +--- + ext/openssl/tests/san_absent_cn_fallback.phpt | 61 ++++++++++++++++++ + ext/openssl/tests/san_no_cn_fallback.phpt | 64 +++++++++++++++++++ + ext/openssl/tests/san_peer_matching.phpt | 2 +- + ext/openssl/tests/san_srv_no_cn_fallback.phpt | 57 +++++++++++++++++ + ext/openssl/tests/san_uri_no_cn_fallback.phpt | 57 +++++++++++++++++ + ext/openssl/xp_ssl.c | 28 +++++++- + 6 files changed, 265 insertions(+), 4 deletions(-) + create mode 100644 ext/openssl/tests/san_absent_cn_fallback.phpt + create mode 100644 ext/openssl/tests/san_no_cn_fallback.phpt + create mode 100644 ext/openssl/tests/san_srv_no_cn_fallback.phpt + create mode 100644 ext/openssl/tests/san_uri_no_cn_fallback.phpt + +Index: php-7.4.33/ext/openssl/xp_ssl.c +=================================================================== +--- php-7.4.33.orig/ext/openssl/xp_ssl.c ++++ php-7.4.33/ext/openssl/xp_ssl.c +@@ -421,7 +421,8 @@ static zend_bool php_openssl_matches_wil + } + /* }}} */ + +-static zend_bool php_openssl_matches_san_list(X509 *peer, const char *subject_name) /* {{{ */ ++static zend_bool php_openssl_matches_san_list( ++ X509 *peer, const char *subject_name, zend_bool *has_service_id) + { + int i, len; + unsigned char *cert_name = NULL; +@@ -430,10 +431,14 @@ static zend_bool php_openssl_matches_san + GENERAL_NAMES *alt_names = X509_get_ext_d2i(peer, NID_subject_alt_name, 0, 0); + int alt_name_count = sk_GENERAL_NAME_num(alt_names); + ++ *has_service_id = 0; ++ + for (i = 0; i < alt_name_count; i++) { + GENERAL_NAME *san = sk_GENERAL_NAME_value(alt_names, i); + + if (san->type == GEN_DNS) { ++ *has_service_id = 1; ++ + ASN1_STRING_to_UTF8(&cert_name, san->d.dNSName); + if ((size_t)ASN1_STRING_length(san->d.dNSName) != strlen((const char*)cert_name)) { + OPENSSL_free(cert_name); +@@ -472,6 +477,16 @@ static zend_bool php_openssl_matches_san + * Because IP SAN names are officially deprecated and are + * not allowed by CAs starting in 2015. Deal with it. + */ ++ } else if (san->type == GEN_URI) { ++ *has_service_id = 1; ++ } else if (san->type == GEN_OTHERNAME) { ++ char oid32; ++ ++ /* SRV-ID, matched by OID because NID_SRVName needs OpenSSL 3.0 */ ++ if (OBJ_obj2txt(oid, sizeof(oid), san->d.otherName->type_id, 1) > 0 ++ && strcmp(oid, "1.3.6.1.5.5.7.8.7") == 0) { ++ *has_service_id = 1; ++ } + } + } + +@@ -479,7 +494,6 @@ static zend_bool php_openssl_matches_san + + return 0; + } +-/* }}} */ + + static zend_bool php_openssl_matches_common_name(X509 *peer, const char *subject_name) /* {{{ */ + { +@@ -585,8 +599,16 @@ static int php_openssl_apply_peer_verifi + } + + if (peer_name) { +- if (php_openssl_matches_san_list(peer, peer_name)) { ++ zend_bool has_service_id = 0; ++ ++ if (php_openssl_matches_san_list(peer, peer_name, &has_service_id)) { + return SUCCESS; ++ } else if (has_service_id) { ++ /* CN must be ignored if the certificate presents a service identity. */ ++ php_error_docref(NULL, E_WARNING, ++ "Peer certificate subjectAltName did not match expected name `%s'", ++ peer_name); ++ return FAILURE; + } else if (php_openssl_matches_common_name(peer, peer_name)) { + return SUCCESS; + } else {
View file
php7-CVE-2026-92842.patch
Added
@@ -0,0 +1,31 @@ +Index: php-7.4.33/ext/standard/filters.c +=================================================================== +--- php-7.4.33.orig/ext/standard/filters.c ++++ php-7.4.33/ext/standard/filters.c +@@ -367,7 +367,7 @@ static php_conv_err_t php_conv_base64_en + inst->line_ccnt = line_len; + inst->line_len = line_len; + if (lbchars != NULL) { +- inst->lbchars = (lbchars_dup ? pestrdup(lbchars, persistent) : lbchars); ++ inst->lbchars = (lbchars_dup ? pestrndup(lbchars, lbchars_len, persistent) : lbchars); + inst->lbchars_len = lbchars_len; + } else { + inst->lbchars = NULL; +@@ -976,7 +976,7 @@ static php_conv_err_t php_conv_qprint_en + inst->line_ccnt = line_len; + inst->line_len = line_len; + if (lbchars != NULL) { +- inst->lbchars = (lbchars_dup ? pestrdup(lbchars, persistent) : lbchars); ++ inst->lbchars = (lbchars_dup ? pestrndup(lbchars, lbchars_len, persistent) : lbchars); + inst->lbchars_len = lbchars_len; + } else { + inst->lbchars = NULL; +@@ -1189,7 +1189,7 @@ static php_conv_err_t php_conv_qprint_de + inst->next_char = 0; + inst->lb_ptr = inst->lb_cnt = 0; + if (lbchars != NULL) { +- inst->lbchars = (lbchars_dup ? pestrdup(lbchars, persistent) : lbchars); ++ inst->lbchars = (lbchars_dup ? pestrndup(lbchars, lbchars_len, persistent) : lbchars); + inst->lbchars_len = lbchars_len; + } else { + inst->lbchars = NULL;
View file
php7-CVE-2026-93682.patch
Added
@@ -0,0 +1,41 @@ +From 547566f17a12b4900efb69a7cf8cd325d00613a2 Mon Sep 17 00:00:00 2001 +From: Ilia Alshanetsky <ilia@ilia.ws> +Date: Mon, 24 Aug 2026 12:05:47 -0400 +Subject: PATCH http Fix out-of-bounds read on empty Location header + +An empty Location header allocates a single byte for the NUL +terminator, so reading location1 in the relative-redirect branch +over-reads heap memory and could append a garbage-derived path to the +redirect target instead of the correct host root. Use location_len +instead of strlen, and skip the relative join when location_len is 0, +so the second byte is never read. + +Closes GH-23467 +--- + ext/standard/http_fopen_wrapper.c | 4 +-- + .../http/http_empty_location_redirect.phpt | 36 +++++++++++++++++++ + 2 files changed, 38 insertions(+), 2 deletions(-) + create mode 100644 ext/standard/tests/http/http_empty_location_redirect.phpt + +Index: php-7.4.33/ext/standard/http_fopen_wrapper.c +=================================================================== +--- php-7.4.33.orig/ext/standard/http_fopen_wrapper.c ++++ php-7.4.33/ext/standard/http_fopen_wrapper.c +@@ -1034,7 +1034,7 @@ finish: + + char *new_path = NULL; + +- if (strlen(header_info.location) < 8 || ++ if (header_info.location_len < 8 || + (strncasecmp(header_info.location, "http://", sizeof("http://")-1) && + strncasecmp(header_info.location, "https://", sizeof("https://")-1) && + strncasecmp(header_info.location, "ftp://", sizeof("ftp://")-1) && +@@ -1042,7 +1042,7 @@ finish: + { + char *loc_path = NULL; + if (*header_info.location != '/') { +- if (*(header_info.location+1) != '\0' && resource->path) { ++ if (header_info.location_len > 0 && resource->path) { + char *s = strrchr(ZSTR_VAL(resource->path), '/'); + if (!s) { + s = ZSTR_VAL(resource->path);
View file
php7-CVE-2026-9672.patch
Added
@@ -0,0 +1,42 @@ +From fcd691b377d02285740744bee17c0f298be227d5 Mon Sep 17 00:00:00 2001 +From: Ilija Tovilo <ilija.tovilo@me.com> +Date: Tue, 28 Jul 2026 02:48:11 +0200 +Subject: PATCH libgd patch for CVE-2026-9672 + +Patch by Pierre Joye (pierrejoye). +--- + ext/gd/libgd/gd_gif_in.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/ext/gd/libgd/gd_gif_in.c b/ext/gd/libgd/gd_gif_in.c +index 1f697236107f..e055f9024455 100644 +--- a/ext/gd/libgd/gd_gif_in.c ++++ b/ext/gd/libgd/gd_gif_in.c +@@ -450,7 +450,7 @@ LWZReadByte_(gdIOCtx *fd, LZW_STATIC_DATA *sd, char flag, int input_code_size, i + sd->table1i = i; + } + for (; i < (1<<MAX_LWZ_BITS); ++i) +- sd->table0i = sd->table10 = 0; ++ sd->table0i = sd->table1i = 0; + + sd->sp = sd->stack; + +@@ -494,6 +494,8 @@ LWZReadByte_(gdIOCtx *fd, LZW_STATIC_DATA *sd, char flag, int input_code_size, i + + if (count != 0) + return -2; ++ ++ return -2; + } + + incode = code; +@@ -560,7 +562,7 @@ ReadImage(gdImagePtr im, gdIOCtx *fd, int len, int height, unsigned char (*cmap) + int v; + int xpos = 0, ypos = 0, pass = 0; + int i; +- LZW_STATIC_DATA sd; ++ LZW_STATIC_DATA sd = {0}; + + + /* +
View file
php7-crypt-possible-buffer-overread.patch
Added
@@ -0,0 +1,12 @@ +Index: php-7.4.33/ext/standard/crypt.c +=================================================================== +--- php-7.4.33.orig/ext/standard/crypt.c ++++ php-7.4.33/ext/standard/crypt.c +@@ -151,6 +151,7 @@ PHPAPI zend_string *php_crypt(const char + } else if ( + salt0 == '$' && + salt1 == '2' && ++ salt2 != 0 && + salt3 == '$') { + char outputPHP_MAX_SALT_LEN + 1; +
View file
php7-fix-newer-versions-icu.patch
Deleted
@@ -1,36 +0,0 @@ -diff -purN a/build/php.m4 b/build/php.m4 ---- a/build/php.m4 2022-10-31 11:36:05.000000000 +0100 -+++ b/build/php.m4 2024-05-30 21:17:33.622778211 +0200 -@@ -1910,9 +1910,8 @@ AC_DEFUN(PHP_SETUP_ICU, - ICU_CFLAGS="$ICU_CFLAGS -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1" - ICU_CXXFLAGS="$ICU_CXXFLAGS -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit" - -- if test "$PKG_CONFIG icu-io --atleast-version=60"; then -- ICU_CFLAGS="$ICU_CFLAGS -DU_HIDE_OBSOLETE_UTF_OLD_H=1" -- fi -+ AS_IF($PKG_CONFIG icu-io --atleast-version=60, -+ ICU_CFLAGS="$ICU_CFLAGS -DU_HIDE_OBSOLETE_UTF_OLD_H=1") - - ICU_CFLAGS="$ICU_CFLAGS -DU_DEFINE_FALSE_AND_TRUE=1" - ) -diff -purN a/ext/intl/config.m4 b/ext/intl/config.m4 ---- a/ext/intl/config.m4 2022-10-31 11:36:14.000000000 +0100 -+++ b/ext/intl/config.m4 2024-05-30 21:23:44.630021359 +0200 -@@ -83,7 +83,16 @@ if test "$PHP_INTL" != "no"; then - breakiterator/codepointiterator_methods.cpp" - - PHP_REQUIRE_CXX() -- PHP_CXX_COMPILE_STDCXX(11, mandatory, PHP_INTL_STDCXX) -+ -+ AC_MSG_CHECKING(if intl requires -std=gnu++17) -+ AS_IF($PKG_CONFIG icu-uc --atleast-version=74, -+ AC_MSG_RESULT(yes) -+ PHP_CXX_COMPILE_STDCXX(17, mandatory, PHP_INTL_STDCXX) -+ , -+ AC_MSG_RESULT(no) -+ PHP_CXX_COMPILE_STDCXX(11, mandatory, PHP_INTL_STDCXX) -+ ) -+ - PHP_INTL_CXX_FLAGS="$INTL_COMMON_FLAGS $PHP_INTL_STDCXX $ICU_CXXFLAGS" - if test "$ext_shared" = "no"; then - PHP_ADD_SOURCES(PHP_EXT_DIR(intl), $PHP_INTL_CXX_SOURCES, $PHP_INTL_CXX_FLAGS)
View file
_link
Changed
@@ -1,4 +1,4 @@ -<link project="openSUSE.org:devel:languages:php:php74" baserev="1eef1f726a8f2d34912260d3197e77d2"> +<link project="openSUSE.org:devel:languages:php:php74" baserev="f7bd93c9f1bf9cc8d906e66094ff488e"> <patches> <branch/> </patches>
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.