Bug 1388162

Summary: HTTPS request hangs when HTTP proxy responds too soon
Product: Red Hat Enterprise Linux 7 Reporter: Martin Frodl <mfrodl>
Component: curlAssignee: Kamil Dudka <kdudka>
Status: CLOSED ERRATA QA Contact: Karel Srot <ksrot>
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: 7.3CC: kdudka, raysatiro, szidek
Target Milestone: rcKeywords: FastFix, Patch
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: curl-7.29.0-39.el7 Doc Type: No Doc Update
Doc Text:
undefined
Story Points: ---
Clone Of: Environment:
Last Closed: 2017-08-01 17:02:31 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 1313924    
Attachments:
Description Flags
Proposed patch none

Description Martin Frodl 2016-10-24 15:44:45 UTC
Created attachment 1213507 [details]
Proposed patch

Description of problem:

When using a proxy for HTTPS requests, the SSL handshake is started in the CURLM_STATE_WAITCONNECT state and typically completed in CURLM_STATE_PROTOCONNECT. Ocasionally, however, when the proxy responds fast enough, the SSL handshake can be completed before CURLM_STATE_PROTOCONNECT.

Once in the CURLM_STATE_PROTOCONNECT state, nss_connect_common() is called.. At the very beginning, the function checks if the used connection is not already completed:

  if(connssl->state == ssl_connection_complete)
    return CURLE_OK;

The problem is, the variable 'done' inidicating a completed handshake is not set to TRUE in this case. As a consequence, the state machine gets stuck in CURLM_STATE_PROTOCONNECT because the variable 'protocol_connect' will always be FALSE.

I am attaching a patch that fixed the problem for me.

Version-Release number of selected component (if applicable):
curl-7.29.0-25.el7.s390x

How reproducible:
Randomly, but frequently enough. I only experienced this bug on s390x machines but other environments might be affected too.

Steps to Reproduce:
$ sudo yum -y install httpd mod_ssl squid
$ sudo systemctl start httpd squid
$ sudo echo OK > /var/www/html/test
$ while curl -v -k -x localhost:3128 https://localhost/test; do sleep 1; done

Actual results:

* About to connect() to proxy localhost port 3128 (#0)
*   Trying ::1...
* Connected to localhost (::1) port 3128 (#0)
* Establish HTTP proxy tunnel to localhost:443
> CONNECT localhost:443 HTTP/1.1
> Host: localhost:443
> User-Agent: curl/7.29.0
> Proxy-Connection: Keep-Alive
> 
< HTTP/1.1 200 Connection established
< 
* Proxy replied OK to CONNECT request
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* SSL connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate:
* 	subject: ...
* 	start date: ...
* 	expire date: ...
* 	common name: ...
* 	issuer: ...
<hangs>

Expected results:
All requests are served successfully.

Comment 2 Kamil Dudka 2016-10-25 08:11:41 UTC
Comment on attachment 1213507 [details]
Proposed patch

Thanks for the patch!  It looks good to me ... but we need to do the assignment in non-blocking mode only.  Otherwise we would dereference a NULL pointer.

I will push the patch upstream on your behalf (with the condition inserted).

Comment 3 Kamil Dudka 2016-10-25 10:08:04 UTC
upstream commit:

https://github.com/curl/curl/commit/curl-7_50_3-100-geb84412

Comment 9 errata-xmlrpc 2017-08-01 17:02:31 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://access.redhat.com/errata/RHSA-2017:2016