From 67052a8aeeca8cd80d1dd33c2792f917573accc8 Mon Sep 17 00:00:00 2001 From: Andreas Dilger Date: Sat, 4 Aug 2001 00:51:18 -0600 Subject: [PATCH] Add extra checks for bad symlinks, including zero length symlinks, too long i_size for slow and fast symlinks, i_size_high set, multiple blocks for slow symlinks. --- e2fsck/e2fsck.h | 1 + e2fsck/pass1.c | 49 ++++++++++++++++++++++++++++++++++++++++---- e2fsck/pass2.c | 5 +++-- e2fsck/problem.c | 2 +- lib/ext2fs/ext2_fs.h | 2 ++ tests/ChangeLog | 4 ++++ tests/README | 1 + 7 files changed, 57 insertions(+), 7 deletions(-) diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h index 2ce49ae1..fe2537ca 100644 --- a/e2fsck/e2fsck.h +++ b/e2fsck/e2fsck.h @@ -316,6 +316,7 @@ extern int e2fsck_run_ext3_journal(e2fsck_t ctx); /* pass1.c */ extern void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool); extern int e2fsck_pass1_check_device_inode(struct ext2_inode *inode); +extern int e2fsck_pass1_check_symlink(ext2_filsys fs, struct ext2_inode *inode); /* pass2.c */ extern int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir, ext2_ino_t ino); diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index 501f4485..a8188ff7 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -146,6 +146,44 @@ int e2fsck_pass1_check_device_inode(struct ext2_inode *inode) return 1; } +/* + * Check to make sure a symlink inode is real. Returns 1 if the symlink + * checks out, 0 if not. + */ +int e2fsck_pass1_check_symlink(ext2_filsys fs, struct ext2_inode *inode) +{ + if (inode->i_size_high || inode->i_size == 0) + return 0; + + if (inode->i_flags & (EXT2_IMMUTABLE_FL |EXT2_APPEND_FL |EXT2_INDEX_FL)) + return 0; + + if (inode->i_blocks) { + int i; + + if (inode->i_blocks > fs->blocksize >> 9) + return 0; + + for (i = 1; i < EXT2_N_BLOCKS; i++) + if (inode->i_block[i]) + return 0; + + if (inode->i_size > fs->blocksize) + return 0; + + /* Defer check of i_size until block number validated */ + } else { + if (inode->i_size > EXT2_LINK_DIR - 1) + return 0; + + if (inode->i_size != + strnlen((char *)inode->i_block, EXT2_LINK_DIR)) + return 0; + } + + return 1; +} + /* * If the immutable (or append-only) flag is set on the inode, offer * to clear it. @@ -561,10 +599,9 @@ void e2fsck_pass1(e2fsck_t ctx) } else if (LINUX_S_ISLNK (inode.i_mode)) { check_immutable(ctx, &pctx); ctx->fs_symlinks_count++; + if (!e2fsck_pass1_check_symlink(fs, &inode)) + mark_inode_bad(ctx, ino); if (!inode.i_blocks) { - if (inode.i_size_high || - (inode.i_size > EXT2_N_BLOCKS*4)) - mark_inode_bad(ctx, ino); ctx->fs_fast_symlinks_count++; goto next; } @@ -1216,12 +1253,16 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, } pctx->num = 0; } - if (!pb.is_dir && (inode->i_size_high || inode->i_size & 0x80000000UL)) + if (!pb.is_dir && + (inode->i_size_high || inode->i_size & 0x80000000UL) && + !ext2fs_test_inode_bitmap(ctx->inode_bad_map, ino)) ctx->large_files++; if (pb.num_blocks != inode->i_blocks) { pctx->num = pb.num_blocks; if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) { inode->i_blocks = pb.num_blocks; + if (LINUX_S_ISLNK(inode->i_mode)) + mark_inode_bad(ctx, ino); e2fsck_write_inode(ctx, ino, inode, "check_blocks"); } pctx->num = 0; diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c index a885f6f1..0d27d96c 100644 --- a/e2fsck/pass2.c +++ b/e2fsck/pass2.c @@ -699,9 +699,10 @@ extern int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir, && !e2fsck_pass1_check_device_inode(&inode)) problem = PR_2_BAD_SOCKET; else if (LINUX_S_ISLNK(inode.i_mode) - && (inode.i_size_high || - (inode.i_size > EXT2_N_BLOCKS*4))) + && !e2fsck_pass1_check_symlink(fs, &inode)) { + pctx.str = inode.i_blocks ? "" : "fast "; problem = PR_2_SYMLINK_SIZE; + } if (problem) { if (fix_problem(ctx, problem, &pctx)) { diff --git a/e2fsck/problem.c b/e2fsck/problem.c index cee69a9d..ebfaab47 100644 --- a/e2fsck/problem.c +++ b/e2fsck/problem.c @@ -928,7 +928,7 @@ static const struct e2fsck_problem problem_table[] = { /* Invalid fast symlink size */ { PR_2_SYMLINK_SIZE, - N_("@i %i (%Q) is a fast symlink with a bad size (%Is)\n"), + N_("@i %i (%Q) is a %ssymlink with a bad size (%Is)\n"), PROMPT_CLEAR, 0 }, /* i_file_acl (extended attribute block) is bad */ diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h index 0eb7be71..0a773d16 100644 --- a/lib/ext2fs/ext2_fs.h +++ b/lib/ext2fs/ext2_fs.h @@ -169,6 +169,8 @@ struct ext2_group_desc #define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1) #define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) +#define EXT2_LINK_DIR (EXT2_N_BLOCKS * 4) + /* * Inode flags */ diff --git a/tests/ChangeLog b/tests/ChangeLog index 15da8ac5..d22b2bfe 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,7 @@ +2001-07-26 Andreas Dilger + + * f_symlinks: Add several fast symlink error cases to test. + 2001-07-27 Theodore Tso * f_filetype: Update expect.1 to match changed problem message diff --git a/tests/README b/tests/README index 73e26817..d075db57 100644 --- a/tests/README +++ b/tests/README @@ -63,5 +63,6 @@ noroot.img Filesystem with a deleted root directory okgroup.img Filesystem that's exactly 8193 blocks long (otherwise OK) overfsblks.img Filesystem with overlapping inode and block bitmaps +symlinks.img Filesystem with bad symlink sizes