Commit 250a17e8 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'erofs-for-6.18-rc3-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs

Pull erofs fixes from Gao Xiang:
 "Just three small fixes to address fuzzed images in relatively new
  features, as reported by Robert.

   - Hardening against fuzzed encoded extents

   - Fix infinite loops due to crafted subpage compact indexes

   - Improve z_erofs_extent_lookback()"

* tag 'erofs-for-6.18-rc3-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs:
  erofs: consolidate z_erofs_extent_lookback()
  erofs: avoid infinite loops due to corrupted subpage compact indexes
  erofs: fix crafted invalid cases for encoded extents
parents 9ea74602 2a13fc41
Loading
Loading
Loading
Loading
+30 −29
Original line number Diff line number Diff line
@@ -55,10 +55,6 @@ static int z_erofs_load_full_lcluster(struct z_erofs_maprecorder *m,
	} else {
		m->partialref = !!(advise & Z_EROFS_LI_PARTIAL_REF);
		m->clusterofs = le16_to_cpu(di->di_clusterofs);
		if (m->clusterofs >= 1 << vi->z_lclusterbits) {
			DBG_BUGON(1);
			return -EFSCORRUPTED;
		}
		m->pblk = le32_to_cpu(di->di_u.blkaddr);
	}
	return 0;
@@ -240,21 +236,29 @@ static int z_erofs_load_compact_lcluster(struct z_erofs_maprecorder *m,
static int z_erofs_load_lcluster_from_disk(struct z_erofs_maprecorder *m,
					   unsigned int lcn, bool lookahead)
{
	struct erofs_inode *vi = EROFS_I(m->inode);
	int err;

	if (vi->datalayout == EROFS_INODE_COMPRESSED_COMPACT) {
		err = z_erofs_load_compact_lcluster(m, lcn, lookahead);
	} else {
		DBG_BUGON(vi->datalayout != EROFS_INODE_COMPRESSED_FULL);
		err = z_erofs_load_full_lcluster(m, lcn);
	}
	if (err)
		return err;

	if (m->type >= Z_EROFS_LCLUSTER_TYPE_MAX) {
		erofs_err(m->inode->i_sb, "unknown type %u @ lcn %u of nid %llu",
			  m->type, lcn, EROFS_I(m->inode)->nid);
		DBG_BUGON(1);
		return -EOPNOTSUPP;
	} else if (m->type != Z_EROFS_LCLUSTER_TYPE_NONHEAD &&
		   m->clusterofs >= (1 << vi->z_lclusterbits)) {
		DBG_BUGON(1);
		return -EFSCORRUPTED;
	}

	switch (EROFS_I(m->inode)->datalayout) {
	case EROFS_INODE_COMPRESSED_FULL:
		return z_erofs_load_full_lcluster(m, lcn);
	case EROFS_INODE_COMPRESSED_COMPACT:
		return z_erofs_load_compact_lcluster(m, lcn, lookahead);
	default:
		return -EINVAL;
	}
	return 0;
}

static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m,
@@ -268,21 +272,20 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m,
		unsigned long lcn = m->lcn - lookback_distance;
		int err;

		if (!lookback_distance)
			break;

		err = z_erofs_load_lcluster_from_disk(m, lcn, false);
		if (err)
			return err;

		if (m->type == Z_EROFS_LCLUSTER_TYPE_NONHEAD) {
			lookback_distance = m->delta[0];
			if (!lookback_distance)
				break;
			continue;
		} else {
		}
		m->headtype = m->type;
		m->map->m_la = (lcn << lclusterbits) | m->clusterofs;
		return 0;
	}
	}
	erofs_err(sb, "bogus lookback distance %u @ lcn %lu of nid %llu",
		  lookback_distance, m->lcn, vi->nid);
	DBG_BUGON(1);
@@ -431,13 +434,6 @@ static int z_erofs_map_blocks_fo(struct inode *inode,
			end = inode->i_size;
	} else {
		if (m.type != Z_EROFS_LCLUSTER_TYPE_NONHEAD) {
			/* m.lcn should be >= 1 if endoff < m.clusterofs */
			if (!m.lcn) {
				erofs_err(sb, "invalid logical cluster 0 at nid %llu",
					  vi->nid);
				err = -EFSCORRUPTED;
				goto unmap_out;
			}
			end = (m.lcn << lclusterbits) | m.clusterofs;
			map->m_flags |= EROFS_MAP_FULL_MAPPED;
			m.delta[0] = 1;
@@ -596,7 +592,7 @@ static int z_erofs_map_blocks_ext(struct inode *inode,
			vi->z_fragmentoff = map->m_plen;
			if (recsz > offsetof(struct z_erofs_extent, pstart_lo))
				vi->z_fragmentoff |= map->m_pa << 32;
		} else if (map->m_plen) {
		} else if (map->m_plen & Z_EROFS_EXTENT_PLEN_MASK) {
			map->m_flags |= EROFS_MAP_MAPPED |
				EROFS_MAP_FULL_MAPPED | EROFS_MAP_ENCODED;
			fmt = map->m_plen >> Z_EROFS_EXTENT_PLEN_FMT_BIT;
@@ -715,6 +711,7 @@ static int z_erofs_map_sanity_check(struct inode *inode,
				    struct erofs_map_blocks *map)
{
	struct erofs_sb_info *sbi = EROFS_I_SB(inode);
	u64 pend;

	if (!(map->m_flags & EROFS_MAP_ENCODED))
		return 0;
@@ -732,6 +729,10 @@ static int z_erofs_map_sanity_check(struct inode *inode,
	if (unlikely(map->m_plen > Z_EROFS_PCLUSTER_MAX_SIZE ||
		     map->m_llen > Z_EROFS_PCLUSTER_MAX_DSIZE))
		return -EOPNOTSUPP;
	/* Filesystems beyond 48-bit physical block addresses are invalid */
	if (unlikely(check_add_overflow(map->m_pa, map->m_plen, &pend) ||
		     (pend >> sbi->blkszbits) >= BIT_ULL(48)))
		return -EFSCORRUPTED;
	return 0;
}