Blob Blame History Raw
From 21c386860f1973344872eec4e4dd68644b1b48aa Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Fri, 10 Mar 2023 11:15:19 +0000
Subject: [PATCH] ktls: Do not return GNUTLS_E_INTERRUPTED/AGAIN from short
 writes

If sendmsg returns a short write, we end up going around the loop with
data_to_send being smaller.  However if sendmsg then returns -EAGAIN
or -EINTR then we return an error.  But we have "forgotten" that we
already sent some data.

This causes the caller to retry gnutls_record_send with the full
buffer (ie. with a buffer that has already been partially sent),
causing desynchronization.

Instead check if we sent some data in this case and return the number
of bytes sent.

Fixes: https://gitlab.com/gnutls/gnutls/-/issues/1470
Thanks: Dan Berrange for suggesting a fix
Signed-off-by: Richard W.M. Jones <rjones@redhat.com>
---
 lib/system/ktls.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/lib/system/ktls.c b/lib/system/ktls.c
index fd57a9c30..bb59fab7c 100644
--- a/lib/system/ktls.c
+++ b/lib/system/ktls.c
@@ -604,9 +604,17 @@ int _gnutls_ktls_send_control_msg(gnutls_session_t session,
 		if (ret == -1) {
 			switch (errno) {
 			case EINTR:
-				return GNUTLS_E_INTERRUPTED;
+				if (data_to_send < data_size) {
+					return data_size - data_to_send;
+				} else {
+					return GNUTLS_E_INTERRUPTED;
+				}
 			case EAGAIN:
-				return GNUTLS_E_AGAIN;
+				if (data_to_send < data_size) {
+					return data_size - data_to_send;
+				} else {
+					return GNUTLS_E_AGAIN;
+				}
 			default:
 				return GNUTLS_E_PUSH_ERROR;
 			}
-- 
2.39.2