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: Eric Sesterhenn <snakebyte@gmx.de>
Signed-off-by: Dave Chinner <david@fromorbit.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>

authored by

Dave Chinner and committed by
Christoph Hellwig
a6cb767e 1aacc064

+30 -11
+30 -11
fs/xfs/xfs_log.c
··· 562 562 } 563 563 564 564 mp->m_log = xlog_alloc_log(mp, log_target, blk_offset, num_bblks); 565 - if (!mp->m_log) { 566 - cmn_err(CE_WARN, "XFS: Log allocation failed: No memory!"); 567 - error = ENOMEM; 565 + if (IS_ERR(mp->m_log)) { 566 + error = -PTR_ERR(mp->m_log); 568 567 goto out; 569 568 } 570 569 ··· 1179 1180 xfs_buf_t *bp; 1180 1181 int i; 1181 1182 int iclogsize; 1183 + int error = ENOMEM; 1182 1184 1183 1185 log = kmem_zalloc(sizeof(xlog_t), KM_MAYFAIL); 1184 - if (!log) 1185 - return NULL; 1186 + if (!log) { 1187 + xlog_warn("XFS: Log allocation failed: No memory!"); 1188 + goto out; 1189 + } 1186 1190 1187 1191 log->l_mp = mp; 1188 1192 log->l_targ = log_target; ··· 1203 1201 log->l_grant_reserve_cycle = 1; 1204 1202 log->l_grant_write_cycle = 1; 1205 1203 1204 + error = EFSCORRUPTED; 1206 1205 if (xfs_sb_version_hassector(&mp->m_sb)) { 1207 1206 log->l_sectbb_log = mp->m_sb.sb_logsectlog - BBSHIFT; 1208 - ASSERT(log->l_sectbb_log <= mp->m_sectbb_log); 1207 + if (log->l_sectbb_log < 0 || 1208 + log->l_sectbb_log > mp->m_sectbb_log) { 1209 + xlog_warn("XFS: Log sector size (0x%x) out of range.", 1210 + log->l_sectbb_log); 1211 + goto out_free_log; 1212 + } 1213 + 1209 1214 /* for larger sector sizes, must have v2 or external log */ 1210 - ASSERT(log->l_sectbb_log == 0 || 1211 - log->l_logBBstart == 0 || 1212 - xfs_sb_version_haslogv2(&mp->m_sb)); 1213 - ASSERT(mp->m_sb.sb_logsectlog >= BBSHIFT); 1215 + if (log->l_sectbb_log != 0 && 1216 + (log->l_logBBstart != 0 && 1217 + !xfs_sb_version_haslogv2(&mp->m_sb))) { 1218 + xlog_warn("XFS: log sector size (0x%x) invalid " 1219 + "for configuration.", log->l_sectbb_log); 1220 + goto out_free_log; 1221 + } 1222 + if (mp->m_sb.sb_logsectlog < BBSHIFT) { 1223 + xlog_warn("XFS: Log sector log (0x%x) too small.", 1224 + mp->m_sb.sb_logsectlog); 1225 + goto out_free_log; 1226 + } 1214 1227 } 1215 1228 log->l_sectbb_mask = (1 << log->l_sectbb_log) - 1; 1216 1229 1217 1230 xlog_get_iclog_buffer_size(mp, log); 1218 1231 1232 + error = ENOMEM; 1219 1233 bp = xfs_buf_get_empty(log->l_iclog_size, mp->m_logdev_targp); 1220 1234 if (!bp) 1221 1235 goto out_free_log; ··· 1331 1313 xfs_buf_free(log->l_xbuf); 1332 1314 out_free_log: 1333 1315 kmem_free(log); 1334 - return NULL; 1316 + out: 1317 + return ERR_PTR(-error); 1335 1318 } /* xlog_alloc_log */ 1336 1319 1337 1320