From 678ecff9808ab9fd340e9110935b02de4ab73543 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 13 Feb 2025 19:49:13 +0100 Subject: [PATCH] Fix memory leak on overflow in _php_stream_scandir() On overflow, only the array is freed, but not the strings. Closes GH-17789. --- NEWS | 1 + main/streams/streams.c | 24 +++++++++++++----------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/NEWS b/NEWS index bbc96dd924a..9493e4f6af7 100644 --- a/NEWS +++ b/NEWS @@ -41,6 +41,7 @@ PHP NEWS - Streams: . Fixed bug GH-17650 (realloc with size 0 in user_filters.c). (nielsdos) + . Fix memory leak on overflow in _php_stream_scandir(). (nielsdos) - Windows: . Fixed phpize for Windows 11 (24H2). (bwoebi) diff --git a/main/streams/streams.c b/main/streams/streams.c index 934ed142115..7a5dc2a58aa 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -2469,25 +2469,19 @@ PHPAPI int _php_stream_scandir(const char *dirname, zend_string **namelist[], in vector_size = 10; } else { if(vector_size*2 < vector_size) { - /* overflow */ - php_stream_closedir(stream); - efree(vector); - return -1; + goto overflow; } vector_size *= 2; } - vector = (zend_string **) safe_erealloc(vector, vector_size, sizeof(char *), 0); + vector = (zend_string **) safe_erealloc(vector, vector_size, sizeof(zend_string *), 0); } vector[nfiles] = zend_string_init(sdp.d_name, strlen(sdp.d_name), 0); - nfiles++; - if(vector_size < 10 || nfiles == 0) { - /* overflow */ - php_stream_closedir(stream); - efree(vector); - return -1; + if(vector_size < 10 || nfiles + 1 == 0) { + goto overflow; } + nfiles++; } php_stream_closedir(stream); @@ -2497,5 +2491,13 @@ PHPAPI int _php_stream_scandir(const char *dirname, zend_string **namelist[], in qsort(*namelist, nfiles, sizeof(zend_string *), (int(*)(const void *, const void *))compare); } return nfiles; + +overflow: + php_stream_closedir(stream); + for (unsigned int i = 0; i < nfiles; i++) { + zend_string_efree(vector[i]); + } + efree(vector); + return -1; } /* }}} */