From: "Darrick J. Wong" <darrick.wong@oracle.com>
To: sandeen@redhat.com, darrick.wong@oracle.com
Cc: linux-xfs@vger.kernel.org
Subject: [PATCH 17/27] xfs_scrub: warn about suspicious characters in directory/xattr names
Date: Fri, 05 Jan 2018 17:53:12 -0800 [thread overview]
Message-ID: <151520359246.2027.3615786246549955688.stgit@magnolia> (raw)
In-Reply-To: <151520348769.2027.9860697266310422360.stgit@magnolia>
From: Darrick J. Wong <darrick.wong@oracle.com>
Look for control characters and punctuation that interfere with shell
globbing in directory entry names and extended attribute key names.
Technically these aren't filesystem corruptions because names are
arbitrary sequences of bytes, but they've been known to cause problems
in the Unix environment so warn if we see them.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
configure.ac | 2 +
debian/control | 2 -
include/builddefs.in | 1
m4/Makefile | 1
m4/package_attr.m4 | 23 ++++++
scrub/Makefile | 6 ++
scrub/common.c | 54 ++++++++++++++
scrub/common.h | 4 +
scrub/phase5.c | 192 ++++++++++++++++++++++++++++++++++++++++++++++++++
scrub/xfs_scrub.h | 1
10 files changed, 285 insertions(+), 1 deletion(-)
create mode 100644 m4/package_attr.m4
diff --git a/configure.ac b/configure.ac
index 796a91b..e2e3f66 100644
--- a/configure.ac
+++ b/configure.ac
@@ -166,6 +166,8 @@ AC_HAVE_STATFS_FLAGS
AC_HAVE_MAP_SYNC
AC_HAVE_DEVMAPPER
AC_HAVE_MALLINFO
+AC_PACKAGE_WANT_ATTRIBUTES_H
+AC_HAVE_LIBATTR
if test "$enable_blkid" = yes; then
AC_HAVE_BLKID_TOPO
diff --git a/debian/control b/debian/control
index f5980b2..f664a6b 100644
--- a/debian/control
+++ b/debian/control
@@ -3,7 +3,7 @@ Section: admin
Priority: optional
Maintainer: XFS Development Team <linux-xfs@vger.kernel.org>
Uploaders: Nathan Scott <nathans@debian.org>, Anibal Monsalve Salazar <anibal@debian.org>
-Build-Depends: uuid-dev, dh-autoreconf, debhelper (>= 5), gettext, libtool, libreadline-gplv2-dev | libreadline5-dev, libblkid-dev (>= 2.17), linux-libc-dev, libdevmapper-dev
+Build-Depends: uuid-dev, dh-autoreconf, debhelper (>= 5), gettext, libtool, libreadline-gplv2-dev | libreadline5-dev, libblkid-dev (>= 2.17), linux-libc-dev, libdevmapper-dev, libattr1-dev
Standards-Version: 3.9.1
Homepage: https://xfs.wiki.kernel.org/
diff --git a/include/builddefs.in b/include/builddefs.in
index 28cf0d8..cc1b7e2 100644
--- a/include/builddefs.in
+++ b/include/builddefs.in
@@ -120,6 +120,7 @@ HAVE_STATFS_FLAGS = @have_statfs_flags@
HAVE_MAP_SYNC = @have_map_sync@
HAVE_DEVMAPPER = @have_devmapper@
HAVE_MALLINFO = @have_mallinfo@
+HAVE_LIBATTR = @have_libattr@
GCCFLAGS = -funsigned-char -fno-strict-aliasing -Wall
# -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-decl
diff --git a/m4/Makefile b/m4/Makefile
index 77f2edd..d5f1d2f 100644
--- a/m4/Makefile
+++ b/m4/Makefile
@@ -17,6 +17,7 @@ LSRCFILES = \
package_blkid.m4 \
package_devmapper.m4 \
package_globals.m4 \
+ package_attr.m4 \
package_libcdev.m4 \
package_pthread.m4 \
package_sanitizer.m4 \
diff --git a/m4/package_attr.m4 b/m4/package_attr.m4
new file mode 100644
index 0000000..4324923
--- /dev/null
+++ b/m4/package_attr.m4
@@ -0,0 +1,23 @@
+AC_DEFUN([AC_PACKAGE_WANT_ATTRIBUTES_H],
+ [
+ AC_CHECK_HEADERS(attr/attributes.h)
+ ])
+
+#
+# Check if we have a ATTR_ROOT flag and libattr structures
+#
+AC_DEFUN([AC_HAVE_LIBATTR],
+ [ AC_MSG_CHECKING([for struct attrlist_cursor])
+ AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <attr/attributes.h>
+ ], [
+struct attrlist_cursor *cur;
+struct attrlist *list;
+struct attrlist_ent *ent;
+int flags = ATTR_ROOT;
+ ], have_libattr=yes
+ AC_MSG_RESULT(yes),
+ AC_MSG_RESULT(no))
+ AC_SUBST(have_libattr)
+ ])
diff --git a/scrub/Makefile b/scrub/Makefile
index adb868e..67ac6af 100644
--- a/scrub/Makefile
+++ b/scrub/Makefile
@@ -53,8 +53,14 @@ ifeq ($(HAVE_SYNCFS),yes)
LCFLAGS += -DHAVE_SYNCFS
endif
+ifeq ($(HAVE_LIBATTR),yes)
+LCFLAGS += -DHAVE_LIBATTR
+endif
+
default: depend $(LTCOMMAND)
+phase5.o: $(TOPDIR)/include/builddefs
+
include $(BUILDRULES)
install: default $(INSTALL_SCRUB)
diff --git a/scrub/common.c b/scrub/common.c
index eb602a8..b02e7fc 100644
--- a/scrub/common.c
+++ b/scrub/common.c
@@ -339,3 +339,57 @@ background_sleep(void)
tv.tv_nsec = time % 1000000;
nanosleep(&tv, NULL);
}
+
+/*
+ * Return the input string with non-printing bytes escaped.
+ * Caller must free the buffer.
+ */
+char *
+string_escape(
+ const char *in)
+{
+ char *str;
+ const char *p;
+ char *q;
+ int x;
+
+ str = malloc(strlen(in) * 4);
+ if (!str)
+ return NULL;
+ for (p = in, q = str; *p != '\0'; p++) {
+ if (isprint(*p)) {
+ *q = *p;
+ q++;
+ } else {
+ x = sprintf(q, "\\x%02x", *p);
+ q += x;
+ }
+ }
+ *q = '\0';
+ return str;
+}
+
+/*
+ * Record another naming warning, and decide if it's worth
+ * complaining about.
+ */
+bool
+should_warn_about_name(
+ struct scrub_ctx *ctx)
+{
+ bool whine;
+ bool res;
+
+ pthread_mutex_lock(&ctx->lock);
+ ctx->naming_warnings++;
+ whine = ctx->naming_warnings == TOO_MANY_NAME_WARNINGS;
+ res = ctx->naming_warnings < TOO_MANY_NAME_WARNINGS;
+ pthread_mutex_unlock(&ctx->lock);
+
+ if (whine && !(debug || verbose))
+ str_info(ctx, ctx->mntpoint,
+_("More than %u naming warnings, shutting up."),
+ TOO_MANY_NAME_WARNINGS);
+
+ return debug || verbose || res;
+}
diff --git a/scrub/common.h b/scrub/common.h
index 81e83c2..e5a13d8 100644
--- a/scrub/common.h
+++ b/scrub/common.h
@@ -72,5 +72,9 @@ static inline int syncfs(int fd)
bool find_mountpoint(char *mtab, struct scrub_ctx *ctx);
void background_sleep(void);
+char *string_escape(const char *in);
+
+#define TOO_MANY_NAME_WARNINGS 10000
+bool should_warn_about_name(struct scrub_ctx *ctx);
#endif /* XFS_SCRUB_COMMON_H_ */
diff --git a/scrub/phase5.c b/scrub/phase5.c
index 0b161e3..98d30f8 100644
--- a/scrub/phase5.c
+++ b/scrub/phase5.c
@@ -20,10 +20,15 @@
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
+#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
+#ifdef HAVE_LIBATTR
+# include <attr/attributes.h>
+#endif
#include "xfs.h"
+#include "handle.h"
#include "path.h"
#include "workqueue.h"
#include "xfs_scrub.h"
@@ -34,6 +39,181 @@
/* Phase 5: Check directory connectivity. */
/*
+ * Warn about problematic bytes in a directory/attribute name. That means
+ * terminal control characters and escape sequences, since that could be used
+ * to do something naughty to the user's computer and/or break scripts. XFS
+ * doesn't consider any byte sequence invalid, so don't flag these as errors.
+ */
+static bool
+xfs_scrub_check_name(
+ struct scrub_ctx *ctx,
+ const char *descr,
+ const char *namedescr,
+ const char *name)
+{
+ const char *p;
+ bool bad = false;
+ char *errname;
+
+ /* Complain about zero length names. */
+ if (*name == '\0' && should_warn_about_name(ctx)) {
+ str_warn(ctx, descr, _("Zero length name found."));
+ return true;
+ }
+
+ /* control characters */
+ for (p = name; *p; p++) {
+ if ((*p >= 1 && *p <= 31) || *p == 127) {
+ bad = true;
+ break;
+ }
+ }
+
+ if (bad && should_warn_about_name(ctx)) {
+ errname = string_escape(name);
+ if (!errname) {
+ str_errno(ctx, descr);
+ return false;
+ }
+ str_info(ctx, descr,
+_("Control character found in %s name \"%s\"."),
+ namedescr, errname);
+ free(errname);
+ }
+
+ return true;
+}
+
+/*
+ * Iterate a directory looking for filenames with problematic
+ * characters.
+ */
+static bool
+xfs_scrub_scan_dirents(
+ struct scrub_ctx *ctx,
+ const char *descr,
+ int *fd)
+{
+ DIR *dir;
+ struct dirent *dentry;
+ bool moveon = true;
+
+ dir = fdopendir(*fd);
+ if (!dir) {
+ str_errno(ctx, descr);
+ goto out;
+ }
+ *fd = -1; /* closedir will close *fd for us */
+
+ dentry = readdir(dir);
+ while (dentry) {
+ moveon = xfs_scrub_check_name(ctx, descr, _("directory"),
+ dentry->d_name);
+ if (!moveon)
+ break;
+ dentry = readdir(dir);
+ }
+
+ closedir(dir);
+out:
+ return moveon;
+}
+
+#ifdef HAVE_LIBATTR
+/* Routines to scan all of an inode's xattrs for name problems. */
+struct xfs_attr_ns {
+ int flags;
+ const char *name;
+};
+
+static const struct xfs_attr_ns attr_ns[] = {
+ {0, "user"},
+ {ATTR_ROOT, "system"},
+ {ATTR_SECURE, "secure"},
+ {0, NULL},
+};
+
+/*
+ * Check all the xattr names in a particular namespace of a file handle
+ * for Unicode normalization problems or collisions.
+ */
+static bool
+xfs_scrub_scan_fhandle_namespace_xattrs(
+ struct scrub_ctx *ctx,
+ const char *descr,
+ struct xfs_handle *handle,
+ const struct xfs_attr_ns *attr_ns)
+{
+ struct attrlist_cursor cur;
+ char attrbuf[XFS_XATTR_LIST_MAX];
+ char keybuf[NAME_MAX + 1];
+ struct attrlist *attrlist = (struct attrlist *)attrbuf;
+ struct attrlist_ent *ent;
+ bool moveon = true;
+ int i;
+ int error;
+
+ memset(attrbuf, 0, XFS_XATTR_LIST_MAX);
+ memset(&cur, 0, sizeof(cur));
+ memset(keybuf, 0, NAME_MAX + 1);
+ error = attr_list_by_handle(handle, sizeof(*handle), attrbuf,
+ XFS_XATTR_LIST_MAX, attr_ns->flags, &cur);
+ while (!error) {
+ /* Examine the xattrs. */
+ for (i = 0; i < attrlist->al_count; i++) {
+ ent = ATTR_ENTRY(attrlist, i);
+ snprintf(keybuf, NAME_MAX, "%s.%s", attr_ns->name,
+ ent->a_name);
+ moveon = xfs_scrub_check_name(ctx, descr,
+ _("extended attribute"), keybuf);
+ if (!moveon)
+ goto out;
+ }
+
+ if (!attrlist->al_more)
+ break;
+ error = attr_list_by_handle(handle, sizeof(*handle), attrbuf,
+ XFS_XATTR_LIST_MAX, attr_ns->flags, &cur);
+ }
+ if (error && errno != ESTALE)
+ str_errno(ctx, descr);
+out:
+ return moveon;
+}
+
+/*
+ * Check all the xattr names in all the xattr namespaces for problematic
+ * characters.
+ */
+static bool
+xfs_scrub_scan_fhandle_xattrs(
+ struct scrub_ctx *ctx,
+ const char *descr,
+ struct xfs_handle *handle)
+{
+ const struct xfs_attr_ns *ns;
+ bool moveon = true;
+
+ for (ns = attr_ns; ns->name; ns++) {
+ moveon = xfs_scrub_scan_fhandle_namespace_xattrs(ctx, descr,
+ handle, ns);
+ if (!moveon)
+ break;
+ }
+ return moveon;
+}
+#else
+static inline bool
+xfs_scrub_scan_fhandle_xattrs(
+ struct scrub_ctx *ctx,
+ const char *descr,
+ struct xfs_handle *handle)
+{
+ return true;
+}
+#endif /* HAVE_LIBATTR */
+
+/*
* Verify the connectivity of the directory tree.
* We know that the kernel's open-by-handle function will try to reconnect
* parents of an opened directory, so we'll accept that as sufficient.
@@ -58,6 +238,11 @@ xfs_scrub_connections(
(uint64_t)bstat->bs_ino, agno, agino);
background_sleep();
+ /* Warn about naming problems in xattrs. */
+ moveon = xfs_scrub_scan_fhandle_xattrs(ctx, descr, handle);
+ if (!moveon)
+ goto out;
+
/* Open the dir, let the kernel try to reconnect it to the root. */
if (S_ISDIR(bstat->bs_mode)) {
fd = xfs_open_handle(handle);
@@ -69,6 +254,13 @@ xfs_scrub_connections(
}
}
+ /* Warn about naming problems in the directory entries. */
+ if (fd >= 0 && S_ISDIR(bstat->bs_mode)) {
+ moveon = xfs_scrub_scan_dirents(ctx, descr, &fd);
+ if (!moveon)
+ goto out;
+ }
+
out:
if (fd >= 0)
close(fd);
diff --git a/scrub/xfs_scrub.h b/scrub/xfs_scrub.h
index c9f53d8..66003e4 100644
--- a/scrub/xfs_scrub.h
+++ b/scrub/xfs_scrub.h
@@ -90,6 +90,7 @@ struct scrub_ctx {
unsigned long long errors_found;
unsigned long long warnings_found;
unsigned long long inodes_checked;
+ unsigned long long naming_warnings;
bool need_repair;
bool preen_triggers[XFS_SCRUB_TYPE_NR];
};
next prev parent reply other threads:[~2018-01-06 1:58 UTC|newest]
Thread overview: 61+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-01-06 1:51 [PATCH v11 00/27] xfsprogs: online scrub/repair support Darrick J. Wong
2018-01-06 1:51 ` [PATCH 01/27] xfs_scrub: create online filesystem scrub program Darrick J. Wong
2018-01-12 0:16 ` Eric Sandeen
2018-01-12 1:08 ` Darrick J. Wong
2018-01-12 1:07 ` Eric Sandeen
2018-01-12 1:10 ` Darrick J. Wong
2018-01-06 1:51 ` [PATCH 02/27] xfs_scrub: common error handling Darrick J. Wong
2018-01-12 1:15 ` Eric Sandeen
2018-01-12 1:23 ` Darrick J. Wong
2018-01-06 1:51 ` [PATCH 03/27] xfs_scrub: set up command line argument parsing Darrick J. Wong
2018-01-11 23:39 ` Eric Sandeen
2018-01-12 1:53 ` Darrick J. Wong
2018-01-12 1:30 ` Eric Sandeen
2018-01-12 2:03 ` Darrick J. Wong
2018-01-06 1:51 ` [PATCH 04/27] xfs_scrub: dispatch the various phases of the scrub program Darrick J. Wong
2018-01-06 1:51 ` [PATCH 05/27] xfs_scrub: figure out how many threads we're going to need Darrick J. Wong
2018-01-06 1:52 ` [PATCH 06/27] xfs_scrub: create an abstraction for a block device Darrick J. Wong
2018-01-11 23:24 ` Eric Sandeen
2018-01-11 23:59 ` Darrick J. Wong
2018-01-12 0:04 ` Eric Sandeen
2018-01-12 1:27 ` Darrick J. Wong
2018-01-06 1:52 ` [PATCH 07/27] xfs_scrub: find XFS filesystem geometry Darrick J. Wong
2018-01-06 1:52 ` [PATCH 08/27] xfs_scrub: add inode iteration functions Darrick J. Wong
2018-01-06 1:52 ` [PATCH 09/27] xfs_scrub: add space map " Darrick J. Wong
2018-01-06 1:52 ` [PATCH 10/27] xfs_scrub: add file " Darrick J. Wong
2018-01-11 23:19 ` Eric Sandeen
2018-01-12 0:24 ` Darrick J. Wong
2018-01-06 1:52 ` [PATCH 11/27] xfs_scrub: filesystem counter collection functions Darrick J. Wong
2018-01-06 1:52 ` [PATCH 12/27] xfs_scrub: wrap the scrub ioctl Darrick J. Wong
2018-01-11 23:12 ` Eric Sandeen
2018-01-12 0:28 ` Darrick J. Wong
2018-01-06 1:52 ` [PATCH 13/27] xfs_scrub: scan filesystem and AG metadata Darrick J. Wong
2018-01-06 1:52 ` [PATCH 14/27] xfs_scrub: thread-safe stats counter Darrick J. Wong
2018-01-06 1:53 ` [PATCH 15/27] xfs_scrub: scan inodes Darrick J. Wong
2018-01-06 1:53 ` [PATCH 16/27] xfs_scrub: check directory connectivity Darrick J. Wong
2018-01-06 1:53 ` Darrick J. Wong [this message]
2018-01-06 1:53 ` [PATCH 18/27] xfs_scrub: warn about normalized Unicode name collisions Darrick J. Wong
2018-01-16 23:52 ` Eric Sandeen
2018-01-16 23:57 ` Eric Sandeen
2018-01-16 23:59 ` Darrick J. Wong
2018-01-06 1:53 ` [PATCH 19/27] xfs_scrub: create a bitmap data structure Darrick J. Wong
2018-01-06 1:53 ` [PATCH 20/27] xfs_scrub: create infrastructure to read verify data blocks Darrick J. Wong
2018-01-06 1:53 ` [PATCH 21/27] xfs_scrub: scrub file " Darrick J. Wong
2018-01-11 23:25 ` Eric Sandeen
2018-01-12 0:29 ` Darrick J. Wong
2018-01-06 1:53 ` [PATCH 22/27] xfs_scrub: optionally use SCSI READ VERIFY commands to scrub data blocks on disk Darrick J. Wong
2018-01-06 1:53 ` [PATCH 23/27] xfs_scrub: check summary counters Darrick J. Wong
2018-01-06 1:54 ` [PATCH 24/27] xfs_scrub: fstrim the free areas if there are no errors on the filesystem Darrick J. Wong
2018-01-16 22:07 ` Eric Sandeen
2018-01-16 22:23 ` Darrick J. Wong
2018-01-06 1:54 ` [PATCH 25/27] xfs_scrub: progress indicator Darrick J. Wong
2018-01-11 23:27 ` Eric Sandeen
2018-01-12 0:32 ` Darrick J. Wong
2018-01-06 1:54 ` [PATCH 26/27] xfs_scrub: create a script to scrub all xfs filesystems Darrick J. Wong
2018-01-06 1:54 ` [PATCH 27/27] xfs_scrub: integrate services with systemd Darrick J. Wong
2018-01-06 3:50 ` [PATCH 07/27] xfs_scrub: find XFS filesystem geometry Darrick J. Wong
2018-01-12 4:17 ` [PATCH v11 00/27] xfsprogs: online scrub/repair support Eric Sandeen
2018-01-17 1:31 ` Darrick J. Wong
2018-01-16 19:21 ` [PATCH 28/27] xfs_scrub: wire up repair ioctl Darrick J. Wong
2018-01-16 19:21 ` [PATCH 29/27] xfs_scrub: schedule and manage repairs to the filesystem Darrick J. Wong
-- strict thread matches above, loose matches on Subject: below --
2017-11-17 21:00 [PATCH v10 00/27] xfsprogs-4.15: online scrub/repair support Darrick J. Wong
2017-11-17 21:01 ` [PATCH 17/27] xfs_scrub: warn about suspicious characters in directory/xattr names Darrick J. Wong
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=151520359246.2027.3615786246549955688.stgit@magnolia \
--to=darrick.wong@oracle.com \
--cc=linux-xfs@vger.kernel.org \
--cc=sandeen@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).