Details
-
Bug
-
Status: Needs Feedback (View Workflow)
-
Major
-
Resolution: Unresolved
-
10.11.19, 11.4.13, 12.3.3
-
None
-
None
Description
Description
The VIO code fix for MDEV-30452 — handling OpenSSL 3.x SSL_R_UNEXPECTED_EOF_WHILE_READING in vio/viossl.c — was committed in January 2023 to branch bb-10.10-release-ssl (commit 11ae4ed4bf1) but never merged into any release branch. The JIRA ticket was closed as "Fixed in 10.10.3", but the 10.10.3 release (tag mariadb-10.10.3, commit e3e72644cfc) only includes the test-file adjustments, not the VIO code changes. Since 10.10 reached EOL in May 2023, the fix exists only on an orphaned branch.
All currently supported versions — 10.11.x, 11.4.x, 11.8.x, 12.3.x — are missing this fix as of September 2026.
Impact
Without this fix, when a client disconnects without sending close_notify (common with Java connection pools, abrupt network failures, or load balancers), OpenSSL 3.x pushes SSL_R_UNEXPECTED_EOF_WHILE_READING onto the per-thread error queue. MariaDB's vio_ssl_close() never clears these errors. In pool-of-threads mode, where worker threads are reused across connections, the stale error queue corrupts SSL_get_error() results for the next connection assigned to the same worker. The next connection then breaks with "Socket error" or "Got an error writing communication packets" even though nothing is wrong with it.
The bug requires all of: OpenSSL 3.x, SSL enabled, pool-of-threads, network connections (not localhost), and clients that disconnect without close_notify. On OpenSSL 1.1.1, the same situation produces SSL_ERROR_SYSCALL with errno=0, which does not add entries to the error queue — so the leak does not occur.
The three missing code changes in vio/viossl.c
All three changes exist in commit 11ae4ed4bf1 on branch bb-10.10-release-ssl. None exist on any active branch.
1. vio_ssl_close() — error queue not cleared after SSL_shutdown() failure
This is the critical fix for the thread pool scenario.
Current code on all active branches (10.11 through 12.3):
default: /* Shutdown failed */ |
DBUG_PRINT("vio_error", ("SSL_shutdown() failed, error: %d", |
SSL_get_error(ssl, r)));
|
break; |
In release builds, DBUG_PRINT expands to do { } while (0) — SSL_get_error() is never called, ERR_clear_error() is never called. The OpenSSL error queue retains whatever SSL_shutdown() left on it.
Note: MariaDB calls SSL_set_quiet_shutdown(ssl, 1) before SSL_shutdown(), which should prevent any actual shutdown protocol. However, after SSL_read() hits SSL_R_UNEXPECTED_EOF_WHILE_READING, OpenSSL's internal SSLfatal() moves the state machine to an error state where SSL_in_init() returns 1. In that state, SSL_shutdown() ignores the quiet_shutdown flag and returns -1, pushing SSL_R_SHUTDOWN_WHILE_IN_INIT onto the error queue.
MDEV-30452 fix:
default: /* Shutdown failed */ |
#ifdef SSL_R_UNEXPECTED_EOF_WHILE_READING
|
{
|
unsigned long err= ERR_peek_last_error(); |
int ssl_error= SSL_get_error(ssl, r); |
if (ssl_error == SSL_ERROR_SSL && |
(ERR_GET_REASON(err) == SSL_R_UNEXPECTED_EOF_WHILE_READING ||
|
ERR_GET_REASON(err) == SSL_R_SHUTDOWN_WHILE_IN_INIT))
|
{
|
ERR_clear_error();
|
break; |
}
|
DBUG_PRINT("vio_error", ("SSL_shutdown() failed, error: %d", |
ssl_error));
|
}
|
#else
|
DBUG_PRINT("vio_error", ("SSL_shutdown() failed, error: %d", |
SSL_get_error(ssl, r)));
|
#endif
|
break; |
2. ssl_set_sys_error() — wrong errno for unexpected EOF
Current signature on all active branches:
static void ssl_set_sys_error(int ssl_error) |
The SSL_ERROR_SSL case unconditionally sets errno = EPROTO. On OpenSSL 3.x, an unexpected EOF (peer disconnect without close_notify) triggers SSL_ERROR_SSL — but this is not a protocol error, it is the equivalent of what OpenSSL 1.1.1 reported as SSL_ERROR_SYSCALL with errno=0.
MDEV-30452 adds an unsigned long err parameter and checks the reason code before setting errno:
static void ssl_set_sys_error(int ssl_error, unsigned long err) |
{
|
...
|
case SSL_ERROR_SSL: |
#ifdef SSL_R_UNEXPECTED_EOF_WHILE_READING
|
if (ERR_GET_REASON(err) == SSL_R_UNEXPECTED_EOF_WHILE_READING) |
{
|
errno= 0; |
break; |
}
|
#endif
|
/* Protocol error. */ |
error= EPROTO;
|
break; |
3. ssl_should_retry() — ERR_peek_error() scoping
Current code on all active branches:
static my_bool ssl_should_retry(Vio *vio, int ret, ...) |
{
|
...
|
#if defined(ERR_LIB_X509) && defined(X509_R_CERT_ALREADY_IN_HASH_TABLE)
|
unsigned long err = ERR_peek_error(); // inside #if block |
...
|
#endif
|
ssl_error= SSL_get_error(ssl, ret);
|
...
|
default: |
ssl_set_sys_error(ssl_error); // cannot pass err |
The variable err is scoped inside the #if block and cannot be passed to ssl_set_sys_error(). MDEV-30452 moves the ERR_peek_error() call before the #if block so the error reason code is captured before SSL_get_error() can modify the queue:
static my_bool ssl_should_retry(Vio *vio, int ret, ...) |
{
|
...
|
unsigned long err = ERR_peek_error(); // unconditional, before #if |
|
|
#if defined(ERR_LIB_X509) && defined(X509_R_CERT_ALREADY_IN_HASH_TABLE)
|
...
|
#endif
|
ssl_error= SSL_get_error(ssl, ret);
|
...
|
default: |
ssl_set_sys_error(ssl_error, err); // err now available |
How the fix was lost:
- 2023-01-23 —
MDEV-30452filed: Galera test galera_var_reject_queries fails on OpenSSL 3.x due to SSL_R_UNEXPECTED_EOF_WHILE_READING. - 2023-01-31 — Julius Goryavsky commits the VIO code fix (commit 11ae4ed4bf1) to branch bb-10.10-release-ssl. This branch was a work branch that was never merged back into 10.10.
- 2023-02-01 — A separate commit (e3e72644cfc) with only test-file adjustments (error code expectations in 8 .test/.result files) is committed to the 10.10 mainline. This commit contains zero changes to vio/viossl.c.
- 2023-02-06 —
MDEV-30452closed as "Fixed in 10.10.3". - 2023-02 — MariaDB 10.10.3 released. Contains the test changes from e3e72644cfc. Does not contain the VIO fix from 11ae4ed4bf1.
- 2023-05 — MariaDB 10.10 reaches EOL.
- 2023 onward — The 10.10->10.11 merge carries e3e72644cfc (test changes) forward. git merge-base --is-ancestor e3e72644cfc mariadb-10.11.19 returns true, which makes it appear as if
MDEV-30452was merged — but only the tests were; the code fix was not. - Present — Branch bb-10.10-release-ssl (last commit 2023-01-31) remains on GitHub. Zero active branches contain the VIO fix.
Verification:
To confirm the fix is missing from any branch, check for SSL_R_UNEXPECTED_EOF_WHILE_READING in vio/viossl.c:
$ git show mariadb-10.11.19:vio/viossl.c | grep -c SSL_R_UNEXPECTED_EOF_WHILE_READING
|
0
|
$ git show mariadb-11.4.13:vio/viossl.c | grep -c SSL_R_UNEXPECTED_EOF_WHILE_READING
|
0
|
$ git show mariadb-12.3.3:vio/viossl.c | grep -c SSL_R_UNEXPECTED_EOF_WHILE_READING
|
0
|
$ git show origin/bb-10.10-release-ssl:vio/viossl.c | grep -c SSL_R_UNEXPECTED_EOF_WHILE_READING
|
4
|
Confirm that the code-fix commit was never merged:
$ git merge-base --is-ancestor 11ae4ed4bf1 mariadb-10.11.19 && echo yes || echo no
|
no
|
$ git merge-base --is-ancestor 11ae4ed4bf1 mariadb-12.3.3 && echo yes || echo no
|
no
|
Confirm that the test-only commit WAS merged (this is why the JIRA ticket looks "fixed"):
$ git merge-base --is-ancestor e3e72644cfc mariadb-10.11.19 && echo yes || echo no
|
yes
|
Proposed action:
Forward-port the vio/viossl.c changes from commit 11ae4ed4bf1 (branch bb-10.10-release-ssl) into all active release branches: 10.11, 11.4, 11.8, 12.3.
The surrounding code in vio/viossl.c has not changed between 10.10 and 12.3 in the relevant functions. The viosslfactories.c changes in the same commit are cleanup unrelated to the SSL error handling and can be evaluated separately.
References:
MDEV-30452(original ticket, closed as "Fixed in 10.10.3"): https://jira.mariadb.org/browse/MDEV-30452- Commit with the VIO code fix (only on orphaned branch): https://github.com/MariaDB/server/commit/11ae4ed4bf1
- Orphaned branch containing the fix: https://github.com/MariaDB/server/tree/bb-10.10-release-ssl
- Commit with test-only changes (merged into all branches): https://github.com/MariaDB/server/commit/e3e72644cfc
- CONC-818 (client-side counterpart, still Open): https://jira.mariadb.org/browse/CONC-818
MDEV-33070(threadpool off-by-one, related but insufficient): https://jira.mariadb.org/browse/MDEV-33070- OpenSSL commit introducing SSL_R_UNEXPECTED_EOF_WHILE_READING in 3.0: https://github.com/openssl/openssl/commit/09b90e0
This bug analysis and report was assisted by AI.
The original customer report against RHEL 9: https://redhat.atlassian.net/browse/RHEL-155151