Skip to content

Commit 86810a9

Browse files
committed
Merge branch 'guilt/xfs-5.19-fuzz-fixes' into xfs-5.19-for-next
2 parents 166afc4 + f0f5f65 commit 86810a9

File tree

3 files changed

+191
-54
lines changed

3 files changed

+191
-54
lines changed

fs/xfs/libxfs/xfs_btree.c

Lines changed: 105 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,52 @@ xfs_btree_magic(
5151
return magic;
5252
}
5353

54+
static xfs_failaddr_t
55+
xfs_btree_check_lblock_siblings(
56+
struct xfs_mount *mp,
57+
struct xfs_btree_cur *cur,
58+
int level,
59+
xfs_fsblock_t fsb,
60+
xfs_fsblock_t sibling)
61+
{
62+
if (sibling == NULLFSBLOCK)
63+
return NULL;
64+
if (sibling == fsb)
65+
return __this_address;
66+
if (level >= 0) {
67+
if (!xfs_btree_check_lptr(cur, sibling, level + 1))
68+
return __this_address;
69+
} else {
70+
if (!xfs_verify_fsbno(mp, sibling))
71+
return __this_address;
72+
}
73+
74+
return NULL;
75+
}
76+
77+
static xfs_failaddr_t
78+
xfs_btree_check_sblock_siblings(
79+
struct xfs_mount *mp,
80+
struct xfs_btree_cur *cur,
81+
int level,
82+
xfs_agnumber_t agno,
83+
xfs_agblock_t agbno,
84+
xfs_agblock_t sibling)
85+
{
86+
if (sibling == NULLAGBLOCK)
87+
return NULL;
88+
if (sibling == agbno)
89+
return __this_address;
90+
if (level >= 0) {
91+
if (!xfs_btree_check_sptr(cur, sibling, level + 1))
92+
return __this_address;
93+
} else {
94+
if (!xfs_verify_agbno(mp, agno, sibling))
95+
return __this_address;
96+
}
97+
return NULL;
98+
}
99+
54100
/*
55101
* Check a long btree block header. Return the address of the failing check,
56102
* or NULL if everything is ok.
@@ -65,6 +111,8 @@ __xfs_btree_check_lblock(
65111
struct xfs_mount *mp = cur->bc_mp;
66112
xfs_btnum_t btnum = cur->bc_btnum;
67113
int crc = xfs_has_crc(mp);
114+
xfs_failaddr_t fa;
115+
xfs_fsblock_t fsb = NULLFSBLOCK;
68116

69117
if (crc) {
70118
if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid))
@@ -83,16 +131,16 @@ __xfs_btree_check_lblock(
83131
if (be16_to_cpu(block->bb_numrecs) >
84132
cur->bc_ops->get_maxrecs(cur, level))
85133
return __this_address;
86-
if (block->bb_u.l.bb_leftsib != cpu_to_be64(NULLFSBLOCK) &&
87-
!xfs_btree_check_lptr(cur, be64_to_cpu(block->bb_u.l.bb_leftsib),
88-
level + 1))
89-
return __this_address;
90-
if (block->bb_u.l.bb_rightsib != cpu_to_be64(NULLFSBLOCK) &&
91-
!xfs_btree_check_lptr(cur, be64_to_cpu(block->bb_u.l.bb_rightsib),
92-
level + 1))
93-
return __this_address;
94134

95-
return NULL;
135+
if (bp)
136+
fsb = XFS_DADDR_TO_FSB(mp, xfs_buf_daddr(bp));
137+
138+
fa = xfs_btree_check_lblock_siblings(mp, cur, level, fsb,
139+
be64_to_cpu(block->bb_u.l.bb_leftsib));
140+
if (!fa)
141+
fa = xfs_btree_check_lblock_siblings(mp, cur, level, fsb,
142+
be64_to_cpu(block->bb_u.l.bb_rightsib));
143+
return fa;
96144
}
97145

98146
/* Check a long btree block header. */
@@ -130,6 +178,9 @@ __xfs_btree_check_sblock(
130178
struct xfs_mount *mp = cur->bc_mp;
131179
xfs_btnum_t btnum = cur->bc_btnum;
132180
int crc = xfs_has_crc(mp);
181+
xfs_failaddr_t fa;
182+
xfs_agblock_t agbno = NULLAGBLOCK;
183+
xfs_agnumber_t agno = NULLAGNUMBER;
133184

134185
if (crc) {
135186
if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
@@ -146,16 +197,18 @@ __xfs_btree_check_sblock(
146197
if (be16_to_cpu(block->bb_numrecs) >
147198
cur->bc_ops->get_maxrecs(cur, level))
148199
return __this_address;
149-
if (block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK) &&
150-
!xfs_btree_check_sptr(cur, be32_to_cpu(block->bb_u.s.bb_leftsib),
151-
level + 1))
152-
return __this_address;
153-
if (block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK) &&
154-
!xfs_btree_check_sptr(cur, be32_to_cpu(block->bb_u.s.bb_rightsib),
155-
level + 1))
156-
return __this_address;
157200

158-
return NULL;
201+
if (bp) {
202+
agbno = xfs_daddr_to_agbno(mp, xfs_buf_daddr(bp));
203+
agno = xfs_daddr_to_agno(mp, xfs_buf_daddr(bp));
204+
}
205+
206+
fa = xfs_btree_check_sblock_siblings(mp, cur, level, agno, agbno,
207+
be32_to_cpu(block->bb_u.s.bb_leftsib));
208+
if (!fa)
209+
fa = xfs_btree_check_sblock_siblings(mp, cur, level, agno,
210+
agbno, be32_to_cpu(block->bb_u.s.bb_rightsib));
211+
return fa;
159212
}
160213

161214
/* Check a short btree block header. */
@@ -4271,6 +4324,21 @@ xfs_btree_visit_block(
42714324
if (xfs_btree_ptr_is_null(cur, &rptr))
42724325
return -ENOENT;
42734326

4327+
/*
4328+
* We only visit blocks once in this walk, so we have to avoid the
4329+
* internal xfs_btree_lookup_get_block() optimisation where it will
4330+
* return the same block without checking if the right sibling points
4331+
* back to us and creates a cyclic reference in the btree.
4332+
*/
4333+
if (cur->bc_flags & XFS_BTREE_LONG_PTRS) {
4334+
if (be64_to_cpu(rptr.l) == XFS_DADDR_TO_FSB(cur->bc_mp,
4335+
xfs_buf_daddr(bp)))
4336+
return -EFSCORRUPTED;
4337+
} else {
4338+
if (be32_to_cpu(rptr.s) == xfs_daddr_to_agbno(cur->bc_mp,
4339+
xfs_buf_daddr(bp)))
4340+
return -EFSCORRUPTED;
4341+
}
42744342
return xfs_btree_lookup_get_block(cur, level, &rptr, &block);
42754343
}
42764344

@@ -4445,20 +4513,21 @@ xfs_btree_lblock_verify(
44454513
{
44464514
struct xfs_mount *mp = bp->b_mount;
44474515
struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
4516+
xfs_fsblock_t fsb;
4517+
xfs_failaddr_t fa;
44484518

44494519
/* numrecs verification */
44504520
if (be16_to_cpu(block->bb_numrecs) > max_recs)
44514521
return __this_address;
44524522

44534523
/* sibling pointer verification */
4454-
if (block->bb_u.l.bb_leftsib != cpu_to_be64(NULLFSBLOCK) &&
4455-
!xfs_verify_fsbno(mp, be64_to_cpu(block->bb_u.l.bb_leftsib)))
4456-
return __this_address;
4457-
if (block->bb_u.l.bb_rightsib != cpu_to_be64(NULLFSBLOCK) &&
4458-
!xfs_verify_fsbno(mp, be64_to_cpu(block->bb_u.l.bb_rightsib)))
4459-
return __this_address;
4460-
4461-
return NULL;
4524+
fsb = XFS_DADDR_TO_FSB(mp, xfs_buf_daddr(bp));
4525+
fa = xfs_btree_check_lblock_siblings(mp, NULL, -1, fsb,
4526+
be64_to_cpu(block->bb_u.l.bb_leftsib));
4527+
if (!fa)
4528+
fa = xfs_btree_check_lblock_siblings(mp, NULL, -1, fsb,
4529+
be64_to_cpu(block->bb_u.l.bb_rightsib));
4530+
return fa;
44624531
}
44634532

44644533
/**
@@ -4499,22 +4568,23 @@ xfs_btree_sblock_verify(
44994568
{
45004569
struct xfs_mount *mp = bp->b_mount;
45014570
struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
4502-
xfs_agblock_t agno;
4571+
xfs_agnumber_t agno;
4572+
xfs_agblock_t agbno;
4573+
xfs_failaddr_t fa;
45034574

45044575
/* numrecs verification */
45054576
if (be16_to_cpu(block->bb_numrecs) > max_recs)
45064577
return __this_address;
45074578

45084579
/* sibling pointer verification */
45094580
agno = xfs_daddr_to_agno(mp, xfs_buf_daddr(bp));
4510-
if (block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK) &&
4511-
!xfs_verify_agbno(mp, agno, be32_to_cpu(block->bb_u.s.bb_leftsib)))
4512-
return __this_address;
4513-
if (block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK) &&
4514-
!xfs_verify_agbno(mp, agno, be32_to_cpu(block->bb_u.s.bb_rightsib)))
4515-
return __this_address;
4516-
4517-
return NULL;
4581+
agbno = xfs_daddr_to_agbno(mp, xfs_buf_daddr(bp));
4582+
fa = xfs_btree_check_sblock_siblings(mp, NULL, -1, agno, agbno,
4583+
be32_to_cpu(block->bb_u.s.bb_leftsib));
4584+
if (!fa)
4585+
fa = xfs_btree_check_sblock_siblings(mp, NULL, -1, agno, agbno,
4586+
be32_to_cpu(block->bb_u.s.bb_rightsib));
4587+
return fa;
45184588
}
45194589

