gfs2: page poisoning fix

Processes can write to the last page of a file using mmap, and when the file
size is not a multiple of the page size, this can be used to write beyond the
end of the file.  This is sometimes referred to as page poisoning, and it is
not a problem in itself because the data beyond eof will be ignored.  However,
we currently fail to clear out any space beyond the end of the file that we
skip over when the file size is increased, so that "poison" can end up getting
exposed.  Fix that.

Fixes xfstest generic/363.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
This commit is contained in:
Andreas Gruenbacher
2026-05-27 21:15:04 +02:00
parent 70008e22ab
commit 4982e58669
3 changed files with 30 additions and 0 deletions

View File

@@ -1321,6 +1321,19 @@ static int gfs2_block_zero_range(struct inode *inode, loff_t from, loff_t length
&gfs2_iomap_write_ops, NULL);
}
int gfs2_clear_beyond_eof(struct inode *inode, loff_t end)
{
loff_t isize = i_size_read(inode);
unsigned int len = isize & ~PAGE_MASK;
if (!len || isize >= end)
return 0;
len = PAGE_SIZE - len;
if (end - isize < len)
len = end - isize;
return gfs2_block_zero_range(inode, isize, len);
}
#define GFS2_JTRUNC_REVOKES 8192
/**
@@ -2096,6 +2109,12 @@ static int do_grow(struct inode *inode, u64 size)
unstuff = 1;
}
if (!unstuff) {
error = gfs2_clear_beyond_eof(inode, size);
if (error)
goto do_grow_qunlock;
}
error = gfs2_trans_begin(sdp, RES_DINODE + RES_STATFS + RES_RG_BIT +
(unstuff &&
gfs2_is_jdata(ip) ? RES_JDATA : 0) +

View File

@@ -58,6 +58,7 @@ int gfs2_get_extent(struct inode *inode, u64 lblock, u64 *dblock,
unsigned int *extlen);
int gfs2_alloc_extent(struct inode *inode, u64 lblock, u64 *dblock,
unsigned *extlen, bool *new);
int gfs2_clear_beyond_eof(struct inode *inode, loff_t end);
int gfs2_setattr_size(struct inode *inode, u64 size);
int gfs2_truncatei_resume(struct gfs2_inode *ip);
int gfs2_file_dealloc(struct gfs2_inode *ip);

View File

@@ -1057,6 +1057,10 @@ static ssize_t gfs2_file_buffered_write(struct kiocb *iocb,
goto out_unlock;
}
ret = gfs2_clear_beyond_eof(inode, iocb->ki_pos);
if (ret)
goto out_unlock;
pagefault_disable();
ret = iomap_file_buffered_write(iocb, from, &gfs2_iomap_ops,
&gfs2_iomap_write_ops, NULL);
@@ -1265,6 +1269,12 @@ static long __gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t
next = (next + 1) << sdp->sd_sb.sb_bsize_shift;
if (!(mode & FALLOC_FL_KEEP_SIZE)) {
error = gfs2_clear_beyond_eof(inode, offset + len);
if (error)
return error;
}
offset &= bsize_mask;
len = next - offset;