Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xfs: distinguish between inobt and finobt magic values

The inode btree verifier code is shared between the inode btree and
free inode btree because the underlying metadata formats are
essentially equivalent. A side effect of this is that the verifier
cannot determine whether a particular btree block should have an
inobt or finobt magic value.

This logic allows an unfortunate xfs_repair bug to escape detection
where certain level > 0 nodes of the finobt are stamped with inobt
magic by xfs_repair finobt reconstruction. This is fortunately not a
severe problem since the inode btree magic values do not contribute
to any changes in kernel behavior, but we do need a means to detect
and prevent this problem in the future.

Add a field to xfs_buf_ops to store the v4 and v5 superblock magic
values expected by a particular verifier. Add a helper to check an
on-disk magic value against the value expected by the verifier. Call
the helper from the shared [f]inobt verifier code for magic value
verification. This ensures that the inode btree blocks each have the
appropriate magic value based on specific tree type and superblock
version.

Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>

authored by

Brian Foster and committed by
Darrick J. Wong
8473fee3 01e68f40

+28 -9
+7 -9
fs/xfs/libxfs/xfs_ialloc_btree.c
··· 260 260 xfs_failaddr_t fa; 261 261 unsigned int level; 262 262 263 + if (!xfs_verify_magic(bp, block->bb_magic)) 264 + return __this_address; 265 + 263 266 /* 264 267 * During growfs operations, we can't verify the exact owner as the 265 268 * perag is not fully initialised and hence not attached to the buffer. ··· 273 270 * but beware of the landmine (i.e. need to check pag->pagi_init) if we 274 271 * ever do. 275 272 */ 276 - switch (block->bb_magic) { 277 - case cpu_to_be32(XFS_IBT_CRC_MAGIC): 278 - case cpu_to_be32(XFS_FIBT_CRC_MAGIC): 273 + if (xfs_sb_version_hascrc(&mp->m_sb)) { 279 274 fa = xfs_btree_sblock_v5hdr_verify(bp); 280 275 if (fa) 281 276 return fa; 282 - /* fall through */ 283 - case cpu_to_be32(XFS_IBT_MAGIC): 284 - case cpu_to_be32(XFS_FIBT_MAGIC): 285 - break; 286 - default: 287 - return __this_address; 288 277 } 289 278 290 279 /* level verification */ ··· 323 328 324 329 const struct xfs_buf_ops xfs_inobt_buf_ops = { 325 330 .name = "xfs_inobt", 331 + .magic = { cpu_to_be32(XFS_IBT_MAGIC), cpu_to_be32(XFS_IBT_CRC_MAGIC) }, 326 332 .verify_read = xfs_inobt_read_verify, 327 333 .verify_write = xfs_inobt_write_verify, 328 334 .verify_struct = xfs_inobt_verify, ··· 331 335 332 336 const struct xfs_buf_ops xfs_finobt_buf_ops = { 333 337 .name = "xfs_finobt", 338 + .magic = { cpu_to_be32(XFS_FIBT_MAGIC), 339 + cpu_to_be32(XFS_FIBT_CRC_MAGIC) }, 334 340 .verify_read = xfs_inobt_read_verify, 335 341 .verify_write = xfs_inobt_write_verify, 336 342 .verify_struct = xfs_inobt_verify,
+19
fs/xfs/xfs_buf.c
··· 2204 2204 2205 2205 atomic_set(&bp->b_lru_ref, lru_ref); 2206 2206 } 2207 + 2208 + /* 2209 + * Verify an on-disk magic value against the magic value specified in the 2210 + * verifier structure. The verifier magic is in disk byte order so the caller is 2211 + * expected to pass the value directly from disk. 2212 + */ 2213 + bool 2214 + xfs_verify_magic( 2215 + struct xfs_buf *bp, 2216 + uint32_t dmagic) 2217 + { 2218 + struct xfs_mount *mp = bp->b_target->bt_mount; 2219 + int idx; 2220 + 2221 + idx = xfs_sb_version_hascrc(&mp->m_sb); 2222 + if (unlikely(WARN_ON(!bp->b_ops || !bp->b_ops->magic[idx]))) 2223 + return false; 2224 + return dmagic == bp->b_ops->magic[idx]; 2225 + }
+2
fs/xfs/xfs_buf.h
··· 125 125 126 126 struct xfs_buf_ops { 127 127 char *name; 128 + uint32_t magic[2]; /* v4 and v5 on disk magic values */ 128 129 void (*verify_read)(struct xfs_buf *); 129 130 void (*verify_write)(struct xfs_buf *); 130 131 xfs_failaddr_t (*verify_struct)(struct xfs_buf *bp); ··· 387 386 #define xfs_readonly_buftarg(buftarg) bdev_read_only((buftarg)->bt_bdev) 388 387 389 388 int xfs_buf_reverify(struct xfs_buf *bp, const struct xfs_buf_ops *ops); 389 + bool xfs_verify_magic(struct xfs_buf *bp, uint32_t dmagic); 390 390 391 391 #endif /* __XFS_BUF_H__ */