* [PATCH] xfstests: 313,314: user namespace uid/gids in inode, ACL
@ 2013-06-25 19:34 Dwight Engen
2013-06-26 1:09 ` Dave Chinner
0 siblings, 1 reply; 14+ messages in thread
From: Dwight Engen @ 2013-06-25 19:34 UTC (permalink / raw)
To: xfs
These tests verify that the uid/gids in an inode and in ACLs get translated
from/to a user namespace to/from disk correctly.
I had to use getfacl instead of the chacl -l because I need numeric uids
to make the output consistent.
A new program nsexec was added to facilitate creating/entering a user
namespace for testing. The orignal source for the program is
https://lwn.net/Articles/539940. I added the -s option to become "root"
in the user namespace.
Tested against btrfs, ext4, and xfs with my proposed user namespace changes.
Signed-off-by: Dwight Engen <dwight.engen@oracle.com>
---
.gitignore | 1 +
common/attr | 14 +++
src/Makefile | 2 +-
src/nsexec.c | 239 ++++++++++++++++++++++++++++++++++++++++++++++++++
tests/generic/313 | 107 ++++++++++++++++++++++
tests/generic/313.out | 20 +++++
tests/generic/314 | 102 +++++++++++++++++++++
tests/generic/314.out | 51 +++++++++++
tests/generic/group | 2 +
9 files changed, 537 insertions(+), 1 deletion(-)
create mode 100644 src/nsexec.c
create mode 100755 tests/generic/313
create mode 100644 tests/generic/313.out
create mode 100755 tests/generic/314
create mode 100644 tests/generic/314.out
diff --git a/.gitignore b/.gitignore
index 5aa68c3..fc5050a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -63,6 +63,7 @@
/src/mmapcat
/src/multi_open_unlink
/src/nametest
+/src/nsexec
/src/permname
/src/preallo_rw_pattern_reader
/src/preallo_rw_pattern_writer
diff --git a/common/attr b/common/attr
index e5070bf..4a3ac9e 100644
--- a/common/attr
+++ b/common/attr
@@ -54,6 +54,20 @@ _acl_filter_id()
-e "s/ $acl3 / id3 /"
}
+_getfacl_filter_id()
+{
+ sed \
+ -e "s/user:$acl1/user:id1/" \
+ -e "s/user:$acl2/user:id2/" \
+ -e "s/user:$acl3/user:id3/" \
+ -e "s/group:$acl1/group:id1/" \
+ -e "s/group:$acl2/group:id2/" \
+ -e "s/group:$acl3/group:id3/" \
+ -e "s/: $acl1/: id1/" \
+ -e "s/: $acl2/: id2/" \
+ -e "s/: $acl3/: id3/"
+}
+
# filtered ls
#
_acl_ls()
diff --git a/src/Makefile b/src/Makefile
index c18ffc9..4eabdc7 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -18,7 +18,7 @@ LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \
locktest unwritten_mmap bulkstat_unlink_test t_stripealign \
bulkstat_unlink_test_modified t_dir_offset t_futimens t_immutable \
stale_handle pwrite_mmap_blocked t_dir_offset2 seek_sanity_test \
- seek_copy_test t_readdir_1 t_readdir_2 fsync-tester
+ seek_copy_test t_readdir_1 t_readdir_2 fsync-tester nsexec
SUBDIRS =
diff --git a/src/nsexec.c b/src/nsexec.c
new file mode 100644
index 0000000..f033b1a
--- /dev/null
+++ b/src/nsexec.c
@@ -0,0 +1,239 @@
+/* userns_child_exec.c
+
+ Copyright 2013, Michael Kerrisk
+ Licensed under GNU General Public License v2 or later
+
+ Create a child process that executes a shell command in new
+ namespace(s); allow UID and GID mappings to be specified when
+ creating a user namespace.
+*/
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <sched.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+
+/* A simple error-handling function: print an error message based
+ on the value in 'errno' and terminate the calling process */
+
+#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
+ } while (0)
+
+struct child_args {
+ char **argv; /* Command to be executed by child, with arguments */
+ int pipe_fd[2]; /* Pipe used to synchronize parent and child */
+};
+
+static int verbose, setid;
+
+static void
+usage(char *pname)
+{
+ fprintf(stderr, "Usage: %s [options] cmd [arg...]\n\n", pname);
+ fprintf(stderr, "Create a child process that executes a shell command "
+ "in a new user namespace,\n"
+ "and possibly also other new namespace(s).\n\n");
+ fprintf(stderr, "Options can be:\n\n");
+#define fpe(str) fprintf(stderr, " %s", str);
+ fpe("-i New IPC namespace\n");
+ fpe("-m New mount namespace\n");
+ fpe("-n New network namespace\n");
+ fpe("-p New PID namespace\n");
+ fpe("-u New UTS namespace\n");
+ fpe("-U New user namespace\n");
+ fpe("-M uid_map Specify UID map for user namespace\n");
+ fpe("-G gid_map Specify GID map for user namespace\n");
+ fpe(" If -M or -G is specified, -U is required\n");
+ fpe("-s Set uid/gid to 0 in the new user namespace\n");
+ fpe("-v Display verbose messages\n");
+ fpe("\n");
+ fpe("Map strings for -M and -G consist of records of the form:\n");
+ fpe("\n");
+ fpe(" ID-inside-ns ID-outside-ns len\n");
+ fpe("\n");
+ fpe("A map string can contain multiple records, separated by commas;\n");
+ fpe("the commas are replaced by newlines before writing to map files.\n");
+
+ exit(EXIT_FAILURE);
+}
+
+/* Update the mapping file 'map_file', with the value provided in
+ 'mapping', a string that defines a UID or GID mapping. A UID or
+ GID mapping consists of one or more newline-delimited records
+ of the form:
+
+ ID_inside-ns ID-outside-ns length
+
+ Requiring the user to supply a string that contains newlines is
+ of course inconvenient for command-line use. Thus, we permit the
+ use of commas to delimit records in this string, and replace them
+ with newlines before writing the string to the file. */
+
+static void
+update_map(char *mapping, char *map_file)
+{
+ int fd, j;
+ size_t map_len; /* Length of 'mapping' */
+
+ /* Replace commas in mapping string with newlines */
+
+ map_len = strlen(mapping);
+ for (j = 0; j < map_len; j++)
+ if (mapping[j] == ',')
+ mapping[j] = '\n';
+
+ fd = open(map_file, O_RDWR);
+ if (fd == -1) {
+ fprintf(stderr, "open %s: %s\n", map_file, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (write(fd, mapping, map_len) != map_len) {
+ fprintf(stderr, "write %s: %s\n", map_file, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ close(fd);
+}
+
+static int /* Start function for cloned child */
+childFunc(void *arg)
+{
+ struct child_args *args = (struct child_args *) arg;
+ char ch;
+
+ /* Wait until the parent has updated the UID and GID mappings. See
+ the comment in main(). We wait for end of file on a pipe that will
+ be closed by the parent process once it has updated the mappings. */
+
+ close(args->pipe_fd[1]); /* Close our descriptor for the write end
+ of the pipe so that we see EOF when
+ parent closes its descriptor */
+ if (read(args->pipe_fd[0], &ch, 1) != 0) {
+ fprintf(stderr, "Failure in child: read from pipe returned != 0\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (setid) {
+ if (setgid(0) < 0)
+ fprintf(stderr, "Failure in child to setgid 0: %s\n", strerror(errno));
+ if (setuid(0) < 0)
+ fprintf(stderr, "Failure in child to setuid 0: %s\n", strerror(errno));
+ }
+
+ /* Execute a shell command */
+
+ execvp(args->argv[0], args->argv);
+ errExit("execvp");
+}
+
+#define STACK_SIZE (1024 * 1024)
+
+static char child_stack[STACK_SIZE]; /* Space for child's stack */
+
+int
+main(int argc, char *argv[])
+{
+ int flags, opt;
+ pid_t child_pid;
+ struct child_args args;
+ char *uid_map, *gid_map;
+ char map_path[PATH_MAX];
+
+ /* Parse command-line options. The initial '+' character in
+ the final getopt() argument prevents GNU-style permutation
+ of command-line options. That's useful, since sometimes
+ the 'command' to be executed by this program itself
+ has command-line options. We don't want getopt() to treat
+ those as options to this program. */
+
+ flags = 0;
+ verbose = 0;
+ setid = 0;
+ gid_map = NULL;
+ uid_map = NULL;
+ while ((opt = getopt(argc, argv, "+imnpuUM:G:vs")) != -1) {
+ switch (opt) {
+ case 'i': flags |= CLONE_NEWIPC; break;
+ case 'm': flags |= CLONE_NEWNS; break;
+ case 'n': flags |= CLONE_NEWNET; break;
+ case 'p': flags |= CLONE_NEWPID; break;
+ case 'u': flags |= CLONE_NEWUTS; break;
+ case 'v': verbose = 1; break;
+ case 'M': uid_map = optarg; break;
+ case 'G': gid_map = optarg; break;
+ case 'U': flags |= CLONE_NEWUSER; break;
+ case 's': setid = 1; break;
+ default: usage(argv[0]);
+ }
+ }
+
+ /* -M or -G without -U is nonsensical */
+
+ if ((uid_map != NULL || gid_map != NULL) &&
+ !(flags & CLONE_NEWUSER))
+ usage(argv[0]);
+
+ args.argv = &argv[optind];
+
+ /* We use a pipe to synchronize the parent and child, in order to
+ ensure that the parent sets the UID and GID maps before the child
+ calls execve(). This ensures that the child maintains its
+ capabilities during the execve() in the common case where we
+ want to map the child's effective user ID to 0 in the new user
+ namespace. Without this synchronization, the child would lose
+ its capabilities if it performed an execve() with nonzero
+ user IDs (see the capabilities(7) man page for details of the
+ transformation of a process's capabilities during execve()). */
+
+ if (pipe(args.pipe_fd) == -1)
+ errExit("pipe");
+
+ /* Create the child in new namespace(s) */
+
+ child_pid = clone(childFunc, child_stack + STACK_SIZE,
+ flags | SIGCHLD, &args);
+ if (child_pid == -1)
+ errExit("clone");
+
+ /* Parent falls through to here */
+
+ if (verbose)
+ printf("%s: PID of child created by clone() is %ld\n",
+ argv[0], (long) child_pid);
+
+ /* Update the UID and GID maps in the child */
+
+ if (uid_map != NULL) {
+ snprintf(map_path, PATH_MAX, "/proc/%ld/uid_map",
+ (long) child_pid);
+ update_map(uid_map, map_path);
+ }
+ if (gid_map != NULL) {
+ snprintf(map_path, PATH_MAX, "/proc/%ld/gid_map",
+ (long) child_pid);
+ update_map(gid_map, map_path);
+ }
+
+ /* Close the write end of the pipe, to signal to the child that we
+ have updated the UID and GID maps */
+
+ close(args.pipe_fd[1]);
+
+ if (waitpid(child_pid, NULL, 0) == -1) /* Wait for child */
+ errExit("waitpid");
+
+ if (verbose)
+ printf("%s: terminating\n", argv[0]);
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/tests/generic/313 b/tests/generic/313
new file mode 100755
index 0000000..0dd6213
--- /dev/null
+++ b/tests/generic/313
@@ -0,0 +1,107 @@
+#! /bin/bash
+# FS QA Test No. 313
+#
+# Check uid/gid to/from disk with a user namespace. A new file
+# will be created from inside a userns. We check that the uid/gid
+# is correct from both inside the userns and also from init_user_ns.
+# We will then unmount and remount the file system and check the
+# uid/gid from both inside the userns and from init_user_ns to show
+# that the correct uid was flushed and brought back from disk.
+#
+#-----------------------------------------------------------------------
+# Copyright (C) 2013 Oracle, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#-----------------------------------------------------------------------
+#
+
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+
+_cleanup()
+{
+ cd /
+ umount $SCRATCH_DEV >/dev/null 2>&1
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/attr
+
+nsexec=$here/src/nsexec
+lstat64=$here/src/lstat64
+file=$SCRATCH_MNT/file1
+
+# real QA test starts here
+_supported_fs generic
+# only Linux supports user namespace
+_supported_os Linux
+
+[ -x $nsexec ] || _notrun "$nsexec executable not found"
+[ -x $lstat64 ] || _notrun "$lstat64 executable not found"
+
+rm -f $seqres.full
+
+_require_scratch
+_need_to_be_root
+_require_user
+qa_user_id=`grep $qa_user /etc/passwd |awk -F: '{print $3}'`
+
+_filter_output()
+{
+ sed \
+ -e "s/$qa_user_id/qa_user/g" \
+ -e "s!$SCRATCH_MNT!\$SCRATCH_MNT!"
+}
+
+_print_numeric_uid()
+{
+ echo "From init_user_ns"
+ $here/src/lstat64 $file |head -3 |_filter_output
+
+ echo "From user_ns"
+ $nsexec -s -U -M "0 $qa_user_id 1000" -G "0 $qa_user_id 1000" $here/src/lstat64 $file |head -3 |_filter_output
+}
+
+umount $SCRATCH_DEV >/dev/null 2>&1
+echo "*** MKFS ***" >>$seqres.full
+echo "" >>$seqres.full
+_scratch_mkfs >>$seqres.full 2>&1 || _fail "mkfs failed"
+_scratch_mount >>$seqres.full 2>&1 || _fail "mount failed"
+chmod 777 $SCRATCH_MNT
+
+# create $file as "root" in userns, which is $qa_user in parent namespace
+$nsexec -s -U -M "0 $qa_user_id 1000" -G "0 $qa_user_id 1000" touch $file
+
+_print_numeric_uid
+
+echo ""
+echo "*** Remounting ***"
+echo ""
+sync
+umount $SCRATCH_MNT >>$seqres.full 2>&1
+_scratch_mount >>$seqres.full 2>&1 || _fail "mount failed"
+
+_print_numeric_uid
+
+umount $SCRATCH_DEV >/dev/null 2>&1
+status=0
+exit
diff --git a/tests/generic/313.out b/tests/generic/313.out
new file mode 100644
index 0000000..eab14c4
--- /dev/null
+++ b/tests/generic/313.out
@@ -0,0 +1,20 @@
+QA output created by 313
+From init_user_ns
+ File: "$SCRATCH_MNT/file1"
+ Size: 0 Filetype: Regular File
+ Mode: (0644/-rw-r--r--) Uid: (qa_user) Gid: (qa_user)
+From user_ns
+ File: "$SCRATCH_MNT/file1"
+ Size: 0 Filetype: Regular File
+ Mode: (0644/-rw-r--r--) Uid: (0) Gid: (0)
+
+*** Remounting ***
+
+From init_user_ns
+ File: "$SCRATCH_MNT/file1"
+ Size: 0 Filetype: Regular File
+ Mode: (0644/-rw-r--r--) Uid: (qa_user) Gid: (qa_user)
+From user_ns
+ File: "$SCRATCH_MNT/file1"
+ Size: 0 Filetype: Regular File
+ Mode: (0644/-rw-r--r--) Uid: (0) Gid: (0)
diff --git a/tests/generic/314 b/tests/generic/314
new file mode 100755
index 0000000..40228b8
--- /dev/null
+++ b/tests/generic/314
@@ -0,0 +1,102 @@
+#! /bin/bash
+# FS QA Test No. 314
+#
+# Check get/set ACLs to/from disk with a user namespace. A new file
+# will be created and ACLs set on it from both inside a userns and
+# from init_user_ns. We check that the ACL is is correct from both
+# inside the userns and also from init_user_ns. We will then unmount
+# and remount the file system and check the ACL from both inside the
+# userns and from init_user_ns to show that the correct uid/gid in
+# the ACL was flushed and brought back from disk.
+#
+#-----------------------------------------------------------------------
+# Copyright (C) 2013 Oracle, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#-----------------------------------------------------------------------
+#
+
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+
+_cleanup()
+{
+ cd /
+ umount $SCRATCH_DEV >/dev/null 2>&1
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/attr
+
+nsexec=$here/src/nsexec
+file=$SCRATCH_MNT/file1
+
+# real QA test starts here
+_supported_fs generic
+# only Linux supports user namespace
+_supported_os Linux
+
+[ -x $nsexec ] || _notrun "$nsexec executable not found"
+
+rm -f $seqres.full
+
+_require_scratch
+_need_to_be_root
+_acl_setup_ids
+_require_acls
+
+_print_getfacls()
+{
+ echo "From init_user_ns"
+ getfacl -n $file 2>/dev/null | _getfacl_filter_id | sed -e "s!$SCRATCH_MNT!\$SCRATCH_MNT!"
+
+ echo "From user_ns"
+ $nsexec -U -M "0 $acl1 1000" -G "0 $acl2 1000" getfacl -n $file 2>/dev/null | _getfacl_filter_id | sed -e "s!$SCRATCH_MNT!\$SCRATCH_MNT!"
+}
+
+umount $SCRATCH_DEV >/dev/null 2>&1
+echo "*** MKFS ***" >>$seqres.full
+echo "" >>$seqres.full
+_scratch_mkfs >>$seqres.full 2>&1 || _fail "mkfs failed"
+_scratch_mount >>$seqres.full 2>&1 || _fail "mount failed"
+
+touch $file
+chown $acl1.$acl1 $file
+
+# set acls from init_user_ns, to be checked from inside the userns
+setfacl -n -m u:$acl2:rw,g:$acl2:r $file
+# set acls from inside userns, to be checked from init_user_ns
+$nsexec -s -U -M "0 $acl1 1000" -G "0 $acl2 1000" setfacl -n -m u:root:rx,g:root:x $file
+
+_print_getfacls
+
+echo "*** Remounting ***"
+echo ""
+sync
+umount $SCRATCH_MNT >>$seqres.full 2>&1
+_scratch_mount >>$seqres.full 2>&1 || _fail "mount failed"
+
+_print_getfacls
+
+umount $SCRATCH_DEV >/dev/null 2>&1
+status=0
+exit
diff --git a/tests/generic/314.out b/tests/generic/314.out
new file mode 100644
index 0000000..b88354c
--- /dev/null
+++ b/tests/generic/314.out
@@ -0,0 +1,51 @@
+QA output created by 314
+From init_user_ns
+# file: mnt/xfs-scratch/file1
+# owner: id1
+# group: id1
+user::rw-
+user:id1:r-x #effective:r--
+user:id2:rw- #effective:r--
+group::r--
+group:id2:--x #effective:---
+mask::r--
+other::r--
+
+From user_ns
+# file: mnt/xfs-scratch/file1
+# owner: 0
+# group: 65534
+user::rw-
+user:0:r-x #effective:r--
+user:1:rw- #effective:r--
+group::r--
+group:0:--x #effective:---
+mask::r--
+other::r--
+
+*** Remounting ***
+
+From init_user_ns
+# file: mnt/xfs-scratch/file1
+# owner: id1
+# group: id1
+user::rw-
+user:id1:r-x #effective:r--
+user:id2:rw- #effective:r--
+group::r--
+group:id2:--x #effective:---
+mask::r--
+other::r--
+
+From user_ns
+# file: mnt/xfs-scratch/file1
+# owner: 0
+# group: 65534
+user::rw-
+user:0:r-x #effective:r--
+user:1:rw- #effective:r--
+group::r--
+group:0:--x #effective:---
+mask::r--
+other::r--
+
diff --git a/tests/generic/group b/tests/generic/group
index bd443c1..ead1cb1 100644
--- a/tests/generic/group
+++ b/tests/generic/group
@@ -115,3 +115,5 @@
310 auto
311 auto metadata log
312 auto quick prealloc enospc
+313 auto metadata quick
+314 acl attr auto quick
--
1.8.1.4
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH] xfstests: 313,314: user namespace uid/gids in inode, ACL
2013-06-25 19:34 [PATCH] xfstests: 313,314: user namespace uid/gids in inode, ACL Dwight Engen
@ 2013-06-26 1:09 ` Dave Chinner
2013-06-26 16:30 ` Dwight Engen
` (3 more replies)
0 siblings, 4 replies; 14+ messages in thread
From: Dave Chinner @ 2013-06-26 1:09 UTC (permalink / raw)
To: Dwight Engen; +Cc: xfs
On Tue, Jun 25, 2013 at 03:34:43PM -0400, Dwight Engen wrote:
> These tests verify that the uid/gids in an inode and in ACLs get translated
> from/to a user namespace to/from disk correctly.
>
> I had to use getfacl instead of the chacl -l because I need numeric uids
> to make the output consistent.
>
> A new program nsexec was added to facilitate creating/entering a user
> namespace for testing. The orignal source for the program is
> https://lwn.net/Articles/539940. I added the -s option to become "root"
> in the user namespace.
>
> Tested against btrfs, ext4, and xfs with my proposed user namespace changes.
Can you split it out into a patch per test? It's easier to review
that way...
Cheers,
Dave.
--
Dave Chinner
david@fromorbit.com
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] xfstests: 313,314: user namespace uid/gids in inode, ACL
2013-06-26 1:09 ` Dave Chinner
@ 2013-06-26 16:30 ` Dwight Engen
2013-06-27 16:03 ` [PATCH 1/3] xfstests: add nsexec user namespace helper Dwight Engen
` (2 subsequent siblings)
3 siblings, 0 replies; 14+ messages in thread
From: Dwight Engen @ 2013-06-26 16:30 UTC (permalink / raw)
To: Dave Chinner; +Cc: xfs
On Wed, 26 Jun 2013 11:09:31 +1000
Dave Chinner <david@fromorbit.com> wrote:
> On Tue, Jun 25, 2013 at 03:34:43PM -0400, Dwight Engen wrote:
> > These tests verify that the uid/gids in an inode and in ACLs get
> > translated from/to a user namespace to/from disk correctly.
> >
> > I had to use getfacl instead of the chacl -l because I need numeric
> > uids to make the output consistent.
> >
> > A new program nsexec was added to facilitate creating/entering a
> > user namespace for testing. The orignal source for the program is
> > https://lwn.net/Articles/539940. I added the -s option to become
> > "root" in the user namespace.
> >
> > Tested against btrfs, ext4, and xfs with my proposed user namespace
> > changes.
>
> Can you split it out into a patch per test? It's easier to review
> that way...
Sure, I'll split out adding the nsexec program separately as well.
> Cheers,
>
> Dave.
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 1/3] xfstests: add nsexec user namespace helper
2013-06-26 1:09 ` Dave Chinner
2013-06-26 16:30 ` Dwight Engen
@ 2013-06-27 16:03 ` Dwight Engen
2013-08-19 14:10 ` Rich Johnston
2013-08-19 15:03 ` Rich Johnston
2013-06-27 16:03 ` [PATCH 2/3] xfstests 313: user namespace uid/gids in an inode Dwight Engen
2013-06-27 16:03 ` [PATCH 3/3] xfstests 314: user namespace uid/gids in an ACL Dwight Engen
3 siblings, 2 replies; 14+ messages in thread
From: Dwight Engen @ 2013-06-27 16:03 UTC (permalink / raw)
To: Dave Chinner; +Cc: xfs
Add new program nsexec to facilitate creating/entering a user namespace. The
orignal source for the program is https://lwn.net/Articles/539940. I added
the -s option to become "root" in the user namespace.
Signed-off-by: Dwight Engen <dwight.engen@oracle.com>
---
.gitignore | 1 +
src/Makefile | 2 +-
src/nsexec.c | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 241 insertions(+), 1 deletion(-)
create mode 100644 src/nsexec.c
diff --git a/.gitignore b/.gitignore
index ad7afbc..23e4c82 100644
--- a/.gitignore
+++ b/.gitignore
@@ -63,6 +63,7 @@
/src/mmapcat
/src/multi_open_unlink
/src/nametest
+/src/nsexec
/src/permname
/src/preallo_rw_pattern_reader
/src/preallo_rw_pattern_writer
diff --git a/src/Makefile b/src/Makefile
index c18ffc9..4eabdc7 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -18,7 +18,7 @@ LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \
locktest unwritten_mmap bulkstat_unlink_test t_stripealign \
bulkstat_unlink_test_modified t_dir_offset t_futimens t_immutable \
stale_handle pwrite_mmap_blocked t_dir_offset2 seek_sanity_test \
- seek_copy_test t_readdir_1 t_readdir_2 fsync-tester
+ seek_copy_test t_readdir_1 t_readdir_2 fsync-tester nsexec
SUBDIRS =
diff --git a/src/nsexec.c b/src/nsexec.c
new file mode 100644
index 0000000..f033b1a
--- /dev/null
+++ b/src/nsexec.c
@@ -0,0 +1,239 @@
+/* userns_child_exec.c
+
+ Copyright 2013, Michael Kerrisk
+ Licensed under GNU General Public License v2 or later
+
+ Create a child process that executes a shell command in new
+ namespace(s); allow UID and GID mappings to be specified when
+ creating a user namespace.
+*/
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <sched.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+
+/* A simple error-handling function: print an error message based
+ on the value in 'errno' and terminate the calling process */
+
+#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
+ } while (0)
+
+struct child_args {
+ char **argv; /* Command to be executed by child, with arguments */
+ int pipe_fd[2]; /* Pipe used to synchronize parent and child */
+};
+
+static int verbose, setid;
+
+static void
+usage(char *pname)
+{
+ fprintf(stderr, "Usage: %s [options] cmd [arg...]\n\n", pname);
+ fprintf(stderr, "Create a child process that executes a shell command "
+ "in a new user namespace,\n"
+ "and possibly also other new namespace(s).\n\n");
+ fprintf(stderr, "Options can be:\n\n");
+#define fpe(str) fprintf(stderr, " %s", str);
+ fpe("-i New IPC namespace\n");
+ fpe("-m New mount namespace\n");
+ fpe("-n New network namespace\n");
+ fpe("-p New PID namespace\n");
+ fpe("-u New UTS namespace\n");
+ fpe("-U New user namespace\n");
+ fpe("-M uid_map Specify UID map for user namespace\n");
+ fpe("-G gid_map Specify GID map for user namespace\n");
+ fpe(" If -M or -G is specified, -U is required\n");
+ fpe("-s Set uid/gid to 0 in the new user namespace\n");
+ fpe("-v Display verbose messages\n");
+ fpe("\n");
+ fpe("Map strings for -M and -G consist of records of the form:\n");
+ fpe("\n");
+ fpe(" ID-inside-ns ID-outside-ns len\n");
+ fpe("\n");
+ fpe("A map string can contain multiple records, separated by commas;\n");
+ fpe("the commas are replaced by newlines before writing to map files.\n");
+
+ exit(EXIT_FAILURE);
+}
+
+/* Update the mapping file 'map_file', with the value provided in
+ 'mapping', a string that defines a UID or GID mapping. A UID or
+ GID mapping consists of one or more newline-delimited records
+ of the form:
+
+ ID_inside-ns ID-outside-ns length
+
+ Requiring the user to supply a string that contains newlines is
+ of course inconvenient for command-line use. Thus, we permit the
+ use of commas to delimit records in this string, and replace them
+ with newlines before writing the string to the file. */
+
+static void
+update_map(char *mapping, char *map_file)
+{
+ int fd, j;
+ size_t map_len; /* Length of 'mapping' */
+
+ /* Replace commas in mapping string with newlines */
+
+ map_len = strlen(mapping);
+ for (j = 0; j < map_len; j++)
+ if (mapping[j] == ',')
+ mapping[j] = '\n';
+
+ fd = open(map_file, O_RDWR);
+ if (fd == -1) {
+ fprintf(stderr, "open %s: %s\n", map_file, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (write(fd, mapping, map_len) != map_len) {
+ fprintf(stderr, "write %s: %s\n", map_file, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ close(fd);
+}
+
+static int /* Start function for cloned child */
+childFunc(void *arg)
+{
+ struct child_args *args = (struct child_args *) arg;
+ char ch;
+
+ /* Wait until the parent has updated the UID and GID mappings. See
+ the comment in main(). We wait for end of file on a pipe that will
+ be closed by the parent process once it has updated the mappings. */
+
+ close(args->pipe_fd[1]); /* Close our descriptor for the write end
+ of the pipe so that we see EOF when
+ parent closes its descriptor */
+ if (read(args->pipe_fd[0], &ch, 1) != 0) {
+ fprintf(stderr, "Failure in child: read from pipe returned != 0\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (setid) {
+ if (setgid(0) < 0)
+ fprintf(stderr, "Failure in child to setgid 0: %s\n", strerror(errno));
+ if (setuid(0) < 0)
+ fprintf(stderr, "Failure in child to setuid 0: %s\n", strerror(errno));
+ }
+
+ /* Execute a shell command */
+
+ execvp(args->argv[0], args->argv);
+ errExit("execvp");
+}
+
+#define STACK_SIZE (1024 * 1024)
+
+static char child_stack[STACK_SIZE]; /* Space for child's stack */
+
+int
+main(int argc, char *argv[])
+{
+ int flags, opt;
+ pid_t child_pid;
+ struct child_args args;
+ char *uid_map, *gid_map;
+ char map_path[PATH_MAX];
+
+ /* Parse command-line options. The initial '+' character in
+ the final getopt() argument prevents GNU-style permutation
+ of command-line options. That's useful, since sometimes
+ the 'command' to be executed by this program itself
+ has command-line options. We don't want getopt() to treat
+ those as options to this program. */
+
+ flags = 0;
+ verbose = 0;
+ setid = 0;
+ gid_map = NULL;
+ uid_map = NULL;
+ while ((opt = getopt(argc, argv, "+imnpuUM:G:vs")) != -1) {
+ switch (opt) {
+ case 'i': flags |= CLONE_NEWIPC; break;
+ case 'm': flags |= CLONE_NEWNS; break;
+ case 'n': flags |= CLONE_NEWNET; break;
+ case 'p': flags |= CLONE_NEWPID; break;
+ case 'u': flags |= CLONE_NEWUTS; break;
+ case 'v': verbose = 1; break;
+ case 'M': uid_map = optarg; break;
+ case 'G': gid_map = optarg; break;
+ case 'U': flags |= CLONE_NEWUSER; break;
+ case 's': setid = 1; break;
+ default: usage(argv[0]);
+ }
+ }
+
+ /* -M or -G without -U is nonsensical */
+
+ if ((uid_map != NULL || gid_map != NULL) &&
+ !(flags & CLONE_NEWUSER))
+ usage(argv[0]);
+
+ args.argv = &argv[optind];
+
+ /* We use a pipe to synchronize the parent and child, in order to
+ ensure that the parent sets the UID and GID maps before the child
+ calls execve(). This ensures that the child maintains its
+ capabilities during the execve() in the common case where we
+ want to map the child's effective user ID to 0 in the new user
+ namespace. Without this synchronization, the child would lose
+ its capabilities if it performed an execve() with nonzero
+ user IDs (see the capabilities(7) man page for details of the
+ transformation of a process's capabilities during execve()). */
+
+ if (pipe(args.pipe_fd) == -1)
+ errExit("pipe");
+
+ /* Create the child in new namespace(s) */
+
+ child_pid = clone(childFunc, child_stack + STACK_SIZE,
+ flags | SIGCHLD, &args);
+ if (child_pid == -1)
+ errExit("clone");
+
+ /* Parent falls through to here */
+
+ if (verbose)
+ printf("%s: PID of child created by clone() is %ld\n",
+ argv[0], (long) child_pid);
+
+ /* Update the UID and GID maps in the child */
+
+ if (uid_map != NULL) {
+ snprintf(map_path, PATH_MAX, "/proc/%ld/uid_map",
+ (long) child_pid);
+ update_map(uid_map, map_path);
+ }
+ if (gid_map != NULL) {
+ snprintf(map_path, PATH_MAX, "/proc/%ld/gid_map",
+ (long) child_pid);
+ update_map(gid_map, map_path);
+ }
+
+ /* Close the write end of the pipe, to signal to the child that we
+ have updated the UID and GID maps */
+
+ close(args.pipe_fd[1]);
+
+ if (waitpid(child_pid, NULL, 0) == -1) /* Wait for child */
+ errExit("waitpid");
+
+ if (verbose)
+ printf("%s: terminating\n", argv[0]);
+
+ exit(EXIT_SUCCESS);
+}
--
1.8.1.4
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 2/3] xfstests 313: user namespace uid/gids in an inode
2013-06-26 1:09 ` Dave Chinner
2013-06-26 16:30 ` Dwight Engen
2013-06-27 16:03 ` [PATCH 1/3] xfstests: add nsexec user namespace helper Dwight Engen
@ 2013-06-27 16:03 ` Dwight Engen
2013-08-19 14:10 ` Rich Johnston
2013-08-19 15:03 ` Rich Johnston
2013-06-27 16:03 ` [PATCH 3/3] xfstests 314: user namespace uid/gids in an ACL Dwight Engen
3 siblings, 2 replies; 14+ messages in thread
From: Dwight Engen @ 2013-06-27 16:03 UTC (permalink / raw)
To: Dave Chinner; +Cc: xfs
Signed-off-by: Dwight Engen <dwight.engen@oracle.com>
---
tests/generic/313 | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++
tests/generic/313.out | 20 ++++++++++
tests/generic/group | 1 +
3 files changed, 128 insertions(+)
create mode 100644 tests/generic/313
create mode 100644 tests/generic/313.out
diff --git a/tests/generic/313 b/tests/generic/313
new file mode 100644
index 0000000..0dd6213
--- /dev/null
+++ b/tests/generic/313
@@ -0,0 +1,107 @@
+#! /bin/bash
+# FS QA Test No. 313
+#
+# Check uid/gid to/from disk with a user namespace. A new file
+# will be created from inside a userns. We check that the uid/gid
+# is correct from both inside the userns and also from init_user_ns.
+# We will then unmount and remount the file system and check the
+# uid/gid from both inside the userns and from init_user_ns to show
+# that the correct uid was flushed and brought back from disk.
+#
+#-----------------------------------------------------------------------
+# Copyright (C) 2013 Oracle, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#-----------------------------------------------------------------------
+#
+
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+
+_cleanup()
+{
+ cd /
+ umount $SCRATCH_DEV >/dev/null 2>&1
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/attr
+
+nsexec=$here/src/nsexec
+lstat64=$here/src/lstat64
+file=$SCRATCH_MNT/file1
+
+# real QA test starts here
+_supported_fs generic
+# only Linux supports user namespace
+_supported_os Linux
+
+[ -x $nsexec ] || _notrun "$nsexec executable not found"
+[ -x $lstat64 ] || _notrun "$lstat64 executable not found"
+
+rm -f $seqres.full
+
+_require_scratch
+_need_to_be_root
+_require_user
+qa_user_id=`grep $qa_user /etc/passwd |awk -F: '{print $3}'`
+
+_filter_output()
+{
+ sed \
+ -e "s/$qa_user_id/qa_user/g" \
+ -e "s!$SCRATCH_MNT!\$SCRATCH_MNT!"
+}
+
+_print_numeric_uid()
+{
+ echo "From init_user_ns"
+ $here/src/lstat64 $file |head -3 |_filter_output
+
+ echo "From user_ns"
+ $nsexec -s -U -M "0 $qa_user_id 1000" -G "0 $qa_user_id 1000" $here/src/lstat64 $file |head -3 |_filter_output
+}
+
+umount $SCRATCH_DEV >/dev/null 2>&1
+echo "*** MKFS ***" >>$seqres.full
+echo "" >>$seqres.full
+_scratch_mkfs >>$seqres.full 2>&1 || _fail "mkfs failed"
+_scratch_mount >>$seqres.full 2>&1 || _fail "mount failed"
+chmod 777 $SCRATCH_MNT
+
+# create $file as "root" in userns, which is $qa_user in parent namespace
+$nsexec -s -U -M "0 $qa_user_id 1000" -G "0 $qa_user_id 1000" touch $file
+
+_print_numeric_uid
+
+echo ""
+echo "*** Remounting ***"
+echo ""
+sync
+umount $SCRATCH_MNT >>$seqres.full 2>&1
+_scratch_mount >>$seqres.full 2>&1 || _fail "mount failed"
+
+_print_numeric_uid
+
+umount $SCRATCH_DEV >/dev/null 2>&1
+status=0
+exit
diff --git a/tests/generic/313.out b/tests/generic/313.out
new file mode 100644
index 0000000..eab14c4
--- /dev/null
+++ b/tests/generic/313.out
@@ -0,0 +1,20 @@
+QA output created by 313
+From init_user_ns
+ File: "$SCRATCH_MNT/file1"
+ Size: 0 Filetype: Regular File
+ Mode: (0644/-rw-r--r--) Uid: (qa_user) Gid: (qa_user)
+From user_ns
+ File: "$SCRATCH_MNT/file1"
+ Size: 0 Filetype: Regular File
+ Mode: (0644/-rw-r--r--) Uid: (0) Gid: (0)
+
+*** Remounting ***
+
+From init_user_ns
+ File: "$SCRATCH_MNT/file1"
+ Size: 0 Filetype: Regular File
+ Mode: (0644/-rw-r--r--) Uid: (qa_user) Gid: (qa_user)
+From user_ns
+ File: "$SCRATCH_MNT/file1"
+ Size: 0 Filetype: Regular File
+ Mode: (0644/-rw-r--r--) Uid: (0) Gid: (0)
diff --git a/tests/generic/group b/tests/generic/group
index bd443c1..5c2b4d7 100644
--- a/tests/generic/group
+++ b/tests/generic/group
@@ -115,3 +115,4 @@
310 auto
311 auto metadata log
312 auto quick prealloc enospc
+313 auto metadata quick
--
1.8.1.4
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 3/3] xfstests 314: user namespace uid/gids in an ACL
2013-06-26 1:09 ` Dave Chinner
` (2 preceding siblings ...)
2013-06-27 16:03 ` [PATCH 2/3] xfstests 313: user namespace uid/gids in an inode Dwight Engen
@ 2013-06-27 16:03 ` Dwight Engen
2013-08-19 14:11 ` Rich Johnston
3 siblings, 1 reply; 14+ messages in thread
From: Dwight Engen @ 2013-06-27 16:03 UTC (permalink / raw)
To: Dave Chinner; +Cc: xfs
Signed-off-by: Dwight Engen <dwight.engen@oracle.com>
---
common/attr | 14 +++++++
tests/generic/314 | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++
tests/generic/314.out | 51 +++++++++++++++++++++++++
tests/generic/group | 1 +
4 files changed, 168 insertions(+)
create mode 100644 tests/generic/314
create mode 100644 tests/generic/314.out
diff --git a/common/attr b/common/attr
index e5070bf..4a3ac9e 100644
--- a/common/attr
+++ b/common/attr
@@ -54,6 +54,20 @@ _acl_filter_id()
-e "s/ $acl3 / id3 /"
}
+_getfacl_filter_id()
+{
+ sed \
+ -e "s/user:$acl1/user:id1/" \
+ -e "s/user:$acl2/user:id2/" \
+ -e "s/user:$acl3/user:id3/" \
+ -e "s/group:$acl1/group:id1/" \
+ -e "s/group:$acl2/group:id2/" \
+ -e "s/group:$acl3/group:id3/" \
+ -e "s/: $acl1/: id1/" \
+ -e "s/: $acl2/: id2/" \
+ -e "s/: $acl3/: id3/"
+}
+
# filtered ls
#
_acl_ls()
diff --git a/tests/generic/314 b/tests/generic/314
new file mode 100644
index 0000000..fc0b722
--- /dev/null
+++ b/tests/generic/314
@@ -0,0 +1,102 @@
+#! /bin/bash
+# FS QA Test No. 314
+#
+# Check get/set ACLs to/from disk with a user namespace. A new file
+# will be created and ACLs set on it from both inside a userns and
+# from init_user_ns. We check that the ACL is is correct from both
+# inside the userns and also from init_user_ns. We will then unmount
+# and remount the file system and check the ACL from both inside the
+# userns and from init_user_ns to show that the correct uid/gid in
+# the ACL was flushed and brought back from disk.
+#
+#-----------------------------------------------------------------------
+# Copyright (C) 2013 Oracle, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#-----------------------------------------------------------------------
+#
+
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+
+_cleanup()
+{
+ cd /
+ umount $SCRATCH_DEV >/dev/null 2>&1
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/attr
+
+nsexec=$here/src/nsexec
+file=$SCRATCH_MNT/file1
+
+# real QA test starts here
+_supported_fs generic
+# only Linux supports user namespace
+_supported_os Linux
+
+[ -x $nsexec ] || _notrun "$nsexec executable not found"
+
+rm -f $seqres.full
+
+_require_scratch
+_need_to_be_root
+_acl_setup_ids
+_require_acls
+
+_print_getfacls()
+{
+ echo "From init_user_ns"
+ getfacl -n $file 2>/dev/null | _getfacl_filter_id | sed -e "s!$SCRATCH_MNT!\$SCRATCH_MNT!"
+
+ echo "From user_ns"
+ $nsexec -U -M "0 $acl1 1000" -G "0 $acl2 1000" getfacl -n $file 2>/dev/null | _getfacl_filter_id | sed -e "s!$SCRATCH_MNT!\$SCRATCH_MNT!"
+}
+
+umount $SCRATCH_DEV >/dev/null 2>&1
+echo "*** MKFS ***" >>$seqres.full
+echo "" >>$seqres.full
+_scratch_mkfs >>$seqres.full 2>&1 || _fail "mkfs failed"
+_scratch_mount >>$seqres.full 2>&1 || _fail "mount failed"
+
+touch $file
+chown $acl1.$acl1 $file
+
+# set acls from init_user_ns, to be checked from inside the userns
+setfacl -n -m u:$acl2:rw,g:$acl2:r $file
+# set acls from inside userns, to be checked from init_user_ns
+$nsexec -s -U -M "0 $acl1 1000" -G "0 $acl2 1000" setfacl -n -m u:root:rx,g:root:x $file
+
+_print_getfacls
+
+echo "*** Remounting ***"
+echo ""
+sync
+umount $SCRATCH_MNT >>$seqres.full 2>&1
+_scratch_mount >>$seqres.full 2>&1 || _fail "mount failed"
+
+_print_getfacls
+
+umount $SCRATCH_DEV >/dev/null 2>&1
+status=0
+exit
diff --git a/tests/generic/314.out b/tests/generic/314.out
new file mode 100644
index 0000000..b88354c
--- /dev/null
+++ b/tests/generic/314.out
@@ -0,0 +1,51 @@
+QA output created by 314
+From init_user_ns
+# file: mnt/xfs-scratch/file1
+# owner: id1
+# group: id1
+user::rw-
+user:id1:r-x #effective:r--
+user:id2:rw- #effective:r--
+group::r--
+group:id2:--x #effective:---
+mask::r--
+other::r--
+
+From user_ns
+# file: mnt/xfs-scratch/file1
+# owner: 0
+# group: 65534
+user::rw-
+user:0:r-x #effective:r--
+user:1:rw- #effective:r--
+group::r--
+group:0:--x #effective:---
+mask::r--
+other::r--
+
+*** Remounting ***
+
+From init_user_ns
+# file: mnt/xfs-scratch/file1
+# owner: id1
+# group: id1
+user::rw-
+user:id1:r-x #effective:r--
+user:id2:rw- #effective:r--
+group::r--
+group:id2:--x #effective:---
+mask::r--
+other::r--
+
+From user_ns
+# file: mnt/xfs-scratch/file1
+# owner: 0
+# group: 65534
+user::rw-
+user:0:r-x #effective:r--
+user:1:rw- #effective:r--
+group::r--
+group:0:--x #effective:---
+mask::r--
+other::r--
+
diff --git a/tests/generic/group b/tests/generic/group
index 5c2b4d7..ead1cb1 100644
--- a/tests/generic/group
+++ b/tests/generic/group
@@ -116,3 +116,4 @@
311 auto metadata log
312 auto quick prealloc enospc
313 auto metadata quick
+314 acl attr auto quick
--
1.8.1.4
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 1/3] xfstests: add nsexec user namespace helper
2013-06-27 16:03 ` [PATCH 1/3] xfstests: add nsexec user namespace helper Dwight Engen
@ 2013-08-19 14:10 ` Rich Johnston
2013-08-19 15:03 ` Rich Johnston
1 sibling, 0 replies; 14+ messages in thread
From: Rich Johnston @ 2013-08-19 14:10 UTC (permalink / raw)
To: Dwight Engen; +Cc: xfs
Looks good.
Reviewed-by: <rjohnston@sgi.com>
On 06/27/2013 11:03 AM, Dwight Engen wrote:
> Add new program nsexec to facilitate creating/entering a user namespace. The
> orignal source for the program is https://lwn.net/Articles/539940. I added
original
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 2/3] xfstests 313: user namespace uid/gids in an inode
2013-06-27 16:03 ` [PATCH 2/3] xfstests 313: user namespace uid/gids in an inode Dwight Engen
@ 2013-08-19 14:10 ` Rich Johnston
2013-08-19 15:03 ` Rich Johnston
1 sibling, 0 replies; 14+ messages in thread
From: Rich Johnston @ 2013-08-19 14:10 UTC (permalink / raw)
To: Dwight Engen; +Cc: xfs
Looks good.
Reviewed-by: <rjohnston@sgi.com>
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/3] xfstests 314: user namespace uid/gids in an ACL
2013-06-27 16:03 ` [PATCH 3/3] xfstests 314: user namespace uid/gids in an ACL Dwight Engen
@ 2013-08-19 14:11 ` Rich Johnston
2013-08-19 17:34 ` Dwight Engen
2013-08-19 17:34 ` [PATCH v2] xfstests generic/318: " Dwight Engen
0 siblings, 2 replies; 14+ messages in thread
From: Rich Johnston @ 2013-08-19 14:11 UTC (permalink / raw)
To: Dwight Engen; +Cc: xfs
On 06/27/2013 11:03 AM, Dwight Engen wrote:
> Signed-off-by: Dwight Engen <dwight.engen@oracle.com>
> +#! /bin/bash
> +# FS QA Test No. 314
> +#
> +# Check get/set ACLs to/from disk with a user namespace. A new file
> +# will be created and ACLs set on it from both inside a userns and
> +# from init_user_ns. We check that the ACL is is correct from both
> +# inside the userns and also from init_user_ns. We will then unmount
> +# and remount the file system and check the ACL from both inside the
> +# userns and from init_user_ns to show that the correct uid/gid in
> +# the ACL was flushed and brought back from disk.
> +#
...
> +
> +_print_getfacls()
> +{
> + echo "From init_user_ns"
> + getfacl -n $file 2>/dev/null | _getfacl_filter_id | sed -e "s!$SCRATCH_MNT!\$SCRATCH_MNT!"
I think you need to loose the last sed command and use the getfacl flag
--absolute-names and pipe it to _filter_scratch like this:
getfacl --absolute-names -n $file 2>/dev/null | _filter_scratch |
_getfacl_filter_id
> +
> + echo "From user_ns"
> + $nsexec -U -M "0 $acl1 1000" -G "0 $acl2 1000" getfacl -n $file 2>/dev/null | _getfacl_filter_id | sed -e "s!$SCRATCH_MNT!\$SCRATCH_MNT!"
Same as above.
...
Also need to update 314.out
I tested with these changes as test 316 but not sure if the new output
is correct.
--Rich
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 2/3] xfstests 313: user namespace uid/gids in an inode
2013-06-27 16:03 ` [PATCH 2/3] xfstests 313: user namespace uid/gids in an inode Dwight Engen
2013-08-19 14:10 ` Rich Johnston
@ 2013-08-19 15:03 ` Rich Johnston
1 sibling, 0 replies; 14+ messages in thread
From: Rich Johnston @ 2013-08-19 15:03 UTC (permalink / raw)
To: Dwight Engen; +Cc: xfs
Thanks for splitting the original patch Dwight, this patch has been
committed.
--Rich
commit 531a2473ce411fdc0af07d7ef86b2aaadf239b39
Author: Dwight Engen <dwight.engen@oracle.com>
Date: Thu Jun 27 16:03:34 2013 +0000
xfstests generic/317: user namespace uid/gids in an inode
[rjohnston: renumbered test to 317]
Signed-off-by: Dwight Engen <dwight.engen@oracle.com>
Reviewed-by: <rjohnston@sgi.com>
Signed-off-by: <rjohnston@sgi.com>
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/3] xfstests: add nsexec user namespace helper
2013-06-27 16:03 ` [PATCH 1/3] xfstests: add nsexec user namespace helper Dwight Engen
2013-08-19 14:10 ` Rich Johnston
@ 2013-08-19 15:03 ` Rich Johnston
1 sibling, 0 replies; 14+ messages in thread
From: Rich Johnston @ 2013-08-19 15:03 UTC (permalink / raw)
To: Dwight Engen; +Cc: xfs
Thanks for the patch Dwight, it has been committed.
--Rich
commit 3f424be6396205edd6aec1d46de04349aebe9306
Author: Dwight Engen <dwight.engen@oracle.com>
Date: Thu Jun 27 16:03:28 2013 +0000
xfstests: add nsexec user namespace helper
Add new program nsexec to facilitate creating/entering a user
namespace. The
original source for the program is https://lwn.net/Articles/539940.
I added
the -s option to become "root" in the user namespace.
Signed-off-by: Dwight Engen <dwight.engen@oracle.com>
Reviewed-by: <rjohnston@sgi.com>
Signed-off-by: <rjohnston@sgi.com>
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/3] xfstests 314: user namespace uid/gids in an ACL
2013-08-19 14:11 ` Rich Johnston
@ 2013-08-19 17:34 ` Dwight Engen
2013-08-19 17:34 ` [PATCH v2] xfstests generic/318: " Dwight Engen
1 sibling, 0 replies; 14+ messages in thread
From: Dwight Engen @ 2013-08-19 17:34 UTC (permalink / raw)
To: Rich Johnston; +Cc: xfs
On Mon, 19 Aug 2013 09:11:09 -0500
Rich Johnston <rjohnston@sgi.com> wrote:
>
>
> On 06/27/2013 11:03 AM, Dwight Engen wrote:
> > Signed-off-by: Dwight Engen <dwight.engen@oracle.com>
>
> > +#! /bin/bash
> > +# FS QA Test No. 314
> > +#
> > +# Check get/set ACLs to/from disk with a user namespace. A new file
> > +# will be created and ACLs set on it from both inside a userns and
> > +# from init_user_ns. We check that the ACL is is correct from both
> > +# inside the userns and also from init_user_ns. We will then
> > unmount +# and remount the file system and check the ACL from both
> > inside the +# userns and from init_user_ns to show that the correct
> > uid/gid in +# the ACL was flushed and brought back from disk.
> > +#
> ...
> > +
> > +_print_getfacls()
> > +{
> > + echo "From init_user_ns"
> > + getfacl -n $file 2>/dev/null | _getfacl_filter_id | sed -e
> > "s!$SCRATCH_MNT!\$SCRATCH_MNT!"
>
> I think you need to loose the last sed command and use the getfacl
> flag --absolute-names and pipe it to _filter_scratch like this:
>
> getfacl --absolute-names -n $file 2>/dev/null | _filter_scratch |
> _getfacl_filter_id
Yep good catch, the scratch mount point was making it into the .out file.
> > +
> > + echo "From user_ns"
> > + $nsexec -U -M "0 $acl1 1000" -G "0 $acl2 1000" getfacl -n
> > $file 2>/dev/null | _getfacl_filter_id | sed -e
> > "s!$SCRATCH_MNT!\$SCRATCH_MNT!"
> Same as above.
> ...
> Also need to update 314.out
>
> I tested with these changes as test 316 but not sure if the new
> output is correct.
Yes it looks correct with these changes, updated patch to follow.
> --Rich
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2] xfstests generic/318: user namespace uid/gids in an ACL
2013-08-19 14:11 ` Rich Johnston
2013-08-19 17:34 ` Dwight Engen
@ 2013-08-19 17:34 ` Dwight Engen
2013-08-19 20:49 ` Rich Johnston
1 sibling, 1 reply; 14+ messages in thread
From: Dwight Engen @ 2013-08-19 17:34 UTC (permalink / raw)
To: Rich Johnston; +Cc: xfs
Signed-off-by: Dwight Engen <dwight.engen@oracle.com>
---
v2 Fixed to use --absolute-names and _filter_scratch to get reproducible
pathnames in the .out file, renumbered to 318 and rebased onto 531a2473.
common/attr | 14 +++++++
tests/generic/318 | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++
tests/generic/318.out | 51 +++++++++++++++++++++++++
tests/generic/group | 1 +
4 files changed, 168 insertions(+)
create mode 100755 tests/generic/318
create mode 100644 tests/generic/318.out
diff --git a/common/attr b/common/attr
index e5070bf..4a3ac9e 100644
--- a/common/attr
+++ b/common/attr
@@ -54,6 +54,20 @@ _acl_filter_id()
-e "s/ $acl3 / id3 /"
}
+_getfacl_filter_id()
+{
+ sed \
+ -e "s/user:$acl1/user:id1/" \
+ -e "s/user:$acl2/user:id2/" \
+ -e "s/user:$acl3/user:id3/" \
+ -e "s/group:$acl1/group:id1/" \
+ -e "s/group:$acl2/group:id2/" \
+ -e "s/group:$acl3/group:id3/" \
+ -e "s/: $acl1/: id1/" \
+ -e "s/: $acl2/: id2/" \
+ -e "s/: $acl3/: id3/"
+}
+
# filtered ls
#
_acl_ls()
diff --git a/tests/generic/318 b/tests/generic/318
new file mode 100755
index 0000000..d3bce51
--- /dev/null
+++ b/tests/generic/318
@@ -0,0 +1,102 @@
+#! /bin/bash
+# FS QA Test No. 318
+#
+# Check get/set ACLs to/from disk with a user namespace. A new file
+# will be created and ACLs set on it from both inside a userns and
+# from init_user_ns. We check that the ACL is is correct from both
+# inside the userns and also from init_user_ns. We will then unmount
+# and remount the file system and check the ACL from both inside the
+# userns and from init_user_ns to show that the correct uid/gid in
+# the ACL was flushed and brought back from disk.
+#
+#-----------------------------------------------------------------------
+# Copyright (C) 2013 Oracle, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#-----------------------------------------------------------------------
+#
+
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+
+_cleanup()
+{
+ cd /
+ umount $SCRATCH_DEV >/dev/null 2>&1
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/attr
+
+nsexec=$here/src/nsexec
+file=$SCRATCH_MNT/file1
+
+# real QA test starts here
+_supported_fs generic
+# only Linux supports user namespace
+_supported_os Linux
+
+[ -x $nsexec ] || _notrun "$nsexec executable not found"
+
+rm -f $seqres.full
+
+_require_scratch
+_need_to_be_root
+_acl_setup_ids
+_require_acls
+
+_print_getfacls()
+{
+ echo "From init_user_ns"
+ getfacl --absolute-names -n $file 2>/dev/null | _filter_scratch | _getfacl_filter_id
+
+ echo "From user_ns"
+ $nsexec -U -M "0 $acl1 1000" -G "0 $acl2 1000" getfacl --absolute-names -n $file 2>/dev/null | _filter_scratch | _getfacl_filter_id
+}
+
+umount $SCRATCH_DEV >/dev/null 2>&1
+echo "*** MKFS ***" >>$seqres.full
+echo "" >>$seqres.full
+_scratch_mkfs >>$seqres.full 2>&1 || _fail "mkfs failed"
+_scratch_mount >>$seqres.full 2>&1 || _fail "mount failed"
+
+touch $file
+chown $acl1.$acl1 $file
+
+# set acls from init_user_ns, to be checked from inside the userns
+setfacl -n -m u:$acl2:rw,g:$acl2:r $file
+# set acls from inside userns, to be checked from init_user_ns
+$nsexec -s -U -M "0 $acl1 1000" -G "0 $acl2 1000" setfacl -n -m u:root:rx,g:root:x $file
+
+_print_getfacls
+
+echo "*** Remounting ***"
+echo ""
+sync
+umount $SCRATCH_MNT >>$seqres.full 2>&1
+_scratch_mount >>$seqres.full 2>&1 || _fail "mount failed"
+
+_print_getfacls
+
+umount $SCRATCH_DEV >/dev/null 2>&1
+status=0
+exit
diff --git a/tests/generic/318.out b/tests/generic/318.out
new file mode 100644
index 0000000..e2b42a4
--- /dev/null
+++ b/tests/generic/318.out
@@ -0,0 +1,51 @@
+QA output created by 318
+From init_user_ns
+# file: SCRATCH_MNT/file1
+# owner: id1
+# group: id1
+user::rw-
+user:id1:r-x #effective:r--
+user:id2:rw- #effective:r--
+group::r--
+group:id2:--x #effective:---
+mask::r--
+other::r--
+
+From user_ns
+# file: SCRATCH_MNT/file1
+# owner: 0
+# group: 65534
+user::rw-
+user:0:r-x #effective:r--
+user:1:rw- #effective:r--
+group::r--
+group:0:--x #effective:---
+mask::r--
+other::r--
+
+*** Remounting ***
+
+From init_user_ns
+# file: SCRATCH_MNT/file1
+# owner: id1
+# group: id1
+user::rw-
+user:id1:r-x #effective:r--
+user:id2:rw- #effective:r--
+group::r--
+group:id2:--x #effective:---
+mask::r--
+other::r--
+
+From user_ns
+# file: SCRATCH_MNT/file1
+# owner: 0
+# group: 65534
+user::rw-
+user:0:r-x #effective:r--
+user:1:rw- #effective:r--
+group::r--
+group:0:--x #effective:---
+mask::r--
+other::r--
+
diff --git a/tests/generic/group b/tests/generic/group
index 59baf9e..1aee03c 100644
--- a/tests/generic/group
+++ b/tests/generic/group
@@ -120,3 +120,4 @@
315 auto quick rw prealloc
316 auto quick
317 auto metadata quick
+318 acl attr auto quick
--
1.8.1.4
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v2] xfstests generic/318: user namespace uid/gids in an ACL
2013-08-19 17:34 ` [PATCH v2] xfstests generic/318: " Dwight Engen
@ 2013-08-19 20:49 ` Rich Johnston
0 siblings, 0 replies; 14+ messages in thread
From: Rich Johnston @ 2013-08-19 20:49 UTC (permalink / raw)
To: Dwight Engen; +Cc: xfs
Looks good Dwight, thanks for reworking the patch, it has been committed.
commit 511f9be2595f4d9bc4447335d839227d85969e8a
Author: Dwight Engen <dwight.engen@oracle.com>
Date: Mon Aug 19 17:34:42 2013 +0000
xfstests generic/318: user namespace uid/gids in an ACL
Signed-off-by: Dwight Engen <dwight.engen@oracle.com>
Reviewed-by: Rich Johnston <rjohnston@sgi.com>
Signed-off-by: Rich Johnston <rjohnston@sgi.com>
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2013-08-19 20:49 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-06-25 19:34 [PATCH] xfstests: 313,314: user namespace uid/gids in inode, ACL Dwight Engen
2013-06-26 1:09 ` Dave Chinner
2013-06-26 16:30 ` Dwight Engen
2013-06-27 16:03 ` [PATCH 1/3] xfstests: add nsexec user namespace helper Dwight Engen
2013-08-19 14:10 ` Rich Johnston
2013-08-19 15:03 ` Rich Johnston
2013-06-27 16:03 ` [PATCH 2/3] xfstests 313: user namespace uid/gids in an inode Dwight Engen
2013-08-19 14:10 ` Rich Johnston
2013-08-19 15:03 ` Rich Johnston
2013-06-27 16:03 ` [PATCH 3/3] xfstests 314: user namespace uid/gids in an ACL Dwight Engen
2013-08-19 14:11 ` Rich Johnston
2013-08-19 17:34 ` Dwight Engen
2013-08-19 17:34 ` [PATCH v2] xfstests generic/318: " Dwight Engen
2013-08-19 20:49 ` Rich Johnston
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.