]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xfs: fix missing check for invalid attr flags
authorDarrick J. Wong <djwong@kernel.org>
Mon, 22 Apr 2024 16:47:27 +0000 (09:47 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 23 Apr 2024 14:46:53 +0000 (07:46 -0700)
The xattr scrubber doesn't check for undefined flags in shortform attr
entries.  Therefore, define a mask XFS_ATTR_ONDISK_MASK that has all
possible XFS_ATTR_* flags in it, and use that to check for unknown bits
in xchk_xattr_actor.

Refactor the check in the dabtree scanner function to use the new mask
as well.  The redundant checks need to be in place because the dabtree
check examines the hash mappings and therefore needs to decode the attr
leaf entries to compute the namehash.  This happens before the walk of
the xattr entries themselves.

Fixes: ae0506eba78fd ("xfs: check used space of shortform xattr structures")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
fs/xfs/libxfs/xfs_da_format.h
fs/xfs/scrub/attr.c

index aac3fe0396140d4673ab5da60e850ee0ea0e7f0b..ecd0616f5776a2f52e993bf20fe575d4717e0d2a 100644 (file)
@@ -719,8 +719,13 @@ struct xfs_attr3_leafblock {
 #define XFS_ATTR_ROOT          (1u << XFS_ATTR_ROOT_BIT)
 #define XFS_ATTR_SECURE                (1u << XFS_ATTR_SECURE_BIT)
 #define XFS_ATTR_INCOMPLETE    (1u << XFS_ATTR_INCOMPLETE_BIT)
+
 #define XFS_ATTR_NSP_ONDISK_MASK       (XFS_ATTR_ROOT | XFS_ATTR_SECURE)
 
+#define XFS_ATTR_ONDISK_MASK   (XFS_ATTR_NSP_ONDISK_MASK | \
+                                XFS_ATTR_LOCAL | \
+                                XFS_ATTR_INCOMPLETE)
+
 #define XFS_ATTR_NAMESPACE_STR \
        { XFS_ATTR_LOCAL,       "local" }, \
        { XFS_ATTR_ROOT,        "root" }, \
index 5b855d7c98211793e04de00e4985d9bb97209efa..5ca79af47e81e69776715e9d7de99f4be6571212 100644 (file)
@@ -192,6 +192,11 @@ xchk_xattr_actor(
        if (xchk_should_terminate(sc, &error))
                return error;
 
+       if (attr_flags & ~XFS_ATTR_ONDISK_MASK) {
+               xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, args.blkno);
+               return -ECANCELED;
+       }
+
        if (attr_flags & XFS_ATTR_INCOMPLETE) {
                /* Incomplete attr key, just mark the inode for preening. */
                xchk_ino_set_preen(sc, ip->i_ino);
@@ -481,7 +486,6 @@ xchk_xattr_rec(
        xfs_dahash_t                    hash;
        int                             nameidx;
        int                             hdrsize;
-       unsigned int                    badflags;
        int                             error;
 
        ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
@@ -511,10 +515,11 @@ xchk_xattr_rec(
 
        /* Retrieve the entry and check it. */
        hash = be32_to_cpu(ent->hashval);
-       badflags = ~(XFS_ATTR_LOCAL | XFS_ATTR_ROOT | XFS_ATTR_SECURE |
-                       XFS_ATTR_INCOMPLETE);
-       if ((ent->flags & badflags) != 0)
+       if (ent->flags & ~XFS_ATTR_ONDISK_MASK) {
                xchk_da_set_corrupt(ds, level);
+               return 0;
+       }
+
        if (ent->flags & XFS_ATTR_LOCAL) {
                lentry = (struct xfs_attr_leaf_name_local *)
                                (((char *)bp->b_addr) + nameidx);