linux-ext4.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] libext2fs: fix off-by-one bug in ext2fs_extent_insert()
@ 2014-01-16  4:41 Theodore Ts'o
  2014-01-16  6:43 ` Theodore Ts'o
  0 siblings, 1 reply; 2+ messages in thread
From: Theodore Ts'o @ 2014-01-16  4:41 UTC (permalink / raw)
  To: Ext4 Developers List; +Cc: Theodore Ts'o

When inserting the first extent into an empty inode, the
ext2fs_extent_insert() leaves path->left set to 1 instead of 0.  Since
path->curr is pointing at the last (only) extent in the file,
path->left should be 0.

This is mostly harmless, and gets corrected fairly quickly if the
calling applicaton jumps to a different part of the extent tree ---
for example, by calling ext2fs_extent_goto(), or calling
ext2fs_extent_get with the flags argument set to EXT2_EXTENT_ROOT.
Which is why we hadn't noticed this problem until now.

However, if you insert four extents using ext2fs_extent_insert, the
fourth insert will end up copying many bytes in the i_block[] array,
since path->left is one larger than it should be.  This results in the
inode fields i_generation, i_file_acl, and i_size_high getting zeroed
out.

This problem can be replicated as follows:

% mke2fs -F -t /tmp/ext4 /tmp/foo.img 100
% debugfs -w /tmp/foo.img
debugfs: copy /dev/null foo
debugfs: set_inode_field foo i_size_hi 1
debugfs: stat foo
debugfs: extent_open foo
debugfs (extent ino 12): insert --after 0 1 100
debugfs (extent ino 12): insert --after 1 1 101
debugfs (extent ino 12): insert --after 2 1 102
debugfs (extent ino 12): insert --after 3 1 103
debugfs (extent ino 12): extent_close
debugfs: stat foo
debugfs: quit

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
---
 lib/ext2fs/extent.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/lib/ext2fs/extent.c b/lib/ext2fs/extent.c
index 5cdc2e4..6f4f1d2 100644
--- a/lib/ext2fs/extent.c
+++ b/lib/ext2fs/extent.c
@@ -1092,8 +1092,10 @@ errcode_t ext2fs_extent_insert(ext2_extent_handle_t handle, int flags,
 			ix++;
 			path->left--;
 		}
-	} else
+	} else {
 		ix = EXT_FIRST_INDEX(eh);
+		path->left = -1;
+	}
 
 	path->curr = ix;
 
-- 
1.8.5.rc3.362.gdf10213


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] libext2fs: fix off-by-one bug in ext2fs_extent_insert()
  2014-01-16  4:41 [PATCH] libext2fs: fix off-by-one bug in ext2fs_extent_insert() Theodore Ts'o
@ 2014-01-16  6:43 ` Theodore Ts'o
  0 siblings, 0 replies; 2+ messages in thread
From: Theodore Ts'o @ 2014-01-16  6:43 UTC (permalink / raw)
  To: Ext4 Developers List

Here is a fixed up commit description, since there were a number of
typo's in the original.

					- Ted

commit 07f47fa2c755c139d26fd9fe2ac652d7cda04491
Author: Theodore Ts'o <tytso@mit.edu>
Date:   Wed Jan 15 23:29:21 2014 -0500

    libext2fs: fix off-by-one bug in ext2fs_extent_insert()
    
    When inserting the first extent into an empty inode, the
    ext2fs_extent_insert() leaves path->left set to 1 instead of 0.  Since
    path->curr is pointing at the last (only) extent in the file,
    path->left should be 0.
    
    This is mostly harmless, and gets corrected fairly quickly if the
    calling applicaton jumps to a different part of the extent tree ---
    for example, by calling ext2fs_extent_goto(), or calling
    ext2fs_extent_get with the flags argument set to EXT2_EXTENT_ROOT.
    Which is why we hadn't noticed this problem until now.
    
    However, if you insert four extents using ext2fs_extent_insert, the
    fourth insert will end up copying too many bytes in the i_block[]
    array, since path->left is one larger than it should be.  This results
    in the inode fields i_generation, i_file_acl, and i_size_high getting
    zeroed out.
    
    This problem can be replicated as follows:
    
    % cp /dev/null /tmp/foo.img
    % mke2fs -F -t ext4 /tmp/foo.img 100
    % debugfs -w /tmp/foo.img
    debugfs: write /dev/null foo
    debugfs: set_inode_field foo i_size_hi 1
    debugfs: stat foo
     <----- note that the inode's size is 4294967296
    debugfs: extent_open foo
    debugfs (extent ino 12): insert --after 0 1 100
    debugfs (extent ino 12): insert --after 1 1 101
    debugfs (extent ino 12): insert --after 2 1 102
    debugfs (extent ino 12): insert --after 3 1 103
    debugfs (extent ino 12): extent_close
    debugfs: stat foo
     <----- note that the inode's size is now 0
    debugfs: quit
    
    Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2014-01-16  6:43 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-01-16  4:41 [PATCH] libext2fs: fix off-by-one bug in ext2fs_extent_insert() Theodore Ts'o
2014-01-16  6:43 ` Theodore Ts'o

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).