xfs: validate inode di_forkoff
authorEric Sandeen <sandeen@redhat.com>
Sat, 29 Sep 2018 03:50:13 +0000 (13:50 +1000)
committerDave Chinner <david@fromorbit.com>
Sat, 29 Sep 2018 03:50:13 +0000 (13:50 +1000)
Verify the inode di_forkoff, lifted from xfs_repair's
process_check_inode_forkoff().

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
fs/xfs/libxfs/xfs_inode_buf.c

index 30d1d60f1d46e62ff71eca1f45b273536cc6cce1..09d9c8cfa4a09f933a55f1122879809ecb3010af 100644 (file)
@@ -415,6 +415,31 @@ xfs_dinode_verify_fork(
        return NULL;
 }
 
+static xfs_failaddr_t
+xfs_dinode_verify_forkoff(
+       struct xfs_dinode       *dip,
+       struct xfs_mount        *mp)
+{
+       if (!XFS_DFORK_Q(dip))
+               return NULL;
+
+       switch (dip->di_format)  {
+       case XFS_DINODE_FMT_DEV:
+               if (dip->di_forkoff != (roundup(sizeof(xfs_dev_t), 8) >> 3))
+                       return __this_address;
+               break;
+       case XFS_DINODE_FMT_LOCAL:      /* fall through ... */
+       case XFS_DINODE_FMT_EXTENTS:    /* fall through ... */
+       case XFS_DINODE_FMT_BTREE:
+               if (dip->di_forkoff >= (XFS_LITINO(mp, dip->di_version) >> 3))
+                       return __this_address;
+               break;
+       default:
+               return __this_address;
+       }
+       return NULL;
+}
+
 xfs_failaddr_t
 xfs_dinode_verify(
        struct xfs_mount        *mp,
@@ -470,6 +495,11 @@ xfs_dinode_verify(
        if (mode && (flags & XFS_DIFLAG_REALTIME) && !mp->m_rtdev_targp)
                return __this_address;
 
+       /* check for illegal values of forkoff */
+       fa = xfs_dinode_verify_forkoff(dip, mp);
+       if (fa)
+               return fa;
+
        /* Do we have appropriate data fork formats for the mode? */
        switch (mode & S_IFMT) {
        case S_IFIFO: