diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index e6ed9e09c027..f5f28755b2ff 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -2950,31 +2950,40 @@ xlog_valid_rec_header( xfs_daddr_t blkno, int bufsize) { + struct xfs_mount *mp = log->l_mp; + u32 h_version = be32_to_cpu(rhead->h_version); int hlen; - if (XFS_IS_CORRUPT(log->l_mp, + if (XFS_IS_CORRUPT(mp, rhead->h_magicno != cpu_to_be32(XLOG_HEADER_MAGIC_NUM))) return -EFSCORRUPTED; - if (XFS_IS_CORRUPT(log->l_mp, - (!rhead->h_version || - (be32_to_cpu(rhead->h_version) & - (~XLOG_VERSION_OKBITS))))) { - xfs_warn(log->l_mp, "%s: unrecognised log version (%d).", - __func__, be32_to_cpu(rhead->h_version)); + + if (XFS_IS_CORRUPT(mp, !h_version)) return -EFSCORRUPTED; - } + if (XFS_IS_CORRUPT(mp, (h_version & ~XLOG_VERSION_OKBITS))) + return -EFSCORRUPTED; + + /* + * the log version is known, but must match the superblock log + * version feature bits for the header to be considered valid + */ + if (xfs_has_logv2(mp)) { + if (XFS_IS_CORRUPT(mp, !(h_version & XLOG_VERSION_2))) + return -EFSCORRUPTED; + } else if (XFS_IS_CORRUPT(mp, !(h_version & XLOG_VERSION_1))) + return -EFSCORRUPTED; /* * LR body must have data (or it wouldn't have been written) * and h_len must not be greater than LR buffer size. */ hlen = be32_to_cpu(rhead->h_len); - if (XFS_IS_CORRUPT(log->l_mp, hlen <= 0 || hlen > bufsize)) + if (XFS_IS_CORRUPT(mp, hlen <= 0 || hlen > bufsize)) return -EFSCORRUPTED; - if (XFS_IS_CORRUPT(log->l_mp, - blkno > log->l_logBBsize || blkno > INT_MAX)) + if (XFS_IS_CORRUPT(mp, blkno > log->l_logBBsize || blkno > INT_MAX)) return -EFSCORRUPTED; + return 0; }