Welcome! Log In Create A New Profile

Advanced

Re: Memory Leak Issue in Nginx PCRE2

Maxim Dounin
October 17, 2023 12:02AM
Hello!

On Mon, Oct 16, 2023 at 06:19:48PM +0400, Sergey Kandaurov wrote:

>
> > On 11 Oct 2023, at 02:04, Maxim Dounin <mdounin@mdounin.ru> wrote:
> >
> > 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@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;
> > }
> >
>
> Note that direct leaks are also reported when
> pcre2_compile_context_create() is called in runtime from a worker
> process, such as in ngx_http_ssi_regex_match(). The patch stands
> correct in this regard though. Anyway, leaking a compile context
> in a worker process doesn't seem to be harmful as they do not
> accumulate: it's only possible to allocate up to two contexts
> in a worker process: the 1st borrowed from the master process,
> and the 2nd allocated in runtime (replacing the COW'ed one).

In ngx_http_ssi_regex_match(), compile context is only allocated
(via ngx_regex_compile()) if ngx_regex_compile_context is NULL,
that is, no additional contexts will be allocated if COW'ed one is
available. And with the patch, if there is an allocated compile
context, it will be properly freed on cycle destruction in
ngx_regex_cleanup().

> Currently, nginx configuration doesn't seem to provide a way to
> alter the default values in the compile context (per man pcre2api).
> So the proposed change does look correct. But potentially, if we'd
> want to change this behaviour, the patch has a subtle downside,
> which may prevent to apply such configuration changes:
> - on the 1st configuration reload, ngx_regex_compile() will be called
> with the compile context borrowed from a previous cycle (if any), so
> any compile context changes won't be applied to the new configuration
> - on subsequent reloads, this is not an issue, because a previous
> cycle cleanup will free and reset ngx_regex_compile_context, such
> that a current cycle runs will ngx_regex_compile_context == NULL,
> and it will cause to allocate a new context in the next cycle.

Sure. Compile contexts are expected to be equivalent regardless
of when a particular context allocation happens, and the existing
code relies on this.

If we'll consider changing this, it would be required to somehow
provide access from ngx_regex_compile() to the relevant cycle
(that is, either the cycle being created during configuration
parsing, or ngx_cycle for runtime compilation). And with such
access, the ngx_regex_compile_context global variable and direct
allocation from heap won't be needed, as it would be easier to
simply allocate compile context from the cycle pool.

> Other than that, it looks good.

Thanks for looking, pushed to http://mdounin.ru/hg/nginx/

--
Maxim Dounin
http://mdounin.ru/
_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel
Subject Author Views Posted

Memory Leak Issue in Nginx PCRE2

上勾拳 297 September 26, 2023 01:14PM

Re: Memory Leak Issue in Nginx PCRE2

Maxim Dounin 64 October 10, 2023 06:06PM

Re: Memory Leak Issue in Nginx PCRE2

Sergey Kandaurov 52 October 16, 2023 10:20AM

Re: Memory Leak Issue in Nginx PCRE2

Maxim Dounin 72 October 17, 2023 12:02AM

Re: Memory Leak Issue in Nginx PCRE2

上勾拳 61 October 12, 2023 11:04AM



Sorry, you do not have permission to post/reply in this forum.

Online Users

Guests: 293
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready