Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit be65b18a authored by Dave Chinner's avatar Dave Chinner Committed by Dave Chinner
Browse files

xfs: catch bad block numbers freeing extents.



A fuzzed filesystem crashed a kernel when freeing an extent with a
block number beyond the end of the filesystem. Convert all the debug
asserts in xfs_free_extent() to active checks so that we catch bad
extents and return that the filesytsem is corrupted rather than
crashing.

Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarAlex Elder <aelder@sgi.com>
parent fd074841
Loading
Loading
Loading
Loading
+23 −7
Original line number Original line Diff line number Diff line
@@ -2395,17 +2395,33 @@ xfs_free_extent(
	memset(&args, 0, sizeof(xfs_alloc_arg_t));
	memset(&args, 0, sizeof(xfs_alloc_arg_t));
	args.tp = tp;
	args.tp = tp;
	args.mp = tp->t_mountp;
	args.mp = tp->t_mountp;

	/*
	 * validate that the block number is legal - the enables us to detect
	 * and handle a silent filesystem corruption rather than crashing.
	 */
	args.agno = XFS_FSB_TO_AGNO(args.mp, bno);
	args.agno = XFS_FSB_TO_AGNO(args.mp, bno);
	ASSERT(args.agno < args.mp->m_sb.sb_agcount);
	if (args.agno >= args.mp->m_sb.sb_agcount)
		return EFSCORRUPTED;

	args.agbno = XFS_FSB_TO_AGBNO(args.mp, bno);
	args.agbno = XFS_FSB_TO_AGBNO(args.mp, bno);
	if (args.agbno >= args.mp->m_sb.sb_agblocks)
		return EFSCORRUPTED;

	args.pag = xfs_perag_get(args.mp, args.agno);
	args.pag = xfs_perag_get(args.mp, args.agno);
	if ((error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING)))
	ASSERT(args.pag);

	error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING);
	if (error)
		goto error0;
		goto error0;
#ifdef DEBUG

	ASSERT(args.agbp != NULL);
	/* validate the extent size is legal now we have the agf locked */
	ASSERT((args.agbno + len) <=
	if (args.agbno + len >
		be32_to_cpu(XFS_BUF_TO_AGF(args.agbp)->agf_length));
			be32_to_cpu(XFS_BUF_TO_AGF(args.agbp)->agf_length)) {
#endif
		error = EFSCORRUPTED;
		goto error0;
	}

	error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0);
	error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0);
error0:
error0:
	xfs_perag_put(args.pag);
	xfs_perag_put(args.pag);