LCOV - code coverage report
Current view: top level - fs/xfs/libxfs - xfs_symlink_remote.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-djwa @ Mon Jul 31 20:08:17 PDT 2023 Lines: 73 91 80.2 %
Date: 2023-07-31 20:08:17 Functions: 8 8 100.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  * Copyright (c) 2000-2006 Silicon Graphics, Inc.
       4             :  * Copyright (c) 2012-2013 Red Hat, Inc.
       5             :  * All rights reserved.
       6             :  */
       7             : #include "xfs.h"
       8             : #include "xfs_fs.h"
       9             : #include "xfs_format.h"
      10             : #include "xfs_log_format.h"
      11             : #include "xfs_shared.h"
      12             : #include "xfs_trans_resv.h"
      13             : #include "xfs_mount.h"
      14             : #include "xfs_inode.h"
      15             : #include "xfs_error.h"
      16             : #include "xfs_trans.h"
      17             : #include "xfs_buf_item.h"
      18             : #include "xfs_log.h"
      19             : 
      20             : 
      21             : /*
      22             :  * Each contiguous block has a header, so it is not just a simple pathlen
      23             :  * to FSB conversion.
      24             :  */
      25             : int
      26   240353456 : xfs_symlink_blocks(
      27             :         struct xfs_mount *mp,
      28             :         int             pathlen)
      29             : {
      30   240353456 :         int buflen = XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
      31             : 
      32   240353456 :         return (pathlen + buflen - 1) / buflen;
      33             : }
      34             : 
      35             : int
      36    18316506 : xfs_symlink_hdr_set(
      37             :         struct xfs_mount        *mp,
      38             :         xfs_ino_t               ino,
      39             :         uint32_t                offset,
      40             :         uint32_t                size,
      41             :         struct xfs_buf          *bp)
      42             : {
      43    18316506 :         struct xfs_dsymlink_hdr *dsl = bp->b_addr;
      44             : 
      45    18316506 :         if (!xfs_has_crc(mp))
      46             :                 return 0;
      47             : 
      48    18316506 :         memset(dsl, 0, sizeof(struct xfs_dsymlink_hdr));
      49    18316506 :         dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC);
      50    18316506 :         dsl->sl_offset = cpu_to_be32(offset);
      51    18316506 :         dsl->sl_bytes = cpu_to_be32(size);
      52    18316506 :         uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid);
      53    18316800 :         dsl->sl_owner = cpu_to_be64(ino);
      54    18316800 :         dsl->sl_blkno = cpu_to_be64(xfs_buf_daddr(bp));
      55    18316800 :         bp->b_ops = &xfs_symlink_buf_ops;
      56             : 
      57    18316800 :         return sizeof(struct xfs_dsymlink_hdr);
      58             : }
      59             : 
      60             : /*
      61             :  * Checking of the symlink header is split into two parts. the verifier does
      62             :  * CRC, location and bounds checking, the unpacking function checks the path
      63             :  * parameters and owner.
      64             :  */
      65             : bool
      66   203945244 : xfs_symlink_hdr_ok(
      67             :         xfs_ino_t               ino,
      68             :         uint32_t                offset,
      69             :         uint32_t                size,
      70             :         struct xfs_buf          *bp)
      71             : {
      72   203945244 :         struct xfs_dsymlink_hdr *dsl = bp->b_addr;
      73             : 
      74   407890488 :         if (offset != be32_to_cpu(dsl->sl_offset))
      75             :                 return false;
      76   408436870 :         if (size != be32_to_cpu(dsl->sl_bytes))
      77             :                 return false;
      78   204254907 :         if (ino != be64_to_cpu(dsl->sl_owner))
      79           0 :                 return false;
      80             : 
      81             :         /* ok */
      82             :         return true;
      83             : }
      84             : 
      85             : static xfs_failaddr_t
      86     3403678 : xfs_symlink_verify(
      87             :         struct xfs_buf          *bp)
      88             : {
      89     3403678 :         struct xfs_mount        *mp = bp->b_mount;
      90     3403678 :         struct xfs_dsymlink_hdr *dsl = bp->b_addr;
      91             : 
      92     3403678 :         if (!xfs_has_crc(mp))
      93           0 :                 return __this_address;
      94     3403678 :         if (!xfs_verify_magic(bp, dsl->sl_magic))
      95           0 :                 return __this_address;
      96     3403678 :         if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid))
      97           0 :                 return __this_address;
      98     3403678 :         if (xfs_buf_daddr(bp) != be64_to_cpu(dsl->sl_blkno))
      99           0 :                 return __this_address;
     100     6807356 :         if (be32_to_cpu(dsl->sl_offset) +
     101     3403678 :                                 be32_to_cpu(dsl->sl_bytes) >= XFS_SYMLINK_MAXLEN)
     102           0 :                 return __this_address;
     103     3403678 :         if (dsl->sl_owner == 0)
     104           0 :                 return __this_address;
     105     3403678 :         if (!xfs_log_check_lsn(mp, be64_to_cpu(dsl->sl_lsn)))
     106           0 :                 return __this_address;
     107             : 
     108             :         return NULL;
     109             : }
     110             : 
     111             : static void
     112      562830 : xfs_symlink_read_verify(
     113             :         struct xfs_buf  *bp)
     114             : {
     115      562830 :         struct xfs_mount *mp = bp->b_mount;
     116      562830 :         xfs_failaddr_t  fa;
     117             : 
     118             :         /* no verification of non-crc buffers */
     119      562830 :         if (!xfs_has_crc(mp))
     120             :                 return;
     121             : 
     122      562830 :         if (!xfs_buf_verify_cksum(bp, XFS_SYMLINK_CRC_OFF))
     123           2 :                 xfs_verifier_error(bp, -EFSBADCRC, __this_address);
     124             :         else {
     125      562828 :                 fa = xfs_symlink_verify(bp);
     126      562828 :                 if (fa)
     127           0 :                         xfs_verifier_error(bp, -EFSCORRUPTED, fa);
     128             :         }
     129             : }
     130             : 
     131             : static void
     132     2840850 : xfs_symlink_write_verify(
     133             :         struct xfs_buf  *bp)
     134             : {
     135     2840850 :         struct xfs_mount *mp = bp->b_mount;
     136     2840850 :         struct xfs_buf_log_item *bip = bp->b_log_item;
     137     2840850 :         xfs_failaddr_t          fa;
     138             : 
     139             :         /* no verification of non-crc buffers */
     140     2840850 :         if (!xfs_has_crc(mp))
     141             :                 return;
     142             : 
     143     2840850 :         fa = xfs_symlink_verify(bp);
     144     2840850 :         if (fa) {
     145           0 :                 xfs_verifier_error(bp, -EFSCORRUPTED, fa);
     146           0 :                 return;
     147             :         }
     148             : 
     149     2840850 :         if (bip) {
     150     2840850 :                 struct xfs_dsymlink_hdr *dsl = bp->b_addr;
     151     2840850 :                 dsl->sl_lsn = cpu_to_be64(bip->bli_item.li_lsn);
     152             :         }
     153     2840850 :         xfs_buf_update_cksum(bp, XFS_SYMLINK_CRC_OFF);
     154             : }
     155             : 
     156             : const struct xfs_buf_ops xfs_symlink_buf_ops = {
     157             :         .name = "xfs_symlink",
     158             :         .magic = { 0, cpu_to_be32(XFS_SYMLINK_MAGIC) },
     159             :         .verify_read = xfs_symlink_read_verify,
     160             :         .verify_write = xfs_symlink_write_verify,
     161             :         .verify_struct = xfs_symlink_verify,
     162             : };
     163             : 
     164             : void
     165           4 : xfs_symlink_local_to_remote(
     166             :         struct xfs_trans        *tp,
     167             :         struct xfs_buf          *bp,
     168             :         struct xfs_inode        *ip,
     169             :         struct xfs_ifork        *ifp)
     170             : {
     171           4 :         struct xfs_mount        *mp = ip->i_mount;
     172           4 :         char                    *buf;
     173             : 
     174           4 :         xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SYMLINK_BUF);
     175             : 
     176           4 :         if (!xfs_has_crc(mp)) {
     177           0 :                 bp->b_ops = NULL;
     178           0 :                 memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
     179           0 :                 xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
     180           0 :                 return;
     181             :         }
     182             : 
     183             :         /*
     184             :          * As this symlink fits in an inode literal area, it must also fit in
     185             :          * the smallest buffer the filesystem supports.
     186             :          */
     187           4 :         ASSERT(BBTOB(bp->b_length) >=
     188             :                         ifp->if_bytes + sizeof(struct xfs_dsymlink_hdr));
     189             : 
     190           4 :         bp->b_ops = &xfs_symlink_buf_ops;
     191             : 
     192           4 :         buf = bp->b_addr;
     193           4 :         buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp);
     194           8 :         memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes);
     195           4 :         xfs_trans_log_buf(tp, bp, 0, sizeof(struct xfs_dsymlink_hdr) +
     196           4 :                                         ifp->if_bytes - 1);
     197             : }
     198             : 
     199             : /*
     200             :  * Verify the in-memory consistency of an inline symlink data fork. This
     201             :  * does not do on-disk format checks.
     202             :  */
     203             : xfs_failaddr_t
     204     8714754 : xfs_symlink_shortform_verify(
     205             :         struct xfs_inode        *ip)
     206             : {
     207     8714754 :         struct xfs_ifork        *ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK);
     208     8714754 :         char                    *sfp = (char *)ifp->if_u1.if_data;
     209     8714754 :         int                     size = ifp->if_bytes;
     210     8714754 :         char                    *endp = sfp + size;
     211             : 
     212     8714754 :         ASSERT(ifp->if_format == XFS_DINODE_FMT_LOCAL);
     213             : 
     214             :         /*
     215             :          * Zero length symlinks should never occur in memory as they are
     216             :          * never allowed to exist on disk.
     217             :          */
     218     8714754 :         if (!size)
     219           0 :                 return __this_address;
     220             : 
     221             :         /* No negative sizes or overly long symlink targets. */
     222     8714754 :         if (size < 0 || size > XFS_SYMLINK_MAXLEN)
     223           0 :                 return __this_address;
     224             : 
     225             :         /* No NULLs in the target either. */
     226    17429508 :         if (memchr(sfp, 0, size - 1))
     227           2 :                 return __this_address;
     228             : 
     229             :         /* We /did/ null-terminate the buffer, right? */
     230     8714752 :         if (*endp != 0)
     231           0 :                 return __this_address;
     232             :         return NULL;
     233             : }

Generated by: LCOV version 1.14