From 7b2fdc6de13df0007c441c5d26e44567adc0f810 Mon Sep 17 00:00:00 2001 From: michael-grunder Date: Mon, 1 Jun 2026 10:02:54 -0700 Subject: [PATCH] fix: Guard against bulk length overflow Clamp range in a couple library functions to values that can fit into an iint, since we narrow it later. A more comprehensive change that widens all of these values to 64 bits will come in a future commit. --- library.c | 23 ++++++++++++++++++++--- library.h | 2 +- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/library.c b/library.c index 92e6efc1..1bb6fa63 100644 --- a/library.c +++ b/library.c @@ -778,6 +778,12 @@ redis_sock_read_bulk_reply(RedisSock *redis_sock, int bytes) char *reply; ssize_t got; + if (bytes < -1 || bytes > INT_MAX - 2) { + zend_throw_exception_ex(redis_exception_ce, 0, + "protocol error, invalid bulk length: %d", bytes); + return NULL; + } + if (-1 == bytes || -1 == redis_check_eof(redis_sock, 1, 0)) { return NULL; } @@ -4642,18 +4648,29 @@ redis_read_variant_line(RedisSock *redis_sock, REDIS_REPLY_TYPE reply_type, } PHP_REDIS_API int -redis_read_variant_bulk(RedisSock *redis_sock, int size, zval *z_ret +redis_read_variant_bulk(RedisSock *redis_sock, long size, zval *z_ret ) { + int bytes; + + if (size < -1 || size > INT_MAX - 2) { + zend_throw_exception_ex(redis_exception_ce, 0, + "protocol error, invalid bulk length: %ld", size); + ZVAL_FALSE(z_ret); + return -1; + } + + bytes = size; + // Attempt to read the bulk reply - char *bulk_resp = redis_sock_read_bulk_reply(redis_sock, size); + char *bulk_resp = redis_sock_read_bulk_reply(redis_sock, bytes); /* Set our reply to FALSE on failure, and the string on success */ if(bulk_resp == NULL) { ZVAL_FALSE(z_ret); return -1; } - ZVAL_STRINGL(z_ret, bulk_resp, size); + ZVAL_STRINGL(z_ret, bulk_resp, bytes); efree(bulk_resp); return 0; } diff --git a/library.h b/library.h index d5c30c88..39227c62 100644 --- a/library.h +++ b/library.h @@ -238,7 +238,7 @@ PHP_REDIS_API int redis_acl_log_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *r */ PHP_REDIS_API int redis_read_reply_type(RedisSock *redis_sock, REDIS_REPLY_TYPE *reply_type, long *reply_info); -PHP_REDIS_API int redis_read_variant_bulk(RedisSock *redis_sock, int size, zval *z_ret); +PHP_REDIS_API int redis_read_variant_bulk(RedisSock *redis_sock, long size, zval *z_ret); PHP_REDIS_API int redis_read_multibulk_recursive(RedisSock *redis_sock, long long elements, int status_strings, zval *z_ret); PHP_REDIS_API int redis_read_variant_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx); PHP_REDIS_API int redis_read_raw_variant_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);