From 7c33eb1e7fd3248ad29c172b5b4c0658a7be3adc Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Thu, 28 Mar 2024 09:00:13 +0000 Subject: [PATCH] QUIC APL: Revise SSL_pending and SSL_has_pending handling for s_client compat Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24040) --- ssl/quic/quic_impl.c | 53 ++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/ssl/quic/quic_impl.c b/ssl/quic/quic_impl.c index c4c332b203..62ebcd29aa 100644 --- a/ssl/quic/quic_impl.c +++ b/ssl/quic/quic_impl.c @@ -25,7 +25,7 @@ static void aon_write_finish(QUIC_XSO *xso); static int create_channel(QUIC_CONNECTION *qc); static QUIC_XSO *create_xso_from_stream(QUIC_CONNECTION *qc, QUIC_STREAM *qs); static int qc_try_create_default_xso_for_write(QCTX *ctx); -static int qc_wait_for_default_xso_for_read(QCTX *ctx); +static int qc_wait_for_default_xso_for_read(QCTX *ctx, int peek); static void quic_lock(QUIC_CONNECTION *qc); static void quic_unlock(QUIC_CONNECTION *qc); static void quic_lock_for_io(QCTX *ctx); @@ -268,7 +268,7 @@ static int ossl_unused expect_quic_with_stream_lock(const SSL *s, int remote_ini if (!qc_try_create_default_xso_for_write(ctx)) goto err; } else { - if (!qc_wait_for_default_xso_for_read(ctx)) + if (!qc_wait_for_default_xso_for_read(ctx, /*peek=*/0)) goto err; } @@ -1851,7 +1851,7 @@ static int quic_wait_for_stream(void *arg) } QUIC_NEEDS_LOCK -static int qc_wait_for_default_xso_for_read(QCTX *ctx) +static int qc_wait_for_default_xso_for_read(QCTX *ctx, int peek) { /* Called on a QCSO and we don't currently have a default stream. */ uint64_t expect_id; @@ -1893,6 +1893,9 @@ static int qc_wait_for_default_xso_for_read(QCTX *ctx) } if (qs == NULL) { + if (peek) + return 0; + if (!qc_blocking_mode(qc)) /* Non-blocking mode, so just bail immediately. */ return QUIC_RAISE_NORMAL_ERROR(ctx, SSL_ERROR_WANT_READ); @@ -2524,10 +2527,19 @@ int ossl_quic_write_flags(SSL *s, const void *buf, size_t len, *written = 0; - if (!expect_quic_with_stream_lock(s, /*remote_init=*/0, /*io=*/1, &ctx)) - return 0; + if (len == 0) { + /* Do not autocreate default XSO for zero-length writes. */ + if (!expect_quic(s, &ctx)) + return 0; - partial_write = ((ctx.xso->ssl_mode & SSL_MODE_ENABLE_PARTIAL_WRITE) != 0); + quic_lock_for_io(&ctx); + } else { + if (!expect_quic_with_stream_lock(s, /*remote_init=*/0, /*io=*/1, &ctx)) + return 0; + } + + partial_write = ((ctx.xso != NULL) + ? ((ctx.xso->ssl_mode & SSL_MODE_ENABLE_PARTIAL_WRITE) != 0) : 0); if ((flags & ~SSL_WRITE_FLAG_CONCLUDE) != 0) { ret = QUIC_RAISE_NON_NORMAL_ERROR(&ctx, SSL_R_UNSUPPORTED_WRITE_FLAG, NULL); @@ -2549,7 +2561,7 @@ int ossl_quic_write_flags(SSL *s, const void *buf, size_t len, } /* Ensure correct stream state, stream send part not concluded, etc. */ - if (!quic_validate_for_write(ctx.xso, &err)) { + if (len > 0 && !quic_validate_for_write(ctx.xso, &err)) { ret = QUIC_RAISE_NON_NORMAL_ERROR(&ctx, err, NULL); goto out; } @@ -2753,7 +2765,7 @@ static int quic_read(SSL *s, void *buf, size_t len, size_t *bytes_read, int peek * Wait until we get a stream initiated by the peer (blocking mode) or * fail if we don't have one yet (non-blocking mode). */ - if (!qc_wait_for_default_xso_for_read(&ctx)) { + if (!qc_wait_for_default_xso_for_read(&ctx, /*peek=*/0)) { ret = 0; /* error already raised here */ goto out; } @@ -2840,8 +2852,6 @@ static size_t ossl_quic_pending_int(const SSL *s, int check_channel) { QCTX ctx; size_t avail = 0; - int fin = 0; - if (!expect_quic(s, &ctx)) return 0; @@ -2849,21 +2859,26 @@ static size_t ossl_quic_pending_int(const SSL *s, int check_channel) quic_lock(ctx.qc); if (ctx.xso == NULL) { - QUIC_RAISE_NON_NORMAL_ERROR(&ctx, SSL_R_NO_STREAM, NULL); - goto out; + /* No XSO yet, but there might be a default XSO eligible to be created. */ + if (qc_wait_for_default_xso_for_read(&ctx, /*peek=*/1)) { + ctx.xso = ctx.qc->default_xso; + } else { + QUIC_RAISE_NON_NORMAL_ERROR(&ctx, SSL_R_NO_STREAM, NULL); + goto out; + } } - if (ctx.xso->stream == NULL - || !ossl_quic_stream_has_recv_buffer(ctx.xso->stream)) { + if (ctx.xso->stream == NULL) { QUIC_RAISE_NON_NORMAL_ERROR(&ctx, ERR_R_INTERNAL_ERROR, NULL); goto out; } - if (!ossl_quic_rstream_available(ctx.xso->stream->rstream, &avail, &fin)) - avail = 0; - - if (avail == 0 && check_channel && ossl_quic_channel_has_pending(ctx.qc->ch)) - avail = 1; + if (check_channel) + avail = ossl_quic_stream_recv_pending(ctx.xso->stream) + || ossl_quic_channel_has_pending(ctx.qc->ch) + || ossl_quic_channel_is_term_any(ctx.qc->ch); + else + avail = ossl_quic_stream_recv_pending(ctx.xso->stream); out: quic_unlock(ctx.qc);