diff --git a/ext/standard/filters.c b/ext/standard/filters.c index a7c0a035a239..0c08600648cd 100644 --- a/ext/standard/filters.c +++ b/ext/standard/filters.c @@ -1715,12 +1715,14 @@ static size_t php_dechunk(char *buf, size_t len, php_chunked_filter_data *data) data->chunk_size = 0; case CHUNK_SIZE: while (p < end) { + size_t digit; + if (*p >= '0' && *p <= '9') { - data->chunk_size = (data->chunk_size * 16) + (*p - '0'); + digit = *p - '0'; } else if (*p >= 'A' && *p <= 'F') { - data->chunk_size = (data->chunk_size * 16) + (*p - 'A' + 10); + digit = *p - 'A' + 10; } else if (*p >= 'a' && *p <= 'f') { - data->chunk_size = (data->chunk_size * 16) + (*p - 'a' + 10); + digit = *p - 'a' + 10; } else if (data->state == CHUNK_SIZE_START) { data->state = CHUNK_ERROR; break; @@ -1728,6 +1730,11 @@ static size_t php_dechunk(char *buf, size_t len, php_chunked_filter_data *data) data->state = CHUNK_SIZE_EXT; break; } + if (data->chunk_size > (SIZE_MAX / 16)) { + data->state = CHUNK_ERROR; + break; + } + data->chunk_size = (data->chunk_size * 16) + digit; data->state = CHUNK_SIZE; p++; } diff --git a/ext/standard/tests/filters/dechunk_size_overflow.phpt b/ext/standard/tests/filters/dechunk_size_overflow.phpt new file mode 100644 index 000000000000..ac42733e16e0 --- /dev/null +++ b/ext/standard/tests/filters/dechunk_size_overflow.phpt @@ -0,0 +1,38 @@ +--TEST-- +dechunk filter must reject a chunk size that overflows size_t +--SKIPIF-- + +--INI-- +allow_url_fopen=1 +--FILE-- + +--EXPECTF-- +string(%d) "%s +BODYDATA +0 +" +string(%d) "%s +BODYDATA +0 +" +string(5) "hello"