From: Theodore Ts'o Date: Fri, 3 Aug 2012 00:47:46 +0000 (-0400) Subject: libext2fs: when checking the inode's checksum, allow an all-zero inode X-Git-Tag: v1.43-WIP-2012-09-22~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=97fac35094160261907eeb693498ef6ebd27283e;p=thirdparty%2Fe2fsprogs.git libext2fs: when checking the inode's checksum, allow an all-zero inode When the kernel writes an inode where all of the other inodes in in the inode table (itable) block are unused, it skips reading the itable block from disk, and instead uses an all zeros block. This can cause e2fsck to complain when it iterates over the inodes using ext2fs_get_next_inode() since the inode apparently has an invalid checksum. Normally the inode won't be returned at all if it is at the end of the block group's part of the inode table, thanks to the bg_itable_unused field. But it's possible for this situation to happen earlier in the inode table block. Fix this by changing ext2fs_inode_csum_verify() to allow the inode to be all zero's; if the checksum fails, and the inode is all zero's, treat it as a valid checksum. Reported-by: Tao Ma Reported-by: Zheng Liu Signed-off-by: "Theodore Ts'o" --- diff --git a/lib/ext2fs/csum.c b/lib/ext2fs/csum.c index 3083fb1d3..6c2e562a2 100644 --- a/lib/ext2fs/csum.c +++ b/lib/ext2fs/csum.c @@ -655,7 +655,8 @@ int ext2fs_inode_csum_verify(ext2_filsys fs, ext2_ino_t inum, { errcode_t retval; __u32 provided, calculated; - int has_hi; + int i, has_hi; + char *cp; if (fs->super->s_creator_os != EXT2_OS_LINUX || !EXT2_HAS_RO_COMPAT_FEATURE(fs->super, @@ -675,7 +676,23 @@ int ext2fs_inode_csum_verify(ext2_filsys fs, ext2_ino_t inum, } else calculated &= 0xFFFF; - return provided == calculated; + if (provided == calculated) + return 1; + + /* + * If the checksum didn't match, it's possible it was due to + * the inode being all zero's. It's unlikely this is the + * case, but it can happen. So check for it here. (We only + * check the base inode since that's good enough, and it's not + * worth the bother to figure out how much of the extended + * inode, if any, is present.) + */ + for (cp = (char *) inode, i = 0; + i < sizeof(struct ext2_inode); + cp++, i++) + if (*cp) + return 0; + return 1; /* Inode must have been all zero's */ } errcode_t ext2fs_inode_csum_set(ext2_filsys fs, ext2_ino_t inum,