Commit d6ca7796bf for openssl.org
commit d6ca7796bf66f65d0c69cb0c0806ed38ce3f3105
Author: Matt Caswell <matt@openssl.foundation>
Date: Thu Jun 25 17:15:16 2026 +0100
SSL_poll: fix abort_blocking mishandling in poll_translate()/poll_block()
When SSL_poll() has to block, poll_translate() registers each item's QUIC
connection for cross-thread notification one item at a time. If an item
turns out to already be ready right as it is being registered, translation
sets abort_blocking and is meant to bail out so the caller retries the
readout instead of actually blocking.
Two bugs in that abort path:
- poll_translate() returned immediately on abort_blocking without calling
postpoll_translation_cleanup() for any earlier items that had already
had their blocking section entered. Those items' enter/leave calls were
left unbalanced, leaking into the QUIC reactor's blocking-waiter count.
Fixed by routing through the existing "out" cleanup label, mirroring
what the FAIL_ITEM()/error path already does for items 0..i-1.
- poll_block() initializes ok = 0 and only ever sets it on the actual
poll() success path. The abort_blocking branch jumped straight to "out"
without setting ok, so SSL_poll() reported failure even though nothing
actually went wrong; the caller's retry loop never got a chance to pick
up the now-ready item.
Assisted-by: Claude:claude-sonnet-4-6
Reviewed-by: Saša NedvÄ›dický <sashan@openssl.org>
Reviewed-by: Paul Yang <paulyang.inf@gmail.com>
MergeDate: Wed Jul 29 07:20:31 2026
(Merged from https://github.com/openssl/openssl/pull/31743)
diff --git a/ssl/rio/poll_immediate.c b/ssl/rio/poll_immediate.c
index 24b82f3a6a..edb39b2a6c 100644
--- a/ssl/rio/poll_immediate.c
+++ b/ssl/rio/poll_immediate.c
@@ -233,7 +233,7 @@ static int poll_translate(SSL_POLL_ITEM *items,
FAIL_ITEM(i);
if (*abort_blocking)
- return 1;
+ goto out;
if (!SSL_get_event_timeout(ssl, &timeout, &is_infinite))
FAIL_ITEM(i++); /* need to clean up this item too */
@@ -271,7 +271,12 @@ static int poll_translate(SSL_POLL_ITEM *items,
}
out:
- if (!ok)
+ /*
+ * On abort_blocking, the item which triggered the abort has already
+ * balanced its own enter/leave of the blocking section (see
+ * poll_translate_ssl_quic()); only items 0..i-1 still need cleanup here.
+ */
+ if (!ok || *abort_blocking)
postpoll_translation_cleanup(items, i, stride, wctx);
*p_earliest_wakeup_deadline = earliest_wakeup_deadline;
@@ -320,8 +325,15 @@ static int poll_block(SSL_POLL_ITEM *items,
p_result_count))
goto out;
- if (abort_blocking)
+ if (abort_blocking) {
+ /*
+ * Nothing actually failed; we just shouldn't block because an item
+ * may have become ready while we were setting up. The caller's
+ * retry loop will call poll_readout() again to pick this up.
+ */
+ ok = 1;
goto out;
+ }
earliest_wakeup_deadline = ossl_time_min(earliest_wakeup_deadline,
user_deadline);