]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs: enforce one namespace per attribute
authorDarrick J. Wong <djwong@kernel.org>
Mon, 29 Jul 2024 23:22:44 +0000 (16:22 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 30 Jul 2024 00:01:02 +0000 (17:01 -0700)
Source kernel commit: ea0b3e814741fb64e7785b564ea619578058e0b0

Create a standardized helper function to enforce one namespace bit per
extended attribute, and refactor all the open-coded hweight logic.  This
function is not a static inline to avoid porting hassles in userspace.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
libxfs/xfs_attr.c
libxfs/xfs_attr.h
libxfs/xfs_attr_leaf.c
repair/attr_repair.c

index 26674116f254aec7b084ab3aac64cc604e689941..e0a3bc7028bc41de65c5f677c53753d54d271e71 100644 (file)
@@ -1530,12 +1530,23 @@ out_release:
        return error;
 }
 
+/* Enforce that there is at most one namespace bit per attr. */
+inline bool xfs_attr_check_namespace(unsigned int attr_flags)
+{
+       return hweight32(attr_flags & XFS_ATTR_NSP_ONDISK_MASK) < 2;
+}
+
 /* Returns true if the attribute entry name is valid. */
 bool
 xfs_attr_namecheck(
+       unsigned int    attr_flags,
        const void      *name,
        size_t          length)
 {
+       /* Only one namespace bit allowed. */
+       if (!xfs_attr_check_namespace(attr_flags))
+               return false;
+
        /*
         * MAXNAMELEN includes the trailing null, but (name/length) leave it
         * out, so use >= for the length check.
index 79b457adb7bda0acae237ddaf30f17735825bdbb..cd106b0a424fa145ef7a704637d5cb62dd480647 100644 (file)
@@ -560,7 +560,9 @@ enum xfs_attr_update {
 int xfs_attr_set(struct xfs_da_args *args, enum xfs_attr_update op);
 int xfs_attr_set_iter(struct xfs_attr_intent *attr);
 int xfs_attr_remove_iter(struct xfs_attr_intent *attr);
-bool xfs_attr_namecheck(const void *name, size_t length);
+bool xfs_attr_check_namespace(unsigned int attr_flags);
+bool xfs_attr_namecheck(unsigned int attr_flags, const void *name,
+               size_t length);
 int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
 void xfs_init_attr_trans(struct xfs_da_args *args, struct xfs_trans_res *tres,
                         unsigned int *total);
index 47f2836fb711c687c0c1d9df2761051adbfcfeee..346f0127dbc973e58d57367ccbdc951d6497d5bc 100644 (file)
@@ -947,6 +947,11 @@ xfs_attr_shortform_to_leaf(
                nargs.hashval = xfs_da_hashname(sfe->nameval,
                                                sfe->namelen);
                nargs.attr_filter = sfe->flags & XFS_ATTR_NSP_ONDISK_MASK;
+               if (!xfs_attr_check_namespace(sfe->flags)) {
+                       xfs_da_mark_sick(args);
+                       error = -EFSCORRUPTED;
+                       goto out;
+               }
                error = xfs_attr3_leaf_lookup_int(bp, &nargs); /* set a->index */
                ASSERT(error == -ENOATTR);
                error = xfs_attr3_leaf_add(bp, &nargs);
@@ -1060,7 +1065,7 @@ xfs_attr_shortform_verify(
                 * one namespace flag per xattr, so we can just count the
                 * bits (i.e. hweight) here.
                 */
-               if (hweight8(sfep->flags & XFS_ATTR_NSP_ONDISK_MASK) > 1)
+               if (!xfs_attr_check_namespace(sfep->flags))
                        return __this_address;
 
                sfep = next_sfep;
index 206a97d6684ce7e22209d2266445b0faa90683f0..0f2f7a284bdd72f3c0eed3da14f5c5a11a878c8d 100644 (file)
@@ -292,7 +292,8 @@ process_shortform_attr(
                }
 
                /* namecheck checks for null chars in attr names. */
-               if (!libxfs_attr_namecheck(currententry->nameval,
+               if (!libxfs_attr_namecheck(currententry->flags,
+                                          currententry->nameval,
                                           currententry->namelen)) {
                        do_warn(
        _("entry contains illegal character in shortform attribute name\n"));
@@ -473,7 +474,7 @@ process_leaf_attr_local(
 
        local = xfs_attr3_leaf_name_local(leaf, i);
        if (local->namelen == 0 ||
-           !libxfs_attr_namecheck(local->nameval,
+           !libxfs_attr_namecheck(entry->flags, local->nameval,
                                   local->namelen)) {
                do_warn(
        _("attribute entry %d in attr block %u, inode %" PRIu64 " has bad name (namelen = %d)\n"),
@@ -529,7 +530,7 @@ process_leaf_attr_remote(
        remotep = xfs_attr3_leaf_name_remote(leaf, i);
 
        if (remotep->namelen == 0 ||
-           !libxfs_attr_namecheck(remotep->name,
+           !libxfs_attr_namecheck(entry->flags, remotep->name,
                                   remotep->namelen) ||
            be32_to_cpu(entry->hashval) !=
                        libxfs_da_hashname((unsigned char *)&remotep->name[0],