aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2017-02-02 18:13:57 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-04-08 03:30:30 -0400
commit0a6844abacc1adf428f80ad1b4b1f4cce915d2b2 (patch)
treec2b7548bf2af6ec5b0da06975f11bd53f96899dc
parent4127a5d9fb89fd74d2816456e309eb82a3d375a9 (diff)
xfs: fix toctou race when locking an inode to access the data map
commit 4b5bd5bf3fb182dc504b1b64e0331300f156e756 upstream. We use di_format and if_flags to decide whether we're grabbing the ilock in btree mode (btree extents not loaded) or shared mode (anything else), but the state of those fields can be changed by other threads that are also trying to load the btree extents -- IFEXTENTS gets set before the _bmap_read_extents call and cleared if it fails. We don't actually need to have IFEXTENTS set until after the bmbt records are successfully loaded and validated, which will fix the race between multiple threads trying to read the same directory. The next patch strengthens directory bmbt validation by refusing to open the directory if reading the bmbt to start directory readahead fails. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--fs/xfs/libxfs/xfs_inode_fork.c3
1 files changed, 1 insertions, 2 deletions
diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
index 222e103356c6..421341f93bea 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.c
+++ b/fs/xfs/libxfs/xfs_inode_fork.c
@@ -497,15 +497,14 @@ xfs_iread_extents(
497 * We know that the size is valid (it's checked in iformat_btree) 497 * We know that the size is valid (it's checked in iformat_btree)
498 */ 498 */
499 ifp->if_bytes = ifp->if_real_bytes = 0; 499 ifp->if_bytes = ifp->if_real_bytes = 0;
500 ifp->if_flags |= XFS_IFEXTENTS;
501 xfs_iext_add(ifp, 0, nextents); 500 xfs_iext_add(ifp, 0, nextents);
502 error = xfs_bmap_read_extents(tp, ip, whichfork); 501 error = xfs_bmap_read_extents(tp, ip, whichfork);
503 if (error) { 502 if (error) {
504 xfs_iext_destroy(ifp); 503 xfs_iext_destroy(ifp);
505 ifp->if_flags &= ~XFS_IFEXTENTS;
506 return error; 504 return error;
507 } 505 }
508 xfs_validate_extents(ifp, nextents, XFS_EXTFMT_INODE(ip)); 506 xfs_validate_extents(ifp, nextents, XFS_EXTFMT_INODE(ip));
507 ifp->if_flags |= XFS_IFEXTENTS;
509 return 0; 508 return 0;
510} 509}
511/* 510/*