]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_repair: allow '/' in attribute names
authorEric Sandeen <sandeen@redhat.com>
Mon, 28 Jan 2019 19:03:03 +0000 (13:03 -0600)
committerEric Sandeen <sandeen@redhat.com>
Mon, 28 Jan 2019 19:03:03 +0000 (13:03 -0600)
For some reason, since the earliest days of XFS, a '/' character
in an extended attribute name has been treated as corruption by
xfs_repair.  This despite nothing in other userspace tools or the
kernel having this restriction.

My best guess is that this was an unintentional leftover from
common code between dirs & attrs in the "da" code, and there has
never been a good reason for it.

Since userspace and kernelspace allow such a name to be set,
listed, and read, it seems wrong to flag it as corruption.
So, make this test conditional on whether we're validating a name
in a dir, as opposed to the name of an attr.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
repair/attr_repair.c
repair/da_util.c
repair/da_util.h
repair/dir2.c

index 1d04500ffe2f79997b0980196eb7e29eabdede70..5ad81c091ea4d3317d1288ee07166ea6e700a52b 100644 (file)
@@ -122,6 +122,14 @@ set_da_freemap(xfs_mount_t *mp, da_freemap_t *map, int start, int stop)
  * fork being emptied and put in shortform format.
  */
 
+static int
+attr_namecheck(
+       uint8_t *name,
+       int     length)
+{
+       return namecheck((char *)name, length, false);
+}
+
 /*
  * This routine just checks what security needs are for attribute values
  * only called when root flag is set, otherwise these names could exist in
@@ -292,11 +300,9 @@ process_shortform_attr(
                        }
                }
 
-               /* namecheck checks for / and null terminated for file names.
-                * attributes names currently follow the same rules.
-               */
-               if (namecheck((char *)&currententry->nameval[0],
-                                               currententry->namelen))  {
+               /* namecheck checks for null chars in attr names. */
+               if (attr_namecheck(currententry->nameval,
+                                               currententry->namelen)) {
                        do_warn(
        _("entry contains illegal character in shortform attribute name\n"));
                        junkit = 1;
@@ -458,7 +464,7 @@ process_leaf_attr_local(
        xfs_attr_leaf_name_local_t *local;
 
        local = xfs_attr3_leaf_name_local(leaf, i);
-       if (local->namelen == 0 || namecheck((char *)&local->nameval[0],
+       if (local->namelen == 0 || attr_namecheck(local->nameval,
                                                        local->namelen)) {
                do_warn(
        _("attribute entry %d in attr block %u, inode %" PRIu64 " has bad name (namelen = %d)\n"),
@@ -513,7 +519,7 @@ process_leaf_attr_remote(
 
        remotep = xfs_attr3_leaf_name_remote(leaf, i);
 
-       if (remotep->namelen == 0 || namecheck((char *)&remotep->name[0],
+       if (remotep->namelen == 0 || attr_namecheck(remotep->name,
                                                remotep->namelen) ||
                        be32_to_cpu(entry->hashval) !=
                                libxfs_da_hashname((unsigned char *)&remotep->name[0],
index 1450767fba08931771141f15db5fca5412ff14db..c5e690c30b78a73e253f8e1f4dca989724c33647 100644 (file)
 #include "da_util.h"
 
 /*
- * takes a name and length (name need not be null-terminated)
- * and returns 1 if the name contains a '/' or a \0, returns 0
- * otherwise
+ * Takes a name and length (name need not be null-terminated) and whether
+ * we are checking a dir (as opposed to an attr).
+ * Returns 1 if the name contains a NUL or if a directory entry contains a '/'.
+ * Returns 0 if the name checks out.
  */
 int
-namecheck(char *name, int length)
+namecheck(
+       char    *name,
+       int     length,
+       bool    isadir)
 {
-       char *c;
-       int i;
+       char    *c;
+       int     i;
 
        ASSERT(length < MAXNAMELEN);
 
        for (c = name, i = 0; i < length; i++, c++) {
-               if (*c == '/' || *c == '\0')
+               if (isadir && *c == '/')
+                       return 0;
+               if (*c == '\0')
                        return 1;
        }
 
index d36dfd0d5f360b8fd4d1b9c927d1500b13badcf5..041dff748d8e758689883cd907b59a6ce259c740 100644 (file)
@@ -27,7 +27,8 @@ typedef struct da_bt_cursor {
 int
 namecheck(
        char            *name,
-       int             length);
+       int             length,
+       bool            isadir);
 
 struct xfs_buf *
 da_read_buf(
index e67ec590c0917698fcab4df412b52cba13a6505f..094ecb3deb2aa66237c48883f73fe7ba3d96bfdd 100644 (file)
@@ -44,6 +44,14 @@ _("malloc failed (%zu bytes) dir2_add_badlist:ino %" PRIu64 "\n"),
        l->ino = ino;
 }
 
+static int
+dir_namecheck(
+       uint8_t *name,
+       int     length)
+{
+       return namecheck((char *)name, length, true);
+}
+
 int
 dir2_is_badino(
        xfs_ino_t       ino)
@@ -310,7 +318,7 @@ _("entry #%d %s in shortform dir %" PRIu64),
                 * the length value is stored in a byte
                 * so it can't be too big, it can only wrap
                 */
-               if (namecheck((char *)&sfep->name[0], namelen))  {
+               if (dir_namecheck(sfep->name, namelen)) {
                        /*
                         * junk entry
                         */
@@ -781,7 +789,7 @@ _("\twould clear inode number in entry at offset %" PRIdPTR "...\n"),
                 * during phase 4.
                 */
                junkit = dep->name[0] == '/';
-               nm_illegal = namecheck((char *)dep->name, dep->namelen);
+               nm_illegal = dir_namecheck(dep->name, dep->namelen);
                if (ino_discovery && nm_illegal) {
                        do_warn(
 _("entry at block %u offset %" PRIdPTR " in directory inode %" PRIu64 " has illegal name \"%*.*s\": "),