Re: [PATCH] Fixed 413 custom error page for HTTP/2 and HTTP/3 (ticket #2609)

2024-03-05 Thread Maxim Dounin
Hello!

On Mon, Mar 04, 2024 at 06:46:23PM +0400, Roman Arutyunyan wrote:

> # HG changeset patch
> # User Roman Arutyunyan 
> # Date 1709563405 -14400
> #  Mon Mar 04 18:43:25 2024 +0400
> # Node ID 3b0be477ab7246caba4c5152286b8be520ee0418
> # Parent  44da04c2d4db94ad4eefa84b299e07c5fa4a00b9
> Fixed 413 custom error page for HTTP/2 and HTTP/3 (ticket #2609).
> 
> Previously an attempt to return a custom 413 error page for these protocols
> resulted in the standard 413 page (if recursive_error_pages was off) or
> otherwise internal redirection cycle followed by the 500 error.
> 
> Discarding request body for HTTP/1 starts by setting r->discard_body which
> indicates the body is currently being discarded.  If and when the entire body
> is read and discarded, the flag is cleared and r->headers_in.content_length_n
> is set to zero.  Both r->discard_body and r->headers_in.content_length_n
> prevent nginx from re-generating 413 error after internal redirect in
> ngx_http_core_find_config_phase().
> 
> However the above does not work for HTTP/2 and HTTP/3.  Discarding request
> body for these protocols does not affect the above mentioned fields, which is
> why there's no protection against re-generating the 413 error.  The fix is to
> assign zero to r->headers_in.content_length_n much like in HTTP/1 case after
> the body is entirely read and discarded, except for these protocols no active
> discard is needed.
> 
> diff --git a/src/http/ngx_http_request_body.c 
> b/src/http/ngx_http_request_body.c
> --- a/src/http/ngx_http_request_body.c
> +++ b/src/http/ngx_http_request_body.c
> @@ -640,12 +640,14 @@ ngx_http_discard_request_body(ngx_http_r
>  #if (NGX_HTTP_V2)
>  if (r->stream) {
>  r->stream->skip_data = 1;
> +r->headers_in.content_length_n = 0;
>  return NGX_OK;
>  }
>  #endif
>  
>  #if (NGX_HTTP_V3)
>  if (r->http_version == NGX_HTTP_VERSION_30) {
> +r->headers_in.content_length_n = 0;
>  return NGX_OK;
>  }
>  #endif

The patch is wrong, see here:

https://trac.nginx.org/nginx/ticket/1152#comment:6 

The issue is in my TODO list.  Once properly fixed, you'll be able 
to merge the fix from freenginx.

Alternatively, consider submitting patches to 
the nginx-de...@freenginx.org list for proper review.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: announcing freenginx.org

2024-02-15 Thread Maxim Dounin
Hello!

On Thu, Feb 15, 2024 at 04:49:10PM +0800, Archimedes Gaviola wrote:

> On Thu, Feb 15, 2024 at 2:03 AM Maxim Dounin  wrote:
> 
> > Hello!
> >
> > As you probably know, F5 closed Moscow office in 2022, and I no
> > longer work for F5 since then.  Still, we’ve reached an agreement
> > that I will maintain my role in nginx development as a volunteer.
> > And for almost two years I was working on improving nginx and
> > making it better for everyone, for free.
> >
> > Unfortunately, some new non-technical management at F5 recently
> > decided that they know better how to run open source projects.  In
> > particular, they decided to interfere with security policy nginx
> > uses for years, ignoring both the policy and developers’ position.
> >
> > That’s quite understandable: they own the project, and can do
> > anything with it, including doing marketing-motivated actions,
> > ignoring developers position and community.  Still, this
> > contradicts our agreement.  And, more importantly, I no longer able
> > to control which changes are made in nginx within F5, and no longer
> > see nginx as a free and open source project developed and
> > maintained for the public good.
> >
> > As such, starting from today, I will no longer participate in nginx
> > development as run by F5.  Instead, I’m starting an alternative
> > project, which is going to be run by developers, and not corporate
> > entities:
> >
> > http://freenginx.org/
> >
> > The goal is to keep nginx development free from arbitrary corporate
> > actions.  Help and contributions are welcome.  Hope it will be
> > beneficial for everyone.
> >
> >
> > --
> > Maxim Dounin
> > http://freenginx.org/
> 
> Hi Maxim,
> 
> Sorry to hear that. Is the license still the same for freenginx?

Yes, the license will remain the same.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: announcing freenginx.org

2024-02-14 Thread Maxim Dounin
Hello!

On Thu, Feb 15, 2024 at 01:33:08AM +0300, Vasiliy Soshnikov wrote:

> Hello Maxim,
> Sad to read it. I can't promise that, but I will try to support your
> project by using freenginx at least.
> I wish good luck to freenginx!

Thanks, appreciated.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: announcing freenginx.org

2024-02-14 Thread Maxim Dounin
Hello!

On Wed, Feb 14, 2024 at 10:45:37PM +0100, Sergey Brester wrote:

> Hi Maxim,
> 
> it is pity to hear such news...
> 
> I have few comments and questions about, which I enclosed inline below...
> 
> Regards,
> Serg.
> 
> 14.02.2024 19:03, Maxim Dounin wrote:
> 
> > Hello!
> > 
> > As you probably know, F5 closed Moscow office in 2022, and I no
> > longer work for F5 since then. Still, we've reached an agreement
> > that I will maintain my role in nginx development as a volunteer.
> > And for almost two years I was working on improving nginx and
> > making it better for everyone, for free.
> 
> And you did a very good job!

Thanks.

> > Unfortunately, some new non-technical management at F5 recently
> > decided that they know better how to run open source projects. In
> > particular, they decided to interfere with security policy nginx
> > uses for years, ignoring both the policy and developers' position.
> 
> Can you explain a bit more about that (or provide some examples
> or a link to a public discussion about, if it exists)?

I've already provided some details here:

https://freenginx.org/pipermail/nginx/2024-February/07.html

: The most recent "security advisory" was released despite the fact 
: that the particular bug in the experimental HTTP/3 code is 
: expected to be fixed as a normal bug as per the existing security 
: policy, and all the developers, including me, agree on this.
:
: And, while the particular action isn't exactly very bad, the 
: approach in general is quite problematic.

There was no public discussion.  The only discussion I'm aware of 
happened on the security-alert@ list, and the consensus was that 
the bug should be fixed as a normal bug.  Still, I was reached 
several days ago with the information that some unnamed management 
requested an advisory and security release anyway, regardless of 
the policy and developers position.

> > That's quite understandable: they own the project, and can do
> > anything with it, including doing marketing-motivated actions,
> > ignoring developers position and community. Still, this
> > contradicts our agreement. And, more importantly, I no longer able
> > to control which changes are made in nginx within F5, and no longer
> > see nginx as a free and open source project developed and
> > maintained for the public good.
> 
> Do you speak only about you?.. Or are there also other developers which
> share your point of view? Just for the record...
> What is about R. Arutyunyan, V. Bartenev and others?
> Could one expect any statement from Igor (Sysoev) about the subject?

I speak only about me.  Others, if they are interested in, are 
welcome to join.

> > As such, starting from today, I will no longer participate in nginx
> > development as run by F5. Instead, I'm starting an alternative
> > project, which is going to be run by developers, and not corporate
> > entities:
> > 
> > http://freenginx.org/ [1]
> 
> Why yet another fork? I mean why just not "angie", for instance?

The "angie" fork shares the same problem as nginx run by F5: it's 
run by a for-profit corporate entity.  Even if it's good enough 
now, things might change unexpectedly, like it happened with F5.

> Additionally I'd like to ask whether the name "freenginx" is really well
> thought-out?
> I mean:
>   - it can be easy confused with free nginx (compared to nginx plus)
>   - the search for that will be horrible (if you would try to search for
> freenginx,
> even as exact (within quotes, with plus etc), many internet search
> engine
> would definitely include free nginx in the result.
>   - possibly copyright or trademark problems, etc

Apart from potential trademark concerns (which I believe do not 
apply here, but IANAL), these does not seem to be significant (and 
search results are already good enough).  Still, the name aligns 
well with project goals.

> > The goal is to keep nginx development free from arbitrary corporate
> > actions. Help and contributions are welcome. Hope it will be
> > beneficial for everyone.
> 
> Just as an idea: switch the primary dev to GH (github)... (and commonly from
> hg to git).
> I'm sure it would boost the development drastically, as well as bring many
> new
> developers and let grow the community.

While I understand the suggestion and potential benefits, I'm not 
a fun of git and github, and prefer Mercurial.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


announcing freenginx.org

2024-02-14 Thread Maxim Dounin
Hello!

As you probably know, F5 closed Moscow office in 2022, and I no
longer work for F5 since then.  Still, we’ve reached an agreement
that I will maintain my role in nginx development as a volunteer.
And for almost two years I was working on improving nginx and
making it better for everyone, for free.

Unfortunately, some new non-technical management at F5 recently
decided that they know better how to run open source projects.  In
particular, they decided to interfere with security policy nginx
uses for years, ignoring both the policy and developers’ position.

That’s quite understandable: they own the project, and can do
anything with it, including doing marketing-motivated actions,
ignoring developers position and community.  Still, this
contradicts our agreement.  And, more importantly, I no longer able
to control which changes are made in nginx within F5, and no longer
see nginx as a free and open source project developed and
maintained for the public good.

As such, starting from today, I will no longer participate in nginx
development as run by F5.  Instead, I’m starting an alternative
project, which is going to be run by developers, and not corporate
entities:

http://freenginx.org/

The goal is to keep nginx development free from arbitrary corporate
actions.  Help and contributions are welcome.  Hope it will be
beneficial for everyone.


-- 
Maxim Dounin
http://freenginx.org/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: Upstream response time populated even when upstream connection timed out.

2024-02-10 Thread Maxim Dounin
Hello!

On Fri, Feb 09, 2024 at 12:15:54PM +, Sambhav Gupta via nginx-devel wrote:

> I have noticed that upstream response time is populated to a 
> non-zero and non-negative value in Nginx even when upstream 
> connection times out.
> 
> This is not true with other values like upstream connect time 
> and upstream header time.
> 
> Is this intentional ?

Yes.  The $upstream_response_time variable shows total time spent 
when working with the upstream, with all the activities included.  
It is always set as long as nginx was working with an upstream, 
even if there was an error or a timeout.

In contrast, $upstream_connect_time and $upstream_header_time are 
only set when the connection was established or the header was 
successfully received, respectively.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: Segfault when interpreting cached X-Accel-Redirect response

2024-02-06 Thread Maxim Dounin
Hello!

On Tue, Feb 06, 2024 at 01:36:20PM +0100, Jan Prachař wrote:

> Hello,
> 
> I have one last note bellow.
> 
> On Tue, 2024-02-06 at 14:08 +0300, Maxim Dounin wrote:
> > Hello!
> > 
> > On Tue, Feb 06, 2024 at 11:42:40AM +0100, Jan Prachař wrote:
> > 
> > > Hello Maxim,
> > > 
> > > On Tue, 2024-02-06 at 00:46 +0300, Maxim Dounin wrote:
> > > > Hello!
> > > > 
> > > > On Mon, Feb 05, 2024 at 06:01:54PM +0100, Jan Prachař wrote:
> > > > 
> > > > > Hello,
> > > > > 
> > > > > thank you for your responses.
> > > > > 
> > > > > On Sat, 2024-02-03 at 04:25 +0300, Maxim Dounin wrote:
> > > > > > Hello!
> > > > > > 
> > > > > > On Fri, Feb 02, 2024 at 01:47:51PM +0100, Jan Prachař wrote:
> > > > > > 
> > > > > > > On Fri, 2024-02-02 at 12:48 +0100, Jiří Setnička via nginx-devel 
> > > > > > > wrote:
> > > > > > > > Hello,
> > > > > > > > 
> > > > > > > > Also, I believe that the core of the problem is because of the 
> > > > > > > > ngx_http_finalize_request(r, NGX_DONE); call in the 
> > > > > > > > ngx_http_upstream_process_headers function. This call is needed 
> > > > > > > > when 
> > > > > > > > doing an internal redirect after the real upstream request (to 
> > > > > > > > close the 
> > > > > > > > upstream request), but when serving from the cache, there is no 
> > > > > > > > upstream 
> > > > > > > > request to close and this call causes 
> > > > > > > > ngx_http_set_lingering_close to be 
> > > > > > > > called from the ngx_http_finalize_connection with no active 
> > > > > > > > request on 
> > > > > > > > the connection yielding to the segfault.
> > > > > > > 
> > > > > > > Hello,
> > > > > > > 
> > > > > > > I am Jiří's colleague, and so I have taken a closer look at the 
> > > > > > > problem. Another
> > > > > > > indication of the issue is the alert in the error log for 
> > > > > > > non-keepalive connections,
> > > > > > > stating "http request count is zero while closing request."
> > > > > > > 
> > > > > > > Upon reviewing the nginx source code, I discovered that the 
> > > > > > > function
> > > > > > > ngx_http_upstream_finalize_request(), when called with rc = 
> > > > > > > NGX_DECLINED, does not invoke
> > > > > > > ngx_http_finalize_request(). However, when there is nothing to 
> > > > > > > clean up (u->cleanup ==
> > > > > > > NULL), it does. Therefore, I believe the appropriate fix is to 
> > > > > > > follow the patch below.
> > > > > > > 
> > > > > > > Best, Jan Prachař
> > > > > > > 
> > > > > > > # User Jan Prachař 
> > > > > > > # Date 1706877176 -3600
> > > > > > > #  Fri Feb 02 13:32:56 2024 +0100
> > > > > > > # Node ID 851c994b48c48c9cd3d32b9aa402f4821aeb8bb2
> > > > > > > # Parent  cf3d537ec6706f8713a757df256f2cfccb8f9b01
> > > > > > > Upstream: Fix "request count is zero" when procesing 
> > > > > > > X-Accel-Redirect
> > > > > > > 
> > > > > > > ngx_http_upstream_finalize_request(r, u, NGX_DECLINED) should not 
> > > > > > > call
> > > > > > > ngx_http_finalize_request().
> > > > > > > 
> > > > > > > diff -r cf3d537ec670 -r 851c994b48c4 src/http/ngx_http_upstream.c
> > > > > > > --- a/src/http/ngx_http_upstream.c  Thu Nov 26 21:00:25 2020 
> > > > > > > +0100
> > > > > > > +++ b/src/http/ngx_http_upstream.c  Fri Feb 02 13:32:56 2024 
> > > > > > > +0100
> > > > > > > @@ -4340,6 +4340,11 @@
> > > > > > >  
> > > > > > >  if (u->cleanup == NULL) {
> > > > > > >  /* the request was already finalize

Re: Segfault when interpreting cached X-Accel-Redirect response

2024-02-06 Thread Maxim Dounin
Hello!

On Tue, Feb 06, 2024 at 11:42:40AM +0100, Jan Prachař wrote:

> Hello Maxim,
> 
> On Tue, 2024-02-06 at 00:46 +0300, Maxim Dounin wrote:
> > Hello!
> > 
> > On Mon, Feb 05, 2024 at 06:01:54PM +0100, Jan Prachař wrote:
> > 
> > > Hello,
> > > 
> > > thank you for your responses.
> > > 
> > > On Sat, 2024-02-03 at 04:25 +0300, Maxim Dounin wrote:
> > > > Hello!
> > > > 
> > > > On Fri, Feb 02, 2024 at 01:47:51PM +0100, Jan Prachař wrote:
> > > > 
> > > > > On Fri, 2024-02-02 at 12:48 +0100, Jiří Setnička via nginx-devel 
> > > > > wrote:
> > > > > > Hello,
> > > > > > 
> > > > > > Also, I believe that the core of the problem is because of the 
> > > > > > ngx_http_finalize_request(r, NGX_DONE); call in the 
> > > > > > ngx_http_upstream_process_headers function. This call is needed 
> > > > > > when 
> > > > > > doing an internal redirect after the real upstream request (to 
> > > > > > close the 
> > > > > > upstream request), but when serving from the cache, there is no 
> > > > > > upstream 
> > > > > > request to close and this call causes ngx_http_set_lingering_close 
> > > > > > to be 
> > > > > > called from the ngx_http_finalize_connection with no active request 
> > > > > > on 
> > > > > > the connection yielding to the segfault.
> > > > > 
> > > > > Hello,
> > > > > 
> > > > > I am Jiří's colleague, and so I have taken a closer look at the 
> > > > > problem. Another
> > > > > indication of the issue is the alert in the error log for 
> > > > > non-keepalive connections,
> > > > > stating "http request count is zero while closing request."
> > > > > 
> > > > > Upon reviewing the nginx source code, I discovered that the function
> > > > > ngx_http_upstream_finalize_request(), when called with rc = 
> > > > > NGX_DECLINED, does not invoke
> > > > > ngx_http_finalize_request(). However, when there is nothing to clean 
> > > > > up (u->cleanup ==
> > > > > NULL), it does. Therefore, I believe the appropriate fix is to follow 
> > > > > the patch below.
> > > > > 
> > > > > Best, Jan Prachař
> > > > > 
> > > > > # User Jan Prachař 
> > > > > # Date 1706877176 -3600
> > > > > #  Fri Feb 02 13:32:56 2024 +0100
> > > > > # Node ID 851c994b48c48c9cd3d32b9aa402f4821aeb8bb2
> > > > > # Parent  cf3d537ec6706f8713a757df256f2cfccb8f9b01
> > > > > Upstream: Fix "request count is zero" when procesing X-Accel-Redirect
> > > > > 
> > > > > ngx_http_upstream_finalize_request(r, u, NGX_DECLINED) should not call
> > > > > ngx_http_finalize_request().
> > > > > 
> > > > > diff -r cf3d537ec670 -r 851c994b48c4 src/http/ngx_http_upstream.c
> > > > > --- a/src/http/ngx_http_upstream.c  Thu Nov 26 21:00:25 2020 +0100
> > > > > +++ b/src/http/ngx_http_upstream.c  Fri Feb 02 13:32:56 2024 +0100
> > > > > @@ -4340,6 +4340,11 @@
> > > > >  
> > > > >  if (u->cleanup == NULL) {
> > > > >  /* the request was already finalized */
> > > > > +
> > > > > +if (rc == NGX_DECLINED) {
> > > > > +return;
> > > > > +}
> > > > > +
> > > > >  ngx_http_finalize_request(r, NGX_DONE);
> > > > >  return;
> > > > >  }
> > > > 
> > > > I somewhat agree: the approach suggested by Jiří certainly looks 
> > > > incorrect. The ngx_http_upstream_cache_send() function, which 
> > > > calls ngx_http_upstream_process_headers() with r->cached set, can 
> > > > be used in two contexts: before the cleanup handler is installed 
> > > > (i.e., when sending a cached response during upstream request 
> > > > initialization) and after it is installed (i.e., when sending a 
> > > > stale cached response on upstream errors).  In the latter case 
> > > > skipping finalization would mean a socket leak.
> > > > 
> > > > Still, checking for NGX_DECLINED explic

Re: Segfault when interpreting cached X-Accel-Redirect response

2024-02-05 Thread Maxim Dounin
Hello!

On Mon, Feb 05, 2024 at 06:01:54PM +0100, Jan Prachař wrote:

> Hello,
> 
> thank you for your responses.
> 
> On Sat, 2024-02-03 at 04:25 +0300, Maxim Dounin wrote:
> > Hello!
> > 
> > On Fri, Feb 02, 2024 at 01:47:51PM +0100, Jan Prachař wrote:
> > 
> > > On Fri, 2024-02-02 at 12:48 +0100, Jiří Setnička via nginx-devel wrote:
> > > > Hello,
> > > > 
> > > > Also, I believe that the core of the problem is because of the 
> > > > ngx_http_finalize_request(r, NGX_DONE); call in the 
> > > > ngx_http_upstream_process_headers function. This call is needed when 
> > > > doing an internal redirect after the real upstream request (to close 
> > > > the 
> > > > upstream request), but when serving from the cache, there is no 
> > > > upstream 
> > > > request to close and this call causes ngx_http_set_lingering_close to 
> > > > be 
> > > > called from the ngx_http_finalize_connection with no active request on 
> > > > the connection yielding to the segfault.
> > > 
> > > Hello,
> > > 
> > > I am Jiří's colleague, and so I have taken a closer look at the problem. 
> > > Another
> > > indication of the issue is the alert in the error log for non-keepalive 
> > > connections,
> > > stating "http request count is zero while closing request."
> > > 
> > > Upon reviewing the nginx source code, I discovered that the function
> > > ngx_http_upstream_finalize_request(), when called with rc = NGX_DECLINED, 
> > > does not invoke
> > > ngx_http_finalize_request(). However, when there is nothing to clean up 
> > > (u->cleanup ==
> > > NULL), it does. Therefore, I believe the appropriate fix is to follow the 
> > > patch below.
> > > 
> > > Best, Jan Prachař
> > > 
> > > # User Jan Prachař 
> > > # Date 1706877176 -3600
> > > #  Fri Feb 02 13:32:56 2024 +0100
> > > # Node ID 851c994b48c48c9cd3d32b9aa402f4821aeb8bb2
> > > # Parent  cf3d537ec6706f8713a757df256f2cfccb8f9b01
> > > Upstream: Fix "request count is zero" when procesing X-Accel-Redirect
> > > 
> > > ngx_http_upstream_finalize_request(r, u, NGX_DECLINED) should not call
> > > ngx_http_finalize_request().
> > > 
> > > diff -r cf3d537ec670 -r 851c994b48c4 src/http/ngx_http_upstream.c
> > > --- a/src/http/ngx_http_upstream.c  Thu Nov 26 21:00:25 2020 +0100
> > > +++ b/src/http/ngx_http_upstream.c  Fri Feb 02 13:32:56 2024 +0100
> > > @@ -4340,6 +4340,11 @@
> > >  
> > >  if (u->cleanup == NULL) {
> > >  /* the request was already finalized */
> > > +
> > > +if (rc == NGX_DECLINED) {
> > > +return;
> > > +}
> > > +
> > >  ngx_http_finalize_request(r, NGX_DONE);
> > >  return;
> > >  }
> > 
> > I somewhat agree: the approach suggested by Jiří certainly looks 
> > incorrect. The ngx_http_upstream_cache_send() function, which 
> > calls ngx_http_upstream_process_headers() with r->cached set, can 
> > be used in two contexts: before the cleanup handler is installed 
> > (i.e., when sending a cached response during upstream request 
> > initialization) and after it is installed (i.e., when sending a 
> > stale cached response on upstream errors).  In the latter case 
> > skipping finalization would mean a socket leak.
> > 
> > Still, checking for NGX_DECLINED explicitly also looks wrong, for 
> > a number of reasons.
> > 
> > First, the specific code path isn't just for "nothing to clean 
> > up", it's for the very specific case when the request was already 
> > finalized due to filter finalization, see 5994:5abf5af257a7.  This 
> > code path is not expected to be triggered when the cleanup handler 
> > isn't installed yet - before the cleanup handler is installed, 
> > upstream code is expected to call ngx_http_finalize_request() 
> > directly instead.  And it would be semantically wrong to check for 
> > NGX_DECLINED: if it's here, it means something already gone wrong.
> > 
> > I think the generic issue here is that 
> > ngx_http_upstream_process_headers(), which is normally used for 
> > upstream responses and calls ngx_http_upstream_finalize_request(), 
> > is also used for cached responses.  Still, it assumes it is used 
> > for an upstream response, and calls 
> > ngx_http_upstream_finalize_reques

Re: Segfault when interpreting cached X-Accel-Redirect response

2024-02-02 Thread Maxim Dounin
ERROR in other places to trigger 
appropriate error handling instead of calling 
ngx_http_upstream_finalize_request() directly (this no longer 
tries to return 500 Internal Server Error response though, as 
doing so might be unsafe after copying some of the cached headers 
to the response).

Please take a look if it works for you.

diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -588,10 +588,6 @@ ngx_http_upstream_init_request(ngx_http_
 if (rc == NGX_OK) {
 rc = ngx_http_upstream_cache_send(r, u);
 
-if (rc == NGX_DONE) {
-return;
-}
-
 if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) {
 rc = NGX_DECLINED;
 r->cached = 0;
@@ -1088,7 +1084,7 @@ ngx_http_upstream_cache_send(ngx_http_re
 if (rc == NGX_OK) {
 
 if (ngx_http_upstream_process_headers(r, u) != NGX_OK) {
-return NGX_DONE;
+return NGX_ERROR;
 }
 
 return ngx_http_cache_send(r);
@@ -2516,7 +2512,14 @@ ngx_http_upstream_process_header(ngx_htt
 }
 }
 
-if (ngx_http_upstream_process_headers(r, u) != NGX_OK) {
+rc = ngx_http_upstream_process_headers(r, u);
+
+if (rc == NGX_DONE) {
+return;
+}
+
+if (rc == NGX_ERROR) {
+ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
 return;
 }
 
@@ -2576,10 +2579,6 @@ ngx_http_upstream_test_next(ngx_http_req
 u->cache_status = NGX_HTTP_CACHE_STALE;
 rc = ngx_http_upstream_cache_send(r, u);
 
-if (rc == NGX_DONE) {
-return NGX_OK;
-}
-
 if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) {
 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
 }
@@ -2621,10 +2620,6 @@ ngx_http_upstream_test_next(ngx_http_req
 u->cache_status = NGX_HTTP_CACHE_REVALIDATED;
 rc = ngx_http_upstream_cache_send(r, u);
 
-if (rc == NGX_DONE) {
-return NGX_OK;
-}
-
 if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) {
 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
 }
@@ -2827,7 +2822,8 @@ ngx_http_upstream_process_headers(ngx_ht
 }
 
 if (u->headers_in.x_accel_redirect
-&& !(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT))
+&& !(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT)
+&& !r->cached)
 {
 ngx_http_upstream_finalize_request(r, u, NGX_DECLINED);
 
@@ -2918,18 +2914,14 @@ ngx_http_upstream_process_headers(ngx_ht
 
 if (hh) {
 if (hh->copy_handler(r, [i], hh->conf) != NGX_OK) {
-ngx_http_upstream_finalize_request(r, u,
-   NGX_HTTP_INTERNAL_SERVER_ERROR);
-return NGX_DONE;
+return NGX_ERROR;
 }
 
 continue;
 }
 
 if (ngx_http_upstream_copy_header_line(r, [i], 0) != NGX_OK) {
-ngx_http_upstream_finalize_request(r, u,
-   NGX_HTTP_INTERNAL_SERVER_ERROR);
-return NGX_DONE;
+return NGX_ERROR;
 }
 }
 
@@ -4442,10 +4434,6 @@ ngx_http_upstream_next(ngx_http_request_
     u->cache_status = NGX_HTTP_CACHE_STALE;
 rc = ngx_http_upstream_cache_send(r, u);
 
-if (rc == NGX_DONE) {
-return;
-}
-
 if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) {
 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
 }

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] SSL: fixed $ssl_curves allocation error handling

2024-01-29 Thread Maxim Dounin
Hello!

On Fri, Jan 26, 2024 at 02:36:29PM +0400, Sergey Kandaurov wrote:

> # HG changeset patch
> # User Sergey Kandaurov 
> # Date 1706265240 -14400
> #  Fri Jan 26 14:34:00 2024 +0400
> # Node ID 2f70dd17c16461f833eafec2dcf9193557bfb176
> # Parent  ee40e2b1d0833b46128a357fbc84c6e23be9be07
> SSL: fixed $ssl_curves allocation error handling.
> 
> diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
> --- a/src/event/ngx_event_openssl.c
> +++ b/src/event/ngx_event_openssl.c
> @@ -5187,6 +5187,9 @@ ngx_ssl_get_curves(ngx_connection_t *c, 
>  }
>  
>  curves = ngx_palloc(pool, n * sizeof(int));
> +if (curves == NULL) {
> +return NGX_ERROR;
> +}
>  
>  n = SSL_get1_curves(c->ssl->connection, curves);
>  len = 0;

Looks good.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH 2 of 4] Upstream: fixed usage of closed sockets with filter finalization

2024-01-29 Thread Maxim Dounin
Hello!

On Mon, Jan 29, 2024 at 05:21:43PM +0400, Sergey Kandaurov wrote:

> 
> > On 29 Jan 2024, at 10:43, Maxim Dounin  wrote:
> > 
> > Hello!
> > 
> > On Fri, Jan 26, 2024 at 04:26:00PM +0400, Sergey Kandaurov wrote:
> > 
> >>> On 27 Nov 2023, at 06:50, Maxim Dounin  wrote:
> >>> 
> >>> # HG changeset patch
> >>> # User Maxim Dounin 
> >>> # Date 1701049758 -10800
> >>> #  Mon Nov 27 04:49:18 2023 +0300
> >>> # Node ID faf0b9defc76b8683af466f8a950c2c241382970
> >>> # Parent  a5e39e9d1f4c84dcbe6a2f9e079372a3d63aef0b
> >>> Upstream: fixed usage of closed sockets with filter finalization.
> >>> 
> >>> When filter finalization is triggered when working with an upstream 
> >>> server,
> >>> and error_page redirects request processing to some simple handler,
> >>> ngx_http_request_finalize() triggers request termination when the response
> >>> is sent.  In particular, via the upstream cleanup handler, nginx will 
> >>> close
> >>> the upstream connection and the corresponding socket.
> >>> 
> >>> Still, this can happen to be with ngx_event_pipe() on stack.  While
> >>> the code will set p->downstream_error due to NGX_ERROR returned from the
> >>> output filter chain by filter finalization, otherwise the error will be
> >>> ignored till control returns to ngx_http_upstream_process_request().
> >>> And event pipe might try reading from the (already closed) socket, 
> >>> resulting
> >>> in "readv() failed (9: Bad file descriptor) while reading upstream" errors
> >>> (or even segfaults with SSL).
> >>> 
> >>> Such errors were seen with the following configuration:
> >>> 
> >>>   location /t2 {
> >>>   proxy_pass http://127.0.0.1:8080/big;
> >>> 
> >>>   image_filter_buffer 10m;
> >>>   image_filter   resize  150 100;
> >>>   error_page 415   = /empty;
> >>>   }
> >>> 
> >>>   location /empty {
> >>>   return 204;
> >>>   }
> >>> 
> >>>   location /big {
> >>>   # big enough static file
> >>>   }
> >>> 
> >>> Fix is to set p->upstream_error in ngx_http_upstream_finalize_request(),
> >>> so the existing checks in ngx_event_pipe_read_upstream() will prevent
> >>> further reading from the closed upstream connection.
> >>> 
> >>> Similarly, p->upstream_error is now checked when handling events at
> >>> ngx_event_pipe() exit, as checking p->upstream->fd is not enough if
> >>> keepalive upstream connections are being used and the connection was
> >>> saved to cache during request termination.
> >>> 
> >> 
> >> Setting p->upstream_error in ngx_http_upstream_finalize_request()
> >> may look suspicious, because it is used to be set on connection errors
> >> such as upstream timeout or recv error, or, as a recently introduced
> >> exception in the fastcgi module, - also when the FastCGI record ends
> >> prematurely, before receiving all the expected content.
> >> But technically I think this is quite correct, because we no longer
> >> want to receive further data, and also (and you mention this in the
> >> commit log) this repeats closing an upstream connection socket in
> >> the same place in ngx_http_upstream_finalize_request().
> >> So I think it should be fine.
> > 
> > The biggest concern I personally see here is with the added 
> > p->upstream_error check at ngx_event_pipe() exit.  If there is a 
> > real upstream error, such as when the connection is reset by the 
> > upstream server, and if we want the pipe to be active for some 
> > time (for example, if we want it to continue writing to the 
> > downstream connection), there will be no ngx_handle_read_event() 
> > call.  For level-triggered event methods this means that the read 
> > event for the upstream connection will be generated again and 
> > again.
> > 
> > This shouldn't be the problem for existing ngx_event_pipe() uses 
> > though, as p->upstream_error is anyway triggers 
> > ngx_http_upstream_finalize_request().
> > 
> > Still, we can consider introducing a separate flag, such as 
> > p->upstream_closed, or clearing p->upstream, and checking these in 
> > ngx_event_pipe() instead.  This probably 

Re: [PATCH 1 of 4] Fixed request termination with AIO and subrequests (ticket #2555)

2024-01-29 Thread Maxim Dounin
Hello!

On Mon, Jan 29, 2024 at 06:07:58PM +0400, Roman Arutyunyan wrote:

> Hi,
> 
> On Mon, Jan 29, 2024 at 10:58:09AM +0300, Maxim Dounin wrote:
> > Hello!
> > 
> > On Fri, Jan 26, 2024 at 04:02:30PM +0400, Roman Arutyunyan wrote:
> > 
> > > On Mon, Nov 27, 2023 at 05:50:24AM +0300, Maxim Dounin wrote:
> > > > # HG changeset patch
> > > > # User Maxim Dounin 
> > > > # Date 1701049682 -10800
> > > > #  Mon Nov 27 04:48:02 2023 +0300
> > > > # Node ID a5e39e9d1f4c84dcbe6a2f9e079372a3d63aef0b
> > > > # Parent  f366007dd23a6ce8e8427c1b3042781b618a2ade
> > > > Fixed request termination with AIO and subrequests (ticket #2555).
> > > > 
> > > > When a request was terminated due to an error via 
> > > > ngx_http_terminate_request()
> > > > while an AIO operation was running in a subrequest, various issues were
> > > > observed.  This happened because ngx_http_request_finalizer() was only 
> > > > set
> > > > in the subrequest where ngx_http_terminate_request() was called, but not
> > > > in the subrequest where the AIO operation was running.  After completion
> > > > of the AIO operation resumed normal processing of the subrequest, 
> > > > leading
> > > > to issues.
> > > 
> > > Something is wrong with the last sentence.
> > 
> > Thanks, rewritten as:
> > 
> > ... After completion
> > of the AIO operation normal processing of the subrequest was resumed, 
> > leading
> > to issues.
> > 
> > > > In particular, in case of the upstream module, termination of the 
> > > > request
> > > > called upstream cleanup, which closed the upstream connection.  
> > > > Attempts to
> > > > further work with the upstream connection after AIO operation completion
> > > > resulted in segfaults in ngx_ssl_recv(), "readv() failed (9: Bad file
> > > > descriptor) while reading upstream" errors, or socket leaks.
> > > 
> > > Can you elaborate on socket leaks?
> > 
> > For example, consider a request which is waiting for additional 
> > data from the upstream, so the only timer is the read timer for 
> > the upstream connection, and which is terminated because the 
> > client closed the connection.  Request termination will remove the 
> > only timer.  Still, the client connection is not yet closed by 
> > nginx.  So as long as the request is not actually freed following 
> > completion of the AIO operation, this is a socket leak: we have no 
> > timers left, and no further events expected.  And this can easily 
> > happen if neither segfault nor readv() error was triggered (for 
> > example, if p->upstream->read->ready was not set during AIO 
> > operation completion).
> > 
> > > > In ticket #2555, issues were observed with the following configuration
> > > > with cache background update (with thread writing instrumented to
> > > > introduce a delay, when a client closes the connection during an 
> > > > update):
> > > > 
> > > > location = /background-and-aio-write {
> > > > proxy_pass ...
> > > > proxy_cache one;
> > > > proxy_cache_valid 200 1s;
> > > > proxy_cache_background_update on;
> > > > proxy_cache_use_stale updating;
> > > > aio threads;
> > > > aio_write on;
> > > > limit_rate 1000;
> > > > }
> > > > 
> > > > Similarly, the same issue can be seen with SSI, and can be caused by
> > > > errors in subrequests, such as in the following configuration
> > > > (were "/proxy" uses AIO, and "/sleep" returns 444 after some delay,
> > > 
> > > s/were/where/ ?
> > 
> > Fixed, thanks.
> > 
> > > > causing request termination):
> > > > 
> > > > location = /ssi-active-boom {
> > > > ssi on;
> > > > ssi_types *;
> > > > return 200 '
> > > >
> > > >
> > > >';
> > > > limit_rate 1000;
> > > > }
> > > > 
> > > > Or the same with both AIO operation and the error in non-active 
> > > > subrequests
> > > > (which needs slightly different handling, see below):
> > > > 
> > &g

Re: nginx-tests SSL tests failing out of the box?

2024-01-29 Thread Maxim Dounin
Hello!

On Mon, Jan 29, 2024 at 05:23:15PM +0400, Sergey Kandaurov wrote:

> > On 29 Jan 2024, at 07:24, Maxim Dounin  wrote:
> > 
> > Hello!
> > 
> > On Sat, Jan 27, 2024 at 07:19:45AM +0300, Maxim Dounin wrote:
> > 
> >> Hello!
> >> 
> >> On Fri, Jan 26, 2024 at 09:29:58PM +0400, Sergey Kandaurov wrote:
> >> 
> >>> On Thu, Jan 25, 2024 at 11:38:57PM +0300, Maxim Dounin wrote:
> >>>> Hello!
> >>>> 
> >>>> On Thu, Jan 25, 2024 at 06:59:36PM +, Mayerhofer, Austin via 
> >>>> nginx-devel wrote:
> >>>> 
> >>>>> Hi all,
> >>>>> 
> >>>>> I have not made any changes to NGINX. Vanilla NGINX (./configure with 
> >>>>> no flags) passes all tests that run, but when compiling with SSL, not 
> >>>>> all SSL tests are passing. Is this expected, or do I need to configure 
> >>>>> nginx further aside from adding the --with-http_ssl_module flag? Do 
> >>>>> each of the failing tests below require separate fixes, or is there a 
> >>>>> one-size-fits-all solution for all of them?
> >>>>> 
> >>>>> OS: MacOS 12.6.3
> >>>>> Chip: Apple M1 Max
> >>>>> NGINX: 1.24.0 built from source code with ./configure --with-debug 
> >>>>> --with-http_ssl_module
> >>>>> Nginx-tests: 
> >>>>> https://github.com/nginx/nginx-tests/tree/4c2ad8093952706f327d04887c5546bad91b75a6
> >>>>> OpenSSL: 3.2.0 (/opt/homebrew/bin/openssl)
> >>>>> Perl: 5.30.3 (/usr/bin/perl)
> >>>>> 
> >>>>> When I run
> >>>>> 
> >>>>> ```
> >>>>> TEST_NGINX_BINARY=/usr/local/nginx/sbin/nginx prove -v ssl.t
> >>>>> ```
> >>>>> 
> >>>>> I see
> >>>>> 
> >>>>> ```
> >>>>> not ok 2 - session reused
> >>>>> 
> >>>>> #   Failed test 'session reused'
> >>>>> #   at ssl.t line 187.
> >>>>> #   'HTTP/1.1 200 OK
> >>>>> # Server: nginx/1.24.0
> >>>>> # Date: Thu, 25 Jan 2024 18:50:10 GMT
> >>>>> # Content-Type: text/plain
> >>>>> # Content-Length: 6
> >>>>> # Connection: close
> >>>>> #
> >>>>> # body .'
> >>>>> # doesn't match '(?^m:^body r$)'
> >>>>> ```
> >>>> 
> >>>> [...]
> >>>> 
> >>>> It looks like SSL session reuse is broken in Perl you are 
> >>>> using.  This might be the case if, for example, Net::SSLeay in 
> >>>> your installation was compiled with system LibreSSL as an SSL 
> >>>> library - at least on the server side LibreSSL simply does not 
> >>>> support session reuse with TLSv1.3.
> >>>> 
> >>>> Test suite checks if nginx was compiled with LibreSSL and marks 
> >>>> appropriate tests as TODO, but if the Perl module is broken 
> >>>> instead, the test will fail.
> >>>> 
> >>> 
> >>> Well, technically, we could test this and skip appropriately:
> >>> 
> >>> diff --git a/ssl_session_reuse.t b/ssl_session_reuse.t
> >>> --- a/ssl_session_reuse.t
> >>> +++ b/ssl_session_reuse.t
> >>> @@ -166,7 +166,9 @@ local $TODO = 'no TLSv1.3 sessions, old 
> >>> local $TODO = 'no TLSv1.3 sessions, old IO::Socket::SSL'
> >>> if $IO::Socket::SSL::VERSION < 2.061 && test_tls13();
> >>> local $TODO = 'no TLSv1.3 sessions in LibreSSL'
> >>> - if $t->has_module('LibreSSL') && test_tls13();
> >>> + if ($t->has_module('LibreSSL')
> >>> + || Net::SSLeay::constant("LIBRESSL_VERSION_NUMBER"))
> >>> + && test_tls13();
> >>> 
> >>> is(test_reuse(8443), 1, 'tickets reused');
> >>> is(test_reuse(8444), 1, 'tickets and cache reused');
> >>> 
> >>> But I see little to no purpose: if the testing tool is broken
> >>> in various unexpected ways (another example is X509_V_ERR_INVALID_PURPOSE
> >>> in peer certificate verification as reported in the adjacent thread),
> >>> I think we barely can handle this in general.
> >> 
> >> I generally agree.
> >> 
> >> Stil

Re: Nginx-tests stream_ssl_conf_command.t test hanging indefinitely

2024-01-29 Thread Maxim Dounin
Hello!

On Fri, Jan 26, 2024 at 01:14:56AM +, Mayerhofer, Austin via nginx-devel 
wrote:

> Hey Maxim,
> 
> Thanks, I installed homebrew’s Perl and all these tests are 
> passing now, woohoo!
> 
> However a few others are failing now including ssl_ocsp.t and 
> ssl_verify_depth.t, failing 13/17 and 3/11 tests respectively 
> with the same error:
> 
> ```
> #   Failed test 'verify depth 2 - end'
> #   at ssl_verify_depth.t line 169.
> #   'HTTP/1.1 400 Bad Request
> # Server: nginx/1.24.0
> # Date: Fri, 26 Jan 2024 01:08:10 GMT
> # Content-Type: text/html
> # Content-Length: 215
> # Connection: close
> # X-Client: CN=end
> # X-Verify: FAILED:unsuitable certificate purpose

[...]

Should be fixed with this patch:

https://mailman.nginx.org/pipermail/nginx-devel/2024-January/TSFBB5DWWQKXKDTGVLSH5VWJYMRCMCV4.html

Thanks for reporting this.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH 1 of 4] Fixed request termination with AIO and subrequests (ticket #2555)

2024-01-28 Thread Maxim Dounin
Hello!

On Fri, Jan 26, 2024 at 04:02:30PM +0400, Roman Arutyunyan wrote:

> On Mon, Nov 27, 2023 at 05:50:24AM +0300, Maxim Dounin wrote:
> > # HG changeset patch
> > # User Maxim Dounin 
> > # Date 1701049682 -10800
> > #  Mon Nov 27 04:48:02 2023 +0300
> > # Node ID a5e39e9d1f4c84dcbe6a2f9e079372a3d63aef0b
> > # Parent  f366007dd23a6ce8e8427c1b3042781b618a2ade
> > Fixed request termination with AIO and subrequests (ticket #2555).
> > 
> > When a request was terminated due to an error via 
> > ngx_http_terminate_request()
> > while an AIO operation was running in a subrequest, various issues were
> > observed.  This happened because ngx_http_request_finalizer() was only set
> > in the subrequest where ngx_http_terminate_request() was called, but not
> > in the subrequest where the AIO operation was running.  After completion
> > of the AIO operation resumed normal processing of the subrequest, leading
> > to issues.
> 
> Something is wrong with the last sentence.

Thanks, rewritten as:

... After completion
of the AIO operation normal processing of the subrequest was resumed, leading
to issues.

> > In particular, in case of the upstream module, termination of the request
> > called upstream cleanup, which closed the upstream connection.  Attempts to
> > further work with the upstream connection after AIO operation completion
> > resulted in segfaults in ngx_ssl_recv(), "readv() failed (9: Bad file
> > descriptor) while reading upstream" errors, or socket leaks.
> 
> Can you elaborate on socket leaks?

For example, consider a request which is waiting for additional 
data from the upstream, so the only timer is the read timer for 
the upstream connection, and which is terminated because the 
client closed the connection.  Request termination will remove the 
only timer.  Still, the client connection is not yet closed by 
nginx.  So as long as the request is not actually freed following 
completion of the AIO operation, this is a socket leak: we have no 
timers left, and no further events expected.  And this can easily 
happen if neither segfault nor readv() error was triggered (for 
example, if p->upstream->read->ready was not set during AIO 
operation completion).

> > In ticket #2555, issues were observed with the following configuration
> > with cache background update (with thread writing instrumented to
> > introduce a delay, when a client closes the connection during an update):
> > 
> > location = /background-and-aio-write {
> > proxy_pass ...
> > proxy_cache one;
> > proxy_cache_valid 200 1s;
> > proxy_cache_background_update on;
> > proxy_cache_use_stale updating;
> > aio threads;
> > aio_write on;
> > limit_rate 1000;
> > }
> > 
> > Similarly, the same issue can be seen with SSI, and can be caused by
> > errors in subrequests, such as in the following configuration
> > (were "/proxy" uses AIO, and "/sleep" returns 444 after some delay,
> 
> s/were/where/ ?

Fixed, thanks.

> > causing request termination):
> > 
> > location = /ssi-active-boom {
> > ssi on;
> > ssi_types *;
> > return 200 '
> >
> >
> >';
> > limit_rate 1000;
> > }
> > 
> > Or the same with both AIO operation and the error in non-active subrequests
> > (which needs slightly different handling, see below):
> > 
> > location = /ssi-non-active-boom {
> > ssi on;
> > ssi_types *;
> > return 200 '
> >
> >
> >
> >';
> > limit_rate 1000;
> > }
> > 
> > Similarly, issues can be observed with just static files.  However,
> > with static files potential impact is limited due to timeout safeguards
> > in ngx_http_writer(), and the fact that c->error is set during request
> > termination.
> > In a simple configuration with an AIO operation in the active subrequest,
> > such as in the following configuration, the connection is closed right
> > after completion of the AIO operation anyway, since ngx_http_writer()
> > tries to write to the connection and fails due to c->error set:
> > 
> > location = /ssi-active-static-boom {
> > ssi on;
> > ssi_types *;
> > return 200 '
> >
> >
> >';
> > limit_rate 1000;
>

Re: [PATCH 4 of 4] AIO operations now add timers (ticket #2162)

2024-01-28 Thread Maxim Dounin
Hello!

On Fri, Jan 26, 2024 at 04:27:30PM +0400, Sergey Kandaurov wrote:

> 
> > On 27 Nov 2023, at 06:50, Maxim Dounin  wrote:
> > 
> > # HG changeset patch
> > # User Maxim Dounin 
> > # Date 1701050170 -10800
> > #  Mon Nov 27 04:56:10 2023 +0300
> > # Node ID 00c3e7333145ddb5ea0eeaaa66b3d9c26973c9c2
> > # Parent  61d08e4cf97cc073200ec32fc6ada9a2d48ffe51
> > AIO operations now add timers (ticket #2162).
> > 
> > Each AIO (thread IO) operation being run is now accompanied with 1-minute
> > timer.  This timer prevents unexpected shutdown of the worker process while
> > an AIO operation is running, and logs an alert if the operation is running
> > for too long.
> > 
> > This fixes "open socket left" alerts during worker processes shutdown
> > due to pending AIO (or thread IO) operations while corresponding requests
> > have no timers.  In particular, such errors were observed while reading
> > cache headers (ticket #2162), and with worker_shutdown_timeout.
> > 
> > diff --git a/src/http/ngx_http_copy_filter_module.c 
> > b/src/http/ngx_http_copy_filter_module.c
> > --- a/src/http/ngx_http_copy_filter_module.c
> > +++ b/src/http/ngx_http_copy_filter_module.c
> > @@ -170,6 +170,8 @@ ngx_http_copy_aio_handler(ngx_output_cha
> > file->aio->data = r;
> > file->aio->handler = ngx_http_copy_aio_event_handler;
> > 
> > +ngx_add_timer(>aio->event, 6);
> > +
> > r->main->blocked++;
> > r->aio = 1;
> > ctx->aio = 1;
> > @@ -192,6 +194,17 @@ ngx_http_copy_aio_event_handler(ngx_even
> > ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
> >"http aio: \"%V?%V\"", >uri, >args);
> > 
> > +if (ev->timedout) {
> > +ngx_log_error(NGX_LOG_ALERT, c->log, 0,
> > +  "aio operation took too long");
> > +ev->timedout = 0;
> > +return;
> > +}
> > +
> > +if (ev->timer_set) {
> > +ngx_del_timer(ev);
> > +}
> > +
> > r->main->blocked--;
> > r->aio = 0;
> > 
> > @@ -273,6 +286,8 @@ ngx_http_copy_thread_handler(ngx_thread_
> > return NGX_ERROR;
> > }
> > 
> > +ngx_add_timer(>event, 6);
> > +
> > r->main->blocked++;
> > r->aio = 1;
> > 
> > @@ -297,6 +312,17 @@ ngx_http_copy_thread_event_handler(ngx_e
> > ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
> >"http thread: \"%V?%V\"", >uri, >args);
> > 
> > +if (ev->timedout) {
> > +ngx_log_error(NGX_LOG_ALERT, c->log, 0,
> > +  "thread operation took too long");
> > +ev->timedout = 0;
> > +return;
> > +}
> > +
> > +if (ev->timer_set) {
> > +ngx_del_timer(ev);
> > +}
> > +
> > r->main->blocked--;
> > r->aio = 0;
> > 
> > diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c
> > --- a/src/http/ngx_http_file_cache.c
> > +++ b/src/http/ngx_http_file_cache.c
> > @@ -705,6 +705,8 @@ ngx_http_file_cache_aio_read(ngx_http_re
> > c->file.aio->data = r;
> > c->file.aio->handler = ngx_http_cache_aio_event_handler;
> > 
> > +ngx_add_timer(>file.aio->event, 6);
> > +
> > r->main->blocked++;
> > r->aio = 1;
> > 
> > @@ -752,6 +754,17 @@ ngx_http_cache_aio_event_handler(ngx_eve
> > ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
> >"http file cache aio: \"%V?%V\"", >uri, >args);
> > 
> > +if (ev->timedout) {
> > +ngx_log_error(NGX_LOG_ALERT, c->log, 0,
> > +  "aio operation took too long");
> > +ev->timedout = 0;
> > +return;
> > +}
> > +
> > +if (ev->timer_set) {
> > +ngx_del_timer(ev);
> > +}
> > +
> > r->main->blocked--;
> > r->aio = 0;
> > 
> > @@ -810,6 +823,8 @@ ngx_http_cache_thread_handler(ngx_thread
> > return NGX_ERROR;
> > }
> > 
> > +ngx_add_timer(>event, 6);
> > +
> > r->main->blocked++;
> > r->aio = 1;
> > 
> > @@ -831,6 +846,17 @@ ngx_http_cache_thread_event_handler(ngx_
> > ngx

Re: [PATCH 3 of 4] Silenced complaints about socket leaks on forced termination

2024-01-28 Thread Maxim Dounin
Hello!

On Fri, Jan 26, 2024 at 04:26:21PM +0400, Sergey Kandaurov wrote:

> 
> > On 27 Nov 2023, at 06:50, Maxim Dounin  wrote:
> > 
> > # HG changeset patch
> > # User Maxim Dounin 
> > # Date 1701049787 -10800
> > #  Mon Nov 27 04:49:47 2023 +0300
> > # Node ID 61d08e4cf97cc073200ec32fc6ada9a2d48ffe51
> > # Parent  faf0b9defc76b8683af466f8a950c2c241382970
> > Silenced complaints about socket leaks on forced termination.
> > 
> > When graceful shutdown was requested, and then nginx was forced to
> > do fast shutdown, it used to (incorrectly) complain about open sockets
> > left in connections which weren't yet closed when fast shutdown
> > was requested.
> > 
> > Fix is to avoid complaining about open sockets when fast shutdown was
> > requested after graceful one.  Abnormal termination, if requested with
> > the WINCH signal, can still happen though.
> 
> I've been wondering about such IMHO odd behaviour and support the fix.
> There might be an opinion that once you requested graceful shutdown,
> you have to wait until it's done, but I think that requesting fast
> shutdown afterwards should be legitimate.

I tend to think that the existing behaviour might be usable in some 
situations, like when one wants to look into remaining connections 
after waiting for some time for graceful shutdown to complete.  
Still, it is very confusing for unaware people, and I've seen lots 
of reports about socket leaks which in fact aren't.  And, more 
importantly, with the existing behaviour when looking at a socket 
leak report you never know if it's real or not.  So it is 
certainly worth fixing.

> 
> > 
> > diff --git a/src/os/unix/ngx_process_cycle.c 
> > b/src/os/unix/ngx_process_cycle.c
> > --- a/src/os/unix/ngx_process_cycle.c
> > +++ b/src/os/unix/ngx_process_cycle.c
> > @@ -948,7 +948,7 @@ ngx_worker_process_exit(ngx_cycle_t *cyc
> > }
> > }
> > 
> > -if (ngx_exiting) {
> > +if (ngx_exiting && !ngx_terminate) {
> > c = cycle->connections;
> > for (i = 0; i < cycle->connection_n; i++) {
> > if (c[i].fd != -1
> > @@ -963,11 +963,11 @@ ngx_worker_process_exit(ngx_cycle_t *cyc
> > ngx_debug_quit = 1;
> > }
> > }
> > +}
> > 
> > -if (ngx_debug_quit) {
> > -ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "aborting");
> > -ngx_debug_point();
> > -}
> > +if (ngx_debug_quit) {
> > +ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "aborting");
> > +ngx_debug_point();
> > }
> > 
> > /*
> > diff --git a/src/os/win32/ngx_process_cycle.c 
> > b/src/os/win32/ngx_process_cycle.c
> > --- a/src/os/win32/ngx_process_cycle.c
> > +++ b/src/os/win32/ngx_process_cycle.c
> > @@ -834,7 +834,7 @@ ngx_worker_process_exit(ngx_cycle_t *cyc
> > }
> > }
> > 
> > -if (ngx_exiting) {
> > +if (ngx_exiting && !ngx_terminate) {
> > c = cycle->connections;
> > for (i = 0; i < cycle->connection_n; i++) {
> > if (c[i].fd != (ngx_socket_t) -1
> 
> I think it's fine.

Thanks for looking, pushed to http://mdounin.ru/hg/nginx/.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH 2 of 4] Upstream: fixed usage of closed sockets with filter finalization

2024-01-28 Thread Maxim Dounin
Hello!

On Fri, Jan 26, 2024 at 04:26:00PM +0400, Sergey Kandaurov wrote:

> > On 27 Nov 2023, at 06:50, Maxim Dounin  wrote:
> > 
> > # HG changeset patch
> > # User Maxim Dounin 
> > # Date 1701049758 -10800
> > #  Mon Nov 27 04:49:18 2023 +0300
> > # Node ID faf0b9defc76b8683af466f8a950c2c241382970
> > # Parent  a5e39e9d1f4c84dcbe6a2f9e079372a3d63aef0b
> > Upstream: fixed usage of closed sockets with filter finalization.
> > 
> > When filter finalization is triggered when working with an upstream server,
> > and error_page redirects request processing to some simple handler,
> > ngx_http_request_finalize() triggers request termination when the response
> > is sent.  In particular, via the upstream cleanup handler, nginx will close
> > the upstream connection and the corresponding socket.
> > 
> > Still, this can happen to be with ngx_event_pipe() on stack.  While
> > the code will set p->downstream_error due to NGX_ERROR returned from the
> > output filter chain by filter finalization, otherwise the error will be
> > ignored till control returns to ngx_http_upstream_process_request().
> > And event pipe might try reading from the (already closed) socket, resulting
> > in "readv() failed (9: Bad file descriptor) while reading upstream" errors
> > (or even segfaults with SSL).
> > 
> > Such errors were seen with the following configuration:
> > 
> >location /t2 {
> >proxy_pass http://127.0.0.1:8080/big;
> > 
> >image_filter_buffer 10m;
> >image_filter   resize  150 100;
> >error_page 415   = /empty;
> >}
> > 
> >location /empty {
> >return 204;
> >}
> > 
> >location /big {
> ># big enough static file
> >}
> > 
> > Fix is to set p->upstream_error in ngx_http_upstream_finalize_request(),
> > so the existing checks in ngx_event_pipe_read_upstream() will prevent
> > further reading from the closed upstream connection.
> > 
> > Similarly, p->upstream_error is now checked when handling events at
> > ngx_event_pipe() exit, as checking p->upstream->fd is not enough if
> > keepalive upstream connections are being used and the connection was
> > saved to cache during request termination.
> > 
> 
> Setting p->upstream_error in ngx_http_upstream_finalize_request()
> may look suspicious, because it is used to be set on connection errors
> such as upstream timeout or recv error, or, as a recently introduced
> exception in the fastcgi module, - also when the FastCGI record ends
> prematurely, before receiving all the expected content.
> But technically I think this is quite correct, because we no longer
> want to receive further data, and also (and you mention this in the
> commit log) this repeats closing an upstream connection socket in
> the same place in ngx_http_upstream_finalize_request().
> So I think it should be fine.

The biggest concern I personally see here is with the added 
p->upstream_error check at ngx_event_pipe() exit.  If there is a 
real upstream error, such as when the connection is reset by the 
upstream server, and if we want the pipe to be active for some 
time (for example, if we want it to continue writing to the 
downstream connection), there will be no ngx_handle_read_event() 
call.  For level-triggered event methods this means that the read 
event for the upstream connection will be generated again and 
again.

This shouldn't be the problem for existing ngx_event_pipe() uses 
though, as p->upstream_error is anyway triggers 
ngx_http_upstream_finalize_request().

Still, we can consider introducing a separate flag, such as 
p->upstream_closed, or clearing p->upstream, and checking these in 
ngx_event_pipe() instead.  This probably would be a more clear 
solution.

Updated patch below:

# HG changeset patch
# User Maxim Dounin 
# Date 1706510064 -10800
#  Mon Jan 29 09:34:24 2024 +0300
# Node ID 4a91a03dcd8df0652884ed6ebe9f7437ce82fd26
# Parent  7b630f6487068f7cc9dd83762fb4ea39f2f340e9
Upstream: fixed usage of closed sockets with filter finalization.

When filter finalization is triggered when working with an upstream server,
and error_page redirects request processing to some simple handler,
ngx_http_request_finalize() triggers request termination when the response
is sent.  In particular, via the upstream cleanup handler, nginx will close
the upstream connection and the corresponding socket.

Still, this can happen to be with ngx_event_pipe() on stack.  While
the code will set p->downstream_error due to NGX_ERROR returned from the
output filter chain by filter finalization, otherwise the error will be
ignored till control ret

Re: nginx-tests SSL tests failing out of the box?

2024-01-28 Thread Maxim Dounin
Hello!

On Sat, Jan 27, 2024 at 07:19:45AM +0300, Maxim Dounin wrote:

> Hello!
> 
> On Fri, Jan 26, 2024 at 09:29:58PM +0400, Sergey Kandaurov wrote:
> 
> > On Thu, Jan 25, 2024 at 11:38:57PM +0300, Maxim Dounin wrote:
> > > Hello!
> > > 
> > > On Thu, Jan 25, 2024 at 06:59:36PM +, Mayerhofer, Austin via 
> > > nginx-devel wrote:
> > > 
> > > > Hi all,
> > > > 
> > > > I have not made any changes to NGINX. Vanilla NGINX (./configure with 
> > > > no flags) passes all tests that run, but when compiling with SSL, not 
> > > > all SSL tests are passing. Is this expected, or do I need to configure 
> > > > nginx further aside from adding the --with-http_ssl_module flag? Do 
> > > > each of the failing tests below require separate fixes, or is there a 
> > > > one-size-fits-all solution for all of them?
> > > > 
> > > > OS: MacOS 12.6.3
> > > > Chip: Apple M1 Max
> > > > NGINX: 1.24.0 built from source code with ./configure --with-debug 
> > > > --with-http_ssl_module
> > > > Nginx-tests: 
> > > > https://github.com/nginx/nginx-tests/tree/4c2ad8093952706f327d04887c5546bad91b75a6
> > > > OpenSSL: 3.2.0 (/opt/homebrew/bin/openssl)
> > > > Perl: 5.30.3 (/usr/bin/perl)
> > > > 
> > > > When I run
> > > > 
> > > > ```
> > > > TEST_NGINX_BINARY=/usr/local/nginx/sbin/nginx prove -v ssl.t
> > > > ```
> > > > 
> > > > I see
> > > > 
> > > > ```
> > > > not ok 2 - session reused
> > > > 
> > > > #   Failed test 'session reused'
> > > > #   at ssl.t line 187.
> > > > #   'HTTP/1.1 200 OK
> > > > # Server: nginx/1.24.0
> > > > # Date: Thu, 25 Jan 2024 18:50:10 GMT
> > > > # Content-Type: text/plain
> > > > # Content-Length: 6
> > > > # Connection: close
> > > > #
> > > > # body .'
> > > > # doesn't match '(?^m:^body r$)'
> > > > ```
> > > 
> > > [...]
> > > 
> > > It looks like SSL session reuse is broken in Perl you are 
> > > using.  This might be the case if, for example, Net::SSLeay in 
> > > your installation was compiled with system LibreSSL as an SSL 
> > > library - at least on the server side LibreSSL simply does not 
> > > support session reuse with TLSv1.3.
> > > 
> > > Test suite checks if nginx was compiled with LibreSSL and marks 
> > > appropriate tests as TODO, but if the Perl module is broken 
> > > instead, the test will fail.
> > > 
> > 
> > Well, technically, we could test this and skip appropriately:
> > 
> > diff --git a/ssl_session_reuse.t b/ssl_session_reuse.t
> > --- a/ssl_session_reuse.t
> > +++ b/ssl_session_reuse.t
> > @@ -166,7 +166,9 @@ local $TODO = 'no TLSv1.3 sessions, old 
> >  local $TODO = 'no TLSv1.3 sessions, old IO::Socket::SSL'
> > if $IO::Socket::SSL::VERSION < 2.061 && test_tls13();
> >  local $TODO = 'no TLSv1.3 sessions in LibreSSL'
> > -   if $t->has_module('LibreSSL') && test_tls13();
> > +   if ($t->has_module('LibreSSL')
> > +   || Net::SSLeay::constant("LIBRESSL_VERSION_NUMBER"))
> > +   && test_tls13();
> >  
> >  is(test_reuse(8443), 1, 'tickets reused');
> >  is(test_reuse(8444), 1, 'tickets and cache reused');
> > 
> > But I see little to no purpose: if the testing tool is broken
> > in various unexpected ways (another example is X509_V_ERR_INVALID_PURPOSE
> > in peer certificate verification as reported in the adjacent thread),
> > I think we barely can handle this in general.
> 
> I generally agree.
> 
> Still, the X509_V_ERR_INVALID_PURPOSE seems to be an OpenSSL 
> 3.2.0-related issue: for tests using CA root certificates without 
> CA:TRUE it now generates X509_V_ERR_INVALID_CA on the root 
> certificate, which then changed to X509_V_ERR_INVALID_PURPOSE.
> 
> Given the list of incompatible changes from NEWS.md, and the fact 
> that the same tests work fine with OpenSSL 3.2.0 but with 
> "openssl" binary from older versions, it seems to be this:
> 
>   * The `x509`, `ca`, and `req` apps now always produce X.509v3 certificates.
> 
> This needs to be addressed.

Patch:

# HG changeset patch
# User Maxim Dounin 
# Date 1706477656 -10800
#  Mon Jan 29 00:34:16 2024 +0300
# Node ID 156665421f83a054cf331e8f9a27dd4d2f86114d
# Parent  27a7

Re: nginx-tests: Some SSL tests are failing with openssl 3.2.0

2024-01-28 Thread Maxim Dounin
Hello!

On Fri, Jan 26, 2024 at 04:28:15PM -0300, Renato Botelho wrote:

> I'm building nginx on an environment with openssl 3.2.0 and some SSL tests
> are failing.  I suspect it's related to openssl version because it works on
> another env with older openssl.  But maybe I'm wrong.

That's a result of incompatible change introduced in the 
"openssl" application by OpenSSL 3.2.0, it now generates X509v3 
certs even if not asked to, just discussed here:

https://mailman.nginx.org/pipermail/nginx-devel/2024-January/32O7PUI3XJZZGBMLS2NAH654MS23MVDD.html

Will be eventually fixed.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: nginx-tests SSL tests failing out of the box?

2024-01-26 Thread Maxim Dounin
Hello!

On Fri, Jan 26, 2024 at 09:29:58PM +0400, Sergey Kandaurov wrote:

> On Thu, Jan 25, 2024 at 11:38:57PM +0300, Maxim Dounin wrote:
> > Hello!
> > 
> > On Thu, Jan 25, 2024 at 06:59:36PM +, Mayerhofer, Austin via 
> > nginx-devel wrote:
> > 
> > > Hi all,
> > > 
> > > I have not made any changes to NGINX. Vanilla NGINX (./configure with no 
> > > flags) passes all tests that run, but when compiling with SSL, not all 
> > > SSL tests are passing. Is this expected, or do I need to configure nginx 
> > > further aside from adding the --with-http_ssl_module flag? Do each of the 
> > > failing tests below require separate fixes, or is there a 
> > > one-size-fits-all solution for all of them?
> > > 
> > > OS: MacOS 12.6.3
> > > Chip: Apple M1 Max
> > > NGINX: 1.24.0 built from source code with ./configure --with-debug 
> > > --with-http_ssl_module
> > > Nginx-tests: 
> > > https://github.com/nginx/nginx-tests/tree/4c2ad8093952706f327d04887c5546bad91b75a6
> > > OpenSSL: 3.2.0 (/opt/homebrew/bin/openssl)
> > > Perl: 5.30.3 (/usr/bin/perl)
> > > 
> > > When I run
> > > 
> > > ```
> > > TEST_NGINX_BINARY=/usr/local/nginx/sbin/nginx prove -v ssl.t
> > > ```
> > > 
> > > I see
> > > 
> > > ```
> > > not ok 2 - session reused
> > > 
> > > #   Failed test 'session reused'
> > > #   at ssl.t line 187.
> > > #   'HTTP/1.1 200 OK
> > > # Server: nginx/1.24.0
> > > # Date: Thu, 25 Jan 2024 18:50:10 GMT
> > > # Content-Type: text/plain
> > > # Content-Length: 6
> > > # Connection: close
> > > #
> > > # body .'
> > > # doesn't match '(?^m:^body r$)'
> > > ```
> > 
> > [...]
> > 
> > It looks like SSL session reuse is broken in Perl you are 
> > using.  This might be the case if, for example, Net::SSLeay in 
> > your installation was compiled with system LibreSSL as an SSL 
> > library - at least on the server side LibreSSL simply does not 
> > support session reuse with TLSv1.3.
> > 
> > Test suite checks if nginx was compiled with LibreSSL and marks 
> > appropriate tests as TODO, but if the Perl module is broken 
> > instead, the test will fail.
> > 
> 
> Well, technically, we could test this and skip appropriately:
> 
> diff --git a/ssl_session_reuse.t b/ssl_session_reuse.t
> --- a/ssl_session_reuse.t
> +++ b/ssl_session_reuse.t
> @@ -166,7 +166,9 @@ local $TODO = 'no TLSv1.3 sessions, old 
>  local $TODO = 'no TLSv1.3 sessions, old IO::Socket::SSL'
>   if $IO::Socket::SSL::VERSION < 2.061 && test_tls13();
>  local $TODO = 'no TLSv1.3 sessions in LibreSSL'
> - if $t->has_module('LibreSSL') && test_tls13();
> + if ($t->has_module('LibreSSL')
> + || Net::SSLeay::constant("LIBRESSL_VERSION_NUMBER"))
> + && test_tls13();
>  
>  is(test_reuse(8443), 1, 'tickets reused');
>  is(test_reuse(8444), 1, 'tickets and cache reused');
> 
> But I see little to no purpose: if the testing tool is broken
> in various unexpected ways (another example is X509_V_ERR_INVALID_PURPOSE
> in peer certificate verification as reported in the adjacent thread),
> I think we barely can handle this in general.

I generally agree.

Still, the X509_V_ERR_INVALID_PURPOSE seems to be an OpenSSL 
3.2.0-related issue: for tests using CA root certificates without 
CA:TRUE it now generates X509_V_ERR_INVALID_CA on the root 
certificate, which then changed to X509_V_ERR_INVALID_PURPOSE.

Given the list of incompatible changes from NEWS.md, and the fact 
that the same tests work fine with OpenSSL 3.2.0 but with 
"openssl" binary from older versions, it seems to be this:

  * The `x509`, `ca`, and `req` apps now always produce X.509v3 certificates.

This needs to be addressed.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] Enforce that CR precede LF in chunk lines

2024-01-25 Thread Maxim Dounin
Hello!

On Thu, Jan 25, 2024 at 08:32:17PM +, Ben Kallus wrote:

> > Still, there is a robustness principle which allows applications
> > to parse requests with various deviations from the grammar.
> 
> Whether this is principle is good is a matter of opinion. I tend to
> lean toward thinking that it is not (as you can probably tell) but
> reasonable minds will differ on this point.
> 
> > You may want to be more specific what "off by one" means here.
> 
> Happy to :)
> 
> Here's an example of a payload that smuggles a request past Apache
> Traffic Server to a Node.js backend:
> ```
> POST / HTTP/1.1\r\n
> Transfer-Encoding: chunked\r\n
> \r\n
> 2\r\r
> ;a\r\n
> 02\r\n
> 2d\r\n
> 0\r\n
> \r\n
> DELETE / HTTP/1.1\r\n
> Content-Length: 183\r\n
> \r\n
> 0\r\n\r\nGET / HTTP/1.1\r\n\r\n
> ```
> The exact mechanism of this payload is relatively unimportant (it has
> to do with the `2\r\r;a`). The important point is that the POST is
> seen by both ATS and Node, the DELETE is seen only by Node, and the
> GET is seen only by ATS. Thus, the DELETE request is smuggled.
> 
> (A very similar attack worked on Google Cloud's classic application
> load balancer, and on Akamai's load balancer until very recently when
> companies patched the bugs. I'm still working on the writeup for those
> bugs, but you can see us present the material here:
> https://yewtu.be/watch?v=aKPAX00ft5s=2h19m0s)
> 
> You'll notice that the DELETE request has a Content-Length header.
> This is because in order for the smuggling to go undetected, the
> response to the DELETE request needs to be sent only after the GET
> request is forwarded. One way to do this is to add a message body to
> the DELETE request, so that it remains incomplete until the arrival of
> the GET request. It is therefore necessary for the attacker to predict
> the length of the GET request after it has passed through the reverse
> proxy, so that this length can be used to compute the Content-Length
> (or chunk size) in the DELETE request. Because reverse proxies often
> modify requests, this is not always straightforward.
> 
> In this instance, I use a Content-Length header of 183 because with
> the configuration of ATS that I was attacking, `GET /
> HTTP/1.1\r\n\r\n` ends up becoming 178 bytes long due to the insertion
> of X-Forwarded-For, Via, etc., +5 for `0\r\n\r\n`. If I had used a
> length less than 183, then Node would send a 400 after responding to
> the DELETE request, which makes the reverse proxy aware that request
> smuggling has occurred. If I had used a length greater than 183, then
> Node would time out waiting for the rest of the DELETE request's
> message body. Thus, I need to guess the length exactly right to pull
> off undetected request smuggling. Guessing correctly can be
> challenging, especially when added headers have unpredictable lengths.
> This is common with CDNs, which often insert random identifiers into
> request headers.
> 
> If instead of using Content-Length, I had used a chunked message body
> to smuggle the DELETE request, and the backend server allows bare LF
> as a chunk line terminator, then my length guess could be one less
> than the correct value without invalidating the message for servers
> that accept bare LF in chunk lines. Thus, when developing future
> request smuggling attacks, getting my length guess correct is a little
> easier when the backend server allows bare LF chunk line endings.

As far as I understand what goes on here and what do you mean by 
using a chunked message body, with length guess which is one less 
than the correct value you'll end up with LF + "\r\n0\r\n\r\n" at 
the request end, which will result in 400.  Length which is one 
more will work though, so understood, thanks.

In the original exploit length which is two less should work 
though, due to the "SHOULD ignore at least one empty line (CRLF) 
received prior to the request-line" robustness exception in 2.2. 
Message parsing of RFC 9112.  And one less might also work, as 
long as empty lines before the request-line accept bare LF (not 
sure about Node though).

Overall, I don't think there is a big difference here.

> > including manual testing such
> > as with nc(1).
> 
> If you pass the -C flag, nc will translate LF to CRLF for you :)

It won't, because "-C" is a non-portable flag provided by a 
Debian-specific patch.  And even if it will work for some, this 
will still complicate testing.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: nginx-tests SSL tests failing out of the box?

2024-01-25 Thread Maxim Dounin
Hello!

On Thu, Jan 25, 2024 at 06:59:36PM +, Mayerhofer, Austin via nginx-devel 
wrote:

> Hi all,
> 
> I have not made any changes to NGINX. Vanilla NGINX (./configure with no 
> flags) passes all tests that run, but when compiling with SSL, not all SSL 
> tests are passing. Is this expected, or do I need to configure nginx further 
> aside from adding the --with-http_ssl_module flag? Do each of the failing 
> tests below require separate fixes, or is there a one-size-fits-all solution 
> for all of them?
> 
> OS: MacOS 12.6.3
> Chip: Apple M1 Max
> NGINX: 1.24.0 built from source code with ./configure --with-debug 
> --with-http_ssl_module
> Nginx-tests: 
> https://github.com/nginx/nginx-tests/tree/4c2ad8093952706f327d04887c5546bad91b75a6
> OpenSSL: 3.2.0 (/opt/homebrew/bin/openssl)
> Perl: 5.30.3 (/usr/bin/perl)
> 
> When I run
> 
> ```
> TEST_NGINX_BINARY=/usr/local/nginx/sbin/nginx prove -v ssl.t
> ```
> 
> I see
> 
> ```
> not ok 2 - session reused
> 
> #   Failed test 'session reused'
> #   at ssl.t line 187.
> #   'HTTP/1.1 200 OK
> # Server: nginx/1.24.0
> # Date: Thu, 25 Jan 2024 18:50:10 GMT
> # Content-Type: text/plain
> # Content-Length: 6
> # Connection: close
> #
> # body .'
> # doesn't match '(?^m:^body r$)'
> ```

[...]

It looks like SSL session reuse is broken in Perl you are 
using.  This might be the case if, for example, Net::SSLeay in 
your installation was compiled with system LibreSSL as an SSL 
library - at least on the server side LibreSSL simply does not 
support session reuse with TLSv1.3.

Test suite checks if nginx was compiled with LibreSSL and marks 
appropriate tests as TODO, but if the Perl module is broken 
instead, the test will fail.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] Enforce that CR precede LF in chunk lines

2024-01-25 Thread Maxim Dounin
Hello!

On Thu, Jan 25, 2024 at 03:21:16AM +, Ben Kallus wrote:

> The HTTP/1.1 standards allow the recognition of bare LF as a line
> terminator in some contexts.
> 
> From RFC 9112 Section 2.2:
> > Although the line terminator for the start-line and fields is the sequence 
> > CRLF, a recipient MAY recognize a single LF as a line terminator and ignore 
> > any preceding CR.
> 
> From RFC 7230 Section 3.5:
> > Although the line terminator for the start-line and header fields is
> > the sequence CRLF, a recipient MAY recognize a single LF as a line
> > terminator and ignore any preceding CR.
> 
> From RFC 2616 Section 19.3:
> > The line terminator for message-header fields is the sequence CRLF.
> > However, we recommend that applications, when parsing such headers,
> > recognize a single LF as a line terminator and ignore the leading CR.
> 
> In summary, bare LF can be recognized as a line terminator for a
> field-line (i.e. a header or trailer) or a start-line, but not outside
> of these contexts. In particular, bare LF is not an acceptable line
> terminator for chunk data lines or chunk size lines. One of the
> rejection messages for an RFC 9112 errata report makes the reasoning
> behind this choice clear:
> 
> > The difference was intentional. A chunked parser is not a start line or 
> > field parser (it is a message body parser) and it is supposed to be less 
> > forgiving because it does not have to retain backwards compatibility with 
> > 1.0 parsers.
> > Hence, bare LF around the chunk sizes would be invalid and should result in 
> > the connection being marked as invalid.

Still, there is a robustness principle which allows applications 
to parse requests with various deviations from the grammar.  
Quoting RFC 2616:

   Although this document specifies the requirements for the generation
   of HTTP/1.1 messages, not all applications will be correct in their
   implementation. We therefore recommend that operational applications
   be tolerant of deviations whenever those deviations can be
   interpreted unambiguously.

As such, it is certainly valid for a HTTP/1.1 server based on RFC 
2616 to accept LF as line terminator in chunk sizes.

While RFC 7230 and RFC 9112 tried to harden requirements, and now 
say that "the server SHOULD respond with 400" on deviations which 
are not explicitly allowed, it is still not a violation to accept 
such deviations.

> Currently, Nginx allows chunk lines (both size and data) to use bare
> LF as a line terminator. This means that (for example) the following
> payload is erroneously accepted:
> ```
> POST / HTTP/1.1\r\n
> Host: whatever\r\n
> Transfer-Encoding: chunked\r\n
> 0\n# <--- This is
> missing a \r
> \r\n
> ```
> 
> This is probably not such a big deal, but it is a standards violation,
> and it comes with one small consequence: chunk lengths that are off by
> one will not invalidate the message body.
> 
> I've developed a few request smuggling exploits against other servers
> and proxies in the past that rely upon the attacker's ability to
> predict the length of a request after it has passed through a reverse
> proxy. This is usually straightforward, but if there are any
> unpredictable headers inserted by the proxy, getting the guess right
> becomes nontrivial. Being able to be off by one thus makes the
> attacker's job a little bit easier.

You may want to be more specific what "off by one" means here.  

While it is true that an attacker which isn't able to generate 
proper CRLF for some reason might be stopped by such a 
restriction, it still needs to ensure there is an LF, which makes 
things mostly equivalent in almost all cases.

> Given that many popular HTTP implementations (Apache httpd, Node,
> Boost::Beast, Lighttpd) adhere to the standard on this line
> termination issue, we should expect this change to break almost no
> clients, since any client generating requests that terminate chunk
> lines with bare LF would already be incompatible with a large portion
> of the web.
> 
> It is, however, also true that many HTTP implementations (Go net/http,
> H2O, LiteSpeed) exhibit the same behavior as Nginx, and it's probably
> worth exploring why that is.
> 
> The following patch changes Nginx's parsing behavior to match the
> standard. Note that this patch does not stop Nginx from allowing bare
> LF in request lines, response lines, headers, or trailers. It stops
> Nginx from accepting bare LF only in chunk size and data lines, where
> the standard does not permit LF/CRLF permissiveness. It's also a
> delete-only patch, which is always nice :)
> 
> If you all are open to this change, it will also be neces

Re: [PATCH] SSL: Added SSLKEYLOGFILE key material to debug logging

2024-01-24 Thread Maxim Dounin
Hello!

On Sun, Jan 21, 2024 at 10:37:24AM +, J Carter wrote:

> # HG changeset patch
> # User J Carter 
> # Date 1705832811 0
> #  Sun Jan 21 10:26:51 2024 +
> # Node ID b00332a5253eefb53bacc024c72f55876c2eac6e
> # Parent  ee40e2b1d0833b46128a357fbc84c6e23be9be07
> SSL: Added SSLKEYLOGFILE key material to debug logging.
> 
> This patch also introduces the debug_keylog error log level flag, which
> may be used to graunually enable or ommit logging of key material via
> error level flags (note, it's always enabled when using
> debug_connection).
> 
> Each line of key material is output to the error log as separate log
> message, and is prepended with 'ssl keylog: ' for convenient extraction.
> 
> The purpose of logging key material is to allow external tools, such as
> wireshark/tshark, to decrypt captured TLS connections in all situations.
> 
> Previously, only TLS 1.2 (and below) connections could be decrypted
> when specific ciphers suites were used, and when the decrypter had
> access to the acting server's TLS certificates and keys. It was not
> possible to decrypt TLS 1.3 traffic without generating SSLKEYLOGFILE on
> peer, or by using other hacks on nginx host (using GDB, or patched ssl
> libraries).

Thanks for the patch.

Logging session keying material is known to be problematic from 
ethical point of view.  As such, I would rather avoid introducing 
relevant functionality in nginx.

[...]

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: Core: Avoid memcpy from NULL

2024-01-24 Thread Maxim Dounin
_stream_limit_conn_module.o |  105 
 stream/ngx_stream_log_module.o|  872 ++--
 stream/ngx_stream_proxy_module.o  |  749 ++--
 stream/ngx_stream_script.o|   16 
 31 files changed, 10658 insertions(+), 10549 deletions(-)

In particular, in the only real change in ngx_palloc.o assembler 
is as follows:

@@ -452,16 +452,19 @@ ngx_reset_pool:
testl   %ebx, %ebx
jne .L99 .L97:
+   testl   %esi, %esi
+   je  .L100
movl%esi, %eax
.p2align 4,,10
.p2align 3

Which corresponds to restored with -fno-delete-null-pointer-check 
initial "p" check on the first iteration of the second loop, due 
to "pool->large" being used in the first loop initialization:

for (l = pool->large; l; l = l->next) {
if (l->alloc) {
ngx_free(l->alloc);
}
}

for (p = pool; p; p = p->d.next) {
p->d.last = (u_char *) p + sizeof(ngx_pool_t);
p->d.failed = 0;
}

Many other cases, such as multiple changes in ngx_inet.o, one of 
the two changes in ngx_open_file_cache.o, and one change 
ngx_http_parse.o, correspond to ngx_strlchr() calls, where 
subsequent result check is omitted because no-match is directly 
handled by the inlined ngx_strlchr() code:

p = ngx_strlchr(uri->data, last, '?');

if (p) { ... }

And there seems to be no real changes in ngx_http_script.o and 
ngx_stream_script.o, just some minor instructions reordering.

Overall, it might be feasible to review all the differences to 
ensure there are no real issues introduced by various compiler 
optimizations.

[...]

> There is a proposal for C2y to define memcpy(NULL,NULL,0):
> https://docs.google.com/document/d/1guH_HgibKrX7t9JfKGfWX2UCPyZOTLsnRfR6UleD1F8/edit
> If you feel strongly that memcpy from NULL should be defined, feel
> free to contribute to it :)

Interesting, thanks.  This would be the best solution and will 
eliminate the need for any changes by defining the behaviour, as 
it should.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] Year 2024

2024-01-23 Thread Maxim Dounin
Hello!

On Tue, Jan 23, 2024 at 12:56:47PM +, Yaroslav Zhuravlev wrote:

>  GNUmakefile  |  2 +-
>  text/LICENSE |  2 +-
>  xml/menu.xml |  1 +
>  3 files changed, 3 insertions(+), 2 deletions(-)
> 
> 

> # HG changeset patch
> # User Yaroslav Zhuravlev 
> # Date 1706014530 0
> #  Tue Jan 23 12:55:30 2024 +
> # Node ID 9fa58eaa9b8fd4dcd9677d37a86140f945eaf7c6
> # Parent  87d313e1bf7f365ac81693aae5d83907869774cb
> Year 2024.
> 
> diff --git a/GNUmakefile b/GNUmakefile
> --- a/GNUmakefile
> +++ b/GNUmakefile
> @@ -71,7 +71,7 @@
>  
>  YEARS =  \
>   2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019  \
> - 2020 2021 2022
> + 2020 2021 2022 2023
>  
>  all: news arx 404 $(LANGS)
>  
> diff --git a/text/LICENSE b/text/LICENSE
> --- a/text/LICENSE
> +++ b/text/LICENSE
> @@ -1,6 +1,6 @@
>  /* 
>   * Copyright (C) 2002-2021 Igor Sysoev
> - * Copyright (C) 2011-2023 Nginx, Inc.
> + * Copyright (C) 2011-2024 Nginx, Inc.
>   * All rights reserved.
>   *
>   * Redistribution and use in source and binary forms, with or without
> diff --git a/xml/menu.xml b/xml/menu.xml
> --- a/xml/menu.xml
> +++ b/xml/menu.xml
> @@ -59,6 +59,7 @@
>  -->
>  
>   news 
> +
>  
>  
>  

Looks good.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] Documented opensourcing of the OTel module

2024-01-23 Thread Maxim Dounin
Hello!

On Tue, Jan 23, 2024 at 01:49:07PM +, Yaroslav Zhuravlev wrote:

>  xml/en/docs/index.xml   |   8 +++-
>  xml/en/docs/ngx_otel_module.xml |  20 +++-
>  xml/ru/docs/index.xml   |  10 --
>  3 files changed, 30 insertions(+), 8 deletions(-)
> 
> 

> # HG changeset patch
> # User Yaroslav Zhuravlev 
> # Date 1704815768 0
> #  Tue Jan 09 15:56:08 2024 +
> # Node ID 00807e94be3622a79d7796be6ea11934f97b2662
> # Parent  e3116677300fa455200da63002c746aece689029
> Documented opensourcing of the OTel module.
> 
> diff --git a/xml/en/docs/index.xml b/xml/en/docs/index.xml
> --- a/xml/en/docs/index.xml
> +++ b/xml/en/docs/index.xml
> @@ -8,7 +8,7 @@
> link="/en/docs/"
>   lang="en"
> - rev="49"
> + rev="50"
>   toc="no">
>  
>  
> @@ -681,6 +681,12 @@
>  ngx_mgmt_module
>  
>  
> +
> +
> +
> +
> +
> +
>  
>  
>  ngx_otel_module
> diff --git a/xml/en/docs/ngx_otel_module.xml b/xml/en/docs/ngx_otel_module.xml
> --- a/xml/en/docs/ngx_otel_module.xml
> +++ b/xml/en/docs/ngx_otel_module.xml
> @@ -9,12 +9,14 @@
>link="/en/docs/ngx_otel_module.html"
>  lang="en"
> -rev="1">
> +rev="2">
>  
>  
>  
>  
> -The ngx_otel_module module (1.23.4) provides
> +The ngx_otel_module module (1.23.4) is nginx-authored

Quoting from 
https://mailman.nginx.org/pipermail/nginx-devel/2023-October/4AGH5XVKNP6UDFE32PZIXYO7JQ4RE37P.html:

: Note that "nginx-authored" here looks misleading, as no nginx core 
: developers work on this module.

> +https://github.com/nginxinc/nginx-otel;>third-party module
> +that provides
>  https://opentelemetry.io;>OpenTelemetry
>  distributed tracing support.
>  The module supports
> @@ -23,12 +25,20 @@
>  
>  
>  
> +The module is open source since 1.25.2.
> +Download and install instructions are available
> + url="https://github.com/nginxinc/nginx-otel/blob/main/README.md;>here.
> +The module is also available as a prebuilt
> +nginx-module-otel dynamic module
> +package (1.25.4).
> +
> +
> +
>  
>  This module is available as part of our
>  commercial subscription
> -in nginx-plus-module-otel package.
> -After installation, the module can be loaded
> -dynamically.
> +(the
> + url="https://docs.nginx.com/nginx/admin-guide/dynamic-modules/opentelemetry;>nginx-plus-module-otel
>  package).

I don't see reasons to provide additional links here.  Rather, the 
note probably can be removed altogether, or changed to something 
like "In previuos versions, this module is available...".

>  
>  
>  
> diff --git a/xml/ru/docs/index.xml b/xml/ru/docs/index.xml
> --- a/xml/ru/docs/index.xml
> +++ b/xml/ru/docs/index.xml
> @@ -8,7 +8,7 @@
> link="/ru/docs/"
>   lang="ru"
> - rev="49"
> + rev="50"
>   toc="no">
>  
>  
> @@ -687,9 +687,15 @@
>  ngx_mgmt_module [en]
>  
>  
> +
> +
> +
> +
> +
> +
>  
>  
> -ngx_otel_module [en]
> +ngx_otel_module [en]
>  
>  
>  

> ___
> nginx-devel mailing list
> nginx-devel@nginx.org
> https://mailman.nginx.org/mailman/listinfo/nginx-devel


-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] Avoiding mixed socket families in PROXY protocol v1 (ticket #2594)

2024-01-23 Thread Maxim Dounin
Hello!

On Mon, Jan 22, 2024 at 07:48:01PM +0400, Roman Arutyunyan wrote:

> Hi,
> 
> On Mon, Jan 22, 2024 at 02:59:21PM +0300, Maxim Dounin wrote:
> > Hello!
> > 
> > On Mon, Jan 22, 2024 at 02:49:54PM +0400, Roman Arutyunyan wrote:
> > 
> > > # HG changeset patch
> > > # User Roman Arutyunyan 
> > > # Date 1705916128 -14400
> > > #  Mon Jan 22 13:35:28 2024 +0400
> > > # Node ID 2f12c929527b2337c15ef99d3a4dc97819b61fbd
> > > # Parent  ee40e2b1d0833b46128a357fbc84c6e23be9be07
> > > Avoiding mixed socket families in PROXY protocol v1 (ticket #2594).

Also nitpicking: ticket #2010 might be a better choice.

The #2594 is actually a duplicate (with a side issue noted that 
using long unix socket path might result in a PROXY protocol 
header without ports and CRLF) and should be closed as such.

> > > 
> > > When using realip module, remote and local addreses of a connection can 
> > > belong
> > > to different address families.  This previously resulted in generating 
> > > PROXY
> > > protocol headers like this:
> > > 
> > >   PROXY TCP4 127.0.0.1 unix:/tmp/nginx1.sock 55544 0
> > > 
> > > The PROXY protocol v1 specification does not allow mixed families.  The 
> > > change
> > > will generate the unknown PROXY protocol header in this case:
> > > 
> > >   PROXY UNKNOWN
> > > 
> > > Also, the above mentioned format for unix socket address is not specified 
> > > in
> > > PROXY protocol v1 and is a by-product of internal nginx representation of 
> > > it.
> > > The change eliminates such addresses from  PROXY protocol headers as well.
> > 
> > Nitpicking: double space in "from  PROXY".
> 
> Yes, thanks.
> 
> > This change will essentially disable use of PROXY protocol in such 
> > configurations.  While it is probably good enough from formal 
> > point of view, and better that what we have now, this might still 
> > be a surprise, especially when multiple address families are used 
> > on the original proxy server, and the configuration works for some 
> > of them, but not for others.
> > 
> > Wouldn't it be better to remember if the PROXY protocol was used 
> > to set the address, and use $proxy_protocol_server_addr / 
> > $proxy_protocol_server_port in this case?
> > 
> > Alternatively, we can use some dummy server address instead, so 
> > the client address will be still sent.
> 
> Another alternative is duplicating client address in this case, see patch.

I don't think it is a good idea.  Using some meaningful real 
address might easily mislead users.  I would rather use a clearly 
dummy address instead, such as INADDR_ANY with port 0.

Also, as suggested, using the server address as obtained via PROXY 
protocol from the client might be a better solution as long as the 
client address was set via PROXY protocol (regardless of whether 
address families match or not), and what users expect from the 
"proty_protocol on;" when chaining stream proxies in the first 
place.

[...]

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] Avoiding mixed socket families in PROXY protocol v1 (ticket #2594)

2024-01-22 Thread Maxim Dounin
Hello!

On Mon, Jan 22, 2024 at 02:49:54PM +0400, Roman Arutyunyan wrote:

> # HG changeset patch
> # User Roman Arutyunyan 
> # Date 1705916128 -14400
> #  Mon Jan 22 13:35:28 2024 +0400
> # Node ID 2f12c929527b2337c15ef99d3a4dc97819b61fbd
> # Parent  ee40e2b1d0833b46128a357fbc84c6e23be9be07
> Avoiding mixed socket families in PROXY protocol v1 (ticket #2594).
> 
> When using realip module, remote and local addreses of a connection can belong
> to different address families.  This previously resulted in generating PROXY
> protocol headers like this:
> 
>   PROXY TCP4 127.0.0.1 unix:/tmp/nginx1.sock 55544 0
> 
> The PROXY protocol v1 specification does not allow mixed families.  The change
> will generate the unknown PROXY protocol header in this case:
> 
>   PROXY UNKNOWN
> 
> Also, the above mentioned format for unix socket address is not specified in
> PROXY protocol v1 and is a by-product of internal nginx representation of it.
> The change eliminates such addresses from  PROXY protocol headers as well.

Nitpicking: double space in "from  PROXY".

This change will essentially disable use of PROXY protocol in such 
configurations.  While it is probably good enough from formal 
point of view, and better that what we have now, this might still 
be a surprise, especially when multiple address families are used 
on the original proxy server, and the configuration works for some 
of them, but not for others.

Wouldn't it be better to remember if the PROXY protocol was used 
to set the address, and use $proxy_protocol_server_addr / 
$proxy_protocol_server_port in this case?

Alternatively, we can use some dummy server address instead, so 
the client address will be still sent.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH 1 of 3] Stream: socket peek in preread phase

2024-01-19 Thread Maxim Dounin
Hello!

On Fri, Jan 19, 2024 at 03:42:37PM +0400, Sergey Kandaurov wrote:

> 
> > On 18 Jan 2024, at 23:44, Maxim Dounin  wrote:
> > 
> > Hello!
> > 
> > On Thu, Jan 18, 2024 at 08:15:33PM +0400, Sergey Kandaurov wrote:
> > 
> >> On Thu, Jan 18, 2024 at 07:06:06PM +0400, Roman Arutyunyan wrote:
> >>> Hi,
> >>> 
> >>> # HG changeset patch
> >>> # User Roman Arutyunyan 
> >>> # Date 1702476295 -14400
> >>> #  Wed Dec 13 18:04:55 2023 +0400
> >>> # Node ID 7324e8e73595c3093fcc2cbd2b5d6b1a947be3b0
> >>> # Parent  ee40e2b1d0833b46128a357fbc84c6e23be9be07
> >>> Stream: socket peek in preread phase.
> >>> 
> >>> Previously, preread buffer was always read out from socket, which made it
> >>> impossible to terminate SSL on the connection without introducing 
> >>> additional
> >>> SSL BIOs.  The following patches will rely on this.
> >>> 
> >>> Now, when possible, recv(MSG_PEEK) is used instead, which keeps data in 
> >>> socket.
> >>> It's called if SSL is not already terminated and if an egde-triggered 
> >>> event
> >>> method is used.  For epoll, EPOLLRDHUP support is also required.
> >>> 
> >>> diff --git a/src/stream/ngx_stream_core_module.c 
> >>> b/src/stream/ngx_stream_core_module.c
> >>> --- a/src/stream/ngx_stream_core_module.c
> >>> +++ b/src/stream/ngx_stream_core_module.c
> >>> @@ -10,6 +10,11 @@
> >>> #include 
> >>> 
> >>> 
> >>> +static ngx_uint_t ngx_stream_preread_can_peek(ngx_connection_t *c);
> >>> +static ngx_int_t ngx_stream_preread_peek(ngx_stream_session_t *s,
> >>> +ngx_stream_phase_handler_t *ph);
> >>> +static ngx_int_t ngx_stream_preread(ngx_stream_session_t *s,
> >>> +ngx_stream_phase_handler_t *ph);
> >>> static ngx_int_t ngx_stream_core_preconfiguration(ngx_conf_t *cf);
> >>> static void *ngx_stream_core_create_main_conf(ngx_conf_t *cf);
> >>> static char *ngx_stream_core_init_main_conf(ngx_conf_t *cf, void *conf);
> >>> @@ -203,8 +208,6 @@ ngx_int_t
> >>> ngx_stream_core_preread_phase(ngx_stream_session_t *s,
> >>> ngx_stream_phase_handler_t *ph)
> >>> {
> >>> -size_t   size;
> >>> -ssize_t  n;
> >>> ngx_int_trc;
> >>> ngx_connection_t*c;
> >>> ngx_stream_core_srv_conf_t  *cscf;
> >>> @@ -217,56 +220,33 @@ ngx_stream_core_preread_phase(ngx_stream
> >>> 
> >>> if (c->read->timedout) {
> >>> rc = NGX_STREAM_OK;
> >>> +goto done;
> >>> +}
> >>> 
> >>> -} else if (c->read->timer_set) {
> >>> -rc = NGX_AGAIN;
> >>> +if (!c->read->timer_set) {
> >>> +rc = ph->handler(s);
> >>> 
> >>> -} else {
> >>> -rc = ph->handler(s);
> >>> +if (rc != NGX_AGAIN) {
> >>> +goto done;
> >>> +}
> >>> }
> >>> 
> >>> -while (rc == NGX_AGAIN) {
> >>> -
> >>> +if (c->buffer == NULL) {
> >>> +c->buffer = ngx_create_temp_buf(c->pool, 
> >>> cscf->preread_buffer_size);
> >>> if (c->buffer == NULL) {
> >>> -c->buffer = ngx_create_temp_buf(c->pool, 
> >>> cscf->preread_buffer_size);
> >>> -if (c->buffer == NULL) {
> >>> -rc = NGX_ERROR;
> >>> -break;
> >>> -}
> >>> +rc = NGX_ERROR;
> >>> +goto done;
> >>> }
> >>> -
> >>> -size = c->buffer->end - c->buffer->last;
> >>> -
> >>> -if (size == 0) {
> >>> -ngx_log_error(NGX_LOG_ERR, c->log, 0, "preread buffer full");
> >>> -rc = NGX_STREAM_BAD_REQUEST;
> >>> -break;
> >>> -}
> >>> +}
> >>> 
> >>> -if (c->read->eof) {
> >>> -rc = NGX_STREAM_OK;
> >>> -break;
> >>> -}
> >>> -
> >

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

2024-01-18 Thread Maxim Dounin
eam
> >  }
> >  
> >  
> > +static ngx_uint_t
> > +ngx_stream_preread_can_peek(ngx_connection_t *c)
> > +{
> > +#if (NGX_STREAM_SSL)
> > +if (c->ssl) {
> > +return 0;
> > +}
> > +#endif
> > +
> > +if ((ngx_event_flags & NGX_USE_CLEAR_EVENT) == 0) {
> > +return 0;
> > +}
> > +
> > +#if (NGX_HAVE_KQUEUE)
> > +if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
> > +return 1;
> > +}
> > +#endif
> > +
> > +#if (NGX_HAVE_EPOLLRDHUP)
> > +if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && ngx_use_epoll_rdhup) {
> > +return 1;
> > +}
> > +#endif
> > +
> > +return 0;
> > +}
> > +
> > +
> > +static ngx_int_t
> > +ngx_stream_preread_peek(ngx_stream_session_t *s, 
> > ngx_stream_phase_handler_t *ph)
> > +{
> > +ssize_tn;
> > +ngx_int_t  rc;
> > +ngx_err_t  err;
> > +ngx_connection_t  *c;
> > +
> > +c = s->connection;
> > +
> > +n = recv(c->fd, (char *) c->buffer->last,
> > + c->buffer->end - c->buffer->last, MSG_PEEK);
> > +
> > +err = ngx_socket_errno;
> > +
> > +ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, "stream recv(): %z", 
> > n);
> > +
> > +if (n == -1) {
> > +if (err == NGX_EAGAIN) {
> > +c->read->ready = 0;
> > +return NGX_AGAIN;
> > +}
> > +
> > +ngx_connection_error(c, err, "recv() failed");
> > +return NGX_STREAM_OK;
> > +}
> > +
> > +if (n == 0) {
> > +return NGX_STREAM_OK;
> > +}
> > +
> > +c->buffer->last += n;
> > +
> > +rc = ph->handler(s);
> > +
> > +if (rc != NGX_AGAIN) {
> > +c->buffer->last = c->buffer->pos;
> > +return rc;
> > +}
> > +
> > +if (c->buffer->last == c->buffer->end) {
> > +ngx_log_error(NGX_LOG_ERR, c->log, 0, "preread buffer full");
> > +return NGX_STREAM_BAD_REQUEST;
> > +}
> > +
> > +if (c->read->pending_eof) {
> > +return NGX_STREAM_OK;
> > +}
> > +
> > +c->buffer->last = c->buffer->pos;
> > +
> > +return NGX_AGAIN;
> > +}
> > +
> > +
> > +static ngx_int_t
> > +ngx_stream_preread(ngx_stream_session_t *s, ngx_stream_phase_handler_t *ph)
> > +{
> > +ssize_tn;
> > +ngx_int_t  rc;
> > +ngx_connection_t  *c;
> > +
> > +c = s->connection;
> > +
> > +while (c->read->ready) {
> > +
> > +n = c->recv(c, c->buffer->last, c->buffer->end - c->buffer->last);
> > +
> > +if (n == NGX_AGAIN) {
> > +return NGX_AGAIN;
> > +}
> > +
> > +if (n == NGX_ERROR || n == 0) {
> > +return NGX_STREAM_OK;
> > +}
> > +
> > +c->buffer->last += n;
> > +
> > +rc = ph->handler(s);
> > +
> > +if (rc != NGX_AGAIN) {
> > +return rc;
> > +}
> > +
> > +if (c->buffer->last == c->buffer->end) {
> > +ngx_log_error(NGX_LOG_ERR, c->log, 0, "preread buffer full");
> > +return NGX_STREAM_BAD_REQUEST;
> > +}
> > +}
> > +
> > +return NGX_AGAIN;
> > +}
> > +
> > +
> >  ngx_int_t
> >  ngx_stream_core_content_phase(ngx_stream_session_t *s,
> >  ngx_stream_phase_handler_t *ph)
> 
> Looks good.

I'm somewhat sceptical about the idea of functionality which 
depends on the edge-triggered event methods being available.

If/when the patch series is reviewed, please make sure it gets my 
approval before commit.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: This is a question about the "$status" log value when "proxy_read_timeout" occurs.

2024-01-16 Thread Maxim Dounin
Hello!

On Tue, Jan 16, 2024 at 01:15:09PM +0900, 박규철 wrote:

> This is a question about the "$status" log value when "proxy_read_timeout"
> occurs.
> Nginx version in use: v1.25.3
> 
> Contents of 1Mbyte size were requested to [Origin Server].
> A response up to approximately 500Kbytes in size, including the header, was
> received without delay.
> However, after 500Kbytes, no response was received from Origin for 3
> seconds and the connection (time-out)
> Since the message "upstream timed out...while reading upstream" was logged
> in the error log, I think the connection was lost due to the
> "proxy_read_timeout 3s" setting.
> 
> While checking the log, I noticed that the "$status" value in the access
> log was different from what I thought.
> In my opinion, if the connection was terminated by "proxy_read_timeout",
> the "$status" value would be 5xx, but the "$status" value in the saved
> access log was 200.
> 
> A normal response was not completed due to "proxy_read_timeout", so I would
> like to know why the "$status" value is stored as 200 instead of 5xx.
> Should I check a variable other than "$status" for responses to abnormal
> timeouts such as "proxy_read_timeout"?

The $status variable shows the status as sent to the client in the 
response headers.  When proxy_read_timeout happens, the response 
headers are already sent, so $status contains 200 as sent to the 
client.

For errors happened during sending the response body, consider 
looking into the error log.  Some generic information about 
successful request completion might be found in the 
$request_completion variable 
(http://nginx.org/r/$request_completion).  Note though that it 
might not be set for variety of reasons.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: processing a request without body

2024-01-13 Thread Maxim Dounin
Hello!

On Sat, Jan 13, 2024 at 03:11:11PM +0800, Muhammad Nuzaihan wrote:

> Hi Maxim,
> 
> I did enable debug logs before i posted the question.
> 
> With json payload, my code is executed right after doing malloc and
> "http request body content length filter".
> 
> Without a json payload, it doesn't execute my request
> validation.That's why i thought it might be due to content length is
> 0.
> 
> Here is the debug log when i curl with an empty payload:
> 
> 2024/01/13 15:01:19 [debug] 2452969#0: *11 rewrite phase: 0
> 2024/01/13 15:01:19 [debug] 2452969#0: *11 test location: "/"
> 2024/01/13 15:01:19 [debug] 2452969#0: *11 test location: "proxy/health"
> 2024/01/13 15:01:19 [debug] 2452969#0: *11 test location: "proxy/unhealthy"
> 2024/01/13 15:01:19 [debug] 2452969#0: *11 test location:
> "proxy/profile/alice/comment"
> 2024/01/13 15:01:19 [debug] 2452969#0: *11 using configuration
> "/proxy/profile/alice/comment"
> 2024/01/13 15:01:19 [debug] 2452969#0: *11 http cl:0 max:1048576
> 2024/01/13 15:01:19 [debug] 2452969#0: *11 rewrite phase: 2
> 2024/01/13 15:01:19 [debug] 2452969#0: *11 post rewrite phase: 3
> 2024/01/13 15:01:19 [debug] 2452969#0: *11 generic phase: 4
> 2024/01/13 15:01:19 [debug] 2452969#0: *11 http request body content
> length filter
> 2024/01/13 15:01:19 [debug] 2452969#0: *11 http read client request body

Clearly request body reading is called here, at the preaccess 
phase.  This implies that your code is called - nginx itself won't 
try to read the request body that early.  Everything else is up to 
your code.

> 2024/01/13 15:01:19 [debug] 2452969#0: *11 recv: eof:0, avail:0
> 2024/01/13 15:01:19 [debug] 2452969#0: *11 http client request body recv -2
> 2024/01/13 15:01:19 [debug] 2452969#0: *11 http client request body rest 1
> 2024/01/13 15:01:19 [debug] 2452969#0: *11 event timer add: 3: 6:183385517

Note that request body reading code blocks waiting for more data.

> 2024/01/13 15:01:19 [debug] 2452969#0: *11 http finalize request: -4,
> "/proxy/profile/alice/comment?" a:1, c:2
> 2024/01/13 15:01:19 [debug] 2452969#0: *11 http request count:2 blk:0
> 2024/01/13 15:01:19 [debug] 2452969#0: *11 access phase: 7
> 2024/01/13 15:01:19 [debug] 2452969#0: *11 access phase: 8

Note that phase handling continues here: it shouldn't, since 
request body reading is in progress. 

This suggested that your code fails to stop phase handling after 
calling ngx_http_read_client_request_body(): note you should 
return NGX_DONE to stop processing unless there is an immediate 
error.

[...]

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] fastcgi_params: added REMOTE_HOST parameter

2024-01-12 Thread Maxim Dounin
Hello!

On Fri, Jan 12, 2024 at 11:03:45PM +, Jakub Zelenka wrote:

> On Fri, Jan 12, 2024 at 10:20 PM Maxim Dounin  wrote:
> 
> > > # HG changeset patch
> > > # User Jakub Zelenka 
> > > # Date 1705078404 0
> > > #  Fri Jan 12 16:53:24 2024 +
> > > # Node ID 1ff2f737bd318a730d0944a6037c8fd7c7da2656
> > > # Parent  ee40e2b1d0833b46128a357fbc84c6e23be9be07
> > > Added REMOTE_HOST parameter to fastcgi_params.
> > >
> > > When HTTP/3 is used, users will no longer get HTTP_HOST as host header
> > is no
> > > longer set by most clients. It is useful / necessary for many setups to
> > have
> > > such information and REMOTE_HOST is defined in CGI/1.1 for such purpose.
> >
> > https://datatracker.ietf.org/doc/html/rfc3875#section-4.1.9
> >
> >The REMOTE_HOST variable contains the fully qualified domain name of
> >the client sending the request to the server, if available, otherwise
> >NULL.
> >
> > That is, REMOTE_HOST is completely unrelated.  It is not the
> > hostname of the requested server, but the hostname of the client -
> > result of a reverse DNS lookup of a client's IP address, something
> > used to be provided by some servers when Internet was small (e.g,
> > HostnameLookups in Apache).  It is certainly not the right param
> > to use for $host.
> >
> >
> I think you are right. I somehow thought about nginx as a client for some
> reason (technically it's a client from FPM point of view) but I agree that
> the meaning is different here.
> 
> > IMO, proper param to use would be SERVER_NAME.  It is set to
> > $server_name by default, though can be modified locally to provide
> > $host if needed in the particular configuration.
> 
> I think it's probably the best option. Although current default value is a
> bit unfortunate as it's just server_name specified by user so most of the
> time is meaningless. Not sure if it can really comply with linked RFC
> either as it doesn't have to be hostname. On the other side it's been
> default for ages so I guess it won't be changed, right?

Well, $server_name is actually expected to be a proper/canonical 
name of the server.  In particular, it is used by nginx itself 
when returning redirects with "server_name_in_redirect on;" (used 
to be the default, but not anymore, since the default server_name 
was changed to "" in nginx 0.8.48).

I believe it is up to the particular server configuration if 
SERVER_NAME should be set to $server_name, that is, the canonical 
name of the server, or should use $host, as might be preferred in 
more dynamic configurations where multiple names are handled in a 
single server{} block or when server_name is not set at all.

Changing the default as provided in various fastcgi_param files as 
shipped with nginx might be indeed troublesome though.  For 
example, if a configuration expects SERVER_NAME to be a canonical 
name, changing SERVER_NAME to client-controlled $host might result 
in security issues.

> It's all just a bit unfortunate because with HTTP/3, there is no longer any
> server host info in the default configuration that would be passed to FPM.

The "Host" header is not required to be present in HTTP/1.x 
either, and even in HTTP/1.1 where it is required to be present, 
it might not match the authority actually requested via the 
request line.  That is, technically using the "Host" header for 
anything, except might be links sent to the client itself, is 
almost always wrong.

OTOH, for HTTP/2 nginx emulates the "Host" header based on the 
":authority" pseudo-header.  Given the amount of pain the approach 
taken for HTTP/3 causes, we might consider doing the same for 
HTTP/3 as well.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: processing a request without body

2024-01-12 Thread Maxim Dounin
Hello!

On Fri, Jan 12, 2024 at 10:17:42PM +0800, Muhammad Nuzaihan wrote:

> Hi Maxim,
> 
> Thank you so much for your explaination.
> 
> I have another question. If i have an empty string in my payload, it
> skips the phase handler completely.
> 
> Example: curl -X POST http://localhost/proxy/profile/alice/comment -d
> '' -H 'Content-Type: application/json'
> 
> the flag "-d ''"
> 
> I do doing it at NGX_HTTP_ACCESS_PHASE in the handler. It seems that
> if "content_length = 0", it skips the access phase handler as well?

Access phase handlers are called for all requests (unless these 
are rejected at earlier stages).  If in doubt, consider configuring 
debug logging and add appropriate debug logging to your module, it 
should make things obvious enough.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] fastcgi_params: added REMOTE_HOST parameter

2024-01-12 Thread Maxim Dounin
Hello!

On Fri, Jan 12, 2024 at 05:04:22PM +, Jakub Zelenka wrote:

> Hi,
> 
> I'm a PHP-FPM maintainer and some FPM users have issues with missing host
> header when using HTTP/3: https://github.com/php/php-src/issues/13021 .
> This is not an nginx issue as correctly noted in
> https://trac.nginx.org/nginx/ticket/2281 but it would be nice to have
> fastcgi_param set for getting host in default config. I was thinking how to
> best expose $host and REMOTE_HOST seems logical and so I think it could be
> useful addition. I can update FPM to also set REMOTE_HOST from HTTP_HOST if
> REMOTE_HOST is not set which would make it even more available for HTTP/1.1
> and HTTP/2 users.
> 
> Please let me know what you think!
> 
> # HG changeset patch
> # User Jakub Zelenka 
> # Date 1705078404 0
> #  Fri Jan 12 16:53:24 2024 +
> # Node ID 1ff2f737bd318a730d0944a6037c8fd7c7da2656
> # Parent  ee40e2b1d0833b46128a357fbc84c6e23be9be07
> Added REMOTE_HOST parameter to fastcgi_params.
> 
> When HTTP/3 is used, users will no longer get HTTP_HOST as host header is no
> longer set by most clients. It is useful / necessary for many setups to have
> such information and REMOTE_HOST is defined in CGI/1.1 for such purpose.

https://datatracker.ietf.org/doc/html/rfc3875#section-4.1.9

   The REMOTE_HOST variable contains the fully qualified domain name of
   the client sending the request to the server, if available, otherwise
   NULL.

That is, REMOTE_HOST is completely unrelated.  It is not the 
hostname of the requested server, but the hostname of the client - 
result of a reverse DNS lookup of a client's IP address, something 
used to be provided by some servers when Internet was small (e.g, 
HostnameLookups in Apache).  It is certainly not the right param 
to use for $host.

IMO, proper param to use would be SERVER_NAME.  It is set to 
$server_name by default, though can be modified locally to provide 
$host if needed in the particular configuration.

> 
> diff -r ee40e2b1d083 -r 1ff2f737bd31 conf/fastcgi_params
> --- a/conf/fastcgi_params   Mon Dec 25 21:15:48 2023 +0400
> +++ b/conf/fastcgi_params   Fri Jan 12 16:53:24 2024 +
> @@ -17,6 +17,7 @@
> 
>  fastcgi_param  REMOTE_ADDR$remote_addr;
>  fastcgi_param  REMOTE_PORT$remote_port;
> +fastcgi_param  REMOTE_HOST$host;
>  fastcgi_param  SERVER_ADDR$server_addr;
>  fastcgi_param  SERVER_PORT$server_port;
>  fastcgi_param  SERVER_NAME$server_name;

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: processing a request without body

2024-01-11 Thread Maxim Dounin
Hello!

On Fri, Jan 12, 2024 at 03:26:39AM +0800, Muhammad Nuzaihan wrote:

> Hi Maxim,
> 
> After searching the archives, I found the solution which you had
> answered before:
> https://www.ruby-forum.com/t/trouble-getting-the-request-body-of-a-http-post/180463/4
> 
> The code that reads the body is:
> rc = ngx_http_read_client_request_body(r,
>   ngx_http_foo_body_handler);
> 
> if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
>   return rc;
> }
> 
> Can i buy you coffee?

You may want to start with basic examples and the dev guide, 
specifically:

https://nginx.org/en/docs/dev/development_guide.html#http_request_body

Note though that reading the request body during phase processing, 
in contrast to doing so in a content handler, requires special 
precautions.  In particular, you'll have to call 
ngx_http_finalize_request(NGX_DONE) to ensure correct request 
reference counting:

https://hg.nginx.org/nginx/file/tip/src/http/modules/ngx_http_mirror_module.c#l120

Further, to resuming phase processing after reading the request 
body you'll have to restore r->write_event_handler and call 
ngx_http_core_run_phases().  See here in the mirror module for an 
example:

https://hg.nginx.org/nginx/file/tip/src/http/modules/ngx_http_mirror_module.c#l144

Hope this helps.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: Core: Avoid memcpy from NULL

2024-01-09 Thread Maxim Dounin
Hello!

On Tue, Jan 09, 2024 at 04:18:06PM +, Ben Kallus wrote:

> > This demonstrates that your patch
> > is clearly insufficient.  Further, Vladimir's patch is clearly
> > insufficient too, as shown for the another patch in the same
> > patch series.
> 
> "Insufficient" only when compared to a hypothetical perfectly exhaustive
> patch that requires "huge work," as you put it. It's best not to let the
> perfect be the enemy of the good.
> 
> Avoiding UB in normal program execution (as opposed to the test suite) will
> prevent common workloads from executing UB, which is not merely an issue of
> "theoretical correctness." See https://blog.regehr.org/archives/213
> (section "A Fun Case Analysis") for an example of how this "NULL used in
> nonnull context" issue leads to unexpected program behavior.
> 
> Thus, I think the best approach is to patch pstrdup to avoid
> memcpy-from-NULL, and patch other functions only if someone can present a
> backtrace from a real configuration of nginx that executed UB.

Thank you for your opinion.

As I tried to explain in the review of Vladimir's patches, fixing 
scattered sanitizer reports individually, assuming no direct 
impact is present, has an obvious downside: as long as there is a 
consistent coding pattern which causes such reports, fixing 
individual reports will hide the pattern from being seen by the 
sanitizer, but won't eliminate it.  As such, it will greatly 
reduce pressure on fixing the pattern, but if the pattern is 
indeed practically dangerous and has security consequences, it 
will be trivial for an attacker to find out cases which are not 
fixed and exploit them.  As such, I prefer to identify patterns 
and fix them consistently over the code base instead of trying to 
quench individual reports.

Quenching individual reports makes sense if we don't want to fix 
the pattern, assuming it is completely harmless anyway, but rather 
want to simplify usage of the sanitizer to identify other issues.  
This does not look like what you are advocating about though.  
(Also, again, patching just ngx_pstrdup() is clearly not enough 
even for this, see Vladimir's patch for a list of other places 
reported by UBSan in perfectly real configurations.)

As already pointed out previously, there are no known cases 
when memcpy(p, NULL, 0) can result in miscompilation of nginx 
code, as nginx usually does not checks string data pointers 
against NULL (and instead checks length, if needed).  In 
particular, ngx_pstrdup() you are trying to patch doesn't.  That 
is, this is exactly the "no direct impact" situation as assumed 
above.  If you think there are cases when the code can be 
miscompiled in practice, and not theoretically, please share.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH 4 of 4] AIO operations now add timers (ticket #2162)

2024-01-08 Thread Maxim Dounin
Hello!

On Mon, Jan 08, 2024 at 01:31:11PM +, J Carter wrote:

> On Mon, 8 Jan 2024 11:25:55 +
> J Carter  wrote:
> 
> > Hello,
> > 
> > On Mon, 27 Nov 2023 05:50:27 +0300
> > Maxim Dounin  wrote:
> > 
> > > # HG changeset patch
> > > # User Maxim Dounin 
> > > # Date 1701050170 -10800
> > > #  Mon Nov 27 04:56:10 2023 +0300
> > > # Node ID 00c3e7333145ddb5ea0eeaaa66b3d9c26973c9c2
> > > # Parent  61d08e4cf97cc073200ec32fc6ada9a2d48ffe51
> > > AIO operations now add timers (ticket #2162).
> > > 
> > > Each AIO (thread IO) operation being run is now accompanied with 1-minute
> > > timer.  This timer prevents unexpected shutdown of the worker process 
> > > while
> > > an AIO operation is running, and logs an alert if the operation is running
> > > for too long.  
> > 
> > Shouldn't this timer's duration be set to match worker_shutdown_timeout's
> > duration rather than being hard coded to 60s ?
> 
> Ah nevermind, I understand.
> 
> These timers will either expire from passing the 60s set duration, or 
> will expire as worker_process_timeout itself expires, kills the 
> connection and times out associated timers (including the aio timers). 
> 
> Setting it to worker_shutdown_timeout's duration would be pointless 
> (an 'infinite' timer would give the same result).
> 
> So the only situation in which a different value for these AIO 
> timers would make sense is if these AIO operations are expected to
> take longer 60s, but less than worker_shutdown_timeout (in cases 
> where it has been increased from it's own default of 60s).
> 
> In that case the AIO operation's timeout would have to be one 
> (or more) of it's own directives, with a value less than 
> worker_shutdown_timeout. 

Not really.

When worker_shutdown_timeout expires, it tries to terminate the 
request, but it can't as long as an AIO operation is running.  
When the AIO operation completes, the request will be actually 
terminated and the worker process will be allowed to exit.  So far 
so good.

But if the AIO operation never completes, the timer will expire 
after 1 minute, will log an alert, and the worker processes will 
be anyway allowed to exit (with the request still present).  This 
might not be actually possible though - for example, 
ngx_thread_pool_exit_worker() will just block waiting for all 
pending operations to complete.

In theory, the situation when an AIO operation never completes 
should never happen, and just a counter of pending AIO 
operations can be used instead to delay shutdown (which is 
essentially equivalent to an infinite timer).  

In practice, though, using a large enough guard timer might be 
better: it provides additional level of protection against bugs or 
system misbehaviour, and at least logs an alert if something 
really weird happens.  It is also looks more universal and in line 
with current approach of using existing timers as an indicator 
that something is going on and shutdown should be delayed.

The timer is expected to be "large enough", since we cannot do 
anything meaningful with an AIO operation which never completes, 
we can only complain loudly, so the timer should never expire 
unless there is something really wrong.  This is not the case with 
worker_shutdown_timeout: it can be set to an arbitrary low value, 
which is not expected to mean that something is really wrong if 
the timer expires, but rather means that nginx shouldn't try to 
process remaining requests, but should instead close them as long 
as it can do so.  That is, worker_shutdown_timeout does not fit 
semantically.  Further, worker_shutdown_timeout is not set by 
default, so it simply cannot be used.

The 1 minute was chosen as it matches default send_timeout, which 
typically accompanies AIO operations when sending responses (and 
also delays shutdown, so no "open socket left" alerts are normally 
seen).  Still, send_timeout is also quite different semantically, 
and therefore a hardcoded value is used instead.

I don't think there are valid cases when AIO operations can take 
longer than 1 minute, as these are considered to be small and fast 
operations, which are normally done synchronously within nginx 
event loop when not using AIO, and an operations which takes 1m 
would mean nginx is completely unresponsive.  Still, if we'll 
found out that 1 minute is not large enough in some cases, 
we can just bump it to a larger value.

[...]

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] SSL: raised limit for upstream session size

2024-01-08 Thread Maxim Dounin
Hello!

On Tue, Dec 26, 2023 at 12:29:54AM +0400, Sergey Kandaurov wrote:

> > On 23 Dec 2023, at 01:46, Maxim Dounin  wrote:
> > 
> > Hello!
> > 
> > On Fri, Dec 22, 2023 at 06:28:34PM +0400, Sergey Kandaurov wrote:
> > 
> >> # HG changeset patch
> >> # User Sergey Kandaurov 
> >> # Date 1703255284 -14400
> >> #  Fri Dec 22 18:28:04 2023 +0400
> >> # Node ID a463fb67e143c051fd373d1df94e5813a37d5cea
> >> # Parent  44266e0651c44f530c4aa66e68c1b9464a9acee7
> >> SSL: raised limit for upstream session size.
> >> 
> >> Unlike shared session cache used to store multiple client SSL sessions and
> >> which may be per a single SSL connection, sessions saved from upstream are
> >> per upstream server peer, so there is no such multiplier effect, but they
> >> may be of noticeably larger size due to session tickets being used.
> >> 
> >> It was observed that session tickets sent from JVM backends may result in
> >> a decoded session size nearly the previous maximum session size limit of
> >> 4096 or slightly beyond.  Raising the limit allows to save such sessions.
> > 
> > Session tickets are not expected to be larger than sessions 
> > itself, except by several bytes used for key identification and 
> > encryption overhead.  I see no reasons why the limit should be 
> > different in different places.
> > 
> > And 4096 for an SSL session looks a lot.  The only justification I 
> > can assume here is an SSL session with the client certificate (or 
> > even certificate chain) being saved into the session.  It might 
> > worth looking into what actually happens here.
> > 
> 
> Indeed.  Both local and peer certificate chains are serialized and
> encrypted as part of constructing a session ticket.  Per the original
> change to support tickets, this is hardcoded and may not be adjusted:
> https://hg.openjdk.org/jdk/jdk/rev/c2398053ee90#l4.352
> https://hg.openjdk.org/jdk/jdk/rev/c2398053ee90#l10.261

From my limited understanding of the JDK code, at least peerCerts 
seems to contain only certificates actually sent by the client, 
which is understandable (links to Github, since hg.openjdk.org 
used to be unresponsive when writing this, and returned 504 for 
almost all requests):

https://github.com/openjdk/jdk/blob/4fc6b0ffa4f771991a5ebd982b5133d2e364fdae/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java#L416

But localCerts seems to be always set on the server side, with all 
the certificates being sent to the client:

https://github.com/openjdk/jdk/blob/4fc6b0ffa4f771991a5ebd982b5133d2e364fdae/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java#L265
 

This looks like an issue on the JDK side: there are no reasons why 
server certificates needs to be saved into the session on the 
server, as they are readily available on the server.  Further, 
relevant saving code seems to be commented as "Client identity", 
which suggests that these might be saved unintentionally with an 
assumption that the code is only used on the client (OTOH, I don't 
see why the client needs its own certificates in the session as 
well).

Do you have an affected JVM backend on hand to confirm it's indeed 
the case?

I tend to think this needs to be reported to JDK developers.  
Their current code results in sending server certificate chain to 
the client at least two times (once in the handshake itself, and 
at least once in the ticket; not to mention that there can be more 
than one ticket in TLSv1.3), and they might reconsider doing this.

(Funny enough, they seems to be using cache to deserialize 
certificates from such tickets, see 
https://bugs.openjdk.org/browse/JDK-8286433 for details.)

Meanwhile, we can consider implementing a workaround on our side 
(that is, raising the limit, though I don't think there should be 
separate limits; also, I'm somewhat concerned about using 8k 
buffers on stack, we currently don't use anything larger than 4k) 
or instead focus on providing some guidance to users of affected 
JVM backends (I guess switching off tickets and/or TLSv1.3 should 
be enough in most cases).

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: Core: Avoid memcpy from NULL

2024-01-04 Thread Maxim Dounin
Hello!

On Wed, Jan 03, 2024 at 11:57:57PM +, Ben Kallus wrote:

> > Still, general style guidelines suggests that the code shouldn't
> > be written this way, and the only reason for j++ in the line in
> > question is that it mimics corresponding IPv4 code.
> 
> > It's not "just happens".
> 
> The point I'm trying to make is that ensuring correctness with
> function-like macros is difficult, both because of operator precedence
> and argument reevaluation. Expecting contributors to read the
> definitions of every macro they use becomes more and more cumbersome
> as the codebase expands, especially when some symbols are variably
> macros or functions depending on the state of (even infrequently-used)
> compile-time constants.

Sure, and hence the style.

> All that said, upon further reflection, I think the UB issue is best
> solved outside of ngx_strcpy, where the overhead of an extra check may
> have a performance impact. The following patch is sufficient to
> silence UBSan in my configuration:

I've already pointed you to the Vladimir's patch which contains at 
least a dozen of places where the same "UB issue" is reported when 
running nginx tests with UBSan.  This demonstrates that your patch 
is clearly insufficient.  Further, Vladimir's patch is clearly 
insufficient too, as shown for the another patch in the same 
patch series.

If we want to follow this approach, we need some way to trace 
places where zero length memcpy() can occur.  My best guess is 
that the only way is to look through all ngx_cpymem() / 
ngx_memcpy() / ngx_memmove() / ngx_movemem() calls, as nginx 
routinely uses { 0, NULL } as an empty string.  Given that there 
are 600+ of such calls in the codebase, and at least some need 
serious audit to find out if { 0, NULL } can appear in the call, 
this is going to be a huge work.  And, given that the only 
expected effect is theoretical correctness of the code, I doubt it 
worth the effort, especially given that the end result will likely 
reduce readability of the code.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: Core: Avoid memcpy from NULL

2023-12-31 Thread Maxim Dounin
Hello!

On Fri, Dec 29, 2023 at 04:50:36PM +, Ben Kallus wrote:

> > Still, -O0 is often used at least during development, and it might
> > be unreasonable to introduce extra function calls in basic
> > primitives.
> 
> I don't think this is a major cause for concern. It is perfectly
> reasonable for ngx_memcpy be a wrapper function around memcpy; I think
> most people would assume that from the name. In fact, it's *already*
> implemented as a function when NGX_MEMCPY_LIMIT is defined.

The NGX_MEMCPY_LIMIT is a very specific debugging define, which 
implies additional overhead for memcpy calls.  And it's certainly 
not an excuse for changing all the macro definitions to function 
calls.

Whether or not ngx_memcpy() can be implemented as a wrapper 
function is a separate question.

> > Further, nginx generally supports all available platforms
> > reasonably compatible with POSIX and C89.  This implies that
> > inline might be not available.
> 
> On such platforms, moving ngx_memcpy to a function may introduce some
> performance overhead. The question is whether slightly better
> performance on obscure systems is worth the mental overhead of working
> with function-like macros.

As said earlier in the thread, while some might prefer other 
approaches, function-like macros are used everywhere in nginx.

> > Sure (but see above about performance overhead; and another
> > question is if it needs to be solved, or following existing style
> > is enough to never see the issue).
> 
> A little extra performance overhead on C89 systems, or builds with -O0
> is a very small price to pay. ngx_resolver.c:4283 contains direct
> evidence that function-like macros incur mental overhead:
> ```
> ngx_memcpy(sin6->sin6_addr.s6_addr, addr6[j++].s6_addr, 16);
> ```
> Here we have an expression with a side-effect being passed into a
> function-like macro. As luck would have it, the second argument to
> ngx_memcpy is evaluated only once, so this is coincidentally okay.
> This particular landmine has been armed for a decade (see
> https://github.com/nginx/nginx/blob/769eded73267274e018f460dd76b417538aa5934/src/core/ngx_resolver.c#L2902).
> Thus, the existing style guidelines are not enough to prevent issues
> with function-like macros from arising in nginx. Inline functions
> solve this problem near-optimally.

The mentioned call specifically assumes that the second argument 
is only evaluated once, and it was certainly checked that it is 
only evaluated once when the call was written.  That is, there is 
no issue here.

Still, general style guidelines suggests that the code shouldn't 
be written this way, and the only reason for j++ in the line in 
question is that it mimics corresponding IPv4 code.

> > good luck with doing something like "ngx_max(foo & 0xff, bar)".
> 
> Nginx is littered with uses of expressions in ngx_max and ngx_min, it
> just happens that none of those expressions use operators of lower
> precedence than < and >. This seems like an invitation for human
> error.

It's not "just happens".

> Thus, I argue that the best solution to the memcpy-from-NULL problem
> is to replace ngx_memcpy and ngx_cpymem with inline functions with the
> appropriate checks for n==0. Going forward, it's probably smart to
> consider transitioning away from function-like macros more generally.

As I said earlier in this thread, I'm not exactly against using 
inline functions here, and I think a solution with inline 
functions can be accepted provided it is demonstrated that it 
introduces no measurable performance degradation.

Still, I'm very sceptical about the idea of "transitioning away 
from function-like macros".

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH 00 of 12] HTTP/3 proxying to upstreams

2023-12-29 Thread Maxim Dounin
Hello!

On Thu, Dec 28, 2023 at 05:23:38PM +0300, Vladimir Homutov via nginx-devel 
wrote:

> On Thu, Dec 28, 2023 at 04:31:41PM +0300, Maxim Dounin wrote:
> > Hello!
> >
> > On Wed, Dec 27, 2023 at 04:17:38PM +0300, Vladimir Homutov via nginx-devel 
> > wrote:
> >
> > > On Wed, Dec 27, 2023 at 02:48:04PM +0300, Maxim Dounin wrote:
> > > > Hello!
> > > >
> > > > On Mon, Dec 25, 2023 at 07:52:41PM +0300, Vladimir Homutov via 
> > > > nginx-devel wrote:
> > > >
> > > > > Hello, everyone,
> > > > >
> > > > > and Merry Christmas to all!
> > > > >
> > > > > I'm a developer of an nginx fork Angie.  Recently we implemented
> > > > > an HTTP/3 proxy support in our fork [1].
> > > > >
> > > > > We'd like to contribute this functionality to nginx OSS community.
> > > > > Hence here is a patch series backported from Angie to the current
> > > > > head of nginx mainline branch (1.25.3)
> > > >
> > > > Thank you for the patches.
> > > >
> > > > Are there any expected benefits from HTTP/3 being used as a
> > > > protocol to upstream servers?
> > >
> > > Personally, I don't see much.
> > >
> > > Probably, faster connection establishing to due 0RTT support (need to be
> > > implemented) and better multiplexing (again, if implemented wisely).
> > > I have made some simple benchmarks, and it looks more or less similar
> > > to usual SSL connections.
> >
> > Thanks for the details.
> >
> > Multiplexing is available since introduction of the FastCGI
> > protocol, yet to see it working in upstream connections.  As for
> > 0-RTT, using keepalive connections is probably more efficient
> > anyway (and not really needed for upstream connections in most
> > cases as well).
> 
> With HTTP/3 and keepalive we can have just one quic "connection" per upstream
> server (in extreme). We perform heavy handshake once, and leave it open.
> Next we just create HTTP/3 streams to perform request. They can perfectly
> run in parallel and use same quic connection. Probably, this is something
> worth implementing, with limitations of course: we don't want to mix
> requests from different (classes of) clients in same connection, we
> don't want eternal life of such connection and we need means to control
> level of such multiplexing.

Multiplexing has various downsides: already mentioned security 
implications, issues with balancing requests between upstream 
entities not directly visible to the client (such as different 
worker processes), added complexity.  And, as already mentioned, 
it is not something new in HTTP/3.

[...]

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH 00 of 12] HTTP/3 proxying to upstreams

2023-12-28 Thread Maxim Dounin
Hello!

On Wed, Dec 27, 2023 at 04:17:38PM +0300, Vladimir Homutov via nginx-devel 
wrote:

> On Wed, Dec 27, 2023 at 02:48:04PM +0300, Maxim Dounin wrote:
> > Hello!
> >
> > On Mon, Dec 25, 2023 at 07:52:41PM +0300, Vladimir Homutov via nginx-devel 
> > wrote:
> >
> > > Hello, everyone,
> > >
> > > and Merry Christmas to all!
> > >
> > > I'm a developer of an nginx fork Angie.  Recently we implemented
> > > an HTTP/3 proxy support in our fork [1].
> > >
> > > We'd like to contribute this functionality to nginx OSS community.
> > > Hence here is a patch series backported from Angie to the current
> > > head of nginx mainline branch (1.25.3)
> >
> > Thank you for the patches.
> >
> > Are there any expected benefits from HTTP/3 being used as a
> > protocol to upstream servers?
> 
> Personally, I don't see much.
> 
> Probably, faster connection establishing to due 0RTT support (need to be
> implemented) and better multiplexing (again, if implemented wisely).
> I have made some simple benchmarks, and it looks more or less similar
> to usual SSL connections.

Thanks for the details.

Multiplexing is available since introduction of the FastCGI 
protocol, yet to see it working in upstream connections.  As for 
0-RTT, using keepalive connections is probably more efficient 
anyway (and not really needed for upstream connections in most 
cases as well).

> >
> > [...]
> >
> > > Probably, the HTTP/3 proxy should be implemented in a separate module.
> > > Currently it is a patch to the HTTP proxy module to minimize 
> > > boilerplate.
> >
> > Sure.  I'm very much against the idea of mixing different upstream
> > protocols in a single protocol module.
> 
> noted.
> 
> > (OTOH, there are some uncertain plans to make proxy module able to
> > work with other protocols based on the scheme, such as in
> > "proxy_pass fastcgi://127.0.0.1:9000;".  This is mostly irrelevant
> > though, and might never happen.)
> 
> well, currently we have separate proxying modules that are similar enough to
> think about merging them like suggested. Not sure if one big module with
> methods will worth it, as semantics is slightly different.
> 
> proxy modules are already addons on top of upstream module, which does
> the heavy lifting. What requires improvement is probably the
> configuration that makes user to remember many similar directives doing
> the same thing but for different protocols.

Yep, making things easier to configure (and modify, if something 
related to configuration directives is changed or additional 
protocol is added) is the main motivator.  Still, there are indeed 
differences between protocol modules, and this makes single module 
inconvenient sometimes.  As such, plans are uncertain (and the 
previous attempt to do this failed miserably).

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: Re: Don't delete timer of write event when it's delayed.

2023-12-27 Thread Maxim Dounin
Hello!

On Wed, Dec 27, 2023 at 08:38:15PM +0800, Jiuzhou Cui wrote:

> Thank you for your reply.
> 
> Firstly, we meet the problem. And this patch works for me.
> 
> My scenario is after send response body about 10-20MB, we just set:
> 1. limit_rate = 1KB
> 2. limit_rate_after = body_bytes_sent
> 3. proxy_buffering = "on" (I think this is the key issue)
> 
> At the request begining, we didn't set proxy_buffering = "on" and limit_rate.

Sorry, not sure what you are trying to say.

You modify r->limit_rate and r->limit_rate_after from your module 
after sending some parts of the response?  This is not expected to 
work due to the mentioned design limitation of non-buffered 
proxying, and generally looks like a bug in your module, it 
shouldn't do this.

Further, it is not possible to change upstream buffering after 
nginx started sending the response.  It's a one-time choice, and 
modifications of r->upstream->buffering won't do anything (though 
also incorrect, as it's not something expected to be modified by 
modules).

Or I understood something incorrectly?

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH 00 of 12] HTTP/3 proxying to upstreams

2023-12-27 Thread Maxim Dounin
Hello!

On Mon, Dec 25, 2023 at 07:52:41PM +0300, Vladimir Homutov via nginx-devel 
wrote:

> Hello, everyone,
> 
> and Merry Christmas to all!
> 
> I'm a developer of an nginx fork Angie.  Recently we implemented
> an HTTP/3 proxy support in our fork [1].
> 
> We'd like to contribute this functionality to nginx OSS community.
> Hence here is a patch series backported from Angie to the current
> head of nginx mainline branch (1.25.3)

Thank you for the patches.

Are there any expected benefits from HTTP/3 being used as a 
protocol to upstream servers?

[...]

> Probably, the HTTP/3 proxy should be implemented in a separate module.
> Currently it is a patch to the HTTP proxy module to minimize boilerplate.

Sure.  I'm very much against the idea of mixing different upstream 
protocols in a single protocol module.

(OTOH, there are some uncertain plans to make proxy module able to 
work with other protocols based on the scheme, such as in 
"proxy_pass fastcgi://127.0.0.1:9000;".  This is mostly irrelevant 
though, and might never happen.)

[...]

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: Don't delete timer of write event when it's delayed.

2023-12-27 Thread Maxim Dounin
Hello!

On Wed, Dec 27, 2023 at 10:56:44AM +0800, Jiuzhou Cui wrote:

> Hello!
> 
> 
> # HG changeset patch
> # User Jiuzhou Cui 
> # Date 1703645578 -28800
> #  Wed Dec 27 10:52:58 2023 +0800
> # Node ID 474ae07e47272e435d81c0ca9e4867aae35c30ab
> # Parent  ee40e2b1d0833b46128a357fbc84c6e23be9be07
> Don't delete timer of write event when it's delayed.
> 
> 
> This will make download speed alway zero when limit_rate in body filter.
> 
> 
> diff -r ee40e2b1d083 -r 474ae07e4727 src/http/ngx_http_upstream.c
> --- a/src/http/ngx_http_upstream.c  Mon Dec 25 21:15:48 2023 +0400
> +++ b/src/http/ngx_http_upstream.c  Wed Dec 27 10:52:58 2023 +0800
> @@ -3787,11 +3787,13 @@
>  }
>  }
> 
> 
> -if (downstream->write->active && !downstream->write->ready) {
> -ngx_add_timer(downstream->write, clcf->send_timeout);
> -
> -} else if (downstream->write->timer_set) {
> -ngx_del_timer(downstream->write);
> +if (!downstream->write->delayed) {
> +if (downstream->write->active && !downstream->write->ready) {
> +ngx_add_timer(downstream->write, clcf->send_timeout);
> +
> +} else if (downstream->write->timer_set) {
> +ngx_del_timer(downstream->write);
> +}
>  }
> 
> 
>  if (upstream->read->eof || upstream->read->error) {

Thank you for the patch.

You are patching the 
ngx_http_upstream_process_non_buffered_request() function, which 
is, as can be correctly concluded from the function name, is used 
for non-buffered proxying.  Non-buffered proxying is specifically 
designed to return responses as long as they are available, and is 
not compatible with limit_rate.  Moreover, limit_rate is 
explicitly disabled in the ngx_http_upstream_send_response() 
function when the relevant handers are set:

u->read_event_handler = ngx_http_upstream_process_non_buffered_upstream;
r->write_event_handler =
 ngx_http_upstream_process_non_buffered_downstream;

r->limit_rate = 0;
r->limit_rate_set = 1;

(https://hg.nginx.org/nginx/file/release-1.25.3/src/http/ngx_http_upstream.c#l3092)

As such, the issue you are trying to fix is not expected to 
appear.

Could you please clarify the configuration you are seeing the 
issue with, and steps to reproduce the issue?

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] ssl: SSL_get0_verified_chain is available for LibreSSL >= 3.3.6

2023-12-23 Thread Maxim Dounin
Hello!

On Fri, Dec 22, 2023 at 05:53:30PM +0400, Sergey Kandaurov wrote:

> 
> > On 21 Dec 2023, at 02:40, Maxim Dounin  wrote:
> > 
> > Hello!
> > 
> > On Tue, Dec 19, 2023 at 10:44:00PM +0400, Sergey Kandaurov wrote:
> > 
> >> 
> >>> On 19 Dec 2023, at 12:58, Maxim Dounin  wrote:
> >>> 
> >>> Hello!
> >>> 
> >>> On Tue, Dec 19, 2023 at 02:09:10AM +0400, Sergey Kandaurov wrote:
> >>> 
> >>>>> On 24 Nov 2023, at 00:29, Ilya Shipitsin  wrote:
> >>>>> 
> >>>>> # HG changeset patch
> >>>>> # User Ilya Shipitsin 
> >>>>> # Date 1700769135 -3600
> >>>>> #  Thu Nov 23 20:52:15 2023 +0100
> >>>>> # Node ID 2001e73ce136d5bfc9bde27d338865b14b8ad436
> >>>>> # Parent  7ec761f0365f418511e30b82e9adf80bc56681df
> >>>>> ssl: SSL_get0_verified_chain is available for LibreSSL >= 3.3.6
> >>>> 
> >>>> style: SSL prefix should be uppercase.
> >>>> 
> >>>>> 
> >>>>> diff -r 7ec761f0365f -r 2001e73ce136 
> >>>>> src/event/ngx_event_openssl_stapling.c
> >>>>> --- a/src/event/ngx_event_openssl_stapling.cThu Oct 26 23:35:09 
> >>>>> 2023 +0300
> >>>>> +++ b/src/event/ngx_event_openssl_stapling.cThu Nov 23 20:52:15 
> >>>>> 2023 +0100
> >>>>> @@ -893,7 +893,8 @@
> >>>>>   ocsp->cert_status = V_OCSP_CERTSTATUS_GOOD;
> >>>>>   ocsp->conf = ocf;
> >>>>> 
> >>>>> -#if (OPENSSL_VERSION_NUMBER >= 0x1010L && !defined 
> >>>>> LIBRESSL_VERSION_NUMBER)
> >>>>> +/* minimum OpenSSL 1.1.1 & LibreSSL 3.3.6 */
> >>>>> +#if (OPENSSL_VERSION_NUMBER >= 0x1010L && !defined 
> >>>>> LIBRESSL_VERSION_NUMBER) || (defined(LIBRESSL_VERSION_NUMBER) && 
> >>>>> (LIBRESSL_VERSION_NUMBER >= 0x3030600L))
> >>>>> 
> >>>>>   ocsp->certs = SSL_get0_verified_chain(c->ssl->connection);
> >>>>> 
> >>>> 
> >>>> Testing "defined(LIBRESSL_VERSION_NUMBER)" is superfluous.
> >>>> The macro test suffers from a very long line.
> >>>> 
> >>>> The correct version test seems to be against LibreSSL 3.5.0, see
> >>>> https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.5.0-relnotes.txt
> >>>> 
> >>>> So, the resulting change would be as follows:
> >>>> 
> >>>> diff --git a/src/event/ngx_event_openssl_stapling.c 
> >>>> b/src/event/ngx_event_openssl_stapling.c
> >>>> --- a/src/event/ngx_event_openssl_stapling.c
> >>>> +++ b/src/event/ngx_event_openssl_stapling.c
> >>>> @@ -893,7 +893,9 @@ ngx_ssl_ocsp_validate(ngx_connection_t *
> >>>>ocsp->cert_status = V_OCSP_CERTSTATUS_GOOD;
> >>>>ocsp->conf = ocf;
> >>>> 
> >>>> -#if (OPENSSL_VERSION_NUMBER >= 0x1010L && !defined 
> >>>> LIBRESSL_VERSION_NUMBER)
> >>>> +#if (OPENSSL_VERSION_NUMBER >= 0x1010L \
> >>>> + && !defined LIBRESSL_VERSION_NUMBER) \
> >>>> +|| LIBRESSL_VERSION_NUMBER >= 0x305fL
> >>> 
> >>> Rather, 
> >>> 
> >>> +#if (OPENSSL_VERSION_NUMBER >= 0x1010L   
> >>>  \
> >>> + && (!defined LIBRESSL_VERSION_NUMBER
> >>>  \
> >>> + || LIBRESSL_VERSION_NUMBER >= 0x305fL))
> >>> 
> >> 
> >> Agree.  For the sake of completeness:
> >> 
> >> # HG changeset patch
> >> # User Sergey Kandaurov 
> >> # Date 1703004490 -14400
> >> #  Tue Dec 19 20:48:10 2023 +0400
> >> # Node ID 267cee796462f4f6bacf825c8fd24d13845d36f4
> >> # Parent  7a6d52990f2e2d88460a3dc6cc84aac89b7329ea
> >> SSL: using SSL_get0_verified_chain() with LibreSSL 3.5.0+.
> >> 
> >> Prodded by Ilya Shipitsin.
> >> 
> >> diff --git a/src/event/ngx_event_openssl_stapling.c 
> >> b/src/event/ngx_event_openssl_stapling.c
> >> --- a/src/event/ngx_event_openssl_stapling.c
> >> +++ b/src/event/ngx_event_openssl_stapling.c
> >> @@ -893,7 +893,9 @@ ngx_ssl_ocsp_va

Re: [PATCH] SSL: raised limit for upstream session size

2023-12-22 Thread Maxim Dounin
Hello!

On Fri, Dec 22, 2023 at 06:28:34PM +0400, Sergey Kandaurov wrote:

> # HG changeset patch
> # User Sergey Kandaurov 
> # Date 1703255284 -14400
> #  Fri Dec 22 18:28:04 2023 +0400
> # Node ID a463fb67e143c051fd373d1df94e5813a37d5cea
> # Parent  44266e0651c44f530c4aa66e68c1b9464a9acee7
> SSL: raised limit for upstream session size.
> 
> Unlike shared session cache used to store multiple client SSL sessions and
> which may be per a single SSL connection, sessions saved from upstream are
> per upstream server peer, so there is no such multiplier effect, but they
> may be of noticeably larger size due to session tickets being used.
> 
> It was observed that session tickets sent from JVM backends may result in
> a decoded session size nearly the previous maximum session size limit of
> 4096 or slightly beyond.  Raising the limit allows to save such sessions.

Session tickets are not expected to be larger than sessions 
itself, except by several bytes used for key identification and 
encryption overhead.  I see no reasons why the limit should be 
different in different places.

And 4096 for an SSL session looks a lot.  The only justification I 
can assume here is an SSL session with the client certificate (or 
even certificate chain) being saved into the session.  It might 
worth looking into what actually happens here.

[...]

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH 2 of 2] Win32: extended ngx_random range to 0x7fffffff

2023-12-22 Thread Maxim Dounin
Hello!

On Fri, Dec 22, 2023 at 05:52:30PM +0400, Sergey Kandaurov wrote:

> On Thu, Dec 21, 2023 at 07:14:40PM +0300, Maxim Dounin wrote:
> > Hello!
> > 
> > On Thu, Dec 21, 2023 at 05:37:02PM +0400, Sergey Kandaurov wrote:
> > 
> > > > On 16 Dec 2023, at 06:57, Maxim Dounin  wrote:
> > > > 
> > > > Hello!
> > > > 
> > > > On Sat, Dec 09, 2023 at 08:42:11AM +, J Carter wrote:
> > > > 
> > > >> On Sat, 09 Dec 2023 07:46:10 +
> > > >> J Carter  wrote:
> > > >> 
> > > >>> # HG changeset patch
> > > >>> # User J Carter 
> > > >>> # Date 1702101635 0
> > > >>> #  Sat Dec 09 06:00:35 2023 +
> > > >>> # Node ID 1a77698f82d2580aa8b8f62ce89b4dbb6d678c5d
> > > >>> # Parent  d9275e982a7188a1ea7855295ffa93362ea9830f
> > > >>> Win32: extended ngx_random range to 0x7fff
> > > >>> 
> > > >>> rand() is used on win32. RAND_MAX is implementation defined. win32's 
> > > >>> is
> > > >>> 0x7fff.
> > > >>> 
> > > >>> Existing uses of ngx_random rely upon 0x7fff range provided by
> > > >>> posix implementations of random().
> > > >>> 
> > > >>> diff -r d9275e982a71 -r 1a77698f82d2 src/os/win32/ngx_win32_config.h
> > > >>> --- a/src/os/win32/ngx_win32_config.h Sat Dec 09 05:09:07 2023 +
> > > >>> +++ b/src/os/win32/ngx_win32_config.h Sat Dec 09 06:00:35 2023 +
> > > >>> @@ -280,7 +280,9 @@
> > > >>> 
> > > >>> #define NGX_HAVE_GETADDRINFO 1
> > > >>> 
> > > >>> -#define ngx_random   rand
> > > >>> +#define ngx_random   
> > > >>>   \
> > > >>> +((rand() << 16) | (rand() << 1) | (rand() >> 14))
> > > >>> +
> > > >>> #define ngx_debug_init()
> > > >>> 
> > > >>> 
> > > >> 
> > > >> ^ my mistake - copying error..
> > > >> 
> > > >> # HG changeset patch
> > > >> # User J Carter 
> > > >> # Date 1702111094 0
> > > >> #  Sat Dec 09 08:38:14 2023 +
> > > >> # Node ID 10ef59a412a330872fc6d46de64f42e32e997b3a
> > > >> # Parent  d9275e982a7188a1ea7855295ffa93362ea9830f
> > > >> Win32: extended ngx_random range to 0x7fff
> > > > 
> > > > Nitpicking:
> > > > 
> > > > Win32: extended ngx_random() range to 0x7fff.
> > > > 
> > > >> 
> > > >> rand() is used on win32. RAND_MAX is implementation defined. win32's is
> > > >> 0x7fff.
> > > >> 
> > > >> Existing uses of ngx_random rely upon 0x7fff range provided by
> > > >> posix implementations of random().
> > > > 
> > > > Thanks for catching this.
> > > > 
> > > > As far as I can see, the only module which actually relies on the 
> > > > range is the random index module.  Relying on the ngx_random() 
> > > > range generally looks wrong to me, and we might want to change the 
> > > > code to don't.  OTOH, it's the only way to get a completely 
> > > > uniform distribution, and that's what the module tries to do.  As 
> > > > such, it might be good enough to preserve it as is, at least till 
> > > > further changes to ngx_random().
> > > > 
> > > > Either way, wider range for ngx_random() should be beneficial in 
> > > > other places.
> > > > 
> > > >> 
> > > >> diff -r d9275e982a71 -r 10ef59a412a3 src/os/win32/ngx_win32_config.h
> > > >> --- a/src/os/win32/ngx_win32_config.h  Sat Dec 09 05:09:07 2023 +
> > > >> +++ b/src/os/win32/ngx_win32_config.h  Sat Dec 09 08:38:14 2023 +
> > > >> @@ -280,7 +280,9 @@
> > > >> 
> > > >> #define NGX_HAVE_GETADDRINFO 1
> > > >> 
> > > >> -#define ngx_random   rand
> > > >> +#define ngx_random()  
> > > >>\
> > > > 
> > > > Nitpicking: the "\" character should be a

Re: [PATCH 2 of 2] Win32: extended ngx_random range to 0x7fffffff

2023-12-21 Thread Maxim Dounin
Hello!

On Thu, Dec 21, 2023 at 05:37:02PM +0400, Sergey Kandaurov wrote:

> > On 16 Dec 2023, at 06:57, Maxim Dounin  wrote:
> > 
> > Hello!
> > 
> > On Sat, Dec 09, 2023 at 08:42:11AM +, J Carter wrote:
> > 
> >> On Sat, 09 Dec 2023 07:46:10 +
> >> J Carter  wrote:
> >> 
> >>> # HG changeset patch
> >>> # User J Carter 
> >>> # Date 1702101635 0
> >>> #  Sat Dec 09 06:00:35 2023 +
> >>> # Node ID 1a77698f82d2580aa8b8f62ce89b4dbb6d678c5d
> >>> # Parent  d9275e982a7188a1ea7855295ffa93362ea9830f
> >>> Win32: extended ngx_random range to 0x7fff
> >>> 
> >>> rand() is used on win32. RAND_MAX is implementation defined. win32's is
> >>> 0x7fff.
> >>> 
> >>> Existing uses of ngx_random rely upon 0x7fff range provided by
> >>> posix implementations of random().
> >>> 
> >>> diff -r d9275e982a71 -r 1a77698f82d2 src/os/win32/ngx_win32_config.h
> >>> --- a/src/os/win32/ngx_win32_config.h Sat Dec 09 05:09:07 2023 +
> >>> +++ b/src/os/win32/ngx_win32_config.h Sat Dec 09 06:00:35 2023 +
> >>> @@ -280,7 +280,9 @@
> >>> 
> >>> #define NGX_HAVE_GETADDRINFO 1
> >>> 
> >>> -#define ngx_random   rand
> >>> +#define ngx_random   
> >>>   \
> >>> +((rand() << 16) | (rand() << 1) | (rand() >> 14))
> >>> +
> >>> #define ngx_debug_init()
> >>> 
> >>> 
> >> 
> >> ^ my mistake - copying error..
> >> 
> >> # HG changeset patch
> >> # User J Carter 
> >> # Date 1702111094 0
> >> #  Sat Dec 09 08:38:14 2023 +
> >> # Node ID 10ef59a412a330872fc6d46de64f42e32e997b3a
> >> # Parent  d9275e982a7188a1ea7855295ffa93362ea9830f
> >> Win32: extended ngx_random range to 0x7fff
> > 
> > Nitpicking:
> > 
> > Win32: extended ngx_random() range to 0x7fff.
> > 
> >> 
> >> rand() is used on win32. RAND_MAX is implementation defined. win32's is
> >> 0x7fff.
> >> 
> >> Existing uses of ngx_random rely upon 0x7fff range provided by
> >> posix implementations of random().
> > 
> > Thanks for catching this.
> > 
> > As far as I can see, the only module which actually relies on the 
> > range is the random index module.  Relying on the ngx_random() 
> > range generally looks wrong to me, and we might want to change the 
> > code to don't.  OTOH, it's the only way to get a completely 
> > uniform distribution, and that's what the module tries to do.  As 
> > such, it might be good enough to preserve it as is, at least till 
> > further changes to ngx_random().
> > 
> > Either way, wider range for ngx_random() should be beneficial in 
> > other places.
> > 
> >> 
> >> diff -r d9275e982a71 -r 10ef59a412a3 src/os/win32/ngx_win32_config.h
> >> --- a/src/os/win32/ngx_win32_config.h  Sat Dec 09 05:09:07 2023 +
> >> +++ b/src/os/win32/ngx_win32_config.h  Sat Dec 09 08:38:14 2023 +
> >> @@ -280,7 +280,9 @@
> >> 
> >> #define NGX_HAVE_GETADDRINFO 1
> >> 
> >> -#define ngx_random   rand
> >> +#define ngx_random()  
> >>\
> > 
> > Nitpicking: the "\" character should be at the 79th column (in 
> > some files at 78th).  This ensures that a diff won't wrap on a 
> > standard 80-column terminal.
> > 
> >> +((rand() << 16) | (rand() << 1) | (rand() >> 14))
> >> +
> >> #define ngx_debug_init()
> > 
> > Using "|" for random numbers looks utterly wrong to me, even if 
> > ORed values are guaranteed to not interfere.
> > 
> > I would rather use "^", and avoid dependency on the particular 
> > value of RAND_MAX (other than POSIX-required minimum of 32767) by 
> > using something like
> > 
> >   0x7fff & ((rand() << 16) ^ (rand() << 8) ^ rand())
> > 
> > with proper typecasts.
> > 
> > Something like this should work:
> > 
> > diff --git a/src/os/win32/ngx_win32_config.h 
> > b/src/os/win32/ngx_win32_config.h
> > --- a/src/os/win32/ngx_win32_config.h
> > +++ b/src/os/win32/ngx_win32_config.h
> > @@ -280,7 +280,11 @@ typedef int

Re: processing a request without body

2023-12-20 Thread Maxim Dounin
Hello!

On Tue, Dec 19, 2023 at 10:11:04PM +0800, Muhammad Nuzaihan wrote:

> Thanks Maxim, Vasility,
> 
> The problem i was going to solve is to i needed to run my specific
> function that takes  the data of request URL path, Headers and request
> body and determine and validate that all that data is correct before
> sending upstream, or else i would deny the request with 4xx code
> errors.
> 
> Handlers can only handle (from what i know) URL path and headers.
> 
> Request body requires a request chain (ngx_chain_t)) to piece out the
> request body and handlers doesn't seem to have t ngx_chain_t unlike
> request body filters.
> 
> Or maybe i am wrong in this case?

It looks like you are trying to do something which simply cannot 
be done.  For example, consider a configuration with 
"proxy_request_buffering off;" - in such a configuration request 
body is being read _after_ the request is passed to the upstream 
server, and you simply cannot validate request body before passing 
request headers to the upstream server.

As long as you have to examine both request body and request 
headers, I think there can be two possible solutions:

1. Install a phase handler, in which read the request body 
yourself, and check both request headers and request body once 
it's read.  See the mirror module as an example on how to read the 
body in a phase handler and properly resume processing after it.  
This will break proxying without request buffering, though might 
be good enough for your particular task.

2. Install a phase handler to check request headers, and a request 
body filter to check the request body.  Do checking in both 
places, and abort request processing when you see that data aren't 
correct.  This will work with proxying without request buffering, 
but will be generally more complex to implement.  And, obviously, 
this in case of proxying without request buffering this won't let 
you to validate request body before the request headers are sent 
to upstream server.

Hope this helps.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: Core: Avoid memcpy from NULL

2023-12-20 Thread Maxim Dounin
Hello!

On Sat, Dec 16, 2023 at 04:26:37PM -0500, Ben Kallus wrote:

> > In general macro definitions in nginx are used everywhere for
> > efficiency reasons
> 
> Clang inlines short functions with -O1, and GCC does so with -O2 or
> -O1 -finline-small-functions. Are there any platforms that Nginx needs
> to support for which short function inlining isn't sufficient to solve
> this issue?

In nginx, functions expected to be inlined are marked with 
"ngx_inline", which normally resolves to "inline" (on unix) or 
"__inline" (on win32).  As such, modern versions of both clang and 
gcc will inline corresponding functions unless optimization is 
disabled.

Still, -O0 is often used at least during development, and it might 
be unreasonable to introduce extra function calls in basic 
primitives.

Further, nginx generally supports all available platforms 
reasonably compatible with POSIX and C89.  This implies that 
inline might be not available.

> > While some might prefer other approaches, writing code like
> > "ngx_memcpy(dst, src, ++len)" in nginx is just wrong, and
> > shouldn't be trusted to work, much like it won't work with
> > "ngx_cpymem(dst, src, ++len)".
> 
> It is indeed wrong to use an expression with a side-effect in an
> argument to cpymem, but it's also not very obvious that it's wrong. An
> inlined function solves the argument reevaluation issue without
> performance overhead.

Sure (but see above about performance overhead; and another 
question is if it needs to be solved, or following existing style 
is enough to never see the issue).

The point is: in nginx, it's anyway wrong to use arguments with 
side effects.  And even expressions without side effects might 
won't work.  While many macro definitions were adjusted to accept 
expressions instead of the bare variables (see 2f9214713666 and 
https://mailman.nginx.org/pipermail/nginx-devel/2020-July/013354.html 
for an example), some still don't or can be picky.  For example, 
good luck with doing something like "ngx_max(foo & 0xff, bar)".

As such, it's certainly not an argument against using checks in 
macro definitions in the particular patch.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] ssl: SSL_get0_verified_chain is available for LibreSSL >= 3.3.6

2023-12-20 Thread Maxim Dounin
Hello!

On Tue, Dec 19, 2023 at 10:44:00PM +0400, Sergey Kandaurov wrote:

> 
> > On 19 Dec 2023, at 12:58, Maxim Dounin  wrote:
> > 
> > Hello!
> > 
> > On Tue, Dec 19, 2023 at 02:09:10AM +0400, Sergey Kandaurov wrote:
> > 
> >>> On 24 Nov 2023, at 00:29, Ilya Shipitsin  wrote:
> >>> 
> >>> # HG changeset patch
> >>> # User Ilya Shipitsin 
> >>> # Date 1700769135 -3600
> >>> #  Thu Nov 23 20:52:15 2023 +0100
> >>> # Node ID 2001e73ce136d5bfc9bde27d338865b14b8ad436
> >>> # Parent  7ec761f0365f418511e30b82e9adf80bc56681df
> >>> ssl: SSL_get0_verified_chain is available for LibreSSL >= 3.3.6
> >> 
> >> style: SSL prefix should be uppercase.
> >> 
> >>> 
> >>> diff -r 7ec761f0365f -r 2001e73ce136 
> >>> src/event/ngx_event_openssl_stapling.c
> >>> --- a/src/event/ngx_event_openssl_stapling.c  Thu Oct 26 23:35:09 
> >>> 2023 +0300
> >>> +++ b/src/event/ngx_event_openssl_stapling.c  Thu Nov 23 20:52:15 
> >>> 2023 +0100
> >>> @@ -893,7 +893,8 @@
> >>>ocsp->cert_status = V_OCSP_CERTSTATUS_GOOD;
> >>>ocsp->conf = ocf;
> >>> 
> >>> -#if (OPENSSL_VERSION_NUMBER >= 0x1010L && !defined 
> >>> LIBRESSL_VERSION_NUMBER)
> >>> +/* minimum OpenSSL 1.1.1 & LibreSSL 3.3.6 */
> >>> +#if (OPENSSL_VERSION_NUMBER >= 0x1010L && !defined 
> >>> LIBRESSL_VERSION_NUMBER) || (defined(LIBRESSL_VERSION_NUMBER) && 
> >>> (LIBRESSL_VERSION_NUMBER >= 0x3030600L))
> >>> 
> >>>ocsp->certs = SSL_get0_verified_chain(c->ssl->connection);
> >>> 
> >> 
> >> Testing "defined(LIBRESSL_VERSION_NUMBER)" is superfluous.
> >> The macro test suffers from a very long line.
> >> 
> >> The correct version test seems to be against LibreSSL 3.5.0, see
> >> https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.5.0-relnotes.txt
> >> 
> >> So, the resulting change would be as follows:
> >> 
> >> diff --git a/src/event/ngx_event_openssl_stapling.c 
> >> b/src/event/ngx_event_openssl_stapling.c
> >> --- a/src/event/ngx_event_openssl_stapling.c
> >> +++ b/src/event/ngx_event_openssl_stapling.c
> >> @@ -893,7 +893,9 @@ ngx_ssl_ocsp_validate(ngx_connection_t *
> >> ocsp->cert_status = V_OCSP_CERTSTATUS_GOOD;
> >> ocsp->conf = ocf;
> >> 
> >> -#if (OPENSSL_VERSION_NUMBER >= 0x1010L && !defined 
> >> LIBRESSL_VERSION_NUMBER)
> >> +#if (OPENSSL_VERSION_NUMBER >= 0x1010L \
> >> + && !defined LIBRESSL_VERSION_NUMBER) \
> >> +|| LIBRESSL_VERSION_NUMBER >= 0x305fL
> > 
> > Rather, 
> > 
> > +#if (OPENSSL_VERSION_NUMBER >= 0x1010L 
> >\
> > + && (!defined LIBRESSL_VERSION_NUMBER  
> >\
> > + || LIBRESSL_VERSION_NUMBER >= 0x305fL))
> > 
> 
> Agree.  For the sake of completeness:
> 
> # HG changeset patch
> # User Sergey Kandaurov 
> # Date 1703004490 -14400
> #  Tue Dec 19 20:48:10 2023 +0400
> # Node ID 267cee796462f4f6bacf825c8fd24d13845d36f4
> # Parent  7a6d52990f2e2d88460a3dc6cc84aac89b7329ea
> SSL: using SSL_get0_verified_chain() with LibreSSL 3.5.0+.
> 
> Prodded by Ilya Shipitsin.
> 
> diff --git a/src/event/ngx_event_openssl_stapling.c 
> b/src/event/ngx_event_openssl_stapling.c
> --- a/src/event/ngx_event_openssl_stapling.c
> +++ b/src/event/ngx_event_openssl_stapling.c
> @@ -893,7 +893,9 @@ ngx_ssl_ocsp_validate(ngx_connection_t *
>  ocsp->cert_status = V_OCSP_CERTSTATUS_GOOD;
>  ocsp->conf = ocf;
>  
> -#if (OPENSSL_VERSION_NUMBER >= 0x1010L && !defined 
> LIBRESSL_VERSION_NUMBER)
> +#if (OPENSSL_VERSION_NUMBER >= 0x1010L   
>  \
> + && (!defined LIBRESSL_VERSION_NUMBER
>  \
> + || LIBRESSL_VERSION_NUMBER >= 0x305fL))
>  
>  ocsp->certs = SSL_get0_verified_chain(c->ssl->connection);
>  
> 
> >> 
> >> ocsp->certs = SSL_get0_verified_chain(c->ssl->connection);
> >> 
> >> 
> >> On the other hand, I don't like the resulting style mudness.
> >> It may have sense just to drop old LibreSSL versions support:
> >> maintaining one or two m

Re: [PATCH] ssl: SSL_get0_verified_chain is available for LibreSSL >= 3.3.6

2023-12-19 Thread Maxim Dounin
Hello!

On Tue, Dec 19, 2023 at 12:16:58PM +0100, Илья Шипицин wrote:

> вт, 19 дек. 2023 г. в 09:58, Maxim Dounin :
> 
> > Hello!
> >
> > On Tue, Dec 19, 2023 at 02:09:10AM +0400, Sergey Kandaurov wrote:
> >
> > > > On 24 Nov 2023, at 00:29, Ilya Shipitsin  wrote:
> > > >
> > > > # HG changeset patch
> > > > # User Ilya Shipitsin 
> > > > # Date 1700769135 -3600
> > > > #  Thu Nov 23 20:52:15 2023 +0100
> > > > # Node ID 2001e73ce136d5bfc9bde27d338865b14b8ad436
> > > > # Parent  7ec761f0365f418511e30b82e9adf80bc56681df
> > > > ssl: SSL_get0_verified_chain is available for LibreSSL >= 3.3.6
> > >
> > > style: SSL prefix should be uppercase.
> > >
> > > >
> > > > diff -r 7ec761f0365f -r 2001e73ce136
> > src/event/ngx_event_openssl_stapling.c
> > > > --- a/src/event/ngx_event_openssl_stapling.cThu Oct 26
> > 23:35:09 2023 +0300
> > > > +++ b/src/event/ngx_event_openssl_stapling.cThu Nov 23
> > 20:52:15 2023 +0100
> > > > @@ -893,7 +893,8 @@
> > > > ocsp->cert_status = V_OCSP_CERTSTATUS_GOOD;
> > > > ocsp->conf = ocf;
> > > >
> > > > -#if (OPENSSL_VERSION_NUMBER >= 0x1010L && !defined
> > LIBRESSL_VERSION_NUMBER)
> > > > +/* minimum OpenSSL 1.1.1 & LibreSSL 3.3.6 */
> > > > +#if (OPENSSL_VERSION_NUMBER >= 0x1010L && !defined
> > LIBRESSL_VERSION_NUMBER) || (defined(LIBRESSL_VERSION_NUMBER) &&
> > (LIBRESSL_VERSION_NUMBER >= 0x3030600L))
> > > >
> > > > ocsp->certs = SSL_get0_verified_chain(c->ssl->connection);
> > > >
> > >
> > > Testing "defined(LIBRESSL_VERSION_NUMBER)" is superfluous.
> > > The macro test suffers from a very long line.
> > >
> > > The correct version test seems to be against LibreSSL 3.5.0, see
> > > https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.5.0-relnotes.txt
> > >
> > > So, the resulting change would be as follows:
> > >
> > > diff --git a/src/event/ngx_event_openssl_stapling.c
> > b/src/event/ngx_event_openssl_stapling.c
> > > --- a/src/event/ngx_event_openssl_stapling.c
> > > +++ b/src/event/ngx_event_openssl_stapling.c
> > > @@ -893,7 +893,9 @@ ngx_ssl_ocsp_validate(ngx_connection_t *
> > >  ocsp->cert_status = V_OCSP_CERTSTATUS_GOOD;
> > >  ocsp->conf = ocf;
> > >
> > > -#if (OPENSSL_VERSION_NUMBER >= 0x1010L && !defined
> > LIBRESSL_VERSION_NUMBER)
> > > +#if (OPENSSL_VERSION_NUMBER >= 0x1010L \
> > > + && !defined LIBRESSL_VERSION_NUMBER) \
> > > +|| LIBRESSL_VERSION_NUMBER >= 0x305fL
> >
> > Rather,
> >
> > +#if (OPENSSL_VERSION_NUMBER >= 0x1010L
> > \
> > + && (!defined LIBRESSL_VERSION_NUMBER
> >  \
> > + || LIBRESSL_VERSION_NUMBER >= 0x305fL))
> >
> > >
> > >  ocsp->certs = SSL_get0_verified_chain(c->ssl->connection);
> > >
> > >
> > > On the other hand, I don't like the resulting style mudness.
> > > It may have sense just to drop old LibreSSL versions support:
> > > maintaining one or two most recent stable branches should be enough.
> >
> > +1 on this.
> >
> 
> if we want to keep code clean, we can move "if LibreSSL >= 3.7" to
> "configure" level

I wouldn't expect such a change to be accepted.  We generally 
don't try to test various SSL library features in configure - 
there are a lot of things to check, and testing appropriate 
defines (or version numbers, if no defines are available) is 
believed to work much better.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: Meaning of proxy_ignore_client_abort

2023-12-19 Thread Maxim Dounin
Hello!

On Tue, Dec 19, 2023 at 04:02:46PM +0100, Jan Prachař wrote:

> Hello,
> 
> I have proxy module configured with proxy_ignore_client_abort on; but 
> connection to
> upstream is still being closed. This is in debug log:
> 
>  writev() failed (32: Broken pipe) while sending to client, ...
>  http write filter 
>  http copy filter: -1 ...
>  pipe read upstream: 0
>  pipe buf free s:0 t:1 f:0 55DEBEF95EC0, pos 55DEBEF95EC0, size: 473 
> file: 0,
> size: 0
>  pipe buf free s:0 t:1 f:0 55DEBEF91EB0, pos 55DEBEF91EB0, size: 0 
> file: 0, size:
> 0
>  pipe length: 22594336
>  event timer: 23, old: 15583745, new: 15583837
>  http upstream downstream error
>  finalize http upstream request: -1
>  finalize http proxy request
>  close http upstream connection: 23
> 
> It seems, that check if ignore_client_abort is on, is missing here: 
> https://trac.nginx.org/nginx/browser/nginx/src/http/ngx_http_upstream.c#L4223
> 
> Or is there any reason why the connection is closed regardless the 
> ignore_client_abort?

When an error while sending to the client occurs, like in the log 
you've provided, the connection is closed regardless of the 
"proxy_ignore_client_abort" directive.  The directive only 
affects nginx behaviour when nginx is waiting for a response from 
the upstream server: with "proxy_ignore_client_abort on;" nginx 
will not try to detect if the client already closed the 
connection and close the upstream connection accordingly.  When 
the response is being sent, the upstream server is expected to be 
smart enough to recognize that the connection was closed.

Note that the docs say 
(http://nginx.org/r/proxy_ignore_client_abort):

: Determines whether the connection with a proxied server should 
: be closed when a client closes the connection without waiting for 
: a response.

While it probably can be improved, it explicitly says "without 
waiting for a response", and nothing about "when reading a 
response".

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] ssl: SSL_get0_verified_chain is available for LibreSSL >= 3.3.6

2023-12-19 Thread Maxim Dounin
Hello!

On Tue, Dec 19, 2023 at 02:09:10AM +0400, Sergey Kandaurov wrote:

> > On 24 Nov 2023, at 00:29, Ilya Shipitsin  wrote:
> > 
> > # HG changeset patch
> > # User Ilya Shipitsin 
> > # Date 1700769135 -3600
> > #  Thu Nov 23 20:52:15 2023 +0100
> > # Node ID 2001e73ce136d5bfc9bde27d338865b14b8ad436
> > # Parent  7ec761f0365f418511e30b82e9adf80bc56681df
> > ssl: SSL_get0_verified_chain is available for LibreSSL >= 3.3.6
> 
> style: SSL prefix should be uppercase.
> 
> > 
> > diff -r 7ec761f0365f -r 2001e73ce136 src/event/ngx_event_openssl_stapling.c
> > --- a/src/event/ngx_event_openssl_stapling.cThu Oct 26 23:35:09 
> > 2023 +0300
> > +++ b/src/event/ngx_event_openssl_stapling.cThu Nov 23 20:52:15 
> > 2023 +0100
> > @@ -893,7 +893,8 @@
> > ocsp->cert_status = V_OCSP_CERTSTATUS_GOOD;
> > ocsp->conf = ocf;
> > 
> > -#if (OPENSSL_VERSION_NUMBER >= 0x1010L && !defined 
> > LIBRESSL_VERSION_NUMBER)
> > +/* minimum OpenSSL 1.1.1 & LibreSSL 3.3.6 */
> > +#if (OPENSSL_VERSION_NUMBER >= 0x1010L && !defined 
> > LIBRESSL_VERSION_NUMBER) || (defined(LIBRESSL_VERSION_NUMBER) && 
> > (LIBRESSL_VERSION_NUMBER >= 0x3030600L))
> > 
> > ocsp->certs = SSL_get0_verified_chain(c->ssl->connection);
> > 
> 
> Testing "defined(LIBRESSL_VERSION_NUMBER)" is superfluous.
> The macro test suffers from a very long line.
> 
> The correct version test seems to be against LibreSSL 3.5.0, see
> https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.5.0-relnotes.txt
> 
> So, the resulting change would be as follows:
> 
> diff --git a/src/event/ngx_event_openssl_stapling.c 
> b/src/event/ngx_event_openssl_stapling.c
> --- a/src/event/ngx_event_openssl_stapling.c
> +++ b/src/event/ngx_event_openssl_stapling.c
> @@ -893,7 +893,9 @@ ngx_ssl_ocsp_validate(ngx_connection_t *
>  ocsp->cert_status = V_OCSP_CERTSTATUS_GOOD;
>  ocsp->conf = ocf;
>  
> -#if (OPENSSL_VERSION_NUMBER >= 0x1010L && !defined 
> LIBRESSL_VERSION_NUMBER)
> +#if (OPENSSL_VERSION_NUMBER >= 0x1010L \
> + && !defined LIBRESSL_VERSION_NUMBER) \
> +|| LIBRESSL_VERSION_NUMBER >= 0x305fL

Rather, 

+#if (OPENSSL_VERSION_NUMBER >= 0x1010L\
+ && (!defined LIBRESSL_VERSION_NUMBER \
+ || LIBRESSL_VERSION_NUMBER >= 0x305fL))

>  
>  ocsp->certs = SSL_get0_verified_chain(c->ssl->connection);
>  
> 
> On the other hand, I don't like the resulting style mudness.
> It may have sense just to drop old LibreSSL versions support:
> maintaining one or two most recent stable branches should be enough.

+1 on this.

We certainly don't want to maintain support for ancient LibreSSL 
versions.  IMO, just two branches is more than enough (and this is 
what I use in my testing, which usually means latest development 
release and latest stable release).

At most, this probably can be three branches - which seems to 
match LibreSSL support policy, 
https://www.libressl.org/releases.html:

: LibreSSL transitions to a new stable release branch every 6 months 
: in coordination with the OpenBSD development schedule. LibreSSL 
: stable branches are updated for 1 year after their corresponding 
: OpenBSD branch is tagged for release. See below for the current 
: stable release branches.

In either case, LibreSSL versions below 3.5.0 are already not 
supported.  If I understand correctly, right now the oldest 
supported branch is 3.7.x.

> But anyway, I don't see an obvious win over the existing code:
> the certificate chain is reconstructed if SSL_get0_verified_chain()
> is (detected to be) not present, which should be fine in most cases.
> 
> That said, it doesn't seem to deserve introducing 3-line macro test,
> or (see OTOH note) breaking old LibreSSL support for no apparent reason.

Reconstruction of the chain implies verification of signatures 
along the chain and can be costly.  As such, it certainly would be 
better to use SSL_get0_verified_chain() as long as it is 
available.

Also, removing the "!defined LIBRESSL_VERSION_NUMBER" check might 
be seen as positive even without any additional benefits.

Along with that, however, we might want to adjust the 
LIBRESSL_VERSION_NUMBER check in the ngx_event_openssl.h file, so 
OPENSSL_VERSION_NUMBER is set to a better value for old LibreSSL 
versions - for example, to only set OPENSSL_VERSION_NUMBER to 
0x101fL for LibreSSL 3.5.0 or above.  This might allow to 
preserve limited compatibility with ancient LibreSSL versions 
without additional efforts (not tested though).

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: Core: Avoid memcpy from NULL

2023-12-15 Thread Maxim Dounin
Hello!

On Fri, Dec 15, 2023 at 03:46:19PM +0100, Dipl. Ing. Sergey Brester via 
nginx-devel wrote:

> Enclosed few thoughts to the subject:
> 
> - since it is very rare situation that one needs only a memcpy without 
> to know whether previous alloc may fail
>(e. g. some of pointers were NULL), me too thinks that the caller 
> should be responsible for the check.
>So I would not extend ngx_memcpy or ngx_cpymem in that way.

That's not about failed allocations, it's about ability to work 
with empty strings which aren't explicitly set to something other 
than { 0, NULL }.  And you may refer to Vladimir's patch I've 
referenced to find out what it means in terms of the "caller 
should be responsible" approach even without trying to look into 
places not explicitly reported by the UB sanitizer.

https://mailman.nginx.org/pipermail/nginx-devel/2023-October/PX7VH5A273NLUGSYC7DR2AZRU75CIQ3Q.html
https://mailman.nginx.org/pipermail/nginx-devel/2023-December/DCGUEGEFS6TSVIWNEWUEZO3FZMR6ESYZ.html

> - rewrite of `ngx_memcpy` define like here:
>```
>+ #define ngx_memcpy(dst, src, n) (void) ((n) == 0 ? (dst) : 
> memcpy(dst, src, n))
>```
>may introduce a regression or compat issues, e. g. fully functioning 
> codes like that may become broken hereafter:
>```
>ngx_memcpy(dst, src, ++len); // because n would be incremented twice 
> in the macro now
>```
>Sure, `ngx_cpymem` has also the same issue, but it had that already 
> before the "fix"...
>Anyway, I'm always against of such macros (no matter with or without 
> check it would be better as an inline function instead).

In general macro definitions in nginx are used everywhere for 
efficiency reasons, and macro definitions usually aren't safe.  
While some might prefer other approaches, writing code like 
"ngx_memcpy(dst, src, ++len)" in nginx is just wrong, and 
shouldn't be trusted to work, much like it won't work with 
"ngx_cpymem(dst, src, ++len)".

I'm not exactly against using inline functions here, but the 
particular argument is at most very weak. 

> My conclusion:
>a fix of affected places invoking `ngx_memcpy` and `ngx_cpymem`, and 
> possibly an assert in `ngx_memcpy`
>and `ngx_cpymem` would be fully enough, in my opinion.

Well, thank you for your opinion, appreciated.  I don't think this 
approach is going to work though, see my review of Vladimir's 
patch.

Ideally, I would prefer this to be fixed in the C standard (and 
GCC).  But given this is not a likely option, and there is a 
constant stream of reports "hey, UB sanitizer reports about 
memcpy(dst, NULL, 0) in nginx" we might consider actually 
silencing this by introducing appropriate checks at the interface 
level.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH 2 of 2] Win32: extended ngx_random range to 0x7fffffff

2023-12-15 Thread Maxim Dounin
Hello!

On Sat, Dec 09, 2023 at 08:42:11AM +, J Carter wrote:

> On Sat, 09 Dec 2023 07:46:10 +
> J Carter  wrote:
> 
> > # HG changeset patch
> > # User J Carter 
> > # Date 1702101635 0
> > #  Sat Dec 09 06:00:35 2023 +
> > # Node ID 1a77698f82d2580aa8b8f62ce89b4dbb6d678c5d
> > # Parent  d9275e982a7188a1ea7855295ffa93362ea9830f
> > Win32: extended ngx_random range to 0x7fff
> > 
> > rand() is used on win32. RAND_MAX is implementation defined. win32's is
> > 0x7fff.
> > 
> > Existing uses of ngx_random rely upon 0x7fff range provided by
> > posix implementations of random().
> > 
> > diff -r d9275e982a71 -r 1a77698f82d2 src/os/win32/ngx_win32_config.h
> > --- a/src/os/win32/ngx_win32_config.h   Sat Dec 09 05:09:07 2023 +
> > +++ b/src/os/win32/ngx_win32_config.h   Sat Dec 09 06:00:35 2023 +
> > @@ -280,7 +280,9 @@
> >  
> >  #define NGX_HAVE_GETADDRINFO 1
> >  
> > -#define ngx_random   rand
> > +#define ngx_random 
> > \
> > +((rand() << 16) | (rand() << 1) | (rand() >> 14))
> > +
> >  #define ngx_debug_init()
> >  
> >  
> 
> ^ my mistake - copying error..
> 
> # HG changeset patch
> # User J Carter 
> # Date 1702111094 0
> #  Sat Dec 09 08:38:14 2023 +
> # Node ID 10ef59a412a330872fc6d46de64f42e32e997b3a
> # Parent  d9275e982a7188a1ea7855295ffa93362ea9830f
> Win32: extended ngx_random range to 0x7fff

Nitpicking:

Win32: extended ngx_random() range to 0x7fff.

> 
> rand() is used on win32. RAND_MAX is implementation defined. win32's is
> 0x7fff.
> 
> Existing uses of ngx_random rely upon 0x7fff range provided by
> posix implementations of random().

Thanks for catching this.

As far as I can see, the only module which actually relies on the 
range is the random index module.  Relying on the ngx_random() 
range generally looks wrong to me, and we might want to change the 
code to don't.  OTOH, it's the only way to get a completely 
uniform distribution, and that's what the module tries to do.  As 
such, it might be good enough to preserve it as is, at least till 
further changes to ngx_random().

Either way, wider range for ngx_random() should be beneficial in 
other places.

> 
> diff -r d9275e982a71 -r 10ef59a412a3 src/os/win32/ngx_win32_config.h
> --- a/src/os/win32/ngx_win32_config.h Sat Dec 09 05:09:07 2023 +
> +++ b/src/os/win32/ngx_win32_config.h Sat Dec 09 08:38:14 2023 +
> @@ -280,7 +280,9 @@
>  
>  #define NGX_HAVE_GETADDRINFO 1
>  
> -#define ngx_random   rand
> +#define ngx_random() 
> \

Nitpicking: the "\" character should be at the 79th column (in 
some files at 78th).  This ensures that a diff won't wrap on a 
standard 80-column terminal.

> +((rand() << 16) | (rand() << 1) | (rand() >> 14))
> +
>  #define ngx_debug_init()

Using "|" for random numbers looks utterly wrong to me, even if 
ORed values are guaranteed to not interfere.

I would rather use "^", and avoid dependency on the particular 
value of RAND_MAX (other than POSIX-required minimum of 32767) by 
using something like

   0x7fff & ((rand() << 16) ^ (rand() << 8) ^ rand())

with proper typecasts.

Something like this should work:

diff --git a/src/os/win32/ngx_win32_config.h b/src/os/win32/ngx_win32_config.h
--- a/src/os/win32/ngx_win32_config.h
+++ b/src/os/win32/ngx_win32_config.h
@@ -280,7 +280,11 @@ typedef int sig_atomic_t
 
 #define NGX_HAVE_GETADDRINFO 1
 
-#define ngx_random       rand
+#define ngx_random()  \
+((long) (0x7fff & ( ((uint32_t) rand() << 16) \
+  ^ ((uint32_t) rand() << 8)  \
+  ^ ((uint32_t) rand()) )))
+
 #define ngx_debug_init()
 
 

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] Add ssl_client_tls_bind variable

2023-12-15 Thread Maxim Dounin
Hello!

On Fri, Dec 15, 2023 at 06:02:45PM +1100, Rob Casey wrote:

> First time caller, long time listener.
> 
> This patch introduces the variable $ssl_client_tls_bind which provides the
> last Finished message returned by the OpenSSL SSL_get_peer_finished()
> function. The value returned by this function may be used in TLS channel
> binding operations as described in RFC 5929
> <https://datatracker.ietf.org/doc/html/rfc5929> (TLSv1.2) and RFC 9266
> <https://datatracker.ietf.org/doc/html/rfc9266> (TLSv1.3). The bytes
> returned by this function are base64-encoded for ease-of-use as per
> suggestion on Nginx forum thread
> <https://forum.nginx.org/read.php?10,286777>.

You might be interested in a previous attempt to introduce similar 
variables, here:

https://mailman.nginx.org/pipermail/nginx-devel/2021-May/014082.html
https://mailman.nginx.org/pipermail/nginx-devel/2021-June/014090.html

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: Core: Avoid memcpy from NULL

2023-12-14 Thread Maxim Dounin
Hello!

On Wed, Dec 13, 2023 at 11:09:28AM -0500, Ben Kallus wrote:

> Nginx executes numerous `memcpy`s from NULL during normal execution.
> `memcpy`ing to or from NULL is undefined behavior. Accordingly, some
> compilers (gcc -O2) make optimizations that assume `memcpy` arguments
> are not NULL. Nginx with UBSan crashes during startup due to this
> issue.
> 
> Consider the following function:
> ```C
> #include 
> 
> int f(int i) {
> char a[] = {'a'};
> void *src = i ? a : NULL;
> char dst[1];
> memcpy(dst, src, 0);
> return src == NULL;
> }
> ```
> Here's what gcc13.2 -O2 -fno-builtin will do to it:
> ```asm
> f:
> sub rsp, 24
> xor eax, eax
> testedi, edi
> lea rsi, [rsp+14]
> lea rdi, [rsp+15]
> mov BYTE PTR [rsp+14], 97
> cmove   rsi, rax
> xor edx, edx
> callmemcpy
> xor eax, eax
> add rsp, 24
> ret
> ```
> Note that `f` always returns 0, regardless of the value of `i`.
> 
> Feel free to try for yourself at https://gcc.godbolt.org/z/zfvnMMsds
> 
> The reasoning here is that since memcpy from NULL is UB, the optimizer
> is free to assume that `src` is non-null. You might consider this to
> be a problem with the compiler, or the C standard, and I might agree.
> Regardless, relying on UB is inherently un-portable, and requires
> maintenance to ensure that new compiler releases don't break existing
> assumptions about the behavior of undefined operations.
> 
> The following patch adds a check to `ngx_memcpy` and `ngx_cpymem` that
> makes 0-length memcpy explicitly a noop. Since all memcpying from NULL
> in Nginx uses n==0, this should be sufficient to avoid UB.
> 
> It would be more efficient to instead add a check to every call to
> ngx_memcpy and ngx_cpymem that might be used with src==NULL, but in
> the discussion of a previous patch that proposed such a change, a more
> straightforward and tidy solution was desired.
> It may also be worth considering adding checks for NULL memset,
> memmove, etc. I think this is not necessary unless it is demonstrated
> that Nginx actually executes such undefined calls.
> 
> # HG changeset patch
> # User Ben Kallus 
> # Date 1702406466 18000
> #  Tue Dec 12 13:41:06 2023 -0500
> # Node ID d270203d4ecf77cc14a2652c727e236afc659f4a
> # Parent  a6f79f044de58b594563ac03139cd5e2e6a81bdb
> Add NULL check to ngx_memcpy and ngx_cpymem to satisfy UBSan.
> 
> diff -r a6f79f044de5 -r d270203d4ecf src/core/ngx_string.c
> --- a/src/core/ngx_string.c Wed Nov 29 10:58:21 2023 +0400
> +++ b/src/core/ngx_string.c Tue Dec 12 13:41:06 2023 -0500
> @@ -2098,6 +2098,10 @@
>  ngx_debug_point();
>  }
> 
> +if (n == 0) {
> +return dst;
> +}
> +
>  return memcpy(dst, src, n);
>  }
> 
> diff -r a6f79f044de5 -r d270203d4ecf src/core/ngx_string.h
> --- a/src/core/ngx_string.h Wed Nov 29 10:58:21 2023 +0400
> +++ b/src/core/ngx_string.h Tue Dec 12 13:41:06 2023 -0500
> @@ -103,8 +103,9 @@
>   * gcc3 compiles memcpy(d, s, 4) to the inline "mov"es.
>   * icc8 compile memcpy(d, s, 4) to the inline "mov"es or XMM moves.
>   */
> -#define ngx_memcpy(dst, src, n)   (void) memcpy(dst, src, n)
> -#define ngx_cpymem(dst, src, n)   (((u_char *) memcpy(dst, src, n)) + (n))
> +#define ngx_memcpy(dst, src, n) (void) ((n) == 0 ? (dst) : memcpy(dst, src, 
> n))
> +#define ngx_cpymem(dst, src, n)  
> \
> +((u_char *) ((n) == 0 ? (dst) : memcpy(dst, src, n)) + (n))
> 
>  #endif
> 
> diff -r a6f79f044de5 -r d270203d4ecf src/http/v2/ngx_http_v2.c
> --- a/src/http/v2/ngx_http_v2.c Wed Nov 29 10:58:21 2023 +0400
> +++ b/src/http/v2/ngx_http_v2.c Tue Dec 12 13:41:06 2023 -0500
> @@ -3998,9 +3998,7 @@
>  n = size;
>  }
> 
> -if (n > 0) {
> -rb->buf->last = ngx_cpymem(rb->buf->last, pos, n);
> -}
> +rb->buf->last = ngx_cpymem(rb->buf->last, pos, n);
> 
>  ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
> "http2 request body recv %uz", n);

For the record, I've already provided some feedback to Ben in the 
ticket here:

https://trac.nginx.org/nginx/ticket/2570

And pointed to the existing thread here:

https://mailman.nginx.org/pipermail/nginx-devel/2023-October/PX7VH5A273NLUGSYC7DR2AZRU75CIQ3Q.html
https://mailman.nginx.org/pipermail/nginx-devel/2023-December/DCGUEGEFS6TSVIWNEWUEZO3FZMR6ESYZ.html

Hope this helps.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] Added asm ISB as asm pause for ngx_cpu_pause() for aarch64

2023-12-13 Thread Maxim Dounin
21198
> Difference at 95.0% confidence
> 1044.47 +/- 435.826
> 0.800713% +/- 0.334115%
> (Student's t, pooled s = 582.792)

That's without any caching being used, that is, basically just a 
result of slightly different compilation, correct?

This might be seen as a reference point of how slightly different 
compilation can affect performance.  We've previously seen 
cases of 2-3% performance improvement observed as a result of a 
nop change, and these results seem to be in line.

Tuning compilation to ensure there is no difference here might be 
the way to go.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: processing a request without body

2023-12-13 Thread Maxim Dounin
Hello!

On Wed, Dec 13, 2023 at 03:55:56PM +0800, Muhammad Nuzaihan wrote:

> I need to process requests with only URI path (without body) for a module.
> 
> It seems ngx_http_request_body_filter_pt is *not* executed whenever
> there is a request without a body (it looked like it bypassed without
> request body) and only ngx_http_output_body_filter_pt  part of the
> code is executed.
> 
> For example i do a request curl curl like this:
> 
> curl - -X POST http://localhost:8080/proxy/profile/alice/comment
> 
> and i need to validate /proxy/profile/alice/comment in my module and
> there is no http headers and no body. Only URI path.

When reading an HTTP request, nginx reads the request line and 
request headers, and then starts request processing by passing it 
through as sequence of request processing phases - in each phase, 
corresponding handlers are called.  The request body filters are 
only called if there is a request body, and some handler actually 
requested reading of the request body - so it's expected these are 
not called if there is no request body.

If you want to handle request based on the request line and the 
request headers, consider using appropriate phase handler, see

https://nginx.org/en/docs/dev/development_guide.html#http_phases

and the source code for details.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] Added asm ISB as asm pause for ngx_cpu_pause() for aarch64

2023-12-12 Thread Maxim Dounin
81dd7f9b037b59b362/src/mongo/platform/pause.h#L61
> 
> MySQL:
> https://github.com/mysql/mysql-server/blob/87307d4ddd88405117e3f1e51323836d57ab1f57/storage/innobase/include/ut0ut.h#L108
> 
> Jemalloc:
> https://github.com/jemalloc/jemalloc/blob/e4817c8d89a2a413e835c4adeab5c5c4412f9235/configure.ac#L436

Thanks for the links.
For the record, here are relevant commits / pull requests:

https://github.com/wiredtiger/wiredtiger/pull/6080
https://github.com/mongodb/mongo/commit/6979525674af67405984c58585766dd4d0c3f2a8

https://bugs.mysql.com/bug.php?id=100664
https://github.com/mysql/mysql-server/commit/f2a4ed5b65a6c03ee1bea60b8c3bb4db64dbed10

https://github.com/jemalloc/jemalloc/pull/2205
https://github.com/jemalloc/jemalloc/commit/89fe8ee6bf7a23556350d883a310c0224a171879

At least MySQL bug seems to have some interesting details.

> > Could you please clarify reasons for the "memory" clobber here?
> 
> Putting in the memory clobber for ISB is redundant because ISB is a 
> barrier itself, but it's probably the GCC appropriate thing to do. I 
> also like it as a hint for someone not familiar with ISB. ISB will pause 
> the frontend (fetch-decode) to allow the CPU backend (execute-retire) to 
> finish whatever operations are in flight. It's possible that some of 
> those operations are writes to memory. Hence why we should tell the 
> compiler "this instruction may update memory".

I don't think this interpretation is correct - memory is updated 
by other instructions, not ISB.  And it's the compiler who emitted 
these instructions, so it perfectly knows that these will 
eventually update memory.

Note that the ngx_cpu_pause() call does not need to be a barrier, 
neither a hardware barrier nor a compiler barrier.  Instead, nginx 
relies on using volatile variables for locks, so these are always 
loaded from memory by the compiler on pre-lock checks (and will 
test the updated value if it's changed by other CPUs), and proper 
barrier semantics of ngx_atomic_cmp_set().

The "memory" clobber essentially tells compiler that it cannot 
optimize stores and loads across the call, and must reload 
anything from memory after the call.  While this might be expected 
in other uses (for example, cpu_relax() in Linux is expected to be 
a compiler barrier), this is not something needed in 
ngx_cpu_pause().

[...]

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] Added asm ISB as asm pause for ngx_cpu_pause() for aarch64

2023-12-08 Thread Maxim Dounin
Hello!

Thank you for the patch.
Some comments and questions below.

On Wed, Dec 06, 2023 at 10:06:57AM -0600, julio.sua...@foss.arm.com wrote:

> # HG changeset patch
> # User Julio Suarez 
> # Date 1701877879 21600
> #  Wed Dec 06 09:51:19 2023 -0600
> # Node ID 53d289b8676fc678ca90e02ece174300a3631f79
> # Parent  f366007dd23a6ce8e8427c1b3042781b618a2ade
> Added asm ISB as asm pause for ngx_cpu_pause() for aarch64

Nitpicking:

Added ISB as ngx_cpu_pause() for aarch64.

> 
> For aarch64 (A.K.A. Arm64), ngx_cpu_pause() evaluates to empty by the
> GCC preprocessor. This results in an empty for loop in the lock
> check code in ngx_rwlock.c/ngx_spinlock.c (a bug).
> Thus, on Arm CPUs, there is no wait between checks of a lock.

Could you please clarify what do you mean by "a bug"?  An empty 
ngx_cpu_pause() is certainly not a bug, it's just a lack of a more 
optimal solution for the particular architecture.

> When a delay like the PAUSE that is there for x86 is added,
> there is a 2-5% increase in the number of requests/sec Arm CPUs
> can achieve under high load.

Could you please provide some details on how did you get these 
numbers?

> Currently, options for a spin lock delay element
> are YIELD and ISB. YIELD is assembled into a NOP for most Arm CPUs.
> YIELD is for Arm implementations with SMT.
> Most Arm implementations are single core - single thread (non-SMT).
> Thus, this commit uses ISB (Instruction Barrier Sync) since it
> will provide a slightly longer delay than a NOP.
> 
> Other projects that implement spin locks have used ISB as
> the delay element which has yielded performance gains as well.

Looking through various open source projects, I'm seeing the 
following uses on arm64 CPUs:

FreeBSD, sys/arm64/include/cpu.h:

#define cpu_spinwait()  __asm __volatile("yield" ::: "memory")

FreeBSD, lib/libthr/arch/aarch64/include/pthread_md.h:

#define CPU_SPINWAIT

Linux, arch/arm64/include/asm/vdso/processor.h:

static inline void cpu_relax(void)
{
asm volatile("yield" ::: "memory");
}

The only popular project I was able to find which uses ISB is 
Rust:

https://github.com/rust-lang/rust/commit/c064b6560b7ce0adeb9bbf5d7dcf12b1acb0c807

From the commit log it looks like it mostly focuses on the delay 
introduced by the instruction, ignoring other effects. In 
particular, YIELD is expected to be more friendly for various 
emulation environments, see Linux commit here:

https://github.com/torvalds/linux/commit/1baa82f48030f38d1895301f1ec93acbcb3d15db

Overall, the YIELD instruction seems to be better suited and 
specifically designed for the task in question, as per the 
documentation
(https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/YIELD--YIELD-):

: YIELD is a hint instruction. Software with a multithreading 
: capability can use a YIELD instruction to indicate to the PE that 
: it is performing a task, for example a spin-lock, that could be 
: swapped out to improve overall system performance. The PE can use 
: this hint to suspend and resume multiple software threads if it 
: supports the capability.

Please also note that ngx_cpu_pause() is only used on 
multiprocessor systems: the code checks if (ngx_ncpu > 1) before 
using it.

> 
> Last, ISB is not an architecturally defined solution
> for short spin lock delays.
> A candidate for a short delay solution is the WFET
> instruction (Wait For Event with Timeout).
> However, there aren't any Arm implementations in the market that
> support this instruction yet. When that occurs,
> WFET can be tested as a replacement for ISB. Until then,
> ISB will do.
> 
> diff -r f366007dd23a -r 53d289b8676f src/os/unix/ngx_atomic.h
> --- a/src/os/unix/ngx_atomic.hTue Nov 14 15:26:02 2023 +0400
> +++ b/src/os/unix/ngx_atomic.hWed Dec 06 09:51:19 2023 -0600
> @@ -66,6 +66,8 @@
>  
>  #if ( __i386__ || __i386 || __amd64__ || __amd64 )
>  #define ngx_cpu_pause() __asm__ ("pause")
> +#elif ( __aarch64__ )
> +#define ngx_cpu_pause() __asm__ ("isb" ::: "memory")

Could you please clarify reasons for the "memory" clobber here?

>  #else
>  #define ngx_cpu_pause()
>  #endif

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: Error: nginx: [emerg] unknown directive "stream" in /etc/nginx/nginx.conf:11

2023-12-07 Thread Maxim Dounin
Hello!

On Thu, Dec 07, 2023 at 05:34:23PM +0300, Sergey A. Osokin wrote:

> On Thu, Dec 07, 2023 at 09:17:37AM +, Gandla, Kesavardhana via nginx 
> wrote:
> > Dear NGINX community,
> > 
> > I am Kesavardhana Gandla from Medtronic R, Bangalore. I am trying to 
> > evaluate the nginx on YOCTO Linux based embedded product.
> > My Linux version: 5.15.71  aarch64 GNU/Linux.
> > While using the stream option on target the below error is coming.
> > 
> > Error: nginx: [emerg] unknown directive "stream" in /etc/nginx/nginx.conf:11
> 
> Please avoid cross-posting to multiple mailing lists.  Since this
> question is related to nginx development, it can be addressed to
> nginx-devel mailing list.

Certainly this is not related to nginx development.  For 
user-level questions, please use the nginx@ mailing list.  
Alternatively, reading the docs might be a good idea.

Thanks for understanding.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH 1 of 2] Core: avoid calling memcpy() in edge cases

2023-12-03 Thread Maxim Dounin
; diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c
> --- a/src/http/ngx_http_file_cache.c
> +++ b/src/http/ngx_http_file_cache.c
> @@ -1270,7 +1270,9 @@ ngx_http_file_cache_set_header(ngx_http_
>  
>  if (c->etag.len <= NGX_HTTP_CACHE_ETAG_LEN) {
>  h->etag_len = (u_char) c->etag.len;
> -ngx_memcpy(h->etag, c->etag.data, c->etag.len);
> +if (c->etag.len) {
> +ngx_memcpy(h->etag, c->etag.data, c->etag.len);
> +}
>  }
>  
>  if (c->vary.len) {
> diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c
> --- a/src/http/ngx_http_variables.c
> +++ b/src/http/ngx_http_variables.c
> @@ -2157,6 +2157,9 @@ ngx_http_variable_request_body(ngx_http_
>  
>  for ( /* void */ ; cl; cl = cl->next) {
>  buf = cl->buf;
> +if (buf->last == buf->pos) {
> +continue;
> +}
>  p = ngx_cpymem(p, buf->pos, buf->last - buf->pos);
>  }
>  
> diff --git a/src/mail/ngx_mail_auth_http_module.c 
> b/src/mail/ngx_mail_auth_http_module.c
> --- a/src/mail/ngx_mail_auth_http_module.c
> +++ b/src/mail/ngx_mail_auth_http_module.c
> @@ -1314,11 +1314,15 @@ ngx_mail_auth_http_create_request(ngx_ma
>  *b->last++ = CR; *b->last++ = LF;
>  
>  b->last = ngx_cpymem(b->last, "Auth-User: ", sizeof("Auth-User: ") - 1);
> -b->last = ngx_copy(b->last, login.data, login.len);
> +if (login.len) {
> +b->last = ngx_copy(b->last, login.data, login.len);
> +}
>  *b->last++ = CR; *b->last++ = LF;
>  
>  b->last = ngx_cpymem(b->last, "Auth-Pass: ", sizeof("Auth-Pass: ") - 1);
> -b->last = ngx_copy(b->last, passwd.data, passwd.len);
> +if (passwd.len) {
> +b->last = ngx_copy(b->last, passwd.data, passwd.len);
> +}
>  *b->last++ = CR; *b->last++ = LF;
>  
>  if (s->auth_method != NGX_MAIL_AUTH_PLAIN && s->salt.len) {
> @@ -1375,7 +1379,9 @@ ngx_mail_auth_http_create_request(ngx_ma
>  
>  b->last = ngx_cpymem(b->last, "Auth-SMTP-Helo: ",
>   sizeof("Auth-SMTP-Helo: ") - 1);
> -b->last = ngx_copy(b->last, s->smtp_helo.data, s->smtp_helo.len);
> +if (s->smtp_helo.len) {
> +b->last = ngx_copy(b->last, s->smtp_helo.data, s->smtp_helo.len);
> +}
>  *b->last++ = CR; *b->last++ = LF;
>  
>  b->last = ngx_cpymem(b->last, "Auth-SMTP-From: ",

If at all, these probably should check for login.len, passwd.len, 
and s->smtp_helo.len, similarly to other cases nearby, and avoid 
sending the headers altogether.

> diff --git a/src/stream/ngx_stream_script.c b/src/stream/ngx_stream_script.c
> --- a/src/stream/ngx_stream_script.c
> +++ b/src/stream/ngx_stream_script.c
> @@ -842,7 +842,9 @@ ngx_stream_script_copy_var_code(ngx_stre
>  
>  if (value && !value->not_found) {
>  p = e->pos;
> -e->pos = ngx_copy(p, value->data, value->len);
> +if (value->len) {
> +e->pos = ngx_copy(p, value->data, value->len);
> +}
>  
>  ngx_log_debug2(NGX_LOG_DEBUG_STREAM,
> e->session->connection->log, 0,

Obviously enough, there should be a corresponding change in 
ngx_http_script_copy_var_code().

Overall, similarly to the other patch in the series, I'm highly 
sceptical about doing such scattered changes based on the UB 
sanitizer reports from some test runs.  Rather, we should use UB 
sanitizer reports to identify problematic patterns, and fix these 
patterns all other the code (if at all).

Further, in this particular case I tend to think that the problem 
is not with nginx code, but rather with the memcpy() interface UB 
sanitizer tries to enforce.  It should be completely safe to call 
memcpy(p, NULL, 0), and if it doesn't, we might consider adding 
appropriate guards at interface level, such as in ngx_memcpy() / 
ngx_cpymem() wrappers, and not in each call.  Trying to check 
length everywhere is just ugly and unreadable.

Also, while recent versions of gcc are known to miscompile some 
code which uses memcpy(p, NULL, 0) (see [1], with "-O2" or with 
"-O1 -ftree-vrp" optimization flags in my tests), I don't think 
this affects nginx code.  If it does, we might also consider 
force-switching off relevant optimizations (if enabled, as we use 
"-O1" by default).

[1] 
https://stackoverflow.com/questions/5243012/is-it-guaranteed-to-be-safe-to-perform-memcpy0-0-0

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH 1 of 2] HTTP: uniform overflow checks in ngx_http_alloc_large_header_buffer

2023-11-29 Thread Maxim Dounin
Hello!

On Wed, Nov 29, 2023 at 11:24:03AM +0300, Vladimir Homutov via nginx-devel 
wrote:

> On Tue, Nov 28, 2023 at 05:58:23AM +0300, Maxim Dounin wrote:
> > Hello!
> >
> > On Fri, Nov 10, 2023 at 12:11:54PM +0300, Vladimir Homutov via nginx-devel 
> > wrote:
> >
> > > If URI is not fully parsed yet, some pointers are not set.
> > > As a result, the calculation of "new + (ptr - old)" expression
> > > may overflow. In such a case, just avoid calculating it, as value
> > > will be set correctly later by the parser in any case.
> > >
> > > The issue was found by GCC undefined behaviour sanitizer.
> > >
> > >
> > >  src/http/ngx_http_request.c |  34 ++
> > >  1 files changed, 26 insertions(+), 8 deletions(-)
> > >
> > >
> >
> > > # HG changeset patch
> > > # User Vladimir Khomutov 
> > > # Date 1699604478 -10800
> > > #  Fri Nov 10 11:21:18 2023 +0300
> > > # Node ID 505e927eb7a75f0fdce4caddb4ab9d9c71c9b9c8
> > > # Parent  dadd13fdcf5228c8e8380e120d4621002e3b0919
> > > HTTP: uniform overflow checks in ngx_http_alloc_large_header_buffer.
> > >
> > > If URI is not fully parsed yet, some pointers are not set.
> > > As a result, the calculation of "new + (ptr - old)" expression
> > > may overflow. In such a case, just avoid calculating it, as value
> > > will be set correctly later by the parser in any case.
> > >
> > > The issue was found by GCC undefined behaviour sanitizer.
> >
> > I would rather refrain from saying this is an issue, it is not
> > (unless a compiler actually starts to do silly things as long as
> > it sees something formally defined as "undefined behavior" in C
> > standard, and this would be indeed an issue - in the compiler).
> > As already noted in the initial review, the code as written is
> > completely safe in practice.  For such mostly style commits we
> > usually write something like "Prodded by...".
> 
> totally agreed
> 
> >
> > Also note that the issue is not an overflow, but rather
> > subtraction of pointers which do not belong to the same array
> > object (C11, 6.5.6 Additive operators, p.9):
> >
> > : When two pointers are subtracted, both shall point to elements
> > : of the same array object, or one past the last element of the
> > : array object
> >
> > The undefined behaviour is present as long as "ptr" and "old" are
> > not in the same buffer (i.e., array object), which is the case
> > when "ptr" is not set.  And another one follows when trying to add
> > the (already undefined) subtraction result to "new" (since the
> > result is not going to belong to the same array object):
> >
> > : If both the pointer operand and the result point to elements of
> > : the same array object, or one past the last element of the array
> > : object, the evaluation shall not produce an overflow; otherwise,
> > : the behavior is undefined.
> >
> > Overflow here might be an indicator that certainly there is an
> > undefined behaviour, but it's just an indicator.
> >
> > You may want to rewrite commit log accordingly.
> 
> The commit log was updated.
> 
> > > diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
> > > --- a/src/http/ngx_http_request.c
> > > +++ b/src/http/ngx_http_request.c
> > > @@ -1718,14 +1718,23 @@ ngx_http_alloc_large_header_buffer(ngx_h
> [...]
> > >  if (r->host_start) {
> >
> > See review of the second patch about r->port_start / r->port_end.
> > I would rather change it similarly for now.
> 
> I would prefer to remove both, so this patch has nothing about it.
> 
> updated patch:
> 
> 

> # HG changeset patch
> # User Vladimir Khomutov 
> # Date 1701245585 -10800
> #  Wed Nov 29 11:13:05 2023 +0300
> # Node ID 7c8ecb3fee20dfbb9a627441377dd09509988e2a
> # Parent  dacad3a9c7b8435a4c67ad2b67f261e7b4e36d8e
> HTTP: uniform checks in ngx_http_alloc_large_header_buffer().
> 
> If URI is not fully parsed yet, some pointers are not set.  As a result,
> the calculation of "new + (ptr - old)" expression is flawed.
> 
> According to  C11, 6.5.6 Additive operators, p.9:

Seems to be an extra space in "to  C11".

> 
> : When two pointers are subtracted, both shall point to elements
> : of the same array object, or one past the last element of the
> : array object
> 
> Since &qu

Re: [PATCH 2 of 2] HTTP: removed unused r->port_start

2023-11-29 Thread Maxim Dounin
Hello!

On Wed, Nov 29, 2023 at 11:20:33AM +0300, Vladimir Homutov via nginx-devel 
wrote:

> On Tue, Nov 28, 2023 at 05:57:39AM +0300, Maxim Dounin wrote:
> > Hello!
> >
> > On Fri, Nov 10, 2023 at 12:11:55PM +0300, Vladimir Homutov via nginx-devel 
> > wrote:
> >
> > >
> > > It is no longer used since the refactoring in 8e5bf1bc87e2 (2008).
> >
> > Neither r->port_start nor r->port_end were ever used.
> >
> > The r->port_end is set by the parser, though it was never used by
> > the following code (and was never usable, since not copied by the
> > ngx_http_alloc_large_header_buffer() without r->port_start set).
> >
> > The 8e5bf1bc87e2 commit is completely unrelated, it is about
> > refactoring of the ngx_parse_inet_url() function, which had a
> > local variable named "port_start".
> 
> exactly, thanks for noticing.
> 
> >
> > >
> > > diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
> > > --- a/src/http/ngx_http_request.c
> > > +++ b/src/http/ngx_http_request.c
> > > @@ -1744,8 +1744,7 @@ ngx_http_alloc_large_header_buffer(ngx_h
> > >  }
> > >  }
> > >
> > > -if (r->port_start) {
> > > -r->port_start = new + (r->port_start - old);
> > > +if (r->port_end) {
> > >  r->port_end = new + (r->port_end - old);
> > >  }
> > >
> > > diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
> > > --- a/src/http/ngx_http_request.h
> > > +++ b/src/http/ngx_http_request.h
> > > @@ -597,7 +597,6 @@ struct ngx_http_request_s {
> > >  u_char   *schema_end;
> > >  u_char   *host_start;
> > >  u_char   *host_end;
> > > -u_char   *port_start;
> > >  u_char   *port_end;
> > >
> > >  unsigned  http_minor:16;
> >
> > I don't think it's a good change.  Rather, we should either remove
> > both, or (eventually) fix these and provide some valid usage of
> > the port as parsed either from the request line or from the Host
> > header, similarly to the $host variable.
> >
> 
> I think that we should remove both, as unused code still needs to be
> maintained without any advantage, as this example shows.
> Restoring it will be trivial, if ever required.
> 
> 
> 

> # HG changeset patch
> # User Vladimir Khomutov 
> # Date 1701165434 -10800
> #  Tue Nov 28 12:57:14 2023 +0300
> # Node ID dacad3a9c7b8435a4c67ad2b67f261e7b4e36d8e
> # Parent  f366007dd23a6ce8e8427c1b3042781b618a2ade
> HTTP: removed unused r->port_start and r->port_end.
> 
> Neither r->port_start nor r->port_end were ever used.
> 
> The r->port_end is set by the parser, though it was never used by
> the following code (and was never usable, since not copied by the
> ngx_http_alloc_large_header_buffer() without r->port_start set).
> 
> diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c
> --- a/src/http/ngx_http_parse.c
> +++ b/src/http/ngx_http_parse.c
> @@ -451,19 +451,16 @@ ngx_http_parse_request_line(ngx_http_req
>  
>  switch (ch) {
>  case '/':
> -r->port_end = p;
>  r->uri_start = p;
>  state = sw_after_slash_in_uri;
>  break;
>  case '?':
> -r->port_end = p;
>  r->uri_start = p;
>  r->args_start = p + 1;
>  r->empty_path_in_uri = 1;
>  state = sw_uri;
>  break;
>  case ' ':
> -r->port_end = p;
>  /*
>   * use single "/" from request line to preserve pointers,
>   * if request line will be copied to large client buffer
> diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
> --- a/src/http/ngx_http_request.c
> +++ b/src/http/ngx_http_request.c
> @@ -1735,11 +1735,6 @@ ngx_http_alloc_large_header_buffer(ngx_h
>  }
>  }
>  
> -if (r->port_start) {
> -r->port_start = new + (r->port_start - old);
> -r->port_end = new + (r->port_end - old);
> -}
> -
>  if (r->uri_ext) {
>  r->uri_ext = new + (r->uri_ext - old);
>  }
> diff --git a/src/http/ngx_http_r

Re: [PATCH 1 of 2] HTTP: uniform overflow checks in ngx_http_alloc_large_header_buffer

2023-11-27 Thread Maxim Dounin
Hello!

On Fri, Nov 10, 2023 at 12:11:54PM +0300, Vladimir Homutov via nginx-devel 
wrote:

> If URI is not fully parsed yet, some pointers are not set.
> As a result, the calculation of "new + (ptr - old)" expression
> may overflow. In such a case, just avoid calculating it, as value
> will be set correctly later by the parser in any case.
> 
> The issue was found by GCC undefined behaviour sanitizer.
> 
> 
>  src/http/ngx_http_request.c |  34 ++
>  1 files changed, 26 insertions(+), 8 deletions(-)
> 
> 

> # HG changeset patch
> # User Vladimir Khomutov 
> # Date 1699604478 -10800
> #  Fri Nov 10 11:21:18 2023 +0300
> # Node ID 505e927eb7a75f0fdce4caddb4ab9d9c71c9b9c8
> # Parent  dadd13fdcf5228c8e8380e120d4621002e3b0919
> HTTP: uniform overflow checks in ngx_http_alloc_large_header_buffer.
> 
> If URI is not fully parsed yet, some pointers are not set.
> As a result, the calculation of "new + (ptr - old)" expression
> may overflow. In such a case, just avoid calculating it, as value
> will be set correctly later by the parser in any case.
> 
> The issue was found by GCC undefined behaviour sanitizer.

I would rather refrain from saying this is an issue, it is not 
(unless a compiler actually starts to do silly things as long as 
it sees something formally defined as "undefined behavior" in C 
standard, and this would be indeed an issue - in the compiler).  
As already noted in the initial review, the code as written is 
completely safe in practice.  For such mostly style commits we 
usually write something like "Prodded by...".

Also note that the issue is not an overflow, but rather 
subtraction of pointers which do not belong to the same array 
object (C11, 6.5.6 Additive operators, p.9):

: When two pointers are subtracted, both shall point to elements 
: of the same array object, or one past the last element of the 
: array object

The undefined behaviour is present as long as "ptr" and "old" are 
not in the same buffer (i.e., array object), which is the case 
when "ptr" is not set.  And another one follows when trying to add 
the (already undefined) subtraction result to "new" (since the 
result is not going to belong to the same array object):

: If both the pointer operand and the result point to elements of 
: the same array object, or one past the last element of the array 
: object, the evaluation shall not produce an overflow; otherwise, 
: the behavior is undefined.

Overflow here might be an indicator that certainly there is an 
undefined behaviour, but it's just an indicator.

You may want to rewrite commit log accordingly.

> 
> diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
> --- a/src/http/ngx_http_request.c
> +++ b/src/http/ngx_http_request.c
> @@ -1718,14 +1718,23 @@ ngx_http_alloc_large_header_buffer(ngx_h
>  r->request_end = new + (r->request_end - old);
>  }
>  
> -r->method_end = new + (r->method_end - old);
> -
> -r->uri_start = new + (r->uri_start - old);
> -r->uri_end = new + (r->uri_end - old);
> +if (r->method_end) {
> +r->method_end = new + (r->method_end - old);
> +}
> +
> +if (r->uri_start) {
> +r->uri_start = new + (r->uri_start - old);
> +}
> +
> +if (r->uri_end) {
> +r->uri_end = new + (r->uri_end - old);
> +}
>  
>  if (r->schema_start) {
>  r->schema_start = new + (r->schema_start - old);
> -r->schema_end = new + (r->schema_end - old);
> +if (r->schema_end) {
> +r->schema_end = new + (r->schema_end - old);
> +}
>  }
>  
>  if (r->host_start) {

See review of the second patch about r->port_start / r->port_end.  
I would rather change it similarly for now.

> @@ -1754,9 +1763,18 @@ ngx_http_alloc_large_header_buffer(ngx_h
>  
>  } else {
>  r->header_name_start = new;
> -r->header_name_end = new + (r->header_name_end - old);
> -r->header_start = new + (r->header_start - old);
> -r->header_end = new + (r->header_end - old);
> +
> +if (r->header_name_end) {
> +r->header_name_end = new + (r->header_name_end - old);
> +}
> +
> +if (r->header_start) {
> +r->header_start = new + (r->header_start - old);
> +}
> +
> +if (r->header_end) {
> +r->header_end = new + (r->header_end - old);
> +}
>  }
>  
>  r->header_in = b;

Otherwise looks good.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH 2 of 2] HTTP: removed unused r->port_start

2023-11-27 Thread Maxim Dounin
Hello!

On Fri, Nov 10, 2023 at 12:11:55PM +0300, Vladimir Homutov via nginx-devel 
wrote:

> It is no longer used since the refactoring in 8e5bf1bc87e2 (2008).
> 
> 
>  src/http/ngx_http_request.c |  3 +--
>  src/http/ngx_http_request.h |  1 -
>  2 files changed, 1 insertions(+), 3 deletions(-)
> 
> 

> # HG changeset patch
> # User Vladimir Khomutov 
> # Date 1699603821 -10800
> #  Fri Nov 10 11:10:21 2023 +0300
> # Node ID 6f957e137407d8f3f7e34f413c92103004b44594
> # Parent  505e927eb7a75f0fdce4caddb4ab9d9c71c9b9c8
> HTTP: removed unused r->port_start.
> 
> It is no longer used since the refactoring in 8e5bf1bc87e2 (2008).

Neither r->port_start nor r->port_end were ever used.

The r->port_end is set by the parser, though it was never used by 
the following code (and was never usable, since not copied by the 
ngx_http_alloc_large_header_buffer() without r->port_start set).

The 8e5bf1bc87e2 commit is completely unrelated, it is about 
refactoring of the ngx_parse_inet_url() function, which had a 
local variable named "port_start".

> 
> diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
> --- a/src/http/ngx_http_request.c
> +++ b/src/http/ngx_http_request.c
> @@ -1744,8 +1744,7 @@ ngx_http_alloc_large_header_buffer(ngx_h
>  }
>  }
>  
> -if (r->port_start) {
> -r->port_start = new + (r->port_start - old);
> +if (r->port_end) {
>  r->port_end = new + (r->port_end - old);
>  }
>  
> diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
> --- a/src/http/ngx_http_request.h
> +++ b/src/http/ngx_http_request.h
> @@ -597,7 +597,6 @@ struct ngx_http_request_s {
>  u_char   *schema_end;
>  u_char   *host_start;
>  u_char   *host_end;
> -u_char   *port_start;
>  u_char   *port_end;
>  
>  unsigned  http_minor:16;

I don't think it's a good change.  Rather, we should either remove 
both, or (eventually) fix these and provide some valid usage of 
the port as parsed either from the request line or from the Host 
header, similarly to the $host variable.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


[PATCH 1 of 4] Fixed request termination with AIO and subrequests (ticket #2555)

2023-11-26 Thread Maxim Dounin
# HG changeset patch
# User Maxim Dounin 
# Date 1701049682 -10800
#  Mon Nov 27 04:48:02 2023 +0300
# Node ID a5e39e9d1f4c84dcbe6a2f9e079372a3d63aef0b
# Parent  f366007dd23a6ce8e8427c1b3042781b618a2ade
Fixed request termination with AIO and subrequests (ticket #2555).

When a request was terminated due to an error via ngx_http_terminate_request()
while an AIO operation was running in a subrequest, various issues were
observed.  This happened because ngx_http_request_finalizer() was only set
in the subrequest where ngx_http_terminate_request() was called, but not
in the subrequest where the AIO operation was running.  After completion
of the AIO operation resumed normal processing of the subrequest, leading
to issues.

In particular, in case of the upstream module, termination of the request
called upstream cleanup, which closed the upstream connection.  Attempts to
further work with the upstream connection after AIO operation completion
resulted in segfaults in ngx_ssl_recv(), "readv() failed (9: Bad file
descriptor) while reading upstream" errors, or socket leaks.

In ticket #2555, issues were observed with the following configuration
with cache background update (with thread writing instrumented to
introduce a delay, when a client closes the connection during an update):

location = /background-and-aio-write {
proxy_pass ...
proxy_cache one;
proxy_cache_valid 200 1s;
proxy_cache_background_update on;
proxy_cache_use_stale updating;
aio threads;
aio_write on;
limit_rate 1000;
}

Similarly, the same issue can be seen with SSI, and can be caused by
errors in subrequests, such as in the following configuration
(were "/proxy" uses AIO, and "/sleep" returns 444 after some delay,
causing request termination):

location = /ssi-active-boom {
ssi on;
ssi_types *;
return 200 '
   
   
   ';
limit_rate 1000;
}

Or the same with both AIO operation and the error in non-active subrequests
(which needs slightly different handling, see below):

location = /ssi-non-active-boom {
ssi on;
ssi_types *;
return 200 '
   
   
   
   ';
limit_rate 1000;
}

Similarly, issues can be observed with just static files.  However,
with static files potential impact is limited due to timeout safeguards
in ngx_http_writer(), and the fact that c->error is set during request
termination.

In a simple configuration with an AIO operation in the active subrequest,
such as in the following configuration, the connection is closed right
after completion of the AIO operation anyway, since ngx_http_writer()
tries to write to the connection and fails due to c->error set:

location = /ssi-active-static-boom {
ssi on;
ssi_types *;
return 200 '
   
   
   ';
limit_rate 1000;
}

In the following configuration, with an AIO operation in a non-active
subrequest, the connection is closed only after send_timeout expires:

location = /ssi-non-active-static-boom {
ssi on;
ssi_types *;
return 200 '
   
   
   
   ';
limit_rate 1000;
}

Fix is to introduce r->main->terminated flag, which is to be checked
by AIO event handlers when the r->main->blocked counter is decremented.
When the flag is set, handlers are expected to wake up the connection
instead of the subrequest (which might be already cleaned up).

Additionally, now ngx_http_request_finalizer() is always set in the
active subrequest, so waking up the connection properly finalizes the
request even if termination happened in a non-active subrequest.

diff --git a/src/http/ngx_http_copy_filter_module.c 
b/src/http/ngx_http_copy_filter_module.c
--- a/src/http/ngx_http_copy_filter_module.c
+++ b/src/http/ngx_http_copy_filter_module.c
@@ -195,9 +195,18 @@ ngx_http_copy_aio_event_handler(ngx_even
 r->main->blocked--;
 r->aio = 0;
 
-r->write_event_handler(r);
+if (r->main->terminated) {
+/*
+ * trigger connection event handler if the request was
+ * terminated
+ */
 
-ngx_http_run_posted_requests(c);
+c->write->handler(c->write);
+
+} else {
+r->write_event_handler(r);
+ngx_http_run_posted_requests(c);
+}
 }
 
 #endif
@@ -305,11 +314,11 @@ ngx_http_copy_thread_event_handler(ngx_e
 
 #endif
 
-if (r->done) {
+if (r->done || r->main->terminated) {
 /*
  * trigger connection event handler if the subrequest was
- * already finalized; this can happen if the handler is used
- * for sendfile() in threads
+ * already finalized (this c

[PATCH 4 of 4] AIO operations now add timers (ticket #2162)

2023-11-26 Thread Maxim Dounin
# HG changeset patch
# User Maxim Dounin 
# Date 1701050170 -10800
#  Mon Nov 27 04:56:10 2023 +0300
# Node ID 00c3e7333145ddb5ea0eeaaa66b3d9c26973c9c2
# Parent  61d08e4cf97cc073200ec32fc6ada9a2d48ffe51
AIO operations now add timers (ticket #2162).

Each AIO (thread IO) operation being run is now accompanied with 1-minute
timer.  This timer prevents unexpected shutdown of the worker process while
an AIO operation is running, and logs an alert if the operation is running
for too long.

This fixes "open socket left" alerts during worker processes shutdown
due to pending AIO (or thread IO) operations while corresponding requests
have no timers.  In particular, such errors were observed while reading
cache headers (ticket #2162), and with worker_shutdown_timeout.

diff --git a/src/http/ngx_http_copy_filter_module.c 
b/src/http/ngx_http_copy_filter_module.c
--- a/src/http/ngx_http_copy_filter_module.c
+++ b/src/http/ngx_http_copy_filter_module.c
@@ -170,6 +170,8 @@ ngx_http_copy_aio_handler(ngx_output_cha
 file->aio->data = r;
 file->aio->handler = ngx_http_copy_aio_event_handler;
 
+ngx_add_timer(>aio->event, 6);
+
 r->main->blocked++;
 r->aio = 1;
 ctx->aio = 1;
@@ -192,6 +194,17 @@ ngx_http_copy_aio_event_handler(ngx_even
 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http aio: \"%V?%V\"", >uri, >args);
 
+if (ev->timedout) {
+ngx_log_error(NGX_LOG_ALERT, c->log, 0,
+  "aio operation took too long");
+ev->timedout = 0;
+return;
+}
+
+if (ev->timer_set) {
+ngx_del_timer(ev);
+}
+
 r->main->blocked--;
 r->aio = 0;
 
@@ -273,6 +286,8 @@ ngx_http_copy_thread_handler(ngx_thread_
 return NGX_ERROR;
 }
 
+ngx_add_timer(>event, 6);
+
 r->main->blocked++;
 r->aio = 1;
 
@@ -297,6 +312,17 @@ ngx_http_copy_thread_event_handler(ngx_e
 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http thread: \"%V?%V\"", >uri, >args);
 
+if (ev->timedout) {
+ngx_log_error(NGX_LOG_ALERT, c->log, 0,
+  "thread operation took too long");
+ev->timedout = 0;
+return;
+}
+
+if (ev->timer_set) {
+ngx_del_timer(ev);
+}
+
 r->main->blocked--;
 r->aio = 0;
 
diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -705,6 +705,8 @@ ngx_http_file_cache_aio_read(ngx_http_re
 c->file.aio->data = r;
 c->file.aio->handler = ngx_http_cache_aio_event_handler;
 
+ngx_add_timer(>file.aio->event, 6);
+
 r->main->blocked++;
 r->aio = 1;
 
@@ -752,6 +754,17 @@ ngx_http_cache_aio_event_handler(ngx_eve
 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http file cache aio: \"%V?%V\"", >uri, >args);
 
+if (ev->timedout) {
+ngx_log_error(NGX_LOG_ALERT, c->log, 0,
+  "aio operation took too long");
+ev->timedout = 0;
+return;
+}
+
+if (ev->timer_set) {
+ngx_del_timer(ev);
+}
+
 r->main->blocked--;
 r->aio = 0;
 
@@ -810,6 +823,8 @@ ngx_http_cache_thread_handler(ngx_thread
 return NGX_ERROR;
 }
 
+ngx_add_timer(>event, 6);
+
 r->main->blocked++;
 r->aio = 1;
 
@@ -831,6 +846,17 @@ ngx_http_cache_thread_event_handler(ngx_
 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http file cache thread: \"%V?%V\"", >uri, >args);
 
+if (ev->timedout) {
+ngx_log_error(NGX_LOG_ALERT, c->log, 0,
+  "thread operation took too long");
+ev->timedout = 0;
+return;
+}
+
+if (ev->timer_set) {
+ngx_del_timer(ev);
+}
+
 r->main->blocked--;
 r->aio = 0;
 
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -3949,6 +3949,8 @@ ngx_http_upstream_thread_handler(ngx_thr
 r->aio = 1;
 p->aio = 1;
 
+ngx_add_timer(>event, 6);
+
 return NGX_OK;
 }
 
@@ -3967,6 +3969,17 @@ ngx_http_upstream_thread_event_handler(n
 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http upstream thread: \"%V?%V\"", >uri, >args);
 
+if (ev->timedout) {
+ngx_log_error(NGX_LOG_ALERT, c->log, 0,
+  "thread operation took too long");
+ev->timedout = 0;
+return;
+}
+
+if (ev->timer_set) {
+ngx_del_t

[PATCH 2 of 4] Upstream: fixed usage of closed sockets with filter finalization

2023-11-26 Thread Maxim Dounin
# HG changeset patch
# User Maxim Dounin 
# Date 1701049758 -10800
#  Mon Nov 27 04:49:18 2023 +0300
# Node ID faf0b9defc76b8683af466f8a950c2c241382970
# Parent  a5e39e9d1f4c84dcbe6a2f9e079372a3d63aef0b
Upstream: fixed usage of closed sockets with filter finalization.

When filter finalization is triggered when working with an upstream server,
and error_page redirects request processing to some simple handler,
ngx_http_request_finalize() triggers request termination when the response
is sent.  In particular, via the upstream cleanup handler, nginx will close
the upstream connection and the corresponding socket.

Still, this can happen to be with ngx_event_pipe() on stack.  While
the code will set p->downstream_error due to NGX_ERROR returned from the
output filter chain by filter finalization, otherwise the error will be
ignored till control returns to ngx_http_upstream_process_request().
And event pipe might try reading from the (already closed) socket, resulting
in "readv() failed (9: Bad file descriptor) while reading upstream" errors
(or even segfaults with SSL).

Such errors were seen with the following configuration:

location /t2 {
proxy_pass http://127.0.0.1:8080/big;

image_filter_buffer 10m;
image_filter   resize  150 100;
error_page 415   = /empty;
}

location /empty {
return 204;
}

location /big {
# big enough static file
}

Fix is to set p->upstream_error in ngx_http_upstream_finalize_request(),
so the existing checks in ngx_event_pipe_read_upstream() will prevent
further reading from the closed upstream connection.

Similarly, p->upstream_error is now checked when handling events at
ngx_event_pipe() exit, as checking p->upstream->fd is not enough if
keepalive upstream connections are being used and the connection was
saved to cache during request termination.

diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c
--- a/src/event/ngx_event_pipe.c
+++ b/src/event/ngx_event_pipe.c
@@ -57,7 +57,9 @@ ngx_event_pipe(ngx_event_pipe_t *p, ngx_
 do_write = 1;
 }
 
-if (p->upstream->fd != (ngx_socket_t) -1) {
+if (p->upstream->fd != (ngx_socket_t) -1
+&& !p->upstream_error)
+{
 rev = p->upstream->read;
 
 flags = (rev->eof || rev->error) ? NGX_CLOSE_EVENT : 0;
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -4561,6 +4561,10 @@ ngx_http_upstream_finalize_request(ngx_h
 
 u->peer.connection = NULL;
 
+if (u->pipe) {
+u->pipe->upstream_error = 1;
+}
+
 if (u->pipe && u->pipe->temp_file) {
 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http upstream temp fd: %d",
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


[PATCH 3 of 4] Silenced complaints about socket leaks on forced termination

2023-11-26 Thread Maxim Dounin
# HG changeset patch
# User Maxim Dounin 
# Date 1701049787 -10800
#  Mon Nov 27 04:49:47 2023 +0300
# Node ID 61d08e4cf97cc073200ec32fc6ada9a2d48ffe51
# Parent  faf0b9defc76b8683af466f8a950c2c241382970
Silenced complaints about socket leaks on forced termination.

When graceful shutdown was requested, and then nginx was forced to
do fast shutdown, it used to (incorrectly) complain about open sockets
left in connections which weren't yet closed when fast shutdown
was requested.

Fix is to avoid complaining about open sockets when fast shutdown was
requested after graceful one.  Abnormal termination, if requested with
the WINCH signal, can still happen though.

diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -948,7 +948,7 @@ ngx_worker_process_exit(ngx_cycle_t *cyc
 }
 }
 
-if (ngx_exiting) {
+if (ngx_exiting && !ngx_terminate) {
 c = cycle->connections;
 for (i = 0; i < cycle->connection_n; i++) {
 if (c[i].fd != -1
@@ -963,11 +963,11 @@ ngx_worker_process_exit(ngx_cycle_t *cyc
 ngx_debug_quit = 1;
 }
 }
+}
 
-if (ngx_debug_quit) {
-ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "aborting");
-ngx_debug_point();
-}
+if (ngx_debug_quit) {
+ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "aborting");
+ngx_debug_point();
 }
 
 /*
diff --git a/src/os/win32/ngx_process_cycle.c b/src/os/win32/ngx_process_cycle.c
--- a/src/os/win32/ngx_process_cycle.c
+++ b/src/os/win32/ngx_process_cycle.c
@@ -834,7 +834,7 @@ ngx_worker_process_exit(ngx_cycle_t *cyc
 }
 }
 
-if (ngx_exiting) {
+if (ngx_exiting && !ngx_terminate) {
 c = cycle->connections;
 for (i = 0; i < cycle->connection_n; i++) {
 if (c[i].fd != (ngx_socket_t) -1
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


[PATCH 0 of 4] aio fixes

2023-11-26 Thread Maxim Dounin
Hello!

Here is a patch series which fixes several issues with AIO (threaded IO)
and some related issues, initially inspired by ticket #2555.

Most notably, it fixes various issues with incorrect request termination
with subrequests when an AIO operation is running in another subrequest,
as observed in ticket #2555 (first patch).  Additionally, it fixes an
issue with request termination due to filter finalization with
ngx_event_pipe() on stack (second patch), fixes incorrect alerts about
open sockets left when SIGQUIT is followed by SIGTERM (third patch),
and introduces guard timers for AIO operations to prevent premature
shutdown of worker processes (forth patch, ticket #2162).

In tests this fixes two alerts as observed with aio_write, in
image_filter_finalize.t and in proxy_cache_use_stale.t:

image_filter_finalize.t (Wstat: 0 Tests: 5 Failed: 0)
  TODO passed:   4
proxy_cache_use_stale.t (Wstat: 0 Tests: 36 Failed: 0)
  TODO passed:   35

Review and testing appreciated.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] Linux packages: added Ubuntu 23.04 "mantic"

2023-11-11 Thread Maxim Dounin
Hello!

On Thu, Nov 09, 2023 at 07:43:09PM -0800, Konstantin Pavlov wrote:

> # HG changeset patch
> # User Konstantin Pavlov 
> # Date 1699587725 28800
> #  Thu Nov 09 19:42:05 2023 -0800
> # Node ID d9dba9159ddf3adaf0263f17f3ed69228aa6c972
> # Parent  5cfaf094e2a041d3fa6eaf58799f575295e451ab
> Linux packages: added Ubuntu 23.04 "mantic".
> 
> diff -r 5cfaf094e2a0 -r d9dba9159ddf xml/en/linux_packages.xml
> --- a/xml/en/linux_packages.xml   Tue Oct 24 15:16:17 2023 -0700
> +++ b/xml/en/linux_packages.xml   Thu Nov 09 19:42:05 2023 -0800
> @@ -7,7 +7,7 @@
> link="/en/linux_packages.html"
>   lang="en"
> - rev="91">
> + rev="92">
>  
>  
>  
> @@ -92,6 +92,11 @@ versions:
>  x86_64, aarch64/arm64
>  
>  
> +
> +23.10 “mantic”
> +x86_64, aarch64/arm64
> +
> +
>  
>  
>  
> diff -r 5cfaf094e2a0 -r d9dba9159ddf xml/ru/linux_packages.xml
> --- a/xml/ru/linux_packages.xml   Tue Oct 24 15:16:17 2023 -0700
> +++ b/xml/ru/linux_packages.xml   Thu Nov 09 19:42:05 2023 -0800
> @@ -7,7 +7,7 @@
> link="/ru/linux_packages.html"
>   lang="ru"
> -     rev="91">
> + rev="92">
>  
>  
>  
> @@ -92,6 +92,11 @@
>  x86_64, aarch64/arm64
>  
>  
> +
> +23.10 “mantic”
> +x86_64, aarch64/arm64
> +
> +
>  
>  

Looks good.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: RESTCONF Server-Sent-Event session control in nginx

2023-10-31 Thread Maxim Dounin
Hello!

On Tue, Oct 31, 2023 at 06:20:43AM +, Lucas JunSeong Kim 김준성 wrote:

> Hi, I have a question.
> 
> We have the system which the following structure is used:
> 
> Nginx <> CGI interpreter <> yumapro Netconf server
> 
> Multiple CGI interpreters are created and used through the settings below.
> 
> spawn-fcgi -s /var/run/fcgiwrap.socket -F 5 -- /var/www/yang-api/restconf
> 
> Nginx <> CGI interpreter <> yumapro Netconf server
>  CGI interpreter
>  CGI interpreter
>  CGI interpreter
>  CGI interpreter

[...]

This mailing list is dedicated to nginx development.  For 
questions on how to configure nginx, please use the nginx@ mailing 
list instead, see http://nginx.org/en/support.html for details.

Thank you.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH 2 of 2] HTTP: suppressed possible overflow in interim r->uri_end calculation

2023-10-27 Thread Maxim Dounin
Hello!

On Fri, Oct 27, 2023 at 02:58:45PM +0300, Vladimir Homutov via nginx-devel 
wrote:

> If URI is not fully parsed yet, the r->uri_end pointer is NULL.
> As a result, calculation of "new + (r->uri_end - old)" expression
> may overflow.  In such case, just avoid calculating it, as r->uri_end
> will be set correctly later by the parser in any case.
> 
> The issue was found by GCC undefined behaviour sanitizer.
> 
> 
>  src/http/ngx_http_request.c |  4 +++-
>  1 files changed, 3 insertions(+), 1 deletions(-)
> 
> 

> # HG changeset patch
> # User Vladimir Khomutov 
> # Date 1698407686 -10800
> #  Fri Oct 27 14:54:46 2023 +0300
> # Node ID 1b28902de1c648fc2586bba8e05c2ff63e0e33cb
> # Parent  ef9f124b156aff0e9f66057e438af835bd7a60d2
> HTTP: suppressed possible overflow in interim r->uri_end calculation.
> 
> If URI is not fully parsed yet, the r->uri_end pointer is NULL.
> As a result, calculation of "new + (r->uri_end - old)" expression
> may overflow.  In such case, just avoid calculating it, as r->uri_end
> will be set correctly later by the parser in any case.
> 
> The issue was found by GCC undefined behaviour sanitizer.
> 
> diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
> --- a/src/http/ngx_http_request.c
> +++ b/src/http/ngx_http_request.c
> @@ -1721,7 +1721,9 @@ ngx_http_alloc_large_header_buffer(ngx_h
>  r->method_end = new + (r->method_end - old);
>  
>  r->uri_start = new + (r->uri_start - old);
> -r->uri_end = new + (r->uri_end - old);
> +if (r->uri_end) {
> +r->uri_end = new + (r->uri_end - old);
> +}
>  
>  if (r->schema_start) {
>  r->schema_start = new + (r->schema_start - old);

As already noted off-list, this is certainly not the only field 
which might be not yet set when 
ngx_http_alloc_large_header_buffer() is called.  From the patch 
context as shown, at least r->method_end and r->uri_start might 
not be set as well, leading to similar overflows.  And certainly 
there are other fields as well.

While I have no objections to fixing such overflows, which formally 
might be seen as undefined behaviour (though safe in practice, since 
calculated values are never used), I very much object to fixing 
just the particular items which were reported by a particular 
sanitizer in particular test runs.

Rather, sanitizer results should be used to identify patterns we 
want to fix (if at all), and then all such patterns should be 
fixed (or not).

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] Linux packages: documented nginx-module-otel package

2023-10-26 Thread Maxim Dounin
Hello!

On Wed, Oct 25, 2023 at 10:52:40AM +0100, Yaroslav Zhuravlev wrote:

[...]

> As an optional variant to consider, perhaps it might be good
> to reflect that it's a third party module authored by nginx devs, e.g:

[...]

> +Additionally, since version 1.25.3
> +nginx-authored third-party module
> +https://github.com/nginxinc/nginx-otel;>nginx-otel
> +is built as dynamic and shipped as a separate package:
> +
> +nginx-module-otel
> +

Note that "nginx-authored" here looks misleading, as no nginx core 
developers work on this module.

Overall, I do support the clear distinction between nginx's own 
modules and 3rd-party modules provided in the packages repository.  
(But, as correctly noted by Konstantin, this should include njs as 
well.)

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: nginx 1.25.3 changes draft

2023-10-24 Thread Maxim Dounin
Hello!

On Tue, Oct 24, 2023 at 05:07:46PM +0400, Sergey Kandaurov wrote:

> 
> > On 24 Oct 2023, at 16:34, Maxim Dounin  wrote:
> > 
> > Hello!
> > 
> > 
> > Changes with nginx 1.25.324 Oct 2023
> > 
> >*) Change: improved detection of misbehaving clients when using HTTP/2.
> > 
> >*) Feature: startup speedup when using a large number of locations.
> >   Thanks to Yusuke Nojima.
> > 
> >*) Bugfix: a segmentation fault might occur in a worker process when
> >   using HTTP/2 without SSL; the bug had appeared in 1.25.1.
> > 
> >*) Bugfix: the "Status" backend response header line with an empty
> >   reason phrase was handled incorrectly.
> > 
> >*) Bugfix: memory leak during reconfiguration when using the PCRE2
> >   library.
> >   Thanks to ZhenZhong Wu.
> > 
> >*) Bugfixes and improvements in HTTP/3.
> > 
> > 
> > Изменения в nginx 1.25.3  24.10.2023
> > 
> >*) Изменение: улучшено детектирование некорректного поведения клиентов
> >   при использовании HTTP/2.
> > 
> >*) Добавление: уменьшение времени запуска при использовании большого
> >   количества location'ов.
> >   Спасибо Yusuke Nojima.
> > 
> >*) Исправление: при использовании HTTP/2 без SSL в рабочем процессе мог
> >   произойти segmentation fault; ошибка появилась в 1.25.1.
> > 
> >*) Исправление: строка "Status" в заголовке ответа бэкенда с пустой
> >   поясняющей фразой обрабатывалась некорректно.
> > 
> >*) Исправление: утечки памяти во время переконфигурации при
> >   использовании библиотеки PCRE2.
> >   Спасибо ZhenZhong Wu.
> > 
> >*) Исправления и улучшения в HTTP/3.
> > 
> > 
> 
> Looks good.

Thanks, pushed:

http://mdounin.ru/hg/nginx
http://mdounin.ru/hg/nginx.org

Release files:

http://mdounin.ru/temp/nginx-1.25.3.tar.gz
http://mdounin.ru/temp/nginx-1.25.3.tar.gz.asc
http://mdounin.ru/temp/nginx-1.25.3.zip
http://mdounin.ru/temp/nginx-1.25.3.zip.asc

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


nginx 1.25.3 changes draft

2023-10-24 Thread Maxim Dounin
Hello!


Changes with nginx 1.25.324 Oct 2023

*) Change: improved detection of misbehaving clients when using HTTP/2.

*) Feature: startup speedup when using a large number of locations.
   Thanks to Yusuke Nojima.

*) Bugfix: a segmentation fault might occur in a worker process when
   using HTTP/2 without SSL; the bug had appeared in 1.25.1.

*) Bugfix: the "Status" backend response header line with an empty
   reason phrase was handled incorrectly.

*) Bugfix: memory leak during reconfiguration when using the PCRE2
   library.
   Thanks to ZhenZhong Wu.

*) Bugfixes and improvements in HTTP/3.


Изменения в nginx 1.25.3  24.10.2023

*) Изменение: улучшено детектирование некорректного поведения клиентов
   при использовании HTTP/2.

*) Добавление: уменьшение времени запуска при использовании большого
   количества location'ов.
   Спасибо Yusuke Nojima.

*) Исправление: при использовании HTTP/2 без SSL в рабочем процессе мог
   произойти segmentation fault; ошибка появилась в 1.25.1.

*) Исправление: строка "Status" в заголовке ответа бэкенда с пустой
   поясняющей фразой обрабатывалась некорректно.

*) Исправление: утечки памяти во время переконфигурации при
   использовании библиотеки PCRE2.
   Спасибо ZhenZhong Wu.

*) Исправления и улучшения в HTTP/3.


-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] HTTP/2: fixed buffer management with HTTP/2 auto-detection

2023-10-20 Thread Maxim Dounin
Hello!

On Fri, Oct 20, 2023 at 06:04:32PM +0400, Sergey Kandaurov wrote:

> > On 20 Oct 2023, at 17:23, Sergey Kandaurov  wrote:
> > 
> > # HG changeset patch
> > # User Sergey Kandaurov 
> > # Date 1697808142 -14400
> > #  Fri Oct 20 17:22:22 2023 +0400
> > # Node ID 318c8ace6aa24506004bfbb7d52674f61a3716a5
> > # Parent  3038bd4d78169a5e8a2624d79cf76f45f0805ddc
> > HTTP/2: fixed buffer management with HTTP/2 auto-detection.
> > 
> > As part of normal HTTP/2 processing, incomplete frames are saved in the
> > control state using a fixed size memcpy of NGX_HTTP_V2_STATE_BUFFER_SIZE.
> > For this matter, two state buffers are reserved in the HTTP/2 recv buffer.
> > 
> > As part of HTTP/2 auto-detection on plain TCP connections, initial data
> > is first read into a buffer specified by the client_header_buffer_size
> > directive that doesn't have state reservation.  Previously, this made it
> > possible to over-read the buffer as part of saving the state.
> > 
> > The fix is to read the available buffer size rather than a fixed size.
> > Although memcpy of a fixed size can produce a better optimized code,
> 
> From my limited testing, replacing a fixed size with an available size
> degrades "-O" optimized memcpy from SSE instructions over XMM registers
> to simple MOVs.

I don't think it matters compared to other costs within the loop.

> > handling of incomplete frames isn't a common execution path, so it was
> > sacrificed for the sake of simplicity of the fix.
> 
> Another approach is to displace initial data into the recv buffer
> for subsequent processing, which would require additional handling
> in ngx_http_v2_init().  After some pondering I declined it due to
> added complexity without a good reason.
> 
> > 
> > diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
> > --- a/src/http/v2/ngx_http_v2.c
> > +++ b/src/http/v2/ngx_http_v2.c
> > @@ -386,13 +386,11 @@ ngx_http_v2_read_handler(ngx_event_t *re
> > h2mcf = ngx_http_get_module_main_conf(h2c->http_connection->conf_ctx,
> >   ngx_http_v2_module);
> > 
> > -available = h2mcf->recv_buffer_size - 2 * 
> > NGX_HTTP_V2_STATE_BUFFER_SIZE;
> > +available = h2mcf->recv_buffer_size - NGX_HTTP_V2_STATE_BUFFER_SIZE;
> > 
> > do {
> > p = h2mcf->recv_buffer;
> > -
> > -ngx_memcpy(p, h2c->state.buffer, NGX_HTTP_V2_STATE_BUFFER_SIZE);
> > -end = p + h2c->state.buffer_used;
> > +end = ngx_cpymem(p, h2c->state.buffer, h2c->state.buffer_used);
> > 
> > n = c->recv(c, end, available);
> > 
> > @@ -2592,7 +2590,7 @@ ngx_http_v2_state_save(ngx_http_v2_conne
> > return ngx_http_v2_connection_error(h2c, 
> > NGX_HTTP_V2_INTERNAL_ERROR);
> > }
> > 
> > -ngx_memcpy(h2c->state.buffer, pos, NGX_HTTP_V2_STATE_BUFFER_SIZE);
> > +ngx_memcpy(h2c->state.buffer, pos, size);
> > 
> > h2c->state.buffer_used = size;
> > h2c->state.handler = handler;
> > diff --git a/src/http/v2/ngx_http_v2_module.c 
> > b/src/http/v2/ngx_http_v2_module.c
> > --- a/src/http/v2/ngx_http_v2_module.c
> > +++ b/src/http/v2/ngx_http_v2_module.c
> > @@ -388,7 +388,7 @@ ngx_http_v2_recv_buffer_size(ngx_conf_t 
> > {
> > size_t *sp = data;
> > 
> > -if (*sp <= 2 * NGX_HTTP_V2_STATE_BUFFER_SIZE) {
> > +if (*sp <= NGX_HTTP_V2_STATE_BUFFER_SIZE) {
> > return "value is too small";
> > }
> > 

Looks good.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] Improve performance when starting nginx with a lot of locations

2023-10-17 Thread Maxim Dounin
Hello!

On Tue, Oct 17, 2023 at 03:25:41PM +0400, Sergey Kandaurov wrote:

> > On 11 Oct 2023, at 02:56, Maxim Dounin  wrote:
> > 
> > Hello!
> > 
> > On Thu, Oct 05, 2023 at 10:51:26AM +0900, Yusuke Nojima wrote:
> > 
> >> Thank you for your comment!
> >> 
> >>> Could you please provide some more details about the use case,
> >>> such as how locations are used, and what is the approximate number
> >>> of locations being used?
> >> 
> >> Our team provides development environments to our company's engineers and 
> >> QA.
> >> In this environment, engineers and QA can freely create VMs and deploy
> >> applications on them.
> >> 
> >> Our nginx has the role of routing requests from the internet to all
> >> applications deployed in this environment.
> >> Additionally, it allows setting IP address restrictions, BASIC
> >> authentication, TLS client authentication, and other configurations
> >> for each application.
> >> 
> >> To implement these requirements, we generate a location for each 
> >> application.
> >> Currently, there are approximately 40,000 locations in our environment.
> > 
> > Thank you for the details.  Such configuration looks somewhat 
> > sub-optimal, but understandable for a development / test 
> > environment.  And certainly 40k locations is a lot for the sorting 
> > algorithm currently used.
> > 
> >>> Further, since each location contains configuration for
> >>> all modules, such configurations are expected to require a lot of
> >>> memory
> >> 
> >> Each of our nginx processes was consuming 5GB of memory in terms of
> >> resident size.
> >> This is not a problem as our servers have sufficient memory.
> >> 
> >>> Rather, I would suggest recursive top-bottom merge sort implementation
> >>> instead, which is much simpler and uses stack as temporary storage
> >>> (so it'll naturally die if there will be a queue which requires
> >>> more space for sorting than we have).
> 
> For the record, in my tests on M1 sorting 26^3 locations fit into
> 32k stack size (16k stack size renders the environment unusable).
> Judging by this (unscientific) test, running out of stack should
> not be a practicable issue.

The recursive function uses

ngx_queue_t  *q, tail;

on stack, that is, 3 pointers, so it would need more than 1000 
recursive calls to overflow 32k stack, which is not expected to 
happen unless there are more than 2^1000 locations (and it is 
certainly not possible to have more than 2^64 locations on 64-bit 
platforms).

For 26^3 locations, sorting would use maximum recursion depth of 
15, so would require something like 360 bytes of stack (which is 
certainly less than required by other nginx functions).

> >>> 
> >>> Please take a look if it works for you:
> >> 
> >> I think this implementation is simple and easy to understand.
> >> Although the number of traversals of the list will increase compared
> >> to bottom-up, it will not affect the order.
> >> I believe this will provide sufficient optimization in terms of speed.
> > 
> > Thanks for looking.  In my limited testing, it is slightly faster 
> > than your bottom-up implementation (and significantly faster than 
> > the existing insertion sort when many locations are used).
> > 
> > Below is the full patch (code unchanged), I'll commit it as soon 
> > as some other nginx developer will review it.
> > 
> > # HG changeset patch
> > # User Maxim Dounin 
> > # Date 1696977468 -10800
> > #  Wed Oct 11 01:37:48 2023 +0300
> > # Node ID b891840852ee5cc823eee1769d092ab50928919f
> > # Parent  cdda286c0f1b4b10f30d4eb6a63fefb9b8708ecc
> > Core: changed ngx_queue_sort() to use merge sort.
> > 
> > This improves nginx startup times significantly when using very large number
> > of locations due computational complexity of the sorting algorithm being
> 
> due to

Fixed, thnx.

> > used (insertion sort is O(n*n) on average, while merge sort is O(n*log(n))).
> 
> nitpicking: E2MANYPARENS
> 
> Using a colon might looks better (I don't mind though):
> used: insertion sort is O(n*n) on average, while merge sort is O(n*log(n)).

Thanks, changed.

> > In particular, in a test configuration with 20k locations total startup
> > time is reduced from 8 seconds to 0.9 seconds.
> > 
> > Prodded by Yusuke Nojima,
> > https://mailman.nginx.org/pipermail/nginx-devel/2023-September/NUL3Y2FPPFSHMPTFTL65KXSXNTX3NQMK.htm

Re: Memory Leak Issue in Nginx PCRE2

2023-10-16 Thread Maxim Dounin
Hello!

On Mon, Oct 16, 2023 at 06:19:48PM +0400, Sergey Kandaurov wrote:

> 
> > On 11 Oct 2023, at 02:04, Maxim Dounin  wrote:
> > 
> > Hello!
> > 
> > On Wed, Sep 27, 2023 at 01:13:44AM +0800, 上勾拳 wrote:
> > 
> >> Dear Nginx Developers,
> >> 
> >> I hope this email finds you well. I am reaching out to the mailing list for
> >> the first time to report and discuss an issue I encountered while working
> >> on supporting PCRE2 in OpenResty. If I have made any errors in my reporting
> >> or discussion, please do not hesitate to provide feedback. Your guidance is
> >> greatly appreciated.
> >> 
> >> During my recent work, I used the sanitizer to inspect potential issues,
> >> and I identified a small memory leak in the PCRE2 code section of Nginx.
> >> While this issue does not seem to be critical, it could potentially disrupt
> >> memory checking tools. To help you reproduce the problem, I have included a
> >> minimal configuration below. Please note that this issue occurs when Nginx
> >> is configured to use PCRE2, and the version is 1.22.1 or higher.
> >> 
> >> *Minimal Configuration for Reproduction:*
> >> worker_processes  1;
> >> daemon off;
> >> master_process off;
> >> error_log
> >> /home/zhenzhongw/code/pcre_pr/lua-nginx-module/t/servroot/logs/error.log
> >> debug;
> >> pid
> >> /home/zhenzhongw/code/pcre_pr/lua-nginx-module/t/servroot/logs/nginx.pid;
> >> 
> >> http {
> >>access_log
> >> /home/zhenzhongw/code/pcre_pr/lua-nginx-module/t/servroot/logs/access.log;
> >>#access_log off;
> >>default_type text/plain;
> >>keepalive_timeout  68000ms;
> >>server {
> >>listen  1984;
> >>#placeholder
> >>server_name 'localhost';
> >> 
> >>client_max_body_size 30M;
> >>#client_body_buffer_size 4k;
> >> 
> >># Begin preamble config...
> >> 
> >># End preamble config...
> >> 
> >># Begin test case config...
> >> 
> >>location ~ '^/[a-d]$' {
> >>return 200;
> >>}
> >>}
> >> }
> >> events {
> >>accept_mutex off;
> >> 
> >>worker_connections  64;
> >> }
> >> 
> >> *nginx -V :*
> >> nginx version: nginx/1.25.1 (no pool)
> >> built by gcc 11.4.1 20230605 (Red Hat 11.4.1-2) (GCC)
> >> built with OpenSSL 1.1.1u  30 May 2023
> >> TLS SNI support enabled
> >> configure arguments:
> >> --prefix=/home/zhenzhongw/code/pcre_pr/lua-nginx-module/work/nginx
> >> --with-threads --with-pcre-jit --with-ipv6
> >> --with-cc-opt='-fno-omit-frame-pointer -fsanitize=address
> >> -DNGX_LUA_USE_ASSERT -I/opt/pcre2/include -I/opt/ssl/include'
> >> --with-http_v2_module --with-http_v3_module --with-http_realip_module
> >> --with-http_ssl_module
> >> --add-module=/home/zhenzhongw/code/pcre_pr/ndk-nginx-module
> >> --add-module=/home/zhenzhongw/code/pcre_pr/set-misc-nginx-module
> >> --with-ld-opt='-fsanitize=address -L/opt/pcre2/lib -L/opt/ssl/lib
> >> -Wl,-rpath,/opt/pcre2/lib:/opt/drizzle/lib:/opt/ssl/lib'
> >> --without-mail_pop3_module --without-mail_imap_module
> >> --with-http_image_filter_module --without-mail_smtp_module --with-stream
> >> --with-stream_ssl_module --without-http_upstream_ip_hash_module
> >> --without-http_memcached_module --without-http_auth_basic_module
> >> --without-http_userid_module --with-http_auth_request_module
> >> --add-module=/home/zhenzhongw/code/pcre_pr/echo-nginx-module
> >> --add-module=/home/zhenzhongw/code/pcre_pr/memc-nginx-module
> >> --add-module=/home/zhenzhongw/code/pcre_pr/srcache-nginx-module
> >> --add-module=/home/zhenzhongw/code/pcre_pr/lua-nginx-module
> >> --add-module=/home/zhenzhongw/code/pcre_pr/lua-upstream-nginx-module
> >> --add-module=/home/zhenzhongw/code/pcre_pr/headers-more-nginx-module
> >> --add-module=/home/zhenzhongw/code/pcre_pr/drizzle-nginx-module
> >> --add-module=/home/zhenzhongw/code/pcre_pr/rds-json-nginx-module
> >> --add-module=/home/zhenzhongw/code/pcre_pr/coolkit-nginx-module
> >> --add-module=/home/zhenzhongw/code/pcre_pr/redis2-nginx-module
> >> --add-module=/home/zhenzhongw/code/pcre_pr/stream-lua-nginx-module
> >> --add-module=/home/zhenzhongw/code/pcre_pr/lua-nginx-module/t/data/f

Re: [PATCH] Improve performance when starting nginx with a lot of locations

2023-10-10 Thread Maxim Dounin
Hello!

On Thu, Oct 05, 2023 at 10:51:26AM +0900, Yusuke Nojima wrote:

> Thank you for your comment!
> 
> > Could you please provide some more details about the use case,
> > such as how locations are used, and what is the approximate number
> > of locations being used?
> 
> Our team provides development environments to our company's engineers and QA.
> In this environment, engineers and QA can freely create VMs and deploy
> applications on them.
> 
> Our nginx has the role of routing requests from the internet to all
> applications deployed in this environment.
> Additionally, it allows setting IP address restrictions, BASIC
> authentication, TLS client authentication, and other configurations
> for each application.
> 
> To implement these requirements, we generate a location for each application.
> Currently, there are approximately 40,000 locations in our environment.

Thank you for the details.  Such configuration looks somewhat 
sub-optimal, but understandable for a development / test 
environment.  And certainly 40k locations is a lot for the sorting 
algorithm currently used.

> > Further, since each location contains configuration for
> > all modules, such configurations are expected to require a lot of
> > memory
> 
> Each of our nginx processes was consuming 5GB of memory in terms of
> resident size.
> This is not a problem as our servers have sufficient memory.
> 
> > Rather, I would suggest recursive top-bottom merge sort implementation
> > instead, which is much simpler and uses stack as temporary storage
> > (so it'll naturally die if there will be a queue which requires
> > more space for sorting than we have).
> >
> > Please take a look if it works for you:
> 
> I think this implementation is simple and easy to understand.
> Although the number of traversals of the list will increase compared
> to bottom-up, it will not affect the order.
> I believe this will provide sufficient optimization in terms of speed.

Thanks for looking.  In my limited testing, it is slightly faster 
than your bottom-up implementation (and significantly faster than 
the existing insertion sort when many locations are used).

Below is the full patch (code unchanged), I'll commit it as soon 
as some other nginx developer will review it.

# HG changeset patch
# User Maxim Dounin 
# Date 1696977468 -10800
#  Wed Oct 11 01:37:48 2023 +0300
# Node ID b891840852ee5cc823eee1769d092ab50928919f
# Parent  cdda286c0f1b4b10f30d4eb6a63fefb9b8708ecc
Core: changed ngx_queue_sort() to use merge sort.

This improves nginx startup times significantly when using very large number
of locations due computational complexity of the sorting algorithm being
used (insertion sort is O(n*n) on average, while merge sort is O(n*log(n))).
In particular, in a test configuration with 20k locations total startup
time is reduced from 8 seconds to 0.9 seconds.

Prodded by Yusuke Nojima,
https://mailman.nginx.org/pipermail/nginx-devel/2023-September/NUL3Y2FPPFSHMPTFTL65KXSXNTX3NQMK.html

diff --git a/src/core/ngx_queue.c b/src/core/ngx_queue.c
--- a/src/core/ngx_queue.c
+++ b/src/core/ngx_queue.c
@@ -9,6 +9,10 @@
 #include 
 
 
+static void ngx_queue_merge(ngx_queue_t *queue, ngx_queue_t *tail,
+ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *));
+
+
 /*
  * find the middle queue element if the queue has odd number of elements
  * or the first element of the queue's second part otherwise
@@ -45,13 +49,13 @@ ngx_queue_middle(ngx_queue_t *queue)
 }
 
 
-/* the stable insertion sort */
+/* the stable merge sort */
 
 void
 ngx_queue_sort(ngx_queue_t *queue,
 ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *))
 {
-ngx_queue_t  *q, *prev, *next;
+ngx_queue_t  *q, tail;
 
 q = ngx_queue_head(queue);
 
@@ -59,22 +63,44 @@ ngx_queue_sort(ngx_queue_t *queue,
 return;
 }
 
-for (q = ngx_queue_next(q); q != ngx_queue_sentinel(queue); q = next) {
+q = ngx_queue_middle(queue);
+
+ngx_queue_split(queue, q, );
+
+ngx_queue_sort(queue, cmp);
+ngx_queue_sort(, cmp);
+
+ngx_queue_merge(queue, , cmp);
+}
 
-prev = ngx_queue_prev(q);
-next = ngx_queue_next(q);
 
-ngx_queue_remove(q);
+static void
+ngx_queue_merge(ngx_queue_t *queue, ngx_queue_t *tail,
+ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *))
+{
+ngx_queue_t  *q1, *q2;
+
+q1 = ngx_queue_head(queue);
+q2 = ngx_queue_head(tail);
 
-do {
-if (cmp(prev, q) <= 0) {
-break;
-}
+for ( ;; ) {
+if (q1 == ngx_queue_sentinel(queue)) {
+ngx_queue_add(queue, tail);
+break;
+}
+
+if (q2 == ngx_queue_sentinel(tail)) {
+break;
+}
 
-prev = ngx_queue_prev(prev);
+if (cmp(q1, q2) <= 0) {
+  

Re: Memory Leak Issue in Nginx PCRE2

2023-10-10 Thread Maxim Dounin
bles.c:2555
> #5 0x536088 in ngx_http_core_regex_location
> src/http/ngx_http_core_module.c:3263
> #6 0x537f94 in ngx_http_core_location
> src/http/ngx_http_core_module.c:3115
> #7 0x46ba0a in ngx_conf_handler src/core/ngx_conf_file.c:463
> #8 0x46ba0a in ngx_conf_parse src/core/ngx_conf_file.c:319
> #9 0x5391ec in ngx_http_core_server src/http/ngx_http_core_module.c:2991
> #10 0x46ba0a in ngx_conf_handler src/core/ngx_conf_file.c:463
> #11 0x46ba0a in ngx_conf_parse src/core/ngx_conf_file.c:319
> #12 0x528e4c in ngx_http_block src/http/ngx_http.c:239
> #13 0x46ba0a in ngx_conf_handler src/core/ngx_conf_file.c:463
> #14 0x46ba0a in ngx_conf_parse src/core/ngx_conf_file.c:319
> #15 0x463f74 in ngx_init_cycle src/core/ngx_cycle.c:284
> #12 0x528e4c in ngx_http_block src/http/ngx_http.c:239
> #13 0x46ba0a in ngx_conf_handler src/core/ngx_conf_file.c:463
> #14 0x46ba0a in ngx_conf_parse src/core/ngx_conf_file.c:319
> #15 0x463f74 in ngx_init_cycle src/core/ngx_cycle.c:284
> #16 0x4300c7 in main src/core/nginx.c:295
> #17 0x7ff31a43feaf in __libc_start_call_main (/lib64/libc.so.6+0x3feaf)
> 
> SUMMARY: AddressSanitizer: 72 byte(s) leaked in 1 allocation(s).
> 
> *I have created a patch to address this memory leak issue, which I am
> sharing below:*
> diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c
> index 91381f499..71f583789 100644
> --- a/src/core/ngx_regex.c
> +++ b/src/core/ngx_regex.c
> @@ -600,6 +600,8 @@ ngx_regex_cleanup(void *data)
>   * the new cycle, these will be re-allocated.
>   */
> 
> +ngx_regex_malloc_init(NULL);
> +
>  if (ngx_regex_compile_context) {
>  pcre2_compile_context_free(ngx_regex_compile_context);
>  ngx_regex_compile_context = NULL;
> @@ -611,6 +613,8 @@ ngx_regex_cleanup(void *data)
>  ngx_regex_match_data_size = 0;
>  }
> 
> +ngx_regex_malloc_done();
> +
>  #endif
>  }
> 
> @@ -706,7 +710,13 @@ ngx_regex_module_init(ngx_cycle_t *cycle)
>  ngx_regex_malloc_done();
> 
>  ngx_regex_studies = NULL;
> +
>  #if (NGX_PCRE2)
> +if (ngx_regex_compile_context) {
> +ngx_regex_malloc_init(NULL);
> +pcre2_compile_context_free(ngx_regex_compile_context);
> +ngx_regex_malloc_done();
> +}
>  ngx_regex_compile_context = NULL;
>  #endif
> 
> I kindly request your assistance in reviewing this matter and considering
> the patch for inclusion in Nginx. If you have any questions or need further
> information, please feel free to reach out to me. Your expertise and
> feedback are highly valuable in resolving this issue.

Thank you for the report.

Indeed, this looks like a small leak which manifests itself during 
reconfiguration when nginx is compiled with PCRE2.

The patch looks correct to me, though I think it would be better 
to don't do anything with ngx_regex_compile_context in 
ngx_regex_module_init().  Please take a look if the following 
patch looks good to you:

# HG changeset patch
# User Maxim Dounin 
# Date 1696950530 -10800
#  Tue Oct 10 18:08:50 2023 +0300
# Node ID 0ceb96f57592b77618fba4200797df977241ec9b
# Parent  cdda286c0f1b4b10f30d4eb6a63fefb9b8708ecc
Core: fixed memory leak on configuration reload with PCRE2.

In ngx_regex_cleanup() allocator wasn't configured when calling
pcre2_compile_context_free() and pcre2_match_data_free(), resulting
in no ngx_free() call and leaked memory.  Fix is ensure that allocator
is configured for global allocations, so that ngx_free() is actually
called to free memory.

Additionally, ngx_regex_compile_context was cleared in
ngx_regex_module_init().  It should be either not cleared, so it will
be freed by ngx_regex_cleanup(), or properly freed.  Fix is to
not clear it, so ngx_regex_cleanup() will be able to free it.

Reported by ZhenZhong Wu,
https://mailman.nginx.org/pipermail/nginx-devel/2023-September/3Z5FIKUDRN2WBSL3JWTZJ7SXDA6YIWPB.html

diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c
--- a/src/core/ngx_regex.c
+++ b/src/core/ngx_regex.c
@@ -600,6 +600,8 @@ ngx_regex_cleanup(void *data)
  * the new cycle, these will be re-allocated.
  */
 
+ngx_regex_malloc_init(NULL);
+
 if (ngx_regex_compile_context) {
 pcre2_compile_context_free(ngx_regex_compile_context);
 ngx_regex_compile_context = NULL;
@@ -611,6 +613,8 @@ ngx_regex_cleanup(void *data)
 ngx_regex_match_data_size = 0;
 }
 
+ngx_regex_malloc_done();
+
 #endif
 }
 
@@ -706,9 +710,6 @@ ngx_regex_module_init(ngx_cycle_t *cycle
 ngx_regex_malloc_done();
 
 ngx_regex_studies = NULL;
-#if (NGX_PCRE2)
-ngx_regex_compile_context = NULL;
-#endif
 
 return NGX_OK;
 }


-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] HTTP/2: per-iteration stream handling limit

2023-10-10 Thread Maxim Dounin
Hello!

On Tue, Oct 10, 2023 at 05:57:58PM +, Thomas Ward wrote:

> Maxim:
> 
> If NGINX is unaffected, then F5 is distributing the FUD.

Yes, they are.

> Refer to https://my.f5.com/manage/s/article/K000137106 and the 
> NGINX category, specifically NGINX OSS.  Right now, unless this 
> is updated by F5 (who owns NGINX now) there is conflicting 
> information here.  May I suggest you go internally to F5 and 
> have them actually *revise* their update, or further indicate 
> that "There are already mitigations in place"?

I'm not "internally to F5", I'm an independent developer.  This 
was discussed within nginx security team, with other nginx 
developers, and the conclusion is that nginx is not affected.

I have no idea why F5 decided to include nginx as affected in 
their advisory, who did this, and why.  This is incorrect and 
should be fixed.  I've already pinged them, and hopefully they 
will fix this.

> Ultimately, 
> though, I would assume that keepalive at 100 is also still not 
> enough to *fully* protect against this, therefore at the core 
> "NGINX is still vulnerable to this CVE despite mitigations 
> already being in place for default configuration values and 
> options" is the interpretation, which means yes NGINX is in fact 
> affected by this *in non-default configurations*, which means 
> that it *is* still vulnerable to the CVE.  Mitigations don't 
> mean "fixed" or "not affected" in the strictest interpretation 
> of languages and what means what.

As often the case for DoS vulnerabilities, you cannot be *fully* 
protected, since there is a work to do anyway.  As long as nginx 
is configured to serve HTTP requests, it can be loaded with 
serving HTTP requests, and maximum possible load depends on the 
configurations, including various builtin limits, such as 
keepalive_requests and http2_max_concurrent_streams, and DoS 
mitigations which needs to be explicitly configured, such as 
limit_req and limit_conn.

As already said, in this case the work nginx is willing to do is 
no different from other workloads, such as with normal HTTP/2 
requests or HTTP/1.x requests.  As such, nginx is not considered 
to be affected by this issue.

> 
> 
> Thomas
> 
> -Original Message-
> From: nginx-devel  On Behalf Of Maxim Dounin
> Sent: Tuesday, October 10, 2023 8:53 AM
> To: nginx-devel@nginx.org
> Subject: Re: [PATCH] HTTP/2: per-iteration stream handling limit
> 
> Hello!
> 
> On Tue, Oct 10, 2023 at 03:29:02PM +0300, Maxim Dounin wrote:
> 
> > # HG changeset patch
> > # User Maxim Dounin  # Date 1696940019 -10800
> > #  Tue Oct 10 15:13:39 2023 +0300
> > # Node ID cdda286c0f1b4b10f30d4eb6a63fefb9b8708ecc
> > # Parent  3db945fda515014d220151046d02f3960bcfca0a
> > HTTP/2: per-iteration stream handling limit.
> > 
> > To ensure that attempts to flood servers with many streams are 
> > detected early, a limit of no more than 2 * max_concurrent_streams new 
> > streams per one event loop iteration was introduced.  This limit is 
> > applied even if max_concurrent_streams is not yet reached - for 
> > example, if corresponding streams are handled synchronously or reset.
> > 
> > Further, refused streams are now limited to maximum of 
> > max_concurrent_streams and 100, similarly to priority_limit initial 
> > value, providing some tolerance to clients trying to open several 
> > streams at the connection start, yet low tolerance to flooding attempts.
> 
> To clarify:
> 
> There is FUD being spread that nginx is vulnerable to CVE-2023-44487.
> 
> We do not consider nginx to be affected by this issue.  In the default 
> configuration, nginx is sufficiently protected by the limit of allowed 
> requests per connection (see http://nginx.org/r/keepalive_requests for 
> details), so an attacker will be required to reconnect very often, making the 
> attack obvious and easy to stop at the network level.  And it is not possible 
> to circumvent the max concurrent streams limit in nginx, as nginx only allows 
> additional streams when previous streams are completely closed.
> 
> Further, additional protection can be implemented in nginx by using the 
> "limit_req" directive, which limits the rate of requests and rejects 
> excessive requests.
> 
> Overall, with the handling as implemented in nginx, impact of streams being 
> reset does no seem to be significantly different from impacts from over 
> workloads with large number of requests being sent by the client, such as 
> handling of multiple HTTP/2 requests or HTTP/1.x pipelined requests.
> 
> Nevertheless, we've decided to implemented some additional mitigations which 
> will help nginx to detect such attacks and

Re: [PATCH] HTTP/2: per-iteration stream handling limit

2023-10-10 Thread Maxim Dounin
Hello!

On Tue, Oct 10, 2023 at 04:46:04PM +0400, Sergey Kandaurov wrote:

> 
> > On 10 Oct 2023, at 16:29, Maxim Dounin  wrote:
> > 
> > # HG changeset patch
> > # User Maxim Dounin 
> > # Date 1696940019 -10800
> > #  Tue Oct 10 15:13:39 2023 +0300
> > # Node ID cdda286c0f1b4b10f30d4eb6a63fefb9b8708ecc
> > # Parent  3db945fda515014d220151046d02f3960bcfca0a
> > HTTP/2: per-iteration stream handling limit.
> > 
> > To ensure that attempts to flood servers with many streams are detected
> > early, a limit of no more than 2 * max_concurrent_streams new streams per 
> > one
> > event loop iteration was introduced.  This limit is applied even if
> > max_concurrent_streams is not yet reached - for example, if corresponding
> > streams are handled synchronously or reset.
> > 
> > Further, refused streams are now limited to maximum of 
> > max_concurrent_streams
> > and 100, similarly to priority_limit initial value, providing some tolerance
> > to clients trying to open several streams at the connection start, yet
> > low tolerance to flooding attempts.
> > 
> > diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
> > --- a/src/http/v2/ngx_http_v2.c
> > +++ b/src/http/v2/ngx_http_v2.c
> > @@ -347,6 +347,7 @@ ngx_http_v2_read_handler(ngx_event_t *re
> > ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 read handler");
> > 
> > h2c->blocked = 1;
> > +h2c->new_streams = 0;
> > 
> > if (c->close) {
> > c->close = 0;
> > @@ -1284,6 +1285,14 @@ ngx_http_v2_state_headers(ngx_http_v2_co
> > goto rst_stream;
> > }
> > 
> > +if (h2c->new_streams++ >= 2 * h2scf->concurrent_streams) {
> > +ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
> > +  "client sent too many streams at once");
> > +
> > +status = NGX_HTTP_V2_REFUSED_STREAM;
> > +goto rst_stream;
> > +}
> > +
> > if (!h2c->settings_ack
> > && !(h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG)
> > && h2scf->preread_size < NGX_HTTP_V2_DEFAULT_WINDOW)
> > @@ -1349,6 +1358,12 @@ ngx_http_v2_state_headers(ngx_http_v2_co
> > 
> > rst_stream:
> > 
> > +if (h2c->refused_streams++ > ngx_max(h2scf->concurrent_streams, 100)) {
> > +ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
> > +  "client sent too many refused streams");
> > +return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_NO_ERROR);
> > +}
> > +
> > if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid, status) != NGX_OK) 
> > {
> > return ngx_http_v2_connection_error(h2c, 
> > NGX_HTTP_V2_INTERNAL_ERROR);
> > }
> > diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h
> > --- a/src/http/v2/ngx_http_v2.h
> > +++ b/src/http/v2/ngx_http_v2.h
> > @@ -131,6 +131,8 @@ struct ngx_http_v2_connection_s {
> > ngx_uint_t   processing;
> > ngx_uint_t   frames;
> > ngx_uint_t   idle;
> > +ngx_uint_t   new_streams;
> > +ngx_uint_t   refused_streams;
> > ngx_uint_t   priority_limit;
> > 
> > size_t   send_window;
> 
> Looks good.

Pushed to http://mdounin.ru/hg/nginx/, thanks.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] HTTP/2: per-iteration stream handling limit

2023-10-10 Thread Maxim Dounin
Hello!

On Tue, Oct 10, 2023 at 03:29:02PM +0300, Maxim Dounin wrote:

> # HG changeset patch
> # User Maxim Dounin 
> # Date 1696940019 -10800
> #  Tue Oct 10 15:13:39 2023 +0300
> # Node ID cdda286c0f1b4b10f30d4eb6a63fefb9b8708ecc
> # Parent  3db945fda515014d220151046d02f3960bcfca0a
> HTTP/2: per-iteration stream handling limit.
> 
> To ensure that attempts to flood servers with many streams are detected
> early, a limit of no more than 2 * max_concurrent_streams new streams per one
> event loop iteration was introduced.  This limit is applied even if
> max_concurrent_streams is not yet reached - for example, if corresponding
> streams are handled synchronously or reset.
> 
> Further, refused streams are now limited to maximum of max_concurrent_streams
> and 100, similarly to priority_limit initial value, providing some tolerance
> to clients trying to open several streams at the connection start, yet
> low tolerance to flooding attempts.

To clarify:

There is FUD being spread that nginx is vulnerable to 
CVE-2023-44487.

We do not consider nginx to be affected by this issue.  In the 
default configuration, nginx is sufficiently protected by the 
limit of allowed requests per connection (see 
http://nginx.org/r/keepalive_requests for details), so an attacker 
will be required to reconnect very often, making the attack 
obvious and easy to stop at the network level.  And it is not 
possible to circumvent the max concurrent streams limit in nginx, 
as nginx only allows additional streams when previous streams are 
completely closed.

Further, additional protection can be implemented in nginx by 
using the "limit_req" directive, which limits the rate of requests 
and rejects excessive requests.

Overall, with the handling as implemented in nginx, impact of 
streams being reset does no seem to be significantly different 
from impacts from over workloads with large number of requests 
being sent by the client, such as handling of multiple HTTP/2 
requests or HTTP/1.x pipelined requests.

Nevertheless, we've decided to implemented some additional 
mitigations which will help nginx to detect such attacks and drop 
connections with misbehaving clients faster.  Hence the patch.

> 
> diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
> --- a/src/http/v2/ngx_http_v2.c
> +++ b/src/http/v2/ngx_http_v2.c
> @@ -347,6 +347,7 @@ ngx_http_v2_read_handler(ngx_event_t *re
>  ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 read handler");
>  
>  h2c->blocked = 1;
> +h2c->new_streams = 0;
>  
>  if (c->close) {
>  c->close = 0;
> @@ -1284,6 +1285,14 @@ ngx_http_v2_state_headers(ngx_http_v2_co
>  goto rst_stream;
>  }
>  
> +if (h2c->new_streams++ >= 2 * h2scf->concurrent_streams) {
> +ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
> +  "client sent too many streams at once");
> +
> +status = NGX_HTTP_V2_REFUSED_STREAM;
> +goto rst_stream;
> +}
> +
>  if (!h2c->settings_ack
>  && !(h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG)
>  && h2scf->preread_size < NGX_HTTP_V2_DEFAULT_WINDOW)
> @@ -1349,6 +1358,12 @@ ngx_http_v2_state_headers(ngx_http_v2_co
>  
>  rst_stream:
>  
> +if (h2c->refused_streams++ > ngx_max(h2scf->concurrent_streams, 100)) {
> +ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
> +  "client sent too many refused streams");
> +return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_NO_ERROR);
> +}
> +
>  if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid, status) != NGX_OK) {
>  return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
>  }
> diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h
> --- a/src/http/v2/ngx_http_v2.h
> +++ b/src/http/v2/ngx_http_v2.h
> @@ -131,6 +131,8 @@ struct ngx_http_v2_connection_s {
>  ngx_uint_t   processing;
>  ngx_uint_t   frames;
>  ngx_uint_t   idle;
> +ngx_uint_t   new_streams;
> +ngx_uint_t   refused_streams;
>  ngx_uint_t   priority_limit;
>  
>  size_t   send_window;
> ___
> nginx-devel mailing list
> nginx-devel@nginx.org
> https://mailman.nginx.org/mailman/listinfo/nginx-devel

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


[PATCH] HTTP/2: per-iteration stream handling limit

2023-10-10 Thread Maxim Dounin
# HG changeset patch
# User Maxim Dounin 
# Date 1696940019 -10800
#  Tue Oct 10 15:13:39 2023 +0300
# Node ID cdda286c0f1b4b10f30d4eb6a63fefb9b8708ecc
# Parent  3db945fda515014d220151046d02f3960bcfca0a
HTTP/2: per-iteration stream handling limit.

To ensure that attempts to flood servers with many streams are detected
early, a limit of no more than 2 * max_concurrent_streams new streams per one
event loop iteration was introduced.  This limit is applied even if
max_concurrent_streams is not yet reached - for example, if corresponding
streams are handled synchronously or reset.

Further, refused streams are now limited to maximum of max_concurrent_streams
and 100, similarly to priority_limit initial value, providing some tolerance
to clients trying to open several streams at the connection start, yet
low tolerance to flooding attempts.

diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
--- a/src/http/v2/ngx_http_v2.c
+++ b/src/http/v2/ngx_http_v2.c
@@ -347,6 +347,7 @@ ngx_http_v2_read_handler(ngx_event_t *re
 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 read handler");
 
 h2c->blocked = 1;
+h2c->new_streams = 0;
 
 if (c->close) {
 c->close = 0;
@@ -1284,6 +1285,14 @@ ngx_http_v2_state_headers(ngx_http_v2_co
 goto rst_stream;
 }
 
+if (h2c->new_streams++ >= 2 * h2scf->concurrent_streams) {
+ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
+  "client sent too many streams at once");
+
+status = NGX_HTTP_V2_REFUSED_STREAM;
+goto rst_stream;
+}
+
 if (!h2c->settings_ack
 && !(h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG)
 && h2scf->preread_size < NGX_HTTP_V2_DEFAULT_WINDOW)
@@ -1349,6 +1358,12 @@ ngx_http_v2_state_headers(ngx_http_v2_co
 
 rst_stream:
 
+if (h2c->refused_streams++ > ngx_max(h2scf->concurrent_streams, 100)) {
+ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
+  "client sent too many refused streams");
+return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_NO_ERROR);
+}
+
 if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid, status) != NGX_OK) {
 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
 }
diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h
--- a/src/http/v2/ngx_http_v2.h
+++ b/src/http/v2/ngx_http_v2.h
@@ -131,6 +131,8 @@ struct ngx_http_v2_connection_s {
 ngx_uint_t   processing;
 ngx_uint_t   frames;
 ngx_uint_t   idle;
+ngx_uint_t   new_streams;
+ngx_uint_t   refused_streams;
 ngx_uint_t   priority_limit;
 
 size_t   send_window;
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: optimize the code for searching file in ngx_conf_open_file

2023-10-07 Thread Maxim Dounin
Hello!

On Sat, Oct 07, 2023 at 06:09:18AM +0200, Davood Falahati wrote:

> # HG changeset patch
> # User Davood Falahati <0x0dav...@gmail.com>
> # Date 1696647746 -7200
> #  Sat Oct 07 05:02:26 2023 +0200
> # Node ID ab14ea51bbb15331c9f44f14901d0fd378168647
> # Parent  c073e545e1cdcc736f8869a012a78b2dd836eac9
> optimize the code for searching file in ngx_conf_open_file
> 
> This patch combines two consecutive if statements into one and leveraging
> short circuits circuiting. In the current code, we check the lengths of
> file names and if they match, the file names are being compared.
> 
> I see few other places in the code that writing multiple if statements are
> preferred over short circuit evaluation (e.g.
> http://hg.nginx.org/nginx/file/tip/src/http/ngx_http_file_cache.c#l1153). I
> wanted to make sure if it's a matter of community's taste or if it's in
> line with some performance considerations?
> 
> diff -r c073e545e1cd -r ab14ea51bbb1 src/core/ngx_conf_file.c
> --- a/src/core/ngx_conf_file.c Thu May 18 23:42:22 2023 +0200
> +++ b/src/core/ngx_conf_file.c Sat Oct 07 05:02:26 2023 +0200
> @@ -927,11 +927,7 @@
>  i = 0;
>  }
> 
> -if (full.len != file[i].name.len) {
> -continue;
> -}
> -
> -if (ngx_strcmp(full.data, file[i].name.data) == 0) {
> +if (full.len == file[i].name.len && ngx_strcmp(full.data,
> file[i].name.data) == 0) {
>  return [i];
>  }
>  }

Thanks for your efforts, but we prefer the code as is.

There is no difference between these variants from the performance 
point of view.  On the other hand, the existing variant with 
separate length comparison is certainly more readable.  Further, 
the suggested change uses incorrect indentation, which is just 
wrong.

For more information about submitting patches, please see tips 
here:

http://nginx.org/en/docs/contributing_changes.html

For more information about nginx coding style, please refer to the 
code and here:

http://nginx.org/en/docs/dev/development_guide.html#code_style

Hope this helps.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] Auth basic: Cache credentials if auth_basic_user_file is static

2023-10-03 Thread Maxim Dounin
Hello!

On Tue, Oct 03, 2023 at 03:46:05PM -0700, Toshihito Kikuchi wrote:

> # HG changeset patch
> # User Toshihito Kikuchi 
> # Date 1696359541 25200
> #  Tue Oct 03 11:59:01 2023 -0700
> # Node ID e397ea6cfa85e85ae0865c5061397dc295fb7df1
> # Parent  3db945fda515014d220151046d02f3960bcfca0a
> Auth basic: Cache credentials if auth_basic_user_file is static.
> 
> In the current design, when auth_basic is on, every HTTP request triggers
> file I/O (open, read, close) to the file specified in auth_basic_user_file.
> Probably this is to allow auth_basic_user_file to contain variables.
> 
> If the value is just a static text, however, there is no reason to read the
> same file every request in every worker process.  It unnecessarily consumes
> system resources.
> 
> With this patch, if auth_basic_user_file does not have any variables, we
> cache its content in the location context at configuration time and use it
> in all subsequent requests.  If auth_basic_user_file contain variables, we 
> keep
> the original behavior.

As currently implemented, auth_basic_user_file is read at runtime, 
making it possible to change users and their passwords - which is 
a relatively common task - without reloading nginx itself.  And 
this behaviour matches the one in Apache, which does the same.  
Changing this behaviour to read the password file while loading 
configuration (so any changes to the file won't be applied unless 
nginx is reloaded) would certainly break POLA, and needs some 
really good justification.

Further, in typical setups the file is effectively cached by the 
OS itself, making the I/O operations mentioned almost free, 
especially compared to costs of typical password hash 
calculations.

[...]

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] Updated OpenSSL and zlib versions

2023-09-30 Thread Maxim Dounin
Hello!

On Tue, Sep 26, 2023 at 02:14:18PM +0100, Yaroslav Zhuravlev wrote:

>  xml/en/docs/configure.xml|   6 +++---
>  xml/en/docs/howto_build_on_win32.xml |  10 +-
>  xml/ru/docs/configure.xml|   6 +++---
>  3 files changed, 11 insertions(+), 11 deletions(-)
> 
> 

> # HG changeset patch
> # User Yaroslav Zhuravlev 
> # Date 1695733917 -3600
> #  Tue Sep 26 14:11:57 2023 +0100
> # Node ID 32a78db44cf00ab54063905e2a2ff4e5092a7b28
> # Parent  1ad61bfc7630adf1d6460cf84cec484de4017326
> Updated OpenSSL and zlib versions.
> 
> diff --git a/xml/en/docs/configure.xml b/xml/en/docs/configure.xml
> --- a/xml/en/docs/configure.xml
> +++ b/xml/en/docs/configure.xml
> @@ -8,7 +8,7 @@
> link="/en/docs/configure.html"
>   lang="en"
> - rev="22">
> + rev="23">
>  
>  
>  
> @@ -1270,7 +1270,7 @@
>  
>  sets the path to the sources of the zlib library.
>  The library distribution (version
> -1.1.31.2.11) needs to be downloaded from the
> +1.1.31.2.13) needs to be downloaded from the
>  http://zlib.net;>zlib site and extracted.
>  The rest is done by nginx’s ./configure and
>  make.

> @@ -1359,7 +1359,7 @@
>  --pid-path=/usr/local/nginx/nginx.pid
>  --with-http_ssl_module
>  --with-pcre=../pcre2-10.39
> ---with-zlib=../zlib-1.2.11
> +--with-zlib=../zlib-1.2.13
>  
>  
>  

zlib 1.3 was recently released and works just fine, so this 
probably should be bumped to 1.3 instead.

> diff --git a/xml/en/docs/howto_build_on_win32.xml 
> b/xml/en/docs/howto_build_on_win32.xml
> --- a/xml/en/docs/howto_build_on_win32.xml
> +++ b/xml/en/docs/howto_build_on_win32.xml
> @@ -9,7 +9,7 @@
> link="/en/docs/howto_build_on_win32.html"
>   lang="en"
> - rev="25">
> + rev="26">
>  
>  
>  
> @@ -81,8 +81,8 @@
>  mkdir objs/lib
>  cd objs/lib
>  tar -xzf ../../pcre2-10.39.tar.gz
> -tar -xzf ../../zlib-1.2.11.tar.gz
> -tar -xzf ../../openssl-1.1.1m.tar.gz
> +tar -xzf ../../zlib-1.2.13.tar.gz
> +tar -xzf ../../openssl-3.0.10.tar.gz
>  
>  
>  
> @@ -105,8 +105,8 @@
>  --http-uwsgi-temp-path=temp/uwsgi_temp \
>  --with-cc-opt=-DFD_SETSIZE=1024 \
>  --with-pcre=objs/lib/pcre2-10.39 \
> ---with-zlib=objs/lib/zlib-1.2.11 \
> ---with-openssl=objs/lib/openssl-1.1.1m \
> +--with-zlib=objs/lib/zlib-1.2.13 \
> +--with-openssl=objs/lib/openssl-3.0.10 \
>  --with-openssl-opt=no-asm \
>  --with-http_ssl_module
>  

And this used to match latest release of nginx/Windows, so zlib 
1.2.13 and OpenSSL 3.0.10 are probably fine here.  On the other 
hand, bumping to zlib 1.3 and OpenSSL 3.0.11 might be good enough 
as well (and will save an update to this file).

> diff --git a/xml/ru/docs/configure.xml b/xml/ru/docs/configure.xml
> --- a/xml/ru/docs/configure.xml
> +++ b/xml/ru/docs/configure.xml
> @@ -8,7 +8,7 @@
> link="/ru/docs/configure.html"
>   lang="ru"
> - rev="22">
> + rev="23">
>  
>  
>  
> @@ -1250,7 +1250,7 @@
>  
>  задаёт путь к исходным текстам библиотеки zlib.
>  Дистрибутив библиотеки (версию
> -1.1.31.2.11) нужно взять на сайте
> +1.1.31.2.13) нужно взять на сайте
>  http://zlib.net;>zlib и распаковать.
>  Всё остальное сделают ./configure nginx’а и
>  make.
> @@ -1339,7 +1339,7 @@
>  --pid-path=/usr/local/nginx/nginx.pid
>  --with-http_ssl_module
>  --with-pcre=../pcre2-10.39
> ---with-zlib=../zlib-1.2.11
> +--with-zlib=../zlib-1.2.13
>  
>  
>  

Otherwise looks good to me.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] Improve performance when starting nginx with a lot of locations

2023-09-29 Thread Maxim Dounin
_queue_sentinel(queue)) {
+ngx_queue_add(queue, tail);
+break;
+}
+
+if (q2 == ngx_queue_sentinel(tail)) {
+break;
+}
 
-prev = ngx_queue_prev(prev);
+if (cmp(q1, q2) <= 0) {
+q1 = ngx_queue_next(q1);
+continue;
+}
 
-} while (prev != ngx_queue_sentinel(queue));
+ngx_queue_remove(q2);
+ngx_queue_insert_before(q1, q2);
 
-ngx_queue_insert_after(prev, q);
+q2 = ngx_queue_head(tail);
 }
 }
diff --git a/src/core/ngx_queue.h b/src/core/ngx_queue.h
--- a/src/core/ngx_queue.h
+++ b/src/core/ngx_queue.h
@@ -47,6 +47,9 @@ struct ngx_queue_s {
 (h)->prev = x
 
 
+#define ngx_queue_insert_before   ngx_queue_insert_tail
+
+
 #define ngx_queue_head(h) \
 (h)->next
 


-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH 2 of 2] Added "max_shutdown_workers" directive

2023-09-25 Thread Maxim Dounin
es[i].exiting,
> ngx_processes[i].exited,
> ngx_processes[i].detached,
> ngx_processes[i].respawn,
> -   ngx_processes[i].just_spawn);
> +   ngx_processes[i].just_spawn,
> +   ngx_processes[i].old);
>  
>  if (ngx_processes[i].detached || ngx_processes[i].pid == -1) {
>  return;
> @@ -563,15 +630,16 @@ ngx_reap_children(ngx_cycle_t *cycle)
>  live = 0;
>  for (i = 0; i < ngx_last_process; i++) {
>  
> -ngx_log_debug7(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
> -   "child: %i %P e:%d t:%d d:%d r:%d j:%d",
> +ngx_log_debug8(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
> +   "child: %i %P e:%d t:%d d:%d r:%d j:%d o:%d",
> i,
> ngx_processes[i].pid,
> ngx_processes[i].exiting,
> ngx_processes[i].exited,
> ngx_processes[i].detached,
> ngx_processes[i].respawn,
> -   ngx_processes[i].just_spawn);
> +   ngx_processes[i].just_spawn,
> +   ngx_processes[i].old);
>  
>  if (ngx_processes[i].pid == -1) {
>  continue;
> @@ -660,6 +728,16 @@ ngx_reap_children(ngx_cycle_t *cycle)
>  ngx_processes[i].pid = -1;
>  }
>  

Note: when a process dies, it is restarted if the "respawn" flag 
is set, regardless of the "old" flag.  The "old" flag is preserved 
even if it is no longer relevant after the respawn: the process is 
restarted with the new configuration, and there is no need to 
restart it again.

> +if (ngx_processes[i].old
> +&& ngx_processes[i].exiting
> +&& !ngx_terminate
> +&& !ngx_quit)
> +{
> +if (ngx_restart_worker_process(cycle)) {
> +live = 1;
> +}
> +}
> +
>  } else if (ngx_processes[i].exiting || !ngx_processes[i].detached) {
>  live = 1;
>  }
> @@ -669,6 +747,53 @@ ngx_reap_children(ngx_cycle_t *cycle)
>  }
>  
>  
> +static ngx_uint_t
> +ngx_restart_worker_process(ngx_cycle_t *cycle)
> +{
> +ngx_int_t i, j, m;
> +ngx_core_conf_t  *ccf;
> +
> +ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
> +
> +j = -1;
> +m = ccf->max_shutdown_workers;
> +
> +if (m == 0) {
> +return 0;
> +}
> +
> +for (i = 0; i < ngx_last_process; i++) {
> +
> +if (ngx_processes[i].pid == -1 || !ngx_processes[i].old) {
> +continue;
> +}
> +
> +if (!ngx_processes[i].exiting && !ngx_processes[i].exited) {

The "exited" check here is not needed to catch the processes we 
were called for, or other processes being shut down - they already 
have "exiting" flag set.

On the other hand, this can catch unexpectedly died processes 
(the ones which are still waiting for restart).  As per the code, 
such processes will be counted against max_shutdown_workers as if 
they are shutting down - this looks wrong and can cause reload 
hang.

> +j = i;
> +continue;
> +}
> +
> +if (--m == 0) {
> +return 0;
> +}
> +}
> +
> +if (j == -1) {
> +return 0;
> +}
> +
> +ngx_start_worker_process(cycle, (intptr_t) ngx_processes[j].data,
> + NGX_PROCESS_RESPAWN);
> +
> +ngx_msleep(100);
> +
> +ngx_signal_worker_process(cycle, j,
> +  ngx_signal_value(NGX_SHUTDOWN_SIGNAL));

Also note that the "exited" check above implies that there can be 
multiple exited processes at the same time, but we only restart 
just one process here.

It might be a good idea to restart multiple processes at the same 
time: sleeping for 100ms for each process means that if, for 
example, 64 processes will exit at the same time after shutdown 
timeout expiration, master process will be unresponsive for 6 
seconds.

Also, this looks very close to ngx_restart_worker_processes().  It 
might be a good idea to rework things to ensure unified approach 
to restarting processes instead of providing multiple duplicate 
ways.

> +
> +return 1;
> +}
> +
> +
>  static void
>  ngx_master_process_exit(ngx_cycle_t *cycle)
>  {

Overall, I tend to think that the suggested code is very fragile, 
and I would rather consider re-thinking the approach.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] Linux packages: removed Ubuntu 22.10 'kinetic' due to EOL

2023-09-22 Thread Maxim Dounin
Hello!

On Fri, Sep 22, 2023 at 03:12:23PM -0700, Konstantin Pavlov wrote:

> # HG changeset patch
> # User Konstantin Pavlov 
> # Date 1695420683 25200
> #  Fri Sep 22 15:11:23 2023 -0700
> # Node ID 1ad61bfc7630adf1d6460cf84cec484de4017326
> # Parent  ac4191d05fdf12dbc977a3a26dfde2799d301283
> Linux packages: removed Ubuntu 22.10 'kinetic' due to EOL.
> 
> diff -r ac4191d05fdf -r 1ad61bfc7630 xml/en/linux_packages.xml
> --- a/xml/en/linux_packages.xml   Thu Sep 14 21:20:14 2023 +0100
> +++ b/xml/en/linux_packages.xml   Fri Sep 22 15:11:23 2023 -0700
> @@ -7,7 +7,7 @@
> link="/en/linux_packages.html"
>   lang="en"
> - rev="89">
> + rev="90">
>  
>  
>  
> @@ -88,11 +88,6 @@ versions:
>  
>  
>  
> -22.10 “kinetic”
> -x86_64, aarch64/arm64
> -
> -
> -
>  23.04 “lunar”
>  x86_64, aarch64/arm64
>  
> diff -r ac4191d05fdf -r 1ad61bfc7630 xml/ru/linux_packages.xml
> --- a/xml/ru/linux_packages.xml   Thu Sep 14 21:20:14 2023 +0100
> +++ b/xml/ru/linux_packages.xml   Fri Sep 22 15:11:23 2023 -0700
> @@ -7,7 +7,7 @@
> link="/ru/linux_packages.html"
>   lang="ru"
> - rev="89">
> + rev="90">
>  
>  
>  
> @@ -88,11 +88,6 @@
>  
>  
>  
> -22.10 “kinetic”
> -x86_64, aarch64/arm64
> -
> -
> -
>  23.04 “lunar”
>  x86_64, aarch64/arm64
>  

Looks fine.

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] Mail: allow auth to the proxy without auth to the backend

2023-09-19 Thread Maxim Dounin
Hello!

On Tue, Sep 19, 2023 at 12:28:49PM +0200, Arnout Engelen wrote:

> # HG changeset patch
> # User Arnout Engelen 
> # Date 1695027670 -7200
> #  Mon Sep 18 11:01:10 2023 +0200
> # Node ID 9606e589b9537495c0457383048ac6888be0e7b4
> # Parent  daf8f5ba23d8e9955b22782d945f9c065f4b6baa
> Mail: allow auth to the proxy without auth to the backend
> 
> Currently, when the client authenticates itself to the nginx
> mail proxy, the mail proxy also authenticates itself to the
> backend.
> 
> I encountered a situation where I wanted the proxy to require
> authentication, and forward the mail to a (local/firewalled)
> mailserver that does not have authentication configured. I
> created the patch below to support that.
> 
> I'm providing this patch primarily for feedback at this point:
> while it does work for my scenario and pass the nginx-tests,
> it likely needs additional cleanup and testing. I'd like your
> thoughs on whether this change makes sense in the first place,
> and whether this is generally a reasonable approach - if so I'll
> clean up the patch further.
> 
> My approach is to allow the authentication server to return a
> 'Auth-Method: none' header, in which case the proxy will not
> attempt to authenticate to the backend but instead wait for
> the 'MAIL FROM' from the client.
> 
> You'll notice I've added a 'proxy_auth_method'. The reason I didn't
> overwrite 'auth_method' is that 'auth_method' is also used to determine
> whether to confirm the authentication to the client. Is that acceptable
> from a binary compatibility perspective?
> 
> Looking forward to hearing your thoughts!

From the description it is not clear why "proxy_smtp_auth off;" 
(which is the default and implies that nginx won't try to 
authenticate against SMTP backends) does not work for you.  Could 
you please elaborate?

[...]

-- 
Maxim Dounin
http://mdounin.ru/
___
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel


  1   2   3   4   5   6   7   8   9   10   >