e2fsck: Fix an unhandled corruption case in scan_extent_node()

A corrupted interior node in an extent tree would cause e2fsck to
crash with the error message:

Error1: Corrupt extent header on inode 107192
Aborted (core dumped)

Handle this and related failures when scanning an inode's extent tree
more robustly.

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
bitmap-optimize
Theodore Ts'o 2008-12-25 22:42:38 -05:00
parent 7dca4c88f1
commit 7518c17686
4 changed files with 39 additions and 21 deletions

View File

@ -1655,6 +1655,7 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
problem = PR_1_EXTENT_ENDS_BEYOND;
if (problem) {
report_problem:
pctx->blk = extent.e_pblk;
pctx->blk2 = extent.e_lblk;
pctx->num = extent.e_len;
@ -1662,11 +1663,7 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
pctx->errcode =
ext2fs_extent_delete(ehandle, 0);
if (pctx->errcode) {
fix_problem(ctx,
PR_1_EXTENT_DELETE_FAIL,
pctx);
/* Should never get here */
ctx->flags |= E2F_FLAG_ABORT;
pctx->str = "ext2fs_extent_delete";
return;
}
pctx->errcode = ext2fs_extent_get(ehandle,
@ -1682,23 +1679,27 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
}
if (!is_leaf) {
mark_block_used(ctx, extent.e_pblk);
pb->num_blocks++;
blk = extent.e_pblk;
pctx->errcode = ext2fs_extent_get(ehandle,
EXT2_EXTENT_DOWN, &extent);
if (pctx->errcode) {
printf("Error1: %s on inode %u\n",
error_message(pctx->errcode), pctx->ino);
abort();
pctx->str = "EXT2_EXTENT_DOWN";
problem = PR_1_EXTENT_HEADER_INVALID;
if (pctx->errcode == EXT2_ET_EXTENT_HEADER_BAD)
goto report_problem;
return;
}
scan_extent_node(ctx, pctx, pb, extent.e_lblk, ehandle);
if (pctx->errcode)
return;
pctx->errcode = ext2fs_extent_get(ehandle,
EXT2_EXTENT_UP, &extent);
if (pctx->errcode) {
printf("Error1: %s on inode %u\n",
error_message(pctx->errcode), pctx->ino);
abort();
pctx->str = "EXT2_EXTENT_UP";
return;
}
mark_block_used(ctx, blk);
pb->num_blocks++;
goto next;
}
@ -1780,7 +1781,14 @@ static void check_blocks_extents(e2fsck_t ctx, struct problem_context *pctx,
}
scan_extent_node(ctx, pctx, pb, 0, ehandle);
if (pctx->errcode &&
fix_problem(ctx, PR_1_EXTENT_ITERATE_FAILURE, pctx)) {
pb->num_blocks = 0;
inode->i_blocks = 0;
e2fsck_clear_inode(ctx, ino, inode, E2F_FLAG_RESTART,
"check_blocks_extents");
pctx->errcode = 0;
}
ext2fs_extent_free(ehandle);
}

View File

@ -823,10 +823,11 @@ static struct e2fsck_problem problem_table[] = {
N_("Error while reading over @x tree in @i %i: %m\n"),
PROMPT_CLEAR_INODE, 0 },
/* Error deleting a bogus extent */
{ PR_1_EXTENT_DELETE_FAIL,
N_("Error while deleting extent: %m\n"),
PROMPT_ABORT, 0 },
/* Failure to iterate extents */
{ PR_1_EXTENT_ITERATE_FAILURE,
N_("Failed to iterate extents in @i %i\n"
"\t(op %s, blk %b, lblk %c): %m\n"),
PROMPT_CLEAR_INODE, 0 },
/* Bad starting block in extent */
{ PR_1_EXTENT_BAD_START_BLK,
@ -863,6 +864,10 @@ static struct e2fsck_problem problem_table[] = {
N_("@i %i has out of order extents\n\t(@n logical @b %c, physical @b %b, len %N)\n"),
PROMPT_CLEAR, 0 },
{ PR_1_EXTENT_HEADER_INVALID,
N_("@i %i has an invalid extent node (blk %b, lblk %c)\n"),
PROMPT_CLEAR, 0 },
/* Pass 1b errors */
/* Pass 1B: Rescan for duplicate/bad blocks */

View File

@ -479,8 +479,8 @@ struct problem_context {
/* Error while reading extent tree */
#define PR_1_READ_EXTENT 0x010056
/* Error deleting a bogus extent */
#define PR_1_EXTENT_DELETE_FAIL 0x010057
/* Failure to iterate extents */
#define PR_1_EXTENT_ITERATE_FAILURE 0x010057
/* Bad starting block in extent */
#define PR_1_EXTENT_BAD_START_BLK 0x010058
@ -503,6 +503,9 @@ struct problem_context {
/* Extents are out of order */
#define PR_1_OUT_OF_ORDER_EXTENTS 0x01005E
/* Extent node header invalid */
#define PR_1_EXTENT_HEADER_INVALID 0x01005F
/*
* Pass 1b errors
*/

View File

@ -441,8 +441,10 @@ retry:
eh = (struct ext3_extent_header *) newpath->buf;
retval = ext2fs_extent_header_verify(eh, handle->fs->blocksize);
if (retval)
if (retval) {
handle->level--;
return retval;
}
newpath->left = newpath->entries =
ext2fs_le16_to_cpu(eh->eh_entries);