[PATCH] gRPC: fixed bug when padding is used in DATA frame
Sergey Kandaurov
pluknet at nginx.com
Tue Mar 23 12:25:48 UTC 2021
> On 18 Mar 2021, at 03:55, Maxim Dounin <mdounin at mdounin.ru> wrote:
>
> Hello!
>
> On Wed, Mar 17, 2021 at 06:27:17PM +0300, geniuss99 wrote:
>
> [...]
>
>>> 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?
>>
>> I use gRPC module to pass normal http requests to h2 upstreams, not gRPC ones.
>> Works like a charm.
>>
>> So can't give you any gRPC servers for testing. You can observe the bug by
>> connecting to developers.google.com h2 server for example. They use padding
>> in DATA streams.
>
> Thanks for the example. Interesting, it only use padding when
> returning compressed responses, likely as an attempt to mitigate
> BREACH attacks (https://en.wikipedia.org/wiki/BREACH).
>
> The following patch seem to fix this properly. Review and testing
> appreciated.
>
> # HG changeset patch
> # User Maxim Dounin <mdounin at mdounin.ru>
> # Date 1616027280 -10800
> # Thu Mar 18 03:28:00 2021 +0300
> # Node ID f8dbaa4ae09de125420e5a325b2ccac4a5636494
> # Parent 0215ec9aaa8af6036c62e1db676c9b0cc1d5fca4
> gRPC: fixed handling of padding on DATA frames.
>
> The response size check introduced in 39501ce97e29 did not take into
> account possible padding on DATA frames, resulting in incorrect
> "upstream sent response body larger than indicated content length" errors
> if upstream server used padding in responses with known length.
>
> Fix is to check the actual size of response buffers produced by the code,
> similarly to how it is done in other protocols, instead of checking
> the size of DATA frames.
>
> Reported at:
> http://mailman.nginx.org/pipermail/nginx-devel/2021-March/013907.html
>
> diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c
> --- a/src/http/modules/ngx_http_grpc_module.c
> +++ b/src/http/modules/ngx_http_grpc_module.c
> @@ -2074,17 +2074,6 @@ ngx_http_grpc_filter(void *data, ssize_t
> return NGX_ERROR;
> }
>
> - if (ctx->length != -1) {
> - if ((off_t) ctx->rest > ctx->length) {
> - 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) {
> ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
> "upstream violated stream flow control, "
> @@ -2450,6 +2439,18 @@ ngx_http_grpc_filter(void *data, ssize_t
> b->pos = b->last;
> buf->last = b->pos;
>
> + if (ctx->length != -1) {
> +
> + if (buf->last - buf->pos > ctx->length) {
> + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
> + "upstream sent response body larger "
> + "than indicated content length");
> + return NGX_ERROR;
> + }
> +
> + ctx->length -= buf->last - buf->pos;
> + }
> +
> return NGX_AGAIN;
> }
>
> @@ -2457,6 +2458,18 @@ ngx_http_grpc_filter(void *data, ssize_t
> buf->last = b->pos;
> ctx->rest = ctx->padding;
>
> + if (ctx->length != -1) {
> +
> + if (buf->last - buf->pos > ctx->length) {
> + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
> + "upstream sent response body larger "
> + "than indicated content length");
> + return NGX_ERROR;
> + }
> +
> + ctx->length -= buf->last - buf->pos;
> + }
> +
> done:
>
> if (ctx->padding) {
>
Looks good.
--
Sergey Kandaurov
More information about the nginx-devel
mailing list