projects/aports·blob master · refs

144 lines · 4.5 KiB

1From 2e666964fe76774875905140b2d62f1abf5feb98 Mon Sep 17 00:00:00 2001
2From: Jakub Zelenka <[email protected]>
3Date: Sun, 3 May 2026 20:01:41 +0200
4Subject: [PATCH 4/7] GHSA-7qg2-v9fj-4mwv: [fpm] XSS within status endpoint
5
6Fixes GHSA-7qg2-v9fj-4mwv
7Fixes CVE-2026-6735
8
9(cherry picked from commit 13e72d1c97f72892421b04e8c5c05bc9bb193457)
10---
11 sapi/fpm/fpm/fpm_status.c | 34 +++++++++++--
12 .../tests/ghsa-7qg2-v9fj-4mwv-status-xss.phpt | 48 +++++++++++++++++++
13 2 files changed, 78 insertions(+), 4 deletions(-)
14 create mode 100644 sapi/fpm/tests/ghsa-7qg2-v9fj-4mwv-status-xss.phpt
15
16diff --git a/sapi/fpm/fpm/fpm_status.c b/sapi/fpm/fpm/fpm_status.c
17index f698753cf4c..81292aa3bf8 100644
18--- a/sapi/fpm/fpm/fpm_status.c
19+++ b/sapi/fpm/fpm/fpm_status.c
20@@ -525,8 +525,8 @@ int fpm_status_handle_request(void) /* {{{ */
21 if (full_syntax) {
22 unsigned int i;
23 int first;
24- zend_string *tmp_query_string;
25- char *query_string;
26+ zend_string *tmp_query_string, *tmp_request_uri_string;
27+ char *query_string, *request_uri_string;
28 struct timeval duration, now;
29 float cpu;
30
31@@ -551,13 +551,36 @@ int fpm_status_handle_request(void) /* {{{ */
32 }
33 }
34
35+ request_uri_string = NULL;
36+ tmp_request_uri_string = NULL;
37+ if (proc->request_uri[0] != '\0') {
38+ if (encode_html) {
39+ tmp_request_uri_string = php_escape_html_entities_ex(
40+ (const unsigned char *) proc->request_uri,
41+ strlen(proc->request_uri), 1, ENT_DISALLOWED | ENT_HTML_DOC_XML1 | ENT_COMPAT,
42+ NULL, /* double_encode */ 1, /* quiet */ 0);
43+ request_uri_string = ZSTR_VAL(tmp_request_uri_string);
44+ } else if (encode_json) {
45+ tmp_request_uri_string = php_json_encode_string(proc->request_uri,
46+ strlen(proc->request_uri), PHP_JSON_INVALID_UTF8_IGNORE);
47+ request_uri_string = ZSTR_VAL(tmp_request_uri_string);
48+ /* remove quotes around the string */
49+ if (ZSTR_LEN(tmp_request_uri_string) >= 2) {
50+ request_uri_string[ZSTR_LEN(tmp_request_uri_string) - 1] = '\0';
51+ ++request_uri_string;
52+ }
53+ } else {
54+ request_uri_string = proc->request_uri;
55+ }
56+ }
57+
58 query_string = NULL;
59 tmp_query_string = NULL;
60 if (proc->query_string[0] != '\0') {
61 if (encode_html) {
62 tmp_query_string = php_escape_html_entities_ex(
63 (const unsigned char *) proc->query_string,
64- strlen(proc->query_string), 1, ENT_HTML_IGNORE_ERRORS & ENT_COMPAT,
65+ strlen(proc->query_string), 1, ENT_DISALLOWED | ENT_HTML_DOC_XML1 | ENT_COMPAT,
66 NULL, /* double_encode */ 1, /* quiet */ 0);
67 } else if (encode_json) {
68 tmp_query_string = php_json_encode_string(proc->query_string,
69@@ -596,7 +619,7 @@ int fpm_status_handle_request(void) /* {{{ */
70 proc->requests,
71 duration.tv_sec * 1000000UL + duration.tv_usec,
72 proc->request_method[0] != '\0' ? proc->request_method : "-",
73- proc->request_uri[0] != '\0' ? proc->request_uri : "-",
74+ request_uri_string ? request_uri_string : "-",
75 query_string ? "?" : "",
76 query_string ? query_string : "",
77 proc->content_length,
78@@ -607,6 +630,9 @@ int fpm_status_handle_request(void) /* {{{ */
79 PUTS(buffer);
80 efree(buffer);
81
82+ if (tmp_request_uri_string) {
83+ zend_string_free(tmp_request_uri_string);
84+ }
85 if (tmp_query_string) {
86 zend_string_free(tmp_query_string);
87 }
88diff --git a/sapi/fpm/tests/ghsa-7qg2-v9fj-4mwv-status-xss.phpt b/sapi/fpm/tests/ghsa-7qg2-v9fj-4mwv-status-xss.phpt
89new file mode 100644
90index 00000000000..475bc130a42
91--- /dev/null
92+++ b/sapi/fpm/tests/ghsa-7qg2-v9fj-4mwv-status-xss.phpt
93@@ -0,0 +1,48 @@
94+--TEST--
95+FPM: GHSA-7qg2-v9fj-4mwv - status xss
96+--SKIPIF--
97+<?php include "skipif.inc"; ?>
98+--FILE--
99+<?php
100+
101+require_once "tester.inc";
102+
103+$cfg = <<<EOT
104+[global]
105+error_log = {{FILE:LOG}}
106+[unconfined]
107+listen = {{ADDR}}
108+pm = static
109+pm.max_children = 2
110+pm.status_path = /status
111+catch_workers_output = yes
112+EOT;
113+
114+$code = <<<EOT
115+<?php
116+usleep(200000);
117+EOT;
118+
119+$tester = new FPM\Tester($cfg, $code);
120+$tester->start();
121+$tester->expectLogStartNotices();
122+$responses = $tester
123+ ->multiRequest([
124+ ['uri' => '/<script>alert(1)</script>', 'query' => '<script>alert(2)</script>'],
125+ ['uri' => '/status', 'query' => 'full&html', 'delay' => 100000],
126+ ]);
127+var_dump(strpos($responses[1]->getBody(), '<script>'));
128+$tester->terminate();
129+$tester->expectLogTerminatingNotices();
130+$tester->close();
131+
132+?>
133+Done
134+--EXPECT--
135+bool(false)
136+Done
137+--CLEAN--
138+<?php
139+require_once "tester.inc";
140+FPM\Tester::clean();
141+?>
142--
1432.53.0
144