]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - fs/xfs/libxfs/xfs_inode_buf.c
Merge branch 'xfs-4.10-misc-fixes-3' into for-next
[mirror_ubuntu-bionic-kernel.git] / fs / xfs / libxfs / xfs_inode_buf.c
index 8de9a3a29589bd59c0684c8eab278db3edceba53..dd483e2767f7a38a4dfef5c063148430364b4aaf 100644 (file)
@@ -57,6 +57,17 @@ xfs_inobp_check(
 }
 #endif
 
+bool
+xfs_dinode_good_version(
+       struct xfs_mount *mp,
+       __u8            version)
+{
+       if (xfs_sb_version_hascrc(&mp->m_sb))
+               return version == 3;
+
+       return version == 1 || version == 2;
+}
+
 /*
  * If we are doing readahead on an inode buffer, we might be in log recovery
  * reading an inode allocation buffer that hasn't yet been replayed, and hence
@@ -91,7 +102,7 @@ xfs_inode_buf_verify(
 
                dip = xfs_buf_offset(bp, (i << mp->m_sb.sb_inodelog));
                di_ok = dip->di_magic == cpu_to_be16(XFS_DINODE_MAGIC) &&
-                           XFS_DINODE_GOOD_VERSION(dip->di_version);
+                       xfs_dinode_good_version(mp, dip->di_version);
                if (unlikely(XFS_TEST_ERROR(!di_ok, mp,
                                                XFS_ERRTAG_ITOBP_INOTOBP,
                                                XFS_RANDOM_ITOBP_INOTOBP))) {
@@ -372,7 +383,7 @@ xfs_log_dinode_to_disk(
 static bool
 xfs_dinode_verify(
        struct xfs_mount        *mp,
-       struct xfs_inode        *ip,
+       xfs_ino_t               ino,
        struct xfs_dinode       *dip)
 {
        uint16_t                flags;
@@ -381,6 +392,14 @@ xfs_dinode_verify(
        if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC))
                return false;
 
+       /* don't allow invalid i_size */
+       if (be64_to_cpu(dip->di_size) & (1ULL << 63))
+               return false;
+
+       /* No zero-length symlinks. */
+       if (S_ISLNK(be16_to_cpu(dip->di_mode)) && dip->di_size == 0)
+               return false;
+
        /* only version 3 or greater inodes are extensively verified here */
        if (dip->di_version < 3)
                return true;
@@ -390,7 +409,7 @@ xfs_dinode_verify(
        if (!xfs_verify_cksum((char *)dip, mp->m_sb.sb_inodesize,
                              XFS_DINODE_CRC_OFF))
                return false;
-       if (be64_to_cpu(dip->di_ino) != ip->i_ino)
+       if (be64_to_cpu(dip->di_ino) != ino)
                return false;
        if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_meta_uuid))
                return false;
@@ -425,7 +444,7 @@ xfs_dinode_calc_crc(
                return;
 
        ASSERT(xfs_sb_version_hascrc(&mp->m_sb));
-       crc = xfs_start_cksum((char *)dip, mp->m_sb.sb_inodesize,
+       crc = xfs_start_cksum_update((char *)dip, mp->m_sb.sb_inodesize,
                              XFS_DINODE_CRC_OFF);
        dip->di_crc = xfs_end_cksum(crc);
 }
@@ -482,7 +501,7 @@ xfs_iread(
                return error;
 
        /* even unallocated inodes are verified */
-       if (!xfs_dinode_verify(mp, ip, dip)) {
+       if (!xfs_dinode_verify(mp, ip->i_ino, dip)) {
                xfs_alert(mp, "%s: validation failed for inode %lld failed",
                                __func__, ip->i_ino);