[PATCH 1/6] xfs_scrub: allow auxiliary pathnames for sandboxing

Darrick J. Wong
2023-12-31T22:55:59Z

In the next patch, we'll tighten up the security on the xfs_scrub
service so that it can't escape. However, sandboxing the service
involves making the host filesystem as inaccessible as possible, with
the filesystem to scrub bind mounted onto a known location within the
sandbox. Hence we need one path for reporting and a new -M argument to
tell scrub what it should actually be trying to open.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
man/man8/xfs_scrub.8 | 9 ++++++++-
scrub/phase1.c | 4 ++--
scrub/vfs.c | 2 +-
scrub/xfs_scrub.c | 11 ++++++++---
scrub/xfs_scrub.h | 5 ++++-
5 files changed, 23 insertions(+), 8 deletions(-)

diff --git a/man/man8/xfs_scrub.8 b/man/man8/xfs_scrub.8
index b9f253e1b07..6154011271e 100644
--- a/man/man8/xfs_scrub.8
+++ b/man/man8/xfs_scrub.8
@@ -4,7 +4,7 @@ xfs_scrub \- check and repair the contents of a mounted XFS filesystem
.SH SYNOPSIS
.B xfs_scrub
[
-.B \-abCemnTvx
+.B \-abCeMmnTvx
]
.I mount-point
.br
@@ -79,6 +79,13 @@ behavior.
.B \-k
Do not call TRIM on the free space.
.TP
+.BI \-M " real-mount-point"
+Open the this path for issuing scrub system calls to the kernel.
+The positional
+.I mount-point
+parameter will be used for displaying informational messages and logging.
+This parameter exists to enable process sandboxing for service mode.
+.TP
.BI \-m " file"
Search this file for mounted filesystems instead of /etc/mtab.
.TP
diff --git a/scrub/phase1.c b/scrub/phase1.c
index 1b3f6e8eb4f..516d929d626 100644
--- a/scrub/phase1.c
+++ b/scrub/phase1.c
@@ -146,7 +146,7 @@ phase1_func(
* CAP_SYS_ADMIN, which we probably need to do anything fancy
* with the (XFS driver) kernel.
*/
- error = -xfd_open(&ctx->mnt, ctx->mntpoint,
+ error = -xfd_open(&ctx->mnt, ctx->actual_mntpoint,
O_RDONLY | O_NOATIME | O_DIRECTORY);
if (error) {
if (error == EPERM)
@@ -199,7 +199,7 @@ _("Not an XFS filesystem."));
return error;
}

- error = path_to_fshandle(ctx->mntpoint, &ctx->fshandle,
+ error = path_to_fshandle(ctx->actual_mntpoint, &ctx->fshandle,
&ctx->fshandle_len);
if (error) {
str_errno(ctx, _("getting fshandle"));
diff --git a/scrub/vfs.c b/scrub/vfs.c
index 22c19485a2d..fca9a4cf356 100644
--- a/scrub/vfs.c
+++ b/scrub/vfs.c
@@ -249,7 +249,7 @@ scan_fs_tree(
goto out_cond;
}

- ret = queue_subdir(ctx, &sft, &wq, ctx->mntpoint, true);
+ ret = queue_subdir(ctx, &sft, &wq, ctx->actual_mntpoint, true);
if (ret) {
str_liberror(ctx, ret, _("queueing directory scan"));
goto out_wq;
diff --git a/scrub/xfs_scrub.c b/scrub/xfs_scrub.c
index 37b95aa1e67..4912333219d 100644
--- a/scrub/xfs_scrub.c
+++ b/scrub/xfs_scrub.c
@@ -725,7 +725,7 @@ main(
pthread_mutex_init(&ctx.lock, NULL);
ctx.mode = SCRUB_MODE_REPAIR;
ctx.error_action = ERRORS_CONTINUE;
- while ((c = getopt(argc, argv, "a:bC:de:km:no:TvxV")) != EOF) {
+ while ((c = getopt(argc, argv, "a:bC:de:kM:m:no:TvxV")) != EOF) {
switch (c) {
case 'a':
ctx.max_errors = cvt_u64(optarg, 10);
@@ -769,6 +769,9 @@ main(
case 'k':
want_fstrim = false;
break;
+ case 'M':
+ ctx.actual_mntpoint = optarg;
+ break;
case 'm':
mtab = optarg;
break;
@@ -823,6 +826,8 @@ main(
usage();

ctx.mntpoint = argv[optind];
+ if (!ctx.actual_mntpoint)
+ ctx.actual_mntpoint = ctx.mntpoint;

stdout_isatty = isatty(STDOUT_FILENO);
stderr_isatty = isatty(STDERR_FILENO);
@@ -840,7 +845,7 @@ main(
return SCRUB_RET_OPERROR;

/* Find the mount record for the passed-in argument. */
- if (stat(argv[optind], &ctx.mnt_sb) < 0) {
+ if (stat(ctx.actual_mntpoint, &ctx.mnt_sb) < 0) {
fprintf(stderr,
_("%s: could not stat: %s: %s\n"),
progname, argv[optind], strerror(errno));
@@ -863,7 +868,7 @@ main(
}

fs_table_initialise(0, NULL, 0, NULL);
- fsp = fs_table_lookup_mount(ctx.mntpoint);
+ fsp = fs_table_lookup_mount(ctx.actual_mntpoint);
if (!fsp) {
fprintf(stderr, _("%s: Not a XFS mount point.\n"),
ctx.mntpoint);
diff --git a/scrub/xfs_scrub.h b/scrub/xfs_scrub.h
index 7d48f4bad9c..b0aa9fcc67b 100644
--- a/scrub/xfs_scrub.h
+++ b/scrub/xfs_scrub.h
@@ -38,9 +38,12 @@ enum error_action {
struct scrub_ctx {
/* Immutable scrub state. */

- /* Strings we need for presentation */
+ /* Mountpoint we use for presentation */
char *mntpoint;

+ /* Actual VFS path to the filesystem */
+ char *actual_mntpoint;
+
/* Mountpoint info */
struct stat mnt_sb;
struct statvfs mnt_sv;