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

Commit a6cb767e authored by Dave Chinner's avatar Dave Chinner Committed by Christoph Hellwig
Browse files

xfs: validate log feature fields correctly



If the large log sector size feature bit is set in the
superblock by accident (say disk corruption), the then
fields that are now considered valid are not checked on
production kernels. The checks are present as ASSERT
statements so cause a panic on a debug kernel.

Change this so that the fields are validity checked if
the feature bit is set and abort the log mount if the
fields do not contain valid values.

Reported-by: default avatarEric Sesterhenn <snakebyte@gmx.de>
Signed-off-by: default avatarDave Chinner <david@fromorbit.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 1aacc064
Loading
Loading
Loading
Loading
+30 −11
Original line number Original line Diff line number Diff line
@@ -562,9 +562,8 @@ xfs_log_mount(
	}
	}


	mp->m_log = xlog_alloc_log(mp, log_target, blk_offset, num_bblks);
	mp->m_log = xlog_alloc_log(mp, log_target, blk_offset, num_bblks);
	if (!mp->m_log) {
	if (IS_ERR(mp->m_log)) {
		cmn_err(CE_WARN, "XFS: Log allocation failed: No memory!");
		error = -PTR_ERR(mp->m_log);
		error = ENOMEM;
		goto out;
		goto out;
	}
	}


@@ -1180,10 +1179,13 @@ xlog_alloc_log(xfs_mount_t *mp,
	xfs_buf_t		*bp;
	xfs_buf_t		*bp;
	int			i;
	int			i;
	int			iclogsize;
	int			iclogsize;
	int			error = ENOMEM;


	log = kmem_zalloc(sizeof(xlog_t), KM_MAYFAIL);
	log = kmem_zalloc(sizeof(xlog_t), KM_MAYFAIL);
	if (!log)
	if (!log) {
		return NULL;
		xlog_warn("XFS: Log allocation failed: No memory!");
		goto out;
	}


	log->l_mp	   = mp;
	log->l_mp	   = mp;
	log->l_targ	   = log_target;
	log->l_targ	   = log_target;
@@ -1201,19 +1203,35 @@ xlog_alloc_log(xfs_mount_t *mp,
	log->l_grant_reserve_cycle = 1;
	log->l_grant_reserve_cycle = 1;
	log->l_grant_write_cycle = 1;
	log->l_grant_write_cycle = 1;


	error = EFSCORRUPTED;
	if (xfs_sb_version_hassector(&mp->m_sb)) {
	if (xfs_sb_version_hassector(&mp->m_sb)) {
		log->l_sectbb_log = mp->m_sb.sb_logsectlog - BBSHIFT;
		log->l_sectbb_log = mp->m_sb.sb_logsectlog - BBSHIFT;
		ASSERT(log->l_sectbb_log <= mp->m_sectbb_log);
		if (log->l_sectbb_log < 0 ||
		    log->l_sectbb_log > mp->m_sectbb_log) {
			xlog_warn("XFS: Log sector size (0x%x) out of range.",
						log->l_sectbb_log);
			goto out_free_log;
		}

		/* for larger sector sizes, must have v2 or external log */
		/* for larger sector sizes, must have v2 or external log */
		ASSERT(log->l_sectbb_log == 0 ||
		if (log->l_sectbb_log != 0 &&
			log->l_logBBstart == 0 ||
		    (log->l_logBBstart != 0 &&
			xfs_sb_version_haslogv2(&mp->m_sb));
		     !xfs_sb_version_haslogv2(&mp->m_sb))) {
		ASSERT(mp->m_sb.sb_logsectlog >= BBSHIFT);
			xlog_warn("XFS: log sector size (0x%x) invalid "
				  "for configuration.", log->l_sectbb_log);
			goto out_free_log;
		}
		if (mp->m_sb.sb_logsectlog < BBSHIFT) {
			xlog_warn("XFS: Log sector log (0x%x) too small.",
						mp->m_sb.sb_logsectlog);
			goto out_free_log;
		}
	}
	}
	log->l_sectbb_mask = (1 << log->l_sectbb_log) - 1;
	log->l_sectbb_mask = (1 << log->l_sectbb_log) - 1;


	xlog_get_iclog_buffer_size(mp, log);
	xlog_get_iclog_buffer_size(mp, log);


	error = ENOMEM;
	bp = xfs_buf_get_empty(log->l_iclog_size, mp->m_logdev_targp);
	bp = xfs_buf_get_empty(log->l_iclog_size, mp->m_logdev_targp);
	if (!bp)
	if (!bp)
		goto out_free_log;
		goto out_free_log;
@@ -1313,7 +1331,8 @@ xlog_alloc_log(xfs_mount_t *mp,
	xfs_buf_free(log->l_xbuf);
	xfs_buf_free(log->l_xbuf);
out_free_log:
out_free_log:
	kmem_free(log);
	kmem_free(log);
	return NULL;
out:
	return ERR_PTR(-error);
}	/* xlog_alloc_log */
}	/* xlog_alloc_log */