Skip to content

Commit

Permalink
xfs: Fix stale data exposure when readahead races with hole punch
Browse files Browse the repository at this point in the history
Hole puching currently evicts pages from page cache and then goes on to
remove blocks from the inode. This happens under both XFS_IOLOCK_EXCL
and XFS_MMAPLOCK_EXCL which provides appropriate serialization with
racing reads or page faults. However there is currently nothing that
prevents readahead triggered by fadvise() or madvise() from racing with
the hole punch and instantiating page cache page after hole punching has
evicted page cache in xfs_flush_unmap_range() but before it has removed
blocks from the inode. This page cache page will be mapping soon to be
freed block and that can lead to returning stale data to userspace or
even filesystem corruption.

Fix the problem by protecting handling of readahead requests by
XFS_IOLOCK_SHARED similarly as we protect reads.

CC: [email protected]
Link: https://lore.kernel.org/linux-fsdevel/CAOQ4uxjQNmxqmtA_VbYW0Su9rKRk2zobJmahcyeaEVOFKVQ5dw@mail.gmail.com/
Reported-by: Amir Goldstein <[email protected]>
Signed-off-by: Jan Kara <[email protected]>
Reviewed-by: Darrick J. Wong <[email protected]>
Signed-off-by: Darrick J. Wong <[email protected]>
  • Loading branch information
jankara authored and djwong committed Aug 31, 2019
1 parent cf1ea05 commit 40144e4
Showing 1 changed file with 26 additions and 0 deletions.
26 changes: 26 additions & 0 deletions fs/xfs/xfs_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <linux/falloc.h>
#include <linux/backing-dev.h>
#include <linux/mman.h>
#include <linux/fadvise.h>

static const struct vm_operations_struct xfs_file_vm_ops;

Expand Down Expand Up @@ -933,6 +934,30 @@ xfs_file_fallocate(
return error;
}

STATIC int
xfs_file_fadvise(
struct file *file,
loff_t start,
loff_t end,
int advice)
{
struct xfs_inode *ip = XFS_I(file_inode(file));
int ret;
int lockflags = 0;

/*
* Operations creating pages in page cache need protection from hole
* punching and similar ops
*/
if (advice == POSIX_FADV_WILLNEED) {
lockflags = XFS_IOLOCK_SHARED;
xfs_ilock(ip, lockflags);
}
ret = generic_fadvise(file, start, end, advice);
if (lockflags)
xfs_iunlock(ip, lockflags);
return ret;
}

STATIC loff_t
xfs_file_remap_range(
Expand Down Expand Up @@ -1232,6 +1257,7 @@ const struct file_operations xfs_file_operations = {
.fsync = xfs_file_fsync,
.get_unmapped_area = thp_get_unmapped_area,
.fallocate = xfs_file_fallocate,
.fadvise = xfs_file_fadvise,
.remap_file_range = xfs_file_remap_range,
};

Expand Down

0 comments on commit 40144e4

Please sign in to comment.