ext4: fix xattr shifting when expanding inodes part 2
authorJan Kara <jack@suse.cz>
Thu, 11 Aug 2016 15:58:32 +0000 (11:58 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Thu, 11 Aug 2016 15:58:32 +0000 (11:58 -0400)
When multiple xattrs need to be moved out of inode, we did not properly
recompute total size of xattr headers in the inode and the new header
position. Thus when moving the second and further xattr we asked
ext4_xattr_shift_entries() to move too much and from the wrong place,
resulting in possible xattr value corruption or general memory
corruption.

CC: stable@vger.kernel.org # 4.4.x
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/ext4/xattr.c

index cb1d7b4482de79c0b426a67084be854111811055..b18b1ff7cc2725271c853f989b5da33223fbcac3 100644 (file)
@@ -1516,6 +1516,7 @@ retry:
                error = ext4_xattr_ibody_set(handle, inode, &i, is);
                if (error)
                        goto cleanup;
+               total_ino -= entry_size;
 
                entry = IFIRST(header);
                if (entry_size + EXT4_XATTR_SIZE(size) >= isize_diff)
@@ -1526,11 +1527,11 @@ retry:
                ext4_xattr_shift_entries(entry, -shift_bytes,
                        (void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE +
                        EXT4_I(inode)->i_extra_isize + shift_bytes,
-                       (void *)header, total_ino - entry_size,
-                       inode->i_sb->s_blocksize);
+                       (void *)header, total_ino, inode->i_sb->s_blocksize);
 
                isize_diff -= shift_bytes;
                EXT4_I(inode)->i_extra_isize += shift_bytes;
+               header = IHDR(inode, raw_inode);
 
                i.name = b_entry_name;
                i.value = buffer;