lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20140801181221.12496.71818.stgit@birch.djwong.org>
Date:	Fri, 01 Aug 2014 11:12:21 -0700
From:	"Darrick J. Wong" <darrick.wong@...cle.com>
To:	tytso@....edu, darrick.wong@...cle.com
Cc:	linux-ext4@...r.kernel.org
Subject: [PATCH 06/19] e2fsck: try to salvage extent blocks with bad
 checksums

From: Darrick J. Wong <darrick.wong@...cle.com>

Remove the code that would zap an extent block immediately if the
checksum failed (i.e. strict_csums).  Instead, we'll only do that if
the extent block header shows obvious structural problems; if the
header checks out, then we'll iterate the block and see if we can
recover some extents.

Requires a minor modification to ext2fs_extent_get such that the
extent block will be returned in the buffer even if the return code
indicates a checksum error.  This brings its behavior in line with
the rest of libext2fs.

Signed-off-by: Darrick J. Wong <darrick.wong@...cle.com>
---
 e2fsck/pass1.c      |   45 +++++++++++++++++++--------------------------
 e2fsck/problem.c    |    6 ------
 e2fsck/problem.h    |    3 ---
 lib/ext2fs/extent.c |   10 ++++++----
 4 files changed, 25 insertions(+), 39 deletions(-)

diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index 02683d3..283b0b1 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -2001,7 +2001,10 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
 	int			is_dir, is_leaf;
 	problem_t		problem;
 	struct ext2_extent_info	info;
-	int			failed_csum;
+	int			failed_csum = 0;
+
+	if (pctx->errcode == EXT2_ET_EXTENT_CSUM_INVALID)
+		failed_csum = 1;
 
 	pctx->errcode = ext2fs_extent_get_info(ehandle, &info);
 	if (pctx->errcode)
@@ -2012,7 +2015,6 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
 	while ((pctx->errcode == 0 ||
 		pctx->errcode == EXT2_ET_EXTENT_CSUM_INVALID) &&
 	       info.num_entries-- > 0) {
-		failed_csum = 0;
 		is_leaf = extent.e_flags & EXT2_EXTENT_FLAGS_LEAF;
 		is_dir = LINUX_S_ISDIR(pctx->inode->i_mode);
 		last_lblk = extent.e_lblk + extent.e_len - 1;
@@ -2023,15 +2025,6 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
 		pctx->num = extent.e_len;
 		pctx->blkcount = extent.e_lblk + extent.e_len;
 
-		/* Ask to clear a corrupt extent block */
-		if (try_repairs &&
-		    pctx->errcode == EXT2_ET_EXTENT_CSUM_INVALID) {
-			problem = PR_1_EXTENT_CSUM_INVALID;
-			if (fix_problem(ctx, problem, pctx))
-				goto fix_problem_now;
-			failed_csum = 1;
-		}
-
 		if (extent.e_pblk == 0 ||
 		    extent.e_pblk < ctx->fs->super->s_first_data_block ||
 		    extent.e_pblk >= ext2fs_blocks_count(ctx->fs->super))
@@ -2069,16 +2062,6 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
 			failed_csum = 0;
 		}
 
-		/* Failed csum but passes checks?  Ask to fix checksum. */
-		if (try_repairs && failed_csum && problem == 0 &&
-		    fix_problem(ctx, PR_1_EXTENT_ONLY_CSUM_INVALID, pctx)) {
-			pb->inode_modified = 1;
-			pctx->errcode = ext2fs_extent_replace(ehandle,
-							0, &extent);
-			if (pctx->errcode)
-				return;
-		}
-
 		if (try_repairs && problem) {
 report_problem:
 			if (fix_problem(ctx, problem, pctx)) {
@@ -2124,6 +2107,7 @@ fix_problem_now:
 					pctx->errcode = 0;
 					break;
 				}
+				failed_csum = 0;
 				continue;
 			}
 			goto next;
@@ -2152,15 +2136,13 @@ fix_problem_now:
 			}
 			pctx->errcode = ext2fs_extent_get(ehandle,
 						  EXT2_EXTENT_DOWN, &extent);
