Patch "ext4: avoid modifying checksum fields directly during checksum verification" has been added to the 4.7-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
ext4: avoid modifying checksum fields directly during checksum verification
to the 4.7-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
ext4-avoid-modifying-checksum-fields-directly-during-checksum-verification.patch
and it can be found in the queue-4.7 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
b47820edd1634dc1208f9212b7ecfb4230610a23Mon Sep 17 00:00:00 2001
From: Daeho Jeong <[email protected]>
Date: Sun, 3 Jul 2016 17:51:39 -0400
Subject: ext4: avoid modifying checksum fields directly during checksum verification
From: Daeho Jeong <[email protected]>
commit b47820edd1634dc1208f9212b7ecfb4230610a23 upstream.
We temporally change checksum fields in buffers of some types of metadata into '0' for verifying the checksum values. By doing this without locking the buffer, some metadata's checksums, which are being committed or written back to the storage, could be damaged. In our test, several metadata blocks were found with damaged metadata checksum value during recovery process. When we only verify the checksum value, we have to avoid modifying checksum fields directly.
--- fs/ext4/inode.c | 38 ++++++++++++++++++++++---------------- fs/ext4/namei.c | 9 ++++----- fs/ext4/super.c | 18 +++++++++--------- fs/ext4/xattr.c | 13 +++++++------ 4 files changed, 42 insertions(+), 36 deletions(-)
fs/ext4/inode.c +22 -16
@@ -51,25 +51,31 @@ static __u32 ext4_inode_csum(struct inod struct ext4_inode_info *ei) {struct ext4_sb_info *sbi =EXT4_SB (inode->i_sb); -__u16 csum_lo; -__u16 csum_hi =0 ;__u32 csum; +__u16 dummy_csum =0 ; +int offset = offsetof(struct ext4_inode , i_checksum_lo); +unsigned int csum_size =sizeof (dummy_csum); - csum_lo =le16_to_cpu (raw->i_checksum_lo); - raw->i_checksum_lo =0 ; -if (EXT4_INODE_SIZE (inode->i_sb) >EXT4_GOOD_OLD_INODE_SIZE && -EXT4_FITS_IN_INODE (raw, ei, i_checksum_hi)) { - csum_hi =le16_to_cpu (raw->i_checksum_hi); - raw->i_checksum_hi =0 ; - } - - csum =ext4_chksum (sbi, ei->i_csum_seed, (__u8 *)raw, -EXT4_INODE_SIZE (inode->i_sb)); + csum =ext4_chksum (sbi, ei->i_csum_seed, (__u8 *)raw, offset); + csum =ext4_chksum (sbi, csum, (__u8 *)&dummy_csum, csum_size); + offset += csum_size; + csum =ext4_chksum (sbi, csum, (__u8 *)raw + offset, +EXT4_GOOD_OLD_INODE_SIZE - offset); - raw->i_checksum_lo =cpu_to_le16 (csum_lo); -if (EXT4_INODE_SIZE (inode->i_sb) >EXT4_GOOD_OLD_INODE_SIZE && -EXT4_FITS_IN_INODE (raw, ei, i_checksum_hi)) - raw->i_checksum_hi =cpu_to_le16 (csum_hi); +if (EXT4_INODE_SIZE (inode->i_sb) >EXT4_GOOD_OLD_INODE_SIZE ) { + offset = offsetof(struct ext4_inode , i_checksum_hi); + csum =ext4_chksum (sbi, csum, (__u8 *)raw + +EXT4_GOOD_OLD_INODE_SIZE , + offset -EXT4_GOOD_OLD_INODE_SIZE ); +if (EXT4_FITS_IN_INODE (raw, ei, i_checksum_hi)) { + csum =ext4_chksum (sbi, csum, (__u8 *)&dummy_csum, + csum_size); + offset += csum_size; + csum =ext4_chksum (sbi, csum, (__u8 *)raw + offset, +EXT4_INODE_SIZE (inode->i_sb) - + offset); + } + }return csum; }
fs/ext4/namei.c +4 -5
@@ -420,15 +420,14 @@ static __le32 ext4_dx_csum(struct inodestruct ext4_sb_info *sbi =EXT4_SB (inode->i_sb);struct ext4_inode_info *ei =EXT4_I (inode);__u32 csum; -__le32 save_csum;int size; +__u32 dummy_csum =0 ; +int offset = offsetof(struct dx_tail , dt_checksum); size = count_offset + (count *sizeof (struct dx_entry )); - save_csum = t->dt_checksum; - t->dt_checksum =0 ; csum =ext4_chksum (sbi, ei->i_csum_seed, (__u8 *)dirent, size); - csum =ext4_chksum (sbi, csum, (__u8 *)t,sizeof (struct dx_tail )); - t->dt_checksum = save_csum; + csum =ext4_chksum (sbi, csum, (__u8 *)t, offset); + csum =ext4_chksum (sbi, csum, (__u8 *)&dummy_csum,sizeof (dummy_csum));return cpu_to_le32 (csum); }
fs/ext4/super.c +9 -9
@@ -2068,23 +2068,25 @@ failed:static __le16 ext4_group_desc_csum (struct super_block *sb,__u32 block_group,struct ext4_group_desc *gdp) { -int offset; +int offset = offsetof(struct ext4_group_desc , bg_checksum);__u16 crc =0 ;__le32 le_group =cpu_to_le32 (block_group);struct ext4_sb_info *sbi =EXT4_SB (sb);if (ext4_has_metadata_csum (sbi->s_sb)) {/* Use new metadata_csum algorithm */ -__le16 save_csum;__u32 csum32; +__u16 dummy_csum =0 ; - save_csum = gdp->bg_checksum; - gdp->bg_checksum =0 ; csum32 =ext4_chksum (sbi, sbi->s_csum_seed, (__u8 *)&le_group,sizeof (le_group)); - csum32 =ext4_chksum (sbi, csum32, (__u8 *)gdp, - sbi->s_desc_size); - gdp->bg_checksum = save_csum; + csum32 =ext4_chksum (sbi, csum32, (__u8 *)gdp, offset); + csum32 =ext4_chksum (sbi, csum32, (__u8 *)&dummy_csum, +sizeof (dummy_csum)); + offset +=sizeof (dummy_csum); +if (offset < sbi->s_desc_size) + csum32 =ext4_chksum (sbi, csum32, (__u8 *)gdp + offset, + sbi->s_desc_size - offset); crc = csum32 &0xFFFF ; goto out;
@@ -2094,8 +2096,6 @@ static __le16 ext4_group_desc_csum(strucif (!ext4_has_feature_gdt_csum (sb))return 0 ; - offset = offsetof(struct ext4_group_desc , bg_checksum); - crc =crc16 (~0 , sbi->s_es->s_uuid,sizeof (sbi->s_es->s_uuid)); crc =crc16 (crc, (__u8 *)&le_group,sizeof (le_group)); crc =crc16 (crc, (__u8 *)gdp, offset);
fs/ext4/xattr.c +7 -6
@@ -121,17 +121,18 @@ static __le32 ext4_xattr_block_csum(stru {struct ext4_sb_info *sbi =EXT4_SB (inode->i_sb);__u32 csum; -__le32 save_csum;__le64 dsk_block_nr =cpu_to_le64 (block_nr); +__u32 dummy_csum =0 ; +int offset = offsetof(struct ext4_xattr_header , h_checksum); - save_csum = hdr->h_checksum; - hdr->h_checksum =0 ; csum =ext4_chksum (sbi, sbi->s_csum_seed, (__u8 *)&dsk_block_nr,sizeof (dsk_block_nr)); - csum =ext4_chksum (sbi, csum, (__u8 *)hdr, -EXT4_BLOCK_SIZE (inode->i_sb)); + csum =ext4_chksum (sbi, csum, (__u8 *)hdr, offset); + csum =ext4_chksum (sbi, csum, (__u8 *)&dummy_csum,sizeof (dummy_csum)); + offset +=sizeof (dummy_csum); + csum =ext4_chksum (sbi, csum, (__u8 *)hdr + offset, +EXT4_BLOCK_SIZE (inode->i_sb) - offset); - hdr->h_checksum = save_csum;return cpu_to_le32 (csum); }
Patches currently in stable-queue which might be from [email protected] are
queue-4.7/ext4-avoid-modifying-checksum-fields-directly-during-checksum-verification.patch