xfs: harden directory integrity checks some more
PATCH 1/1 xfs: harden directory integrity checks some more
From: Darrick J. Wong <[email protected]>
If a malicious filesystem image contains a block+ format directory wherein the directory inode's core.mode is set such that S_ISDIR(core.mode) == 0, and if there are subdirectories of the corrupted directory, an attempt to traverse up the directory tree will crash the kernel in __xfs_dir3_data_check. Running the online scrub's parent checks will tend to do this.
The crash occurs because the directory inode's d_ops get set to xfs_dir[23]_nondir_ops (it's not a directory) but the parent pointer scrubber's indiscriminate call to xfs_readdir proceeds past the ASSERT if we have non fatal asserts configured.
Fix the null pointer dereference crash in __xfs_dir3_data_check by looking for S_ISDIR or NULL data_entry_p; and teach the parent scrubber to bail out if it is fed a non-directory "parent".
--- fs/xfs/libxfs/xfs_dir2_data.c | 7 +++++++ fs/xfs/scrub/parent.c | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-)
fs/xfs/libxfs/xfs_dir2_data.c +7 -0
@@ -73,6 +73,13 @@ __xfs_dir3_data_check(*/ ops =xfs_dir_get_ops (mp, dp); +/* +* If this isn't a directory, or we got handed the non-dir ops, +* something is seriously wrong. Bail out. +*/ +if ((dp && !S_ISDIR (VFS_I (dp)->i_mode)) || !ops->data_entry_p) +return __this_address; + hdr = bp->b_addr; p = (char *)ops->data_entry_p (hdr);
fs/xfs/scrub/parent.c +1 -1
@@ -171,7 +171,7 @@ xfs_scrub_parent_validate( error =xfs_iget (mp, sc->tp, dnum,0 ,0 , &dp);if (!xfs_scrub_fblock_xref_process_error (sc,XFS_DATA_FORK ,0 , &error)) goto out; -if (dp == sc->ip) { +if (dp == sc->ip || !S_ISDIR (VFS_I (dp)->i_mode)) {xfs_scrub_fblock_set_corrupt (sc,XFS_DATA_FORK ,0 ); goto out_rele; }
Quoted 29 lines · Darrick J. Wong
From: Darrick J. Wong <[email protected]>
If a malicious filesystem image contains a block+ format directory wherein the directory inode's core.mode is set such that
S_ISDIR(core.mode)== 0, and if there are subdirectories of the corrupted directory, an attempt to traverse up the directory tree will crash the kernel in__xfs_dir3_data_check. Running the online scrub's parent checks will tend to do this.The crash occurs because the directory inode's
d_opsget set to xfs_dir[23]_nondir_ops (it's not a directory) but the parent pointer scrubber's indiscriminate call toxfs_readdirproceeds past the ASSERT if we have non fatal asserts configured.Fix the null pointer dereference crash in
__xfs_dir3_data_checkby looking forS_ISDIRor NULLdata_entry_p; and teach the parent scrubber to bail out if it is fed a non-directory "parent".Signed-off-by Darrick J. Wong <[email protected]>--- fs/xfs/libxfs/xfs_dir2_data.c | 7 +++++++ fs/xfs/scrub/parent.c | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-)fs/xfs/libxfs/xfs_dir2_data.c +0
-0
fs/xfs/libxfs/xfs_dir2_data.c __xfs_dir3_data_check( · line 82
Quoted 10 lines
fs/xfs/libxfs/xfs_dir2_data.c +7
-0@@ -73,6 +73,13 @@ __xfs_dir3_data_check(*/ ops =xfs_dir_get_ops (mp, dp); +/* +* If this isn't a directory, or we got handed the non-dir ops, +* something is seriously wrong. Bail out. +*/ +if ((dp && !S_ISDIR (VFS_I (dp)->i_mode)) || !ops->data_entry_p) +return __this_address; +
I wonder if something like (ops == xfs_nondir_get_ops(mp, NULL)) would be a bit more explicit for the second part of this check..? Otherwise seems Ok to me.
Brian
Quoted 20 lines
fs/xfs/libxfs/xfs_dir2_data.c +0
-0hdr = bp->b_addr; p = (char *)ops->data_entry_p (hdr);fs/xfs/scrub/parent.c +1
-2@@ -171,7 +171,7 @@ xfs_scrub_parent_validate( error =xfs_iget (mp, sc->tp, dnum,0 ,0 , &dp);if (!xfs_scrub_fblock_xref_process_error (sc,XFS_DATA_FORK ,0 , &error)) goto out; -if (dp == sc->ip) { +if (dp == sc->ip || !S_ISDIR (VFS_I (dp)->i_mode)) {xfs_scrub_fblock_set_corrupt (sc,XFS_DATA_FORK ,0 ); goto out_rele; } --To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 33 lines · Brian Foster
Quoted 32 lines · Darrick J. Wong
From: Darrick J. Wong <[email protected]>
If a malicious filesystem image contains a block+ format directory wherein the directory inode's core.mode is set such that
S_ISDIR(core.mode)== 0, and if there are subdirectories of the corrupted directory, an attempt to traverse up the directory tree will crash the kernel in__xfs_dir3_data_check. Running the online scrub's parent checks will tend to do this.The crash occurs because the directory inode's
d_opsget set to xfs_dir[23]_nondir_ops (it's not a directory) but the parent pointer scrubber's indiscriminate call toxfs_readdirproceeds past the ASSERT if we have non fatal asserts configured.Fix the null pointer dereference crash in
__xfs_dir3_data_checkby looking forS_ISDIRor NULLdata_entry_p; and teach the parent scrubber to bail out if it is fed a non-directory "parent".Signed-off-by Darrick J. Wong <[email protected]>--- fs/xfs/libxfs/xfs_dir2_data.c | 7 +++++++ fs/xfs/scrub/parent.c | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-)fs/xfs/libxfs/xfs_dir2_data.c +0
-0@@ -73,6 +73,13 @@ __xfs_dir3_data_check(*/ ops =xfs_dir_get_ops (mp, dp);
Quoted 11 lines
fs/xfs/libxfs/xfs_dir2_data.c __xfs_dir3_data_check( · line 82
Quoted 7 lines
fs/xfs/libxfs/xfs_dir2_data.c +7
-0+/* +* If this isn't a directory, or we got handed the non-dir ops, +* something is seriously wrong. Bail out. +*/ +if ((dp && !S_ISDIR (VFS_I (dp)->i_mode)) || !ops->data_entry_p) +return __this_address; +I wonder if something like (ops ==
xfs_nondir_get_ops(mp, NULL)) would be a bit more explicit for the second part of this check..? Otherwise seems Ok to me.
Sure, though I prefer (ops != xfs_dir_get_ops(mp, NULL)) for defensive reasons.
--D
Quoted 27 lines
Brian
Quoted 17 lines
fs/xfs/libxfs/xfs_dir2_data.c +0
-0hdr = bp->b_addr; p = (char *)ops->data_entry_p (hdr);fs/xfs/scrub/parent.c +1
-2@@ -171,7 +171,7 @@ xfs_scrub_parent_validate( error =xfs_iget (mp, sc->tp, dnum,0 ,0 , &dp);if (!xfs_scrub_fblock_xref_process_error (sc,XFS_DATA_FORK ,0 , &error)) goto out; -if (dp == sc->ip) { +if (dp == sc->ip || !S_ISDIR (VFS_I (dp)->i_mode)) {xfs_scrub_fblock_set_corrupt (sc,XFS_DATA_FORK ,0 ); goto out_rele; } --Quoted 3 lines
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 1/1 xfs: harden directory integrity checks some more
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
If a malicious filesystem image contains a block+ format directory wherein the directory inode's core.mode is set such that S_ISDIR(core.mode) == 0, and if there are subdirectories of the corrupted directory, an attempt to traverse up the directory tree will crash the kernel in __xfs_dir3_data_check. Running the online scrub's parent checks will tend to do this.
The crash occurs because the directory inode's d_ops get set to xfs_dir[23]_nondir_ops (it's not a directory) but the parent pointer scrubber's indiscriminate call to xfs_readdir proceeds past the ASSERT if we have non fatal asserts configured.
Fix the null pointer dereference crash in __xfs_dir3_data_check by looking for S_ISDIR or wrong d_ops; and teach the parent scrubber to bail out if it is fed a non-directory "parent".
---
v2: check for wrong d_ops, not individual function pointers
--- fs/xfs/libxfs/xfs_dir2_data.c | 8 ++++++++ fs/xfs/scrub/parent.c | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-)
fs/xfs/libxfs/xfs_dir2_data.c +8 -0
@@ -73,6 +73,14 @@ __xfs_dir3_data_check(*/ ops =xfs_dir_get_ops (mp, dp); +/* +* If this isn't a directory, or we don't get handed the dir ops, +* something is seriously wrong. Bail out. +*/ +if ((dp && !S_ISDIR (VFS_I (dp)->i_mode)) || + ops !=xfs_dir_get_ops (mp,NULL )) +return __this_address; + hdr = bp->b_addr; p = (char *)ops->data_entry_p (hdr);
fs/xfs/scrub/parent.c +1 -1
@@ -171,7 +171,7 @@ xfs_scrub_parent_validate( error =xfs_iget (mp, sc->tp, dnum,0 ,0 , &dp);if (!xfs_scrub_fblock_xref_process_error (sc,XFS_DATA_FORK ,0 , &error)) goto out; -if (dp == sc->ip) { +if (dp == sc->ip || !S_ISDIR (VFS_I (dp)->i_mode)) {xfs_scrub_fblock_set_corrupt (sc,XFS_DATA_FORK ,0 ); goto out_rele; }
Quoted 14 lines · Darrick J. Wong
From: Darrick J. Wong <[email protected]>
If a malicious filesystem image contains a block+ format directory wherein the directory inode's core.mode is set such that
S_ISDIR(core.mode)== 0, and if there are subdirectories of the corrupted directory, an attempt to traverse up the directory tree will crash the kernel in__xfs_dir3_data_check. Running the online scrub's parent checks will tend to do this.The crash occurs because the directory inode's
d_opsget set to xfs_dir[23]_nondir_ops (it's not a directory) but the parent pointer scrubber's indiscriminate call toxfs_readdirproceeds past the ASSERT if we have non fatal asserts configured.
Quoted 8 lines
Fix the null pointer dereference crash in
__xfs_dir3_data_checkby looking forS_ISDIRor wrongd_ops; and teach the parent scrubber to bail out if it is fed a non-directory "parent".Signed-off-by Darrick J. Wong <[email protected]>---
v2: check for wrongd_ops, not individual function pointers
---
Quoted 40 lines
fs/xfs/libxfs/xfs_dir2_data.c | 8 ++++++++ fs/xfs/scrub/parent.c | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-)fs/xfs/libxfs/xfs_dir2_data.c +8
-0@@ -73,6 +73,14 @@ __xfs_dir3_data_check(*/ ops =xfs_dir_get_ops (mp, dp); +/* +* If this isn't a directory, or we don't get handed the dir ops, +* something is seriously wrong. Bail out. +*/ +if ((dp && !S_ISDIR (VFS_I (dp)->i_mode)) || + ops !=xfs_dir_get_ops (mp,NULL )) +return __this_address; + hdr = bp->b_addr; p = (char *)ops->data_entry_p (hdr);fs/xfs/scrub/parent.c +1
-2@@ -171,7 +171,7 @@ xfs_scrub_parent_validate( error =xfs_iget (mp, sc->tp, dnum,0 ,0 , &dp);if (!xfs_scrub_fblock_xref_process_error (sc,XFS_DATA_FORK ,0 , &error)) goto out; -if (dp == sc->ip) { +if (dp == sc->ip || !S_ISDIR (VFS_I (dp)->i_mode)) {xfs_scrub_fblock_set_corrupt (sc,XFS_DATA_FORK ,0 ); goto out_rele; } --To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html