-			if (pctx->errcode) {
+			if (pctx->errcode &&
+			    pctx->errcode != EXT2_ET_EXTENT_CSUM_INVALID) {
 				pctx->str = "EXT2_EXTENT_DOWN";
 				problem = PR_1_EXTENT_HEADER_INVALID;
 				if (!next_try_repairs)
 					return;
-				if (pctx->errcode ==
-					EXT2_ET_EXTENT_HEADER_BAD ||
-				    pctx->errcode ==
-					EXT2_ET_EXTENT_CSUM_INVALID)
+				if (pctx->errcode == EXT2_ET_EXTENT_HEADER_BAD)
 					goto report_problem;
 				return;
 			}
@@ -2256,6 +2238,7 @@ fix_problem_now:
 				if (pctx->errcode)
 					goto failed_add_dir_block;
 				last_lblk = extent.e_lblk + extent.e_len - 1;
+				failed_csum = 0;
 			}
 		}
 alloc_later:
@@ -2323,6 +2306,16 @@ alloc_later:
 						  EXT2_EXTENT_NEXT_SIB,
 						  &extent);
 	}
+
+	/* Failed csum but passes checks?  Ask to fix checksum. */
+	if (failed_csum &&
+	    fix_problem(ctx, PR_1_EXTENT_ONLY_CSUM_INVALID, pctx)) {
+		pb->inode_modified = 1;
+		pctx->errcode = ext2fs_extent_replace(ehandle, 0, &extent);
+		if (pctx->errcode)
+			return;
+	}
+
 	if (pctx->errcode == EXT2_ET_EXTENT_NO_NEXT)
 		pctx->errcode = 0;
 }
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index dc094ed..1b6bdb0 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -977,12 +977,6 @@ static struct e2fsck_problem problem_table[] = {
 	  N_("@i %i passes checks, but checksum does not match @i.  "),
 	  PROMPT_FIX, PR_PREEN_OK },
 
-	/* Inode extent block checksum does not match extent */
-	{ PR_1_EXTENT_CSUM_INVALID,
-	  N_("@i %i extent block checksum does not match extent\n\t(logical @b "
-	     "%c, @n physical @b %b, len %N)\n"),
-	  PROMPT_CLEAR, 0 },
-
 	/*
 	 * Inode extent block passes checks, but checksum does not match
 	 * extent
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index af7a73e..89db5f3 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -577,9 +577,6 @@ struct problem_context {
 /* inode passes checks, but checksum does not match inode */
 #define PR_1_INODE_ONLY_CSUM_INVALID   0x010068
 
-/* extent block checksum does not match extent block */
-#define PR_1_EXTENT_CSUM_INVALID       0x010069
-
 /* extent block passes checks, but checksum does not match extent block */
 #define PR_1_EXTENT_ONLY_CSUM_INVALID  0x01006A
 
diff --git a/lib/ext2fs/extent.c b/lib/ext2fs/extent.c
index 30673b5..32bc214 100644
--- a/lib/ext2fs/extent.c
+++ b/lib/ext2fs/extent.c
@@ -283,6 +283,7 @@ errcode_t ext2fs_extent_get(ext2_extent_handle_t handle,
 	blk64_t				blk;
 	blk64_t				end_blk;
 	int				orig_op, op;
+	int				failed_csum = 0;
 
 	EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
 
@@ -457,10 +458,8 @@ retry:
 
 		if (!(handle->fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
 		    !ext2fs_extent_block_csum_verify(handle->fs, handle->ino,
-						     eh)) {
-			handle->level--;
-			return EXT2_ET_EXTENT_CSUM_INVALID;
-		}
+						     eh))
+			failed_csum = 1;
 
 		newpath->left = newpath->entries =
 			ext2fs_le16_to_cpu(eh->eh_entries);
@@ -540,6 +539,9 @@ retry:
 	     (path->left != 0)))
 		goto retry;
 
+	if (failed_csum)
+		return EXT2_ET_EXTENT_CSUM_INVALID;
+
 	return 0;
 }
 

--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