From 017da6f063861a1dc3eea5a41c3de8b879d579bd Mon Sep 17 00:00:00 2001
From: Don Brady <don.brady@intel.com>
Date: Wed, 24 Jun 2015 12:17:36 -0600
Subject: [PATCH] Fix for recent zdb -h | -i crashes (seg fault)

Allocating SPA_MAXBLOCKSIZE on the stack is a bad idea (even with the
old 128K size). Use malloc instead when allocating temporary block
buffer memory.

Signed-off-by: Don Brady <don.brady@intel.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #3522
---
 cmd/zdb/zdb.c    | 12 ++++++++++--
 cmd/zdb/zdb_il.c | 15 ++++++++++-----
 2 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/cmd/zdb/zdb.c b/cmd/zdb/zdb.c
index 800d49867d..56f56700fc 100644
--- a/cmd/zdb/zdb.c
+++ b/cmd/zdb/zdb.c
@@ -1070,7 +1070,7 @@ static void
 dump_history(spa_t *spa)
 {
 	nvlist_t **events = NULL;
-	char buf[SPA_MAXBLOCKSIZE];
+	char *buf;
 	uint64_t resid, len, off = 0;
 	uint_t num = 0;
 	int error;
@@ -1080,12 +1080,19 @@ dump_history(spa_t *spa)
 	char internalstr[MAXPATHLEN];
 	int i;
 
+	if ((buf = malloc(SPA_OLD_MAXBLOCKSIZE)) == NULL) {
+		(void) fprintf(stderr, "%s: unable to allocate I/O buffer\n",
+		    __func__);
+		return;
+	}
+
 	do {
-		len = sizeof (buf);
+		len = SPA_OLD_MAXBLOCKSIZE;
 
 		if ((error = spa_history_get(spa, &off, &len, buf)) != 0) {
 			(void) fprintf(stderr, "Unable to read history: "
 			    "error %d\n", error);
+			free(buf);
 			return;
 		}
 
@@ -1136,6 +1143,7 @@ next:
 			dump_nvlist(events[i], 2);
 		}
 	}
+	free(buf);
 }
 
 /*ARGSUSED*/
diff --git a/cmd/zdb/zdb_il.c b/cmd/zdb/zdb_il.c
index b85ef7ddd9..93b905793d 100644
--- a/cmd/zdb/zdb_il.c
+++ b/cmd/zdb/zdb_il.c
@@ -124,7 +124,7 @@ zil_prt_rec_write(zilog_t *zilog, int txtype, lr_write_t *lr)
 	char *data, *dlimit;
 	blkptr_t *bp = &lr->lr_blkptr;
 	zbookmark_phys_t zb;
-	char buf[SPA_MAXBLOCKSIZE];
+	char *buf;
 	int verbose = MAX(dump_opt['d'], dump_opt['i']);
 	int error;
 
@@ -135,6 +135,9 @@ zil_prt_rec_write(zilog_t *zilog, int txtype, lr_write_t *lr)
 	if (txtype == TX_WRITE2 || verbose < 5)
 		return;
 
+	if ((buf = malloc(SPA_MAXBLOCKSIZE)) == NULL)
+		return;
+
 	if (lr->lr_common.lrc_reclen == sizeof (lr_write_t)) {
 		(void) printf("%shas blkptr, %s\n", prefix,
 		    !BP_IS_HOLE(bp) &&
@@ -145,13 +148,13 @@ zil_prt_rec_write(zilog_t *zilog, int txtype, lr_write_t *lr)
 		if (BP_IS_HOLE(bp)) {
 			(void) printf("\t\t\tLSIZE 0x%llx\n",
 			    (u_longlong_t)BP_GET_LSIZE(bp));
-			bzero(buf, sizeof (buf));
+			bzero(buf, SPA_MAXBLOCKSIZE);
 			(void) printf("%s<hole>\n", prefix);
-			return;
+			goto exit;
 		}
 		if (bp->blk_birth < zilog->zl_header->zh_claim_txg) {
 			(void) printf("%s<block already committed>\n", prefix);
-			return;
+			goto exit;
 		}
 
 		SET_BOOKMARK(&zb, dmu_objset_id(zilog->zl_os),
@@ -162,7 +165,7 @@ zil_prt_rec_write(zilog_t *zilog, int txtype, lr_write_t *lr)
 		    bp, buf, BP_GET_LSIZE(bp), NULL, NULL,
 		    ZIO_PRIORITY_SYNC_READ, ZIO_FLAG_CANFAIL, &zb));
 		if (error)
-			return;
+			goto exit;
 		data = buf;
 	} else {
 		data = (char *)(lr + 1);
@@ -180,6 +183,8 @@ zil_prt_rec_write(zilog_t *zilog, int txtype, lr_write_t *lr)
 		data++;
 	}
 	(void) printf("\n");
+exit:
+	free(buf);
 }
 
 /* ARGSUSED */