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

xfs: make sure aglen never goes negative in xfs_refcount_adjust_extents

Prior to calling xfs_refcount_adjust_extents, we trimmed agbno/aglen
such that the end of the range would not be in the middle of a refcount
record. If this is no longer the case, something is seriously wrong
with the btree. Bail out with a corruption error.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Dave Chinner <dchinner@redhat.com>

+17 -3
+17 -3
fs/xfs/libxfs/xfs_refcount.c
··· 986 986 (*agbno) += tmp.rc_blockcount; 987 987 (*aglen) -= tmp.rc_blockcount; 988 988 989 + /* Stop if there's nothing left to modify */ 990 + if (*aglen == 0 || !xfs_refcount_still_have_space(cur)) 991 + break; 992 + 993 + /* Move the cursor to the start of ext. */ 989 994 error = xfs_refcount_lookup_ge(cur, *agbno, 990 995 &found_rec); 991 996 if (error) 992 997 goto out_error; 993 998 } 994 999 995 - /* Stop if there's nothing left to modify */ 996 - if (*aglen == 0 || !xfs_refcount_still_have_space(cur)) 997 - break; 1000 + /* 1001 + * A previous step trimmed agbno/aglen such that the end of the 1002 + * range would not be in the middle of the record. If this is 1003 + * no longer the case, something is seriously wrong with the 1004 + * btree. Make sure we never feed the synthesized record into 1005 + * the processing loop below. 1006 + */ 1007 + if (XFS_IS_CORRUPT(cur->bc_mp, ext.rc_blockcount == 0) || 1008 + XFS_IS_CORRUPT(cur->bc_mp, ext.rc_blockcount > *aglen)) { 1009 + error = -EFSCORRUPTED; 1010 + goto out_error; 1011 + } 998 1012 999 1013 /* 1000 1014 * Adjust the reference count and either update the tree