45204590
/*

fs/xfs/libxfs/xfs_inode_buf.c

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -357,21 +357,38 @@ xfs_dinode_verify_fork(
357357
{
358358
xfs_extnum_t di_nextents;
359359
xfs_extnum_t max_extents;
360+
mode_t mode = be16_to_cpu(dip->di_mode);
361+
uint32_t fork_size = XFS_DFORK_SIZE(dip, mp, whichfork);
362+
uint32_t fork_format = XFS_DFORK_FORMAT(dip, whichfork);
360363

361364
di_nextents = xfs_dfork_nextents(dip, whichfork);
362365

363-
switch (XFS_DFORK_FORMAT(dip, whichfork)) {
366+
/*
367+
* For fork types that can contain local data, check that the fork
368+
* format matches the size of local data contained within the fork.
369+
*
370+
* For all types, check that when the size says the should be in extent
371+
* or btree format, the inode isn't claiming it is in local format.
372+
*/
373+
if (whichfork == XFS_DATA_FORK) {
374+
if (S_ISDIR(mode) || S_ISLNK(mode)) {
375+
if (be64_to_cpu(dip->di_size) <= fork_size &&
376+
fork_format != XFS_DINODE_FMT_LOCAL)
377+
return __this_address;
378+
}
379+
380+
if (be64_to_cpu(dip->di_size) > fork_size &&
381+
fork_format == XFS_DINODE_FMT_LOCAL)
382+
return __this_address;
383+
}
384+
385+
switch (fork_format) {
364386
case XFS_DINODE_FMT_LOCAL:
365387
/*
366-
* no local regular files yet
388+
* No local regular files yet.
367389
*/
368-
if (whichfork == XFS_DATA_FORK) {
369-
if (S_ISREG(be16_to_cpu(dip->di_mode)))
370-
return __this_address;
371-
if (be64_to_cpu(dip->di_size) >
372-
XFS_DFORK_SIZE(dip, mp, whichfork))
373-
return __this_address;
374-
}
390+
if (S_ISREG(mode) && whichfork == XFS_DATA_FORK)
391+
return __this_address;
375392
if (di_nextents)
376393
return __this_address;
377394
break;

fs/xfs/libxfs/xfs_sb.c

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,67 @@
3030
* Physical superblock buffer manipulations. Shared with libxfs in userspace.
3131
*/
3232

33+
/*
34+
* Check that all the V4 feature bits that the V5 filesystem format requires are
35+
* correctly set.
36+
*/
37+
static bool
38+
xfs_sb_validate_v5_features(
39+
struct xfs_sb *sbp)
40+
{
41+
/* We must not have any unknown V4 feature bits set */
42+
if (sbp->sb_versionnum & ~XFS_SB_VERSION_OKBITS)
43+
return false;
44+
45+
/*
46+
* The CRC bit is considered an invalid V4 flag, so we have to add it
47+
* manually to the OKBITS mask.
48+
*/
49+
if (sbp->sb_features2 & ~(XFS_SB_VERSION2_OKBITS |
50+
XFS_SB_VERSION2_CRCBIT))
51+
return false;
52+
53+
/* Now check all the required V4 feature flags are set. */
54+
55+
#define V5_VERS_FLAGS (XFS_SB_VERSION_NLINKBIT | \
56+
XFS_SB_VERSION_ALIGNBIT | \
57+
XFS_SB_VERSION_LOGV2BIT | \
58+
XFS_SB_VERSION_EXTFLGBIT | \
59+
XFS_SB_VERSION_DIRV2BIT | \
60+
XFS_SB_VERSION_MOREBITSBIT)
61+
62+
#define V5_FEAT_FLAGS (XFS_SB_VERSION2_LAZYSBCOUNTBIT | \
63+
XFS_SB_VERSION2_ATTR2BIT | \
64+
XFS_SB_VERSION2_PROJID32BIT | \
65+
XFS_SB_VERSION2_CRCBIT)
66+
67+
if ((sbp->sb_versionnum & V5_VERS_FLAGS) != V5_VERS_FLAGS)
68+
return false;
69+
if ((sbp->sb_features2 & V5_FEAT_FLAGS) != V5_FEAT_FLAGS)
70+
return false;
71+
return true;
72+
}
73+
3374
/*
3475
* We support all XFS versions newer than a v4 superblock with V2 directories.
3576
*/
3677
bool
3778
xfs_sb_good_version(
3879
struct xfs_sb *sbp)
3980
{
40-
/* all v5 filesystems are supported */
81+
/*
82+
* All v5 filesystems are supported, but we must check that all the
83+
* required v4 feature flags are enabled correctly as the code checks
84+
* those flags and not for v5 support.
85+
*/
4186
if (xfs_sb_is_v5(sbp))
42-
return true;
87+
return xfs_sb_validate_v5_features(sbp);
88+
89+
/* We must not have any unknown v4 feature bits set */
90+
if ((sbp->sb_versionnum & ~XFS_SB_VERSION_OKBITS) ||
91+
((sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) &&
92+
(sbp->sb_features2 & ~XFS_SB_VERSION2_OKBITS)))
93+
return false;
4394

4495
/* versions prior to v4 are not supported */
4596
if (XFS_SB_VERSION_NUM(sbp) < XFS_SB_VERSION_4)
@@ -51,12 +102,6 @@ xfs_sb_good_version(
51102
if (!(sbp->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT))
52103
return false;
53104

54-
/* And must not have any unknown v4 feature bits set */
55-
if ((sbp->sb_versionnum & ~XFS_SB_VERSION_OKBITS) ||
56-
((sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) &&
57-
(sbp->sb_features2 & ~XFS_SB_VERSION2_OKBITS)))
58-
return false;
59-
60105
/* It's a supported v4 filesystem */
61106
return true;
62107
}
@@ -70,6 +115,8 @@ xfs_sb_version_to_features(
70115
/* optional V4 features */
71116
if (sbp->sb_rblocks > 0)
72117
features |= XFS_FEAT_REALTIME;
118+
if (sbp->sb_versionnum & XFS_SB_VERSION_NLINKBIT)
119+
features |= XFS_FEAT_NLINK;
73120
if (sbp->sb_versionnum & XFS_SB_VERSION_ATTRBIT)
74121
features |= XFS_FEAT_ATTR;
75122
if (sbp->sb_versionnum & XFS_SB_VERSION_QUOTABIT)
@@ -265,12 +312,15 @@ xfs_validate_sb_common(
265312
bool has_dalign;
266313

267314
if (!xfs_verify_magic(bp, dsb->sb_magicnum)) {
268-
xfs_warn(mp, "bad magic number");
315+
xfs_warn(mp,
316+
"Superblock has bad magic number 0x%x. Not an XFS filesystem?",
317+
be32_to_cpu(dsb->sb_magicnum));
269318
return -EWRONGFS;
270319
}
271320

272321
if (!xfs_sb_good_version(sbp)) {
273-
xfs_warn(mp, "bad version");
322+
xfs_warn(mp,
323+
"Superblock has unknown features enabled or corrupted feature masks.");
274324
return -EWRONGFS;
275325
}
276326

0 commit comments

Comments
 (0)