6787311 dnode_setup_crypto_data and zil_setup_crypto_data leak memory
authorDarren Moffat <Darren.Moffat@Sun.COM>
Tue, 23 Dec 2008 05:06:28 +0000
changeset 13439 ef6086798b5d
parent 13438 2a64a305dd7f
child 13440 a7041a76d586
6787311 dnode_setup_crypto_data and zil_setup_crypto_data leak memory
usr/src/uts/common/fs/zfs/zio_crypt.c
--- a/usr/src/uts/common/fs/zfs/zio_crypt.c	Tue Dec 23 02:33:29 2008 +0000
+++ b/usr/src/uts/common/fs/zfs/zio_crypt.c	Tue Dec 23 05:06:28 2008 +0000
@@ -1729,7 +1729,8 @@
  */
 static int
 dnode_setup_crypto_data(void *src, size_t size,
-    void *dest, iovec_t **srciovp, iovec_t **dstiovp, size_t *cdlen)
+    void *dest, iovec_t **srciovp, iovec_t **dstiovp, size_t *cdlen,
+    boolean_t encrypting)
 {
 	dnode_phys_t *sdnp = src;
 	dnode_phys_t *ddnp = dest;
@@ -1765,15 +1766,16 @@
 	}
 
 	/*
-	 * We have iovcnt bonusbufs that need encrypting so build the uio.
+	 * We have iovcnt bonusbufs that need encrypting so build the iov.
+	 * Plus one addtional iov for the MAC.
 	 */
-	srciov = kmem_alloc(sizeof (iovec_t) * iovcnt, KM_SLEEP);
-
-	/*
-	 * Add an extra iov entry at the end for the MAC.
-	 */
-	iovcnt++;
-	dstiov = kmem_alloc(sizeof (iovec_t) * iovcnt, KM_SLEEP);
+	if (encrypting) {
+		srciov = kmem_alloc(sizeof (iovec_t) * iovcnt, KM_SLEEP);
+		dstiov = kmem_alloc(sizeof (iovec_t) * (iovcnt + 1), KM_SLEEP);
+	} else {
+		srciov = kmem_alloc(sizeof (iovec_t) * (iovcnt + 1), KM_SLEEP);
+		dstiov = kmem_alloc(sizeof (iovec_t) * iovcnt, KM_SLEEP);
+	}
 
 	/* From the beginning again build up the iov */
 	sdnp = src;
@@ -1869,7 +1871,8 @@
  */
 int
 zil_setup_crypto_data(char *src, size_t size,
-    void *dest, iovec_t **srciovp, iovec_t **dstiovp, size_t *cdlen)
+    void *dest, iovec_t **srciovp, iovec_t **dstiovp, size_t *cdlen,
+    boolean_t encrypting)
 {
 	char *slrp, *dlrp;
 	zil_trailer_t *ztp;
@@ -1893,12 +1896,18 @@
 		return (0);
 	}
 
-	/* We have iovcnt log records that need encrypting. */
-	srciov = kmem_alloc(sizeof (iovec_t) * iovcnt, KM_SLEEP);
+	/* 
+	 * We have iovcnt log records that need encrypting.
+	 * Plus one more for the MAC
+	 */
 	iovcheck = iovcnt;
-
-	/* Add an extra iov in dest for the MAC */
-	dstiov = kmem_alloc(sizeof (iovec_t) * (iovcnt + 1), KM_SLEEP);
+	if (encrypting) {
+		srciov = kmem_alloc(sizeof (iovec_t) * iovcnt, KM_SLEEP);
+		dstiov = kmem_alloc(sizeof (iovec_t) * (iovcnt + 1), KM_SLEEP);
+	} else {
+		srciov = kmem_alloc(sizeof (iovec_t) * (iovcnt + 1), KM_SLEEP);
+		dstiov = kmem_alloc(sizeof (iovec_t) * iovcnt, KM_SLEEP);
+	}
 
 	iovcnt = 0;
 	for (slrp = src, dlrp = dest; slrp < src + ztp->zit_nused;
@@ -2013,10 +2022,10 @@
 		iovec_t *srciov, *dstiov;
 		if (type == DMU_OT_DNODE) {
 			iovcnt = dnode_setup_crypto_data(src, srcsize, dest,
-			    &srciov, &dstiov, &plaintext.cd_length);
+			    &srciov, &dstiov, &plaintext.cd_length, B_TRUE);
 		} else if (type == DMU_OT_INTENT_LOG) {
 			iovcnt = zil_setup_crypto_data(src, srcsize, dest,
-			    &srciov, &dstiov, &plaintext.cd_length);
+			    &srciov, &dstiov, &plaintext.cd_length, B_TRUE);
 		}
 		if (iovcnt == 0) {
 			zio_crypt_key_release(key, FTAG);
@@ -2129,6 +2138,10 @@
 		dnode_check_buf(dest, srcsize);
 	}
 #endif /* DEBUG */
+	if (type == DMU_OT_DNODE || type == DMU_OT_INTENT_LOG) {
+		kmem_free(srcuio.uio_iov, sizeof (iovec_t) * srcuio.uio_iovcnt);
+		kmem_free(dstuio.uio_iov, sizeof (iovec_t) * dstuio.uio_iovcnt);
+	}
 
 	return (ret);
 }
@@ -2184,20 +2197,19 @@
 		iovec_t *srciov, *dstiov;
 		if (type == DMU_OT_DNODE) {
 			iovcnt = dnode_setup_crypto_data(src, srcsize, dest,
-			    &srciov, &dstiov, &plaintext.cd_length);
-			if (iovcnt == 0) {
-				zio_crypt_key_release(key, FTAG);
-				return (0);
-			}
+			    &srciov, &dstiov, &plaintext.cd_length, B_FALSE);
 		} else if (type == DMU_OT_INTENT_LOG) {
 			iovcnt = zil_setup_crypto_data(src, srcsize, dest,
-			    &srciov, &dstiov, &plaintext.cd_length);
-			ASSERT(iovcnt != 0);
+			    &srciov, &dstiov, &plaintext.cd_length, B_FALSE);
+		}
+		if (iovcnt == 0) {
+			zio_crypt_key_release(key, FTAG);
+			return (0);
 		}
 		dstuio.uio_iovcnt = iovcnt;
 		dstuio.uio_iov = dstiov;
+
 		ciphertext.cd_length = plaintext.cd_length + maclen;
-
 		srcuio.uio_iov = srciov;
 		srcuio.uio_iovcnt = iovcnt + 1;
 		srcuio.uio_iov[iovcnt].iov_base = mac;
@@ -2278,6 +2290,10 @@
 		dnode_check_buf(dest, srcsize);
 	}
 #endif
+	if (type == DMU_OT_DNODE || type == DMU_OT_INTENT_LOG) {
+		kmem_free(srcuio.uio_iov, sizeof (iovec_t) * srcuio.uio_iovcnt);
+		kmem_free(dstuio.uio_iov, sizeof (iovec_t) * dstuio.uio_iovcnt);
+	}
 	return (ret);
 }