HTTP wrapper leaks Location buffer when an empty Location header is followed by another Location header
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 78/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Ambito
- backend, networking
Direzione di ricerca
Inizia in ext/standard/http_fopen_wrapper.c, in corrispondenza di php_stream_http_response_headers_parse(), e verifica come le intestazioni Location ripetute allocano e ridimensionano il buffer. Il report include una riproduzione della perdita con server.php e client.php; eseguila con una build di PHP di debug e report_memleaks=1. Il lavoro è completato quando la sequenza di un’intestazione vuota seguita da una non vuota non segnala perdite, mentre le intestazioni Location non vuote ripetute continuano a comportarsi come descritto.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Description
The following code:
server.php (run first, php server.php):
<?php
$srv = stream_socket_server("tcp://127.0.0.1:18233", $errno, $errstr);
$conn = stream_socket_accept($srv);
while (($line = fgets($conn, 8192)) !== false) { if (trim($line) === '') break; }
// empty Location value, then a real one
fwrite($conn, "HTTP/1.1 302 Found\r\nLocation:\r\nLocation: /abcdefghijklmno\r\n\r\n");
fclose($conn);
client.php (debug build, php -d report_memleaks=1 client.php):
<?php
@file_get_contents("http://127.0.0.1:18233/");
Resulted in this output:
ext/standard/http_fopen_wrapper.c(341) : Freeing 0x... (16 bytes), script=.../client.php
=== Total 1 memory leaks detected ===
But I expected this output instead:
(no leaks reported)
Root cause: the wrapper stores the Location value using location_len == 0 as the "nothing allocated yet" sentinel (ext/standard/http_fopen_wrapper.c:340 in 8.5.12, :327 on master):
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;
An empty Location: header allocates a 1-byte buffer and then sets location_len = 0, restoring the sentinel state while the pointer is still held. A second Location header takes the emalloc branch again and the first buffer is leaked. Each empty-then-nonempty sequence leaks one buffer per request.
Control (two non-empty Location headers): 0 leaks. Reproduces on current master (8.7.0-dev) as well.
Suggested patch (verified against master: 0 leaks after patching; repeated non-empty Location headers still take the erealloc path and behave as before). header_info is zero-initialized by php_stream_http_response_header_info_init, so the pointer works as the sentinel:
--- a/ext/standard/http_fopen_wrapper.c
+++ b/ext/standard/http_fopen_wrapper.c
@@ -324,7 +324,9 @@ static zend_string *php_stream_http_response_headers_parse(php_stream_wrapper *w
zend_string_efree(last_header_line);
return NULL;
}
- if (header_info->location_len == 0) {
+ /* An empty Location value leaves location_len at 0, so the buffer
+ * pointer, not the length, must be the "already allocated" test. */
+ if (header_info->location == NULL) {
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);
PHP Version
PHP 8.5.12 (also reproduces on master, 8.7.0-dev)
Operating System
Linux x86_64
- Lingua principale
- C
- Stelle
- 40.7k
- Fork
- 8.3k
- Merge medio
- 17h 29m
- PR unite (30g)
- 10
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Nessun modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di php/php-src
-
Case-insensitive substr_compare, ksort, krsort are still locale-dependentForse già presa Una pull request collegata a questa issue è aperta o già unita. ApertaBug Status: Needs Triage
Difficoltà 2/5 1-3 ore Idoneità per principianti 73/100
php/php-src#24552 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Bug Status: Needs Triage
Difficoltà 2/5 1-3 ore Idoneità per principianti 71/100
php/php-src#24505 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
master: part of the mbstring bailout fix got lost in a mergeForse già presa @lazerg l’ha presa 1 giorno fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno
-
Bug Status: Needs Triage
Difficoltà 2/5 1-3 ore Idoneità per principianti 64/100
I maintainer di solito rispondono entro 1 giorno
-
quoted_printable_encode() produces lines longer than 76 characters for bytes 0xF5 to 0xFFForse già presa Una pull request collegata a questa issue è aperta o già unita. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
I maintainer di solito rispondono entro 1 giorno
Issue simili
-
TLS: a stale OpenSSL error makes non-blocking reads fail with "Resource temporarily unavailable"Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 1/5 1-3 ore Idoneità per principianti 82/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
bigtreetech/BIGTREETECH-TouchScreenFirmware#3056 ·
I maintainer di solito rispondono entro 1 giorno
-
Allow pillow 13Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
-
[pico][astrocade] emu/apply.sh edits src/mame/midway/astrohome.cpp, which current MAME has in bally/Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 83/100
FujiNetWIFI/fujinet-firmware#2120 ·
I maintainer di solito rispondono entro 1 giorno