Commit 4d559248 authored by Long Li's avatar Long Li
Browse files

xfs: correct the truncate blocksize of forcealign

hulk inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I9VTE3


CVE: NA

--------------------------------

Now xfs_itruncate_extents() unmap extsize aligned extents for forcealign,
when unaligned truncating down a forceflign file which extsize is bigger
than one block, xfs_truncate_page() only zeros out the tail EOF block,
this could expose stale data.

If we truncate file that contains a large enough written extent:

     |<      ext    >|<      ext    >|
  ...WWWWWWWWWWWWWWWWWWWWWzzzzzzzzzzzz
        ^ (new EOF)      ^ old EOF

Since we only zeros out the tail of the EOF block, and
xfs_itruncate_extents() unmap the whole ailgned extents, it becomes
this state:

     |<      ext    >|
  ...WWWzWWWWWWWWWWWWW
        ^ new EOF

Then if we do an extending write like this, the blocks in the previous
tail extent becomes stale:

     |<      ext    >|      |<     ext     >|
  ...WWWzSSSSSSSSSSSSS......WWWWWWWWWWWzzzzzz
        ^ old EOF     ^ append start  ^ new EOF

Fix this by zeroing out the tail allocation uint for forcealign.

Fixes: fabcdd2d ("fs: xfs: Introduce FORCEALIGN inode flag")
Signed-off-by: default avatarLong Li <leo.lilong@huawei.com>
parent 198535e5
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -770,6 +770,7 @@ xfs_setattr_size(
	uint			lock_flags = 0;
	bool			did_zeroing = false;
	bool                    write_back = false;
	unsigned int            blocksize = 0;

	ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
	ASSERT(xfs_isilocked(ip, XFS_MMAPLOCK_EXCL));
@@ -777,6 +778,11 @@ xfs_setattr_size(
	ASSERT((iattr->ia_valid & (ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_ATIME_SET|
		ATTR_MTIME_SET|ATTR_TIMES_SET)) == 0);

	if (xfs_inode_forcealign(ip) && ip->i_d.di_extsize > 1)
		blocksize = ip->i_d.di_extsize << i_blocksize(inode);
	else
		blocksize = i_blocksize(inode);

	oldsize = inode->i_size;
	newsize = iattr->ia_size;

@@ -808,8 +814,6 @@ xfs_setattr_size(

	write_back = newsize > ip->i_d.di_size && oldsize != ip->i_d.di_size;
	if (newsize < oldsize) {
		unsigned int	blocksize = i_blocksize(inode);

		/*
		 * iomap won't detect a dirty page over an unwritten block (or a
		 * cow block over a hole) and subsequently skips zeroing the