[PATCH] gRPC: fixed bug when padding is used in DATA frame

Maxim Dounin mdounin at mdounin.ru
Tue Mar 16 23:45:13 UTC 2021


Hello!

On Tue, Mar 16, 2021 at 10:04:27PM +0300, geniuss99 wrote:

>  src/http/modules/ngx_http_grpc_module.c |  16 +++++++++++++---
>  1 files changed, 13 insertions(+), 3 deletions(-)
> 
> 
> # HG changeset patch
> # User geniuss99 <geniuss.dev at gmail.com>
> # Date 1615921026 -10800
> #      Tue Mar 16 21:57:06 2021 +0300
> # Node ID 13552d5b785104f9d137d956a6cbef25ec09b345
> # Parent  ed1348e8e25381b3b1a2540289effcf7ccec6fd6
> gRPC: fixed bug when padding is used in DATA frame.
> 
> As per RFC 7540 DATA frame MAY contain padding if the PADDED flag is set
> in "Type" field (see clause 6.1).
> 
> When such frame is sent from an upstream which previously defined payload
> length via "Content-Length" header nginx fails with an error: "upstream sent
> response body larger than indicated content length".
> 
> This happens because padding is not taken into account while comparing expected
> and received payload length.

Thanks for reporting this, looks like a bug introduced by me in 
7680:39501ce97e29 (nginx 1.19.1).

Do you have any particular servers/gRPC libraries in mind which 
actually use padding on DATA frames, and so nginx cannot talk with 
them after introduction of the check in question?

> 
> diff -r ed1348e8e253 -r 13552d5b7851 src/http/modules/ngx_http_grpc_module.c
> --- a/src/http/modules/ngx_http_grpc_module.c	Thu Mar 11 20:49:39 2021 +0300
> +++ b/src/http/modules/ngx_http_grpc_module.c	Tue Mar 16 21:57:06 2021 +0300
> @@ -2075,14 +2075,24 @@
>                  }
>  
>                  if (ctx->length != -1) {
> -                    if ((off_t) ctx->rest > ctx->length) {
> +                    if (ctx->flags & NGX_HTTP_V2_PADDED_FLAG) {
> +                        if (b->pos < b->last) {
> +                            u_char pad_length = *b->pos;
> +                            size_t payload_data_length = ctx->rest - pad_length - 1; // frame_payload_size_bytes - pad_length_bytes - pad_length_field_1_byte
> +
> +                            ctx->length -= payload_data_length;
> +                        }
> +
> +                    } else {
> +                        ctx->length -= ctx->rest;
> +                    }
> +
> +                    if (ctx->length < 0) {
>                          ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
>                                        "upstream sent response body larger "
>                                        "than indicated content length");
>                          return NGX_ERROR;
>                      }
> -
> -                    ctx->length -= ctx->rest;
>                  }
>  
>                  if (ctx->rest > ctx->recv_window) {

The fix looks suboptimal.  Rather, the check should be moved to 
the end of the function, where padding is already handled.  I'll 
take a look how to fix this properly.

(Note well that as per nginx style, local variables are defined at 
the start of the function, "//" comments are not used, and maximum 
line length is 80 characters.  The "Contributing Changes" 
article[1] have additional hints and links to appropriate part of 
the development guide with the details.)

[1] http://nginx.org/en/docs/contributing_changes.html

-- 
Maxim Dounin
http://mdounin.ru/


More information about the nginx-devel mailing list