php7.2: 3.14 - backport new patches from Ubuntu

3.14-stable
parent c7aaee0e79
commit 5f35a48383
  1. 58
      php/php7.2/APKBUILD
  2. 389
      php/php7.2/u10-001-CVE-2021-21703.patch
  3. 128
      php/php7.2/u11-001-CVE-2017-8923.patch
  4. 51
      php/php7.2/u11-002-CVE-2017-9118-pre1.patch
  5. 71
      php/php7.2/u11-003-CVE-2017-9118.patch
  6. 84
      php/php7.2/u11-004-CVE-2017-9119.patch
  7. 41
      php/php7.2/u11-005-CVE-2017-9120.patch
  8. 118
      php/php7.2/u11-006-CVE-2021-21707.patch
  9. 59
      php/php7.2/u12-001-CVE-2022-31625.patch
  10. 23
      php/php7.2/u12-002-CVE-2022-31626.patch
  11. 38
      php/php7.2/u13-001-CVE-2022-31625-2.patch
  12. 100
      php/php7.2/u8-001-CVE-2020-7071-1.patch
  13. 112
      php/php7.2/u8-002-CVE-2020-7071-2.patch
  14. 34
      php/php7.2/u8-003-CVE-2020-7071-3.patch
  15. 181
      php/php7.2/u8-004-CVE-2021-21702-1.patch
  16. 21
      php/php7.2/u8-005-CVE-2021-21702-2.patch
  17. 30
      php/php7.2/u8-006-CVE-2021-21704-1.patch
  18. 41
      php/php7.2/u8-007-CVE-2021-21704-2.patch
  19. 36
      php/php7.2/u8-008-CVE-2021-21704-3.patch
  20. 44
      php/php7.2/u8-009-CVE-2021-21704-4.patch
  21. 50
      php/php7.2/u8-010-CVE-2021-21705.patch
  22. 23
      php/php7.2/u8-011-CVE-2021-21705-2.patch
  23. 156
      php/php7.2/u9-001-lp-1939853-1-Fix-Segfault-with-get_result-and-PS-cursors.patch
  24. 472
      php/php7.2/u9-002-lp-1939853-2-MySQLnd-Support-cursors-in-store-get-result.patch

