Memory Leak Issue in Nginx PCRE2

Maxim Dounin mdounin at mdounin.ru
Tue Oct 10 22:04:04 UTC 2023


Hello!

On Wed, Sep 27, 2023 at 01:13:44AM +0800, 上勾拳 wrote:

> Dear Nginx Developers,
> 
> I hope this email finds you well. I am reaching out to the mailing list for
> the first time to report and discuss an issue I encountered while working
> on supporting PCRE2 in OpenResty. If I have made any errors in my reporting
> or discussion, please do not hesitate to provide feedback. Your guidance is
> greatly appreciated.
> 
> During my recent work, I used the sanitizer to inspect potential issues,
> and I identified a small memory leak in the PCRE2 code section of Nginx.
> While this issue does not seem to be critical, it could potentially disrupt
> memory checking tools. To help you reproduce the problem, I have included a
> minimal configuration below. Please note that this issue occurs when Nginx
> is configured to use PCRE2, and the version is 1.22.1 or higher.
> 
> *Minimal Configuration for Reproduction:*
> worker_processes  1;
> daemon off;
> master_process off;
> error_log
> /home/zhenzhongw/code/pcre_pr/lua-nginx-module/t/servroot/logs/error.log
> debug;
> pid
> /home/zhenzhongw/code/pcre_pr/lua-nginx-module/t/servroot/logs/nginx.pid;
> 
> http {
>     access_log
> /home/zhenzhongw/code/pcre_pr/lua-nginx-module/t/servroot/logs/access.log;
>     #access_log off;
>     default_type text/plain;
>     keepalive_timeout  68000ms;
>     server {
>         listen          1984;
>         #placeholder
>         server_name     'localhost';
> 
>         client_max_body_size 30M;
>         #client_body_buffer_size 4k;
> 
>         # Begin preamble config...
> 
>         # End preamble config...
> 
>         # Begin test case config...
> 
>         location ~ '^/[a-d]$' {
>             return 200;
>         }
>     }
> }
> events {
>     accept_mutex off;
> 
>     worker_connections  64;
> }
> 
> *nginx -V :*
> nginx version: nginx/1.25.1 (no pool)
> built by gcc 11.4.1 20230605 (Red Hat 11.4.1-2) (GCC)
> built with OpenSSL 1.1.1u  30 May 2023
> TLS SNI support enabled
> configure arguments:
> --prefix=/home/zhenzhongw/code/pcre_pr/lua-nginx-module/work/nginx
> --with-threads --with-pcre-jit --with-ipv6
> --with-cc-opt='-fno-omit-frame-pointer -fsanitize=address
> -DNGX_LUA_USE_ASSERT -I/opt/pcre2/include -I/opt/ssl/include'
> --with-http_v2_module --with-http_v3_module --with-http_realip_module
> --with-http_ssl_module
> --add-module=/home/zhenzhongw/code/pcre_pr/ndk-nginx-module
> --add-module=/home/zhenzhongw/code/pcre_pr/set-misc-nginx-module
> --with-ld-opt='-fsanitize=address -L/opt/pcre2/lib -L/opt/ssl/lib
> -Wl,-rpath,/opt/pcre2/lib:/opt/drizzle/lib:/opt/ssl/lib'
> --without-mail_pop3_module --without-mail_imap_module
> --with-http_image_filter_module --without-mail_smtp_module --with-stream
> --with-stream_ssl_module --without-http_upstream_ip_hash_module
> --without-http_memcached_module --without-http_auth_basic_module
> --without-http_userid_module --with-http_auth_request_module
> --add-module=/home/zhenzhongw/code/pcre_pr/echo-nginx-module
> --add-module=/home/zhenzhongw/code/pcre_pr/memc-nginx-module
> --add-module=/home/zhenzhongw/code/pcre_pr/srcache-nginx-module
> --add-module=/home/zhenzhongw/code/pcre_pr/lua-nginx-module
> --add-module=/home/zhenzhongw/code/pcre_pr/lua-upstream-nginx-module
> --add-module=/home/zhenzhongw/code/pcre_pr/headers-more-nginx-module
> --add-module=/home/zhenzhongw/code/pcre_pr/drizzle-nginx-module
> --add-module=/home/zhenzhongw/code/pcre_pr/rds-json-nginx-module
> --add-module=/home/zhenzhongw/code/pcre_pr/coolkit-nginx-module
> --add-module=/home/zhenzhongw/code/pcre_pr/redis2-nginx-module
> --add-module=/home/zhenzhongw/code/pcre_pr/stream-lua-nginx-module
> --add-module=/home/zhenzhongw/code/pcre_pr/lua-nginx-module/t/data/fake-module
> --add-module=/home/zhenzhongw/code/pcre_pr/lua-nginx-module/t/data/fake-shm-module
> --add-module=/home/zhenzhongw/code/pcre_pr/lua-nginx-module/t/data/fake-delayed-load-module
> --with-http_gunzip_module --with-http_dav_module --with-select_module
> --with-poll_module --with-debug --with-poll_module --with-cc=gcc
> 
> *The sanitizer tool reported the following error message: *
> =================================================================
> ==555798==ERROR: LeakSanitizer: detected memory leaks
> 
> Direct leak of 72 byte(s) in 1 object(s) allocated from:
>     #0 0x7f502f6b4a07 in __interceptor_malloc (/lib64/libasan.so.6+0xb4a07)
>     #1 0x4a1737 in ngx_alloc src/os/unix/ngx_alloc.c:22
>     #2 0x525796 in ngx_regex_malloc src/core/ngx_regex.c:509
>     #3 0x7f502f3e745e in _pcre2_memctl_malloc_8
> (/opt/pcre2/lib/libpcre2-8.so.0+0x1145e)
>     #4 0x5771ad in ngx_http_regex_compile src/http/ngx_http_variables.c:2555
>     #5 0x536088 in ngx_http_core_regex_location
> src/http/ngx_http_core_module.c:3263
>     #6 0x537f94 in ngx_http_core_location
> src/http/ngx_http_core_module.c:3115
>     #7 0x46ba0a in ngx_conf_handler src/core/ngx_conf_file.c:463
>     #8 0x46ba0a in ngx_conf_parse src/core/ngx_conf_file.c:319
>     #9 0x5391ec in ngx_http_core_server src/http/ngx_http_core_module.c:2991
>     #10 0x46ba0a in ngx_conf_handler src/core/ngx_conf_file.c:463
>     #11 0x46ba0a in ngx_conf_parse src/core/ngx_conf_file.c:319
>     #12 0x528e4c in ngx_http_block src/http/ngx_http.c:239
>     #13 0x46ba0a in ngx_conf_handler src/core/ngx_conf_file.c:463
>     #14 0x46ba0a in ngx_conf_parse src/core/ngx_conf_file.c:319
>     #15 0x463f74 in ngx_init_cycle src/core/ngx_cycle.c:284
>     #12 0x528e4c in ngx_http_block src/http/ngx_http.c:239
>     #13 0x46ba0a in ngx_conf_handler src/core/ngx_conf_file.c:463
>     #14 0x46ba0a in ngx_conf_parse src/core/ngx_conf_file.c:319
>     #15 0x463f74 in ngx_init_cycle src/core/ngx_cycle.c:284
>     #16 0x4300c7 in main src/core/nginx.c:295
>     #17 0x7ff31a43feaf in __libc_start_call_main (/lib64/libc.so.6+0x3feaf)
> 
> SUMMARY: AddressSanitizer: 72 byte(s) leaked in 1 allocation(s).
> 
> *I have created a patch to address this memory leak issue, which I am
> sharing below:*
> diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c
> index 91381f499..71f583789 100644
> --- a/src/core/ngx_regex.c
> +++ b/src/core/ngx_regex.c
> @@ -600,6 +600,8 @@ ngx_regex_cleanup(void *data)
>       * the new cycle, these will be re-allocated.
>       */
> 
> +    ngx_regex_malloc_init(NULL);
> +
>      if (ngx_regex_compile_context) {
>          pcre2_compile_context_free(ngx_regex_compile_context);
>          ngx_regex_compile_context = NULL;
> @@ -611,6 +613,8 @@ ngx_regex_cleanup(void *data)
>          ngx_regex_match_data_size = 0;
>      }
> 
> +    ngx_regex_malloc_done();
> +
>  #endif
>  }
> 
> @@ -706,7 +710,13 @@ ngx_regex_module_init(ngx_cycle_t *cycle)
>      ngx_regex_malloc_done();
> 
>      ngx_regex_studies = NULL;
> +
>  #if (NGX_PCRE2)
> +    if (ngx_regex_compile_context) {
> +        ngx_regex_malloc_init(NULL);
> +        pcre2_compile_context_free(ngx_regex_compile_context);
> +        ngx_regex_malloc_done();
> +    }
>      ngx_regex_compile_context = NULL;
>  #endif
> 
> I kindly request your assistance in reviewing this matter and considering
> the patch for inclusion in Nginx. If you have any questions or need further
> information, please feel free to reach out to me. Your expertise and
> feedback are highly valuable in resolving this issue.

