From d8a9f171c029dd4260544c46d560e67f95f99690 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Mon, 25 Jul 2022 15:58:59 +0200 Subject: [PATCH 2/3] Fix #81726: phar wrapper: DOS when using quine gzip file The phar wrapper needs to uncompress the file; the uncompressed file might be compressed, so the wrapper implementation loops. This raises potential DOS issues regarding too deep or even infinite recursion (the latter are called compressed file quines[1]). We avoid that by introducing a recursion limit; we choose the somewhat arbitrary limit `3`. This issue has been reported by real_as3617 and gPayl0ad. [1] (cherry picked from commit 404e8bdb68350931176a5bdc86fc417b34fb583d) (cherry picked from commit 96fda78bcddd1d793cf2d0ee463dbb49621b577f) --- NEWS | 2 ++ ext/phar/phar.c | 16 +++++++++++----- ext/phar/tests/bug81726.gz | Bin 0 -> 204 bytes ext/phar/tests/bug81726.phpt | 14 ++++++++++++++ 4 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 ext/phar/tests/bug81726.gz create mode 100644 ext/phar/tests/bug81726.phpt diff --git a/NEWS b/NEWS index 6b14f93031..4b6fcd65e0 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,8 @@ PHP NEWS Backported from 7.4.31 - Core: + . Fixed bug #81726: phar wrapper: DOS when using quine gzip file. + (CVE-2022-31628). (cmb) . Fixed bug #81727: Don't mangle HTTP variable names that clash with ones that have a specific semantic meaning. (CVE-2022-31629). (Derick) diff --git a/ext/phar/phar.c b/ext/phar/phar.c index 850a6e6c46..a7f776efa4 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -1579,7 +1579,8 @@ static int phar_open_from_fp(php_stream* fp, char *fname, int fname_len, char *a const char zip_magic[] = "PK\x03\x04"; const char gz_magic[] = "\x1f\x8b\x08"; const char bz_magic[] = "BZh"; - char *pos, test = '\0'; + char *pos; + int recursion_count = 3; // arbitrary limit to avoid too deep or even infinite recursion const int window_size = 1024; char buffer[1024 + sizeof(token)]; /* a 1024 byte window + the size of the halt_compiler token (moving window) */ const long readsize = sizeof(buffer) - sizeof(token); @@ -1607,8 +1608,7 @@ static int phar_open_from_fp(php_stream* fp, char *fname, int fname_len, char *a MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated entry)") } - if (!test) { - test = '\1'; + if (recursion_count) { pos = buffer+tokenlen; if (!memcmp(pos, gz_magic, 3)) { char err = 0; @@ -1668,7 +1668,10 @@ static int phar_open_from_fp(php_stream* fp, char *fname, int fname_len, char *a compression = PHAR_FILE_COMPRESSED_GZ; /* now, start over */ - test = '\0'; + if (!--recursion_count) { + MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\""); + break; + } continue; } else if (!memcmp(pos, bz_magic, 3)) { php_stream_filter *filter; @@ -1706,7 +1709,10 @@ static int phar_open_from_fp(php_stream* fp, char *fname, int fname_len, char *a compression = PHAR_FILE_COMPRESSED_BZ2; /* now, start over */ - test = '\0'; + if (!--recursion_count) { + MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\""); + break; + } continue; } -- 2.37.3 From 8ba7c1b6dbb0f34ce5087792965648779c12bddb Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Tue, 27 Sep 2022 17:43:40 +0200 Subject: [PATCH 3/3] Fix regression introduced by fixing bug 81726 When a tar phar is created, `phar_open_from_fp()` is also called, but since the file has just been created, none of the format checks can succeed, so we continue to loop, but must not check again for the format. Therefore, we bring back the old `test` variable. Closes GH-9620. (cherry picked from commit 432bf196d59bcb661fcf9cb7029cea9b43f490af) (cherry picked from commit 535c3f592d020a3a43f4ce3577e505d64297b6e8) --- ext/phar/phar.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ext/phar/phar.c b/ext/phar/phar.c index a7f776efa4..45190e22aa 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -1579,7 +1579,7 @@ static int phar_open_from_fp(php_stream* fp, char *fname, int fname_len, char *a const char zip_magic[] = "PK\x03\x04"; const char gz_magic[] = "\x1f\x8b\x08"; const char bz_magic[] = "BZh"; - char *pos; + char *pos, test = '\0'; int recursion_count = 3; // arbitrary limit to avoid too deep or even infinite recursion const int window_size = 1024; char buffer[1024 + sizeof(token)]; /* a 1024 byte window + the size of the halt_compiler token (moving window) */ @@ -1608,7 +1608,8 @@ static int phar_open_from_fp(php_stream* fp, char *fname, int fname_len, char *a MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated entry)") } - if (recursion_count) { + if (!test && recursion_count) { + test = '\1'; pos = buffer+tokenlen; if (!memcmp(pos, gz_magic, 3)) { char err = 0; @@ -1668,6 +1669,7 @@ static int phar_open_from_fp(php_stream* fp, char *fname, int fname_len, char *a compression = PHAR_FILE_COMPRESSED_GZ; /* now, start over */ + test = '\0'; if (!--recursion_count) { MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\""); break; @@ -1709,6 +1711,7 @@ static int phar_open_from_fp(php_stream* fp, char *fname, int fname_len, char *a compression = PHAR_FILE_COMPRESSED_BZ2; /* now, start over */ + test = '\0'; if (!--recursion_count) { MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\""); break; -- 2.37.3 From 9d32d284b25f5df75780911a47b3c23cbaac1761 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Fri, 30 Sep 2022 09:22:14 +0200 Subject: [PATCH] fix NEWS --- NEWS | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index fe4cb9c484..b7a19aea19 100644 --- a/NEWS +++ b/NEWS @@ -1,14 +1,16 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -Backported from 7.4.31 +Backported from 7.4.32 - Core: - . Fixed bug #81726: phar wrapper: DOS when using quine gzip file. - (CVE-2022-31628). (cmb) . Fixed bug #81727: Don't mangle HTTP variable names that clash with ones that have a specific semantic meaning. (CVE-2022-31629). (Derick) +- Phar: + . Fixed bug #81726: phar wrapper: DOS when using quine gzip file. + (CVE-2022-31628). (cmb) + Backported from 7.4.30 - mysqlnd: