[PATCH] Core: fixed environment on exit better

Sergey Kandaurov pluknet at nginx.com
Fri Jun 23 15:55:47 UTC 2023


# HG changeset patch
# User Sergey Kandaurov <pluknet at nginx.com>
# Date 1687535739 -14400
#      Fri Jun 23 19:55:39 2023 +0400
# Node ID 34a8e1a4161542896c11c4a5c60d6a6fe1931e3d
# Parent  c681f4906d838ac45b517fada4c4274ade03fd3c
Core: fixed environment on exit better.

The fix in 6822:c045b4926b2c to replace environment allocations from a pool
was incomplete, such that it left pool owned allocations for variables set
with values using the "env" directive.  Another consumer of this interface
is the QUIC BPF helper that uses the environment variable NGINX_BPF_MAPS.
The fix is to re-allocate variables with malloc, to avoid use after free.
If memory allocation failed, the only option is to expel from environment.

The observed symptoms are similar to described in 6822:c045b4926b2c, that
is a segmentation fault on worker process exit from atexit() handler seen
with 3rd party modules or if nginx was built with lcov profiling.

diff --git a/src/core/nginx.c b/src/core/nginx.c
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -631,17 +631,48 @@ ngx_cleanup_environment(void *data)
 {
     char  **env = data;
 
-    if (environ == env) {
+    char        *p, **penv;
+    size_t       size;
+    ngx_uint_t   i, n;
 
-        /*
-         * if the environment is still used, as it happens on exit,
-         * the only option is to leak it
-         */
-
+    if (environ != env) {
+        ngx_free(env);
         return;
     }
 
-    ngx_free(env);
+    /*
+     * if the environment is still used, as it happens on exit,
+     * the only option is to leak it
+     */
+
+    for (n = 0; env[n]; n++) { }
+
+    for (i = 0; env[i]; i++) {
+
+        for (penv = ngx_os_environ; *penv; penv++) {
+            if (ngx_strcmp(*penv, env[i]) == 0) {
+                break;
+            }
+        }
+
+        if (*penv) {
+            continue;
+        }
+
+        /* substitute pool allocated variables */
+
+        size = ngx_strlen(env[i]) + 1;
+        p = malloc(size);
+
+        if (p) {
+            ngx_memcpy(p, env[i], size);
+            env[i] = p;
+
+        } else {
+            ngx_memmove(&env[i], &env[i + 1], sizeof(char *) * (n - i));
+            i--; n--;
+        }
+    }
 }
 
 


More information about the nginx-devel mailing list