Skip to content

Commit 001c179

Browse files
ChenXiaoSongDarrick J. Wong
authored andcommitted
xfs: fix NULL pointer dereference in xfs_getbmap()
Reproducer: 1. fallocate -l 100M image 2. mkfs.xfs -f image 3. mount image /mnt 4. setxattr("/mnt", "trusted.overlay.upper", NULL, 0, XATTR_CREATE) 5. char arg[32] = "\x01\xff\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x08\x00\x00\x00\xc6\x2a\xf7"; fd = open("/mnt", O_RDONLY|O_DIRECTORY); ioctl(fd, _IOC(_IOC_READ|_IOC_WRITE, 0x58, 0x2c, 0x20), arg); NULL pointer dereference will occur when race happens between xfs_getbmap() and xfs_bmap_set_attrforkoff(): ioctl | setxattr ----------------------------|--------------------------- xfs_getbmap | xfs_ifork_ptr | xfs_inode_has_attr_fork | ip->i_forkoff == 0 | return NULL | ifp == NULL | | xfs_bmap_set_attrforkoff | ip->i_forkoff > 0 xfs_inode_has_attr_fork | ip->i_forkoff > 0 | ifp == NULL | ifp->if_format | Fix this by locking i_lock before xfs_ifork_ptr(). Fixes: abbf9e8 ("xfs: rewrite getbmap using the xfs_iext_* helpers") Signed-off-by: ChenXiaoSong <chenxiaosong2@huawei.com> Signed-off-by: Guo Xuenan <guoxuenan@huawei.com> Reviewed-by: Darrick J. Wong <djwong@kernel.org> [djwong: added fixes tag] Signed-off-by: Darrick J. Wong <djwong@kernel.org>
1 parent 4869b6e commit 001c179

File tree

1 file changed

+9
-8
lines changed

1 file changed

+9
-8
lines changed

fs/xfs/xfs_bmap_util.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -439,29 +439,28 @@ xfs_getbmap(
439439
whichfork = XFS_COW_FORK;
440440
else
441441
whichfork = XFS_DATA_FORK;
442-
ifp = xfs_ifork_ptr(ip, whichfork);
443442

444443
xfs_ilock(ip, XFS_IOLOCK_SHARED);
445444
switch (whichfork) {
446445
case XFS_ATTR_FORK:
446+
lock = xfs_ilock_attr_map_shared(ip);
447447
if (!xfs_inode_has_attr_fork(ip))
448-
goto out_unlock_iolock;
448+
goto out_unlock_ilock;
449449

450450
max_len = 1LL << 32;
451-
lock = xfs_ilock_attr_map_shared(ip);
452451
break;
453452
case XFS_COW_FORK:
453+
lock = XFS_ILOCK_SHARED;
454+
xfs_ilock(ip, lock);
455+
454456
/* No CoW fork? Just return */
455-
if (!ifp)
456-
goto out_unlock_iolock;
457+
if (!xfs_ifork_ptr(ip, whichfork))
458+
goto out_unlock_ilock;
457459

458460
if (xfs_get_cowextsz_hint(ip))
459461
max_len = mp->m_super->s_maxbytes;
460462
else
461463
max_len = XFS_ISIZE(ip);
462-
463-
lock = XFS_ILOCK_SHARED;
464-
xfs_ilock(ip, lock);
465464
break;
466465
case XFS_DATA_FORK:
467466
if (!(iflags & BMV_IF_DELALLOC) &&
@@ -491,6 +490,8 @@ xfs_getbmap(
491490
break;
492491
}
493492

493+
ifp = xfs_ifork_ptr(ip, whichfork);
494+
494495
switch (ifp->if_format) {
495496
case XFS_DINODE_FMT_EXTENTS:
496497
case XFS_DINODE_FMT_BTREE:

0 commit comments

Comments
 (0)