• Akira Fujita's avatar
    ext4: Fix double-free of blocks with EXT4_IOC_MOVE_EXT · 94d7c16c
    Akira Fujita authored
    At the beginning of ext4_move_extent(), we call
    ext4_discard_preallocations() to discard inode PAs of orig and donor
    inodes.  But in the following case, blocks can be double freed, so
    move ext4_discard_preallocations() to the end of ext4_move_extents().
    
    1. Discard inode PAs of orig and donor inodes with
       ext4_discard_preallocations() in ext4_move_extents().
    
       orig : [ DATA1 ]
       donor: [ DATA2 ]
    
    2. While data blocks are exchanging between orig and donor inodes, new
       inode PAs is created to orig by other process's block allocation.
       (Since there are semaphore gaps in ext4_move_extents().)  And new
       inode PAs is used partially (2-1).
    
       2-1 Create new inode PAs to orig inode
       orig : [ DATA1 | used PA1 | free PA1 ]
       donor: [ DATA2 ]
    
    3. Donor inode which has old orig inode's blocks is deleted after
       EXT4_IOC_MOVE_EXT finished (3-1, 3-2).  So the block bitmap
       corresponds to old orig inode's blocks are freed.
    
       3-1 After EXT4_IOC_MOVE_EXT finished
       orig : [ DATA2 |  free PA1 ]
       donor: [ DATA1 |  used PA1 ]
    
       3-2 Delete donor inode
       orig : [ DATA2 |  free PA1 ]
       donor: [ FREE SPACE(DATA1) | FREE SPACE(used PA1) ]
    
    4. The double-free of blocks is occurred, when close() is called to
       orig inode.  Because ext4_discard_preallocations() for orig inode
       frees used PA1 and free PA1, though used PA1 is already freed in 3.
    
       4-1 Double-free of blocks is occurred
       orig : [ DATA2 |  FREE SPACE(free PA1) ]
       donor: [ FREE SPACE(DATA1) | DOUBLE FREE(used PA1) ]
    Signed-off-by: default avatarAkira Fujita <a-fujita@rs.jp.nec.com>
    Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
    94d7c16c
move_extent.c 41 KB