]> git.kaiwu.me - nginx.git/commitdiff
Stream pass: limited the number of passes per connection.
authorRoman Arutyunyan <arut@nginx.com>
Thu, 11 Apr 2024 07:37:30 +0000 (11:37 +0400)
committerRoman Arutyunyan <arut@nginx.com>
Thu, 11 Apr 2024 07:37:30 +0000 (11:37 +0400)
Previously a cycle in pass configuration resulted in stack overflow.

src/stream/ngx_stream_pass_module.c

index 2ed0a51c2a498f94cde9333055991d24eddda97f..2c1c60c6a830742b41cb1ef9c08d5a04351e4b1c 100644 (file)
@@ -10,6 +10,9 @@
 #include <ngx_stream.h>
 
 
+#define NGX_STREAM_PASS_MAX_PASSES  10
+
+
 typedef struct {
     ngx_addr_t                  *addr;
     ngx_stream_complex_value_t  *addr_value;
@@ -17,6 +20,8 @@ typedef struct {
 
 
 static void ngx_stream_pass_handler(ngx_stream_session_t *s);
+static ngx_int_t ngx_stream_pass_check_cycle(ngx_connection_t *c);
+static void ngx_stream_pass_cleanup(void *data);
 static ngx_int_t ngx_stream_pass_match(ngx_listening_t *ls, ngx_addr_t *addr);
 static void *ngx_stream_pass_create_srv_conf(ngx_conf_t *cf);
 static char *ngx_stream_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
@@ -125,6 +130,10 @@ ngx_stream_pass_handler(ngx_stream_session_t *s)
     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
                    "stream pass addr: \"%V\"", &addr->name);
 
+    if (ngx_stream_pass_check_cycle(c) != NGX_OK) {
+        goto failed;
+    }
+
     ls = ngx_cycle->listening.elts;
 
     for (i = 0; i < ngx_cycle->listening.nelts; i++) {
@@ -163,6 +172,48 @@ failed:
 }
 
 
+static ngx_int_t
+ngx_stream_pass_check_cycle(ngx_connection_t *c)
+{
+    ngx_uint_t          *num;
+    ngx_pool_cleanup_t  *cln;
+
+    for (cln = c->pool->cleanup; cln; cln = cln->next) {
+        if (cln->handler != ngx_stream_pass_cleanup) {
+            continue;
+        }
+
+        num = cln->data;
+
+        if (++(*num) > NGX_STREAM_PASS_MAX_PASSES) {
+            ngx_log_error(NGX_LOG_ERR, c->log, 0, "stream pass cycle");
+            return NGX_ERROR;
+        }
+
+        return NGX_OK;
+    }
+
+    cln = ngx_pool_cleanup_add(c->pool, sizeof(ngx_uint_t));
+    if (cln == NULL) {
+        return NGX_ERROR;
+    }
+
+    cln->handler = ngx_stream_pass_cleanup;
+
+    num = cln->data;
+    *num = 1;
+
+    return NGX_OK;
+}
+
+
+static void
+ngx_stream_pass_cleanup(void *data)
+{
+    return;
+}
+
+
 static ngx_int_t
 ngx_stream_pass_match(ngx_listening_t *ls, ngx_addr_t *addr)
 {