Bug 60223 - Non-blocking SSL reads fail when OpenSSL errors are already queued
Summary: Non-blocking SSL reads fail when OpenSSL errors are already queued
Alias: None
Product: Apache httpd-2
Classification: Unclassified
Component: mod_ssl (show other bugs)
Version: 2.4.16
Hardware: PC All
: P2 normal with 1 vote (vote)
Target Milestone: ---
Assignee: Apache HTTPD Bugs Mailing List
Keywords: FixedInTrunk, PatchAvailable
Depends on:
Reported: 2016-10-07 22:26 UTC by Paul Spangler
Modified: 2016-12-31 00:24 UTC (History)
0 users

Trunk patch to clear the error queue when SSL_get_error is needed (980 bytes, patch)
2016-10-07 22:26 UTC, Paul Spangler
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Paul Spangler 2016-10-07 22:26:52 UTC
Created attachment 34335 [details]
Trunk patch to clear the error queue when SSL_get_error is needed

mod_ssl doesn't clear the OpenSSL error queue prior to calling SSL_read, SSL_write, or SSL_accept. It then relies on SSL_get_error to be notified of errors such as SSL_ERROR_WANT_READ. Modules such as mod_websocket that perform non-blocking IO may receive errors if some other OpenSSL error is already queued.

One specific series of events where I run into errors:

1. The server is configured to use mod_session_crypto with the OpenSSL APR crypto provider.
2. The client connects over TLS and requests a WebSocket upgrade.
3. The client's session data is either corrupt or encrypted using an old key.
4. mod_session_crypto attempts to decrypt the session, which results in a call to the OpenSSL function EVP_EncryptFinal_ex.
5. The decryption fails, and the EVP function queues an error to the thread's OpenSSL error queue. The session is discarded, but APR never retrieves the error.
6. The WebSocket upgrade is accepted, and mod_websocket begins a non-blocking read on the input brigade.
7. mod_ssl calls SSL_read and the bio_filter_in_read reports no data is available by calling BIO_set_retry_read and returning -1.
8. mod_ssl then calls SSL_get_error, but instead of getting SSL_ERROR_WANT_READ, it gets the SSL_ERROR_SSL that was queued in step 5.
9. mod_websocket closes the connection due to the error returned by ap_get_brigade.

The attached patch to mod_ssl simply calls ERR_clear_error() prior to calling those three SSL_* functions. Patch was tested with a 2.4.16 64-bit Windows build according to the sequence of events noted previously.

See https://www.openssl.org/docs/manmaster/ssl/SSL_get_error.html#DESCRIPTION for reference.
Comment 1 Jacob Champion 2016-11-11 19:53:11 UTC
Committed in r1769332 (plus a couple explanatory comments), and proposed for backport to 2.4.x.
Comment 2 Eric Covener 2016-12-31 00:24:03 UTC
Fixed in 2.4.25