Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2000-2006 Silicon Graphics, Inc.
0004  * Copyright (c) 2012-2013 Red Hat, Inc.
0005  * All rights reserved.
0006  */
0007 #include "xfs.h"
0008 #include "xfs_fs.h"
0009 #include "xfs_format.h"
0010 #include "xfs_log_format.h"
0011 #include "xfs_shared.h"
0012 #include "xfs_trans_resv.h"
0013 #include "xfs_mount.h"
0014 #include "xfs_inode.h"
0015 #include "xfs_error.h"
0016 #include "xfs_trans.h"
0017 #include "xfs_buf_item.h"
0018 #include "xfs_log.h"
0019 
0020 
0021 /*
0022  * Each contiguous block has a header, so it is not just a simple pathlen
0023  * to FSB conversion.
0024  */
0025 int
0026 xfs_symlink_blocks(
0027     struct xfs_mount *mp,
0028     int     pathlen)
0029 {
0030     int buflen = XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
0031 
0032     return (pathlen + buflen - 1) / buflen;
0033 }
0034 
0035 int
0036 xfs_symlink_hdr_set(
0037     struct xfs_mount    *mp,
0038     xfs_ino_t       ino,
0039     uint32_t        offset,
0040     uint32_t        size,
0041     struct xfs_buf      *bp)
0042 {
0043     struct xfs_dsymlink_hdr *dsl = bp->b_addr;
0044 
0045     if (!xfs_has_crc(mp))
0046         return 0;
0047 
0048     memset(dsl, 0, sizeof(struct xfs_dsymlink_hdr));
0049     dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC);
0050     dsl->sl_offset = cpu_to_be32(offset);
0051     dsl->sl_bytes = cpu_to_be32(size);
0052     uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid);
0053     dsl->sl_owner = cpu_to_be64(ino);
0054     dsl->sl_blkno = cpu_to_be64(xfs_buf_daddr(bp));
0055     bp->b_ops = &xfs_symlink_buf_ops;
0056 
0057     return sizeof(struct xfs_dsymlink_hdr);
0058 }
0059 
0060 /*
0061  * Checking of the symlink header is split into two parts. the verifier does
0062  * CRC, location and bounds checking, the unpacking function checks the path
0063  * parameters and owner.
0064  */
0065 bool
0066 xfs_symlink_hdr_ok(
0067     xfs_ino_t       ino,
0068     uint32_t        offset,
0069     uint32_t        size,
0070     struct xfs_buf      *bp)
0071 {
0072     struct xfs_dsymlink_hdr *dsl = bp->b_addr;
0073 
0074     if (offset != be32_to_cpu(dsl->sl_offset))
0075         return false;
0076     if (size != be32_to_cpu(dsl->sl_bytes))
0077         return false;
0078     if (ino != be64_to_cpu(dsl->sl_owner))
0079         return false;
0080 
0081     /* ok */
0082     return true;
0083 }
0084 
0085 static xfs_failaddr_t
0086 xfs_symlink_verify(
0087     struct xfs_buf      *bp)
0088 {
0089     struct xfs_mount    *mp = bp->b_mount;
0090     struct xfs_dsymlink_hdr *dsl = bp->b_addr;
0091 
0092     if (!xfs_has_crc(mp))
0093         return __this_address;
0094     if (!xfs_verify_magic(bp, dsl->sl_magic))
0095         return __this_address;
0096     if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid))
0097         return __this_address;
0098     if (xfs_buf_daddr(bp) != be64_to_cpu(dsl->sl_blkno))
0099         return __this_address;
0100     if (be32_to_cpu(dsl->sl_offset) +
0101                 be32_to_cpu(dsl->sl_bytes) >= XFS_SYMLINK_MAXLEN)
0102         return __this_address;
0103     if (dsl->sl_owner == 0)
0104         return __this_address;
0105     if (!xfs_log_check_lsn(mp, be64_to_cpu(dsl->sl_lsn)))
0106         return __this_address;
0107 
0108     return NULL;
0109 }
0110 
0111 static void
0112 xfs_symlink_read_verify(
0113     struct xfs_buf  *bp)
0114 {
0115     struct xfs_mount *mp = bp->b_mount;
0116     xfs_failaddr_t  fa;
0117 
0118     /* no verification of non-crc buffers */
0119     if (!xfs_has_crc(mp))
0120         return;
0121 
0122     if (!xfs_buf_verify_cksum(bp, XFS_SYMLINK_CRC_OFF))
0123         xfs_verifier_error(bp, -EFSBADCRC, __this_address);
0124     else {
0125         fa = xfs_symlink_verify(bp);
0126         if (fa)
0127             xfs_verifier_error(bp, -EFSCORRUPTED, fa);
0128     }
0129 }
0130 
0131 static void
0132 xfs_symlink_write_verify(
0133     struct xfs_buf  *bp)
0134 {
0135     struct xfs_mount *mp = bp->b_mount;
0136     struct xfs_buf_log_item *bip = bp->b_log_item;
0137     xfs_failaddr_t      fa;
0138 
0139     /* no verification of non-crc buffers */
0140     if (!xfs_has_crc(mp))
0141         return;
0142 
0143     fa = xfs_symlink_verify(bp);
0144     if (fa) {
0145         xfs_verifier_error(bp, -EFSCORRUPTED, fa);
0146         return;
0147     }
0148 
0149     if (bip) {
0150         struct xfs_dsymlink_hdr *dsl = bp->b_addr;
0151         dsl->sl_lsn = cpu_to_be64(bip->bli_item.li_lsn);
0152     }
0153     xfs_buf_update_cksum(bp, XFS_SYMLINK_CRC_OFF);
0154 }
0155 
0156 const struct xfs_buf_ops xfs_symlink_buf_ops = {
0157     .name = "xfs_symlink",
0158     .magic = { 0, cpu_to_be32(XFS_SYMLINK_MAGIC) },
0159     .verify_read = xfs_symlink_read_verify,
0160     .verify_write = xfs_symlink_write_verify,
0161     .verify_struct = xfs_symlink_verify,
0162 };
0163 
0164 void
0165 xfs_symlink_local_to_remote(
0166     struct xfs_trans    *tp,
0167     struct xfs_buf      *bp,
0168     struct xfs_inode    *ip,
0169     struct xfs_ifork    *ifp)
0170 {
0171     struct xfs_mount    *mp = ip->i_mount;
0172     char            *buf;
0173 
0174     xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SYMLINK_BUF);
0175 
0176     if (!xfs_has_crc(mp)) {
0177         bp->b_ops = NULL;
0178         memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
0179         xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
0180         return;
0181     }
0182 
0183     /*
0184      * As this symlink fits in an inode literal area, it must also fit in
0185      * the smallest buffer the filesystem supports.
0186      */
0187     ASSERT(BBTOB(bp->b_length) >=
0188             ifp->if_bytes + sizeof(struct xfs_dsymlink_hdr));
0189 
0190     bp->b_ops = &xfs_symlink_buf_ops;
0191 
0192     buf = bp->b_addr;
0193     buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp);
0194     memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes);
0195     xfs_trans_log_buf(tp, bp, 0, sizeof(struct xfs_dsymlink_hdr) +
0196                     ifp->if_bytes - 1);
0197 }
0198 
0199 /*
0200  * Verify the in-memory consistency of an inline symlink data fork. This
0201  * does not do on-disk format checks.
0202  */
0203 xfs_failaddr_t
0204 xfs_symlink_shortform_verify(
0205     struct xfs_inode    *ip)
0206 {
0207     struct xfs_ifork    *ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK);
0208     char            *sfp = (char *)ifp->if_u1.if_data;
0209     int         size = ifp->if_bytes;
0210     char            *endp = sfp + size;
0211 
0212     ASSERT(ifp->if_format == XFS_DINODE_FMT_LOCAL);
0213 
0214     /*
0215      * Zero length symlinks should never occur in memory as they are
0216      * never allowed to exist on disk.
0217      */
0218     if (!size)
0219         return __this_address;
0220 
0221     /* No negative sizes or overly long symlink targets. */
0222     if (size < 0 || size > XFS_SYMLINK_MAXLEN)
0223         return __this_address;
0224 
0225     /* No NULLs in the target either. */
0226     if (memchr(sfp, 0, size - 1))
0227         return __this_address;
0228 
0229     /* We /did/ null-terminate the buffer, right? */
0230     if (*endp != 0)
0231         return __this_address;
0232     return NULL;
0233 }