Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-or-later 2 : /* 3 : * Copyright (C) 2017-2023 Oracle. All Rights Reserved. 4 : * Author: Darrick J. Wong <djwong@kernel.org> 5 : */ 6 : #include "xfs.h" 7 : #include "xfs_fs.h" 8 : #include "xfs_shared.h" 9 : #include "xfs_format.h" 10 : #include "xfs_trans_resv.h" 11 : #include "xfs_mount.h" 12 : #include "xfs_log_format.h" 13 : #include "xfs_inode.h" 14 : #include "xfs_symlink.h" 15 : #include "scrub/scrub.h" 16 : #include "scrub/common.h" 17 : 18 : /* Set us up to scrub a symbolic link. */ 19 : int 20 41809375 : xchk_setup_symlink( 21 : struct xfs_scrub *sc) 22 : { 23 : /* Allocate the buffer without the inode lock held. */ 24 41809375 : sc->buf = kvzalloc(XFS_SYMLINK_MAXLEN + 1, XCHK_GFP_FLAGS); 25 41816830 : if (!sc->buf) 26 : return -ENOMEM; 27 : 28 41816830 : return xchk_setup_inode_contents(sc, 0); 29 : } 30 : 31 : /* Symbolic links. */ 32 : 33 : int 34 41598289 : xchk_symlink( 35 : struct xfs_scrub *sc) 36 : { 37 41598289 : struct xfs_inode *ip = sc->ip; 38 41598289 : struct xfs_ifork *ifp; 39 41598289 : loff_t len; 40 41598289 : int error = 0; 41 : 42 41598289 : if (!S_ISLNK(VFS_I(ip)->i_mode)) 43 : return -ENOENT; 44 41444553 : ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK); 45 41444553 : len = ip->i_disk_size; 46 : 47 : /* Plausible size? */ 48 41444553 : if (len > XFS_SYMLINK_MAXLEN || len <= 0) { 49 0 : xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0); 50 0 : goto out; 51 : } 52 : 53 : /* Inline symlink? */ 54 41444553 : if (ifp->if_format == XFS_DINODE_FMT_LOCAL) { 55 28116645 : if (len > xfs_inode_data_fork_size(ip) || 56 14057581 : len > strnlen(ifp->if_u1.if_data, xfs_inode_data_fork_size(ip))) 57 0 : xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0); 58 14059056 : goto out; 59 : } 60 : 61 : /* Remote symlink; must read the contents. */ 62 27386972 : error = xfs_readlink_bmap_ilocked(sc->ip, sc->buf); 63 27387237 : if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error)) 64 0 : goto out; 65 54772447 : if (strnlen(sc->buf, XFS_SYMLINK_MAXLEN) < len) 66 0 : xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0); 67 27393433 : out: 68 41452489 : return error; 69 : }