From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ffbox0-bg.ffmpeg.org (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTPS id 834E44E0D8 for ; Sun, 6 Jul 2025 18:38:25 +0000 (UTC) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.ffmpeg.org (Postfix) with ESMTP id BEB0C691206; Sun, 6 Jul 2025 21:37:06 +0300 (EEST) Received: from btbn.de (btbn.de [144.76.60.213]) by ffbox0-bg.ffmpeg.org (Postfix) with ESMTPS id F2BC86911E7 for ; Sun, 6 Jul 2025 21:36:53 +0300 (EEST) Received: from [authenticated] by btbn.de (Postfix) with ESMTPSA id 4D53527FFCBDB; Sun, 06 Jul 2025 20:36:48 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rothenpieler.org; s=mail; t=1751827008; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Eco/Ij4mJ3MbcsoNz/NqafKwojJ3V7/7XXyppVnKbNQ=; b=rhEf3YQE7sWoIQmyKY0LzhwpintMs8fUXd/qczHy7sk3dcXmqQup8ppDcqHEvnn/thUpbY CqQqXq4CltX1fMiLifvP4MQmnCA5AkSM6XpWXNduwITFqfIxl3G7ycjxv8Y3juB7jT81qb vsEFBi5KDWE4qYFFbKWkrbDJJQE0ZpWQT4fNp2lL05ojeFvEbC9lOycEDv0ZJR6XNE6pqp 2mg+PbX4m0OxcinKmff4ONRkFK/DxzITHeIu3PZeKl9ViE/SsQfaXNB/j2haRzHkHU5UZM BUvDLz1dFztOyotViZxD80+uSnxNm7ocW3L//ZC7DYC8Ii0A6OStSgPCGxy6kg== From: Timo Rothenpieler To: ffmpeg-devel@ffmpeg.org Date: Sun, 6 Jul 2025 20:36:29 +0200 Message-ID: <20250706183634.38579-9-timo@rothenpieler.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250706183634.38579-1-timo@rothenpieler.org> References: <20250706183634.38579-1-timo@rothenpieler.org> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v2 8/8] avformat/tls_schannel: fix non-blocking write breaking TLS sessions X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Timo Rothenpieler Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Archived-At: List-Archive: List-Post: --- libavformat/tls_schannel.c | 111 ++++++++++++++++++++++++++----------- 1 file changed, 79 insertions(+), 32 deletions(-) diff --git a/libavformat/tls_schannel.c b/libavformat/tls_schannel.c index 90d5765a80..031d12fa27 100644 --- a/libavformat/tls_schannel.c +++ b/libavformat/tls_schannel.c @@ -608,6 +608,10 @@ typedef struct TLSContext { int dec_buf_size; int dec_buf_offset; + char *send_buf; + int send_buf_size; + int send_buf_offset; + SecPkgContext_StreamSizes sizes; int connected; @@ -692,6 +696,35 @@ static void init_sec_buffer_desc(SecBufferDesc *desc, SecBuffer *buffers, desc->cBuffers = buffer_count; } +static int tls_process_send_buffer(URLContext *h) +{ + TLSContext *c = h->priv_data; + TLSShared *s = &c->tls_shared; + URLContext *uc = s->is_dtls ? s->udp : s->tcp; + int ret; + + if (!c->send_buf) + return 0; + + ret = ffurl_write(uc, c->send_buf + c->send_buf_offset, c->send_buf_size - c->send_buf_offset); + if (ret == AVERROR(EAGAIN)) { + return AVERROR(EAGAIN); + } else if (ret < 0) { + av_log(h, AV_LOG_ERROR, "Writing encrypted data to socket failed\n"); + return AVERROR(EIO); + } + + c->send_buf_offset += ret; + + if (c->send_buf_offset < c->send_buf_size) + return AVERROR(EAGAIN); + + av_freep(&c->send_buf); + c->send_buf_size = c->send_buf_offset = 0; + + return 0; +} + static int tls_shutdown_client(URLContext *h) { TLSContext *c = h->priv_data; @@ -710,6 +743,11 @@ static int tls_shutdown_client(URLContext *h) init_sec_buffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut)); init_sec_buffer_desc(&BuffDesc, &Buffer, 1); + uc->flags &= ~AVIO_FLAG_NONBLOCK; + ret = tls_process_send_buffer(h); + if (ret < 0) + return ret; + sspi_ret = ApplyControlToken(&c->ctxt_handle, &BuffDesc); if (sspi_ret != SEC_E_OK) av_log(h, AV_LOG_ERROR, "ApplyControlToken failed\n"); @@ -729,7 +767,6 @@ static int tls_shutdown_client(URLContext *h) if (outbuf.pvBuffer) { if (outbuf.cbBuffer > 0) { - uc->flags &= ~AVIO_FLAG_NONBLOCK; ret = ffurl_write(uc, outbuf.pvBuffer, outbuf.cbBuffer); if (ret < 0 || ret != outbuf.cbBuffer) av_log(h, AV_LOG_ERROR, "Failed to send close message\n"); @@ -761,6 +798,9 @@ static int tls_close(URLContext *h) av_freep(&c->dec_buf); c->dec_buf_size = c->dec_buf_offset = 0; + av_freep(&c->send_buf); + c->send_buf_size = c->send_buf_offset = 0; + if (s->is_dtls) { if (!s->external_sock) ffurl_closep(&c->tls_shared.udp); @@ -1263,6 +1303,11 @@ static int tls_read(URLContext *h, uint8_t *buf, int len) goto cleanup; } sspi_ret = SEC_E_OK; + + /* if somehow any send data was left, it is now invalid */ + av_freep(&c->send_buf); + c->send_buf_size = c->send_buf_offset = 0; + continue; } else if (sspi_ret == SEC_I_CONTEXT_EXPIRED) { c->sspi_close_notify = 1; @@ -1307,10 +1352,16 @@ static int tls_write(URLContext *h, const uint8_t *buf, int len) TLSShared *s = &c->tls_shared; URLContext *uc = s->is_dtls ? s->udp : s->tcp; SECURITY_STATUS sspi_ret; - int ret = 0, data_size; - uint8_t *data = NULL; SecBuffer outbuf[4]; SecBufferDesc outbuf_desc; + int ret = 0; + + uc->flags &= ~AVIO_FLAG_NONBLOCK; + uc->flags |= h->flags & AVIO_FLAG_NONBLOCK; + + ret = tls_process_send_buffer(h); + if (ret < 0) + return ret; if (c->sizes.cbMaximumMessage == 0) { sspi_ret = QueryContextAttributes(&c->ctxt_handle, SECPKG_ATTR_STREAM_SIZES, &c->sizes); @@ -1321,50 +1372,46 @@ static int tls_write(URLContext *h, const uint8_t *buf, int len) /* limit how much data we can consume */ len = FFMIN(len, c->sizes.cbMaximumMessage - c->sizes.cbHeader - c->sizes.cbTrailer); - data_size = c->sizes.cbHeader + len + c->sizes.cbTrailer; - data = av_malloc(data_size); - if (data == NULL) + c->send_buf_size = c->sizes.cbHeader + len + c->sizes.cbTrailer; + c->send_buf = av_malloc(c->send_buf_size); + if (c->send_buf == NULL) return AVERROR(ENOMEM); init_sec_buffer(&outbuf[0], SECBUFFER_STREAM_HEADER, - data, c->sizes.cbHeader); + c->send_buf, c->sizes.cbHeader); init_sec_buffer(&outbuf[1], SECBUFFER_DATA, - data + c->sizes.cbHeader, len); + c->send_buf + c->sizes.cbHeader, len); init_sec_buffer(&outbuf[2], SECBUFFER_STREAM_TRAILER, - data + c->sizes.cbHeader + len, - c->sizes.cbTrailer); + c->send_buf + c->sizes.cbHeader + len, + c->sizes.cbTrailer); init_sec_buffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0); init_sec_buffer_desc(&outbuf_desc, outbuf, 4); memcpy(outbuf[1].pvBuffer, buf, len); sspi_ret = EncryptMessage(&c->ctxt_handle, 0, &outbuf_desc, 0); - if (sspi_ret == SEC_E_OK) { - len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer; - - uc->flags &= ~AVIO_FLAG_NONBLOCK; - uc->flags |= h->flags & AVIO_FLAG_NONBLOCK; - - ret = ffurl_write(uc, data, len); - if (ret == AVERROR(EAGAIN)) { - goto done; - } else if (ret < 0 || ret != len) { - ret = AVERROR(EIO); - av_log(h, AV_LOG_ERROR, "Writing encrypted data to socket failed\n"); - goto done; - } - } else { + if (sspi_ret != SEC_E_OK) { + av_freep(&c->send_buf); av_log(h, AV_LOG_ERROR, "Encrypting data failed\n"); if (sspi_ret == SEC_E_INSUFFICIENT_MEMORY) - ret = AVERROR(ENOMEM); - else - ret = AVERROR(EIO); - goto done; + return AVERROR(ENOMEM); + return AVERROR(EIO); + } + + c->send_buf_size = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer; + c->send_buf_offset = 0; + + ret = tls_process_send_buffer(h); + if (ret == AVERROR(EAGAIN)) { + /* We always need to signal that we consumed all (encryped) data since schannel must not + be fed the same data again. Sending will then be completed next call to this function, + and EAGAIN returned until all remaining buffer is sent. */ + return outbuf[1].cbBuffer; + } else if (ret < 0) { + return ret; } -done: - av_freep(&data); - return ret < 0 ? ret : outbuf[1].cbBuffer; + return outbuf[1].cbBuffer; } static int tls_get_file_handle(URLContext *h) -- 2.49.0 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".