From: Carlos Maiolino Date: Thu, 13 Nov 2025 13:57:11 +0000 (+0100) Subject: metadump: catch used extent array overflow X-Git-Tag: v6.18.0~73 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=2a30566311e6e43f5e313c00493740fbb4098fc3;p=xfsprogs-dev.git metadump: catch used extent array overflow An user reported a SIGSEGV when attempting to create a metadump image of a filesystem. The reason is because we fail to catch a possible overflow in the used extents array in process_exinode() which may happen if the extent count is corrupted. This leads process_bmbt_reclist() to attempt to index into the array using the bogus extent count with: convert_extent(&rp[numrecs - 1], &o, &s, &c, &f); Fix this by extending the used counter to uint64_t and checking for the overflow possibility. Reported-by: hubert . Suggested-by: Dave Chinner Signed-off-by: Carlos Maiolino Reviewed-by: Christoph Hellwig --- diff --git a/db/metadump.c b/db/metadump.c index 24eb99da..39639a0d 100644 --- a/db/metadump.c +++ b/db/metadump.c @@ -2395,21 +2395,24 @@ process_btinode( static int process_exinode( - struct xfs_dinode *dip, + struct xfs_dinode *dip, int whichfork) { xfs_extnum_t max_nex = xfs_iext_max_nextents( xfs_dinode_has_large_extent_counts(dip), whichfork); xfs_extnum_t nex = xfs_dfork_nextents(dip, whichfork); - int used = nex * sizeof(struct xfs_bmbt_rec); + uint64_t used; - if (nex > max_nex || used > XFS_DFORK_SIZE(dip, mp, whichfork)) { - if (metadump.show_warnings) - print_warning("bad number of extents %llu in inode %lld", - (unsigned long long)nex, - (long long)metadump.cur_ino); - return 1; - } + if (check_mul_overflow(nex, sizeof(struct xfs_bmbt_rec), &used)) + goto out_warn; + + /* Invalid number of extents */ + if (nex > max_nex) + goto out_warn; + + /* Extent array should fit into the inode fork */ + if (used > XFS_DFORK_SIZE(dip, mp, whichfork)) + goto out_warn; /* Zero unused data fork past used extents */ if (metadump.zero_stale_data && @@ -2421,6 +2424,12 @@ process_exinode( return process_bmbt_reclist(dip, whichfork, (struct xfs_bmbt_rec *)XFS_DFORK_PTR(dip, whichfork), nex); + +out_warn: + if (metadump.show_warnings) + print_warning("bad number of extents %llu in inode %lld", + (unsigned long long)nex, (long long)metadump.cur_ino); + return 1; } static int