HTTP wrapper leaks Location buffer when an empty Location header is followed by another Location header
Les mainteneurs répondent en général sous 1 jour
Personne n'a encore pris cette issue.
Évaluation
- Difficulté
- 2/5
- Temps estimé
- 1-3 heures
- Accessibilité débutants
- 78/100
- Type d'issue
- Bug
- Clarté
- Clairement spécifiée
- Activité
- Active
- Domaine
- backend, networking
Piste de recherche
Commencez dans ext/standard/http_fopen_wrapper.c, au niveau de php_stream_http_response_headers_parse(), et examinez comment les en-têtes Location répétés allouent et redimensionnent le tampon. Le rapport inclut une reproduction de la fuite avec server.php et client.php ; exécutez-la avec une compilation de débogage de PHP et report_memleaks=1. Le travail est terminé lorsque la séquence d’un en-tête vide puis non vide ne signale aucune fuite, tandis que les en-têtes Location non vides répétés se comportent toujours comme décrit.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
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
- Langage dominant
- C
- Étoiles
- 40.4k
- Forks
- 8.2k
- Merge moyen
- 2 j 22 h
- PR mergées (30 j)
- 166
Préparer son environnement
- Aucun Dockerfile ni fichier Docker Compose
- Aucun modèle de pull request
- Lire le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de php/php-src
-
HTTP wrapper leaks dechunk filter when header parsing fails after Transfer-Encoding: chunkedOuverteBug Status: Needs Triage
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
Les mainteneurs répondent en général sous 1 jour
-
Bug Status: Needs Triage
Difficulté 2/5 1-3 heures Accessibilité débutants 71/100
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
Les mainteneurs répondent en général sous 1 jour
-
Bug Status: Needs Triage
Difficulté 2/5 1-3 heures Accessibilité débutants 64/100
Les mainteneurs répondent en général sous 1 jour
-
quoted_printable_encode() produces lines longer than 76 characters for bytes 0xF5 to 0xFFPeut-être pris Une pull request liée à cette issue est ouverte ou déjà fusionnée. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 76/100
Les mainteneurs répondent en général sous 1 jour
Toutes les issues de php/php-src
Issues similaires
-
bug
Difficulté 2/5 1-3 heures Accessibilité débutants 76/100
valkey-io/valkey#4979 · 1 réaction ·
Les mainteneurs répondent en général sous 2 jours
-
Difficulté 2/5 1-3 heures Accessibilité débutants 70/100
colbymchenry/codegraph#2770 ·
Les mainteneurs répondent en général sous 1 jour
-
canard.c 5.0.0: static random() conflicts with newlib's random() (fails to build on ESP-IDF)Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 86/100
OpenCyphal/libcanard#264 ·
-
area/ysql kind/enhancement priority/medium status/awaiting-triage
Difficulté 2/5 1-3 heures Accessibilité débutants 73/100
yugabyte/yugabyte-db#35578 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 66/100
Les mainteneurs répondent en général sous 1 jour