mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 02:17:36 -04:00
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:
@@ -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) +
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user