Blame SOURCES/gnutls-3.6.14-fix-iovec-memory-leak.patch

90a1d9
From 6fbff7fc8aabeee2254405f254220bbe8c05c67d Mon Sep 17 00:00:00 2001
90a1d9
From: Daiki Ueno <ueno@gnu.org>
90a1d9
Date: Fri, 5 Jun 2020 16:26:33 +0200
90a1d9
Subject: [PATCH] crypto-api: always allocate memory when serializing iovec_t
90a1d9
90a1d9
The AEAD iov interface falls back to serializing the input buffers if
90a1d9
the low-level cipher doesn't support scatter/gather encryption.
90a1d9
However, there was a bug in the functions used for the serialization,
90a1d9
which causes memory leaks under a certain condition (i.e. the number
90a1d9
of input buffers is 1).
90a1d9
90a1d9
This patch makes the logic of the functions simpler, by removing a
90a1d9
micro-optimization that tries to minimize the number of calls to
90a1d9
malloc/free.
90a1d9
90a1d9
The original problem was reported by Marius Steffen in:
90a1d9
https://bugzilla.samba.org/show_bug.cgi?id=14399
90a1d9
and the cause was investigated by Alexander Haase in:
90a1d9
https://gitlab.com/gnutls/gnutls/-/merge_requests/1277
90a1d9
90a1d9
Signed-off-by: Daiki Ueno <ueno@gnu.org>
90a1d9
---
90a1d9
 lib/crypto-api.c        | 36 +++++++++++-------------------------
90a1d9
 tests/aead-cipher-vec.c | 33 ++++++++++++++++++---------------
90a1d9
 2 files changed, 29 insertions(+), 40 deletions(-)
90a1d9
90a1d9
diff --git a/lib/crypto-api.c b/lib/crypto-api.c
90a1d9
index 45be64ed1..8524f5ed4 100644
90a1d9
--- a/lib/crypto-api.c
90a1d9
+++ b/lib/crypto-api.c
90a1d9
@@ -891,32 +891,23 @@ gnutls_aead_cipher_encrypt(gnutls_aead_cipher_hd_t handle,
90a1d9
 struct iov_store_st {
90a1d9
 	void *data;
90a1d9
 	size_t size;
90a1d9
-	unsigned allocated;
90a1d9
 };
90a1d9
 
90a1d9
 static void iov_store_free(struct iov_store_st *s)
90a1d9
 {
90a1d9
-	if (s->allocated) {
90a1d9
-		gnutls_free(s->data);
90a1d9
-		s->allocated = 0;
90a1d9
-	}
90a1d9
+	gnutls_free(s->data);
90a1d9
 }
90a1d9
 
90a1d9
 static int iov_store_grow(struct iov_store_st *s, size_t length)
90a1d9
 {
90a1d9
-	if (s->allocated || s->data == NULL) {
90a1d9
-		s->size += length;
90a1d9
-		s->data = gnutls_realloc(s->data, s->size);
90a1d9
-		if (s->data == NULL)
90a1d9
-			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
90a1d9
-		s->allocated = 1;
90a1d9
-	} else {
90a1d9
-		void *data = s->data;
90a1d9
-		size_t size = s->size + length;
90a1d9
-		s->data = gnutls_malloc(size);
90a1d9
-		memcpy(s->data, data, s->size);
90a1d9
-		s->size += length;
90a1d9
-	}
90a1d9
+	void *data;
90a1d9
+
90a1d9
+	s->size += length;
90a1d9
+	data = gnutls_realloc(s->data, s->size);
90a1d9
+	if (data == NULL)
90a1d9
+		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
90a1d9
+
90a1d9
+	s->data = data;
90a1d9
 	return 0;
90a1d9
 }
90a1d9
 
90a1d9
@@ -926,11 +917,6 @@ copy_from_iov(struct iov_store_st *dst, const giovec_t *iov, int iovcnt)
90a1d9
 	memset(dst, 0, sizeof(*dst));
90a1d9
 	if (iovcnt == 0) {
90a1d9
 		return 0;
90a1d9
-	} else if (iovcnt == 1) {
90a1d9
-		dst->data = iov[0].iov_base;
90a1d9
-		dst->size = iov[0].iov_len;
90a1d9
-		/* implies: dst->allocated = 0; */
90a1d9
-		return 0;
90a1d9
 	} else {
90a1d9
 		int i;
90a1d9
 		uint8_t *p;
90a1d9
@@ -944,11 +930,11 @@ copy_from_iov(struct iov_store_st *dst, const giovec_t *iov, int iovcnt)
90a1d9
 
90a1d9
 		p = dst->data;
90a1d9
 		for (i=0;i
90a1d9
-			memcpy(p, iov[i].iov_base, iov[i].iov_len);
90a1d9
+			if (iov[i].iov_len > 0)
90a1d9
+				memcpy(p, iov[i].iov_base, iov[i].iov_len);
90a1d9
 			p += iov[i].iov_len;
90a1d9
 		}
90a1d9
 
90a1d9
-		dst->allocated = 1;
90a1d9
 		return 0;
90a1d9
 	}
90a1d9
 }
