From f9c4264b6b48f4d9559dabd8ff2ff356e12d95fb Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Mon, 7 Sep 2026 19:47:51 +0400 Subject: [PATCH] Geo: check binary base CRC32 before relocation This provides safe pointer handling in the event of a corrupted file. --- src/http/modules/ngx_http_geo_module.c | 41 +++++++++++++++---------- src/stream/ngx_stream_geo_module.c | 42 +++++++++++++++----------- 2 files changed, 50 insertions(+), 33 deletions(-) diff --git a/src/http/modules/ngx_http_geo_module.c b/src/http/modules/ngx_http_geo_module.c index 1350c7db4..2b0bcc165 100644 --- a/src/http/modules/ngx_http_geo_module.c +++ b/src/http/modules/ngx_http_geo_module.c @@ -1423,7 +1423,6 @@ ngx_http_geo_include_binary_base(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, time_t mtime; size_t size, len; ssize_t n; - uint32_t crc32; ngx_err_t err; ngx_int_t rc; ngx_uint_t i; @@ -1518,24 +1517,45 @@ ngx_http_geo_include_binary_base(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, goto failed; } - ngx_crc32_init(crc32); + /* + * the base is walked below without bounds checking, so make sure + * it is intact first: the checksum in the header is computed over + * the entire body, which the walk covers contiguously + */ + + if (size < sizeof(ngx_http_geo_header_t) + + sizeof(ngx_http_variable_value_t) + + 0x10000 * sizeof(ngx_http_geo_range_t *)) + { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "truncated binary geo range base \"%s\"", + name->data); + goto failed; + } + + if (ngx_crc32_long(base + sizeof(ngx_http_geo_header_t), + size - sizeof(ngx_http_geo_header_t)) + != header->crc32) + { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "CRC32 mismatch in binary geo range base \"%s\"", + name->data); + goto failed; + } vv = (ngx_http_variable_value_t *) (base + sizeof(ngx_http_geo_header_t)); while (vv->data) { len = ngx_align(sizeof(ngx_http_variable_value_t) + vv->len, sizeof(void *)); - ngx_crc32_update(&crc32, (u_char *) vv, len); vv->data += (size_t) base; vv = (ngx_http_variable_value_t *) ((u_char *) vv + len); } - ngx_crc32_update(&crc32, (u_char *) vv, sizeof(ngx_http_variable_value_t)); vv++; ranges = (ngx_http_geo_range_t **) vv; for (i = 0; i < 0x10000; i++) { - ngx_crc32_update(&crc32, (u_char *) &ranges[i], sizeof(void *)); if (ranges[i]) { ranges[i] = (ngx_http_geo_range_t *) ((u_char *) ranges[i] + (size_t) base); @@ -1546,24 +1566,13 @@ ngx_http_geo_include_binary_base(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, while ((u_char *) range < base + size) { while (range->value) { - ngx_crc32_update(&crc32, (u_char *) range, - sizeof(ngx_http_geo_range_t)); range->value = (ngx_http_variable_value_t *) ((u_char *) range->value + (size_t) base); range++; } - ngx_crc32_update(&crc32, (u_char *) range, sizeof(void *)); range = (ngx_http_geo_range_t *) ((u_char *) range + sizeof(void *)); } - ngx_crc32_final(crc32); - - if (crc32 != header->crc32) { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "CRC32 mismatch in binary geo range base \"%s\"", name->data); - goto failed; - } - ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "using binary geo range base \"%s\"", name->data); diff --git a/src/stream/ngx_stream_geo_module.c b/src/stream/ngx_stream_geo_module.c index 6dcc3b5a8..d2c1d6892 100644 --- a/src/stream/ngx_stream_geo_module.c +++ b/src/stream/ngx_stream_geo_module.c @@ -1349,7 +1349,6 @@ ngx_stream_geo_include_binary_base(ngx_conf_t *cf, time_t mtime; size_t size, len; ssize_t n; - uint32_t crc32; ngx_err_t err; ngx_int_t rc; ngx_uint_t i; @@ -1444,7 +1443,31 @@ ngx_stream_geo_include_binary_base(ngx_conf_t *cf, goto failed; } - ngx_crc32_init(crc32); + /* + * the base is walked below without bounds checking, so make sure + * it is intact first: the checksum in the header is computed over + * the entire body, which the walk covers contiguously + */ + + if (size < sizeof(ngx_stream_geo_header_t) + + sizeof(ngx_stream_variable_value_t) + + 0x10000 * sizeof(ngx_stream_geo_range_t *)) + { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "truncated binary geo range base \"%s\"", + name->data); + goto failed; + } + + if (ngx_crc32_long(base + sizeof(ngx_stream_geo_header_t), + size - sizeof(ngx_stream_geo_header_t)) + != header->crc32) + { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "CRC32 mismatch in binary geo range base \"%s\"", + name->data); + goto failed; + } vv = (ngx_stream_variable_value_t *) (base + sizeof(ngx_stream_geo_header_t)); @@ -1452,18 +1475,14 @@ ngx_stream_geo_include_binary_base(ngx_conf_t *cf, while (vv->data) { len = ngx_align(sizeof(ngx_stream_variable_value_t) + vv->len, sizeof(void *)); - ngx_crc32_update(&crc32, (u_char *) vv, len); vv->data += (size_t) base; vv = (ngx_stream_variable_value_t *) ((u_char *) vv + len); } - ngx_crc32_update(&crc32, (u_char *) vv, - sizeof(ngx_stream_variable_value_t)); vv++; ranges = (ngx_stream_geo_range_t **) vv; for (i = 0; i < 0x10000; i++) { - ngx_crc32_update(&crc32, (u_char *) &ranges[i], sizeof(void *)); if (ranges[i]) { ranges[i] = (ngx_stream_geo_range_t *) ((u_char *) ranges[i] + (size_t) base); @@ -1474,24 +1493,13 @@ ngx_stream_geo_include_binary_base(ngx_conf_t *cf, while ((u_char *) range < base + size) { while (range->value) { - ngx_crc32_update(&crc32, (u_char *) range, - sizeof(ngx_stream_geo_range_t)); range->value = (ngx_stream_variable_value_t *) ((u_char *) range->value + (size_t) base); range++; } - ngx_crc32_update(&crc32, (u_char *) range, sizeof(void *)); range = (ngx_stream_geo_range_t *) ((u_char *) range + sizeof(void *)); } - ngx_crc32_final(crc32); - - if (crc32 != header->crc32) { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "CRC32 mismatch in binary geo range base \"%s\"", name->data); - goto failed; - } - ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "using binary geo range base \"%s\"", name->data); -- 2.47.3