Skip to content

Commit 5a47f27

Browse files
bukkadevnexen
andcommitted
Fix GH-15395: php-fpm: zend_mm_heap corrupted with cgi-fcgi request
Closes GH-16227 Co-authored-by: David Carlier <devnexen@gmail.com>
1 parent 8537aa6 commit 5a47f27

File tree

5 files changed

+74
-3
lines changed

5 files changed

+74
-3
lines changed

NEWS

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ PHP NEWS
3434
ext/dom/parentnode/tree.c). (nielsdos)
3535
. Fixed bug GH-16151 (Assertion failure in ext/dom/parentnode/tree.c).
3636
(nielsdos)
37-
37+
3838
- GD:
3939
. Fixed bug GH-16232 (bitshift overflow on wbmp file content reading /
4040
fix backport from upstream). (David Carlier)
@@ -68,6 +68,10 @@ PHP NEWS
6868
. Fixed bug GH-16187 (Assertion failure in ext/reflection/php_reflection.c).
6969
(DanielEScherzer)
7070

71+
- SAPI:
72+
. Fixed bug GH-15395 (php-fpm: zend_mm_heap corrupted with cgi-fcgi request).
73+
(Jakub Zelenka, David Carlier)
74+
7175
- SimpleXML:
7276
. Fixed bug GH-15837 (Segmentation fault in ext/simplexml/simplexml.c).
7377
(nielsdos)

main/SAPI.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,12 +507,15 @@ SAPI_API void sapi_deactivate_module(void)
507507
}
508508
if (SG(request_info).auth_user) {
509509
efree(SG(request_info).auth_user);
510+
SG(request_info).auth_user = NULL;
510511
}
511512
if (SG(request_info).auth_password) {
512513
efree(SG(request_info).auth_password);
514+
SG(request_info).auth_password = NULL;
513515
}
514516
if (SG(request_info).auth_digest) {
515517
efree(SG(request_info).auth_digest);
518+
SG(request_info).auth_digest = NULL;
516519
}
517520
if (SG(request_info).content_type_dup) {
518521
efree(SG(request_info).content_type_dup);

main/main.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2672,7 +2672,9 @@ PHPAPI int php_handle_auth_data(const char *auth)
26722672
if (pass) {
26732673
*pass++ = '\0';
26742674
SG(request_info).auth_user = estrndup(ZSTR_VAL(user), ZSTR_LEN(user));
2675-
SG(request_info).auth_password = estrdup(pass);
2675+
if (strlen(pass) > 0) {
2676+
SG(request_info).auth_password = estrdup(pass);
2677+
}
26762678
ret = 0;
26772679
}
26782680
zend_string_free(user);
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
--TEST--
2+
FPM: GH-15335 - PHP_AUTH shutdown use after free
3+
--SKIPIF--
4+
<?php include "skipif.inc"; ?>
5+
--FILE--
6+
<?php
7+
8+
require_once "tester.inc";
9+
10+
$cfg = <<<EOT
11+
[global]
12+
error_log = {{FILE:LOG}}
13+
log_level = notice
14+
[unconfined]
15+
listen = {{ADDR}}
16+
pm = static
17+
pm.max_children = 1
18+
catch_workers_output = yes
19+
php_admin_value[cgi.fix_pathinfo] = no
20+
EOT;
21+
22+
$code = <<<EOT
23+
<?php
24+
echo \$_SERVER["SCRIPT_NAME"] . "\n";
25+
echo \$_SERVER["SCRIPT_FILENAME"] . "\n";
26+
echo \$_SERVER["PHP_SELF"];
27+
EOT;
28+
29+
$tester = new FPM\Tester($cfg, $code);
30+
[$sourceFilePath, $scriptName] = $tester->createSourceFileAndScriptName();
31+
$tester->start();
32+
$tester->expectLogStartNotices();
33+
$tester
34+
->request(
35+
headers: [ "HTTP_AUTHORIZATION" => "Basic Zm9vOg==", "REQUEST_METHOD" => "GET"],
36+
uri: $scriptName,
37+
address: '{{ADDR}}',
38+
scriptFilename: __DIR__ . "/__unknown.php",
39+
scriptName: "/",
40+
)
41+
->expectStatus('404 Not Found');
42+
$tester
43+
->request(
44+
uri: $scriptName,
45+
address: '{{ADDR}}',
46+
params: [],
47+
);
48+
$tester->expectNoLogPattern("/zend_mm_heap corrupted/");
49+
$tester->terminate();
50+
$tester->expectLogTerminatingNotices();
51+
$tester->close();
52+
53+
?>
54+
Done
55+
--EXPECT--
56+
Done
57+
--CLEAN--
58+
<?php
59+
require_once "tester.inc";
60+
FPM\Tester::clean();
61+
?>

sapi/fpm/tests/tester.inc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,7 @@ class Tester
762762
string|array $stdin = null,
763763
bool $expectError = false,
764764
int $readLimit = -1,
765+
array $params = null,
765766
): Response {
766767
if ($this->hasError()) {
767768
return $this->createResponse(expectInvalid: true);
@@ -771,7 +772,7 @@ class Tester
771772
$stdin = $this->parseStdin($stdin, $headers);
772773
}
773774

774-
$params = $this->getRequestParams($query, $headers, $uri, $scriptFilename, $scriptName, $stdin);
775+
$params = $params ?? $this->getRequestParams($query, $headers, $uri, $scriptFilename, $scriptName, $stdin);
775776
$this->trace('Request params', $params);
776777

777778
try {

0 commit comments

Comments
 (0)