Klaus Demo nginx / f2393f8
HTTP/2: fix flow control with padded DATA frames. Previously, flow control didn't account for padding in DATA frames, which meant that its view of the world could drift from peer's view by up to 256 bytes per received padded DATA frame, which could lead to a deadlock. Signed-off-by: Piotr Sikora <piotrsikora@google.com> Piotr Sikora 3 years ago
1 changed file(s) with 13 addition(s) and 11 deletion(s). Raw diff Collapse all Expand all
782782 static u_char *
783783 ngx_http_v2_state_data(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end)
784784 {
785 size_t size;
785786 ngx_http_v2_node_t *node;
786787 ngx_http_v2_stream_t *stream;
788
789 size = h2c->state.length;
787790
788791 if (h2c->state.flags & NGX_HTTP_V2_PADDED_FLAG) {
789792
801804 }
802805
803806 h2c->state.padding = *pos++;
804 h2c->state.length--;
805
806 if (h2c->state.padding > h2c->state.length) {
807
808 if (h2c->state.padding >= size) {
807809 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
808810 "client sent padded DATA frame "
809811 "with incorrect length: %uz, padding: %uz",
810 h2c->state.length, h2c->state.padding);
812 size, h2c->state.padding);
811813
812814 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
813815 }
814816
815 h2c->state.length -= h2c->state.padding;
817 h2c->state.length -= 1 + h2c->state.padding;
816818 }
817819
818820 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
819821 "http2 DATA frame");
820822
821 if (h2c->state.length > h2c->recv_window) {
823 if (size > h2c->recv_window) {
822824 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
823825 "client violated connection flow control: "
824826 "received DATA frame length %uz, available window %uz",
825 h2c->state.length, h2c->recv_window);
827 size, h2c->recv_window);
826828
827829 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_FLOW_CTRL_ERROR);
828830 }
829831
830 h2c->recv_window -= h2c->state.length;
832 h2c->recv_window -= size;
831833
832834 if (h2c->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4) {
833835
853855
854856 stream = node->stream;
855857
856 if (h2c->state.length > stream->recv_window) {
858 if (size > stream->recv_window) {
857859 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
858860 "client violated flow control for stream %ui: "
859861 "received DATA frame length %uz, available window %uz",
860 node->id, h2c->state.length, stream->recv_window);
862 node->id, size, stream->recv_window);
861863
862864 if (ngx_http_v2_terminate_stream(h2c, stream,
863865 NGX_HTTP_V2_FLOW_CTRL_ERROR)
870872 return ngx_http_v2_state_skip_padded(h2c, pos, end);
871873 }
872874
873 stream->recv_window -= h2c->state.length;
875 stream->recv_window -= size;
874876
875877 if (stream->no_flow_control
876878 && stream->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4)