From: Christian Brauner <christian.brauner@ubuntu.com>
To: Eryu Guan <guan@eryu.me>, Christoph Hellwig <hch@lst.de>
Cc: Christian Brauner <brauner@kernel.org>,
linux-fsdevel@vger.kernel.org,
Seth Forshee <seth.forshee@digitalocean.com>,
stable@vger.kernel.org, Eryu Guan <guaneryu@gmail.com>,
fstests@vger.kernel.org
Subject: Re: [PATCH 2/2] generic: test circular mappings
Date: Mon, 15 Nov 2021 12:08:30 +0100 [thread overview]
Message-ID: <20211115110830.rjovyme34ur7mszk@wittgenstein> (raw)
In-Reply-To: <YZEVb/7sTwScTsQ0@desktop>
On Sun, Nov 14, 2021 at 09:55:59PM +0800, Eryu Guan wrote:
> On Tue, Nov 09, 2021 at 03:57:13PM +0100, Christian Brauner wrote:
> > From: Christian Brauner <christian.brauner@ubuntu.com>
> >
> > This test makes sure that setattr behaves correctly on idmapped mounts
> > that make use of circular mappings. Such mappings may e.g. be used to
> > allow two users to share home directories through the same idmapped
> > mount. The tests are explained in detail in code comments.
> >
> > Cc: Seth Forshee <seth.forshee@digitalocean.com>
> > Cc: Eryu Guan <guaneryu@gmail.com>
> > Cc: Christoph Hellwig <hch@lst.de>
> > Cc: fstests@vger.kernel.org
> > CC: linux-fsdevel@vger.kernel.org
> > Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
>
> Is this test known to fail with v5.15-rc7 kernel? I hit the following
> failure:
>
> +idmapped-mounts.c: 13585: setattr_fix - Operation not permitted - failure: change ownership
> +idmapped-mounts.c: 13898: run_test - Success - failure: test that setattr works correctly
Yep, that's expected to fail. This is a regression test. The associated
fix is patch 1/2 in the series. I'm just waiting for Christoph to give
the vfs part an ack before sending it to Linus later this week.
>
> If the bug has been fixed, it'd be better to document the commit that
> fixed the issue in both commit log and test description.
Once the fix is merged I'll include it.
>
> And is there a "1/2" patch? I only see this "2/2" in mailing list.
Yeah, there is but it is the vfs fix. It can be retrieved via b4.
>
> > ---
> > src/idmapped-mounts/idmapped-mounts.c | 434 +++++++++++++++++++++++++-
> > src/idmapped-mounts/utils.c | 43 ++-
> > tests/generic/651 | 27 ++
> > tests/generic/651.out | 2 +
> > 4 files changed, 503 insertions(+), 3 deletions(-)
> > create mode 100755 tests/generic/651
> > create mode 100644 tests/generic/651.out
> >
> > diff --git a/src/idmapped-mounts/idmapped-mounts.c b/src/idmapped-mounts/idmapped-mounts.c
> > index 83b7c89a..b803d171 100644
> > --- a/src/idmapped-mounts/idmapped-mounts.c
> > +++ b/src/idmapped-mounts/idmapped-mounts.c
> > @@ -14,6 +14,7 @@
> > #include <linux/limits.h>
> > #include <linux/types.h>
> > #include <pthread.h>
> > +#include <pwd.h>
> > #include <sched.h>
> > #include <stdbool.h>
> > #include <sys/fsuid.h>
> > @@ -409,6 +410,23 @@ static inline bool switch_fsids(uid_t fsuid, gid_t fsgid)
> > return true;
> > }
> >
> > +static inline bool switch_resids(uid_t uid, gid_t gid)
> > +{
> > + if (setresgid(gid, gid, gid))
> > + return log_errno(false, "failure: setregid");
> > +
> > + if (setresuid(uid, uid, uid))
> > + return log_errno(false, "failure: setresuid");
> > +
> > + if (setfsgid(-1) != gid)
> > + return log_errno(false, "failure: setfsgid(-1)");
> > +
> > + if (setfsuid(-1) != uid)
> > + return log_errno(false, "failure: setfsuid(-1)");
> > +
> > + return true;
> > +}
> > +
> > static inline bool switch_userns(int fd, uid_t uid, gid_t gid, bool drop_caps)
> > {
> > if (setns(fd, CLONE_NEWUSER))
> > @@ -636,6 +654,11 @@ __attribute__((unused)) static int print_r(int fd, const char *path)
> >
> > return ret;
> > }
> > +#else
> > +__attribute__((unused)) static int print_r(int fd, const char *path)
> > +{
> > + return 0;
> > +}
> > #endif
> >
> > /* fd_to_fd - transfer data from one fd to another */
> > @@ -13325,6 +13348,401 @@ out:
> > return fret;
> > }
> >
> > +#define USER1 "fsgqa"
> > +#define USER2 "fsgqa2"
> > +
> > +/**
> > + * lookup_ids - lookup uid and gid for a username
> > + * @name: [in] name of the user
> > + * @uid: [out] pointer to the user-ID
> > + * @gid: [out] pointer to the group-ID
> > + *
> > + * Lookup the uid and gid of a user.
> > + *
> > + * Return: On success, true is returned.
> > + * On error, false is returned.
> > + */
> > +static bool lookup_ids(const char *name, uid_t *uid, gid_t *gid)
> > +{
> > + bool bret = false;
> > + struct passwd *pwentp = NULL;
> > + struct passwd pwent;
> > + char *buf;
> > + ssize_t bufsize;
> > + int ret;
> > +
> > + bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
> > + if (bufsize < 0)
> > + bufsize = 1024;
> > +
> > + buf = malloc(bufsize);
> > + if (!buf)
> > + return bret;
> > +
> > + ret = getpwnam_r(name, &pwent, buf, bufsize, &pwentp);
> > + if (!ret && pwentp) {
> > + *uid = pwent.pw_uid;
> > + *gid = pwent.pw_gid;
> > + bret = true;
> > + }
> > +
> > + free(buf);
> > + return bret;
> > +}
> > +
> > +/**
> > + * setattr_fix - test that setattr works correctly
> > + *
> > + * Test that ->setattr() works correctly for idmapped mounts with circular
> > + * idmappings such as:
> > + *
> > + * b:1000:1001:1
> > + * b:1001:1000:1
> > + *
> > + * Assume a directory /source with two files:
> > + *
> > + * /source/file1 | 1000:1000
> > + * /source/file2 | 1001:1001
> > + *
> > + * and we create an idmapped mount of /source at /target with an idmapped of:
> > + *
> > + * mnt_userns: 1000:1001:1
> > + * 1001:1000:1
> > + *
> > + * In the idmapped mount file1 will be owned by uid 1001 and file2 by uid 1000:
> > + *
> > + * /target/file1 | 1001:1001
> > + * /target/file2 | 1000:1000
> > + *
> > + * Because in essence the idmapped mount switches ownership for {g,u}id 1000
> > + * and {g,u}id 1001.
> > + *
> > + * 1. A user with fs{g,u}id 1000 must be allowed to setattr /target/file2 from
> > + * {g,u}id 1000 in the idmapped mount to {g,u}id 1000.
> > + * 2. A user with fs{g,u}id 1001 must be allowed to setattr /target/file1 from
> > + * {g,u}id 1001 in the idmapped mount to {g,u}id 1001.
> > + * 3. A user with fs{g,u}id 1000 must fail to setattr /target/file1 from
> > + * {g,u}id 1001 in the idmapped mount to {g,u}id 1000.
> > + * This must fail with EPERM. The caller's fs{g,u}id doesn't match the
> > + * {g,u}id of the file.
> > + * 4. A user with fs{g,u}id 1001 must fail to setattr /target/file2 from
> > + * {g,u}id 1000 in the idmapped mount to {g,u}id 1000.
> > + * This must fail with EPERM. The caller's fs{g,u}id doesn't match the
> > + * {g,u}id of the file.
> > + * 5. Both, a user with fs{g,u}id 1000 and a user with fs{g,u}id 1001, must
> > + * fail to setattr /target/file1 owned by {g,u}id 1001 in the idmapped mount
> > + * and /target/file2 owned by {g,u}id 1000 in the idmapped mount to any
> > + * {g,u}id apart from {g,u}id 1000 or 1001 with EINVAL.
> > + * Only {g,u}id 1000 and 1001 have a mapping in the idmapped mount. Other
> > + * {g,u}id are unmapped.
> > + */
> > +static int setattr_fix(void)
> > +{
> > + int fret = -1;
> > + int open_tree_fd = -EBADF;
> > + struct mount_attr attr = {
> > + .attr_set = MOUNT_ATTR_IDMAP,
> > + .userns_fd = -EBADF,
> > + };
> > + int ret;
> > + uid_t user1_uid, user2_uid;
> > + gid_t user1_gid, user2_gid;
> > + pid_t pid;
> > + struct list idmap;
> > + struct list *it_cur, *it_next;
> > +
> > + if (!caps_supported())
> > + return 0;
> > +
> > + list_init(&idmap);
> > +
> > + if (!lookup_ids(USER1, &user1_uid, &user1_gid)) {
> > + log_stderr("failure: lookup_user");
> > + goto out;
> > + }
> > +
> > + if (!lookup_ids(USER2, &user2_uid, &user2_gid)) {
> > + log_stderr("failure: lookup_user");
> > + goto out;
> > + }
> > +
> > + log_debug("Found " USER1 " with uid(%d) and gid(%d) and " USER2 " with uid(%d) and gid(%d)",
> > + user1_uid, user1_gid, user2_uid, user2_gid);
> > +
> > + if (mkdirat(t_dir1_fd, DIR1, 0777)) {
> > + log_stderr("failure: mkdirat");
> > + goto out;
> > + }
> > +
> > + if (mknodat(t_dir1_fd, DIR1 "/" FILE1, S_IFREG | 0644, 0)) {
> > + log_stderr("failure: mknodat");
> > + goto out;
> > + }
> > +
> > + if (chown_r(t_mnt_fd, T_DIR1, user1_uid, user1_gid)) {
> > + log_stderr("failure: chown_r");
> > + goto out;
> > + }
> > +
> > + if (mknodat(t_dir1_fd, DIR1 "/" FILE2, S_IFREG | 0644, 0)) {
> > + log_stderr("failure: mknodat");
> > + goto out;
> > + }
> > +
> > + if (fchownat(t_dir1_fd, DIR1 "/" FILE2, user2_uid, user2_gid, AT_SYMLINK_NOFOLLOW)) {
> > + log_stderr("failure: fchownat");
> > + goto out;
> > + }
> > +
> > + print_r(t_mnt_fd, T_DIR1);
> > +
> > + /* u:1000:1001:1 */
> > + ret = add_map_entry(&idmap, user1_uid, user2_uid, 1, ID_TYPE_UID);
> > + if (ret) {
> > + log_stderr("failure: add_map_entry");
> > + goto out;
> > + }
> > +
> > + /* u:1001:1000:1 */
> > + ret = add_map_entry(&idmap, user2_uid, user1_uid, 1, ID_TYPE_UID);
> > + if (ret) {
> > + log_stderr("failure: add_map_entry");
> > + goto out;
> > + }
> > +
> > + /* g:1000:1001:1 */
> > + ret = add_map_entry(&idmap, user1_gid, user2_gid, 1, ID_TYPE_GID);
> > + if (ret) {
> > + log_stderr("failure: add_map_entry");
> > + goto out;
> > + }
> > +
> > + /* g:1001:1000:1 */
> > + ret = add_map_entry(&idmap, user2_gid, user1_gid, 1, ID_TYPE_GID);
> > + if (ret) {
> > + log_stderr("failure: add_map_entry");
> > + goto out;
> > + }
> > +
> > + attr.userns_fd = get_userns_fd_from_idmap(&idmap);
> > + if (attr.userns_fd < 0) {
> > + log_stderr("failure: get_userns_fd");
> > + goto out;
> > + }
> > +
> > + open_tree_fd = sys_open_tree(t_dir1_fd, DIR1,
> > + AT_NO_AUTOMOUNT |
> > + AT_SYMLINK_NOFOLLOW |
> > + OPEN_TREE_CLOEXEC |
> > + OPEN_TREE_CLONE |
> > + AT_RECURSIVE);
> > + if (open_tree_fd < 0) {
> > + log_stderr("failure: sys_open_tree");
> > + goto out;
> > + }
> > +
> > + if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
> > + log_stderr("failure: sys_mount_setattr");
> > + goto out;
> > + }
> > +
> > + print_r(open_tree_fd, "");
> > +
> > + pid = fork();
> > + if (pid < 0) {
> > + log_stderr("failure: fork");
> > + goto out;
> > + }
> > + if (pid == 0) {
> > + /* switch to {g,u}id 1001 */
> > + if (!switch_resids(user2_uid, user2_gid))
> > + die("failure: switch_resids");
> > +
> > + /* drop all capabilities */
> > + if (!caps_down())
> > + die("failure: caps_down");
> > +
> > + /*
> > + * The {g,u}id 0 is not mapped in this idmapped mount so this
> > + * needs to fail with EINVAL.
> > + */
> > + if (!fchownat(open_tree_fd, FILE1, 0, 0, AT_SYMLINK_NOFOLLOW))
> > + die("failure: change ownership");
> > + if (errno != EINVAL)
> > + die("failure: errno");
> > +
> > + /*
> > + * A user with fs{g,u}id 1001 must be allowed to change
> > + * ownership of /target/file1 owned by {g,u}id 1001 in this
> > + * idmapped mount to {g,u}id 1001.
> > + */
> > + if (fchownat(open_tree_fd, FILE1, user2_uid, user2_gid,
> > + AT_SYMLINK_NOFOLLOW))
> > + die("failure: change ownership");
> > +
> > + /* Verify that the ownership is still {g,u}id 1001. */
> > + if (!expected_uid_gid(open_tree_fd, FILE1, AT_SYMLINK_NOFOLLOW,
> > + user2_uid, user2_gid))
> > + die("failure: check ownership");
> > +
> > + /*
> > + * A user with fs{g,u}id 1001 must not be allowed to change
> > + * ownership of /target/file1 owned by {g,u}id 1001 in this
> > + * idmapped mount to {g,u}id 1000.
> > + */
> > + if (!fchownat(open_tree_fd, FILE1, user1_uid, user1_gid,
> > + AT_SYMLINK_NOFOLLOW))
> > + die("failure: change ownership");
> > + if (errno != EPERM)
> > + die("failure: errno");
> > +
> > + /* Verify that the ownership is still {g,u}id 1001. */
> > + if (!expected_uid_gid(open_tree_fd, FILE1, AT_SYMLINK_NOFOLLOW,
> > + user2_uid, user2_gid))
> > + die("failure: check ownership");
> > +
> > + /*
> > + * A user with fs{g,u}id 1001 must not be allowed to change
> > + * ownership of /target/file2 owned by {g,u}id 1000 in this
> > + * idmapped mount to {g,u}id 1000.
> > + */
> > + if (!fchownat(open_tree_fd, FILE2, user1_uid, user1_gid,
> > + AT_SYMLINK_NOFOLLOW))
> > + die("failure: change ownership");
> > + if (errno != EPERM)
> > + die("failure: errno");
> > +
> > + /* Verify that the ownership is still {g,u}id 1000. */
> > + if (!expected_uid_gid(open_tree_fd, FILE2, AT_SYMLINK_NOFOLLOW,
> > + user1_uid, user1_gid))
> > + die("failure: check ownership");
> > +
> > + /*
> > + * A user with fs{g,u}id 1001 must not be allowed to change
> > + * ownership of /target/file2 owned by {g,u}id 1000 in this
> > + * idmapped mount to {g,u}id 1001.
> > + */
> > + if (!fchownat(open_tree_fd, FILE2, user2_uid, user2_gid,
> > + AT_SYMLINK_NOFOLLOW))
> > + die("failure: change ownership");
> > + if (errno != EPERM)
> > + die("failure: errno");
> > +
> > + /* Verify that the ownership is still {g,u}id 1000. */
> > + if (!expected_uid_gid(open_tree_fd, FILE2, AT_SYMLINK_NOFOLLOW,
> > + user1_uid, user1_gid))
> > + die("failure: check ownership");
> > +
> > + exit(EXIT_SUCCESS);
> > + }
> > + if (wait_for_pid(pid))
> > + goto out;
> > +
> > + pid = fork();
> > + if (pid < 0) {
> > + log_stderr("failure: fork");
> > + goto out;
> > + }
> > + if (pid == 0) {
> > + /* switch to {g,u}id 1000 */
> > + if (!switch_resids(user1_uid, user1_gid))
> > + die("failure: switch_resids");
> > +
> > + /* drop all capabilities */
> > + if (!caps_down())
> > + die("failure: caps_down");
> > +
> > + /*
> > + * The {g,u}id 0 is not mapped in this idmapped mount so this
> > + * needs to fail with EINVAL.
> > + */
> > + if (!fchownat(open_tree_fd, FILE1, 0, 0, AT_SYMLINK_NOFOLLOW))
> > + die("failure: change ownership");
> > + if (errno != EINVAL)
> > + die("failure: errno");
> > +
> > + /*
> > + * A user with fs{g,u}id 1000 must be allowed to change
> > + * ownership of /target/file2 owned by {g,u}id 1000 in this
> > + * idmapped mount to {g,u}id 1000.
> > + */
> > + if (fchownat(open_tree_fd, FILE2, user1_uid, user1_gid,
> > + AT_SYMLINK_NOFOLLOW))
> > + die("failure: change ownership");
> > +
> > + /* Verify that the ownership is still {g,u}id 1000. */
> > + if (!expected_uid_gid(open_tree_fd, FILE2, AT_SYMLINK_NOFOLLOW,
> > + user1_uid, user1_gid))
> > + die("failure: check ownership");
> > +
> > + /*
> > + * A user with fs{g,u}id 1000 must not be allowed to change
> > + * ownership of /target/file2 owned by {g,u}id 1000 in this
> > + * idmapped mount to {g,u}id 1001.
> > + */
> > + if (!fchownat(open_tree_fd, FILE2, user2_uid, user2_gid,
> > + AT_SYMLINK_NOFOLLOW))
> > + die("failure: change ownership");
> > + if (errno != EPERM)
> > + die("failure: errno");
> > +
> > + /* Verify that the ownership is still {g,u}id 1000. */
> > + if (!expected_uid_gid(open_tree_fd, FILE2, AT_SYMLINK_NOFOLLOW,
> > + user1_uid, user1_gid))
> > + die("failure: check ownership");
> > +
> > + /*
> > + * A user with fs{g,u}id 1000 must not be allowed to change
> > + * ownership of /target/file1 owned by {g,u}id 1001 in this
> > + * idmapped mount to {g,u}id 1000.
> > + */
> > + if (!fchownat(open_tree_fd, FILE1, user1_uid, user1_gid,
> > + AT_SYMLINK_NOFOLLOW))
> > + die("failure: change ownership");
> > + if (errno != EPERM)
> > + die("failure: errno");
> > +
> > + /* Verify that the ownership is still {g,u}id 1001. */
> > + if (!expected_uid_gid(open_tree_fd, FILE1, AT_SYMLINK_NOFOLLOW,
> > + user2_uid, user2_gid))
> > + die("failure: check ownership");
> > +
> > + /*
> > + * A user with fs{g,u}id 1000 must not be allowed to change
> > + * ownership of /target/file1 owned by {g,u}id 1001 in this
> > + * idmapped mount to {g,u}id 1001.
> > + */
> > + if (!fchownat(open_tree_fd, FILE1, user2_uid, user2_gid,
> > + AT_SYMLINK_NOFOLLOW))
> > + die("failure: change ownership");
> > + if (errno != EPERM)
> > + die("failure: errno");
> > +
> > + /* Verify that the ownership is still {g,u}id 1001. */
> > + if (!expected_uid_gid(open_tree_fd, FILE1, AT_SYMLINK_NOFOLLOW,
> > + user2_uid, user2_gid))
> > + die("failure: check ownership");
> > +
> > + exit(EXIT_SUCCESS);
> > + }
> > + if (wait_for_pid(pid))
> > + goto out;
> > +
> > + fret = 0;
> > + log_debug("Ran test");
> > +out:
> > + safe_close(attr.userns_fd);
> > + safe_close(open_tree_fd);
> > +
> > + list_for_each_safe(it_cur, &idmap, it_next) {
> > + list_del(it_cur);
> > + free(it_cur->elem);
> > + free(it_cur);
> > + }
> > +
> > + return fret;
> > +}
> > +
> > static void usage(void)
> > {
> > fprintf(stderr, "Description:\n");
> > @@ -13342,6 +13760,7 @@ static void usage(void)
> > fprintf(stderr, "--test-fscaps-regression Run fscap regression tests\n");
> > fprintf(stderr, "--test-nested-userns Run nested userns idmapped mount testsuite\n");
> > fprintf(stderr, "--test-btrfs Run btrfs specific idmapped mount testsuite\n");
> > + fprintf(stderr, "--test-setattr-fix Run setattr regression tests\n");
> >
> > _exit(EXIT_SUCCESS);
> > }
> > @@ -13358,6 +13777,7 @@ static const struct option longopts[] = {
> > {"test-fscaps-regression", no_argument, 0, 'g'},
> > {"test-nested-userns", no_argument, 0, 'n'},
> > {"test-btrfs", no_argument, 0, 'b'},
> > + {"test-setattr-fix", no_argument, 0, 'i'},
> > {NULL, 0, 0, 0},
> > };
> >
> > @@ -13449,6 +13869,10 @@ struct t_idmapped_mounts t_btrfs[] = {
> > { btrfs_subvolume_lookup_user, "test unprivileged subvolume lookup", },
> > };
> >
> > +struct t_idmapped_mounts t_setattr_fix[] = {
> > + { setattr_fix, "test that setattr works correctly", },
> > +};
> > +
> > static bool run_test(struct t_idmapped_mounts suite[], size_t suite_size)
> > {
> > int i;
> > @@ -13487,7 +13911,8 @@ int main(int argc, char *argv[])
> > int fret, ret;
> > int index = 0;
> > bool supported = false, test_btrfs = false, test_core = false,
> > - test_fscaps_regression = false, test_nested_userns = false;
> > + test_fscaps_regression = false, test_nested_userns = false,
> > + test_setattr_fix = false;
> >
> > while ((ret = getopt_long_only(argc, argv, "", longopts, &index)) != -1) {
> > switch (ret) {
> > @@ -13521,6 +13946,9 @@ int main(int argc, char *argv[])
> > case 'e':
> > t_device_scratch = optarg;
> > break;
> > + case 'i':
> > + test_setattr_fix = true;
> > + break;
> > case 'h':
> > /* fallthrough */
> > default:
> > @@ -13609,6 +14037,10 @@ int main(int argc, char *argv[])
> > if (test_btrfs && !run_test(t_btrfs, ARRAY_SIZE(t_btrfs)))
> > goto out;
> >
> > + if (test_setattr_fix &&
> > + !run_test(t_setattr_fix, ARRAY_SIZE(t_setattr_fix)))
> > + goto out;
> > +
> > fret = EXIT_SUCCESS;
> >
> > out:
> > diff --git a/src/idmapped-mounts/utils.c b/src/idmapped-mounts/utils.c
> > index c2afa8dc..faf06fcd 100644
> > --- a/src/idmapped-mounts/utils.c
> > +++ b/src/idmapped-mounts/utils.c
> > @@ -183,6 +183,43 @@ static int map_ids_from_idmap(struct list *idmap, pid_t pid)
> > return 0;
> > }
> >
> > +#ifdef DEBUG_TRACE
> > +static void __print_idmaps(pid_t pid, bool gid)
> > +{
> > + char path_mapping[STRLITERALLEN("/proc/") + INTTYPE_TO_STRLEN(pid_t) +
> > + STRLITERALLEN("/_id_map") + 1];
> > + char *line = NULL;
> > + size_t len = 0;
> > + int ret;
> > + FILE *f;
> > +
> > + ret = snprintf(path_mapping, sizeof(path_mapping), "/proc/%d/%cid_map",
> > + pid, gid ? 'g' : 'u');
> > + if (ret < 0 || (size_t)ret >= sizeof(path_mapping))
> > + return;
> > +
> > + f = fopen(path_mapping, "r");
> > + if (!f)
> > + return;
> > +
> > + while ((ret = getline(&line, &len, f)) > 0)
> > + fprintf(stderr, "%s", line);
> > +
> > + fclose(f);
> > + free(line);
> > +}
> > +
> > +static void print_idmaps(pid_t pid)
> > +{
> > + __print_idmaps(pid, false);
> > + __print_idmaps(pid, true);
> > +}
> > +#else
> > +static void print_idmaps(pid_t pid)
> > +{
> > +}
> > +#endif
> > +
> > int get_userns_fd_from_idmap(struct list *idmap)
> > {
> > int ret;
> > @@ -199,10 +236,12 @@ int get_userns_fd_from_idmap(struct list *idmap)
> > return ret;
> >
> > ret = snprintf(path_ns, sizeof(path_ns), "/proc/%d/ns/user", pid);
> > - if (ret < 0 || (size_t)ret >= sizeof(path_ns))
> > + if (ret < 0 || (size_t)ret >= sizeof(path_ns)) {
> > ret = -EIO;
> > - else
> > + } else {
> > ret = open(path_ns, O_RDONLY | O_CLOEXEC | O_NOCTTY);
> > + print_idmaps(pid);
> > + }
> >
> > (void)kill(pid, SIGKILL);
> > (void)wait_for_pid(pid);
> > diff --git a/tests/generic/651 b/tests/generic/651
> > new file mode 100755
> > index 00000000..49b288d0
> > --- /dev/null
> > +++ b/tests/generic/651
> > @@ -0,0 +1,27 @@
> > +#! /bin/bash
> > +# SPDX-License-Identifier: GPL-2.0
> > +# Copyright (c) 2021 Christian Brauner. All Rights Reserved.
> > +#
> > +# FS QA Test 651
> > +#
> > +# Test that setattr works correctly.
> > +#
> > +. ./common/preamble
> > +_begin_fstest auto attr cap idmapped mount perms
> > +
> > +# Import common functions.
> > +. ./common/filter
> > +
> > +# real QA test starts here
> > +
> > +_supported_fs generic
> > +_require_idmapped_mounts
> > +_require_test
>
> This test also requires user 'fsgqa' and 'fsgqa2'
>
> _require_user fsgqa
> _require_user fsgqa2
>
> Thanks,
> Eryu
>
> > +
> > +echo "Silence is golden"
> > +
> > +$here/src/idmapped-mounts/idmapped-mounts --test-setattr-fix \
> > + --device "$TEST_DEV" --mount "$TEST_DIR" --fstype "$FSTYP"
> > +
> > +status=$?
> > +exit
> > diff --git a/tests/generic/651.out b/tests/generic/651.out
> > new file mode 100644
> > index 00000000..51d73665
> > --- /dev/null
> > +++ b/tests/generic/651.out
> > @@ -0,0 +1,2 @@
> > +QA output created by 651
> > +Silence is golden
> >
> > base-commit: bae1d15f6421cbe99b3e2e134c39d50248e7c261
> > --
> > 2.30.2
>
next prev parent reply other threads:[~2021-11-15 11:09 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-11-09 14:57 [PATCH 1/2] fs: handle circular mappings correctly Christian Brauner
2021-11-09 14:57 ` [PATCH 2/2] generic: test circular mappings Christian Brauner
2021-11-14 13:55 ` Eryu Guan
2021-11-15 11:08 ` Christian Brauner [this message]
2021-11-16 9:40 ` [PATCH 1/2] fs: handle circular mappings correctly Christian Brauner
2021-11-16 15:10 ` Seth Forshee
2021-11-17 6:04 ` Christoph Hellwig
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=20211115110830.rjovyme34ur7mszk@wittgenstein \
--to=christian.brauner@ubuntu.com \
--cc=brauner@kernel.org \
--cc=fstests@vger.kernel.org \
--cc=guan@eryu.me \
--cc=guaneryu@gmail.com \
--cc=hch@lst.de \
--cc=linux-fsdevel@vger.kernel.org \
--cc=seth.forshee@digitalocean.com \
--cc=stable@vger.kernel.org \
/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).