Thank you for the report.

Indeed, this looks like a small leak which manifests itself during 
reconfiguration when nginx is compiled with PCRE2.

The patch looks correct to me, though I think it would be better 
to don't do anything with ngx_regex_compile_context in 
ngx_regex_module_init().  Please take a look if the following 
patch looks good to you:

# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1696950530 -10800
#      Tue Oct 10 18:08:50 2023 +0300
# Node ID 0ceb96f57592b77618fba4200797df977241ec9b
# Parent  cdda286c0f1b4b10f30d4eb6a63fefb9b8708ecc
Core: fixed memory leak on configuration reload with PCRE2.

In ngx_regex_cleanup() allocator wasn't configured when calling
pcre2_compile_context_free() and pcre2_match_data_free(), resulting
in no ngx_free() call and leaked memory.  Fix is ensure that allocator
is configured for global allocations, so that ngx_free() is actually
called to free memory.

Additionally, ngx_regex_compile_context was cleared in
ngx_regex_module_init().  It should be either not cleared, so it will
be freed by ngx_regex_cleanup(), or properly freed.  Fix is to
not clear it, so ngx_regex_cleanup() will be able to free it.

Reported by ZhenZhong Wu,
https://mailman.nginx.org/pipermail/nginx-devel/2023-September/3Z5FIKUDRN2WBSL3JWTZJ7SXDA6YIWPB.html

diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c
--- a/src/core/ngx_regex.c
+++ b/src/core/ngx_regex.c
@@ -600,6 +600,8 @@ ngx_regex_cleanup(void *data)
      * the new cycle, these will be re-allocated.
      */
 
+    ngx_regex_malloc_init(NULL);
+
     if (ngx_regex_compile_context) {
         pcre2_compile_context_free(ngx_regex_compile_context);
         ngx_regex_compile_context = NULL;
@@ -611,6 +613,8 @@ ngx_regex_cleanup(void *data)
         ngx_regex_match_data_size = 0;
     }
 
+    ngx_regex_malloc_done();
+
 #endif
 }
 
@@ -706,9 +710,6 @@ ngx_regex_module_init(ngx_cycle_t *cycle
     ngx_regex_malloc_done();
 
     ngx_regex_studies = NULL;
-#if (NGX_PCRE2)
-    ngx_regex_compile_context = NULL;
-#endif
 
     return NGX_OK;
 }


-- 
Maxim Dounin
http://mdounin.ru/


More information about the nginx-devel mailing list