]> git.kaiwu.me - nginx.git/commitdiff
HTTP/2: fix indirect reprioritization.
authorPiotr Sikora <piotrsikora@google.com>
Fri, 2 Oct 2015 03:25:55 +0000 (20:25 -0700)
committerPiotr Sikora <piotrsikora@google.com>
Fri, 2 Oct 2015 03:25:55 +0000 (20:25 -0700)
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>
src/http/v2/ngx_http_v2.c

index 6cca2b9a38c0e8ddb1ed1600e83073221d8983fb..51cf65a881b631e5082286dc0ea52996ee78db43 100644 (file)
@@ -2914,11 +2914,14 @@ ngx_http_v2_get_closed_node(ngx_http_v2_connection_t *h2c)
         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_connection_t *h2c)
         }
     }
 
-    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_connection_t *h2c,
     }
 
     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);
     }