@ -26,7 +26,7 @@
pkgname=php7.2
_pkgreal=php
pkgver=7.2.34
pkgrel=3
pkgrel=12
_apiver=20170718
_suffix=${pkgname#php}
_suffixA=7
@ -60,7 +60,7 @@ makedepends="
gdbm-dev
gettext-dev
gmp-dev
icu-dev
icu67-dev
imap-dev
krb5-dev
libedit-dev
@ -103,6 +103,29 @@ source="https://php.net/distributions/$_pkgreal-$pkgver.tar.xz
php7-fpm-version-suffix.patch
allow-build-recode-and-imap-together.patch
fix-tests-devserver.patch
u8-001-CVE-2020-7071-1.patch
u8-002-CVE-2020-7071-2.patch
u8-003-CVE-2020-7071-3.patch
u8-004-CVE-2021-21702-1.patch
u8-005-CVE-2021-21702-2.patch
u8-006-CVE-2021-21704-1.patch
u8-007-CVE-2021-21704-2.patch
u8-008-CVE-2021-21704-3.patch
u8-009-CVE-2021-21704-4.patch
u8-010-CVE-2021-21705.patch
u8-011-CVE-2021-21705-2.patch
u9-001-lp-1939853-1-Fix-Segfault-with-get_result-and-PS-cursors.patch
u9-002-lp-1939853-2-MySQLnd-Support-cursors-in-store-get-result.patch
u10-001-CVE-2021-21703.patch
u11-001-CVE-2017-8923.patch
u11-002-CVE-2017-9118-pre1.patch
u11-003-CVE-2017-9118.patch
u11-004-CVE-2017-9119.patch
u11-005-CVE-2017-9120.patch
u11-006-CVE-2021-21707.patch
u12-001-CVE-2022-31625.patch
u12-002-CVE-2022-31626.patch
u13-001-CVE-2022-31625-2.patch
"
builddir="$srcdir/$_pkgreal-$pkgver"
@ -301,7 +324,7 @@ _build() {
--with-iconv=shared \
--with-imap=shared \
--with-imap-ssl \
--with-icu-dir=/usr \
--with-icu-dir=/usr/local \
--enable-intl=shared \
--enable-json=shared \
--with-kerberos \
@ -670,7 +693,8 @@ _mv() {
mv $@
}
sha512sums="7ecc3de3b5db41ec4ff6a5ce6c7e77dc330753c6f3fd87db4d07d6bb763a0b047e83afeef2251b4c6a5d2ff53fd9f3d7e99d091ef2e2c6ab8f18db7447d8a97d php-7.2.34.tar.xz
sha512sums="
7ecc3de3b5db41ec4ff6a5ce6c7e77dc330753c6f3fd87db4d07d6bb763a0b047e83afeef2251b4c6a5d2ff53fd9f3d7e99d091ef2e2c6ab8f18db7447d8a97d php-7.2.34.tar.xz
78ebccf0124ade38fcf8a9cadd4e3bf637f79c45f8bbaebdf1c9c387e39a311555f633ad0713ea9031986e9fb3550055e7e3d719a0477edc3458fccac9307cfd php7.2-fpm.initd
b65f01e7de2195c0ea6b9e09b5acaf022ef8e0b69bfc2c143a5316293f36e8e3a4556b1847ffd330cb7aa2106dac9ca67950c240504934418c5ceb0cea5beb56 php7.2-fpm.logrotate
b44532f8cfe74f7a0c37ede23ee736a5e86a9f254756eca90a5ed8e917bc3e282fe53f0f9a9cc030b49ba94aa52d11363d53433b957501aad2d5ffcdcf6f3573 php7.2-module.conf
@ -680,4 +704,28 @@ e65383c878c991f554641371c145f67eaf6a59f2a0071645279478d69ba16183e92608442ddbe9be
7ded89fb6674efd57028e0e4f40b67f46af45c9bd20d56abd0a8b911c3ab506a2518a57b002e417c80b4fd767721aa2d9ba8e6decd908a742b28f1a4b7373f44 sharedir.patch
6a2f17e0e0e74810eb092da84b025c7226695a46351c3a77d56116cc671a867c97eae253ef3a5c7d34c12361b95673307dc03232b924c2668a2205fa9217632d php7-fpm-version-suffix.patch
f8ecae241a90cbc3e98aa4deb3d5d35ef555f51380e29f4e182a8060dffeb84be74f030a14c6b452668471030d78964f52795ca74275db05543ccad20ef1f2cc allow-build-recode-and-imap-together.patch
5bb1f90de8c543d4efffa8bc604fb3239e478d9d9625d30cd03449643906a0fe5407123403206ec57f4bf9f18893a7ff4524ccf417b2bd8bce4ee7d18815b576 fix-tests-devserver.patch"
5bb1f90de8c543d4efffa8bc604fb3239e478d9d9625d30cd03449643906a0fe5407123403206ec57f4bf9f18893a7ff4524ccf417b2bd8bce4ee7d18815b576 fix-tests-devserver.patch
1ad7276cd0cc253c7c084248b7c1a3508de0a7f7df68b9b48202f225424de470f8fbc62fb2c10211042e8b7ec1ac353ca1cde1638e743199f1ff8d79ce669598 u8-001-CVE-2020-7071-1.patch
3a609c3ccbb39d518a20afd777f1100bc14de98ebc18487ab688c9633a10b44af40b63bb479ebd8b4ddf285aea14526f9b855056b5ac54c7fbd08c5f306f53d1 u8-002-CVE-2020-7071-2.patch
49edc27552743eb93666386927067b0d41846f7200d019bb3c73ffe0e3158eefc8ac01eedf132c9e59bd97b36418d0276c85151ad679e7a62da9c7ea7b7698d5 u8-003-CVE-2020-7071-3.patch
c7d3f8c788704d5b997d40ea1cafa51c9d57d40fb34c4ad2d8f096ff12610830b742f974cfaa96eac82dc41549fe649a07f262904b2737c2d53de85558c051eb u8-004-CVE-2021-21702-1.patch
a3b631bb2d8fa016c29a70ca0f2be4e9bf61137ed221710b5ab23b1d187086f81a8d0e1dbb2c7c2e499c7dc389e698a8f1acfe89807a6a445e83a56c45e4424c u8-005-CVE-2021-21702-2.patch
4ac7923156a851cf059783bcf44183339a5ad3b105bedf8d15980ec34a195fafef397d77ced07d4333f26a0953b1b09c73cfb969df7228235d8bc1985f29ee64 u8-006-CVE-2021-21704-1.patch
4f0764654fa430b5bf52b5ac37413d8fd879fc87aeadbd3ab698b4812a68d0720ce58499bf0a885ed122270fbc419a8f5d0bf4c2fba8705880e830915d22f8ad u8-007-CVE-2021-21704-2.patch
9f24a63f6ae20f81fb3dbd297a0f7e28ab66f0b22aa3683c82a711f5991b031477bdd641b1d3ac9ec529e51a82b5711916dc8523c6742218e0783629868f4364 u8-008-CVE-2021-21704-3.patch
5612baf6614e8c18411efb7fd7a027bf03ca06d9f9f41d33b1733b333316e1a975a34eae785238368e479e98be1bba5a6cc64901d911976b5ccb9e4083fdfa8b u8-009-CVE-2021-21704-4.patch
43e7eb90d0ba9bf6eca92b594d991bd3990817801a1addbaa69b2632a904c67b2831b233e12f494757e4bdf673c255b109a41f4581ea5272f6dec95d39e40ef7 u8-010-CVE-2021-21705.patch
6eeaac947df36a16a703d60bd4c31ce3bb17c1c6ab9fdf76bb78ac278c0f88b197dd6ddc226c9f5d0428b9170ffdd186c30f368077626aabe2a9f05c3e9d735f u8-011-CVE-2021-21705-2.patch
c837e778c17780093a47255d48cc7f47b5ca3fdd9569174145eeae73614bce8565cbbb54cae488b1510e32614edd28a716f5acf5f932cc61a422a33b5606ea4c u9-001-lp-1939853-1-Fix-Segfault-with-get_result-and-PS-cursors.patch
844b7736b3a5ecc5ad247d41419e97e466fae382b82cc1cdf6d56e9a8fa9280bc0f624a3f07fd9d52205372c5d82201d7b3b97dde46577b1d79a62dbb545b07d u9-002-lp-1939853-2-MySQLnd-Support-cursors-in-store-get-result.patch
ea82fa077ea0f5171bbbcd25f1e5265c69bf0b6b544cd601379269755ad9e76184932ade958efbddfd4c921813e333f618e7740334227d3f10bd2036727615d0 u10-001-CVE-2021-21703.patch
bba7c89f05d7663f32ab6fd1fd716496ac8ed801e07e3ace732df8d1e026c851d1ce85c1248a73ee6270a6d8844f1ef687d7e02b595f9d9768e7c550db641ab1 u11-001-CVE-2017-8923.patch
ab62b120c20ae6c1c56a7fbffa09fad6bbdab816e1aaa6888fc3933cf72e6b5a09741181a56879cf3b1b87634675194d5c256dd2bae3926f1f91185313bedec4 u11-002-CVE-2017-9118-pre1.patch
e63ae6e3385bc79ba8507d0676483467a3cd67d1134b8613b0561c5dffe0d247af7561b0a5011d6f84a56dc3f5c9234ecdc2726ee1ea2ccfa77e91a9486ad7cb u11-003-CVE-2017-9118.patch
02f47153d9873359e01e9155f413e06f3a3a0689e059e2012d3d2b3c81ab32a0d695655f98822c771c1c5867ca27123a06eb33ee6766109e235f0e2ed1851019 u11-004-CVE-2017-9119.patch
fddf6c50682b4d778908130477a9160df68dbd257f33991262d49c3eb05a220ec608a9625ce2b7f00241010aaa4ec7d9c7daa1884d66decda4ac7c4547082a4d u11-005-CVE-2017-9120.patch
64460be7ba985c5192a51badabdbec3e530e6a0818d71612f1ad2b1e5e80eedcb97bb7da3bc2b2daca2c9a610d969336432e89b7babc6aa474153f2dbe5d0451 u11-006-CVE-2021-21707.patch
bdd0212861e5b20d4420546dd20d835ad00f704c744214ba4777a534c156cc53254fd191341a96a3556c1a7ad1455be3beb31edf198a9ead77d92d569847bbdb u12-001-CVE-2022-31625.patch
9f5e5798b22e9ed4c6b9cb0fe10372a457c7cfa2fc11b6eac459a358eef9b7ed4e15682365747be431804370fb6511506728fc13ed001906fb60ee26fb3b31b8 u12-002-CVE-2022-31626.patch
06d342debefb45e5ba4b8619cf08614966b89d6eaec00d8c22f01232ef3a4f773e54dcb8a63f2d0d910f7d0f5bb779fd7a22e9bfd6070bb5e73736c358189d27 u13-001-CVE-2022-31625-2.patch
"

@ -0,0 +1,389 @@
Backported of:
From fadb1f8c1d08ae62b4f0a16917040fde57a3b93b Mon Sep 17 00:00:00 2001
From: Jakub Zelenka <bukka@php.net>
Date: Sat, 2 Oct 2021 22:53:41 +0100
Subject: [PATCH] Fix bug #81026 (PHP-FPM oob R/W in root process leading to
priv escalation)
The main change is to store scoreboard procs directly to the variable sized
array rather than indirectly through the pointer.
Signed-off-by: Stanislav Malyshev <stas@php.net>
diff --git a/sapi/fpm/fpm/fpm_children.c b/sapi/fpm/fpm/fpm_children.c
index eed0c675..05513f00 100644
--- a/sapi/fpm/fpm/fpm_children.c
+++ b/sapi/fpm/fpm/fpm_children.c
@@ -243,7 +243,7 @@ void fpm_children_bury() /* {{{ */
fpm_child_unlink(child);
- fpm_scoreboard_proc_free(wp->scoreboard, child->scoreboard_i);
+ fpm_scoreboard_proc_free(child);
fpm_clock_get(&tv1);
@@ -253,9 +253,9 @@ void fpm_children_bury() /* {{{ */
if (!fpm_pctl_can_spawn_children()) {
severity = ZLOG_DEBUG;
}
- zlog(severity, "[pool %s] child %d exited %s after %ld.%06d seconds from start", child->wp->config->name, (int) pid, buf, tv2.tv_sec, (int) tv2.tv_usec);
+ zlog(severity, "[pool %s] child %d exited %s after %ld.%06d seconds from start", wp->config->name, (int) pid, buf, tv2.tv_sec, (int) tv2.tv_usec);
} else {
- zlog(ZLOG_DEBUG, "[pool %s] child %d has been killed by the process management after %ld.%06d seconds from start", child->wp->config->name, (int) pid, tv2.tv_sec, (int) tv2.tv_usec);
+ zlog(ZLOG_DEBUG, "[pool %s] child %d has been killed by the process management after %ld.%06d seconds from start", wp->config->name, (int) pid, tv2.tv_sec, (int) tv2.tv_usec);
}
fpm_child_close(child, 1 /* in event_loop */);
@@ -321,7 +321,7 @@ static struct fpm_child_s *fpm_resources_prepare(struct fpm_worker_pool_s *wp) /
return 0;
}
- if (0 > fpm_scoreboard_proc_alloc(wp->scoreboard, &c->scoreboard_i)) {
+ if (0 > fpm_scoreboard_proc_alloc(c)) {
fpm_stdio_discard_pipes(c);
fpm_child_free(c);
return 0;
@@ -333,7 +333,7 @@ static struct fpm_child_s *fpm_resources_prepare(struct fpm_worker_pool_s *wp) /
static void fpm_resources_discard(struct fpm_child_s *child) /* {{{ */
{
- fpm_scoreboard_proc_free(child->wp->scoreboard, child->scoreboard_i);
+ fpm_scoreboard_proc_free(child);
fpm_stdio_discard_pipes(child);
fpm_child_free(child);
}
@@ -346,10 +346,10 @@ static void fpm_child_resources_use(struct fpm_child_s *child) /* {{{ */
if (wp == child->wp) {
continue;
}
- fpm_scoreboard_free(wp->scoreboard);
+ fpm_scoreboard_free(wp);
}
- fpm_scoreboard_child_use(child->wp->scoreboard, child->scoreboard_i, getpid());
+ fpm_scoreboard_child_use(child, getpid());
fpm_stdio_child_use_pipes(child);
fpm_child_free(child);
}
diff --git a/sapi/fpm/fpm/fpm_request.c b/sapi/fpm/fpm/fpm_request.c
index a4ace853..deaccf43 100644
--- a/sapi/fpm/fpm/fpm_request.c
+++ b/sapi/fpm/fpm/fpm_request.c
@@ -286,7 +286,7 @@ int fpm_request_is_idle(struct fpm_child_s *child) /* {{{ */
struct fpm_scoreboard_proc_s *proc;
/* no need in atomicity here */
- proc = fpm_scoreboard_proc_get(child->wp->scoreboard, child->scoreboard_i);
+ proc = fpm_scoreboard_proc_get_from_child(child);
if (!proc) {
return 0;
}
@@ -301,7 +301,7 @@ int fpm_request_last_activity(struct fpm_child_s *child, struct timeval *tv) /*
if (!tv) return -1;
- proc = fpm_scoreboard_proc_get(child->wp->scoreboard, child->scoreboard_i);
+ proc = fpm_scoreboard_proc_get_from_child(child);
if (!proc) {
return -1;
}
diff --git a/sapi/fpm/fpm/fpm_scoreboard.c b/sapi/fpm/fpm/fpm_scoreboard.c
index 7a65fcbe..091efdc5 100644
--- a/sapi/fpm/fpm/fpm_scoreboard.c
+++ b/sapi/fpm/fpm/fpm_scoreboard.c
@@ -7,6 +7,7 @@
#include <time.h>
#include "fpm_config.h"
+#include "fpm_children.h"
#include "fpm_scoreboard.h"
#include "fpm_shm.h"
#include "fpm_sockets.h"
@@ -24,7 +25,6 @@ static float fpm_scoreboard_tick;
int fpm_scoreboard_init_main() /* {{{ */
{
struct fpm_worker_pool_s *wp;
- unsigned int i;
#ifdef HAVE_TIMES
#if (defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK))
@@ -41,7 +41,7 @@ int fpm_scoreboard_init_main() /* {{{ */
for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
- size_t scoreboard_size, scoreboard_nprocs_size;
+ size_t scoreboard_procs_size;
void *shm_mem;
if (wp->config->pm_max_children < 1) {
@@ -54,22 +54,15 @@ int fpm_scoreboard_init_main() /* {{{ */
return -1;
}
- scoreboard_size = sizeof(struct fpm_scoreboard_s) + (wp->config->pm_max_children) * sizeof(struct fpm_scoreboard_proc_s *);
- scoreboard_nprocs_size = sizeof(struct fpm_scoreboard_proc_s) * wp->config->pm_max_children;
- shm_mem = fpm_shm_alloc(scoreboard_size + scoreboard_nprocs_size);
+ scoreboard_procs_size = sizeof(struct fpm_scoreboard_proc_s) * wp->config->pm_max_children;
+ shm_mem = fpm_shm_alloc(sizeof(struct fpm_scoreboard_s) + scoreboard_procs_size);
if (!shm_mem) {
return -1;
}
- wp->scoreboard = shm_mem;
+ wp->scoreboard = shm_mem;
+ wp->scoreboard->pm = wp->config->pm;
wp->scoreboard->nprocs = wp->config->pm_max_children;
- shm_mem += scoreboard_size;
-
- for (i = 0; i < wp->scoreboard->nprocs; i++, shm_mem += sizeof(struct fpm_scoreboard_proc_s)) {
- wp->scoreboard->procs[i] = shm_mem;
- }
-
- wp->scoreboard->pm = wp->config->pm;
wp->scoreboard->start_epoch = time(NULL);
strlcpy(wp->scoreboard->pool, wp->config->name, sizeof(wp->scoreboard->pool));
}
@@ -163,28 +156,48 @@ struct fpm_scoreboard_s *fpm_scoreboard_get() /* {{{*/
}
/* }}} */
-struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get(struct fpm_scoreboard_s *scoreboard, int child_index) /* {{{*/
+static inline struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get_ex(
+ struct fpm_scoreboard_s *scoreboard, int child_index, unsigned int nprocs) /* {{{*/
{
if (!scoreboard) {
- scoreboard = fpm_scoreboard;
+ return NULL;
}
- if (!scoreboard) {
+ if (child_index < 0 || (unsigned int)child_index >= nprocs) {
return NULL;
}
+ return &scoreboard->procs[child_index];
+}
+/* }}} */
+
+struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get(
+ struct fpm_scoreboard_s *scoreboard, int child_index) /* {{{*/
+{
+ if (!scoreboard) {
+ scoreboard = fpm_scoreboard;
+ }
+
if (child_index < 0) {
child_index = fpm_scoreboard_i;
}
- if (child_index < 0 || (unsigned int)child_index >= scoreboard->nprocs) {
- return NULL;
- }
+ return fpm_scoreboard_proc_get_ex(scoreboard, child_index, scoreboard->nprocs);
+}
+/* }}} */
- return scoreboard->procs[child_index];
+struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get_from_child(struct fpm_child_s *child) /* {{{*/
+{
+ struct fpm_worker_pool_s *wp = child->wp;
+ unsigned int nprocs = wp->config->pm_max_children;
+ struct fpm_scoreboard_s *scoreboard = wp->scoreboard;
+ int child_index = child->scoreboard_i;
+
+ return fpm_scoreboard_proc_get_ex(scoreboard, child_index, nprocs);
}
/* }}} */
+
struct fpm_scoreboard_s *fpm_scoreboard_acquire(struct fpm_scoreboard_s *scoreboard, int nohang) /* {{{ */
{
struct fpm_scoreboard_s *s;
@@ -235,28 +248,28 @@ void fpm_scoreboard_proc_release(struct fpm_scoreboard_proc_s *proc) /* {{{ */
proc->lock = 0;
}
-void fpm_scoreboard_free(struct fpm_scoreboard_s *scoreboard) /* {{{ */
+void fpm_scoreboard_free(struct fpm_worker_pool_s *wp) /* {{{ */
{
- size_t scoreboard_size, scoreboard_nprocs_size;
+ size_t scoreboard_procs_size;
+ struct fpm_scoreboard_s *scoreboard = wp->scoreboard;
if (!scoreboard) {
zlog(ZLOG_ERROR, "**scoreboard is NULL");
return;
}
- scoreboard_size = sizeof(struct fpm_scoreboard_s) + (scoreboard->nprocs) * sizeof(struct fpm_scoreboard_proc_s *);
- scoreboard_nprocs_size = sizeof(struct fpm_scoreboard_proc_s) * scoreboard->nprocs;
+ scoreboard_procs_size = sizeof(struct fpm_scoreboard_proc_s) * wp->config->pm_max_children;
- fpm_shm_free(scoreboard, scoreboard_size + scoreboard_nprocs_size);
+ fpm_shm_free(scoreboard, sizeof(struct fpm_scoreboard_s) + scoreboard_procs_size);
}
/* }}} */
-void fpm_scoreboard_child_use(struct fpm_scoreboard_s *scoreboard, int child_index, pid_t pid) /* {{{ */
+void fpm_scoreboard_child_use(struct fpm_child_s *child, pid_t pid) /* {{{ */
{
struct fpm_scoreboard_proc_s *proc;
- fpm_scoreboard = scoreboard;
- fpm_scoreboard_i = child_index;
- proc = fpm_scoreboard_proc_get(scoreboard, child_index);
+ fpm_scoreboard = child->wp->scoreboard;
+ fpm_scoreboard_i = child->scoreboard_i;
+ proc = fpm_scoreboard_proc_get_from_child(child);
if (!proc) {
return;
}
@@ -265,18 +278,22 @@ void fpm_scoreboard_child_use(struct fpm_scoreboard_s *scoreboard, int child_ind
}
/* }}} */
-void fpm_scoreboard_proc_free(struct fpm_scoreboard_s *scoreboard, int child_index) /* {{{ */
+void fpm_scoreboard_proc_free(struct fpm_child_s *child) /* {{{ */
{
+ struct fpm_worker_pool_s *wp = child->wp;
+ struct fpm_scoreboard_s *scoreboard = wp->scoreboard;
+ int child_index = child->scoreboard_i;
+
if (!scoreboard) {
return;
}
- if (child_index < 0 || (unsigned int)child_index >= scoreboard->nprocs) {
+ if (child_index < 0 || child_index >= wp->config->pm_max_children) {
return;
}
- if (scoreboard->procs[child_index] && scoreboard->procs[child_index]->used > 0) {
- memset(scoreboard->procs[child_index], 0, sizeof(struct fpm_scoreboard_proc_s));
+ if (scoreboard->procs[child_index].used > 0) {
+ memset(&scoreboard->procs[child_index], 0, sizeof(struct fpm_scoreboard_proc_s));
}
/* set this slot as free to avoid search on next alloc */
@@ -284,41 +301,44 @@ void fpm_scoreboard_proc_free(struct fpm_scoreboard_s *scoreboard, int child_ind
}
/* }}} */
-int fpm_scoreboard_proc_alloc(struct fpm_scoreboard_s *scoreboard, int *child_index) /* {{{ */
+int fpm_scoreboard_proc_alloc(struct fpm_child_s *child) /* {{{ */
{
int i = -1;
+ struct fpm_worker_pool_s *wp = child->wp;
+ struct fpm_scoreboard_s *scoreboard = wp->scoreboard;
+ int nprocs = wp->config->pm_max_children;
- if (!scoreboard || !child_index) {
+ if (!scoreboard) {
return -1;
}
/* first try the slot which is supposed to be free */
- if (scoreboard->free_proc >= 0 && (unsigned int)scoreboard->free_proc < scoreboard->nprocs) {
- if (scoreboard->procs[scoreboard->free_proc] && !scoreboard->procs[scoreboard->free_proc]->used) {
+ if (scoreboard->free_proc >= 0 && scoreboard->free_proc < nprocs) {
+ if (!scoreboard->procs[scoreboard->free_proc].used) {
i = scoreboard->free_proc;
}
}
if (i < 0) { /* the supposed free slot is not, let's search for a free slot */
zlog(ZLOG_DEBUG, "[pool %s] the proc->free_slot was not free. Let's search", scoreboard->pool);
- for (i = 0; i < (int)scoreboard->nprocs; i++) {
- if (scoreboard->procs[i] && !scoreboard->procs[i]->used) { /* found */
+ for (i = 0; i < nprocs; i++) {
+ if (!scoreboard->procs[i].used) { /* found */
break;
}
}
}
/* no free slot */
- if (i < 0 || i >= (int)scoreboard->nprocs) {
+ if (i < 0 || i >= nprocs) {
zlog(ZLOG_ERROR, "[pool %s] no free scoreboard slot", scoreboard->pool);
return -1;
}
- scoreboard->procs[i]->used = 1;
- *child_index = i;
+ scoreboard->procs[i].used = 1;
+ child->scoreboard_i = i;
/* supposed next slot is free */
- if (i + 1 >= (int)scoreboard->nprocs) {
+ if (i + 1 >= nprocs) {
scoreboard->free_proc = 0;
} else {
scoreboard->free_proc = i + 1;
diff --git a/sapi/fpm/fpm/fpm_scoreboard.h b/sapi/fpm/fpm/fpm_scoreboard.h
index abce616d..6405abb7 100644
--- a/sapi/fpm/fpm/fpm_scoreboard.h
+++ b/sapi/fpm/fpm/fpm_scoreboard.h
@@ -64,7 +64,7 @@ struct fpm_scoreboard_s {
unsigned int nprocs;
int free_proc;
unsigned long int slow_rq;
- struct fpm_scoreboard_proc_s *procs[];
+ struct fpm_scoreboard_proc_s procs[];
};
int fpm_scoreboard_init_main();
@@ -73,18 +73,19 @@ int fpm_scoreboard_init_child(struct fpm_worker_pool_s *wp);
void fpm_scoreboard_update(int idle, int active, int lq, int lq_len, int requests, int max_children_reached, int slow_rq, int action, struct fpm_scoreboard_s *scoreboard);
struct fpm_scoreboard_s *fpm_scoreboard_get();
struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get(struct fpm_scoreboard_s *scoreboard, int child_index);
+struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get_from_child(struct fpm_child_s *child);
struct fpm_scoreboard_s *fpm_scoreboard_acquire(struct fpm_scoreboard_s *scoreboard, int nohang);
void fpm_scoreboard_release(struct fpm_scoreboard_s *scoreboard);
struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_acquire(struct fpm_scoreboard_s *scoreboard, int child_index, int nohang);
void fpm_scoreboard_proc_release(struct fpm_scoreboard_proc_s *proc);
-void fpm_scoreboard_free(struct fpm_scoreboard_s *scoreboard);
+void fpm_scoreboard_free(struct fpm_worker_pool_s *wp);
-void fpm_scoreboard_child_use(struct fpm_scoreboard_s *scoreboard, int child_index, pid_t pid);
+void fpm_scoreboard_child_use(struct fpm_child_s *child, pid_t pid);
-void fpm_scoreboard_proc_free(struct fpm_scoreboard_s *scoreboard, int child_index);
-int fpm_scoreboard_proc_alloc(struct fpm_scoreboard_s *scoreboard, int *child_index);
+void fpm_scoreboard_proc_free(struct fpm_child_s *child);
+int fpm_scoreboard_proc_alloc(struct fpm_child_s *child);
#ifdef HAVE_TIMES
float fpm_scoreboard_get_tick();
diff --git a/sapi/fpm/fpm/fpm_status.c b/sapi/fpm/fpm/fpm_status.c
index 1d78ebf8..45852a5b 100644
--- a/sapi/fpm/fpm/fpm_status.c
+++ b/sapi/fpm/fpm/fpm_status.c
@@ -402,10 +402,10 @@ int fpm_status_handle_request(void) /* {{{ */
first = 1;
for (i=0; i<scoreboard_p->nprocs; i++) {
- if (!scoreboard_p->procs[i] || !scoreboard_p->procs[i]->used) {
+ if (!scoreboard_p->procs[i].used) {
continue;
}
- proc = *scoreboard_p->procs[i];
+ proc = scoreboard_p->procs[i];
if (first) {
first = 0;
diff --git a/sapi/fpm/fpm/fpm_worker_pool.c b/sapi/fpm/fpm/fpm_worker_pool.c
index 90e15597..96b7ca50 100644
--- a/sapi/fpm/fpm/fpm_worker_pool.c
+++ b/sapi/fpm/fpm/fpm_worker_pool.c
@@ -43,7 +43,7 @@ static void fpm_worker_pool_cleanup(int which, void *arg) /* {{{ */
fpm_worker_pool_config_free(wp->config);
fpm_children_free(wp->children);
if ((which & FPM_CLEANUP_CHILD) == 0 && fpm_globals.parent_pid == getpid()) {
- fpm_scoreboard_free(wp->scoreboard);
+ fpm_scoreboard_free(wp);
}
fpm_worker_pool_free(wp);
}

@ -0,0 +1,128 @@
Backport of:
From 0b7dffb41f0b571c00304c973f9b85ef910d43d9 Mon Sep 17 00:00:00 2001
From: "Christoph M. Becker" <cmbecker69@gmx.de>
Date: Tue, 17 Aug 2021 16:56:52 +0200
Subject: [PATCH] Fix #73122: Integer Overflow when concatenating strings
We must avoid integer overflows in memory allocations, so we introduce
an additional check in the VM, and bail out in the rare case of an
overflow.
Closes GH-7381.
---
NEWS | 1 +
Zend/zend_vm_def.h | 3 +++
Zend/zend_vm_execute.h | 24 ++++++++++++++++++++++++
3 files changed, 28 insertions(+)
#diff --git a/NEWS b/NEWS
#index 89a09e15b61b..f33242bcd7b3 100644
#--- a/NEWS
#+++ b/NEWS
#@@ -6,6 +6,7 @@ PHP NEWS
# . Fixed bug #81302 (Stream position after stream filter removed). (cmb)
# . Fixed bug #81346 (Non-seekable streams don't update position after write).
# (cmb)
#+ . Fixed bug #73122 (Integer Overflow when concatenating strings). (cmb)
#
# - Opcache:
# . Fixed bug #81353 (segfault with preloading and statically bound closure).
Index: php-7.2.34/Zend/zend_vm_def.h
===================================================================
--- php-7.2.34.orig/Zend/zend_vm_def.h
+++ php-7.2.34/Zend/zend_vm_def.h
@@ -316,6 +316,9 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TM
!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_error_noreturn(E_ERROR, "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);
Index: php-7.2.34/Zend/zend_vm_execute.h
===================================================================
--- php-7.2.34.orig/Zend/zend_vm_execute.h
+++ php-7.2.34/Zend/zend_vm_execute.h
@@ -9253,6 +9253,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_error_noreturn(E_ERROR, "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);
@@ -11275,6 +11278,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_error_noreturn(E_ERROR, "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);
@@ -35136,6 +35142,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_error_noreturn(E_ERROR, "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);
@@ -37690,6 +37699,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_error_noreturn(E_ERROR, "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);
@@ -41657,6 +41669,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_error_noreturn(E_ERROR, "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);
@@ -49957,6 +49972,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_error_noreturn(E_ERROR, "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);
@@ -51749,6 +51767,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_error_noreturn(E_ERROR, "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);
@@ -53079,6 +53100,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_error_noreturn(E_ERROR, "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);

@ -0,0 +1,51 @@
From 760ff841a14160f25348f7969985cb8a2c4da3cc Mon Sep 17 00:00:00 2001
From: "Christoph M. Becker" <cmbecker69@gmx.de>
Date: Wed, 21 Jul 2021 13:55:13 +0200
Subject: [PATCH] Fix #74960: Heap buffer overflow via str_repeat
Trying to allocate a `zend_string` with a length only slighty smaller
than `SIZE_MAX` causes an integer overflow, so callers may need to
check that explicitly. To make that easy in a portable way, we
introduce `ZSTR_MAX_LEN`.
Closes GH-7294.
---
NEWS | 1 +
Zend/zend_operators.c | 2 +-
Zend/zend_string.h | 2 ++
3 files changed, 4 insertions(+), 1 deletion(-)
#diff --git a/NEWS b/NEWS
#index 40a01fb4b639..277411332e52 100644
#--- a/NEWS
#+++ b/NEWS
#@@ -15,6 +15,7 @@ PHP NEWS
# . Fixed bug #72146 (Integer overflow on substr_replace). (cmb)
# . Fixed bug #81265 (getimagesize returns 0 for 256px ICO images).
# (George Dietrich)
#+ . Fixed bug #74960 (Heap buffer overflow via str_repeat). (cmb, Dmitry)
#
# 29 Jul 2021, PHP 7.4.22
#
--- a/Zend/zend_operators.c
+++ b/Zend/zend_operators.c
@@ -1759,7 +1759,7 @@ ZEND_API int ZEND_FASTCALL concat_functi
size_t result_len = op1_len + op2_len;
zend_string *result_str;
- if (UNEXPECTED(op1_len > SIZE_MAX - op2_len)) {
+ if (UNEXPECTED(op1_len > ZSTR_MAX_LEN - op2_len)) {
zend_throw_error(NULL, "String size overflow");
if (UNEXPECTED(use_copy1)) {
zval_dtor(op1);
--- a/Zend/zend_string.h
+++ b/Zend/zend_string.h
@@ -74,6 +74,8 @@ END_EXTERN_C()
#define _ZSTR_STRUCT_SIZE(len) (_ZSTR_HEADER_SIZE + len + 1)
+#define ZSTR_MAX_LEN (SIZE_MAX - ZEND_MM_ALIGNED_SIZE(_ZSTR_HEADER_SIZE + 1))
+
#define ZSTR_ALLOCA_ALLOC(str, _len, use_heap) do { \
(str) = (zend_string *)do_alloca(ZEND_MM_ALIGNED_SIZE_EX(_ZSTR_STRUCT_SIZE(_len), 8), (use_heap)); \
GC_REFCOUNT(str) = 1; \

@ -0,0 +1,71 @@
Backport of:
From 712fc54e856d3d8e80a7d074a2733bc6b3a27e90 Mon Sep 17 00:00:00 2001
From: "Christoph M. Becker" <cmbecker69@gmx.de>
Date: Mon, 29 Nov 2021 15:48:41 +0100
Subject: [PATCH] Fix #74604: Out of bounds in php_pcre_replace_impl
Trying to allocate a `zend_string` with a length only slighty smaller
than `SIZE_MAX` causes an integer overflow; we make sure that this
doesn't happen by catering to the maximal overhead of a `zend_string`.
Closes GH-7597.
---
NEWS | 3 +++
Zend/zend_string.h | 3 ++-
ext/pcre/php_pcre.c | 6 +++---
3 files changed, 8 insertions(+), 4 deletions(-)
#diff --git a/NEWS b/NEWS
#index 0b46c1ad5c7a..cfe36d928117 100644
#--- a/NEWS
#+++ b/NEWS
#@@ -16,6 +16,9 @@ PHP NEWS
# - OpenSSL:
# . Fixed bug #75725 (./configure: detecting RAND_egd). (Dilyan Palauzov)
#
#+- PCRE:
#+ . Fixed bug #74604 (Out of bounds in php_pcre_replace_impl). (cmb, Dmitry)
#+
# - Standard:
# . Fixed bug #81618 (dns_get_record fails on FreeBSD for missing type).
# (fsbruva)
Index: php-7.2.34/Zend/zend_string.h
===================================================================
--- php-7.2.34.orig/Zend/zend_string.h
+++ php-7.2.34/Zend/zend_string.h
@@ -74,7 +74,8 @@ END_EXTERN_C()
#define _ZSTR_STRUCT_SIZE(len) (_ZSTR_HEADER_SIZE + len + 1)
-#define ZSTR_MAX_LEN (SIZE_MAX - ZEND_MM_ALIGNED_SIZE(_ZSTR_HEADER_SIZE + 1))
+#define ZSTR_MAX_OVERHEAD (ZEND_MM_ALIGNED_SIZE(_ZSTR_HEADER_SIZE + 1))
+#define ZSTR_MAX_LEN (SIZE_MAX - ZSTR_MAX_OVERHEAD)
#define ZSTR_ALLOCA_ALLOC(str, _len, use_heap) do { \
(str) = (zend_string *)do_alloca(ZEND_MM_ALIGNED_SIZE_EX(_ZSTR_STRUCT_SIZE(_len), 8), (use_heap)); \
Index: php-7.2.34/ext/pcre/php_pcre.c
===================================================================
--- php-7.2.34.orig/ext/pcre/php_pcre.c
+++ php-7.2.34/ext/pcre/php_pcre.c
@@ -1422,7 +1422,7 @@ PHPAPI zend_string *php_pcre_replace_imp
}
if (new_len >= alloc_len) {
- alloc_len = zend_safe_address_guarded(2, new_len, alloc_len);
+ alloc_len = zend_safe_address_guarded(2, new_len, ZSTR_MAX_OVERHEAD) - ZSTR_MAX_OVERHEAD;
if (result == NULL) {
result = zend_string_alloc(alloc_len, 0);
} else {
@@ -1659,9 +1659,9 @@ static zend_string *php_pcre_replace_fun
/* Use custom function to get replacement string and its length. */
eval_result = preg_do_repl_func(fci, fcc, subject, offsets, subpat_names, count, mark);
ZEND_ASSERT(eval_result);
- new_len = zend_safe_address_guarded(1, ZSTR_LEN(eval_result), new_len);
+ new_len = zend_safe_address_guarded(1, ZSTR_LEN(eval_result) + ZSTR_MAX_OVERHEAD, new_len) -ZSTR_MAX_OVERHEAD;
if (new_len >= alloc_len) {
- alloc_len = zend_safe_address_guarded(2, new_len, alloc_len);
+ alloc_len = zend_safe_address_guarded(2, new_len, ZSTR_MAX_OVERHEAD) - ZSTR_MAX_OVERHEAD;
if (result == NULL) {
result = zend_string_alloc(alloc_len, 0);
} else {

@ -0,0 +1,84 @@
Backport of:
From 573ad182d21df2457a0a2f6fd3c075e1f0bfca44 Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Thu, 3 Sep 2020 09:45:54 +0200
Subject: [PATCH] Handle memory limit error during string reallocation
correctly
Do not decrement the refcount before allocating the new string,
as the allocation operation may bail out and cause a use-after-free
lateron. We can only decrement the refcount once the allocation
has succeeded.
Fixes oss-fuzz #25384.
---
Zend/zend_string.h | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
--- a/Zend/zend_string.h
+++ b/Zend/zend_string.h
@@ -211,12 +211,13 @@ static zend_always_inline zend_string *z
ZSTR_LEN(ret) = len;
zend_string_forget_hash_val(ret);
return ret;
- } else {
- GC_REFCOUNT(s)--;
}
}
ret = zend_string_alloc(len, persistent);
memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), MIN(len, ZSTR_LEN(s)) + 1);
+ if (!ZSTR_IS_INTERNED(s)) {
+ GC_REFCOUNT(s)--;
+ }
return ret;
}
@@ -231,12 +232,13 @@ static zend_always_inline zend_string *z
ZSTR_LEN(ret) = len;
zend_string_forget_hash_val(ret);
return ret;
- } else {
- GC_REFCOUNT(s)--;
}
}
ret = zend_string_alloc(len, persistent);
memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), ZSTR_LEN(s) + 1);
+ if (!ZSTR_IS_INTERNED(s)) {
+ GC_REFCOUNT(s)--;
+ }
return ret;
}
@@ -251,12 +253,13 @@ static zend_always_inline zend_string *z
ZSTR_LEN(ret) = len;
zend_string_forget_hash_val(ret);
return ret;
- } else {
- GC_REFCOUNT(s)--;
}
}
ret = zend_string_alloc(len, persistent);
memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), len + 1);
+ if (!ZSTR_IS_INTERNED(s)) {
+ GC_REFCOUNT(s)--;
+ }
return ret;
}
@@ -270,12 +273,13 @@ static zend_always_inline zend_string *z
ZSTR_LEN(ret) = (n * m) + l;
zend_string_forget_hash_val(ret);
return ret;
- } else {
- GC_REFCOUNT(s)--;
}
}
ret = zend_string_safe_alloc(n, m, l, persistent);
memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), MIN((n * m) + l, ZSTR_LEN(s)) + 1);
+ if (!ZSTR_IS_INTERNED(s)) {
+ GC_REFCOUNT(s)--;
+ }
return ret;
}

@ -0,0 +1,41 @@
Backport of:
From 5977610de1aa87630e40a299a2d90fb7cd00bf7c Mon Sep 17 00:00:00 2001
From: "Christoph M. Becker" <cmbecker69@gmx.de>
Date: Mon, 9 Aug 2021 12:48:21 +0200
Subject: [PATCH] Fix #74544: Integer overflow in mysqli_real_escape_string()
The patch has been provided by @johannes.
Closes GH-7353.
---
NEWS | 4 ++++
ext/mysqli/mysqli_api.c | 2 +-
2 files changed, 5 insertions(+), 1 deletion(-)
#diff --git a/NEWS b/NEWS
#index 28341f26c94c..cb5132397221 100644
#--- a/NEWS
#+++ b/NEWS
#@@ -18,6 +18,10 @@ PHP NEWS
# - GD:
# . Fixed bug #51498 (imagefilledellipse does not work for large circles). (cmb)
#
#+- MySQLi:
#+ . Fixed bug #74544 (Integer overflow in mysqli_real_escape_string()). (cmb,
#+ johannes)
#+
# - OpenSSL:
# . Fixed bug #81327 (Error build openssl extension on php 7.4.22). (cmb)
#
--- a/ext/mysqli/mysqli_api.c
+++ b/ext/mysqli/mysqli_api.c
@@ -1967,7 +1967,7 @@ PHP_FUNCTION(mysqli_real_escape_string)
}
MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
- newstr = zend_string_alloc(2 * escapestr_len, 0);
+ newstr = zend_string_safe_alloc(2, escapestr_len, 0, 0);
ZSTR_LEN(newstr) = mysql_real_escape_string(mysql->mysql, ZSTR_VAL(newstr), escapestr, escapestr_len);
newstr = zend_string_truncate(newstr, ZSTR_LEN(newstr), 0);

@ -0,0 +1,118 @@
From f15f8fc573eb38c3c73e23e0930063a6f6409ed4 Mon Sep 17 00:00:00 2001
From: "Christoph M. Becker" <cmbecker69@gmx.de>
Date: Tue, 1 Sep 2020 10:04:28 +0200
Subject: [PATCH] Fix #79971: special character is breaking the path in xml
function
The libxml based XML functions accepting a filename actually accept
URIs with possibly percent-encoded characters. Percent-encoded NUL
bytes lead to truncation, like non-encoded NUL bytes would. We catch
those, and let the functions fail with a respective warning.
---
ext/dom/domimplementation.c | 5 +++++
ext/dom/tests/bug79971_2.phpt | 20 ++++++++++++++++++++
ext/libxml/libxml.c | 9 +++++++++
ext/simplexml/tests/bug79971_1.phpt | 27 +++++++++++++++++++++++++++
ext/simplexml/tests/bug79971_1.xml | 2 ++
5 files changed, 63 insertions(+)
create mode 100644 ext/dom/tests/bug79971_2.phpt
create mode 100644 ext/simplexml/tests/bug79971_1.phpt
create mode 100644 ext/simplexml/tests/bug79971_1.xml
--- a/ext/dom/domimplementation.c
+++ b/ext/dom/domimplementation.c
@@ -114,6 +114,11 @@ PHP_METHOD(domimplementation, createDocu
pch2 = (xmlChar *) systemid;
}
+ if (strstr(name, "%00")) {
+ php_error_docref(NULL, E_WARNING, "URI must not contain percent-encoded NUL bytes");
+ RETURN_FALSE;
+ }
+
uri = xmlParseURI(name);
if (uri != NULL && uri->opaque != NULL) {
localname = xmlStrdup((xmlChar *) uri->opaque);
--- /dev/null
+++ b/ext/dom/tests/bug79971_2.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Bug #79971 (special character is breaking the path in xml function)
+--SKIPIF--
+<?php
+if (!extension_loaded('dom')) die('skip dom extension not available');
+?>
+--FILE--
+<?php
+$imp = new DOMImplementation;
+if (PHP_OS_FAMILY === 'Windows') {
+ $path = '/' . str_replace('\\', '/', __DIR__);
+} else {
+ $path = __DIR__;
+}
+$uri = "file://$path/bug79971_2.xml";
+var_dump($imp->createDocumentType("$uri%00foo"));
+?>
+--EXPECTF--
+Warning: DOMImplementation::createDocumentType(): URI must not contain percent-encoded NUL bytes in %s on line %d
+bool(false)
--- a/ext/libxml/libxml.c
+++ b/ext/libxml/libxml.c
@@ -308,6 +308,10 @@ static void *php_libxml_streams_IO_open_
int isescaped=0;
xmlURI *uri;
+ if (strstr(filename, "%00")) {
+ php_error_docref(NULL, E_WARNING, "URI must not contain percent-encoded NUL bytes");
+ return NULL;
+ }
uri = xmlParseURI(filename);
if (uri && (uri->scheme == NULL ||
@@ -438,6 +442,11 @@ php_libxml_output_buffer_create_filename
if (URI == NULL)
return(NULL);
+ if (strstr(URI, "%00")) {
+ php_error_docref(NULL, E_WARNING, "URI must not contain percent-encoded NUL bytes");
+ return NULL;
+ }
+
puri = xmlParseURI(URI);
if (puri != NULL) {
if (puri->scheme != NULL)
--- /dev/null
+++ b/ext/simplexml/tests/bug79971_1.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Bug #79971 (special character is breaking the path in xml function)
+--SKIPIF--
+<?php
+if (!extension_loaded('simplexml')) die('skip simplexml extension not available');
+?>
+--FILE--
+<?php
+if (PHP_OS_FAMILY === 'Windows') {
+ $path = '/' . str_replace('\\', '/', __DIR__);
+} else {
+ $path = __DIR__;
+}
+$uri = "file://$path/bug79971_1.xml";
+var_dump(simplexml_load_file("$uri%00foo"));
+
+$sxe = simplexml_load_file($uri);
+var_dump($sxe->asXML("$uri.out%00foo"));
+?>
+--EXPECTF--
+Warning: simplexml_load_file(): URI must not contain percent-encoded NUL bytes in %s on line %d
+
+Warning: simplexml_load_file(): I/O warning : failed to load external entity "%s/bug79971_1.xml%00foo" in %s on line %d
+bool(false)
+
+Warning: SimpleXMLElement::asXML(): URI must not contain percent-encoded NUL bytes in %s on line %d
+bool(false)
--- /dev/null
+++ b/ext/simplexml/tests/bug79971_1.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<root></root>

@ -0,0 +1,59 @@
Backport of:
From 55f6895f4b4c677272fd4ee1113acdbd99c4b5ab Mon Sep 17 00:00:00 2001
From: "Christoph M. Becker" <cmbecker69@gmx.de>
Date: Tue, 17 May 2022 12:59:23 +0200
Subject: [PATCH] Fix #81720: Uninitialized array in pg_query_params() leading
to RCE
We must not free parameters which we haven't initialized yet.
We also fix the not directly related issue, that we checked for the
wrong value being `NULL`, potentially causing a segfault.
---
ext/pgsql/pgsql.c | 6 +++---
ext/pgsql/tests/bug81720.phpt | 27 +++++++++++++++++++++++++++
2 files changed, 30 insertions(+), 3 deletions(-)
create mode 100644 ext/pgsql/tests/bug81720.phpt
--- a/ext/pgsql/pgsql.c
+++ b/ext/pgsql/pgsql.c
@@ -1988,7 +1988,7 @@ PHP_FUNCTION(pg_query_params)
if (Z_TYPE(tmp_val) != IS_STRING) {
php_error_docref(NULL, E_WARNING,"Error converting parameter");
zval_ptr_dtor(&tmp_val);
- _php_pgsql_free_params(params, num_params);
+ _php_pgsql_free_params(params, i);
RETURN_FALSE;
}
params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
--- /dev/null
+++ b/ext/pgsql/tests/bug81720.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Bug #81720 (Uninitialized array in pg_query_params() leading to RCE)
+--SKIPIF--
+<?php include("skipif.inc"); ?>
+--FILE--
+<?php
+include('config.inc');
+
+$conn = pg_connect($conn_str);
+
+try {
+ pg_query_params($conn, 'SELECT $1, $2', [1, new stdClass()]);
+} catch (Throwable $ex) {
+ echo $ex->getMessage(), PHP_EOL;
+}
+
+try {
+ pg_send_prepare($conn, "my_query", 'SELECT $1, $2');
+ pg_get_result($conn);
+ pg_send_execute($conn, "my_query", [1, new stdClass()]);
+} catch (Throwable $ex) {
+ echo $ex->getMessage(), PHP_EOL;
+}
+?>
+--EXPECT--
+Object of class stdClass could not be converted to string
+Object of class stdClass could not be converted to string

@ -0,0 +1,23 @@
Backport of:
From 58006537fc5f133ae8549efe5118cde418b3ace9 Mon Sep 17 00:00:00 2001
From: Stanislav Malyshev <smalyshev@gmail.com>
Date: Mon, 6 Jun 2022 00:56:51 -0600
Subject: [PATCH] Fix bug #81719: mysqlnd/pdo password buffer overflow
---
ext/mysqlnd/mysqlnd_wireprotocol.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
--- a/ext/mysqlnd/mysqlnd_wireprotocol.c
+++ b/ext/mysqlnd/mysqlnd_wireprotocol.c
@@ -794,7 +794,8 @@ php_mysqlnd_change_auth_response_write(v
MYSQLND_VIO * vio = packet->header.vio;
MYSQLND_STATS * stats = packet->header.stats;
MYSQLND_CONNECTION_STATE * connection_state = packet->header.connection_state;
- zend_uchar * buffer = pfc->cmd_buffer.length >= packet->auth_data_len? pfc->cmd_buffer.buffer : mnd_emalloc(packet->auth_data_len);
+ size_t total_packet_size = packet->auth_data_len + MYSQLND_HEADER_SIZE;
+ zend_uchar * buffer = pfc->cmd_buffer.length >= total_packet_size? pfc->cmd_buffer.buffer : mnd_emalloc(total_packet_size);
zend_uchar * p = buffer + MYSQLND_HEADER_SIZE; /* start after the header */
DBG_ENTER("php_mysqlnd_change_auth_response_write");

@ -0,0 +1,38 @@
Description: Don't free parameters which haven't been initialized yet.
In the original commit, the fix is applied on pg_query_params(). But for
this release, it can be extended for other methods with the same code.
Author: Rodrigo Figueiredo Zaiden <rodrigo.zaiden@canonical.com>
Origin: backport, https://github.com/php/php-src/commit/55f6895f
Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/php7.2/+bug/1980550
Last-Update: 2022-07-05
---
This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
--- php7.2-7.2.24.orig/ext/pgsql/pgsql.c
+++ php7.2-7.2.24/ext/pgsql/pgsql.c
@@ -2191,7 +2191,7 @@ PHP_FUNCTION(pg_execute)
if (Z_TYPE(tmp_val) != IS_STRING) {
php_error_docref(NULL, E_WARNING,"Error converting parameter");
zval_ptr_dtor(&tmp_val);
- _php_pgsql_free_params(params, num_params);
+ _php_pgsql_free_params(params, i);
RETURN_FALSE;
}
params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
@@ -5011,7 +5011,7 @@ PHP_FUNCTION(pg_send_query_params)
if (Z_TYPE(tmp_val) != IS_STRING) {
php_error_docref(NULL, E_WARNING,"Error converting parameter");
zval_ptr_dtor(&tmp_val);
- _php_pgsql_free_params(params, num_params);
+ _php_pgsql_free_params(params, i);
RETURN_FALSE;
}
params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
@@ -5188,7 +5188,7 @@ PHP_FUNCTION(pg_send_execute)
if (Z_TYPE(tmp_val) != IS_STRING) {
php_error_docref(NULL, E_WARNING,"Error converting parameter");
zval_ptr_dtor(&tmp_val);
- _php_pgsql_free_params(params, num_params);
+ _php_pgsql_free_params(params, i);
RETURN_FALSE;
}
params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));

@ -0,0 +1,100 @@
Backport of:
From 2d3d72412a6734e19a38ed10f385227a6238e4a6 Mon Sep 17 00:00:00 2001
From: "Christoph M. Becker" <cmbecker69@gmx.de>
Date: Wed, 13 May 2020 09:36:52 +0200
Subject: [PATCH] Fix #77423: parse_url() will deliver a wrong host to user
To avoid that `parse_url()` returns an erroneous host, which would be
valid for `FILTER_VALIDATE_URL`, we make sure that only userinfo which
is valid according to RFC 3986 is treated as such.
For consistency with the existing url parsing code, we use ctype
functions, although that is not necessarily correct.
---
ext/standard/tests/strings/url_t.phpt | 6 ++---
ext/standard/tests/url/bug77423.phpt | 30 ++++++++++++++++++++++
ext/standard/tests/url/parse_url_basic_001.phpt | 6 ++---
ext/standard/tests/url/parse_url_basic_003.phpt | 2 +-
ext/standard/tests/url/parse_url_basic_005.phpt | 2 +-
ext/standard/tests/url/parse_url_unterminated.phpt | 6 ++---
ext/standard/url.c | 21 +++++++++++++++
7 files changed, 59 insertions(+), 14 deletions(-)
create mode 100644 ext/standard/tests/url/bug77423.phpt
--- /dev/null
+++ b/ext/filter/tests/bug77423.phpt
@@ -0,0 +1,30 @@
+--TEST--
+Bug #77423 (parse_url() will deliver a wrong host to user)
+--FILE--
+<?php
+$urls = array(
+ "http://php.net\@aliyun.com/aaa.do",
+ "https://example.com\uFF03@bing.com",
+);
+foreach ($urls as $url) {
+ var_dump(filter_var($url, FILTER_VALIDATE_URL));
+ var_dump(parse_url($url));
+}
+?>
+--EXPECT--
+bool(false)
+array(3) {
+ ["scheme"]=>
+ string(4) "http"
+ ["host"]=>
+ string(19) "php.net\@aliyun.com"
+ ["path"]=>
+ string(7) "/aaa.do"
+}
+bool(false)
+array(2) {
+ ["scheme"]=>
+ string(5) "https"
+ ["host"]=>
+ string(26) "example.com\uFF03@bing.com"
+}
--- a/ext/standard/url.c
+++ b/ext/standard/url.c
@@ -92,6 +92,22 @@ PHPAPI php_url *php_url_parse(char const
return php_url_parse_ex(str, strlen(str));
}
+static int is_userinfo_valid(const char *str, size_t len)
+{
+ char *valid = "-._~!$&'()*+,;=:";
+ char *p = str;
+ while (p - str < len) {
+ if (isalpha(*p) || isdigit(*p) || strchr(valid, *p)) {
+ p++;
+ } else if (*p == '%' && p - str <= len - 3 && isdigit(*(p+1)) && isxdigit(*(p+2))) {
+ p += 3;
+ } else {
+ return 0;
+ }
+ }
+ return 1;
+}
+
/* {{{ php_url_parse
*/
PHPAPI php_url *php_url_parse_ex(char const *str, size_t length)
@@ -235,6 +251,9 @@ PHPAPI php_url *php_url_parse_ex(char co
ret->pass = estrndup(pp, (p-pp));
php_replace_controlchars_ex(ret->pass, (p-pp));
} else {
+ if (!is_userinfo_valid(s, p-s)) {
+ goto check_port;
+ }
ret->user = estrndup(s, (p-s));
php_replace_controlchars_ex(ret->user, (p-s));
}
@@ -242,6 +261,7 @@ PHPAPI php_url *php_url_parse_ex(char co
s = p + 1;
}
+check_port:
/* check for port */
if (s < ue && *s == '[' && *(e-1) == ']') {
/* Short circuit portscan,

@ -0,0 +1,112 @@
Backport of:
From 4a89e726bd4d0571991dc22a9a1ad4509e8fe347 Mon Sep 17 00:00:00 2001
From: "Christoph M. Becker" <cmbecker69@gmx.de>
Date: Tue, 19 Jan 2021 11:23:25 +0100
Subject: [PATCH] Alternative fix for bug 77423
That bug report originally was about `parse_url()` misbehaving, but the
security aspect was actually only regarding `FILTER_VALIDATE_URL`.
Since the changes to `parse_url_ex()` apparently affect userland code
which is relying on the sloppy URL parsing[1], this alternative
restores the old parsing behavior, but ensures that the userinfo is
checked for correctness for `FILTER_VALIDATE_URL`.
[1] <https://github.com/php/php-src/commit/5174de7cd33c3d4fa591c9c93859ff9989b07e8c#commitcomment-45967652>
---
ext/filter/logical_filters.c | 23 ++++++++++++++++++++++
.../tests/url => filter/tests}/bug77423.phpt | 15 --------------
ext/standard/tests/strings/url_t.phpt | 6 ++++--
ext/standard/tests/url/parse_url_basic_001.phpt | 6 ++++--
ext/standard/tests/url/parse_url_basic_003.phpt | 2 +-
ext/standard/tests/url/parse_url_basic_005.phpt | 2 +-
ext/standard/tests/url/parse_url_unterminated.phpt | 6 ++++--
ext/standard/url.c | 6 +-----
8 files changed, 38 insertions(+), 28 deletions(-)
rename ext/{standard/tests/url => filter/tests}/bug77423.phpt (53%)
--- a/ext/filter/logical_filters.c
+++ b/ext/filter/logical_filters.c
@@ -514,6 +514,22 @@ void php_filter_validate_domain(PHP_INPU
}
/* }}} */
+static int is_userinfo_valid(char * str)
+{
+ const char *valid = "-._~!$&'()*+,;=:";
+ const char *p = str;
+ while (p - str < strlen(str)) {
+ if (isalpha(*p) || isdigit(*p) || strchr(valid, *p)) {
+ p++;
+ } else if (*p == '%' && p - str <= strlen(str) - 3 && isdigit(*(p+1)) && isxdigit(*(p+2))) {
+ p += 3;
+ } else {
+ return 0;
+ }
+ }
+ return 1;
+}
+
void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
{
php_url *url;
@@ -568,6 +584,13 @@ bad_url:
php_url_free(url);
RETURN_VALIDATION_FAILED
}
+
+ if (url->user != NULL && !is_userinfo_valid(url->user)) {
+ php_url_free(url);
+ RETURN_VALIDATION_FAILED
+
+ }
+
php_url_free(url);
}
/* }}} */
--- a/ext/filter/tests/bug77423.phpt
+++ b/ext/filter/tests/bug77423.phpt
@@ -8,23 +8,8 @@ $urls = array(
);
foreach ($urls as $url) {
var_dump(filter_var($url, FILTER_VALIDATE_URL));
- var_dump(parse_url($url));
}
?>
--EXPECT--
bool(false)
-array(3) {
- ["scheme"]=>
- string(4) "http"
- ["host"]=>
- string(19) "php.net\@aliyun.com"
- ["path"]=>
- string(7) "/aaa.do"
-}
bool(false)
-array(2) {
- ["scheme"]=>
- string(5) "https"
- ["host"]=>
- string(26) "example.com\uFF03@bing.com"
-}
--- a/ext/standard/url.c
+++ b/ext/standard/url.c
@@ -251,9 +251,6 @@ PHPAPI php_url *php_url_parse_ex(char co
ret->pass = estrndup(pp, (p-pp));
php_replace_controlchars_ex(ret->pass, (p-pp));
} else {
- if (!is_userinfo_valid(s, p-s)) {
- goto check_port;
- }
ret->user = estrndup(s, (p-s));
php_replace_controlchars_ex(ret->user, (p-s));
}
@@ -261,7 +258,6 @@ PHPAPI php_url *php_url_parse_ex(char co
s = p + 1;
}
-check_port:
/* check for port */
if (s < ue && *s == '[' && *(e-1) == ']') {
/* Short circuit portscan,

@ -0,0 +1,34 @@
From 9c673083cd46ee2a954a62156acbe4b6e657c048 Mon Sep 17 00:00:00 2001
From: Stanislav Malyshev <stas@php.net>
Date: Wed, 27 Jan 2021 00:13:43 -0800
Subject: [PATCH] Rm unneeded function
---
ext/standard/url.c | 16 ----------------
1 file changed, 16 deletions(-)
--- a/ext/standard/url.c
+++ b/ext/standard/url.c
@@ -92,22 +92,6 @@ PHPAPI php_url *php_url_parse(char const
return php_url_parse_ex(str, strlen(str));
}
-static int is_userinfo_valid(const char *str, size_t len)
-{
- char *valid = "-._~!$&'()*+,;=:";
- char *p = str;
- while (p - str < len) {
- if (isalpha(*p) || isdigit(*p) || strchr(valid, *p)) {
- p++;
- } else if (*p == '%' && p - str <= len - 3 && isdigit(*(p+1)) && isxdigit(*(p+2))) {
- p += 3;
- } else {
- return 0;
- }
- }
- return 1;
-}
-
/* {{{ php_url_parse
*/
PHPAPI php_url *php_url_parse_ex(char const *str, size_t length)

@ -0,0 +1,181 @@
From 3c939e3f69955d087e0bb671868f7267dfb2a502 Mon Sep 17 00:00:00 2001
From: Stanislav Malyshev <stas@php.net>
Date: Sun, 31 Jan 2021 21:15:23 -0800
Subject: [PATCH] Fix bug #80672 - Null Dereference in SoapClient
---
NEWS | 3 +++
ext/soap/php_sdl.c | 26 ++++++++++++++------------
ext/soap/php_xml.c | 4 ++--
ext/soap/tests/bug80672.phpt | 15 +++++++++++++++
ext/soap/tests/bug80672.xml | 6 ++++++
5 files changed, 40 insertions(+), 14 deletions(-)
create mode 100644 ext/soap/tests/bug80672.phpt
create mode 100644 ext/soap/tests/bug80672.xml
--- a/ext/soap/php_sdl.c
+++ b/ext/soap/php_sdl.c
@@ -314,6 +314,8 @@ void sdl_restore_uri_credentials(sdlCtx
ctx->context = NULL;
}
+#define SAFE_STR(a) ((a)?a:"")
+
static void load_wsdl_ex(zval *this_ptr, char *struri, sdlCtx *ctx, int include)
{
sdlPtr tmpsdl = ctx->sdl;
@@ -375,7 +377,7 @@ static void load_wsdl_ex(zval *this_ptr,
if (node_is_equal_ex(trav2, "schema", XSD_NAMESPACE)) {
load_schema(ctx, trav2);
} else if (is_wsdl_element(trav2) && !node_is_equal(trav2,"documentation")) {
- soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav2->name);
+ soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav2->name));
}
trav2 = trav2->next;
}
@@ -436,7 +438,7 @@ static void load_wsdl_ex(zval *this_ptr,
soap_error0(E_ERROR, "Parsing WSDL: <service> has no name attribute");
}
} else if (!node_is_equal(trav,"documentation")) {
- soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav->name);
+ soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav->name));
}
trav = trav->next;
}
@@ -546,7 +548,7 @@ static sdlSoapBindingFunctionHeaderPtr w
}
smart_str_free(&key);
} else if (is_wsdl_element(trav) && !node_is_equal(trav,"documentation")) {
- soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav->name);
+ soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav->name));
}
trav = trav->next;
}
@@ -648,7 +650,7 @@ static void wsdl_soap_binding_body(sdlCt
}
smart_str_free(&key);
} else if (is_wsdl_element(trav) && !node_is_equal(trav,"documentation")) {
- soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav->name);
+ soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav->name));
}
trav = trav->next;
}
@@ -680,14 +682,14 @@ static HashTable* wsdl_message(sdlCtx *c
sdlParamPtr param;
if (trav->ns != NULL && strcmp((char*)trav->ns->href, WSDL_NAMESPACE) != 0) {
- soap_error1(E_ERROR, "Parsing WSDL: Unexpected extensibility element <%s>", trav->name);
+ soap_error1(E_ERROR, "Parsing WSDL: Unexpected extensibility element <%s>", SAFE_STR(trav->name));
}
if (node_is_equal(trav,"documentation")) {
trav = trav->next;
continue;
}
if (!node_is_equal(trav,"part")) {
- soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav->name);
+ soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav->name));
}
part = trav;
param = emalloc(sizeof(sdlParam));
@@ -696,7 +698,7 @@ static HashTable* wsdl_message(sdlCtx *c
name = get_attribute(part->properties, "name");
if (name == NULL) {
- soap_error1(E_ERROR, "Parsing WSDL: No name associated with <part> '%s'", message->name);
+ soap_error1(E_ERROR, "Parsing WSDL: No name associated with <part> '%s'", SAFE_STR(message->name));
}
param->paramName = estrdup((char*)name->children->content);
@@ -765,7 +767,7 @@ static sdlPtr load_wsdl(zval *this_ptr,
continue;
}
if (!node_is_equal(trav,"port")) {
- soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav->name);
+ soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav->name));
}
port = trav;
@@ -804,7 +806,7 @@ static sdlPtr load_wsdl(zval *this_ptr,
}
}
if (trav2 != address && is_wsdl_element(trav2) && !node_is_equal(trav2,"documentation")) {
- soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav2->name);
+ soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav2->name));
}
trav2 = trav2->next;
}
@@ -906,7 +908,7 @@ static sdlPtr load_wsdl(zval *this_ptr,
continue;
}
if (!node_is_equal(trav2,"operation")) {
- soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav2->name);
+ soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav2->name));
}
operation = trav2;
@@ -925,7 +927,7 @@ static sdlPtr load_wsdl(zval *this_ptr,
!node_is_equal(trav3,"output") &&
!node_is_equal(trav3,"fault") &&
!node_is_equal(trav3,"documentation")) {
- soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav3->name);
+ soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav3->name));
}
trav3 = trav3->next;
}
@@ -1103,7 +1105,7 @@ static sdlPtr load_wsdl(zval *this_ptr,
}
}
} else if (is_wsdl_element(trav) && !node_is_equal(trav,"documentation")) {
- soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav->name);
+ soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav->name));
}
trav = trav->next;
}
--- a/ext/soap/php_xml.c
+++ b/ext/soap/php_xml.c
@@ -204,7 +204,7 @@ xmlNsPtr node_find_ns(xmlNodePtr node)
int attr_is_equal_ex(xmlAttrPtr node, char *name, char *ns)
{
- if (name == NULL || strcmp((char*)node->name, name) == 0) {
+ if (name == NULL || ((node->name) && strcmp((char*)node->name, name) == 0)) {
if (ns) {
xmlNsPtr nsPtr = attr_find_ns(node);
if (nsPtr) {
@@ -220,7 +220,7 @@ int attr_is_equal_ex(xmlAttrPtr node, ch
int node_is_equal_ex(xmlNodePtr node, char *name, char *ns)
{
- if (name == NULL || strcmp((char*)node->name, name) == 0) {
+ if (name == NULL || ((node->name) && strcmp((char*)node->name, name) == 0)) {
if (ns) {
xmlNsPtr nsPtr = node_find_ns(node);
if (nsPtr) {
--- /dev/null
+++ b/ext/soap/tests/bug80672.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Bug #80672 Null Dereference in SoapClient
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+try {
+ $client = new SoapClient(__DIR__ . "/bug80672.xml");
+ $query = $soap->query(array('sXML' => 'something'));
+} catch(SoapFault $e) {
+ print $e->getMessage();
+}
+?>
+--EXPECTF--
+SOAP-ERROR: Parsing WSDL: Unexpected WSDL element <>
\ No newline at end of file
--- /dev/null
+++ b/ext/soap/tests/bug80672.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<soap:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:soap="http://schemas.xmlsoap.org/wsdl/">
+<![CDATA[test]]>
+</soap:definitions>

@ -0,0 +1,21 @@
From 06c9633b43a032236b449739a72f4d55cd648fb4 Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Mon, 1 Feb 2021 09:46:17 +0100
Subject: [PATCH] Fix newly introduced compiler warning
(cherry picked from commit ab8177de2c89672e63a7a1ccef4df8f7bf34fbd2)
---
ext/soap/php_sdl.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/ext/soap/php_sdl.c
+++ b/ext/soap/php_sdl.c
@@ -314,7 +314,7 @@ void sdl_restore_uri_credentials(sdlCtx
ctx->context = NULL;
}
-#define SAFE_STR(a) ((a)?a:"")
+#define SAFE_STR(a) ((a)?((const char *)a):"")
static void load_wsdl_ex(zval *this_ptr, char *struri, sdlCtx *ctx, int include)
{

@ -0,0 +1,30 @@
From 286162e9b03071c4308e7e92597bca4239f49d89 Mon Sep 17 00:00:00 2001
From: "Christoph M. Becker" <cmbecker69@gmx.de>
Date: Wed, 5 May 2021 12:42:17 +0200
Subject: [PATCH] Fix #76452: Crash while parsing blob data in
firebird_fetch_blob
We need to prevent integer overflow when calling `erealloc()` with
`len+1`.
---
ext/pdo_firebird/firebird_statement.c | 5 +++++
ext/pdo_firebird/tests/bug_76452.data | Bin 0 -> 856 bytes
ext/pdo_firebird/tests/bug_76452.phpt | 31 ++++++++++++++++++++++++++
3 files changed, 36 insertions(+)
create mode 100644 ext/pdo_firebird/tests/bug_76452.data
create mode 100644 ext/pdo_firebird/tests/bug_76452.phpt
--- a/ext/pdo_firebird/firebird_statement.c
+++ b/ext/pdo_firebird/firebird_statement.c
@@ -294,6 +294,11 @@ static int firebird_fetch_blob(pdo_stmt_