From 70099c896f37553177d2448859df64cd17133529 Mon Sep 17 00:00:00 2001
From: Eric Sandeen <sandeen@sandeen.net>
Date: Thu, 30 Jul 2015 09:21:08 +1000
Subject: [PATCH 17/20] metadump: Zero unused portions of attribute blocks
References: bsc#939367 CVE-2012-2150

Attribute blocks may contain stale disk data either
between names (and/or values), and between the entries
array and the actual names/values.  Zero out both of
these regions.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
Acked-by: Jan Kara <jack@suse.com>

---
 db/metadump.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 50 insertions(+), 14 deletions(-)

diff --git a/db/metadump.c b/db/metadump.c
index c40c896e05f6..32a2f70369dd 100644
--- a/db/metadump.c
+++ b/db/metadump.c
@@ -1332,7 +1332,7 @@ add_remote_vals(
 
 /* Handle remote and leaf attributes */
 static void
-obfuscate_attr_block(
+process_attr_block(
 	char				*block,
 	xfs_fileoff_t			offset)
 {
@@ -1344,6 +1344,7 @@ obfuscate_attr_block(
 	xfs_attr_leaf_name_local_t 	*local;
 	xfs_attr_leaf_name_remote_t 	*remote;
 	__uint32_t			bs = mp->m_sb.sb_blocksize;
+	char				*first_name;
 
 
 	leaf = (xfs_attr_leafblock_t *)block;
@@ -1352,7 +1353,7 @@ obfuscate_attr_block(
 	if ((be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR_LEAF_MAGIC) &&
 	    (be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR3_LEAF_MAGIC)) {
 		for (i = 0; i < attr_data.remote_val_count; i++) {
-			if (attr_data.remote_vals[i] == offset)
+			if (obfuscate && attr_data.remote_vals[i] == offset)
 				/* Macros to handle both attr and attr3 */
 				memset(block +
 					(bs - XFS_ATTR3_RMT_BUF_SPACE(mp, bs)),
@@ -1375,7 +1376,15 @@ obfuscate_attr_block(
 	}
 
 	entry = xfs_attr3_leaf_entryp(leaf);
+	/* We will move this as we parse */
+	first_name = NULL;
 	for (i = 0; i < nentries; i++, entry++) {
+		int nlen, vlen, zlen;
+
+		/* Grows up; if this name is topmost, move first_name */
+		if (!first_name || xfs_attr3_leaf_name(leaf, i) < first_name)
+			first_name = xfs_attr3_leaf_name(leaf, i);
+
 		if (be16_to_cpu(entry->nameidx) > XFS_LBSIZE(mp)) {
 			if (show_warnings)
 				print_warning(
@@ -1392,10 +1401,20 @@ obfuscate_attr_block(
 						(long long)cur_ino);
 				break;
 			}
-			generate_obfuscated_name(0, local->namelen,
-				&local->nameval[0]);
-			memset(&local->nameval[local->namelen], 'v',
-				be16_to_cpu(local->valuelen));
+			if (obfuscate) {
+				generate_obfuscated_name(0, local->namelen,
+					&local->nameval[0]);
+				memset(&local->nameval[local->namelen], 'v',
+					be16_to_cpu(local->valuelen));
+			}
+			/* zero from end of nameval[] to next name start */
+			nlen = local->namelen;
+			vlen = be16_to_cpu(local->valuelen);
+			zlen = xfs_attr_leaf_entsize_local(nlen, vlen) -
+				(sizeof(xfs_attr_leaf_name_local_t) - 1 +
+				 nlen + vlen);
+			if (zero_stale_data)
+				memset(&local->nameval[nlen + vlen], 0, zlen);
 		} else {
 			remote = xfs_attr3_leaf_name_remote(leaf, i);
 			if (remote->namelen == 0 || remote->valueblk == 0) {
@@ -1405,14 +1424,33 @@ obfuscate_attr_block(
 						(long long)cur_ino);
 				break;
 			}
-			generate_obfuscated_name(0, remote->namelen,
-						 &remote->name[0]);
-			add_remote_vals(be32_to_cpu(remote->valueblk),
-					be32_to_cpu(remote->valuelen));
+			if (obfuscate) {
+				generate_obfuscated_name(0, remote->namelen,
+							 &remote->name[0]);
+				add_remote_vals(be32_to_cpu(remote->valueblk),
+						be32_to_cpu(remote->valuelen));
+			}
+			/* zero from end of name[] to next name start */
+			nlen = remote->namelen;
+			zlen = xfs_attr_leaf_entsize_remote(nlen) -
+				(sizeof(xfs_attr_leaf_name_remote_t) - 1 +
+				 nlen);
+			if (zero_stale_data)
+				memset(&remote->name[nlen], 0, zlen);
 		}
 	}
+
+	/* Zero from end of entries array to the first name/val */
+	if (zero_stale_data) {
+		struct xfs_attr_leaf_entry *entries;
+
+		entries = xfs_attr3_leaf_entryp(leaf);
+		memset(&entries[nentries], 0,
+		       first_name - (char *)&entries[nentries]);
+	}
 }
 
+/* Processes symlinks, attrs, directories ... */
 static int
 process_single_fsb_objects(
 	xfs_dfiloff_t	o,
@@ -1460,10 +1498,8 @@ process_single_fsb_objects(
 			iocur_top->need_crc = 1;
 			break;
 		case TYP_ATTR:
-			if (obfuscate) {
-				obfuscate_attr_block(dp, o);
-				iocur_top->need_crc = 1;
-			}
+			process_attr_block(dp, o);
+			iocur_top->need_crc = 1;
 			break;
 		default:
 			break;
-- 
2.1.4

