Yan Zheng
2007-Nov-04 16:29 UTC
[Btrfs-devel][PATCH]Fix u32 overflow in dirty_and_release_pages.
Hello, At file.c:306 inline_size = end_pos; if (isize >= BTRFS_MAX_INLINE_DATA_SIZE(root) || inline_size > 32768 || inline_size >= BTRFS_MAX_INLINE_DATA_SIZE(root)) When 'end_pos' is larger than 2^32, 'inline_size' may become a small value. In this case, 'dirty_and_release_pages' may try to insert a very large inline extent. Regards YZ --- diff -r 2456df534a5f file.c --- a/file.c Thu Nov 01 19:45:34 2007 -0400 +++ b/file.c Mon Nov 05 07:41:23 2007 +0800 @@ -239,7 +239,7 @@ static int dirty_and_release_pages(struc u64 start_pos; u64 end_of_last_block; u64 end_pos = pos + write_bytes; - u32 inline_size; + u64 inline_size; loff_t isize = i_size_read(inode); em = alloc_extent_map(GFP_NOFS);
Yan Zheng
2007-Nov-05 02:46 UTC
[Btrfs-devel][PATCH]Fix u32 overflow in dirty_and_release_pages.
Hello, When calculating the size of inline extent, inode->i_size should also be take into consideration, otherwise sys_write may drop some data silently. You can test this bug by: #dd if=/dev/zero bs=4k count=1 of=test_file #dd if=/dev/zero bs=2k count=1 of=test_file conv=notrunc Previous patch is included in this one, please ignore it. Regards YZ --- diff -r 2456df534a5f file.c --- a/file.c Thu Nov 01 19:45:34 2007 -0400 +++ b/file.c Mon Nov 05 18:44:36 2007 +0800 @@ -239,7 +239,7 @@ static int dirty_and_release_pages(struc u64 start_pos; u64 end_of_last_block; u64 end_pos = pos + write_bytes; - u32 inline_size; + u64 inline_size; loff_t isize = i_size_read(inode); em = alloc_extent_map(GFP_NOFS); @@ -328,9 +328,11 @@ static int dirty_and_release_pages(struc aligned_end, aligned_end, &hint_byte); if (err) goto failed; + if (isize > inline_size) + inline_size = min_t(u64, isize, aligned_end); + inline_size -= start_pos; err = insert_inline_extent(trans, root, inode, start_pos, - end_pos - start_pos, pages, 0, - num_pages); + inline_size, pages, 0, num_pages); BUG_ON(err); } if (end_pos > isize) {