comparison src/http/v2/ngx_http_v2.c @ 7208:affeb6ef732c

HTTP/2: fixed ngx_http_v2_push_stream() allocation error handling. In particular, if a stream object allocation failed, and a client sent the PRIORITY frame for this stream, ngx_http_v2_set_dependency() could dereference a null pointer while trying to re-parent a dependency node.
author Ruslan Ermilov <ru@nginx.com>
date Thu, 15 Feb 2018 17:51:37 +0300
parents 3d2b0b02bd3d
children 3dfe9444324b
comparison
equal deleted inserted replaced
7207:3d2b0b02bd3d 7208:affeb6ef732c
2544 ngx_http_v2_stream_t * 2544 ngx_http_v2_stream_t *
2545 ngx_http_v2_push_stream(ngx_http_v2_stream_t *parent, ngx_str_t *path) 2545 ngx_http_v2_push_stream(ngx_http_v2_stream_t *parent, ngx_str_t *path)
2546 { 2546 {
2547 ngx_int_t rc; 2547 ngx_int_t rc;
2548 ngx_str_t value; 2548 ngx_str_t value;
2549 ngx_pool_t *pool;
2550 ngx_uint_t index;
2549 ngx_table_elt_t **h; 2551 ngx_table_elt_t **h;
2550 ngx_connection_t *fc; 2552 ngx_connection_t *fc;
2551 ngx_http_request_t *r; 2553 ngx_http_request_t *r;
2552 ngx_http_v2_node_t *node; 2554 ngx_http_v2_node_t *node;
2553 ngx_http_v2_stream_t *stream; 2555 ngx_http_v2_stream_t *stream;
2556 ngx_http_v2_srv_conf_t *h2scf;
2554 ngx_http_v2_connection_t *h2c; 2557 ngx_http_v2_connection_t *h2c;
2555 ngx_http_v2_parse_header_t *header; 2558 ngx_http_v2_parse_header_t *header;
2556 2559
2557 h2c = parent->connection; 2560 h2c = parent->connection;
2558 2561
2562 pool = ngx_create_pool(1024, h2c->connection->log);
2563 if (pool == NULL) {
2564 goto rst_stream;
2565 }
2566
2559 node = ngx_http_v2_get_node_by_id(h2c, h2c->last_push, 1); 2567 node = ngx_http_v2_get_node_by_id(h2c, h2c->last_push, 1);
2560 2568
2561 if (node == NULL) { 2569 if (node == NULL) {
2562 return NULL; 2570 ngx_destroy_pool(pool);
2571 goto rst_stream;
2572 }
2573
2574 stream = ngx_http_v2_create_stream(h2c, 1);
2575 if (stream == NULL) {
2576
2577 if (node->parent == NULL) {
2578 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
2579 ngx_http_v2_module);
2580
2581 index = ngx_http_v2_index(h2scf, h2c->last_push);
2582 h2c->streams_index[index] = node->index;
2583
2584 ngx_queue_insert_tail(&h2c->closed, &node->reuse);
2585 h2c->closed_nodes++;
2586 }
2587
2588 ngx_destroy_pool(pool);
2589 goto rst_stream;
2563 } 2590 }
2564 2591
2565 if (node->parent) { 2592 if (node->parent) {
2566 ngx_queue_remove(&node->reuse); 2593 ngx_queue_remove(&node->reuse);
2567 h2c->closed_nodes--; 2594 h2c->closed_nodes--;
2568 } 2595 }
2569 2596
2570 stream = ngx_http_v2_create_stream(h2c, 1); 2597 stream->pool = pool;
2571 if (stream == NULL) {
2572 return NULL;
2573 }
2574
2575 stream->pool = ngx_create_pool(1024, h2c->connection->log);
2576 if (stream->pool == NULL) {
2577 return NULL;
2578 }
2579 2598
2580 r = stream->request; 2599 r = stream->request;
2581 fc = r->connection; 2600 fc = r->connection;
2582 2601
2583 stream->in_closed = 1; 2602 stream->in_closed = 1;
2606 #endif 2625 #endif
2607 { 2626 {
2608 r->schema_end = r->schema_start + 4; 2627 r->schema_end = r->schema_start + 4;
2609 } 2628 }
2610 2629
2611 value.data = ngx_pstrdup(stream->pool, path); 2630 value.data = ngx_pstrdup(pool, path);
2612 if (value.data == NULL) { 2631 if (value.data == NULL) {
2613 return NULL; 2632 goto close;
2614 } 2633 }
2615 2634
2616 value.len = path->len; 2635 value.len = path->len;
2617 2636
2618 rc = ngx_http_v2_parse_path(r, &value); 2637 rc = ngx_http_v2_parse_path(r, &value);
2629 continue; 2648 continue;
2630 } 2649 }
2631 2650
2632 value.len = (*h)->value.len; 2651 value.len = (*h)->value.len;
2633 2652
2634 value.data = ngx_pnalloc(stream->pool, value.len + 1); 2653 value.data = ngx_pnalloc(pool, value.len + 1);
2635 if (value.data == NULL) { 2654 if (value.data == NULL) {
2636 return NULL; 2655 goto close;
2637 } 2656 }
2638 2657
2639 ngx_memcpy(value.data, (*h)->value.data, value.len); 2658 ngx_memcpy(value.data, (*h)->value.data, value.len);
2640 value.data[value.len] = '\0'; 2659 value.data[value.len] = '\0';
2641 2660
2661 if (rc == NGX_DECLINED) { 2680 if (rc == NGX_DECLINED) {
2662 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); 2681 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
2663 return NULL; 2682 return NULL;
2664 } 2683 }
2665 2684
2666 (void) ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); 2685 close:
2686
2687 ngx_http_v2_close_stream(stream, NGX_HTTP_INTERNAL_SERVER_ERROR);
2688
2689 return NULL;
2690
2691 rst_stream:
2692
2693 if (ngx_http_v2_send_rst_stream(h2c, h2c->last_push,
2694 NGX_HTTP_INTERNAL_SERVER_ERROR)
2695 != NGX_OK)
2696 {
2697 h2c->connection->error = 1;
2698 }
2667 2699
2668 return NULL; 2700 return NULL;
2669 } 2701 }
2670 2702
2671 2703