On 15/09/2020 17:35, ma...@apache.org wrote:
> This is an automated email from the ASF dual-hosted git repository.
> 
> markt pushed a commit to branch master
> in repository https://gitbox.apache.org/repos/asf/tomcat.git
> 
> 
> The following commit(s) were added to refs/heads/master by this push:
>      new 6c21ee5  Fix possible concurrency issue
> 6c21ee5 is described below
> 
> commit 6c21ee5a57e6a6fa9c780d4a8f857d5c3a0b9a35
> Author: Mark Thomas <ma...@apache.org>
> AuthorDate: Tue Sep 15 17:34:50 2020 +0100
> 
>     Fix possible concurrency issue

Hi,

This fix is a little on the speculative side.

I've been watching the intermittent CI failures for the last month or so
and there is evidence (mainly in failed WebSocket tests) of something
going wrong in HTTP request parsing.

Today, I saw a failure of once of the TestCoyoteAdapterRequestFuzzing
tests with the following stack trace:

15-Sep-2020 15:15:13.301 INFO [http-nio-127.0.0.1-auto-8-exec-1]
org.apache.coyote.http11.Http11Processor.service Error parsing HTTP
request header
 Note: further occurrences of HTTP request parsing errors will be logged
at DEBUG level.
        java.lang.IllegalArgumentException: Request header is too large
                at
org.apache.coyote.http11.Http11InputBuffer.fill(Http11InputBuffer.java:777)
                at
org.apache.coyote.http11.Http11InputBuffer.parseHeader(Http11InputBuffer.java:938)
                at
org.apache.coyote.http11.Http11InputBuffer.parseHeaders(Http11InputBuffer.java:589)
                at
org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:284)
                at
org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
                at
org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
                at
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590)
                at
org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
                at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
                at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
                at
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
                at java.lang.Thread.run(Thread.java:748)

Given the request, that should not be possible. The only explanation I
can come up with is that the recycling of the InputBuffer was not fully
visible to the http-nio-127.0.0.1-auto-8-exec-1 thread.

This seems a little far-fetched to me but I can't come up with a better
theory. With this theory in mind a looked at the Http11InputBuffer and
if my understanding is correct:
- there is a theoretical concurrency issue
- the patch below fixes it

I do intend to back-port this as my understanding is that the issue is
(theoretically) correct. I'll continue to keep an eye on the CI results
to see if there is any noticeable impact. That said, as I can't
reproduce this and impact is going to have be inferred.

Mark

> ---
>  java/org/apache/coyote/http11/Http11InputBuffer.java | 12 ++++++++----
>  1 file changed, 8 insertions(+), 4 deletions(-)
> 
> diff --git a/java/org/apache/coyote/http11/Http11InputBuffer.java 
> b/java/org/apache/coyote/http11/Http11InputBuffer.java
> index ab0d1c6..555e3ad 100644
> --- a/java/org/apache/coyote/http11/Http11InputBuffer.java
> +++ b/java/org/apache/coyote/http11/Http11InputBuffer.java
> @@ -71,7 +71,7 @@ public class Http11InputBuffer implements InputBuffer, 
> ApplicationBufferHandler
>      /**
>       * State.
>       */
> -    private boolean parsingHeader;
> +    private volatile boolean parsingHeader;
>  
>  
>      /**
> @@ -130,7 +130,7 @@ public class Http11InputBuffer implements InputBuffer, 
> ApplicationBufferHandler
>       */
>      private byte prevChr = 0;
>      private byte chr = 0;
> -    private boolean parsingRequestLine;
> +    private volatile boolean parsingRequestLine;
>      private int parsingRequestLinePhase = 0;
>      private boolean parsingRequestLineEol = false;
>      private int parsingRequestLineStart = 0;
> @@ -266,18 +266,22 @@ public class Http11InputBuffer implements InputBuffer, 
> ApplicationBufferHandler
>  
>          byteBuffer.limit(0).position(0);
>          lastActiveFilter = -1;
> -        parsingHeader = true;
>          swallowInput = true;
>  
>          chr = 0;
>          prevChr = 0;
>          headerParsePos = HeaderParsePosition.HEADER_START;
> -        parsingRequestLine = true;
>          parsingRequestLinePhase = 0;
>          parsingRequestLineEol = false;
>          parsingRequestLineStart = 0;
>          parsingRequestLineQPos = -1;
>          headerData.recycle();
> +        // Recycled last because they are volatile
> +        // All variables visible to this thread are guaranteed to be visible 
> to
> +        // any other thread once that thread reads the same volatile. The 
> first
> +        // action when parsing input data is to read one of these volatiles.
> +        parsingRequestLine = true;
> +        parsingHeader = true;
>      }
>  
>  
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
> For additional commands, e-mail: dev-h...@tomcat.apache.org
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to