@@ -174,6 +174,27 @@ static int jread(struct buffer_head **bhp, journal_t *journal,
return 0;
}
+static int jbd2_descr_block_csum_verify(journal_t *j,
+ void *buf)
+{
+ struct journal_block_tail *tail;
+ __u32 provided, calculated;
+
+ if (!JFS_HAS_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V2))
+ return 1;
+
+ tail = (struct journal_block_tail *)(buf + j->j_blocksize -
+ sizeof(struct journal_block_tail));
+ provided = tail->t_checksum;
+ tail->t_checksum = 0;
+ calculated = ext2fs_crc32c_le(~0, j->j_superblock->s_uuid,
+ sizeof(j->j_superblock->s_uuid));
+ calculated = ext2fs_crc32c_le(calculated, buf, j->j_blocksize);
+ tail->t_checksum = provided;
+
+ provided = ext2fs_be32_to_cpu(provided);
+ return provided == calculated;
+}
/*
* Count the number of in-use tags in a journal descriptor block.
@@ -186,6 +207,9 @@ static int count_tags(journal_t *journal, struct buffer_head *bh)
int nr = 0, size = journal->j_blocksize;
int tag_bytes = journal_tag_bytes(journal);
+ if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V2))
+ size -= sizeof(struct journal_block_tail);
+
tagp = &bh->b_data[sizeof(journal_header_t)];
while ((tagp - bh->b_data + tag_bytes) <= size) {
@@ -364,6 +388,7 @@ static int do_one_pass(journal_t *journal,
int blocktype;
int tag_bytes = journal_tag_bytes(journal);
__u32 crc32_sum = ~0; /* Transactional Checksums */
+ int descr_csum_size = 0;
/* Precompute the maximum metadata descriptors in a descriptor block */
int MAX_BLOCKS_PER_DESC;
@@ -454,6 +479,18 @@ static int do_one_pass(journal_t *journal,
switch(blocktype) {
case JFS_DESCRIPTOR_BLOCK:
+ /* Verify checksum first */
+ if (JFS_HAS_INCOMPAT_FEATURE(journal,
+ JFS_FEATURE_INCOMPAT_CSUM_V2))
+ descr_csum_size =
+ sizeof(struct journal_block_tail);
+ if (descr_csum_size > 0 &&
+ !jbd2_descr_block_csum_verify(journal,
+ bh->b_data)) {
+ err = -EIO;
+ goto failed;
+ }
+
/* If it is a valid descriptor block, replay it
* in pass REPLAY; if journal_checksums enabled, then
* calculate checksums in PASS_SCAN, otherwise,
@@ -484,7 +521,7 @@ static int do_one_pass(journal_t *journal,
tagp = &bh->b_data[sizeof(journal_header_t)];
while ((tagp - bh->b_data + tag_bytes)
- <= journal->j_blocksize) {
+ <= journal->j_blocksize - descr_csum_size) {
unsigned long io_block;
tag = (journal_block_tag_t *) tagp;
Verify the descriptor block checksum when recovering a journal. Signed-off-by: Darrick J. Wong <djwong@us.ibm.com> --- e2fsck/recovery.c | 39 ++++++++++++++++++++++++++++++++++++++- 1 files changed, 38 insertions(+), 1 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html