xfs: create structure verifier function for short form symlinks
authorDarrick J. Wong <darrick.wong@oracle.com>
Mon, 8 Jan 2018 18:51:05 +0000 (10:51 -0800)
committerDarrick J. Wong <darrick.wong@oracle.com>
Mon, 8 Jan 2018 18:54:46 +0000 (10:54 -0800)
Create a function to check the structure of short form symlink targets.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
fs/xfs/libxfs/xfs_shared.h
fs/xfs/libxfs/xfs_symlink_remote.c

index c6f4eb4..67ccb1a 100644 (file)
@@ -143,5 +143,6 @@ bool xfs_symlink_hdr_ok(xfs_ino_t ino, uint32_t offset,
                        uint32_t size, struct xfs_buf *bp);
 void xfs_symlink_local_to_remote(struct xfs_trans *tp, struct xfs_buf *bp,
                                 struct xfs_inode *ip, struct xfs_ifork *ifp);
+xfs_failaddr_t xfs_symlink_shortform_verify(struct xfs_inode *ip);
 
 #endif /* __XFS_SHARED_H__ */
index 5497014..adf2d78 100644 (file)
@@ -209,3 +209,37 @@ xfs_symlink_local_to_remote(
        xfs_trans_log_buf(tp, bp, 0, sizeof(struct xfs_dsymlink_hdr) +
                                        ifp->if_bytes - 1);
 }
+
+/* Verify the consistency of an inline symlink. */
+xfs_failaddr_t
+xfs_symlink_shortform_verify(
+       struct xfs_inode        *ip)
+{
+       char                    *sfp;
+       char                    *endp;
+       struct xfs_ifork        *ifp;
+       int                     size;
+
+       ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_LOCAL);
+       ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
+       sfp = (char *)ifp->if_u1.if_data;
+       size = ifp->if_bytes;
+       endp = sfp + size;
+
+       /* Zero length symlinks can exist while we're deleting a remote one. */
+       if (size == 0)
+               return NULL;
+
+       /* No negative sizes or overly long symlink targets. */
+       if (size < 0 || size > XFS_SYMLINK_MAXLEN)
+               return __this_address;
+
+       /* No NULLs in the target either. */
+       if (memchr(sfp, 0, size - 1))
+               return __this_address;
+
+       /* We /did/ null-terminate the buffer, right? */
+       if (*endp != 0)
+               return __this_address;
+       return NULL;
+}