]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
libext2fs: fix off-by-one bug in ext2fs_extent_insert()
authorTheodore Ts'o <tytso@mit.edu>
Thu, 16 Jan 2014 04:29:21 +0000 (23:29 -0500)
committerTheodore Ts'o <tytso@mit.edu>
Mon, 20 Jan 2014 00:18:48 +0000 (19:18 -0500)
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>
lib/ext2fs/extent.c

index 5cdc2e49a1e3a01bbb9b112bdac574869aa30a39..6f4f1d21b14cce08de24ba43cff7ccbc622ecf9d 100644 (file)
@@ -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;