changeset 6272:b6a665bf858a

HTTP/2: fix indirect reprioritization. Previously, streams that were indirectly reprioritized (either because of a new exclusive dependency on their parent or because of removal of their parent from the dependency tree), didn't have their pointer to the parent node updated. This broke detection of circular dependencies and, as a result, nginx worker would crash due to stack overflow whenever such dependency was introduced. Found with afl-fuzz. Signed-off-by: Piotr Sikora <piotrsikora@google.com>
author Piotr Sikora <piotrsikora@google.com>
date Thu, 01 Oct 2015 20:25:55 -0700
parents 22ee99422329
children 60f916da7294
files src/http/v2/ngx_http_v2.c
diffstat 1 files changed, 13 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/src/http/v2/ngx_http_v2.c
+++ b/src/http/v2/ngx_http_v2.c
@@ -2914,11 +2914,14 @@ ngx_http_v2_get_closed_node(ngx_http_v2_
         weight += child->weight;
     }
 
+    parent = node->parent;
+
     for (q = ngx_queue_head(&node->children);
          q != ngx_queue_sentinel(&node->children);
          q = ngx_queue_next(q))
     {
         child = ngx_queue_data(q, ngx_http_v2_node_t, queue);
+        child->parent = parent;
         child->weight = node->weight * child->weight / weight;
 
         if (child->weight == 0) {
@@ -2926,8 +2929,6 @@ ngx_http_v2_get_closed_node(ngx_http_v2_
         }
     }
 
-    parent = node->parent;
-
     if (parent == NGX_HTTP_V2_ROOT) {
         node->rank = 0;
         node->rel_weight = 1.0;
@@ -3940,8 +3941,8 @@ static void
 ngx_http_v2_set_dependency(ngx_http_v2_connection_t *h2c,
     ngx_http_v2_node_t *node, ngx_uint_t depend, ngx_uint_t exclusive)
 {
-    ngx_queue_t         *children;
-    ngx_http_v2_node_t  *parent, *next;
+    ngx_queue_t         *children, *q;
+    ngx_http_v2_node_t  *parent, *child, *next;
 
     parent = depend ? ngx_http_v2_get_node_by_id(h2c, depend, 0) : NULL;
 
@@ -4003,6 +4004,14 @@ ngx_http_v2_set_dependency(ngx_http_v2_c
     }
 
     if (exclusive) {
+        for (q = ngx_queue_head(children);
+             q != ngx_queue_sentinel(children);
+             q = ngx_queue_next(q))
+        {
+            child = ngx_queue_data(q, ngx_http_v2_node_t, queue);
+            child->parent = node;
+        }
+
         ngx_queue_add(&node->children, children);
         ngx_queue_init(children);
     }