aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/libxfs/xfs_dir2_sf.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/libxfs/xfs_dir2_sf.c')
-rw-r--r--fs/xfs/libxfs/xfs_dir2_sf.c63
1 files changed, 41 insertions, 22 deletions
diff --git a/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
index 96b45cd6c63f..e84af093b2ab 100644
--- a/fs/xfs/libxfs/xfs_dir2_sf.c
+++ b/fs/xfs/libxfs/xfs_dir2_sf.c
@@ -632,36 +632,49 @@ xfs_dir2_sf_check(
632/* Verify the consistency of an inline directory. */ 632/* Verify the consistency of an inline directory. */
633int 633int
634xfs_dir2_sf_verify( 634xfs_dir2_sf_verify(
635 struct xfs_mount *mp, 635 struct xfs_inode *ip)
636 struct xfs_dir2_sf_hdr *sfp,
637 int size)
638{ 636{
637 struct xfs_mount *mp = ip->i_mount;
638 struct xfs_dir2_sf_hdr *sfp;
639 struct xfs_dir2_sf_entry *sfep; 639 struct xfs_dir2_sf_entry *sfep;
640 struct xfs_dir2_sf_entry *next_sfep; 640 struct xfs_dir2_sf_entry *next_sfep;
641 char *endp; 641 char *endp;
642 const struct xfs_dir_ops *dops; 642 const struct xfs_dir_ops *dops;
643 struct xfs_ifork *ifp;
643 xfs_ino_t ino; 644 xfs_ino_t ino;
644 int i; 645 int i;
645 int i8count; 646 int i8count;
646 int offset; 647 int offset;
648 int size;
649 int error;
647 __uint8_t filetype; 650 __uint8_t filetype;
648 651
652 ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_LOCAL);
653 /*
654 * xfs_iread calls us before xfs_setup_inode sets up ip->d_ops,
655 * so we can only trust the mountpoint to have the right pointer.
656 */
649 dops = xfs_dir_get_ops(mp, NULL); 657 dops = xfs_dir_get_ops(mp, NULL);
650 658
659 ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
660 sfp = (struct xfs_dir2_sf_hdr *)ifp->if_u1.if_data;
661 size = ifp->if_bytes;
662
651 /* 663 /*
652 * Give up if the directory is way too short. 664 * Give up if the directory is way too short.
653 */ 665 */
654 XFS_WANT_CORRUPTED_RETURN(mp, size > 666 if (size <= offsetof(struct xfs_dir2_sf_hdr, parent) ||
655 offsetof(struct xfs_dir2_sf_hdr, parent)); 667 size < xfs_dir2_sf_hdr_size(sfp->i8count))
656 XFS_WANT_CORRUPTED_RETURN(mp, size >= 668 return -EFSCORRUPTED;
657 xfs_dir2_sf_hdr_size(sfp->i8count));
658 669
659 endp = (char *)sfp + size; 670 endp = (char *)sfp + size;
660 671
661 /* Check .. entry */ 672 /* Check .. entry */
662 ino = dops->sf_get_parent_ino(sfp); 673 ino = dops->sf_get_parent_ino(sfp);
663 i8count = ino > XFS_DIR2_MAX_SHORT_INUM; 674 i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
664 XFS_WANT_CORRUPTED_RETURN(mp, !xfs_dir_ino_validate(mp, ino)); 675 error = xfs_dir_ino_validate(mp, ino);
676 if (error)
677 return error;
665 offset = dops->data_first_offset; 678 offset = dops->data_first_offset;
666 679
667 /* Check all reported entries */ 680 /* Check all reported entries */
@@ -672,12 +685,12 @@ xfs_dir2_sf_verify(
672 * Check the fixed-offset parts of the structure are 685 * Check the fixed-offset parts of the structure are
673 * within the data buffer. 686 * within the data buffer.
674 */ 687 */
675 XFS_WANT_CORRUPTED_RETURN(mp, 688 if (((char *)sfep + sizeof(*sfep)) >= endp)
676 ((char *)sfep + sizeof(*sfep)) < endp); 689 return -EFSCORRUPTED;
677 690
678 /* Don't allow names with known bad length. */ 691 /* Don't allow names with known bad length. */
679 XFS_WANT_CORRUPTED_RETURN(mp, sfep->namelen > 0); 692 if (sfep->namelen == 0)
680 XFS_WANT_CORRUPTED_RETURN(mp, sfep->namelen < MAXNAMELEN); 693 return -EFSCORRUPTED;
681 694
682 /* 695 /*
683 * Check that the variable-length part of the structure is 696 * Check that the variable-length part of the structure is
@@ -685,33 +698,39 @@ xfs_dir2_sf_verify(
685 * name component, so nextentry is an acceptable test. 698 * name component, so nextentry is an acceptable test.
686 */ 699 */
687 next_sfep = dops->sf_nextentry(sfp, sfep); 700 next_sfep = dops->sf_nextentry(sfp, sfep);
688 XFS_WANT_CORRUPTED_RETURN(mp, endp >= (char *)next_sfep); 701 if (endp < (char *)next_sfep)
702 return -EFSCORRUPTED;
689 703
690 /* Check that the offsets always increase. */ 704 /* Check that the offsets always increase. */
691 XFS_WANT_CORRUPTED_RETURN(mp, 705 if (xfs_dir2_sf_get_offset(sfep) < offset)
692 xfs_dir2_sf_get_offset(sfep) >= offset); 706 return -EFSCORRUPTED;
693 707
694 /* Check the inode number. */ 708 /* Check the inode number. */
695 ino = dops->sf_get_ino(sfp, sfep); 709 ino = dops->sf_get_ino(sfp, sfep);
696 i8count += ino > XFS_DIR2_MAX_SHORT_INUM; 710 i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
697 XFS_WANT_CORRUPTED_RETURN(mp, !xfs_dir_ino_validate(mp, ino)); 711 error = xfs_dir_ino_validate(mp, ino);
712 if (error)
713 return error;
698 714
699 /* Check the file type. */ 715 /* Check the file type. */
700 filetype = dops->sf_get_ftype(sfep); 716 filetype = dops->sf_get_ftype(sfep);
701 XFS_WANT_CORRUPTED_RETURN(mp, filetype < XFS_DIR3_FT_MAX); 717 if (filetype >= XFS_DIR3_FT_MAX)
718 return -EFSCORRUPTED;
702 719
703 offset = xfs_dir2_sf_get_offset(sfep) + 720 offset = xfs_dir2_sf_get_offset(sfep) +
704 dops->data_entsize(sfep->namelen); 721 dops->data_entsize(sfep->namelen);
705 722
706 sfep = next_sfep; 723 sfep = next_sfep;
707 } 724 }
708 XFS_WANT_CORRUPTED_RETURN(mp, i8count == sfp->i8count); 725 if (i8count != sfp->i8count)
709 XFS_WANT_CORRUPTED_RETURN(mp, (void *)sfep == (void *)endp); 726 return -EFSCORRUPTED;
727 if ((void *)sfep != (void *)endp)
728 return -EFSCORRUPTED;
710 729
711 /* Make sure this whole thing ought to be in local format. */ 730 /* Make sure this whole thing ought to be in local format. */
712 XFS_WANT_CORRUPTED_RETURN(mp, offset + 731 if (offset + (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) +
713 (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) + 732 (uint)sizeof(xfs_dir2_block_tail_t) > mp->m_dir_geo->blksize)
714 (uint)sizeof(xfs_dir2_block_tail_t) <= mp->m_dir_geo->blksize); 733 return -EFSCORRUPTED;
715 734
716 return 0; 735 return 0;
717} 736}