Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
86810a9e
Commit
86810a9e
authored
May 04, 2022
by
Dave Chinner
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'guilt/xfs-5.19-fuzz-fixes' into xfs-5.19-for-next
parents
166afc45
f0f5f658
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
191 additions
and
54 deletions
+191
-54
fs/xfs/libxfs/xfs_btree.c
fs/xfs/libxfs/xfs_btree.c
+105
-35
fs/xfs/libxfs/xfs_inode_buf.c
fs/xfs/libxfs/xfs_inode_buf.c
+26
-9
fs/xfs/libxfs/xfs_sb.c
fs/xfs/libxfs/xfs_sb.c
+60
-10
No files found.
fs/xfs/libxfs/xfs_btree.c
View file @
86810a9e
...
@@ -51,6 +51,52 @@ xfs_btree_magic(
...
@@ -51,6 +51,52 @@ xfs_btree_magic(
return
magic
;
return
magic
;
}
}
static
xfs_failaddr_t
xfs_btree_check_lblock_siblings
(
struct
xfs_mount
*
mp
,
struct
xfs_btree_cur
*
cur
,
int
level
,
xfs_fsblock_t
fsb
,
xfs_fsblock_t
sibling
)
{
if
(
sibling
==
NULLFSBLOCK
)
return
NULL
;
if
(
sibling
==
fsb
)
return
__this_address
;
if
(
level
>=
0
)
{
if
(
!
xfs_btree_check_lptr
(
cur
,
sibling
,
level
+
1
))
return
__this_address
;
}
else
{
if
(
!
xfs_verify_fsbno
(
mp
,
sibling
))
return
__this_address
;
}
return
NULL
;
}
static
xfs_failaddr_t
xfs_btree_check_sblock_siblings
(
struct
xfs_mount
*
mp
,
struct
xfs_btree_cur
*
cur
,
int
level
,
xfs_agnumber_t
agno
,
xfs_agblock_t
agbno
,
xfs_agblock_t
sibling
)
{
if
(
sibling
==
NULLAGBLOCK
)
return
NULL
;
if
(
sibling
==
agbno
)
return
__this_address
;
if
(
level
>=
0
)
{
if
(
!
xfs_btree_check_sptr
(
cur
,
sibling
,
level
+
1
))
return
__this_address
;
}
else
{
if
(
!
xfs_verify_agbno
(
mp
,
agno
,
sibling
))
return
__this_address
;
}
return
NULL
;
}
/*
/*
* Check a long btree block header. Return the address of the failing check,
* Check a long btree block header. Return the address of the failing check,
* or NULL if everything is ok.
* or NULL if everything is ok.
...
@@ -65,6 +111,8 @@ __xfs_btree_check_lblock(
...
@@ -65,6 +111,8 @@ __xfs_btree_check_lblock(
struct
xfs_mount
*
mp
=
cur
->
bc_mp
;
struct
xfs_mount
*
mp
=
cur
->
bc_mp
;
xfs_btnum_t
btnum
=
cur
->
bc_btnum
;
xfs_btnum_t
btnum
=
cur
->
bc_btnum
;
int
crc
=
xfs_has_crc
(
mp
);
int
crc
=
xfs_has_crc
(
mp
);
xfs_failaddr_t
fa
;
xfs_fsblock_t
fsb
=
NULLFSBLOCK
;
if
(
crc
)
{
if
(
crc
)
{
if
(
!
uuid_equal
(
&
block
->
bb_u
.
l
.
bb_uuid
,
&
mp
->
m_sb
.
sb_meta_uuid
))
if
(
!
uuid_equal
(
&
block
->
bb_u
.
l
.
bb_uuid
,
&
mp
->
m_sb
.
sb_meta_uuid
))
...
@@ -83,16 +131,16 @@ __xfs_btree_check_lblock(
...
@@ -83,16 +131,16 @@ __xfs_btree_check_lblock(
if
(
be16_to_cpu
(
block
->
bb_numrecs
)
>
if
(
be16_to_cpu
(
block
->
bb_numrecs
)
>
cur
->
bc_ops
->
get_maxrecs
(
cur
,
level
))
cur
->
bc_ops
->
get_maxrecs
(
cur
,
level
))
return
__this_address
;
return
__this_address
;
if
(
block
->
bb_u
.
l
.
bb_leftsib
!=
cpu_to_be64
(
NULLFSBLOCK
)
&&
!
xfs_btree_check_lptr
(
cur
,
be64_to_cpu
(
block
->
bb_u
.
l
.
bb_leftsib
),
level
+
1
))
return
__this_address
;
if
(
block
->
bb_u
.
l
.
bb_rightsib
!=
cpu_to_be64
(
NULLFSBLOCK
)
&&
!
xfs_btree_check_lptr
(
cur
,
be64_to_cpu
(
block
->
bb_u
.
l
.
bb_rightsib
),
level
+
1
))
return
__this_address
;
return
NULL
;
if
(
bp
)
fsb
=
XFS_DADDR_TO_FSB
(
mp
,
xfs_buf_daddr
(
bp
));
fa
=
xfs_btree_check_lblock_siblings
(
mp
,
cur
,
level
,
fsb
,
be64_to_cpu
(
block
->
bb_u
.
l
.
bb_leftsib
));
if
(
!
fa
)
fa
=
xfs_btree_check_lblock_siblings
(
mp
,
cur
,
level
,
fsb
,
be64_to_cpu
(
block
->
bb_u
.
l
.
bb_rightsib
));
return
fa
;
}
}
/* Check a long btree block header. */
/* Check a long btree block header. */
...
@@ -130,6 +178,9 @@ __xfs_btree_check_sblock(
...
@@ -130,6 +178,9 @@ __xfs_btree_check_sblock(
struct
xfs_mount
*
mp
=
cur
->
bc_mp
;
struct
xfs_mount
*
mp
=
cur
->
bc_mp
;
xfs_btnum_t
btnum
=
cur
->
bc_btnum
;
xfs_btnum_t
btnum
=
cur
->
bc_btnum
;
int
crc
=
xfs_has_crc
(
mp
);
int
crc
=
xfs_has_crc
(
mp
);
xfs_failaddr_t
fa
;
xfs_agblock_t
agbno
=
NULLAGBLOCK
;
xfs_agnumber_t
agno
=
NULLAGNUMBER
;
if
(
crc
)
{
if
(
crc
)
{
if
(
!
uuid_equal
(
&
block
->
bb_u
.
s
.
bb_uuid
,
&
mp
->
m_sb
.
sb_meta_uuid
))
if
(
!
uuid_equal
(
&
block
->
bb_u
.
s
.
bb_uuid
,
&
mp
->
m_sb
.
sb_meta_uuid
))
...
@@ -146,16 +197,18 @@ __xfs_btree_check_sblock(
...
@@ -146,16 +197,18 @@ __xfs_btree_check_sblock(
if
(
be16_to_cpu
(
block
->
bb_numrecs
)
>
if
(
be16_to_cpu
(
block
->
bb_numrecs
)
>
cur
->
bc_ops
->
get_maxrecs
(
cur
,
level
))
cur
->
bc_ops
->
get_maxrecs
(
cur
,
level
))
return
__this_address
;
return
__this_address
;
if
(
block
->
bb_u
.
s
.
bb_leftsib
!=
cpu_to_be32
(
NULLAGBLOCK
)
&&
!
xfs_btree_check_sptr
(
cur
,
be32_to_cpu
(
block
->
bb_u
.
s
.
bb_leftsib
),
level
+
1
))
return
__this_address
;
if
(
block
->
bb_u
.
s
.
bb_rightsib
!=
cpu_to_be32
(
NULLAGBLOCK
)
&&
!
xfs_btree_check_sptr
(
cur
,
be32_to_cpu
(
block
->
bb_u
.
s
.
bb_rightsib
),
level
+
1
))
return
__this_address
;
return
NULL
;
if
(
bp
)
{
agbno
=
xfs_daddr_to_agbno
(
mp
,
xfs_buf_daddr
(
bp
));
agno
=
xfs_daddr_to_agno
(
mp
,
xfs_buf_daddr
(
bp
));
}
fa
=
xfs_btree_check_sblock_siblings
(
mp
,
cur
,
level
,
agno
,
agbno
,
be32_to_cpu
(
block
->
bb_u
.
s
.
bb_leftsib
));
if
(
!
fa
)
fa
=
xfs_btree_check_sblock_siblings
(
mp
,
cur
,
level
,
agno
,
agbno
,
be32_to_cpu
(
block
->
bb_u
.
s
.
bb_rightsib
));
return
fa
;
}
}
/* Check a short btree block header. */
/* Check a short btree block header. */
...
@@ -4271,6 +4324,21 @@ xfs_btree_visit_block(
...
@@ -4271,6 +4324,21 @@ xfs_btree_visit_block(
if
(
xfs_btree_ptr_is_null
(
cur
,
&
rptr
))
if
(
xfs_btree_ptr_is_null
(
cur
,
&
rptr
))
return
-
ENOENT
;
return
-
ENOENT
;
/*
* We only visit blocks once in this walk, so we have to avoid the
* internal xfs_btree_lookup_get_block() optimisation where it will
* return the same block without checking if the right sibling points
* back to us and creates a cyclic reference in the btree.
*/
if
(
cur
->
bc_flags
&
XFS_BTREE_LONG_PTRS
)
{
if
(
be64_to_cpu
(
rptr
.
l
)
==
XFS_DADDR_TO_FSB
(
cur
->
bc_mp
,
xfs_buf_daddr
(
bp
)))
return
-
EFSCORRUPTED
;
}
else
{
if
(
be32_to_cpu
(
rptr
.
s
)
==
xfs_daddr_to_agbno
(
cur
->
bc_mp
,
xfs_buf_daddr
(
bp
)))
return
-
EFSCORRUPTED
;
}
return
xfs_btree_lookup_get_block
(
cur
,
level
,
&
rptr
,
&
block
);
return
xfs_btree_lookup_get_block
(
cur
,
level
,
&
rptr
,
&
block
);
}
}
...
@@ -4445,20 +4513,21 @@ xfs_btree_lblock_verify(
...
@@ -4445,20 +4513,21 @@ xfs_btree_lblock_verify(
{
{
struct
xfs_mount
*
mp
=
bp
->
b_mount
;
struct
xfs_mount
*
mp
=
bp
->
b_mount
;
struct
xfs_btree_block
*
block
=
XFS_BUF_TO_BLOCK
(
bp
);
struct
xfs_btree_block
*
block
=
XFS_BUF_TO_BLOCK
(
bp
);
xfs_fsblock_t
fsb
;
xfs_failaddr_t
fa
;
/* numrecs verification */
/* numrecs verification */
if
(
be16_to_cpu
(
block
->
bb_numrecs
)
>
max_recs
)
if
(
be16_to_cpu
(
block
->
bb_numrecs
)
>
max_recs
)
return
__this_address
;
return
__this_address
;
/* sibling pointer verification */
/* sibling pointer verification */
if
(
block
->
bb_u
.
l
.
bb_leftsib
!=
cpu_to_be64
(
NULLFSBLOCK
)
&&
fsb
=
XFS_DADDR_TO_FSB
(
mp
,
xfs_buf_daddr
(
bp
));
!
xfs_verify_fsbno
(
mp
,
be64_to_cpu
(
block
->
bb_u
.
l
.
bb_leftsib
)))
fa
=
xfs_btree_check_lblock_siblings
(
mp
,
NULL
,
-
1
,
fsb
,
return
__this_address
;
be64_to_cpu
(
block
->
bb_u
.
l
.
bb_leftsib
));
if
(
block
->
bb_u
.
l
.
bb_rightsib
!=
cpu_to_be64
(
NULLFSBLOCK
)
&&
if
(
!
fa
)
!
xfs_verify_fsbno
(
mp
,
be64_to_cpu
(
block
->
bb_u
.
l
.
bb_rightsib
)))
fa
=
xfs_btree_check_lblock_siblings
(
mp
,
NULL
,
-
1
,
fsb
,
return
__this_address
;
be64_to_cpu
(
block
->
bb_u
.
l
.
bb_rightsib
));
return
fa
;
return
NULL
;
}
}
/**
/**
...
@@ -4499,7 +4568,9 @@ xfs_btree_sblock_verify(
...
@@ -4499,7 +4568,9 @@ xfs_btree_sblock_verify(
{
{
struct
xfs_mount
*
mp
=
bp
->
b_mount
;
struct
xfs_mount
*
mp
=
bp
->
b_mount
;
struct
xfs_btree_block
*
block
=
XFS_BUF_TO_BLOCK
(
bp
);
struct
xfs_btree_block
*
block
=
XFS_BUF_TO_BLOCK
(
bp
);
xfs_agblock_t
agno
;
xfs_agnumber_t
agno
;
xfs_agblock_t
agbno
;
xfs_failaddr_t
fa
;
/* numrecs verification */
/* numrecs verification */
if
(
be16_to_cpu
(
block
->
bb_numrecs
)
>
max_recs
)
if
(
be16_to_cpu
(
block
->
bb_numrecs
)
>
max_recs
)
...
@@ -4507,14 +4578,13 @@ xfs_btree_sblock_verify(
...
@@ -4507,14 +4578,13 @@ xfs_btree_sblock_verify(
/* sibling pointer verification */
/* sibling pointer verification */
agno
=
xfs_daddr_to_agno
(
mp
,
xfs_buf_daddr
(
bp
));
agno
=
xfs_daddr_to_agno
(
mp
,
xfs_buf_daddr
(
bp
));
if
(
block
->
bb_u
.
s
.
bb_leftsib
!=
cpu_to_be32
(
NULLAGBLOCK
)
&&
agbno
=
xfs_daddr_to_agbno
(
mp
,
xfs_buf_daddr
(
bp
));
!
xfs_verify_agbno
(
mp
,
agno
,
be32_to_cpu
(
block
->
bb_u
.
s
.
bb_leftsib
)))
fa
=
xfs_btree_check_sblock_siblings
(
mp
,
NULL
,
-
1
,
agno
,
agbno
,
return
__this_address
;
be32_to_cpu
(
block
->
bb_u
.
s
.
bb_leftsib
));
if
(
block
->
bb_u
.
s
.
bb_rightsib
!=
cpu_to_be32
(
NULLAGBLOCK
)
&&
if
(
!
fa
)
!
xfs_verify_agbno
(
mp
,
agno
,
be32_to_cpu
(
block
->
bb_u
.
s
.
bb_rightsib
)))
fa
=
xfs_btree_check_sblock_siblings
(
mp
,
NULL
,
-
1
,
agno
,
agbno
,
return
__this_address
;
be32_to_cpu
(
block
->
bb_u
.
s
.
bb_rightsib
));
return
fa
;
return
NULL
;
}
}
/*
/*
...
...
fs/xfs/libxfs/xfs_inode_buf.c
View file @
86810a9e
...
@@ -357,21 +357,38 @@ xfs_dinode_verify_fork(
...
@@ -357,21 +357,38 @@ xfs_dinode_verify_fork(
{
{
xfs_extnum_t
di_nextents
;
xfs_extnum_t
di_nextents
;
xfs_extnum_t
max_extents
;
xfs_extnum_t
max_extents
;
mode_t
mode
=
be16_to_cpu
(
dip
->
di_mode
);
uint32_t
fork_size
=
XFS_DFORK_SIZE
(
dip
,
mp
,
whichfork
);
uint32_t
fork_format
=
XFS_DFORK_FORMAT
(
dip
,
whichfork
);
di_nextents
=
xfs_dfork_nextents
(
dip
,
whichfork
);
di_nextents
=
xfs_dfork_nextents
(
dip
,
whichfork
);
switch
(
XFS_DFORK_FORMAT
(
dip
,
whichfork
))
{
/*
* For fork types that can contain local data, check that the fork
* format matches the size of local data contained within the fork.
*
* For all types, check that when the size says the should be in extent
* or btree format, the inode isn't claiming it is in local format.
*/
if
(
whichfork
==
XFS_DATA_FORK
)
{
if
(
S_ISDIR
(
mode
)
||
S_ISLNK
(
mode
))
{
if
(
be64_to_cpu
(
dip
->
di_size
)
<=
fork_size
&&
fork_format
!=
XFS_DINODE_FMT_LOCAL
)
return
__this_address
;
}
if
(
be64_to_cpu
(
dip
->
di_size
)
>
fork_size
&&
fork_format
==
XFS_DINODE_FMT_LOCAL
)
return
__this_address
;
}
switch
(
fork_format
)
{
case
XFS_DINODE_FMT_LOCAL
:
case
XFS_DINODE_FMT_LOCAL
:
/*
/*
*
no local regular files yet
*
No local regular files yet.
*/
*/
if
(
whichfork
==
XFS_DATA_FORK
)
{
if
(
S_ISREG
(
mode
)
&&
whichfork
==
XFS_DATA_FORK
)
if
(
S_ISREG
(
be16_to_cpu
(
dip
->
di_mode
)))
return
__this_address
;
return
__this_address
;
if
(
be64_to_cpu
(
dip
->
di_size
)
>
XFS_DFORK_SIZE
(
dip
,
mp
,
whichfork
))
return
__this_address
;
}
if
(
di_nextents
)
if
(
di_nextents
)
return
__this_address
;
return
__this_address
;
break
;
break
;
...
...
fs/xfs/libxfs/xfs_sb.c
View file @
86810a9e
...
@@ -30,6 +30,47 @@
...
@@ -30,6 +30,47 @@
* Physical superblock buffer manipulations. Shared with libxfs in userspace.
* Physical superblock buffer manipulations. Shared with libxfs in userspace.
*/
*/
/*
* Check that all the V4 feature bits that the V5 filesystem format requires are
* correctly set.
*/
static
bool
xfs_sb_validate_v5_features
(
struct
xfs_sb
*
sbp
)
{
/* We must not have any unknown V4 feature bits set */
if
(
sbp
->
sb_versionnum
&
~
XFS_SB_VERSION_OKBITS
)
return
false
;
/*
* The CRC bit is considered an invalid V4 flag, so we have to add it
* manually to the OKBITS mask.
*/
if
(
sbp
->
sb_features2
&
~
(
XFS_SB_VERSION2_OKBITS
|
XFS_SB_VERSION2_CRCBIT
))
return
false
;
/* Now check all the required V4 feature flags are set. */
#define V5_VERS_FLAGS (XFS_SB_VERSION_NLINKBIT | \
XFS_SB_VERSION_ALIGNBIT | \
XFS_SB_VERSION_LOGV2BIT | \
XFS_SB_VERSION_EXTFLGBIT | \
XFS_SB_VERSION_DIRV2BIT | \
XFS_SB_VERSION_MOREBITSBIT)
#define V5_FEAT_FLAGS (XFS_SB_VERSION2_LAZYSBCOUNTBIT | \
XFS_SB_VERSION2_ATTR2BIT | \
XFS_SB_VERSION2_PROJID32BIT | \
XFS_SB_VERSION2_CRCBIT)
if
((
sbp
->
sb_versionnum
&
V5_VERS_FLAGS
)
!=
V5_VERS_FLAGS
)
return
false
;
if
((
sbp
->
sb_features2
&
V5_FEAT_FLAGS
)
!=
V5_FEAT_FLAGS
)
return
false
;
return
true
;
}
/*
/*
* We support all XFS versions newer than a v4 superblock with V2 directories.
* We support all XFS versions newer than a v4 superblock with V2 directories.
*/
*/
...
@@ -37,9 +78,19 @@ bool
...
@@ -37,9 +78,19 @@ bool
xfs_sb_good_version
(
xfs_sb_good_version
(
struct
xfs_sb
*
sbp
)
struct
xfs_sb
*
sbp
)
{
{
/* all v5 filesystems are supported */
/*
* All v5 filesystems are supported, but we must check that all the
* required v4 feature flags are enabled correctly as the code checks
* those flags and not for v5 support.
*/
if
(
xfs_sb_is_v5
(
sbp
))
if
(
xfs_sb_is_v5
(
sbp
))
return
true
;
return
xfs_sb_validate_v5_features
(
sbp
);
/* We must not have any unknown v4 feature bits set */
if
((
sbp
->
sb_versionnum
&
~
XFS_SB_VERSION_OKBITS
)
||
((
sbp
->
sb_versionnum
&
XFS_SB_VERSION_MOREBITSBIT
)
&&
(
sbp
->
sb_features2
&
~
XFS_SB_VERSION2_OKBITS
)))
return
false
;
/* versions prior to v4 are not supported */
/* versions prior to v4 are not supported */
if
(
XFS_SB_VERSION_NUM
(
sbp
)
<
XFS_SB_VERSION_4
)
if
(
XFS_SB_VERSION_NUM
(
sbp
)
<
XFS_SB_VERSION_4
)
...
@@ -51,12 +102,6 @@ xfs_sb_good_version(
...
@@ -51,12 +102,6 @@ xfs_sb_good_version(
if
(
!
(
sbp
->
sb_versionnum
&
XFS_SB_VERSION_EXTFLGBIT
))
if
(
!
(
sbp
->
sb_versionnum
&
XFS_SB_VERSION_EXTFLGBIT
))
return
false
;
return
false
;
/* And must not have any unknown v4 feature bits set */
if
((
sbp
->
sb_versionnum
&
~
XFS_SB_VERSION_OKBITS
)
||
((
sbp
->
sb_versionnum
&
XFS_SB_VERSION_MOREBITSBIT
)
&&
(
sbp
->
sb_features2
&
~
XFS_SB_VERSION2_OKBITS
)))
return
false
;
/* It's a supported v4 filesystem */
/* It's a supported v4 filesystem */
return
true
;
return
true
;
}
}
...
@@ -70,6 +115,8 @@ xfs_sb_version_to_features(
...
@@ -70,6 +115,8 @@ xfs_sb_version_to_features(
/* optional V4 features */
/* optional V4 features */
if
(
sbp
->
sb_rblocks
>
0
)
if
(
sbp
->
sb_rblocks
>
0
)
features
|=
XFS_FEAT_REALTIME
;
features
|=
XFS_FEAT_REALTIME
;
if
(
sbp
->
sb_versionnum
&
XFS_SB_VERSION_NLINKBIT
)
features
|=
XFS_FEAT_NLINK
;
if
(
sbp
->
sb_versionnum
&
XFS_SB_VERSION_ATTRBIT
)
if
(
sbp
->
sb_versionnum
&
XFS_SB_VERSION_ATTRBIT
)
features
|=
XFS_FEAT_ATTR
;
features
|=
XFS_FEAT_ATTR
;
if
(
sbp
->
sb_versionnum
&
XFS_SB_VERSION_QUOTABIT
)
if
(
sbp
->
sb_versionnum
&
XFS_SB_VERSION_QUOTABIT
)
...
@@ -265,12 +312,15 @@ xfs_validate_sb_common(
...
@@ -265,12 +312,15 @@ xfs_validate_sb_common(
bool
has_dalign
;
bool
has_dalign
;
if
(
!
xfs_verify_magic
(
bp
,
dsb
->
sb_magicnum
))
{
if
(
!
xfs_verify_magic
(
bp
,
dsb
->
sb_magicnum
))
{
xfs_warn
(
mp
,
"bad magic number"
);
xfs_warn
(
mp
,
"Superblock has bad magic number 0x%x. Not an XFS filesystem?"
,
be32_to_cpu
(
dsb
->
sb_magicnum
));
return
-
EWRONGFS
;
return
-
EWRONGFS
;
}
}
if
(
!
xfs_sb_good_version
(
sbp
))
{
if
(
!
xfs_sb_good_version
(
sbp
))
{
xfs_warn
(
mp
,
"bad version"
);
xfs_warn
(
mp
,
"Superblock has unknown features enabled or corrupted feature masks."
);
return
-
EWRONGFS
;
return
-
EWRONGFS
;
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment