Re: [PATCH 4/5] xfs: fix a UAF when dquot item push

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Aug 23, 2024 at 07:04:38PM +0800, Long Li wrote:
> If errors are encountered while pushing a dquot log item, the dquot dirty
> flag is cleared. Without the protection of dqlock and dqflock locks, the
> dquot reclaim thread may free the dquot. Accessing the log item in xfsaild
> after this can trigger a UAF.
> 
>   CPU0                              CPU1
>   push item                         reclaim dquot
>   -----------------------           -----------------------
>   xfsaild_push_item
>     xfs_qm_dquot_logitem_push(lip)
>       xfs_dqlock_nowait(dqp)
>       xfs_dqflock_nowait(dqp)
>       spin_unlock(&lip->li_ailp->ail_lock)
>       xfs_qm_dqflush(dqp, &bp)
>                        <encountered some errors>
>         xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE)
>         dqp->q_flags &= ~XFS_DQFLAG_DIRTY
>                        <dquot is not diry>
>         xfs_trans_ail_delete(lip, 0)
>         xfs_dqfunlock(dqp)
>       spin_lock(&lip->li_ailp->ail_lock)
>       xfs_dqunlock(dqp)
>                                     xfs_qm_shrink_scan
>                                       list_lru_shrink_walk
>                                         xfs_qm_dquot_isolate
>                                           xfs_dqlock_nowait(dqp)
>                                           xfs_dqfunlock(dqp)
>                                           //dquot is clean, not flush it
>                                           xfs_dqfunlock(dqp)
>                                           dqp->q_flags |= XFS_DQFLAG_FREEING
>                                           xfs_dqunlock(dqp)
>                                           //add dquot to dispose list
>                                       //free dquot in dispose list
>                                       xfs_qm_dqfree_one(dqp)
>   trace_xfs_ail_xxx(lip)  //UAF
> 
> Fix this by returning XFS_ITEM_UNSAFE in xfs_qm_dquot_logitem_push() when
> dquot flush encounters errors (excluding EAGAIN error), ensuring xfsaild
> does not access the log item after it is pushed.
> 
> Fixes: 9e4c109ac822 ("xfs: add AIL pushing tracepoints")
> Signed-off-by: Long Li <leo.lilong@xxxxxxxxxx>
> ---
>  fs/xfs/xfs_dquot_item.c | 10 +++++++++-
>  1 file changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/xfs/xfs_dquot_item.c b/fs/xfs/xfs_dquot_item.c
> index 7d19091215b0..afc7ad91ddef 100644
> --- a/fs/xfs/xfs_dquot_item.c
> +++ b/fs/xfs/xfs_dquot_item.c
> @@ -160,8 +160,16 @@ xfs_qm_dquot_logitem_push(
>  		if (!xfs_buf_delwri_queue(bp, buffer_list))
>  			rval = XFS_ITEM_FLUSHING;
>  		xfs_buf_relse(bp);
> -	} else if (error == -EAGAIN)
> +	} else if (error == -EAGAIN) {
>  		rval = XFS_ITEM_LOCKED;
> +	} else {
> +		/*
> +		 * The dirty flag has been cleared; the dquot may be reclaimed
> +		 * after unlock. It's unsafe to access the item after it has
> +		 * been pushed.
> +		 */
> +		rval = XFS_ITEM_UNSAFE;
> +	}
>  
>  	spin_lock(&lip->li_ailp->ail_lock);

Um, didn't we just establish that lip could have been freed?  Why is it
safe to continue accessing the AIL through the lip here?

--D

>  out_unlock:
> -- 
> 2.39.2
> 
> 




[Index of Archives]     [XFS Filesystem Development (older mail)]     [Linux Filesystem Development]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux RAID]     [Linux SCSI]


  Powered by Linux