diff options
| author | Dave Chinner <dchinner@redhat.com> | 2011-04-08 12:45:07 +1000 | 
|---|---|---|
| committer | Dave Chinner <david@fromorbit.com> | 2011-04-08 12:45:07 +1000 | 
| commit | be65b18a10e62321c5ba09a1dc0f70babeb0eba1 (patch) | |
| tree | 512dba387c91b778c4e2b9fafa42bfef7f074bb7 /fs/xfs | |
| parent | fd074841cfe01b006465fb9388091012585e8dfb (diff) | |
| download | olio-linux-3.10-be65b18a10e62321c5ba09a1dc0f70babeb0eba1.tar.xz olio-linux-3.10-be65b18a10e62321c5ba09a1dc0f70babeb0eba1.zip  | |
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: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Alex Elder <aelder@sgi.com>
Diffstat (limited to 'fs/xfs')
| -rw-r--r-- | fs/xfs/xfs_alloc.c | 30 | 
1 files changed, 23 insertions, 7 deletions
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index 4bc3c649aee..27d64d752ea 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c @@ -2395,17 +2395,33 @@ xfs_free_extent(  	memset(&args, 0, sizeof(xfs_alloc_arg_t));  	args.tp = tp;  	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); -	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); +	if (args.agbno >= args.mp->m_sb.sb_agblocks) +		return EFSCORRUPTED; +  	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; -#ifdef DEBUG -	ASSERT(args.agbp != NULL); -	ASSERT((args.agbno + len) <= -		be32_to_cpu(XFS_BUF_TO_AGF(args.agbp)->agf_length)); -#endif + +	/* validate the extent size is legal now we have the agf locked */ +	if (args.agbno + len > +			be32_to_cpu(XFS_BUF_TO_AGF(args.agbp)->agf_length)) { +		error = EFSCORRUPTED; +		goto error0; +	} +  	error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0);  error0:  	xfs_perag_put(args.pag);  |