90a1d9
diff --git a/tests/aead-cipher-vec.c b/tests/aead-cipher-vec.c
90a1d9
index fba9010d9..6a30a35f7 100644
90a1d9
--- a/tests/aead-cipher-vec.c
90a1d9
+++ b/tests/aead-cipher-vec.c
90a1d9
@@ -49,6 +49,7 @@ static void start(const char *name, int algo)
90a1d9
 	giovec_t auth_iov[2];
90a1d9
 	uint8_t tag[64];
90a1d9
 	size_t tag_size = 0;
90a1d9
+	size_t i;
90a1d9
 
90a1d9
 	key.data = key16;
90a1d9
 	key.size = gnutls_cipher_get_key_size(algo);
90a1d9
@@ -82,21 +83,23 @@ static void start(const char *name, int algo)
90a1d9
 	if (ret < 0)
90a1d9
 		fail("gnutls_cipher_init: %s\n", gnutls_strerror(ret));
90a1d9
 
90a1d9
-	ret = gnutls_aead_cipher_encryptv2(ch,
90a1d9
-					   iv.data, iv.size,
90a1d9
-					   auth_iov, 2,
90a1d9
-					   iov, 3,
90a1d9
-					   tag, &tag_size);
90a1d9
-	if (ret < 0)
90a1d9
-		fail("could not encrypt data: %s\n", gnutls_strerror(ret));
90a1d9
-
90a1d9
-	ret = gnutls_aead_cipher_decryptv2(ch,
90a1d9
-					   iv.data, iv.size,
90a1d9
-					   auth_iov, 2,
90a1d9
-					   iov, 3,
90a1d9
-					   tag, tag_size);
90a1d9
-	if (ret < 0)
90a1d9
-		fail("could not decrypt data: %s\n", gnutls_strerror(ret));
90a1d9
+	for (i = 0; i < 2; i++) {
90a1d9
+		ret = gnutls_aead_cipher_encryptv2(ch,
90a1d9
+						   iv.data, iv.size,
90a1d9
+						   auth_iov, 2,
90a1d9
+						   iov, i + 1,
90a1d9
+						   tag, &tag_size);
90a1d9
+		if (ret < 0)
90a1d9
+			fail("could not encrypt data: %s\n", gnutls_strerror(ret));
90a1d9
+
90a1d9
+		ret = gnutls_aead_cipher_decryptv2(ch,
90a1d9
+						   iv.data, iv.size,
90a1d9
+						   auth_iov, 2,
90a1d9
+						   iov, i + 1,
90a1d9
+						   tag, tag_size);
90a1d9
+		if (ret < 0)
90a1d9
+			fail("could not decrypt data: %s\n", gnutls_strerror(ret));
90a1d9
+	}
90a1d9
 
90a1d9
 	gnutls_aead_cipher_deinit(ch);
90a1d9
 }
90a1d9
-- 
90a1d9
2.25.4
90a1d9