From 0550870b1c590be6beb09b57762ec43b5516f7d1 Mon Sep 17 00:00:00 2001 From: Ma Haijun Date: Wed, 8 Jan 2014 08:15:33 +0800 Subject: fs/ext4: fix calling put_ext4 with truncated offset Curently, we are using 32 bit multiplication to calculate the offset, so the result will always be 32 bit. This can silently cause file system corruption when performing a write operation on partition larger than 4 GiB. This patch address the issue by simply promoting the terms to 64 bit, and let compilers decide how to do the multiplication efficiently. Signed-off-by: Ma Haijun --- fs/ext4/ext4_common.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'fs/ext4/ext4_common.c') diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 352943ec51..cff50d8c17 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -445,9 +445,9 @@ restart: goto fail; } put_ext4(((uint64_t) - (g_parent_inode->b. + ((uint64_t)g_parent_inode->b. blocks.dir_blocks[direct_blk_idx] * - fs->blksz)), zero_buffer, fs->blksz); + (uint64_t)fs->blksz)), zero_buffer, fs->blksz); g_parent_inode->size = g_parent_inode->size + fs->blksz; g_parent_inode->blockcnt = @@ -864,8 +864,8 @@ long int ext4fs_get_new_blk_no(void) for (i = 0; i < fs->no_blkgrp; i++) { if (bgd[i].free_blocks) { if (bgd[i].bg_flags & EXT4_BG_BLOCK_UNINIT) { - put_ext4(((uint64_t) (bgd[i].block_id * - fs->blksz)), + put_ext4(((uint64_t) ((uint64_t)bgd[i].block_id * + (uint64_t)fs->blksz)), zero_buffer, fs->blksz); bgd[i].bg_flags = bgd[i]. @@ -929,8 +929,8 @@ restart: if (bgd[bg_idx].bg_flags & EXT4_BG_BLOCK_UNINIT) { memset(zero_buffer, '\0', fs->blksz); - put_ext4(((uint64_t) (bgd[bg_idx].block_id * - fs->blksz)), zero_buffer, fs->blksz); + put_ext4(((uint64_t) ((uint64_t)bgd[bg_idx].block_id * + (uint64_t)fs->blksz)), zero_buffer, fs->blksz); memcpy(fs->blk_bmaps[bg_idx], zero_buffer, fs->blksz); bgd[bg_idx].bg_flags = bgd[bg_idx].bg_flags & ~EXT4_BG_BLOCK_UNINIT; @@ -996,8 +996,8 @@ int ext4fs_get_new_inode_no(void) bgd[i].free_inodes; if (bgd[i].bg_flags & EXT4_BG_INODE_UNINIT) { put_ext4(((uint64_t) - (bgd[i].inode_id * - fs->blksz)), + ((uint64_t)bgd[i].inode_id * + (uint64_t)fs->blksz)), zero_buffer, fs->blksz); bgd[i].bg_flags = bgd[i].bg_flags & ~EXT4_BG_INODE_UNINIT; @@ -1037,8 +1037,8 @@ restart: ibmap_idx = fs->curr_inode_no / inodes_per_grp; if (bgd[ibmap_idx].bg_flags & EXT4_BG_INODE_UNINIT) { memset(zero_buffer, '\0', fs->blksz); - put_ext4(((uint64_t) (bgd[ibmap_idx].inode_id * - fs->blksz)), zero_buffer, + put_ext4(((uint64_t) ((uint64_t)bgd[ibmap_idx].inode_id * + (uint64_t)fs->blksz)), zero_buffer, fs->blksz); bgd[ibmap_idx].bg_flags = bgd[ibmap_idx].bg_flags & ~EXT4_BG_INODE_UNINIT; @@ -1143,7 +1143,7 @@ static void alloc_single_indirect_block(struct ext2_inode *file_inode, } /* write the block to disk */ - put_ext4(((uint64_t) (si_blockno * fs->blksz)), + put_ext4(((uint64_t) ((uint64_t)si_blockno * (uint64_t)fs->blksz)), si_start_addr, fs->blksz); file_inode->b.blocks.indir_block = si_blockno; } @@ -1242,7 +1242,7 @@ static void alloc_double_indirect_block(struct ext2_inode *file_inode, break; } /* write the block table */ - put_ext4(((uint64_t) (di_blockno_child * fs->blksz)), + put_ext4(((uint64_t) ((uint64_t)di_blockno_child * (uint64_t)fs->blksz)), di_child_buff_start, fs->blksz); free(di_child_buff_start); di_child_buff_start = NULL; @@ -1250,7 +1250,7 @@ static void alloc_double_indirect_block(struct ext2_inode *file_inode, if (*total_remaining_blocks == 0) break; } - put_ext4(((uint64_t) (di_blockno_parent * fs->blksz)), + put_ext4(((uint64_t) ((uint64_t)di_blockno_parent * (uint64_t)fs->blksz)), di_block_start_addr, fs->blksz); file_inode->b.blocks.double_indir_block = di_blockno_parent; } @@ -1348,8 +1348,8 @@ static void alloc_triple_indirect_block(struct ext2_inode *file_inode, break; } /* write the child block */ - put_ext4(((uint64_t) (ti_child_blockno * - fs->blksz)), + put_ext4(((uint64_t) ((uint64_t)ti_child_blockno * + (uint64_t)fs->blksz)), ti_cbuff_start_addr, fs->blksz); free(ti_cbuff_start_addr); @@ -1357,7 +1357,7 @@ static void alloc_triple_indirect_block(struct ext2_inode *file_inode, break; } /* write the parent block */ - put_ext4(((uint64_t) (ti_parent_blockno * fs->blksz)), + put_ext4(((uint64_t) ((uint64_t)ti_parent_blockno * (uint64_t)fs->blksz)), ti_pbuff_start_addr, fs->blksz); free(ti_pbuff_start_addr); @@ -1365,7 +1365,7 @@ static void alloc_triple_indirect_block(struct ext2_inode *file_inode, break; } /* write the grand parent block */ - put_ext4(((uint64_t) (ti_gp_blockno * fs->blksz)), + put_ext4(((uint64_t) ((uint64_t)ti_gp_blockno * (uint64_t)fs->blksz)), ti_gp_buff_start_addr, fs->blksz); file_inode->b.blocks.triple_indir_block = ti_gp_blockno; } -- cgit From 470173274d9ceb18a7140ef93e20be6c2236e7d9 Mon Sep 17 00:00:00 2001 From: Ionut Nicu Date: Mon, 13 Jan 2014 11:59:24 +0100 Subject: ext4fs: use EXT2_BLOCK_SIZE instead of fs->blksz Using fs->blksz in ext4fs_get_extent_block() is not correct since fs->blksz is not initialized on the read path. Use EXT2_BLOCK_SIZE() instead which will produce the desired output. Signed-off-by: Ionut Nicu Signed-off-by: Mathias Rulf --- fs/ext4/ext4_common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs/ext4/ext4_common.c') diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index cff50d8c17..c5e654235a 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -1414,7 +1414,7 @@ static struct ext4_extent_header *ext4fs_get_extent_block { struct ext4_extent_idx *index; unsigned long long block; - struct ext_filesystem *fs = get_fs(); + int blksz = EXT2_BLOCK_SIZE(data); int i; while (1) { @@ -1438,7 +1438,7 @@ static struct ext4_extent_header *ext4fs_get_extent_block block = le16_to_cpu(index[i].ei_leaf_hi); block = (block << 32) + le32_to_cpu(index[i].ei_leaf_lo); - if (ext4fs_devread((lbaint_t)block << log2_blksz, 0, fs->blksz, + if (ext4fs_devread((lbaint_t)block << log2_blksz, 0, blksz, buf)) ext_block = (struct ext4_extent_header *)buf; else -- cgit From b5bbac1a9b07016602559ff483df265fef6c1f83 Mon Sep 17 00:00:00 2001 From: Ionut Nicu Date: Mon, 13 Jan 2014 12:00:08 +0100 Subject: ext4fs: fix "invalid extent block" error For files where we actually have extent indexes following an extent header (ext_block->eh_depth != 0), the do/while loop from ext4fs_get_extent_block() does not select the proper extent index structure. For example, if we have: ext_block->eh_depth = 1 ext_block->eh_entries = 1 fileblock = 0 index[0].ei_block = 0 the do/while loop will exit with i set to 0 and the ext4fs_get_extent_block() function will return 0, even if there was a valid extent index structure following the header. Signed-off-by: Ionut Nicu Signed-off-by: Mathias Rulf --- fs/ext4/ext4_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/ext4/ext4_common.c') diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index c5e654235a..02da75c084 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -1430,7 +1430,7 @@ static struct ext4_extent_header *ext4fs_get_extent_block i++; if (i >= le16_to_cpu(ext_block->eh_entries)) break; - } while (fileblock > le32_to_cpu(index[i].ei_block)); + } while (fileblock >= le32_to_cpu(index[i].ei_block)); if (--i < 0) return 0; -- cgit