]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs: verify extent size hint is valid in inode verifier
authorDave Chinner <dchinner@redhat.com>
Thu, 28 Jun 2018 20:11:58 +0000 (15:11 -0500)
committerEric Sandeen <sandeen@redhat.com>
Thu, 28 Jun 2018 20:11:58 +0000 (15:11 -0500)
Source kernel commit: 7d71a671a2d900606d3a62ed5976d3b0feada3a6

There are rules for vald extent size hints. We enforce them when
applications set them, but fuzzers violate those rules and that
screws us over.

This results in alignment assertion failures when setting up
allocations such as this in direct IO:

XFS: Assertion failed: ap->length, file: fs/xfs/libxfs/xfs_bmap.c, line: 3432
....
Call Trace:
xfs_bmap_btalloc+0x415/0x910
xfs_bmapi_write+0x71c/0x12e0
xfs_iomap_write_direct+0x2a9/0x420
xfs_file_iomap_begin+0x4dc/0xa70
iomap_apply+0x43/0x100
iomap_file_buffered_write+0x62/0x90
xfs_file_buffered_aio_write+0xba/0x300
__vfs_write+0xd5/0x150
vfs_write+0xb6/0x180
ksys_write+0x45/0xa0
do_syscall_64+0x5a/0x180
entry_SYSCALL_64_after_hwframe+0x49/0xbe

And from xfs_db:

core.extsize = 10380288

Which is not an integer multiple of the block size, and so violates
Rule #7 for setting extent size hints. Validate extent size hint
rules in the inode verifier to catch this.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
libxfs/xfs_inode_buf.c

index 15f68080bb522e1a6ba5aa2df6d6ae2d55e21b26..5b8d3024a0b0d9ad549fe648a835314477cf2398 100644 (file)
@@ -393,6 +393,7 @@ xfs_dinode_verify(
        xfs_ino_t               ino,
        struct xfs_dinode       *dip)
 {
+       xfs_failaddr_t          fa;
        uint16_t                mode;
        uint16_t                flags;
        uint64_t                flags2;
@@ -509,6 +510,12 @@ xfs_dinode_verify(
                        return __this_address;
        }
 
+       /* extent size hint validation */
+       fa = xfs_inode_validate_extsize(mp, be32_to_cpu(dip->di_extsize),
+                       mode, flags);
+       if (fa)
+               return fa;
+
        /* only version 3 or greater inodes are extensively verified here */
        if (dip->di_version < 3)
                return NULL;
@@ -517,7 +524,7 @@ xfs_dinode_verify(
 
        /* don't allow reflink/cowextsize if we don't have reflink */
        if ((flags2 & (XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE)) &&
-            !xfs_sb_version_hasreflink(&mp->m_sb))
+            !xfs_sb_version_hasreflink(&mp->m_sb))
                return __this_address;
 
        /* only regular files get reflink */