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