Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

xfs: save ailp before dropping the AIL lock in push callbacks

In xfs_inode_item_push() and xfs_qm_dquot_logitem_push(), the AIL lock
is dropped to perform buffer IO. Once the cluster buffer no longer
protects the log item from reclaim, the log item may be freed by
background reclaim or the dquot shrinker. The subsequent spin_lock()
call dereferences lip->li_ailp, which is a use-after-free.

Fix this by saving the ailp pointer in a local variable while the AIL
lock is held and the log item is guaranteed to be valid.

Reported-by: syzbot+652af2b3c5569c4ab63c@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=652af2b3c5569c4ab63c
Fixes: 90c60e164012 ("xfs: xfs_iflush() is no longer necessary")
Cc: stable@vger.kernel.org # v5.9
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Yuto Ohnuki <ytohnuki@amazon.com>
Signed-off-by: Carlos Maiolino <cem@kernel.org>

authored by

Yuto Ohnuki and committed by
Carlos Maiolino
394d70b8 79ef34ec

+14 -4
+7 -2
fs/xfs/xfs_dquot_item.c
··· 125 125 struct xfs_dq_logitem *qlip = DQUOT_ITEM(lip); 126 126 struct xfs_dquot *dqp = qlip->qli_dquot; 127 127 struct xfs_buf *bp; 128 + struct xfs_ail *ailp = lip->li_ailp; 128 129 uint rval = XFS_ITEM_SUCCESS; 129 130 int error; 130 131 ··· 154 153 goto out_unlock; 155 154 } 156 155 157 - spin_unlock(&lip->li_ailp->ail_lock); 156 + spin_unlock(&ailp->ail_lock); 158 157 159 158 error = xfs_dquot_use_attached_buf(dqp, &bp); 160 159 if (error == -EAGAIN) { ··· 173 172 rval = XFS_ITEM_FLUSHING; 174 173 } 175 174 xfs_buf_relse(bp); 175 + /* 176 + * The buffer no longer protects the log item from reclaim, so 177 + * do not reference lip after this point. 178 + */ 176 179 177 180 out_relock_ail: 178 - spin_lock(&lip->li_ailp->ail_lock); 181 + spin_lock(&ailp->ail_lock); 179 182 out_unlock: 180 183 mutex_unlock(&dqp->q_qlock); 181 184 return rval;
+7 -2
fs/xfs/xfs_inode_item.c
··· 746 746 struct xfs_inode_log_item *iip = INODE_ITEM(lip); 747 747 struct xfs_inode *ip = iip->ili_inode; 748 748 struct xfs_buf *bp = lip->li_buf; 749 + struct xfs_ail *ailp = lip->li_ailp; 749 750 uint rval = XFS_ITEM_SUCCESS; 750 751 int error; 751 752 ··· 772 771 if (!xfs_buf_trylock(bp)) 773 772 return XFS_ITEM_LOCKED; 774 773 775 - spin_unlock(&lip->li_ailp->ail_lock); 774 + spin_unlock(&ailp->ail_lock); 776 775 777 776 /* 778 777 * We need to hold a reference for flushing the cluster buffer as it may ··· 796 795 rval = XFS_ITEM_LOCKED; 797 796 } 798 797 799 - spin_lock(&lip->li_ailp->ail_lock); 798 + /* 799 + * The buffer no longer protects the log item from reclaim, so 800 + * do not reference lip after this point. 801 + */ 802 + spin_lock(&ailp->ail_lock); 800 803 return rval; 801 804 } 802 805