From patchwork Thu Apr 28 15:15:49 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Brauner X-Patchwork-Id: 12830907 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B971AC433EF for ; Thu, 28 Apr 2022 15:16:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1348918AbiD1PTm (ORCPT ); Thu, 28 Apr 2022 11:19:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42178 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348932AbiD1PTk (ORCPT ); Thu, 28 Apr 2022 11:19:40 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A33A4AF1F1 for ; Thu, 28 Apr 2022 08:16:25 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 2698D61F3B for ; Thu, 28 Apr 2022 15:16:25 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6E635C385BE; Thu, 28 Apr 2022 15:16:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1651158984; bh=3X/E6BVrcoKK4YOZNc9P58C0yP9GydP/imp43kRapqI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jRreC87vDQQ/Eo5Tsh4Dlx4kp84mq4IYkd5c188jtzKgEGyTFfUiVshGruooDoILW gJ2jAdUS+Su/czBjOQ3QeWMypC7Qj8r72YY3urIR3un95kcWSXas1SmRrSsvg9tT00 H9tWFOEy5xgcaiMQ+YAYvTnF3UqUKAaHthSiVIj2MnQdVDmD5RVRkB6P7dRiPl+ISG AOuR7k4Wtv9LSjHQDpyQLu8ndvZelwo7fXSm7B983LBgtpD5E6q6ihZ+Jc6uiIQToS Tz2X9jrBoW9JZ+5zdZfrK1+9wwizxQQVEYv8zJXE6iRufwaS18yZ16AqLSbU6qqN/o zpLMtZLIxA4lg== From: Christian Brauner To: Eryu Guan , Zorro Lang , fstests Cc: Christian Brauner , Dave Chinner , Amir Goldstein , Christoph Hellwig , Jan Kara , "Darrick J. Wong" Subject: [PATCH 01/11] src: rename idmapped-mounts folder Date: Thu, 28 Apr 2022 17:15:49 +0200 Message-Id: <20220428151559.947144-2-brauner@kernel.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220428151559.947144-1-brauner@kernel.org> References: <20220428151559.947144-1-brauner@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=10732; h=from:subject; bh=3X/E6BVrcoKK4YOZNc9P58C0yP9GydP/imp43kRapqI=; b=owGbwMvMwCU28Zj0gdSKO4sYT6slMSRlrV90ySlW/bq1vjeveaLtlhN7rv22u6q/jkdM7dfm7buv bn+g3lHKwiDGxSArpsji0G4SLrecp2KzUaYGzBxWJpAhDFycAjCR6wcZ/seKmil0a/5SP+a8ie1eZJ qv14e9Ql6bFpn26Qpt4K7aNp/hN6v5f7Hpi15NcZzsWfC980aVl3TK8bmOZYH/Pwss+3VWgxEA X-Developer-Key: i=brauner@kernel.org; a=openpgp; fpr=4880B8C9BD0E5106FC070F4F7B3C391EFEA93624 Precedence: bulk List-ID: X-Mailing-List: fstests@vger.kernel.org The idmapped mounts test suite has grown to cover a lot of generic vfs functionality that is not concerned with idmapped mounts at all. As was discussed upstream it's time to rename it to something that reflects its generic nature. So rename it from idmapped-mounts to vfs. Cc: Dave Chinner Cc: Amir Goldstein Cc: Eryu Guan Cc: Christoph Hellwig Cc: Zorro Lang Cc: "Darrick J. Wong" Cc: fstests Signed-off-by: Christian Brauner (Microsoft) --- .gitignore | 4 +-- common/rc | 28 +++++++++---------- src/Makefile | 2 +- src/detached_mounts_propagation.c | 2 +- src/feature.c | 2 +- src/{idmapped-mounts => vfs}/Makefile | 4 +-- .../idmapped-mounts.c | 0 src/{idmapped-mounts => vfs}/missing.h | 0 src/{idmapped-mounts => vfs}/mount-idmapped.c | 0 src/{idmapped-mounts => vfs}/utils.c | 0 src/{idmapped-mounts => vfs}/utils.h | 0 tests/btrfs/245 | 2 +- tests/generic/633 | 2 +- tests/generic/644 | 2 +- tests/generic/645 | 2 +- tests/generic/656 | 2 +- tests/xfs/152 | 2 +- tests/xfs/153 | 2 +- 18 files changed, 28 insertions(+), 28 deletions(-) rename src/{idmapped-mounts => vfs}/Makefile (86%) rename src/{idmapped-mounts => vfs}/idmapped-mounts.c (100%) rename src/{idmapped-mounts => vfs}/missing.h (100%) rename src/{idmapped-mounts => vfs}/mount-idmapped.c (100%) rename src/{idmapped-mounts => vfs}/utils.c (100%) rename src/{idmapped-mounts => vfs}/utils.h (100%) diff --git a/.gitignore b/.gitignore index 5f24909e..b9e42635 100644 --- a/.gitignore +++ b/.gitignore @@ -192,8 +192,8 @@ tags /src/aio-dio-regress/aio-last-ref-held-by-io /src/aio-dio-regress/aiocp /src/aio-dio-regress/aiodio_sparse2 -/src/idmapped-mounts/idmapped-mounts -/src/idmapped-mounts/mount-idmapped +/src/vfs/idmapped-mounts +/src/vfs/mount-idmapped /src/log-writes/replay-log /src/perf/*.pyc diff --git a/common/rc b/common/rc index 553ae350..b0940872 100644 --- a/common/rc +++ b/common/rc @@ -355,23 +355,23 @@ _scratch_mount_idmapped() if [ "$type" = "u" ]; then # This means root will be able to create files as uid %id in # the underlying filesystem by going through the idmapped mount. - $here/src/idmapped-mounts/mount-idmapped --map-mount u:0:$id:1 \ - --map-mount u:$id:0:1 \ - --map-mount g:0:0:1 \ - "$SCRATCH_MNT" "$SCRATCH_MNT" || _fail "mount-idmapped failed" + $here/src/vfs/mount-idmapped --map-mount u:0:$id:1 \ + --map-mount u:$id:0:1 \ + --map-mount g:0:0:1 \ + "$SCRATCH_MNT" "$SCRATCH_MNT" || _fail "mount-idmapped failed" elif [ "$type" = "g" ]; then # This means root will be able to create files as gid %id in # the underlying filesystem by going through the idmapped mount. - $here/src/idmapped-mounts/mount-idmapped --map-mount g:0:$id:1 \ - --map-mount g:$id:0:1 \ - --map-mount u:0:0:1 \ - "$SCRATCH_MNT" "$SCRATCH_MNT" || _fail "mount-idmapped failed" + $here/src/vfs/mount-idmapped --map-mount g:0:$id:1 \ + --map-mount g:$id:0:1 \ + --map-mount u:0:0:1 \ + "$SCRATCH_MNT" "$SCRATCH_MNT" || _fail "mount-idmapped failed" elif [ "$type" = "b" ]; then # This means root will be able to create files as uid and gid # %id in the underlying filesystem by going through the idmapped mount. - $here/src/idmapped-mounts/mount-idmapped --map-mount b:0:$id:1 \ - --map-mount b:$id:0:1 \ - "$SCRATCH_MNT" "$SCRATCH_MNT" || _fail "mount-idmapped failed" + $here/src/vfs/mount-idmapped --map-mount b:0:$id:1 \ + --map-mount b:$id:0:1 \ + "$SCRATCH_MNT" "$SCRATCH_MNT" || _fail "mount-idmapped failed" else _fail "usage: either \"u\" (uid), \"g\" (gid), or \"b\" (uid and gid) must be specified " fi @@ -480,7 +480,7 @@ _idmapped_mount() # {g,u}id 10000000 and $(id -u fsgqa) + 10000000. We change ownership # of $mnt so {g,u} id 0 can actually create objects in there. chown 10000000:10000000 $mnt || return 1 - $here/src/idmapped-mounts/mount-idmapped \ + $here/src/vfs/mount-idmapped \ --map-mount b:10000000:0:100000000000 \ $mnt $tmp if [ $? -ne 0 ]; then @@ -2287,12 +2287,12 @@ _require_mount_setattr() # test whether idmapped mounts are supported _require_idmapped_mounts() { - IDMAPPED_MOUNTS_TEST=$here/src/idmapped-mounts/idmapped-mounts + IDMAPPED_MOUNTS_TEST=$here/src/vfs/idmapped-mounts [ -x $IDMAPPED_MOUNTS_TEST ] || _notrun "idmapped-mounts utilities required" _require_mount_setattr - $here/src/idmapped-mounts/idmapped-mounts --supported \ + $here/src/vfs/idmapped-mounts --supported \ --device "$TEST_DEV" \ --mount "$TEST_DIR" \ --fstype "$FSTYP" diff --git a/src/Makefile b/src/Makefile index 24aef09b..7eeb08ef 100644 --- a/src/Makefile +++ b/src/Makefile @@ -76,7 +76,7 @@ TARGETS += uring_read_fault LLDLIBS += -luring endif -SUBDIRS += idmapped-mounts +SUBDIRS += vfs ifeq ($(HAVE_LIBCAP), true) LLDLIBS += -lcap endif diff --git a/src/detached_mounts_propagation.c b/src/detached_mounts_propagation.c index d4bc87f9..17db2c02 100644 --- a/src/detached_mounts_propagation.c +++ b/src/detached_mounts_propagation.c @@ -26,7 +26,7 @@ #include #include -#include "idmapped-mounts/missing.h" +#include "vfs/missing.h" static bool is_shared_mountpoint(const char *path) { diff --git a/src/feature.c b/src/feature.c index bc0b0b30..941f96fb 100644 --- a/src/feature.c +++ b/src/feature.c @@ -46,7 +46,7 @@ #include #endif -#include "idmapped-mounts/missing.h" +#include "vfs/missing.h" #ifndef USRQUOTA #define USRQUOTA 0 diff --git a/src/idmapped-mounts/Makefile b/src/vfs/Makefile similarity index 86% rename from src/idmapped-mounts/Makefile rename to src/vfs/Makefile index ad4ddc99..2df3daf8 100644 --- a/src/idmapped-mounts/Makefile +++ b/src/vfs/Makefile @@ -34,7 +34,7 @@ mount-idmapped: $(CFILES_MOUNT_IDMAPPED) $(Q)$(LTLINK) $(CFILES_MOUNT_IDMAPPED) -o $@ $(CFLAGS) $(LDFLAGS) $(LDLIBS) install: - $(INSTALL) -m 755 -d $(PKG_LIB_DIR)/src/idmapped-mounts - $(INSTALL) -m 755 $(TARGETS) $(PKG_LIB_DIR)/src/idmapped-mounts + $(INSTALL) -m 755 -d $(PKG_LIB_DIR)/src/vfs + $(INSTALL) -m 755 $(TARGETS) $(PKG_LIB_DIR)/src/vfs -include .dep diff --git a/src/idmapped-mounts/idmapped-mounts.c b/src/vfs/idmapped-mounts.c similarity index 100% rename from src/idmapped-mounts/idmapped-mounts.c rename to src/vfs/idmapped-mounts.c diff --git a/src/idmapped-mounts/missing.h b/src/vfs/missing.h similarity index 100% rename from src/idmapped-mounts/missing.h rename to src/vfs/missing.h diff --git a/src/idmapped-mounts/mount-idmapped.c b/src/vfs/mount-idmapped.c similarity index 100% rename from src/idmapped-mounts/mount-idmapped.c rename to src/vfs/mount-idmapped.c diff --git a/src/idmapped-mounts/utils.c b/src/vfs/utils.c similarity index 100% rename from src/idmapped-mounts/utils.c rename to src/vfs/utils.c diff --git a/src/idmapped-mounts/utils.h b/src/vfs/utils.h similarity index 100% rename from src/idmapped-mounts/utils.h rename to src/vfs/utils.h diff --git a/tests/btrfs/245 b/tests/btrfs/245 index f3380ac2..6403f878 100755 --- a/tests/btrfs/245 +++ b/tests/btrfs/245 @@ -26,7 +26,7 @@ _scratch_mount "-o user_subvol_rm_allowed" >> $seqres.full echo "Silence is golden" -$here/src/idmapped-mounts/idmapped-mounts --test-btrfs --device "$TEST_DEV" \ +$here/src/vfs/idmapped-mounts --test-btrfs --device "$TEST_DEV" \ --mountpoint "$TEST_DIR" --scratch-device "$SCRATCH_DEV" \ --scratch-mountpoint "$SCRATCH_MNT" --fstype "$FSTYP" diff --git a/tests/generic/633 b/tests/generic/633 index 38280647..2054b646 100755 --- a/tests/generic/633 +++ b/tests/generic/633 @@ -19,7 +19,7 @@ _require_test echo "Silence is golden" -$here/src/idmapped-mounts/idmapped-mounts --test-core --device "$TEST_DEV" \ +$here/src/vfs/idmapped-mounts --test-core --device "$TEST_DEV" \ --mount "$TEST_DIR" --fstype "$FSTYP" status=$? diff --git a/tests/generic/644 b/tests/generic/644 index 9ed5a511..17fc0539 100755 --- a/tests/generic/644 +++ b/tests/generic/644 @@ -21,7 +21,7 @@ _require_test echo "Silence is golden" -$here/src/idmapped-mounts/idmapped-mounts --test-fscaps-regression \ +$here/src/vfs/idmapped-mounts --test-fscaps-regression \ --device "$TEST_DEV" --mount "$TEST_DIR" --fstype "$FSTYP" status=$? diff --git a/tests/generic/645 b/tests/generic/645 index ffe30bb4..f1209ad0 100755 --- a/tests/generic/645 +++ b/tests/generic/645 @@ -21,7 +21,7 @@ _require_test echo "Silence is golden" -$here/src/idmapped-mounts/idmapped-mounts --test-nested-userns \ +$here/src/vfs/idmapped-mounts --test-nested-userns \ --device "$TEST_DEV" --mount "$TEST_DIR" --fstype "$FSTYP" status=$? diff --git a/tests/generic/656 b/tests/generic/656 index 1231de31..9e95ac96 100755 --- a/tests/generic/656 +++ b/tests/generic/656 @@ -26,7 +26,7 @@ _require_group fsgqa2 echo "Silence is golden" -$here/src/idmapped-mounts/idmapped-mounts --test-setattr-fix-968219708108 \ +$here/src/vfs/idmapped-mounts --test-setattr-fix-968219708108 \ --device "$TEST_DEV" --mount "$TEST_DIR" --fstype "$FSTYP" status=$? diff --git a/tests/xfs/152 b/tests/xfs/152 index 129d9c06..de9b8fc6 100755 --- a/tests/xfs/152 +++ b/tests/xfs/152 @@ -34,7 +34,7 @@ _cleanup() # real QA test starts here _supported_fs xfs _require_idmapped_mounts -_require_test_program "idmapped-mounts/mount-idmapped" +_require_test_program "vfs/mount-idmapped" _require_scratch _require_xfs_quota _require_user fsgqa diff --git a/tests/xfs/153 b/tests/xfs/153 index 37303701..8e1430c0 100755 --- a/tests/xfs/153 +++ b/tests/xfs/153 @@ -34,7 +34,7 @@ _require_scratch _require_xfs_quota _require_user fsgqa _require_idmapped_mounts -_require_test_program "idmapped-mounts/mount-idmapped" +_require_test_program "vfs/mount-idmapped" _scratch_mkfs >/dev/null 2>&1 _scratch_mount From patchwork Thu Apr 28 15:15:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Brauner X-Patchwork-Id: 12830908 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6F3C0C433FE for ; Thu, 28 Apr 2022 15:16:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1348935AbiD1PTp (ORCPT ); Thu, 28 Apr 2022 11:19:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42508 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348919AbiD1PTp (ORCPT ); Thu, 28 Apr 2022 11:19:45 -0400 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EBB9BAF1F1 for ; Thu, 28 Apr 2022 08:16:29 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id AB18EB82E10 for ; Thu, 28 Apr 2022 15:16:28 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 13B1CC385AE; Thu, 28 Apr 2022 15:16:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1651158987; bh=KeCXrr3FeYA22vMQdWUUiQ6CdwbsF6BIAXDWdlmbS0w=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=E0P1kHOE1fKydKxSJLjiE0rUCY3Et7d7p4eURrlZ0yANacsr1gG7YpvTAWceiyp5j +RpQ8yS6ScGAIgQXXLKSGSzaOUyAyHSRRMUEclkPh8n3hZ4WLQ7648BwnX7hfvI+4p c7/MdU2v0igMtiXy5sxfX6jOjgID9I/Z4rbEb1UTwH5s2ca9KoeSOgL6AGUIM51nmn quk1Y+uQupxfn8/qLXCf0nKE/iBt0U/PIrYV7z0zUuqef8ewnc8yV0R2lPv5XkSU17 5JLQ86SKDbTPX2jNdJn6F6qK3Jwm9s1z7DLDTmjgO2lZ+xbrkKFVcqNbD2zDhsrepF zg+HSGj5gv8Mw== From: Christian Brauner To: Eryu Guan , Zorro Lang , fstests Cc: Christian Brauner , Dave Chinner , Amir Goldstein , Christoph Hellwig , Jan Kara , "Darrick J. Wong" Subject: [PATCH 02/11] src/vfs: rename idmapped-mounts.c file Date: Thu, 28 Apr 2022 17:15:50 +0200 Message-Id: <20220428151559.947144-3-brauner@kernel.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220428151559.947144-1-brauner@kernel.org> References: <20220428151559.947144-1-brauner@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=8603; h=from:subject; bh=KeCXrr3FeYA22vMQdWUUiQ6CdwbsF6BIAXDWdlmbS0w=; b=owGbwMvMwCU28Zj0gdSKO4sYT6slMSRlrV+00HtqzfmJHUcu9KyeGF+966Bdj3mj5JcDDFnqE1TM GZYd7ShlYRDjYpAVU2RxaDcJl1vOU7HZKFMDZg4rE8gQBi5OAZjIxAaG/y4vyzf0rtT25d5iXsXhHf vmd+ElvbSNb1sPVzTavWQ0q2VkOFfNqsslopVh2FabIXP63pdlC8QEOFaLRtwurVDrk9rCAAA= X-Developer-Key: i=brauner@kernel.org; a=openpgp; fpr=4880B8C9BD0E5106FC070F4F7B3C391EFEA93624 Precedence: bulk List-ID: X-Mailing-List: fstests@vger.kernel.org The idmapped mounts test suite has grown to cover a lot of generic vfs functionality that is not concerned with idmapped mounts at all. As was discussed upstream it's time to rename it to something that reflects its generic nature. So rename the source file from idmapped-mounts.c to vfstest.c before we split it into multiple source files in the next patches. Cc: Dave Chinner Cc: Amir Goldstein Cc: Eryu Guan Cc: Christoph Hellwig Cc: Zorro Lang Cc: "Darrick J. Wong" Cc: fstests Signed-off-by: Christian Brauner (Microsoft) --- .gitignore | 2 +- common/rc | 8 ++++---- src/vfs/Makefile | 8 ++++---- src/vfs/{idmapped-mounts.c => vfstest.c} | 14 +++++++------- tests/btrfs/245 | 2 +- tests/generic/633 | 2 +- tests/generic/644 | 2 +- tests/generic/645 | 2 +- tests/generic/656 | 2 +- tests/xfs/152 | 2 +- 10 files changed, 22 insertions(+), 22 deletions(-) rename src/vfs/{idmapped-mounts.c => vfstest.c} (99%) diff --git a/.gitignore b/.gitignore index b9e42635..88c79412 100644 --- a/.gitignore +++ b/.gitignore @@ -192,7 +192,7 @@ tags /src/aio-dio-regress/aio-last-ref-held-by-io /src/aio-dio-regress/aiocp /src/aio-dio-regress/aiodio_sparse2 -/src/vfs/idmapped-mounts +/src/vfs/vfstest /src/vfs/mount-idmapped /src/log-writes/replay-log /src/perf/*.pyc diff --git a/common/rc b/common/rc index b0940872..dec6a715 100644 --- a/common/rc +++ b/common/rc @@ -2287,18 +2287,18 @@ _require_mount_setattr() # test whether idmapped mounts are supported _require_idmapped_mounts() { - IDMAPPED_MOUNTS_TEST=$here/src/vfs/idmapped-mounts - [ -x $IDMAPPED_MOUNTS_TEST ] || _notrun "idmapped-mounts utilities required" + IDMAPPED_MOUNTS_TEST=$here/src/vfs/vfstest + [ -x $IDMAPPED_MOUNTS_TEST ] || _notrun "vfstest utilities required" _require_mount_setattr - $here/src/vfs/idmapped-mounts --supported \ + $here/src/vfs/vfstest --idmapped-mounts-supported \ --device "$TEST_DEV" \ --mount "$TEST_DIR" \ --fstype "$FSTYP" if [ $? -ne 0 ]; then - _notrun "idmapped-mounts not support by $FSTYP" + _notrun "vfstest not support by $FSTYP" fi } diff --git a/src/vfs/Makefile b/src/vfs/Makefile index 2df3daf8..adef9ff3 100644 --- a/src/vfs/Makefile +++ b/src/vfs/Makefile @@ -3,8 +3,8 @@ TOPDIR = ../.. include $(TOPDIR)/include/builddefs -TARGETS = idmapped-mounts mount-idmapped -CFILES_IDMAPPED_MOUNTS = idmapped-mounts.c utils.c +TARGETS = vfstest mount-idmapped +CFILES_VFSTEST = vfstest.c utils.c CFILES_MOUNT_IDMAPPED = mount-idmapped.c utils.c HFILES = missing.h utils.h @@ -25,9 +25,9 @@ depend: .dep include $(BUILDRULES) -idmapped-mounts: $(CFILES_IDMAPPED_MOUNTS) +vfstest: $(CFILES_VFSTEST) @echo " [CC] $@" - $(Q)$(LTLINK) $(CFILES_IDMAPPED_MOUNTS) -o $@ $(CFLAGS) $(LDFLAGS) $(LDLIBS) + $(Q)$(LTLINK) $(CFILES_VFSTEST) -o $@ $(CFLAGS) $(LDFLAGS) $(LDLIBS) mount-idmapped: $(CFILES_MOUNT_IDMAPPED) @echo " [CC] $@" diff --git a/src/vfs/idmapped-mounts.c b/src/vfs/vfstest.c similarity index 99% rename from src/vfs/idmapped-mounts.c rename to src/vfs/vfstest.c index 4cf6c3bb..66768175 100644 --- a/src/vfs/idmapped-mounts.c +++ b/src/vfs/vfstest.c @@ -13801,7 +13801,7 @@ static void usage(void) fprintf(stderr, "--fstype Filesystem type used in the tests\n"); fprintf(stderr, "--help Print help\n"); fprintf(stderr, "--mountpoint Mountpoint of device\n"); - fprintf(stderr, "--supported Test whether idmapped mounts are supported on this filesystem\n"); + fprintf(stderr, "--idmapped-mounts-supported Test whether idmapped mounts are supported on this filesystem\n"); fprintf(stderr, "--scratch-mountpoint Mountpoint of scratch device used in the tests\n"); fprintf(stderr, "--scratch-device Scratch device used in the tests\n"); fprintf(stderr, "--test-core Run core idmapped mount testsuite\n"); @@ -13819,7 +13819,7 @@ static const struct option longopts[] = { {"mountpoint", required_argument, 0, 'm'}, {"scratch-mountpoint", required_argument, 0, 'a'}, {"scratch-device", required_argument, 0, 'e'}, - {"supported", no_argument, 0, 's'}, + {"idmapped-mounts-supported", no_argument, 0, 's'}, {"help", no_argument, 0, 'h'}, {"test-core", no_argument, 0, 'c'}, {"test-fscaps-regression", no_argument, 0, 'g'}, @@ -13998,9 +13998,9 @@ 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_setattr_fix_968219708108 = false; + bool idmapped_mounts_supported = false, test_btrfs = false, + test_core = false, test_fscaps_regression = false, + test_nested_userns = false, test_setattr_fix_968219708108 = false; while ((ret = getopt_long_only(argc, argv, "", longopts, &index)) != -1) { switch (ret) { @@ -14014,7 +14014,7 @@ int main(int argc, char *argv[]) t_mountpoint = optarg; break; case 's': - supported = true; + idmapped_mounts_supported = true; break; case 'c': test_core = true; @@ -14070,7 +14070,7 @@ int main(int argc, char *argv[]) die("failed to open %s", t_mountpoint_scratch); t_fs_allow_idmap = fs_allow_idmap(); - if (supported) { + if (idmapped_mounts_supported) { /* * Caller just wants to know whether the filesystem we're on * supports idmapped mounts. diff --git a/tests/btrfs/245 b/tests/btrfs/245 index 6403f878..dadc8492 100755 --- a/tests/btrfs/245 +++ b/tests/btrfs/245 @@ -26,7 +26,7 @@ _scratch_mount "-o user_subvol_rm_allowed" >> $seqres.full echo "Silence is golden" -$here/src/vfs/idmapped-mounts --test-btrfs --device "$TEST_DEV" \ +$here/src/vfs/vfstest --test-btrfs --device "$TEST_DEV" \ --mountpoint "$TEST_DIR" --scratch-device "$SCRATCH_DEV" \ --scratch-mountpoint "$SCRATCH_MNT" --fstype "$FSTYP" diff --git a/tests/generic/633 b/tests/generic/633 index 2054b646..9b29dbf1 100755 --- a/tests/generic/633 +++ b/tests/generic/633 @@ -19,7 +19,7 @@ _require_test echo "Silence is golden" -$here/src/vfs/idmapped-mounts --test-core --device "$TEST_DEV" \ +$here/src/vfs/vfstest --test-core --device "$TEST_DEV" \ --mount "$TEST_DIR" --fstype "$FSTYP" status=$? diff --git a/tests/generic/644 b/tests/generic/644 index 17fc0539..edf9b03e 100755 --- a/tests/generic/644 +++ b/tests/generic/644 @@ -21,7 +21,7 @@ _require_test echo "Silence is golden" -$here/src/vfs/idmapped-mounts --test-fscaps-regression \ +$here/src/vfs/vfstest --test-fscaps-regression \ --device "$TEST_DEV" --mount "$TEST_DIR" --fstype "$FSTYP" status=$? diff --git a/tests/generic/645 b/tests/generic/645 index f1209ad0..74e0f589 100755 --- a/tests/generic/645 +++ b/tests/generic/645 @@ -21,7 +21,7 @@ _require_test echo "Silence is golden" -$here/src/vfs/idmapped-mounts --test-nested-userns \ +$here/src/vfs/vfstest --test-nested-userns \ --device "$TEST_DEV" --mount "$TEST_DIR" --fstype "$FSTYP" status=$? diff --git a/tests/generic/656 b/tests/generic/656 index 9e95ac96..5c090cfa 100755 --- a/tests/generic/656 +++ b/tests/generic/656 @@ -26,7 +26,7 @@ _require_group fsgqa2 echo "Silence is golden" -$here/src/vfs/idmapped-mounts --test-setattr-fix-968219708108 \ +$here/src/vfs/vfstest --test-setattr-fix-968219708108 \ --device "$TEST_DEV" --mount "$TEST_DIR" --fstype "$FSTYP" status=$? diff --git a/tests/xfs/152 b/tests/xfs/152 index de9b8fc6..12b77f91 100755 --- a/tests/xfs/152 +++ b/tests/xfs/152 @@ -246,7 +246,7 @@ qmount_idmapped() mkdir -p "${SCRATCH_MNT}/unmapped" mkdir -p "${SCRATCH_MNT}/idmapped" - $here/src/idmapped-mounts/mount-idmapped \ + $here/src/vfstest/mount-idmapped \ --map-mount b:$id:$id2:1 \ --map-mount b:0:0:1 \ "$SCRATCH_MNT/unmapped" "$SCRATCH_MNT/idmapped" || _fail "mount-idmapped failed" From patchwork Thu Apr 28 15:15:51 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Brauner X-Patchwork-Id: 12830909 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AC4E7C433F5 for ; Thu, 28 Apr 2022 15:16:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1348927AbiD1PTs (ORCPT ); Thu, 28 Apr 2022 11:19:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42672 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348919AbiD1PTr (ORCPT ); Thu, 28 Apr 2022 11:19:47 -0400 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9297EAF1F1 for ; Thu, 28 Apr 2022 08:16:32 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 2FBD6B82DE8 for ; Thu, 28 Apr 2022 15:16:31 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id C2DE3C385AF; Thu, 28 Apr 2022 15:16:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1651158990; bh=QoitQqxwnx8NW6C8v901NMYOU/k3OHQ39C4ImBMAFF8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=X1n8ztrNQT3ngWqBKWBv9mgwelVx+JshCL3w0SwI4iP17Kr12H8+9xuOQw0XDk0EK AcBe2jy+wMH3LyJKgoIRoSqNTM8NrtLSFL7IuTh4o5Muny1PBpK56JxXd7ieOxXt9H UCt1cvaJucF9KRbfneOqtYCqE332J88kMeqa1E6D05bm4ordHqrCGIBWcXd7mLKQOT iikRZJQO3zeVK+D1+6jlzMzYPlFFhMLsruhy7AXx4Tv25mt1Ngf1gK0XREfFM8BbX0 MVMpZ7SD1R75TxZBfwDn/ZsliS4SqAjppnHBL8GWCcYAe827yken0XnXJo8MC8o4jn 6wcC0iZJr14FA== From: Christian Brauner To: Eryu Guan , Zorro Lang , fstests Cc: Christian Brauner , Dave Chinner , Amir Goldstein , Christoph Hellwig , Jan Kara , "Darrick J. Wong" Subject: [PATCH 03/11] vfstest: rename struct t_idmapped_mounts Date: Thu, 28 Apr 2022 17:15:51 +0200 Message-Id: <20220428151559.947144-4-brauner@kernel.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220428151559.947144-1-brauner@kernel.org> References: <20220428151559.947144-1-brauner@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=3628; h=from:subject; bh=QoitQqxwnx8NW6C8v901NMYOU/k3OHQ39C4ImBMAFF8=; b=owGbwMvMwCU28Zj0gdSKO4sYT6slMSRlrV+kuOTJSaUtO7eKdcp/S/2917AhUEFs/9biadffRL6a cPHEx45SFgYxLgZZMUUWh3aTcLnlPBWbjTI1YOawMoEMYeDiFICJ8Fgy/K+T5Gv5dba8MlPh0hbPk5 URm0Mj1a9fOcV6dnNnsKmUciTDP10Ohyf8ubc6/eebJRt/07/HEX44NaNJxjor7L1jyGVlNgA= X-Developer-Key: i=brauner@kernel.org; a=openpgp; fpr=4880B8C9BD0E5106FC070F4F7B3C391EFEA93624 Precedence: bulk List-ID: X-Mailing-List: fstests@vger.kernel.org The idmapped mounts test suite has grown to cover a lot of generic vfs functionality that is not concerned with idmapped mounts at all. As was discussed upstream it's time to rename it to something that reflects its generic nature. Rename the basic structure used for the tests from struct t_idmapped_mounts to struct test_struct. Cc: Dave Chinner Cc: Amir Goldstein Cc: Eryu Guan Cc: Christoph Hellwig Cc: Zorro Lang Cc: "Darrick J. Wong" Cc: fstests Signed-off-by: Christian Brauner (Microsoft) --- src/vfs/utils.h | 6 ++++++ src/vfs/vfstest.c | 18 +++++++----------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/vfs/utils.h b/src/vfs/utils.h index afb3c228..06247ec7 100644 --- a/src/vfs/utils.h +++ b/src/vfs/utils.h @@ -49,6 +49,12 @@ __internal_ret__; \ }) +struct test_struct { + int (*test)(void); + bool require_fs_allow_idmap; + const char *description; +}; + typedef enum idmap_type_t { ID_TYPE_UID, ID_TYPE_GID diff --git a/src/vfs/vfstest.c b/src/vfs/vfstest.c index 66768175..4d2fc93e 100644 --- a/src/vfs/vfstest.c +++ b/src/vfs/vfstest.c @@ -13829,11 +13829,7 @@ static const struct option longopts[] = { {NULL, 0, 0, 0}, }; -struct t_idmapped_mounts { - int (*test)(void); - bool require_fs_allow_idmap; - const char *description; -} basic_suite[] = { +struct test_struct basic_suite[] = { { acls, true, "posix acls on regular mounts", }, { create_in_userns, true, "create operations in user namespace", }, { device_node_in_userns, true, "device node in user namespace", }, @@ -13885,15 +13881,15 @@ struct t_idmapped_mounts { { threaded_idmapped_mount_interactions, true, "threaded operations on idmapped mounts", }, }; -struct t_idmapped_mounts fscaps_in_ancestor_userns[] = { +struct test_struct fscaps_in_ancestor_userns[] = { { fscaps_idmapped_mounts_in_userns_valid_in_ancestor_userns, true, "fscaps on idmapped mounts in user namespace writing fscap valid in ancestor userns", }, }; -struct t_idmapped_mounts t_nested_userns[] = { +struct test_struct t_nested_userns[] = { { nested_userns, true, "test that nested user namespaces behave correctly when attached to idmapped mounts", }, }; -struct t_idmapped_mounts t_btrfs[] = { +struct test_struct t_btrfs[] = { { btrfs_subvolumes_fsids_mapped, true, "test subvolumes with mapped fsids", }, { btrfs_subvolumes_fsids_mapped_userns, true, "test subvolumes with mapped fsids inside user namespace", }, { btrfs_subvolumes_fsids_mapped_user_subvol_rm_allowed, true, "test subvolume deletion with user_subvol_rm_allowed mount option", }, @@ -13919,16 +13915,16 @@ struct t_idmapped_mounts t_btrfs[] = { }; /* Test for commit 968219708108 ("fs: handle circular mappings correctly"). */ -struct t_idmapped_mounts t_setattr_fix_968219708108[] = { +struct test_struct t_setattr_fix_968219708108[] = { { setattr_fix_968219708108, true, "test that setattr works correctly", }, }; -static bool run_test(struct t_idmapped_mounts suite[], size_t suite_size) +static bool run_test(struct test_struct suite[], size_t suite_size) { int i; for (i = 0; i < suite_size; i++) { - struct t_idmapped_mounts *t = &suite[i]; + struct test_struct *t = &suite[i]; int ret; pid_t pid; From patchwork Thu Apr 28 15:15:52 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Brauner X-Patchwork-Id: 12830910 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6AAE9C433FE for ; Thu, 28 Apr 2022 15:16:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1348919AbiD1PTu (ORCPT ); Thu, 28 Apr 2022 11:19:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42764 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348946AbiD1PTs (ORCPT ); Thu, 28 Apr 2022 11:19:48 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C4AC9AFAE8 for ; Thu, 28 Apr 2022 08:16:33 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 537D161F41 for ; Thu, 28 Apr 2022 15:16:33 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7389DC385B0; Thu, 28 Apr 2022 15:16:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1651158992; bh=FGqBUcTN5gk/VnU6gAXInm4V3TsEBwfS/ORrAylSkmY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=G7vhDTsPl4DEk95oPL+H8vlkXsZQX1WLrjU6mfckwSyTC0VP23CFyY6pnZtOUM0as KEHHk1wTdGQa2o+0L1VqHo9AD9gNUvZSIQc1geCayrYWnykS+iB8RryOEdlNNCIOPf r1oefDF5QeS889voMmPjuLGnLfl7fMdnwgF7axkNdj8X8Uy9QGmxb/m9tHYh0cmdnl cZG1avEKGvdRT05q/AgkfBLFo6kMCpHS7KPm2gLAhBJ1io2hYgtNSq/sjezVs7TBXP aULi9YcocjwvWI+ICPWglIjsglSPcP8DKhoMCYOLrPU7DAaPUj4EtKkO+OJL4HWeKu cS5uf9ArEn6/w== From: Christian Brauner To: Eryu Guan , Zorro Lang , fstests Cc: Christian Brauner , Dave Chinner , Amir Goldstein , Christoph Hellwig , Jan Kara , "Darrick J. Wong" Subject: [PATCH 04/11] utils: add missing global.h include Date: Thu, 28 Apr 2022 17:15:52 +0200 Message-Id: <20220428151559.947144-5-brauner@kernel.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220428151559.947144-1-brauner@kernel.org> References: <20220428151559.947144-1-brauner@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=823; h=from:subject; bh=FGqBUcTN5gk/VnU6gAXInm4V3TsEBwfS/ORrAylSkmY=; b=owGbwMvMwCU28Zj0gdSKO4sYT6slMSRlrV/Ee3ziyvAtLfEXFl3NWrEmJOPIq38HrKWP2T/9e1Cl I9LzYkcpC4MYF4OsmCKLQ7tJuNxynorNRpkaMHNYmUCGMHBxCsBE3m9l+Ke81u5m44WZ7oLHWnc5hl TdVz94O7Qka6Lur2kWbwtXvRdgZLjeZ7BX7E2FR9hbp6n/z074ZHBihfFT89fpxnt8P3895sgAAA== X-Developer-Key: i=brauner@kernel.org; a=openpgp; fpr=4880B8C9BD0E5106FC070F4F7B3C391EFEA93624 Precedence: bulk List-ID: X-Mailing-List: fstests@vger.kernel.org Make sure that utils.{c,h} have access to the necessary defines created during the configure stage when building xfstests. Cc: Dave Chinner Cc: Amir Goldstein Cc: Eryu Guan Cc: Christoph Hellwig Cc: Zorro Lang Cc: "Darrick J. Wong" Cc: fstests Signed-off-by: Christian Brauner (Microsoft) --- src/vfs/utils.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vfs/utils.h b/src/vfs/utils.h index 06247ec7..ccf2cefb 100644 --- a/src/vfs/utils.h +++ b/src/vfs/utils.h @@ -3,6 +3,8 @@ #ifndef __IDMAP_UTILS_H #define __IDMAP_UTILS_H +#include "../global.h" + #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif From patchwork Thu Apr 28 15:15:54 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Brauner X-Patchwork-Id: 12830911 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 176BEC433F5 for ; Thu, 28 Apr 2022 15:16:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1348972AbiD1PUB (ORCPT ); Thu, 28 Apr 2022 11:20:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43688 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348951AbiD1PT6 (ORCPT ); Thu, 28 Apr 2022 11:19:58 -0400 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 887BBAFB0E for ; Thu, 28 Apr 2022 08:16:41 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 1A9D2B82D65 for ; Thu, 28 Apr 2022 15:16:40 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 99A98C385A0; Thu, 28 Apr 2022 15:16:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1651158998; bh=LVgLeWcpVG2x7R66VKE8TUUvlPl1vDhqvy2rvfhzVGA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=u9L5hI9SP/Wlw59m08I/+KHj53Uc7mN5yeu6iWq9bxFJCxoJiH2oW4y+yaCDuO3P0 UvzPTsX9vD+oYVGILI+mk4sXa6o8TDI4tpPh6c6nvFLlSYpB7ZhckKGpy6HM1bVNzd V2o1SR1B2fYV0ZqyVkVQvKJcG7wMd9AWxuBm2QGEy0OBxskDWuzumv1Pfi5+5RMyu/ m+9KQ20mf4JIzuUcDAujCmlaruBJZOhOzt4JiPA9knIHHvilUtqWUnqVYBqn/KYVj0 alu4+z5fK4Wq6Vw/sRhRiXvpACw695E26RaDpcCu5tnXz+6w6Ysuk04Ld1R0w37hQ+ QNI7nNPPp8ZXg== From: Christian Brauner To: Eryu Guan , Zorro Lang , fstests Cc: Christian Brauner , Dave Chinner , Amir Goldstein , Christoph Hellwig , Jan Kara , "Darrick J. Wong" Subject: [PATCH 06/11] utils: move helpers into utils Date: Thu, 28 Apr 2022 17:15:54 +0200 Message-Id: <20220428151559.947144-7-brauner@kernel.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220428151559.947144-1-brauner@kernel.org> References: <20220428151559.947144-1-brauner@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=34970; h=from:subject; bh=LVgLeWcpVG2x7R66VKE8TUUvlPl1vDhqvy2rvfhzVGA=; b=owGbwMvMwCU28Zj0gdSKO4sYT6slMSRlrV+85fwiKf6m7OKFX28unHdEtzGvcs2Pf03Bn2Zf/7si Ls5pZ0cpC4MYF4OsmCKLQ7tJuNxynorNRpkaMHNYmUCGMHBxCsBEkjwZGf629LK+XcAxxzE3RkMhID uqzyj9wSRbOyNN1kSeHL559gz/83iav7F+2nJyzqe521Mu/TglHWwXJmctOX1n+oo3TD8W8AAA X-Developer-Key: i=brauner@kernel.org; a=openpgp; fpr=4880B8C9BD0E5106FC070F4F7B3C391EFEA93624 Precedence: bulk List-ID: X-Mailing-List: fstests@vger.kernel.org In order to split the test suite into multiple source files we need to be able to access generic helpers in all source files not just one. So move all generic helpers into utils.{c,h}. Cc: Dave Chinner Cc: Amir Goldstein Cc: Eryu Guan Cc: Christoph Hellwig Cc: Zorro Lang Cc: "Darrick J. Wong" Cc: fstests Signed-off-by: Christian Brauner (Microsoft) --- src/vfs/utils.c | 448 +++++++++++++++++++++++++++++++++ src/vfs/utils.h | 193 +++++++++++++++ src/vfs/vfstest.c | 611 ---------------------------------------------- 3 files changed, 641 insertions(+), 611 deletions(-) diff --git a/src/vfs/utils.c b/src/vfs/utils.c index faf06fcd..28944b70 100644 --- a/src/vfs/utils.c +++ b/src/vfs/utils.c @@ -9,12 +9,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include "utils.h" @@ -423,3 +425,449 @@ int add_map_entry(struct list *head, list_add_tail(head, new_list); return 0; } + +/* __expected_uid_gid - check whether file is owned by the provided uid and gid */ +bool __expected_uid_gid(int dfd, const char *path, int flags, + uid_t expected_uid, gid_t expected_gid, bool log) +{ + int ret; + struct stat st; + + ret = fstatat(dfd, path, &st, flags); + if (ret < 0) + return log_errno(false, "failure: fstatat"); + + if (log && st.st_uid != expected_uid) + log_stderr("failure: uid(%d) != expected_uid(%d)", st.st_uid, expected_uid); + + if (log && st.st_gid != expected_gid) + log_stderr("failure: gid(%d) != expected_gid(%d)", st.st_gid, expected_gid); + + errno = 0; /* Don't report misleading errno. */ + return st.st_uid == expected_uid && st.st_gid == expected_gid; +} + +/* caps_down - lower all effective caps */ +int caps_down(void) +{ + bool fret = false; +#ifdef HAVE_SYS_CAPABILITY_H + cap_t caps = NULL; + int ret = -1; + + caps = cap_get_proc(); + if (!caps) + goto out; + + ret = cap_clear_flag(caps, CAP_EFFECTIVE); + if (ret) + goto out; + + ret = cap_set_proc(caps); + if (ret) + goto out; + + fret = true; + +out: + cap_free(caps); +#endif + return fret; +} + +#ifdef HAVE_LIBURING_H +int io_uring_openat_with_creds(struct io_uring *ring, int dfd, const char *path, + int cred_id, bool with_link, int *ret_cqe) +{ + struct io_uring_cqe *cqe; + struct io_uring_sqe *sqe; + int ret, i, to_submit = 1; + + if (with_link) { + sqe = io_uring_get_sqe(ring); + if (!sqe) + return log_error_errno(-EINVAL, EINVAL, "failure: io_uring_sqe"); + io_uring_prep_nop(sqe); + sqe->flags |= IOSQE_IO_LINK; + sqe->user_data = 1; + to_submit++; + } + + sqe = io_uring_get_sqe(ring); + if (!sqe) + return log_error_errno(-EINVAL, EINVAL, "failure: io_uring_sqe"); + io_uring_prep_openat(sqe, dfd, path, O_RDONLY | O_CLOEXEC, 0); + sqe->user_data = 2; + + if (cred_id != -1) + sqe->personality = cred_id; + + ret = io_uring_submit(ring); + if (ret != to_submit) { + log_stderr("failure: io_uring_submit"); + goto out; + } + + for (i = 0; i < to_submit; i++) { + ret = io_uring_wait_cqe(ring, &cqe); + if (ret < 0) { + log_stderr("failure: io_uring_wait_cqe"); + goto out; + } + + ret = cqe->res; + /* + * Make sure caller can identify that this is a proper io_uring + * failure and not some earlier error. + */ + if (ret_cqe) + *ret_cqe = ret; + io_uring_cqe_seen(ring, cqe); + } + log_debug("Ran test"); +out: + return ret; +} +#endif /* HAVE_LIBURING_H */ + +/* caps_up - raise all permitted caps */ +int caps_up(void) +{ + bool fret = false; +#ifdef HAVE_SYS_CAPABILITY_H + cap_t caps = NULL; + cap_value_t cap; + int ret = -1; + + caps = cap_get_proc(); + if (!caps) + goto out; + + for (cap = 0; cap <= CAP_LAST_CAP; cap++) { + cap_flag_value_t flag; + + ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag); + if (ret) { + if (errno == EINVAL) + break; + else + goto out; + } + + ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag); + if (ret) + goto out; + } + + ret = cap_set_proc(caps); + if (ret) + goto out; + + fret = true; +out: + cap_free(caps); +#endif + return fret; +} + +/* chown_r - recursively change ownership of all files */ +int chown_r(int fd, const char *path, uid_t uid, gid_t gid) +{ + int dfd, ret; + DIR *dir; + struct dirent *direntp; + + dfd = openat(fd, path, O_CLOEXEC | O_DIRECTORY); + if (dfd < 0) + return -1; + + dir = fdopendir(dfd); + if (!dir) { + close(dfd); + return -1; + } + + while ((direntp = readdir(dir))) { + struct stat st; + + if (!strcmp(direntp->d_name, ".") || + !strcmp(direntp->d_name, "..")) + continue; + + ret = fstatat(dfd, direntp->d_name, &st, AT_SYMLINK_NOFOLLOW); + if (ret < 0 && errno != ENOENT) + break; + + if (S_ISDIR(st.st_mode)) + ret = chown_r(dfd, direntp->d_name, uid, gid); + else + ret = fchownat(dfd, direntp->d_name, uid, gid, AT_SYMLINK_NOFOLLOW); + if (ret < 0 && errno != ENOENT) + break; + } + + ret = fchownat(fd, path, uid, gid, AT_SYMLINK_NOFOLLOW); + closedir(dir); + return ret; +} + +/* expected_dummy_vfs_caps_uid - check vfs caps are stored with the provided uid */ +bool expected_dummy_vfs_caps_uid(int fd, uid_t expected_uid) +{ +#define __cap_raised_permitted(x, ns_cap_data) \ + ((ns_cap_data.data[(x) >> 5].permitted) & (1 << ((x)&31))) + struct vfs_ns_cap_data ns_xattr = {}; + ssize_t ret; + + ret = fgetxattr(fd, "security.capability", &ns_xattr, sizeof(ns_xattr)); + if (ret < 0 || ret == 0) + return false; + + if (ns_xattr.magic_etc & VFS_CAP_REVISION_3) { + + if (le32_to_cpu(ns_xattr.rootid) != expected_uid) { + errno = EINVAL; + log_stderr("failure: rootid(%d) != expected_rootid(%d)", le32_to_cpu(ns_xattr.rootid), expected_uid); + } + + return (le32_to_cpu(ns_xattr.rootid) == expected_uid) && + (__cap_raised_permitted(CAP_NET_RAW, ns_xattr) > 0); + } else { + log_stderr("failure: fscaps version"); + } + + return false; +} + +/* set_dummy_vfs_caps - set dummy vfs caps for the provided uid */ +int set_dummy_vfs_caps(int fd, int flags, int rootuid) +{ +#define __raise_cap_permitted(x, ns_cap_data) \ + ns_cap_data.data[(x) >> 5].permitted |= (1 << ((x)&31)) + + struct vfs_ns_cap_data ns_xattr; + + memset(&ns_xattr, 0, sizeof(ns_xattr)); + __raise_cap_permitted(CAP_NET_RAW, ns_xattr); + ns_xattr.magic_etc |= VFS_CAP_REVISION_3 | VFS_CAP_FLAGS_EFFECTIVE; + ns_xattr.rootid = cpu_to_le32(rootuid); + + return fsetxattr(fd, "security.capability", + &ns_xattr, sizeof(ns_xattr), flags); +} + +bool protected_symlinks_enabled(void) +{ + static int enabled = -1; + + if (enabled == -1) { + int fd; + ssize_t ret; + char buf[256]; + + enabled = 0; + + fd = open("/proc/sys/fs/protected_symlinks", O_RDONLY | O_CLOEXEC); + if (fd < 0) + return false; + + ret = read(fd, buf, sizeof(buf)); + close(fd); + if (ret < 0) + return false; + + if (atoi(buf) >= 1) + enabled = 1; + } + + return enabled == 1; +} + +static bool is_xfs(const char *fstype) +{ + static int enabled = -1; + + if (enabled == -1) + enabled = !strcmp(fstype, "xfs"); + + return enabled; +} + +bool xfs_irix_sgid_inherit_enabled(const char *fstype) +{ + static int enabled = -1; + + if (enabled == -1) { + int fd; + ssize_t ret; + char buf[256]; + + enabled = 0; + + if (is_xfs(fstype)) { + fd = open("/proc/sys/fs/xfs/irix_sgid_inherit", O_RDONLY | O_CLOEXEC); + if (fd < 0) + return false; + + ret = read(fd, buf, sizeof(buf)); + close(fd); + if (ret < 0) + return false; + + if (atoi(buf) >= 1) + enabled = 1; + } + } + + return enabled == 1; +} + +bool expected_file_size(int dfd, const char *path, int flags, off_t expected_size) +{ + int ret; + struct stat st; + + ret = fstatat(dfd, path, &st, flags); + if (ret < 0) + return log_errno(false, "failure: fstatat"); + + if (st.st_size != expected_size) + return log_errno(false, "failure: st_size(%zu) != expected_size(%zu)", + (size_t)st.st_size, (size_t)expected_size); + + return true; +} + +/* is_setid - check whether file is S_ISUID and S_ISGID */ +bool is_setid(int dfd, const char *path, int flags) +{ + int ret; + struct stat st; + + ret = fstatat(dfd, path, &st, flags); + if (ret < 0) + return false; + + errno = 0; /* Don't report misleading errno. */ + return (st.st_mode & S_ISUID) || (st.st_mode & S_ISGID); +} + +/* is_setgid - check whether file or directory is S_ISGID */ +bool is_setgid(int dfd, const char *path, int flags) +{ + int ret; + struct stat st; + + ret = fstatat(dfd, path, &st, flags); + if (ret < 0) + return false; + + errno = 0; /* Don't report misleading errno. */ + return (st.st_mode & S_ISGID); +} + +/* is_sticky - check whether file is S_ISVTX */ +bool is_sticky(int dfd, const char *path, int flags) +{ + int ret; + struct stat st; + + ret = fstatat(dfd, path, &st, flags); + if (ret < 0) + return false; + + errno = 0; /* Don't report misleading errno. */ + return (st.st_mode & S_ISVTX) > 0; +} + +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; +} + +/* rm_r - recursively remove all files */ +int rm_r(int fd, const char *path) +{ + int dfd, ret; + DIR *dir; + struct dirent *direntp; + + if (!path || strcmp(path, "") == 0) + return -1; + + dfd = openat(fd, path, O_CLOEXEC | O_DIRECTORY); + if (dfd < 0) + return -1; + + dir = fdopendir(dfd); + if (!dir) { + close(dfd); + return -1; + } + + while ((direntp = readdir(dir))) { + struct stat st; + + if (!strcmp(direntp->d_name, ".") || + !strcmp(direntp->d_name, "..")) + continue; + + ret = fstatat(dfd, direntp->d_name, &st, AT_SYMLINK_NOFOLLOW); + if (ret < 0 && errno != ENOENT) + break; + + if (S_ISDIR(st.st_mode)) + ret = rm_r(dfd, direntp->d_name); + else + ret = unlinkat(dfd, direntp->d_name, 0); + if (ret < 0 && errno != ENOENT) + break; + } + + ret = unlinkat(fd, path, AT_REMOVEDIR); + closedir(dir); + return ret; +} + +/* fd_to_fd - transfer data from one fd to another */ +int fd_to_fd(int from, int to) +{ + for (;;) { + uint8_t buf[PATH_MAX]; + uint8_t *p = buf; + ssize_t bytes_to_write; + ssize_t bytes_read; + + bytes_read = read_nointr(from, buf, sizeof buf); + if (bytes_read < 0) + return -1; + if (bytes_read == 0) + break; + + bytes_to_write = (size_t)bytes_read; + do { + ssize_t bytes_written; + + bytes_written = write_nointr(to, p, bytes_to_write); + if (bytes_written < 0) + return -1; + + bytes_to_write -= bytes_written; + p += bytes_written; + } while (bytes_to_write > 0); + } + + return 0; +} diff --git a/src/vfs/utils.h b/src/vfs/utils.h index c0eeb337..3f7cf911 100644 --- a/src/vfs/utils.h +++ b/src/vfs/utils.h @@ -17,11 +17,36 @@ #include #include #include +#include #include #include +#ifdef HAVE_SYS_CAPABILITY_H +#include +#endif + +#ifdef HAVE_LIBURING_H +#include +#endif + #include "missing.h" +#define T_DIR1 "idmapped_mounts_1" +#define FILE1 "file1" +#define FILE1_RENAME "file1_rename" +#define FILE2 "file2" +#define FILE2_RENAME "file2_rename" +#define DIR1 "dir1" +#define DIR2 "dir2" +#define DIR3 "dir3" +#define DIR1_RENAME "dir1_rename" +#define HARDLINK1 "hardlink1" +#define SYMLINK1 "symlink1" +#define SYMLINK_USER1 "symlink_user1" +#define SYMLINK_USER2 "symlink_user2" +#define SYMLINK_USER3 "symlink_user3" +#define CHRDEV1 "chrdev1" + /* Maximum number of nested user namespaces in the kernel. */ #define MAX_USERNS_LEVEL 32 @@ -37,6 +62,37 @@ ? 10 \ : sizeof(type) <= 8 ? 20 : sizeof(int[-2 * (sizeof(type) > 8)]))) +#define log_stderr(format, ...) \ + fprintf(stderr, "%s: %d: %s - %m - " format "\n", __FILE__, __LINE__, __func__, \ + ##__VA_ARGS__) + +#ifdef DEBUG_TRACE +#define log_debug(format, ...) \ + fprintf(stderr, "%s: %d: %s - " format "\n", __FILE__, __LINE__, \ + __func__, ##__VA_ARGS__) +#else +#define log_debug(format, ...) +#endif + +#define log_error_errno(__ret__, __errno__, format, ...) \ + ({ \ + typeof(__ret__) __internal_ret__ = (__ret__); \ + errno = (__errno__); \ + log_stderr(format, ##__VA_ARGS__); \ + __internal_ret__; \ + }) + +#define log_errno(__ret__, format, ...) log_error_errno(__ret__, errno, format, ##__VA_ARGS__) + +#define die_errno(__errno__, format, ...) \ + ({ \ + errno = (__errno__); \ + log_stderr(format, ##__VA_ARGS__); \ + exit(EXIT_FAILURE); \ + }) + +#define die(format, ...) die_errno(errno, format, ##__VA_ARGS__) + #define syserror(format, ...) \ ({ \ fprintf(stderr, "%m - " format "\n", ##__VA_ARGS__); \ @@ -51,6 +107,68 @@ __internal_ret__; \ }) +#define safe_close(fd) \ + if (fd >= 0) { \ + int _e_ = errno; \ + close(fd); \ + errno = _e_; \ + fd = -EBADF; \ + } + +#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0])) + +#ifndef CAP_NET_RAW +#define CAP_NET_RAW 13 +#endif + +#ifndef VFS_CAP_FLAGS_EFFECTIVE +#define VFS_CAP_FLAGS_EFFECTIVE 0x000001 +#endif + +#ifndef VFS_CAP_U32_3 +#define VFS_CAP_U32_3 2 +#endif + +#ifndef VFS_CAP_U32 +#define VFS_CAP_U32 VFS_CAP_U32_3 +#endif + +#ifndef VFS_CAP_REVISION_1 +#define VFS_CAP_REVISION_1 0x01000000 +#endif + +#ifndef VFS_CAP_REVISION_2 +#define VFS_CAP_REVISION_2 0x02000000 +#endif + +#ifndef VFS_CAP_REVISION_3 +#define VFS_CAP_REVISION_3 0x03000000 +struct vfs_ns_cap_data { + __le32 magic_etc; + struct { + __le32 permitted; + __le32 inheritable; + } data[VFS_CAP_U32]; + __le32 rootid; +}; +#endif + +#if __BYTE_ORDER == __BIG_ENDIAN +#define cpu_to_le16(w16) le16_to_cpu(w16) +#define le16_to_cpu(w16) ((u_int16_t)((u_int16_t)(w16) >> 8) | (u_int16_t)((u_int16_t)(w16) << 8)) +#define cpu_to_le32(w32) le32_to_cpu(w32) +#define le32_to_cpu(w32) \ + ((u_int32_t)((u_int32_t)(w32) >> 24) | (u_int32_t)(((u_int32_t)(w32) >> 8) & 0xFF00) | \ + (u_int32_t)(((u_int32_t)(w32) << 8) & 0xFF0000) | (u_int32_t)((u_int32_t)(w32) << 24)) +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#define cpu_to_le16(w16) ((u_int16_t)(w16)) +#define le16_to_cpu(w16) ((u_int16_t)(w16)) +#define cpu_to_le32(w32) ((u_int32_t)(w32)) +#define le32_to_cpu(w32) ((u_int32_t)(w32)) +#else +#error Expected endianess macro to be set +#endif + struct vfstest_info { uid_t t_overflowuid; gid_t t_overflowgid; @@ -153,9 +271,84 @@ extern int get_userns_fd_from_idmap(struct list *idmap); extern ssize_t read_nointr(int fd, void *buf, size_t count); extern int wait_for_pid(pid_t pid); extern ssize_t write_nointr(int fd, const void *buf, size_t count); + +extern int caps_down(void); +extern int caps_up(void); +static inline bool caps_supported(void) +{ + bool ret = false; + +#ifdef HAVE_SYS_CAPABILITY_H + ret = true; +#endif + + return ret; +} +extern bool expected_dummy_vfs_caps_uid(int fd, uid_t expected_uid); +extern int set_dummy_vfs_caps(int fd, int flags, int rootuid); + extern bool switch_ids(uid_t uid, gid_t gid); + extern int create_userns_hierarchy(struct userns_hierarchy *h); extern int add_map_entry(struct list *head, __u32 id_host, __u32 id_ns, __u32 range, idmap_type_t map_type); +extern bool __expected_uid_gid(int dfd, const char *path, int flags, + uid_t expected_uid, gid_t expected_gid, bool log); +static inline bool expected_uid_gid(int dfd, const char *path, int flags, + uid_t expected_uid, gid_t expected_gid) +{ + return __expected_uid_gid(dfd, path, flags, expected_uid, expected_gid, true); +} + +static inline bool switch_userns(int fd, uid_t uid, gid_t gid, bool drop_caps) +{ + if (setns(fd, CLONE_NEWUSER)) + return log_errno(false, "failure: setns"); + + if (!switch_ids(uid, gid)) + return log_errno(false, "failure: switch_ids"); + + if (drop_caps && !caps_down()) + return log_errno(false, "failure: caps_down"); + + return true; +} + +extern bool switch_resids(uid_t uid, gid_t gid); + +static inline bool switch_fsids(uid_t fsuid, gid_t fsgid) +{ + if (setfsgid(fsgid)) + return log_errno(false, "failure: setfsgid"); + + if (setfsgid(-1) != fsgid) + return log_errno(false, "failure: setfsgid(-1)"); + + if (setfsuid(fsuid)) + return log_errno(false, "failure: setfsuid"); + + if (setfsuid(-1) != fsuid) + return log_errno(false, "failure: setfsuid(-1)"); + + return true; +} + +#ifdef HAVE_LIBURING_H +extern int io_uring_openat_with_creds(struct io_uring *ring, int dfd, + const char *path, int cred_id, + bool with_link, int *ret_cqe); +#endif /* HAVE_LIBURING_H */ + +extern int chown_r(int fd, const char *path, uid_t uid, gid_t gid); +extern int rm_r(int fd, const char *path); +extern int fd_to_fd(int from, int to); +extern bool protected_symlinks_enabled(void); +extern bool xfs_irix_sgid_inherit_enabled(const char *fstype); +extern bool expected_file_size(int dfd, const char *path, int flags, + off_t expected_size); +extern bool is_setid(int dfd, const char *path, int flags); +extern bool is_setgid(int dfd, const char *path, int flags); +extern bool is_sticky(int dfd, const char *path, int flags); + #endif /* __IDMAP_UTILS_H */ diff --git a/src/vfs/vfstest.c b/src/vfs/vfstest.c index 55e2772f..c3eb5ae4 100644 --- a/src/vfs/vfstest.c +++ b/src/vfs/vfstest.c @@ -35,66 +35,9 @@ #include #endif -#ifdef HAVE_SYS_CAPABILITY_H -#include -#endif - -#ifdef HAVE_LIBURING_H -#include -#endif - #include "missing.h" #include "utils.h" -#define T_DIR1 "idmapped_mounts_1" -#define FILE1 "file1" -#define FILE1_RENAME "file1_rename" -#define FILE2 "file2" -#define FILE2_RENAME "file2_rename" -#define DIR1 "dir1" -#define DIR2 "dir2" -#define DIR3 "dir3" -#define DIR1_RENAME "dir1_rename" -#define HARDLINK1 "hardlink1" -#define SYMLINK1 "symlink1" -#define SYMLINK_USER1 "symlink_user1" -#define SYMLINK_USER2 "symlink_user2" -#define SYMLINK_USER3 "symlink_user3" -#define CHRDEV1 "chrdev1" - -#define log_stderr(format, ...) \ - fprintf(stderr, "%s: %d: %s - %m - " format "\n", __FILE__, __LINE__, __func__, \ - ##__VA_ARGS__) - -#ifdef DEBUG_TRACE -#define log_debug(format, ...) \ - fprintf(stderr, "%s: %d: %s - " format "\n", __FILE__, __LINE__, \ - __func__, ##__VA_ARGS__) -#else -#define log_debug(format, ...) -#endif - -#define log_error_errno(__ret__, __errno__, format, ...) \ - ({ \ - typeof(__ret__) __internal_ret__ = (__ret__); \ - errno = (__errno__); \ - log_stderr(format, ##__VA_ARGS__); \ - __internal_ret__; \ - }) - -#define log_errno(__ret__, format, ...) log_error_errno(__ret__, errno, format, ##__VA_ARGS__) - -#define die_errno(__errno__, format, ...) \ - ({ \ - errno = (__errno__); \ - log_stderr(format, ##__VA_ARGS__); \ - exit(EXIT_FAILURE); \ - }) - -#define die(format, ...) die_errno(errno, format, ##__VA_ARGS__) - -#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0])) - static char t_buf[PATH_MAX]; static void init_vfstest_info(struct vfstest_info *info) @@ -148,371 +91,6 @@ static void stash_overflowgid(struct vfstest_info *info) info->t_overflowgid = atoi(buf); } -static bool is_xfs(const char *fstype) -{ - static int enabled = -1; - - if (enabled == -1) - enabled = !strcmp(fstype, "xfs"); - - return enabled; -} - -static bool protected_symlinks_enabled(void) -{ - static int enabled = -1; - - if (enabled == -1) { - int fd; - ssize_t ret; - char buf[256]; - - enabled = 0; - - fd = open("/proc/sys/fs/protected_symlinks", O_RDONLY | O_CLOEXEC); - if (fd < 0) - return false; - - ret = read(fd, buf, sizeof(buf)); - close(fd); - if (ret < 0) - return false; - - if (atoi(buf) >= 1) - enabled = 1; - } - - return enabled == 1; -} - -static bool xfs_irix_sgid_inherit_enabled(const char *fstype) -{ - static int enabled = -1; - - if (enabled == -1) { - int fd; - ssize_t ret; - char buf[256]; - - enabled = 0; - - if (is_xfs(fstype)) { - fd = open("/proc/sys/fs/xfs/irix_sgid_inherit", O_RDONLY | O_CLOEXEC); - if (fd < 0) - return false; - - ret = read(fd, buf, sizeof(buf)); - close(fd); - if (ret < 0) - return false; - - if (atoi(buf) >= 1) - enabled = 1; - } - } - - return enabled == 1; -} - -static inline bool caps_supported(void) -{ - bool ret = false; - -#ifdef HAVE_SYS_CAPABILITY_H - ret = true; -#endif - - return ret; -} - -/* caps_down - lower all effective caps */ -static int caps_down(void) -{ - bool fret = false; -#ifdef HAVE_SYS_CAPABILITY_H - cap_t caps = NULL; - int ret = -1; - - caps = cap_get_proc(); - if (!caps) - goto out; - - ret = cap_clear_flag(caps, CAP_EFFECTIVE); - if (ret) - goto out; - - ret = cap_set_proc(caps); - if (ret) - goto out; - - fret = true; - -out: - cap_free(caps); -#endif - return fret; -} - -/* caps_up - raise all permitted caps */ -static int caps_up(void) -{ - bool fret = false; -#ifdef HAVE_SYS_CAPABILITY_H - cap_t caps = NULL; - cap_value_t cap; - int ret = -1; - - caps = cap_get_proc(); - if (!caps) - goto out; - - for (cap = 0; cap <= CAP_LAST_CAP; cap++) { - cap_flag_value_t flag; - - ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag); - if (ret) { - if (errno == EINVAL) - break; - else - goto out; - } - - ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag); - if (ret) - goto out; - } - - ret = cap_set_proc(caps); - if (ret) - goto out; - - fret = true; -out: - cap_free(caps); -#endif - return fret; -} - -/* __expected_uid_gid - check whether file is owned by the provided uid and gid */ -static bool __expected_uid_gid(int dfd, const char *path, int flags, - uid_t expected_uid, gid_t expected_gid, bool log) -{ - int ret; - struct stat st; - - ret = fstatat(dfd, path, &st, flags); - if (ret < 0) - return log_errno(false, "failure: fstatat"); - - if (log && st.st_uid != expected_uid) - log_stderr("failure: uid(%d) != expected_uid(%d)", st.st_uid, expected_uid); - - if (log && st.st_gid != expected_gid) - log_stderr("failure: gid(%d) != expected_gid(%d)", st.st_gid, expected_gid); - - errno = 0; /* Don't report misleading errno. */ - return st.st_uid == expected_uid && st.st_gid == expected_gid; -} - -static bool expected_uid_gid(int dfd, const char *path, int flags, - uid_t expected_uid, gid_t expected_gid) -{ - return __expected_uid_gid(dfd, path, flags, - expected_uid, expected_gid, true); -} - -static bool expected_file_size(int dfd, const char *path, - int flags, off_t expected_size) -{ - int ret; - struct stat st; - - ret = fstatat(dfd, path, &st, flags); - if (ret < 0) - return log_errno(false, "failure: fstatat"); - - if (st.st_size != expected_size) - return log_errno(false, "failure: st_size(%zu) != expected_size(%zu)", - (size_t)st.st_size, (size_t)expected_size); - - return true; -} - -/* is_setid - check whether file is S_ISUID and S_ISGID */ -static bool is_setid(int dfd, const char *path, int flags) -{ - int ret; - struct stat st; - - ret = fstatat(dfd, path, &st, flags); - if (ret < 0) - return false; - - errno = 0; /* Don't report misleading errno. */ - return (st.st_mode & S_ISUID) || (st.st_mode & S_ISGID); -} - -/* is_setgid - check whether file or directory is S_ISGID */ -static bool is_setgid(int dfd, const char *path, int flags) -{ - int ret; - struct stat st; - - ret = fstatat(dfd, path, &st, flags); - if (ret < 0) - return false; - - errno = 0; /* Don't report misleading errno. */ - return (st.st_mode & S_ISGID); -} - -/* is_sticky - check whether file is S_ISVTX */ -static bool is_sticky(int dfd, const char *path, int flags) -{ - int ret; - struct stat st; - - ret = fstatat(dfd, path, &st, flags); - if (ret < 0) - return false; - - errno = 0; /* Don't report misleading errno. */ - return (st.st_mode & S_ISVTX) > 0; -} - -static inline bool switch_fsids(uid_t fsuid, gid_t fsgid) -{ - if (setfsgid(fsgid)) - return log_errno(false, "failure: setfsgid"); - - if (setfsgid(-1) != fsgid) - return log_errno(false, "failure: setfsgid(-1)"); - - if (setfsuid(fsuid)) - return log_errno(false, "failure: setfsuid"); - - if (setfsuid(-1) != fsuid) - return log_errno(false, "failure: setfsuid(-1)"); - - 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)) - return log_errno(false, "failure: setns"); - - if (!switch_ids(uid, gid)) - return log_errno(false, "failure: switch_ids"); - - if (drop_caps && !caps_down()) - return log_errno(false, "failure: caps_down"); - - return true; -} - -/* rm_r - recursively remove all files */ -static int rm_r(int fd, const char *path) -{ - int dfd, ret; - DIR *dir; - struct dirent *direntp; - - if (!path || strcmp(path, "") == 0) - return -1; - - dfd = openat(fd, path, O_CLOEXEC | O_DIRECTORY); - if (dfd < 0) - return -1; - - dir = fdopendir(dfd); - if (!dir) { - close(dfd); - return -1; - } - - while ((direntp = readdir(dir))) { - struct stat st; - - if (!strcmp(direntp->d_name, ".") || - !strcmp(direntp->d_name, "..")) - continue; - - ret = fstatat(dfd, direntp->d_name, &st, AT_SYMLINK_NOFOLLOW); - if (ret < 0 && errno != ENOENT) - break; - - if (S_ISDIR(st.st_mode)) - ret = rm_r(dfd, direntp->d_name); - else - ret = unlinkat(dfd, direntp->d_name, 0); - if (ret < 0 && errno != ENOENT) - break; - } - - ret = unlinkat(fd, path, AT_REMOVEDIR); - closedir(dir); - return ret; -} - -/* chown_r - recursively change ownership of all files */ -static int chown_r(int fd, const char *path, uid_t uid, gid_t gid) -{ - int dfd, ret; - DIR *dir; - struct dirent *direntp; - - dfd = openat(fd, path, O_CLOEXEC | O_DIRECTORY); - if (dfd < 0) - return -1; - - dir = fdopendir(dfd); - if (!dir) { - close(dfd); - return -1; - } - - while ((direntp = readdir(dir))) { - struct stat st; - - if (!strcmp(direntp->d_name, ".") || - !strcmp(direntp->d_name, "..")) - continue; - - ret = fstatat(dfd, direntp->d_name, &st, AT_SYMLINK_NOFOLLOW); - if (ret < 0 && errno != ENOENT) - break; - - if (S_ISDIR(st.st_mode)) - ret = chown_r(dfd, direntp->d_name, uid, gid); - else - ret = fchownat(dfd, direntp->d_name, uid, gid, AT_SYMLINK_NOFOLLOW); - if (ret < 0 && errno != ENOENT) - break; - } - - ret = fchownat(fd, path, uid, gid, AT_SYMLINK_NOFOLLOW); - closedir(dir); - return ret; -} - /* * There'll be scenarios where you'll want to see the attributes associated with * a directory tree during debugging or just to make sure things look correct. @@ -648,37 +226,6 @@ __attribute__((unused)) static int print_r(int fd, const char *path) } #endif -/* fd_to_fd - transfer data from one fd to another */ -static int fd_to_fd(int from, int to) -{ - for (;;) { - uint8_t buf[PATH_MAX]; - uint8_t *p = buf; - ssize_t bytes_to_write; - ssize_t bytes_read; - - bytes_read = read_nointr(from, buf, sizeof buf); - if (bytes_read < 0) - return -1; - if (bytes_read == 0) - break; - - bytes_to_write = (size_t)bytes_read; - do { - ssize_t bytes_written; - - bytes_written = write_nointr(to, p, bytes_to_write); - if (bytes_written < 0) - return -1; - - bytes_to_write -= bytes_written; - p += bytes_written; - } while (bytes_to_write > 0); - } - - return 0; -} - static int sys_execveat(int fd, const char *path, char **argv, char **envp, int flags) { @@ -690,111 +237,6 @@ static int sys_execveat(int fd, const char *path, char **argv, char **envp, #endif } -#ifndef CAP_NET_RAW -#define CAP_NET_RAW 13 -#endif - -#ifndef VFS_CAP_FLAGS_EFFECTIVE -#define VFS_CAP_FLAGS_EFFECTIVE 0x000001 -#endif - -#ifndef VFS_CAP_U32_3 -#define VFS_CAP_U32_3 2 -#endif - -#ifndef VFS_CAP_U32 -#define VFS_CAP_U32 VFS_CAP_U32_3 -#endif - -#ifndef VFS_CAP_REVISION_1 -#define VFS_CAP_REVISION_1 0x01000000 -#endif - -#ifndef VFS_CAP_REVISION_2 -#define VFS_CAP_REVISION_2 0x02000000 -#endif - -#ifndef VFS_CAP_REVISION_3 -#define VFS_CAP_REVISION_3 0x03000000 -struct vfs_ns_cap_data { - __le32 magic_etc; - struct { - __le32 permitted; - __le32 inheritable; - } data[VFS_CAP_U32]; - __le32 rootid; -}; -#endif - -#if __BYTE_ORDER == __BIG_ENDIAN -#define cpu_to_le16(w16) le16_to_cpu(w16) -#define le16_to_cpu(w16) ((u_int16_t)((u_int16_t)(w16) >> 8) | (u_int16_t)((u_int16_t)(w16) << 8)) -#define cpu_to_le32(w32) le32_to_cpu(w32) -#define le32_to_cpu(w32) \ - ((u_int32_t)((u_int32_t)(w32) >> 24) | (u_int32_t)(((u_int32_t)(w32) >> 8) & 0xFF00) | \ - (u_int32_t)(((u_int32_t)(w32) << 8) & 0xFF0000) | (u_int32_t)((u_int32_t)(w32) << 24)) -#elif __BYTE_ORDER == __LITTLE_ENDIAN -#define cpu_to_le16(w16) ((u_int16_t)(w16)) -#define le16_to_cpu(w16) ((u_int16_t)(w16)) -#define cpu_to_le32(w32) ((u_int32_t)(w32)) -#define le32_to_cpu(w32) ((u_int32_t)(w32)) -#else -#error Expected endianess macro to be set -#endif - -/* expected_dummy_vfs_caps_uid - check vfs caps are stored with the provided uid */ -static bool expected_dummy_vfs_caps_uid(int fd, uid_t expected_uid) -{ -#define __cap_raised_permitted(x, ns_cap_data) \ - ((ns_cap_data.data[(x) >> 5].permitted) & (1 << ((x)&31))) - struct vfs_ns_cap_data ns_xattr = {}; - ssize_t ret; - - ret = fgetxattr(fd, "security.capability", &ns_xattr, sizeof(ns_xattr)); - if (ret < 0 || ret == 0) - return false; - - if (ns_xattr.magic_etc & VFS_CAP_REVISION_3) { - - if (le32_to_cpu(ns_xattr.rootid) != expected_uid) { - errno = EINVAL; - log_stderr("failure: rootid(%d) != expected_rootid(%d)", le32_to_cpu(ns_xattr.rootid), expected_uid); - } - - return (le32_to_cpu(ns_xattr.rootid) == expected_uid) && - (__cap_raised_permitted(CAP_NET_RAW, ns_xattr) > 0); - } else { - log_stderr("failure: fscaps version"); - } - - return false; -} - -/* set_dummy_vfs_caps - set dummy vfs caps for the provided uid */ -static int set_dummy_vfs_caps(int fd, int flags, int rootuid) -{ -#define __raise_cap_permitted(x, ns_cap_data) \ - ns_cap_data.data[(x) >> 5].permitted |= (1 << ((x)&31)) - - struct vfs_ns_cap_data ns_xattr; - - memset(&ns_xattr, 0, sizeof(ns_xattr)); - __raise_cap_permitted(CAP_NET_RAW, ns_xattr); - ns_xattr.magic_etc |= VFS_CAP_REVISION_3 | VFS_CAP_FLAGS_EFFECTIVE; - ns_xattr.rootid = cpu_to_le32(rootuid); - - return fsetxattr(fd, "security.capability", - &ns_xattr, sizeof(ns_xattr), flags); -} - -#define safe_close(fd) \ - if (fd >= 0) { \ - int _e_ = errno; \ - close(fd); \ - errno = _e_; \ - fd = -EBADF; \ - } - static void test_setup(struct vfstest_info *info) { if (mkdirat(info->t_mnt_fd, T_DIR1, 0777)) @@ -6924,59 +6366,6 @@ out: } #ifdef HAVE_LIBURING_H -static int io_uring_openat_with_creds(struct io_uring *ring, int dfd, const char *path, int cred_id, - bool with_link, int *ret_cqe) -{ - struct io_uring_cqe *cqe; - struct io_uring_sqe *sqe; - int ret, i, to_submit = 1; - - if (with_link) { - sqe = io_uring_get_sqe(ring); - if (!sqe) - return log_error_errno(-EINVAL, EINVAL, "failure: io_uring_sqe"); - io_uring_prep_nop(sqe); - sqe->flags |= IOSQE_IO_LINK; - sqe->user_data = 1; - to_submit++; - } - - sqe = io_uring_get_sqe(ring); - if (!sqe) - return log_error_errno(-EINVAL, EINVAL, "failure: io_uring_sqe"); - io_uring_prep_openat(sqe, dfd, path, O_RDONLY | O_CLOEXEC, 0); - sqe->user_data = 2; - - if (cred_id != -1) - sqe->personality = cred_id; - - ret = io_uring_submit(ring); - if (ret != to_submit) { - log_stderr("failure: io_uring_submit"); - goto out; - } - - for (i = 0; i < to_submit; i++) { - ret = io_uring_wait_cqe(ring, &cqe); - if (ret < 0) { - log_stderr("failure: io_uring_wait_cqe"); - goto out; - } - - ret = cqe->res; - /* - * Make sure caller can identify that this is a proper io_uring - * failure and not some earlier error. - */ - if (ret_cqe) - *ret_cqe = ret; - io_uring_cqe_seen(ring, cqe); - } - log_debug("Ran test"); -out: - return ret; -} - static int io_uring(const struct vfstest_info *info) { int fret = -1; From patchwork Thu Apr 28 15:15:55 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Brauner X-Patchwork-Id: 12830912 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AF9CAC43217 for ; Thu, 28 Apr 2022 15:16:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1348986AbiD1PUB (ORCPT ); Thu, 28 Apr 2022 11:20:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43914 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348963AbiD1PUA (ORCPT ); Thu, 28 Apr 2022 11:20:00 -0400 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 86FB5AFB1C for ; Thu, 28 Apr 2022 08:16:44 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 121D9B82E14 for ; Thu, 28 Apr 2022 15:16:43 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6DB08C385AF; Thu, 28 Apr 2022 15:16:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1651159001; bh=u4eSjnlK6GHegIrrd4UU7RVKVlXZSGEAdyh+KGVN+iA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jAuM7bIg942XMwV/HVb9QQxjo+Szh/IMLWjsd5W/j+NF9/f9aLwk0ZU3QV5uixXk8 LR3yx3pqTdQWsK38VdpGA0gBk7qZV+Op+4v0eVuOgCertHyL0Wvn7bRpuV2LuK4CVa 7OMVeNHEHkIm8UexMovy1cWwEsg2ukf65m27qG7fyiV4Piuo7UR6McJEdF4cyzLlHX E8QmTVWx3Erqld7juxZAXAxFdo8H6kH8JEat21PMxQREdhB94V519x4cDesF+G2ZCP zQi5rD8Npz1IiX1863k0nGSIZCBZJUNpyxdpeOE97v2fmwMCX0UotIy3ozJWR6QXWZ mNEClt5fL4zgg== From: Christian Brauner To: Eryu Guan , Zorro Lang , fstests Cc: Christian Brauner , Dave Chinner , Amir Goldstein , Christoph Hellwig , Jan Kara , "Darrick J. Wong" Subject: [PATCH 07/11] missing: move sys_execveat() to missing.h Date: Thu, 28 Apr 2022 17:15:55 +0200 Message-Id: <20220428151559.947144-8-brauner@kernel.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220428151559.947144-1-brauner@kernel.org> References: <20220428151559.947144-1-brauner@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=1788; h=from:subject; bh=u4eSjnlK6GHegIrrd4UU7RVKVlXZSGEAdyh+KGVN+iA=; b=owGbwMvMwCU28Zj0gdSKO4sYT6slMSRlrV8c2/Pr1+rZm1MW7/wTnOBVc4vp4bGNs5N33/WLl94j 77+nuaOUhUGMi0FWTJHFod0kXG45T8Vmo0wNmDmsTCBDGLg4BWAik6IZ/gqmMryy56735D9he9rgds zMeK65xe/upet36BdV7Z1tc4Hhf5Ju4/a9TQd+H3m9SlSyvzio8fxl67f3HOvP3D+XwRG8khcA X-Developer-Key: i=brauner@kernel.org; a=openpgp; fpr=4880B8C9BD0E5106FC070F4F7B3C391EFEA93624 Precedence: bulk List-ID: X-Mailing-List: fstests@vger.kernel.org The missing.h header provides syscalls potentially missing from the used libc. Move the sys_execveat() definition into it. It doesn't belong into vfstest.c. Cc: Dave Chinner Cc: Amir Goldstein Cc: Eryu Guan Cc: Christoph Hellwig Cc: Zorro Lang Cc: "Darrick J. Wong" Cc: fstests Signed-off-by: Christian Brauner (Microsoft) --- src/vfs/missing.h | 11 +++++++++++ src/vfs/vfstest.c | 11 ----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/vfs/missing.h b/src/vfs/missing.h index c4f4cc32..059e742d 100644 --- a/src/vfs/missing.h +++ b/src/vfs/missing.h @@ -148,4 +148,15 @@ static inline int sys_umount2(const char *path, int flags) return syscall(__NR_umount2, path, flags); } +static inline int sys_execveat(int fd, const char *path, char **argv, + char **envp, int flags) +{ +#ifdef __NR_execveat + return syscall(__NR_execveat, fd, path, argv, envp, flags); +#else + errno = ENOSYS; + return -1; +#endif +} + #endif /* __IDMAP_MISSING_H */ diff --git a/src/vfs/vfstest.c b/src/vfs/vfstest.c index c3eb5ae4..f6c8c194 100644 --- a/src/vfs/vfstest.c +++ b/src/vfs/vfstest.c @@ -226,17 +226,6 @@ __attribute__((unused)) static int print_r(int fd, const char *path) } #endif -static int sys_execveat(int fd, const char *path, char **argv, char **envp, - int flags) -{ -#ifdef __NR_execveat - return syscall(__NR_execveat, fd, path, argv, envp, flags); -#else - errno = ENOSYS; - return -1; -#endif -} - static void test_setup(struct vfstest_info *info) { if (mkdirat(info->t_mnt_fd, T_DIR1, 0777)) From patchwork Thu Apr 28 15:15:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Brauner X-Patchwork-Id: 12830913 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 38157C4167B for ; Thu, 28 Apr 2022 15:16:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1348963AbiD1PUC (ORCPT ); Thu, 28 Apr 2022 11:20:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43918 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348950AbiD1PUB (ORCPT ); Thu, 28 Apr 2022 11:20:01 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A5B4FAFB03 for ; Thu, 28 Apr 2022 08:16:45 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 11F7361F30 for ; Thu, 28 Apr 2022 15:16:45 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3CD8DC385AE; Thu, 28 Apr 2022 15:16:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1651159004; bh=DI91Jk+x6vVn7OH2/LfAQYVjetiglO0xDfYszWy1F3A=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WgEL4WK5SMk/77+KkArWmlEgDZqJo8uEGQCmMPuCzilcH8aoHiW0dSQ1HJRXSvhce xnDx3NB1RAaka32Sb5fv9ol3jzp4rmXOuqJCwVqZqIJnCncVJcfMGchq+3KLMyHYN/ g37nV6V5e70nd/zSUavt/o6XosUStX7JJk/NNuW1KwHPx+UV2DORO8kHSIUmKinRpn Y9pLkDN11eNbZ89/eoD68wpu7MtLzeXr4G1yUcwA1W9WcRVky36SLEzrHGPDO/uBe0 zwwf982RjLhOswo0ydAu0vZg5RUT534An/9ee3sd8veg/uUL/YtGyXh6gSLujHVKqw bOmTTWi7vAVGQ== From: Christian Brauner To: Eryu Guan , Zorro Lang , fstests Cc: Christian Brauner , Dave Chinner , Amir Goldstein , Christoph Hellwig , Jan Kara , "Darrick J. Wong" Subject: [PATCH 08/11] utils: add struct test_suite Date: Thu, 28 Apr 2022 17:15:56 +0200 Message-Id: <20220428151559.947144-9-brauner@kernel.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220428151559.947144-1-brauner@kernel.org> References: <20220428151559.947144-1-brauner@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=5520; h=from:subject; bh=DI91Jk+x6vVn7OH2/LfAQYVjetiglO0xDfYszWy1F3A=; b=owGbwMvMwCU28Zj0gdSKO4sYT6slMSRlrV/yomrLitrkHbH225dulzPK+uW1Kkk4/lqvpepbz/23 TGXzOkpZGMS4GGTFFFkc2k3C5ZbzVGw2ytSAmcPKBDKEgYtTACYi18PIcFi6b9Kmmw7y+ydMcfp/MZ mbt2n9JbtcIc+g6+tzXj64dJaR4VnYsVv67qbVE07nc6pGNi1jPbaVT+ARy7llu/O7FuZ1swIA X-Developer-Key: i=brauner@kernel.org; a=openpgp; fpr=4880B8C9BD0E5106FC070F4F7B3C391EFEA93624 Precedence: bulk List-ID: X-Mailing-List: fstests@vger.kernel.org Provide a convenient wrapper struct which provides the tests and the number of tests. The struct can be kept local to each source file so we are sure that the tests and number of tests is correct. In vfstest.c we provide a run_suite() function which expects a struct test_suite and runs the tests provided by that suite. Cc: Dave Chinner Cc: Amir Goldstein Cc: Eryu Guan Cc: Christoph Hellwig Cc: Zorro Lang Cc: "Darrick J. Wong" Cc: fstests Signed-off-by: Christian Brauner (Microsoft) --- src/vfs/utils.h | 5 +++++ src/vfs/vfstest.c | 54 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/src/vfs/utils.h b/src/vfs/utils.h index 3f7cf911..a13efabb 100644 --- a/src/vfs/utils.h +++ b/src/vfs/utils.h @@ -198,6 +198,11 @@ struct test_struct { const char *description; }; +struct test_suite { + size_t nr_tests; + const struct test_struct *tests; +}; + typedef enum idmap_type_t { ID_TYPE_UID, ID_TYPE_GID diff --git a/src/vfs/vfstest.c b/src/vfs/vfstest.c index f6c8c194..e8025e81 100644 --- a/src/vfs/vfstest.c +++ b/src/vfs/vfstest.c @@ -13204,7 +13204,7 @@ static const struct option longopts[] = { {NULL, 0, 0, 0}, }; -struct test_struct basic_suite[] = { +static const struct test_struct t_basic[] = { { acls, true, "posix acls on regular mounts", }, { create_in_userns, true, "create operations in user namespace", }, { device_node_in_userns, true, "device node in user namespace", }, @@ -13256,15 +13256,30 @@ struct test_struct basic_suite[] = { { threaded_idmapped_mount_interactions, true, "threaded operations on idmapped mounts", }, }; -struct test_struct fscaps_in_ancestor_userns[] = { +static const struct test_suite s_basic = { + .tests = t_basic, + .nr_tests = ARRAY_SIZE(t_basic), +}; + +static const struct test_struct t_fscaps_in_ancestor_userns[] = { { fscaps_idmapped_mounts_in_userns_valid_in_ancestor_userns, true, "fscaps on idmapped mounts in user namespace writing fscap valid in ancestor userns", }, }; -struct test_struct t_nested_userns[] = { +static const struct test_suite s_fscaps_in_ancestor_userns = { + .tests = t_fscaps_in_ancestor_userns, + .nr_tests = ARRAY_SIZE(t_fscaps_in_ancestor_userns), +}; + +static const struct test_struct t_nested_userns[] = { { nested_userns, true, "test that nested user namespaces behave correctly when attached to idmapped mounts", }, }; -struct test_struct t_btrfs[] = { +static const struct test_suite s_nested_userns = { + .tests = t_nested_userns, + .nr_tests = ARRAY_SIZE(t_nested_userns), +}; + +static const struct test_struct t_btrfs[] = { { btrfs_subvolumes_fsids_mapped, true, "test subvolumes with mapped fsids", }, { btrfs_subvolumes_fsids_mapped_userns, true, "test subvolumes with mapped fsids inside user namespace", }, { btrfs_subvolumes_fsids_mapped_user_subvol_rm_allowed, true, "test subvolume deletion with user_subvol_rm_allowed mount option", }, @@ -13289,11 +13304,21 @@ struct test_struct t_btrfs[] = { { btrfs_subvolume_lookup_user, true, "test unprivileged subvolume lookup", }, }; +static const struct test_suite s_btrfs = { + .tests = t_btrfs, + .nr_tests = ARRAY_SIZE(t_btrfs), +}; + /* Test for commit 968219708108 ("fs: handle circular mappings correctly"). */ -struct test_struct t_setattr_fix_968219708108[] = { +static const struct test_struct t_setattr_fix_968219708108[] = { { setattr_fix_968219708108, true, "test that setattr works correctly", }, }; +static const struct test_suite s_setattr_fix_968219708108 = { + .tests = t_setattr_fix_968219708108, + .nr_tests = ARRAY_SIZE(t_setattr_fix_968219708108), +}; + static bool run_test(struct vfstest_info *info, const struct test_struct suite[], size_t suite_size) { int i; @@ -13336,6 +13361,12 @@ static bool run_test(struct vfstest_info *info, const struct test_struct suite[] return true; } +static inline bool run_suite(struct vfstest_info *info, + const struct test_suite *suite) +{ + return run_test(info, suite->tests, suite->nr_tests); +} + static bool fs_allow_idmap(const struct vfstest_info *info) { int ret; @@ -13460,24 +13491,21 @@ int main(int argc, char *argv[]) fret = EXIT_FAILURE; - if (test_core && !run_test(&info, basic_suite, ARRAY_SIZE(basic_suite))) + if (test_core && !run_suite(&info, &s_basic)) goto out; if (test_fscaps_regression && - !run_test(&info, fscaps_in_ancestor_userns, - ARRAY_SIZE(fscaps_in_ancestor_userns))) + !run_suite(&info, &s_fscaps_in_ancestor_userns)) goto out; - if (test_nested_userns && - !run_test(&info, t_nested_userns, ARRAY_SIZE(t_nested_userns))) + if (test_nested_userns && !run_suite(&info, &s_nested_userns)) goto out; - if (test_btrfs && !run_test(&info, t_btrfs, ARRAY_SIZE(t_btrfs))) + if (test_btrfs && !run_suite(&info, &s_btrfs)) goto out; if (test_setattr_fix_968219708108 && - !run_test(&info, t_setattr_fix_968219708108, - ARRAY_SIZE(t_setattr_fix_968219708108))) + !run_suite(&info, &s_setattr_fix_968219708108)) goto out; fret = EXIT_SUCCESS; From patchwork Thu Apr 28 15:15:59 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Brauner X-Patchwork-Id: 12830914 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id DD04AC433EF for ; Thu, 28 Apr 2022 15:17:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349047AbiD1PU2 (ORCPT ); Thu, 28 Apr 2022 11:20:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45642 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349021AbiD1PUU (ORCPT ); Thu, 28 Apr 2022 11:20:20 -0400 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EB78FB3DF1 for ; Thu, 28 Apr 2022 08:16:57 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id EA9E7B82D65 for ; Thu, 28 Apr 2022 15:16:55 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6EE05C385B1; Thu, 28 Apr 2022 15:16:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1651159014; bh=qDYOQNXH2eDUFA6HK2CmMTwprii3ixkmCuLdnYQ7C5U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dVb4rujTZv42LsrpczeGyPh5prTuBt54WQQ3MQYSHfTKtfA/Yl3togE1HirWHmZ9J G//DlqJP4eN1wilcvVNeLAVUj3pKr2/XII1LF2j6I/lXS9R6Np9liwhfOSfOGl13v4 wNnOupvMVDNt0kqB+YaJYr5qkzgklXTP1mFfuxzTpkPF/Wof68k4xjPgunwQk9BLRy dHn2t8t1lN4d2WGcqXKxgJdVLmG59db2Y94HRHFRZPaC15fCjnysDuaIqCkZWcV2+e SnNY6hDGSxICnGuCzbKk5nuItiobrU0HWAQzNwHHT0y0zV+tX344292FOaSXtXv06y t6z5qwI1/dOZw== From: Christian Brauner To: Eryu Guan , Zorro Lang , fstests Cc: Christian Brauner , Dave Chinner , Amir Goldstein , Christoph Hellwig , Jan Kara , "Darrick J. Wong" Subject: [PATCH 11/11] vfstest: split out remaining idmapped mount tests Date: Thu, 28 Apr 2022 17:15:59 +0200 Message-Id: <20220428151559.947144-12-brauner@kernel.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220428151559.947144-1-brauner@kernel.org> References: <20220428151559.947144-1-brauner@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=80986; h=from:subject; bh=qDYOQNXH2eDUFA6HK2CmMTwprii3ixkmCuLdnYQ7C5U=; b=owGbwMvMwCU28Zj0gdSKO4sYT6slMSRlrV+qW3BH/f0BtSWMJlYiV4PtTmU+V/QojbscfPLT+x/e J/7e7ShlYRDjYpAVU2RxaDcJl1vOU7HZKFMDZg4rE8gQBi5OAZhIujjDP7vQGyp6f7s/nX4obOXk7H z4wOGAB2/5LnpWdV3g5tyTu4uR4f7i8JPq/vfMt1xpvhcZVqYaP7Gz9bofvzjTQfOXSq66nAA= X-Developer-Key: i=brauner@kernel.org; a=openpgp; fpr=4880B8C9BD0E5106FC070F4F7B3C391EFEA93624 Precedence: bulk List-ID: X-Mailing-List: fstests@vger.kernel.org Split out all the remaining idmapped mount tests into the idmapped mounts source file. Cc: Dave Chinner Cc: Amir Goldstein Cc: Eryu Guan Cc: Christoph Hellwig Cc: Zorro Lang Cc: "Darrick J. Wong" Cc: fstests Signed-off-by: Christian Brauner (Microsoft) --- src/vfs/idmapped-mounts.c | 1123 +++++++++++++++++++++++++++++++++ src/vfs/idmapped-mounts.h | 2 + src/vfs/utils.c | 130 ++++ src/vfs/utils.h | 5 + src/vfs/vfstest.c | 1260 +------------------------------------ 5 files changed, 1261 insertions(+), 1259 deletions(-) diff --git a/src/vfs/idmapped-mounts.c b/src/vfs/idmapped-mounts.c index d935e4c8..8c9b03da 100644 --- a/src/vfs/idmapped-mounts.c +++ b/src/vfs/idmapped-mounts.c @@ -6470,6 +6470,1110 @@ out: return fret; } +static int nested_userns(const struct vfstest_info *info) +{ + int fret = -1; + int ret; + pid_t pid; + unsigned int id; + struct list *it, *next; + struct userns_hierarchy hierarchy[] = { + { .level = 1, .fd_userns = -EBADF, }, + { .level = 2, .fd_userns = -EBADF, }, + { .level = 3, .fd_userns = -EBADF, }, + { .level = 4, .fd_userns = -EBADF, }, + /* Dummy entry that marks the end. */ + { .level = MAX_USERNS_LEVEL, .fd_userns = -EBADF, }, + }; + struct mount_attr attr_level1 = { + .attr_set = MOUNT_ATTR_IDMAP, + .userns_fd = -EBADF, + }; + struct mount_attr attr_level2 = { + .attr_set = MOUNT_ATTR_IDMAP, + .userns_fd = -EBADF, + }; + struct mount_attr attr_level3 = { + .attr_set = MOUNT_ATTR_IDMAP, + .userns_fd = -EBADF, + }; + struct mount_attr attr_level4 = { + .attr_set = MOUNT_ATTR_IDMAP, + .userns_fd = -EBADF, + }; + int fd_dir1 = -EBADF, + fd_open_tree_level1 = -EBADF, + fd_open_tree_level2 = -EBADF, + fd_open_tree_level3 = -EBADF, + fd_open_tree_level4 = -EBADF; + const unsigned int id_file_range = 10000; + + list_init(&hierarchy[0].id_map); + list_init(&hierarchy[1].id_map); + list_init(&hierarchy[2].id_map); + list_init(&hierarchy[3].id_map); + + /* + * Give a large map to the outermost user namespace so we can create + * comfortable nested maps. + */ + ret = add_map_entry(&hierarchy[0].id_map, 1000000, 0, 1000000000, ID_TYPE_UID); + if (ret) { + log_stderr("failure: adding uidmap for userns at level 1"); + goto out; + } + + ret = add_map_entry(&hierarchy[0].id_map, 1000000, 0, 1000000000, ID_TYPE_GID); + if (ret) { + log_stderr("failure: adding gidmap for userns at level 1"); + goto out; + } + + /* This is uid:0->2000000:100000000 in init userns. */ + ret = add_map_entry(&hierarchy[1].id_map, 1000000, 0, 100000000, ID_TYPE_UID); + if (ret) { + log_stderr("failure: adding uidmap for userns at level 2"); + goto out; + } + + /* This is gid:0->2000000:100000000 in init userns. */ + ret = add_map_entry(&hierarchy[1].id_map, 1000000, 0, 100000000, ID_TYPE_GID); + if (ret) { + log_stderr("failure: adding gidmap for userns at level 2"); + goto out; + } + + /* This is uid:0->3000000:999 in init userns. */ + ret = add_map_entry(&hierarchy[2].id_map, 1000000, 0, 999, ID_TYPE_UID); + if (ret) { + log_stderr("failure: adding uidmap for userns at level 3"); + goto out; + } + + /* This is gid:0->3000000:999 in the init userns. */ + ret = add_map_entry(&hierarchy[2].id_map, 1000000, 0, 999, ID_TYPE_GID); + if (ret) { + log_stderr("failure: adding gidmap for userns at level 3"); + goto out; + } + + /* id 999 will remain unmapped. */ + + /* This is uid:1000->2001000:1 in init userns. */ + ret = add_map_entry(&hierarchy[2].id_map, 1000, 1000, 1, ID_TYPE_UID); + if (ret) { + log_stderr("failure: adding uidmap for userns at level 3"); + goto out; + } + + /* This is gid:1000->2001000:1 in init userns. */ + ret = add_map_entry(&hierarchy[2].id_map, 1000, 1000, 1, ID_TYPE_GID); + if (ret) { + log_stderr("failure: adding gidmap for userns at level 3"); + goto out; + } + + /* This is uid:1001->3001001:10000 in init userns. */ + ret = add_map_entry(&hierarchy[2].id_map, 1001001, 1001, 10000000, ID_TYPE_UID); + if (ret) { + log_stderr("failure: adding uidmap for userns at level 3"); + goto out; + } + + /* This is gid:1001->3001001:10000 in init userns. */ + ret = add_map_entry(&hierarchy[2].id_map, 1001001, 1001, 10000000, ID_TYPE_GID); + if (ret) { + log_stderr("failure: adding gidmap for userns at level 3"); + goto out; + } + + /* Don't write a mapping in the 4th userns. */ + list_empty(&hierarchy[4].id_map); + + /* Create the actual userns hierarchy. */ + ret = create_userns_hierarchy(hierarchy); + if (ret) { + log_stderr("failure: create userns hierarchy"); + goto out; + } + + attr_level1.userns_fd = hierarchy[0].fd_userns; + attr_level2.userns_fd = hierarchy[1].fd_userns; + attr_level3.userns_fd = hierarchy[2].fd_userns; + attr_level4.userns_fd = hierarchy[3].fd_userns; + + /* + * Create one directory where we create files for each uid/gid within + * the first userns. + */ + if (mkdirat(info->t_dir1_fd, DIR1, 0777)) { + log_stderr("failure: mkdirat"); + goto out; + } + + fd_dir1 = openat(info->t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC); + if (fd_dir1 < 0) { + log_stderr("failure: openat"); + goto out; + } + + for (id = 0; id <= id_file_range; id++) { + char file[256]; + + snprintf(file, sizeof(file), DIR1 "/" FILE1 "_%u", id); + + if (mknodat(info->t_dir1_fd, file, S_IFREG | 0644, 0)) { + log_stderr("failure: create %s", file); + goto out; + } + + if (fchownat(info->t_dir1_fd, file, id, id, AT_SYMLINK_NOFOLLOW)) { + log_stderr("failure: fchownat %s", file); + goto out; + } + + if (!expected_uid_gid(info->t_dir1_fd, file, 0, id, id)) { + log_stderr("failure: check ownership %s", file); + goto out; + } + } + + /* Create detached mounts for all the user namespaces. */ + fd_open_tree_level1 = sys_open_tree(info->t_dir1_fd, DIR1, + AT_NO_AUTOMOUNT | + AT_SYMLINK_NOFOLLOW | + OPEN_TREE_CLOEXEC | + OPEN_TREE_CLONE); + if (fd_open_tree_level1 < 0) { + log_stderr("failure: sys_open_tree"); + goto out; + } + + fd_open_tree_level2 = sys_open_tree(info->t_dir1_fd, DIR1, + AT_NO_AUTOMOUNT | + AT_SYMLINK_NOFOLLOW | + OPEN_TREE_CLOEXEC | + OPEN_TREE_CLONE); + if (fd_open_tree_level2 < 0) { + log_stderr("failure: sys_open_tree"); + goto out; + } + + fd_open_tree_level3 = sys_open_tree(info->t_dir1_fd, DIR1, + AT_NO_AUTOMOUNT | + AT_SYMLINK_NOFOLLOW | + OPEN_TREE_CLOEXEC | + OPEN_TREE_CLONE); + if (fd_open_tree_level3 < 0) { + log_stderr("failure: sys_open_tree"); + goto out; + } + + fd_open_tree_level4 = sys_open_tree(info->t_dir1_fd, DIR1, + AT_NO_AUTOMOUNT | + AT_SYMLINK_NOFOLLOW | + OPEN_TREE_CLOEXEC | + OPEN_TREE_CLONE); + if (fd_open_tree_level4 < 0) { + log_stderr("failure: sys_open_tree"); + goto out; + } + + /* Turn detached mounts into detached idmapped mounts. */ + if (sys_mount_setattr(fd_open_tree_level1, "", AT_EMPTY_PATH, + &attr_level1, sizeof(attr_level1))) { + log_stderr("failure: sys_mount_setattr"); + goto out; + } + + if (sys_mount_setattr(fd_open_tree_level2, "", AT_EMPTY_PATH, + &attr_level2, sizeof(attr_level2))) { + log_stderr("failure: sys_mount_setattr"); + goto out; + } + + if (sys_mount_setattr(fd_open_tree_level3, "", AT_EMPTY_PATH, + &attr_level3, sizeof(attr_level3))) { + log_stderr("failure: sys_mount_setattr"); + goto out; + } + + if (sys_mount_setattr(fd_open_tree_level4, "", AT_EMPTY_PATH, + &attr_level4, sizeof(attr_level4))) { + log_stderr("failure: sys_mount_setattr"); + goto out; + } + + /* Verify that ownership looks correct for callers in the init userns. */ + for (id = 0; id <= id_file_range; id++) { + bool bret; + unsigned int id_level1, id_level2, id_level3; + char file[256]; + + snprintf(file, sizeof(file), FILE1 "_%u", id); + + id_level1 = id + 1000000; + if (!expected_uid_gid(fd_open_tree_level1, file, 0, id_level1, id_level1)) { + log_stderr("failure: check ownership %s", file); + goto out; + } + + id_level2 = id + 2000000; + if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2)) { + log_stderr("failure: check ownership %s", file); + goto out; + } + + if (id == 999) { + /* This id is unmapped. */ + bret = expected_uid_gid(fd_open_tree_level3, file, 0, info->t_overflowuid, info->t_overflowgid); + } else if (id == 1000) { + id_level3 = id + 2000000; /* We punched a hole in the map at 1000. */ + bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3); + } else { + id_level3 = id + 3000000; /* Rest is business as usual. */ + bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3); + } + if (!bret) { + log_stderr("failure: check ownership %s", file); + goto out; + } + + if (!expected_uid_gid(fd_open_tree_level4, file, 0, info->t_overflowuid, info->t_overflowgid)) { + log_stderr("failure: check ownership %s", file); + goto out; + } + } + + /* Verify that ownership looks correct for callers in the first userns. */ + pid = fork(); + if (pid < 0) { + log_stderr("failure: fork"); + goto out; + } + if (pid == 0) { + if (!switch_userns(attr_level1.userns_fd, 0, 0, false)) + die("failure: switch_userns"); + + for (id = 0; id <= id_file_range; id++) { + bool bret; + unsigned int id_level1, id_level2, id_level3; + char file[256]; + + snprintf(file, sizeof(file), FILE1 "_%u", id); + + id_level1 = id; + if (!expected_uid_gid(fd_open_tree_level1, file, 0, id_level1, id_level1)) + die("failure: check ownership %s", file); + + id_level2 = id + 1000000; + if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2)) + die("failure: check ownership %s", file); + + if (id == 999) { + /* This id is unmapped. */ + bret = expected_uid_gid(fd_open_tree_level3, file, 0, info->t_overflowuid, info->t_overflowgid); + } else if (id == 1000) { + id_level3 = id + 1000000; /* We punched a hole in the map at 1000. */ + bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3); + } else { + id_level3 = id + 2000000; /* Rest is business as usual. */ + bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3); + } + if (!bret) + die("failure: check ownership %s", file); + + if (!expected_uid_gid(fd_open_tree_level4, file, 0, info->t_overflowuid, info->t_overflowgid)) + die("failure: check ownership %s", file); + } + + exit(EXIT_SUCCESS); + } + if (wait_for_pid(pid)) + goto out; + + /* Verify that ownership looks correct for callers in the second userns. */ + pid = fork(); + if (pid < 0) { + log_stderr("failure: fork"); + goto out; + } + if (pid == 0) { + if (!switch_userns(attr_level2.userns_fd, 0, 0, false)) + die("failure: switch_userns"); + + for (id = 0; id <= id_file_range; id++) { + bool bret; + unsigned int id_level2, id_level3; + char file[256]; + + snprintf(file, sizeof(file), FILE1 "_%u", id); + + if (!expected_uid_gid(fd_open_tree_level1, file, 0, info->t_overflowuid, info->t_overflowgid)) + die("failure: check ownership %s", file); + + id_level2 = id; + if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2)) + die("failure: check ownership %s", file); + + if (id == 999) { + /* This id is unmapped. */ + bret = expected_uid_gid(fd_open_tree_level3, file, 0, info->t_overflowuid, info->t_overflowgid); + } else if (id == 1000) { + id_level3 = id; /* We punched a hole in the map at 1000. */ + bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3); + } else { + id_level3 = id + 1000000; /* Rest is business as usual. */ + bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3); + } + if (!bret) + die("failure: check ownership %s", file); + + if (!expected_uid_gid(fd_open_tree_level4, file, 0, info->t_overflowuid, info->t_overflowgid)) + die("failure: check ownership %s", file); + } + + exit(EXIT_SUCCESS); + } + if (wait_for_pid(pid)) + goto out; + + /* Verify that ownership looks correct for callers in the third userns. */ + pid = fork(); + if (pid < 0) { + log_stderr("failure: fork"); + goto out; + } + if (pid == 0) { + if (!switch_userns(attr_level3.userns_fd, 0, 0, false)) + die("failure: switch_userns"); + + for (id = 0; id <= id_file_range; id++) { + bool bret; + unsigned int id_level2, id_level3; + char file[256]; + + snprintf(file, sizeof(file), FILE1 "_%u", id); + + if (!expected_uid_gid(fd_open_tree_level1, file, 0, info->t_overflowuid, info->t_overflowgid)) + die("failure: check ownership %s", file); + + if (id == 1000) { + /* + * The idmapping of the third userns has a hole + * at uid/gid 1000. That means: + * - 1000->userns_0(2000000) // init userns + * - 1000->userns_1(2000000) // level 1 + * - 1000->userns_2(1000000) // level 2 + * - 1000->userns_3(1000) // level 3 (because level 3 has a hole) + */ + id_level2 = id; + bret = expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2); + } else { + bret = expected_uid_gid(fd_open_tree_level2, file, 0, info->t_overflowuid, info->t_overflowgid); + } + if (!bret) + die("failure: check ownership %s", file); + + + if (id == 999) { + /* This id is unmapped. */ + bret = expected_uid_gid(fd_open_tree_level3, file, 0, info->t_overflowuid, info->t_overflowgid); + } else { + id_level3 = id; /* Rest is business as usual. */ + bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3); + } + if (!bret) + die("failure: check ownership %s", file); + + if (!expected_uid_gid(fd_open_tree_level4, file, 0, info->t_overflowuid, info->t_overflowgid)) + die("failure: check ownership %s", file); + } + + exit(EXIT_SUCCESS); + } + if (wait_for_pid(pid)) + goto out; + + /* Verify that ownership looks correct for callers in the fourth userns. */ + pid = fork(); + if (pid < 0) { + log_stderr("failure: fork"); + goto out; + } + if (pid == 0) { + if (setns(attr_level4.userns_fd, CLONE_NEWUSER)) + die("failure: switch_userns"); + + for (id = 0; id <= id_file_range; id++) { + char file[256]; + + snprintf(file, sizeof(file), FILE1 "_%u", id); + + if (!expected_uid_gid(fd_open_tree_level1, file, 0, info->t_overflowuid, info->t_overflowgid)) + die("failure: check ownership %s", file); + + if (!expected_uid_gid(fd_open_tree_level2, file, 0, info->t_overflowuid, info->t_overflowgid)) + die("failure: check ownership %s", file); + + if (!expected_uid_gid(fd_open_tree_level3, file, 0, info->t_overflowuid, info->t_overflowgid)) + die("failure: check ownership %s", file); + + if (!expected_uid_gid(fd_open_tree_level4, file, 0, info->t_overflowuid, info->t_overflowgid)) + die("failure: check ownership %s", file); + } + + exit(EXIT_SUCCESS); + } + if (wait_for_pid(pid)) + goto out; + + /* Verify that chown works correctly for callers in the first userns. */ + pid = fork(); + if (pid < 0) { + log_stderr("failure: fork"); + goto out; + } + if (pid == 0) { + if (!switch_userns(attr_level1.userns_fd, 0, 0, false)) + die("failure: switch_userns"); + + for (id = 0; id <= id_file_range; id++) { + bool bret; + unsigned int id_level1, id_level2, id_level3, id_new; + char file[256]; + + snprintf(file, sizeof(file), FILE1 "_%u", id); + + id_new = id + 1; + if (fchownat(fd_open_tree_level1, file, id_new, id_new, AT_SYMLINK_NOFOLLOW)) + die("failure: fchownat %s", file); + + id_level1 = id_new; + if (!expected_uid_gid(fd_open_tree_level1, file, 0, id_level1, id_level1)) + die("failure: check ownership %s", file); + + id_level2 = id_new + 1000000; + if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2)) + die("failure: check ownership %s", file); + + if (id_new == 999) { + /* This id is unmapped. */ + bret = expected_uid_gid(fd_open_tree_level3, file, 0, info->t_overflowuid, info->t_overflowgid); + } else if (id_new == 1000) { + id_level3 = id_new + 1000000; /* We punched a hole in the map at 1000. */ + bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3); + } else { + id_level3 = id_new + 2000000; /* Rest is business as usual. */ + bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3); + } + if (!bret) + die("failure: check ownership %s", file); + + if (!expected_uid_gid(fd_open_tree_level4, file, 0, info->t_overflowuid, info->t_overflowgid)) + die("failure: check ownership %s", file); + + /* Revert ownership. */ + if (fchownat(fd_open_tree_level1, file, id, id, AT_SYMLINK_NOFOLLOW)) + die("failure: fchownat %s", file); + } + + exit(EXIT_SUCCESS); + } + if (wait_for_pid(pid)) + goto out; + + /* Verify that chown works correctly for callers in the second userns. */ + pid = fork(); + if (pid < 0) { + log_stderr("failure: fork"); + goto out; + } + if (pid == 0) { + if (!switch_userns(attr_level2.userns_fd, 0, 0, false)) + die("failure: switch_userns"); + + for (id = 0; id <= id_file_range; id++) { + bool bret; + unsigned int id_level2, id_level3, id_new; + char file[256]; + + snprintf(file, sizeof(file), FILE1 "_%u", id); + + id_new = id + 1; + if (fchownat(fd_open_tree_level2, file, id_new, id_new, AT_SYMLINK_NOFOLLOW)) + die("failure: fchownat %s", file); + + if (!expected_uid_gid(fd_open_tree_level1, file, 0, info->t_overflowuid, info->t_overflowgid)) + die("failure: check ownership %s", file); + + id_level2 = id_new; + if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2)) + die("failure: check ownership %s", file); + + if (id_new == 999) { + /* This id is unmapped. */ + bret = expected_uid_gid(fd_open_tree_level3, file, 0, info->t_overflowuid, info->t_overflowgid); + } else if (id_new == 1000) { + id_level3 = id_new; /* We punched a hole in the map at 1000. */ + bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3); + } else { + id_level3 = id_new + 1000000; /* Rest is business as usual. */ + bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3); + } + if (!bret) + die("failure: check ownership %s", file); + + if (!expected_uid_gid(fd_open_tree_level4, file, 0, info->t_overflowuid, info->t_overflowgid)) + die("failure: check ownership %s", file); + + /* Revert ownership. */ + if (fchownat(fd_open_tree_level2, file, id, id, AT_SYMLINK_NOFOLLOW)) + die("failure: fchownat %s", file); + } + + exit(EXIT_SUCCESS); + } + if (wait_for_pid(pid)) + goto out; + + /* Verify that chown works correctly for callers in the third userns. */ + pid = fork(); + if (pid < 0) { + log_stderr("failure: fork"); + goto out; + } + if (pid == 0) { + if (!switch_userns(attr_level3.userns_fd, 0, 0, false)) + die("failure: switch_userns"); + + for (id = 0; id <= id_file_range; id++) { + unsigned int id_new; + char file[256]; + + snprintf(file, sizeof(file), FILE1 "_%u", id); + + id_new = id + 1; + if (id_new == 999 || id_new == 1000) { + /* + * We can't change ownership as we can't + * chown from or to an unmapped id. + */ + if (!fchownat(fd_open_tree_level3, file, id_new, id_new, AT_SYMLINK_NOFOLLOW)) + die("failure: fchownat %s", file); + } else { + if (fchownat(fd_open_tree_level3, file, id_new, id_new, AT_SYMLINK_NOFOLLOW)) + die("failure: fchownat %s", file); + } + + if (!expected_uid_gid(fd_open_tree_level1, file, 0, info->t_overflowuid, info->t_overflowgid)) + die("failure: check ownership %s", file); + + /* There's no id 1000 anymore as we changed ownership for id 1000 to 1001 above. */ + if (!expected_uid_gid(fd_open_tree_level2, file, 0, info->t_overflowuid, info->t_overflowgid)) + die("failure: check ownership %s", file); + + if (id_new == 999) { + /* + * We did not change ownership as we can't + * chown to an unmapped id. + */ + if (!expected_uid_gid(fd_open_tree_level3, file, 0, id, id)) + die("failure: check ownership %s", file); + } else if (id_new == 1000) { + /* + * We did not change ownership as we can't + * chown from an unmapped id. + */ + if (!expected_uid_gid(fd_open_tree_level3, file, 0, info->t_overflowuid, info->t_overflowgid)) + die("failure: check ownership %s", file); + } else { + if (!expected_uid_gid(fd_open_tree_level3, file, 0, id_new, id_new)) + die("failure: check ownership %s", file); + } + + if (!expected_uid_gid(fd_open_tree_level4, file, 0, info->t_overflowuid, info->t_overflowgid)) + die("failure: check ownership %s", file); + + /* Revert ownership. */ + if (id_new != 999 && id_new != 1000) { + if (fchownat(fd_open_tree_level3, file, id, id, AT_SYMLINK_NOFOLLOW)) + die("failure: fchownat %s", file); + } + } + + exit(EXIT_SUCCESS); + } + if (wait_for_pid(pid)) + goto out; + + /* Verify that chown works correctly for callers in the fourth userns. */ + pid = fork(); + if (pid < 0) { + log_stderr("failure: fork"); + goto out; + } + if (pid == 0) { + if (setns(attr_level4.userns_fd, CLONE_NEWUSER)) + die("failure: switch_userns"); + + for (id = 0; id <= id_file_range; id++) { + char file[256]; + unsigned long id_new; + + snprintf(file, sizeof(file), FILE1 "_%u", id); + + id_new = id + 1; + if (!fchownat(fd_open_tree_level4, file, id_new, id_new, AT_SYMLINK_NOFOLLOW)) + die("failure: fchownat %s", file); + + if (!expected_uid_gid(fd_open_tree_level1, file, 0, info->t_overflowuid, info->t_overflowgid)) + die("failure: check ownership %s", file); + + if (!expected_uid_gid(fd_open_tree_level2, file, 0, info->t_overflowuid, info->t_overflowgid)) + die("failure: check ownership %s", file); + + if (!expected_uid_gid(fd_open_tree_level3, file, 0, info->t_overflowuid, info->t_overflowgid)) + die("failure: check ownership %s", file); + + if (!expected_uid_gid(fd_open_tree_level4, file, 0, info->t_overflowuid, info->t_overflowgid)) + die("failure: check ownership %s", file); + + } + + exit(EXIT_SUCCESS); + } + if (wait_for_pid(pid)) + goto out; + + fret = 0; + log_debug("Ran test"); + +out: + list_for_each_safe(it, &hierarchy[0].id_map, next) { + list_del(it); + free(it->elem); + free(it); + } + + list_for_each_safe(it, &hierarchy[1].id_map, next) { + list_del(it); + free(it->elem); + free(it); + } + + list_for_each_safe(it, &hierarchy[2].id_map, next) { + list_del(it); + free(it->elem); + free(it); + } + + safe_close(hierarchy[0].fd_userns); + safe_close(hierarchy[1].fd_userns); + safe_close(hierarchy[2].fd_userns); + safe_close(fd_dir1); + safe_close(fd_open_tree_level1); + safe_close(fd_open_tree_level2); + safe_close(fd_open_tree_level3); + safe_close(fd_open_tree_level4); + 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_968219708108 - test for commit 968219708108 ("fs: handle circular mappings 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_968219708108(const struct vfstest_info *info) +{ + 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(info->t_dir1_fd, DIR1, 0777)) { + log_stderr("failure: mkdirat"); + goto out; + } + + if (mknodat(info->t_dir1_fd, DIR1 "/" FILE1, S_IFREG | 0644, 0)) { + log_stderr("failure: mknodat"); + goto out; + } + + if (chown_r(info->t_mnt_fd, T_DIR1, user1_uid, user1_gid)) { + log_stderr("failure: chown_r"); + goto out; + } + + if (mknodat(info->t_dir1_fd, DIR1 "/" FILE2, S_IFREG | 0644, 0)) { + log_stderr("failure: mknodat"); + goto out; + } + + if (fchownat(info->t_dir1_fd, DIR1 "/" FILE2, user2_uid, user2_gid, AT_SYMLINK_NOFOLLOW)) { + log_stderr("failure: fchownat"); + goto out; + } + + print_r(info->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(info->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 const struct test_struct t_idmapped_mounts[] = { { acls, true, "posix acls on regular mounts", }, { create_in_userns, true, "create operations in user namespace", }, @@ -6523,3 +7627,22 @@ const struct test_suite s_fscaps_in_ancestor_userns = { .tests = t_fscaps_in_ancestor_userns, .nr_tests = ARRAY_SIZE(t_fscaps_in_ancestor_userns), }; + +static const struct test_struct t_nested_userns[] = { + { nested_userns, true, "test that nested user namespaces behave correctly when attached to idmapped mounts", }, +}; + +const struct test_suite s_nested_userns = { + .tests = t_nested_userns, + .nr_tests = ARRAY_SIZE(t_nested_userns), +}; + +/* Test for commit 968219708108 ("fs: handle circular mappings correctly"). */ +static const struct test_struct t_setattr_fix_968219708108[] = { + { setattr_fix_968219708108, true, "test that setattr works correctly", }, +}; + +const struct test_suite s_setattr_fix_968219708108 = { + .tests = t_setattr_fix_968219708108, + .nr_tests = ARRAY_SIZE(t_setattr_fix_968219708108), +}; diff --git a/src/vfs/idmapped-mounts.h b/src/vfs/idmapped-mounts.h index 37c8886d..9febecd3 100644 --- a/src/vfs/idmapped-mounts.h +++ b/src/vfs/idmapped-mounts.h @@ -11,5 +11,7 @@ extern const struct test_suite s_idmapped_mounts; extern const struct test_suite s_fscaps_in_ancestor_userns; +extern const struct test_suite s_nested_userns; +extern const struct test_suite s_setattr_fix_968219708108; #endif /* __IDMAPPED_MOUNTS_H */ diff --git a/src/vfs/utils.c b/src/vfs/utils.c index 28944b70..089ac34e 100644 --- a/src/vfs/utils.c +++ b/src/vfs/utils.c @@ -871,3 +871,133 @@ int fd_to_fd(int from, int to) return 0; } + +/* + * There'll be scenarios where you'll want to see the attributes associated with + * a directory tree during debugging or just to make sure things look correct. + * Simply uncomment and place the print_r() helper where you need it. + */ +#ifdef DEBUG_TRACE +static int fd_cloexec(int fd, bool cloexec) +{ + int oflags, nflags; + + oflags = fcntl(fd, F_GETFD, 0); + if (oflags < 0) + return -errno; + + if (cloexec) + nflags = oflags | FD_CLOEXEC; + else + nflags = oflags & ~FD_CLOEXEC; + + if (nflags == oflags) + return 0; + + if (fcntl(fd, F_SETFD, nflags) < 0) + return -errno; + + return 0; +} + +static inline int dup_cloexec(int fd) +{ + int fd_dup; + + fd_dup = dup(fd); + if (fd_dup < 0) + return -errno; + + if (fd_cloexec(fd_dup, true)) { + close(fd_dup); + return -errno; + } + + return fd_dup; +} + +int print_r(int fd, const char *path) +{ + int ret = 0; + int dfd, dfd_dup; + DIR *dir; + struct dirent *direntp; + struct stat st; + + if (!path || *path == '\0') { + char buf[sizeof("/proc/self/fd/") + 30]; + + ret = snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd); + if (ret < 0 || (size_t)ret >= sizeof(buf)) + return -1; + + /* + * O_PATH file descriptors can't be used so we need to re-open + * just in case. + */ + dfd = openat(-EBADF, buf, O_CLOEXEC | O_DIRECTORY, 0); + } else { + dfd = openat(fd, path, O_CLOEXEC | O_DIRECTORY, 0); + } + if (dfd < 0) + return -1; + + /* + * When fdopendir() below succeeds it assumes ownership of the fd so we + * to make sure we always have an fd that fdopendir() can own which is + * why we dup() in the case where the caller wants us to operate on the + * fd directly. + */ + dfd_dup = dup_cloexec(dfd); + if (dfd_dup < 0) { + close(dfd); + return -1; + } + + dir = fdopendir(dfd); + if (!dir) { + close(dfd); + close(dfd_dup); + return -1; + } + /* Transfer ownership to fdopendir(). */ + dfd = -EBADF; + + while ((direntp = readdir(dir))) { + if (!strcmp(direntp->d_name, ".") || + !strcmp(direntp->d_name, "..")) + continue; + + ret = fstatat(dfd_dup, direntp->d_name, &st, AT_SYMLINK_NOFOLLOW); + if (ret < 0 && errno != ENOENT) + break; + + ret = 0; + if (S_ISDIR(st.st_mode)) + ret = print_r(dfd_dup, direntp->d_name); + else + fprintf(stderr, "mode(%o):uid(%d):gid(%d) -> %d/%s\n", + (st.st_mode & ~S_IFMT), st.st_uid, st.st_gid, + dfd_dup, direntp->d_name); + if (ret < 0 && errno != ENOENT) + break; + } + + if (!path || *path == '\0') + ret = fstatat(fd, "", &st, + AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | + AT_EMPTY_PATH); + else + ret = fstatat(fd, path, &st, + AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW); + if (!ret) + fprintf(stderr, "mode(%o):uid(%d):gid(%d) -> %s\n", + (st.st_mode & ~S_IFMT), st.st_uid, st.st_gid, + (path && *path) ? path : "(null)"); + + close(dfd_dup); + closedir(dir); + + return ret; +} +#endif diff --git a/src/vfs/utils.h b/src/vfs/utils.h index a13efabb..07aae675 100644 --- a/src/vfs/utils.h +++ b/src/vfs/utils.h @@ -347,6 +347,11 @@ extern int io_uring_openat_with_creds(struct io_uring *ring, int dfd, extern int chown_r(int fd, const char *path, uid_t uid, gid_t gid); extern int rm_r(int fd, const char *path); +#ifdef DEBUG_TRACE +extern int print_r(int fd, const char *path); +#else +static inline int print_r(int fd, const char *path) { return 0; } +#endif extern int fd_to_fd(int from, int to); extern bool protected_symlinks_enabled(void); extern bool xfs_irix_sgid_inherit_enabled(const char *fstype); diff --git a/src/vfs/vfstest.c b/src/vfs/vfstest.c index dadf1a0b..4567e95f 100644 --- a/src/vfs/vfstest.c +++ b/src/vfs/vfstest.c @@ -79,141 +79,6 @@ static void stash_overflowgid(struct vfstest_info *info) info->t_overflowgid = atoi(buf); } -/* - * There'll be scenarios where you'll want to see the attributes associated with - * a directory tree during debugging or just to make sure things look correct. - * Simply uncomment and place the print_r() helper where you need it. - */ -#ifdef DEBUG_TRACE -static int fd_cloexec(int fd, bool cloexec) -{ - int oflags, nflags; - - oflags = fcntl(fd, F_GETFD, 0); - if (oflags < 0) - return -errno; - - if (cloexec) - nflags = oflags | FD_CLOEXEC; - else - nflags = oflags & ~FD_CLOEXEC; - - if (nflags == oflags) - return 0; - - if (fcntl(fd, F_SETFD, nflags) < 0) - return -errno; - - return 0; -} - -static inline int dup_cloexec(int fd) -{ - int fd_dup; - - fd_dup = dup(fd); - if (fd_dup < 0) - return -errno; - - if (fd_cloexec(fd_dup, true)) { - close(fd_dup); - return -errno; - } - - return fd_dup; -} - -__attribute__((unused)) static int print_r(int fd, const char *path) -{ - int ret = 0; - int dfd, dfd_dup; - DIR *dir; - struct dirent *direntp; - struct stat st; - - if (!path || *path == '\0') { - char buf[sizeof("/proc/self/fd/") + 30]; - - ret = snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd); - if (ret < 0 || (size_t)ret >= sizeof(buf)) - return -1; - - /* - * O_PATH file descriptors can't be used so we need to re-open - * just in case. - */ - dfd = openat(-EBADF, buf, O_CLOEXEC | O_DIRECTORY, 0); - } else { - dfd = openat(fd, path, O_CLOEXEC | O_DIRECTORY, 0); - } - if (dfd < 0) - return -1; - - /* - * When fdopendir() below succeeds it assumes ownership of the fd so we - * to make sure we always have an fd that fdopendir() can own which is - * why we dup() in the case where the caller wants us to operate on the - * fd directly. - */ - dfd_dup = dup_cloexec(dfd); - if (dfd_dup < 0) { - close(dfd); - return -1; - } - - dir = fdopendir(dfd); - if (!dir) { - close(dfd); - close(dfd_dup); - return -1; - } - /* Transfer ownership to fdopendir(). */ - dfd = -EBADF; - - while ((direntp = readdir(dir))) { - if (!strcmp(direntp->d_name, ".") || - !strcmp(direntp->d_name, "..")) - continue; - - ret = fstatat(dfd_dup, direntp->d_name, &st, AT_SYMLINK_NOFOLLOW); - if (ret < 0 && errno != ENOENT) - break; - - ret = 0; - if (S_ISDIR(st.st_mode)) - ret = print_r(dfd_dup, direntp->d_name); - else - fprintf(stderr, "mode(%o):uid(%d):gid(%d) -> %d/%s\n", - (st.st_mode & ~S_IFMT), st.st_uid, st.st_gid, - dfd_dup, direntp->d_name); - if (ret < 0 && errno != ENOENT) - break; - } - - if (!path || *path == '\0') - ret = fstatat(fd, "", &st, - AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | - AT_EMPTY_PATH); - else - ret = fstatat(fd, path, &st, - AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW); - if (!ret) - fprintf(stderr, "mode(%o):uid(%d):gid(%d) -> %s\n", - (st.st_mode & ~S_IFMT), st.st_uid, st.st_gid, - (path && *path) ? path : "(null)"); - - close(dfd_dup); - closedir(dir); - - return ret; -} -#else -__attribute__((unused)) static int print_r(int fd, const char *path) -{ - return 0; -} -#endif - static void test_setup(struct vfstest_info *info) { if (mkdirat(info->t_mnt_fd, T_DIR1, 0777)) @@ -1827,1110 +1692,6 @@ out: return fret; } -static int nested_userns(const struct vfstest_info *info) -{ - int fret = -1; - int ret; - pid_t pid; - unsigned int id; - struct list *it, *next; - struct userns_hierarchy hierarchy[] = { - { .level = 1, .fd_userns = -EBADF, }, - { .level = 2, .fd_userns = -EBADF, }, - { .level = 3, .fd_userns = -EBADF, }, - { .level = 4, .fd_userns = -EBADF, }, - /* Dummy entry that marks the end. */ - { .level = MAX_USERNS_LEVEL, .fd_userns = -EBADF, }, - }; - struct mount_attr attr_level1 = { - .attr_set = MOUNT_ATTR_IDMAP, - .userns_fd = -EBADF, - }; - struct mount_attr attr_level2 = { - .attr_set = MOUNT_ATTR_IDMAP, - .userns_fd = -EBADF, - }; - struct mount_attr attr_level3 = { - .attr_set = MOUNT_ATTR_IDMAP, - .userns_fd = -EBADF, - }; - struct mount_attr attr_level4 = { - .attr_set = MOUNT_ATTR_IDMAP, - .userns_fd = -EBADF, - }; - int fd_dir1 = -EBADF, - fd_open_tree_level1 = -EBADF, - fd_open_tree_level2 = -EBADF, - fd_open_tree_level3 = -EBADF, - fd_open_tree_level4 = -EBADF; - const unsigned int id_file_range = 10000; - - list_init(&hierarchy[0].id_map); - list_init(&hierarchy[1].id_map); - list_init(&hierarchy[2].id_map); - list_init(&hierarchy[3].id_map); - - /* - * Give a large map to the outermost user namespace so we can create - * comfortable nested maps. - */ - ret = add_map_entry(&hierarchy[0].id_map, 1000000, 0, 1000000000, ID_TYPE_UID); - if (ret) { - log_stderr("failure: adding uidmap for userns at level 1"); - goto out; - } - - ret = add_map_entry(&hierarchy[0].id_map, 1000000, 0, 1000000000, ID_TYPE_GID); - if (ret) { - log_stderr("failure: adding gidmap for userns at level 1"); - goto out; - } - - /* This is uid:0->2000000:100000000 in init userns. */ - ret = add_map_entry(&hierarchy[1].id_map, 1000000, 0, 100000000, ID_TYPE_UID); - if (ret) { - log_stderr("failure: adding uidmap for userns at level 2"); - goto out; - } - - /* This is gid:0->2000000:100000000 in init userns. */ - ret = add_map_entry(&hierarchy[1].id_map, 1000000, 0, 100000000, ID_TYPE_GID); - if (ret) { - log_stderr("failure: adding gidmap for userns at level 2"); - goto out; - } - - /* This is uid:0->3000000:999 in init userns. */ - ret = add_map_entry(&hierarchy[2].id_map, 1000000, 0, 999, ID_TYPE_UID); - if (ret) { - log_stderr("failure: adding uidmap for userns at level 3"); - goto out; - } - - /* This is gid:0->3000000:999 in the init userns. */ - ret = add_map_entry(&hierarchy[2].id_map, 1000000, 0, 999, ID_TYPE_GID); - if (ret) { - log_stderr("failure: adding gidmap for userns at level 3"); - goto out; - } - - /* id 999 will remain unmapped. */ - - /* This is uid:1000->2001000:1 in init userns. */ - ret = add_map_entry(&hierarchy[2].id_map, 1000, 1000, 1, ID_TYPE_UID); - if (ret) { - log_stderr("failure: adding uidmap for userns at level 3"); - goto out; - } - - /* This is gid:1000->2001000:1 in init userns. */ - ret = add_map_entry(&hierarchy[2].id_map, 1000, 1000, 1, ID_TYPE_GID); - if (ret) { - log_stderr("failure: adding gidmap for userns at level 3"); - goto out; - } - - /* This is uid:1001->3001001:10000 in init userns. */ - ret = add_map_entry(&hierarchy[2].id_map, 1001001, 1001, 10000000, ID_TYPE_UID); - if (ret) { - log_stderr("failure: adding uidmap for userns at level 3"); - goto out; - } - - /* This is gid:1001->3001001:10000 in init userns. */ - ret = add_map_entry(&hierarchy[2].id_map, 1001001, 1001, 10000000, ID_TYPE_GID); - if (ret) { - log_stderr("failure: adding gidmap for userns at level 3"); - goto out; - } - - /* Don't write a mapping in the 4th userns. */ - list_empty(&hierarchy[4].id_map); - - /* Create the actual userns hierarchy. */ - ret = create_userns_hierarchy(hierarchy); - if (ret) { - log_stderr("failure: create userns hierarchy"); - goto out; - } - - attr_level1.userns_fd = hierarchy[0].fd_userns; - attr_level2.userns_fd = hierarchy[1].fd_userns; - attr_level3.userns_fd = hierarchy[2].fd_userns; - attr_level4.userns_fd = hierarchy[3].fd_userns; - - /* - * Create one directory where we create files for each uid/gid within - * the first userns. - */ - if (mkdirat(info->t_dir1_fd, DIR1, 0777)) { - log_stderr("failure: mkdirat"); - goto out; - } - - fd_dir1 = openat(info->t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC); - if (fd_dir1 < 0) { - log_stderr("failure: openat"); - goto out; - } - - for (id = 0; id <= id_file_range; id++) { - char file[256]; - - snprintf(file, sizeof(file), DIR1 "/" FILE1 "_%u", id); - - if (mknodat(info->t_dir1_fd, file, S_IFREG | 0644, 0)) { - log_stderr("failure: create %s", file); - goto out; - } - - if (fchownat(info->t_dir1_fd, file, id, id, AT_SYMLINK_NOFOLLOW)) { - log_stderr("failure: fchownat %s", file); - goto out; - } - - if (!expected_uid_gid(info->t_dir1_fd, file, 0, id, id)) { - log_stderr("failure: check ownership %s", file); - goto out; - } - } - - /* Create detached mounts for all the user namespaces. */ - fd_open_tree_level1 = sys_open_tree(info->t_dir1_fd, DIR1, - AT_NO_AUTOMOUNT | - AT_SYMLINK_NOFOLLOW | - OPEN_TREE_CLOEXEC | - OPEN_TREE_CLONE); - if (fd_open_tree_level1 < 0) { - log_stderr("failure: sys_open_tree"); - goto out; - } - - fd_open_tree_level2 = sys_open_tree(info->t_dir1_fd, DIR1, - AT_NO_AUTOMOUNT | - AT_SYMLINK_NOFOLLOW | - OPEN_TREE_CLOEXEC | - OPEN_TREE_CLONE); - if (fd_open_tree_level2 < 0) { - log_stderr("failure: sys_open_tree"); - goto out; - } - - fd_open_tree_level3 = sys_open_tree(info->t_dir1_fd, DIR1, - AT_NO_AUTOMOUNT | - AT_SYMLINK_NOFOLLOW | - OPEN_TREE_CLOEXEC | - OPEN_TREE_CLONE); - if (fd_open_tree_level3 < 0) { - log_stderr("failure: sys_open_tree"); - goto out; - } - - fd_open_tree_level4 = sys_open_tree(info->t_dir1_fd, DIR1, - AT_NO_AUTOMOUNT | - AT_SYMLINK_NOFOLLOW | - OPEN_TREE_CLOEXEC | - OPEN_TREE_CLONE); - if (fd_open_tree_level4 < 0) { - log_stderr("failure: sys_open_tree"); - goto out; - } - - /* Turn detached mounts into detached idmapped mounts. */ - if (sys_mount_setattr(fd_open_tree_level1, "", AT_EMPTY_PATH, - &attr_level1, sizeof(attr_level1))) { - log_stderr("failure: sys_mount_setattr"); - goto out; - } - - if (sys_mount_setattr(fd_open_tree_level2, "", AT_EMPTY_PATH, - &attr_level2, sizeof(attr_level2))) { - log_stderr("failure: sys_mount_setattr"); - goto out; - } - - if (sys_mount_setattr(fd_open_tree_level3, "", AT_EMPTY_PATH, - &attr_level3, sizeof(attr_level3))) { - log_stderr("failure: sys_mount_setattr"); - goto out; - } - - if (sys_mount_setattr(fd_open_tree_level4, "", AT_EMPTY_PATH, - &attr_level4, sizeof(attr_level4))) { - log_stderr("failure: sys_mount_setattr"); - goto out; - } - - /* Verify that ownership looks correct for callers in the init userns. */ - for (id = 0; id <= id_file_range; id++) { - bool bret; - unsigned int id_level1, id_level2, id_level3; - char file[256]; - - snprintf(file, sizeof(file), FILE1 "_%u", id); - - id_level1 = id + 1000000; - if (!expected_uid_gid(fd_open_tree_level1, file, 0, id_level1, id_level1)) { - log_stderr("failure: check ownership %s", file); - goto out; - } - - id_level2 = id + 2000000; - if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2)) { - log_stderr("failure: check ownership %s", file); - goto out; - } - - if (id == 999) { - /* This id is unmapped. */ - bret = expected_uid_gid(fd_open_tree_level3, file, 0, info->t_overflowuid, info->t_overflowgid); - } else if (id == 1000) { - id_level3 = id + 2000000; /* We punched a hole in the map at 1000. */ - bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3); - } else { - id_level3 = id + 3000000; /* Rest is business as usual. */ - bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3); - } - if (!bret) { - log_stderr("failure: check ownership %s", file); - goto out; - } - - if (!expected_uid_gid(fd_open_tree_level4, file, 0, info->t_overflowuid, info->t_overflowgid)) { - log_stderr("failure: check ownership %s", file); - goto out; - } - } - - /* Verify that ownership looks correct for callers in the first userns. */ - pid = fork(); - if (pid < 0) { - log_stderr("failure: fork"); - goto out; - } - if (pid == 0) { - if (!switch_userns(attr_level1.userns_fd, 0, 0, false)) - die("failure: switch_userns"); - - for (id = 0; id <= id_file_range; id++) { - bool bret; - unsigned int id_level1, id_level2, id_level3; - char file[256]; - - snprintf(file, sizeof(file), FILE1 "_%u", id); - - id_level1 = id; - if (!expected_uid_gid(fd_open_tree_level1, file, 0, id_level1, id_level1)) - die("failure: check ownership %s", file); - - id_level2 = id + 1000000; - if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2)) - die("failure: check ownership %s", file); - - if (id == 999) { - /* This id is unmapped. */ - bret = expected_uid_gid(fd_open_tree_level3, file, 0, info->t_overflowuid, info->t_overflowgid); - } else if (id == 1000) { - id_level3 = id + 1000000; /* We punched a hole in the map at 1000. */ - bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3); - } else { - id_level3 = id + 2000000; /* Rest is business as usual. */ - bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3); - } - if (!bret) - die("failure: check ownership %s", file); - - if (!expected_uid_gid(fd_open_tree_level4, file, 0, info->t_overflowuid, info->t_overflowgid)) - die("failure: check ownership %s", file); - } - - exit(EXIT_SUCCESS); - } - if (wait_for_pid(pid)) - goto out; - - /* Verify that ownership looks correct for callers in the second userns. */ - pid = fork(); - if (pid < 0) { - log_stderr("failure: fork"); - goto out; - } - if (pid == 0) { - if (!switch_userns(attr_level2.userns_fd, 0, 0, false)) - die("failure: switch_userns"); - - for (id = 0; id <= id_file_range; id++) { - bool bret; - unsigned int id_level2, id_level3; - char file[256]; - - snprintf(file, sizeof(file), FILE1 "_%u", id); - - if (!expected_uid_gid(fd_open_tree_level1, file, 0, info->t_overflowuid, info->t_overflowgid)) - die("failure: check ownership %s", file); - - id_level2 = id; - if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2)) - die("failure: check ownership %s", file); - - if (id == 999) { - /* This id is unmapped. */ - bret = expected_uid_gid(fd_open_tree_level3, file, 0, info->t_overflowuid, info->t_overflowgid); - } else if (id == 1000) { - id_level3 = id; /* We punched a hole in the map at 1000. */ - bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3); - } else { - id_level3 = id + 1000000; /* Rest is business as usual. */ - bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3); - } - if (!bret) - die("failure: check ownership %s", file); - - if (!expected_uid_gid(fd_open_tree_level4, file, 0, info->t_overflowuid, info->t_overflowgid)) - die("failure: check ownership %s", file); - } - - exit(EXIT_SUCCESS); - } - if (wait_for_pid(pid)) - goto out; - - /* Verify that ownership looks correct for callers in the third userns. */ - pid = fork(); - if (pid < 0) { - log_stderr("failure: fork"); - goto out; - } - if (pid == 0) { - if (!switch_userns(attr_level3.userns_fd, 0, 0, false)) - die("failure: switch_userns"); - - for (id = 0; id <= id_file_range; id++) { - bool bret; - unsigned int id_level2, id_level3; - char file[256]; - - snprintf(file, sizeof(file), FILE1 "_%u", id); - - if (!expected_uid_gid(fd_open_tree_level1, file, 0, info->t_overflowuid, info->t_overflowgid)) - die("failure: check ownership %s", file); - - if (id == 1000) { - /* - * The idmapping of the third userns has a hole - * at uid/gid 1000. That means: - * - 1000->userns_0(2000000) // init userns - * - 1000->userns_1(2000000) // level 1 - * - 1000->userns_2(1000000) // level 2 - * - 1000->userns_3(1000) // level 3 (because level 3 has a hole) - */ - id_level2 = id; - bret = expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2); - } else { - bret = expected_uid_gid(fd_open_tree_level2, file, 0, info->t_overflowuid, info->t_overflowgid); - } - if (!bret) - die("failure: check ownership %s", file); - - - if (id == 999) { - /* This id is unmapped. */ - bret = expected_uid_gid(fd_open_tree_level3, file, 0, info->t_overflowuid, info->t_overflowgid); - } else { - id_level3 = id; /* Rest is business as usual. */ - bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3); - } - if (!bret) - die("failure: check ownership %s", file); - - if (!expected_uid_gid(fd_open_tree_level4, file, 0, info->t_overflowuid, info->t_overflowgid)) - die("failure: check ownership %s", file); - } - - exit(EXIT_SUCCESS); - } - if (wait_for_pid(pid)) - goto out; - - /* Verify that ownership looks correct for callers in the fourth userns. */ - pid = fork(); - if (pid < 0) { - log_stderr("failure: fork"); - goto out; - } - if (pid == 0) { - if (setns(attr_level4.userns_fd, CLONE_NEWUSER)) - die("failure: switch_userns"); - - for (id = 0; id <= id_file_range; id++) { - char file[256]; - - snprintf(file, sizeof(file), FILE1 "_%u", id); - - if (!expected_uid_gid(fd_open_tree_level1, file, 0, info->t_overflowuid, info->t_overflowgid)) - die("failure: check ownership %s", file); - - if (!expected_uid_gid(fd_open_tree_level2, file, 0, info->t_overflowuid, info->t_overflowgid)) - die("failure: check ownership %s", file); - - if (!expected_uid_gid(fd_open_tree_level3, file, 0, info->t_overflowuid, info->t_overflowgid)) - die("failure: check ownership %s", file); - - if (!expected_uid_gid(fd_open_tree_level4, file, 0, info->t_overflowuid, info->t_overflowgid)) - die("failure: check ownership %s", file); - } - - exit(EXIT_SUCCESS); - } - if (wait_for_pid(pid)) - goto out; - - /* Verify that chown works correctly for callers in the first userns. */ - pid = fork(); - if (pid < 0) { - log_stderr("failure: fork"); - goto out; - } - if (pid == 0) { - if (!switch_userns(attr_level1.userns_fd, 0, 0, false)) - die("failure: switch_userns"); - - for (id = 0; id <= id_file_range; id++) { - bool bret; - unsigned int id_level1, id_level2, id_level3, id_new; - char file[256]; - - snprintf(file, sizeof(file), FILE1 "_%u", id); - - id_new = id + 1; - if (fchownat(fd_open_tree_level1, file, id_new, id_new, AT_SYMLINK_NOFOLLOW)) - die("failure: fchownat %s", file); - - id_level1 = id_new; - if (!expected_uid_gid(fd_open_tree_level1, file, 0, id_level1, id_level1)) - die("failure: check ownership %s", file); - - id_level2 = id_new + 1000000; - if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2)) - die("failure: check ownership %s", file); - - if (id_new == 999) { - /* This id is unmapped. */ - bret = expected_uid_gid(fd_open_tree_level3, file, 0, info->t_overflowuid, info->t_overflowgid); - } else if (id_new == 1000) { - id_level3 = id_new + 1000000; /* We punched a hole in the map at 1000. */ - bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3); - } else { - id_level3 = id_new + 2000000; /* Rest is business as usual. */ - bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3); - } - if (!bret) - die("failure: check ownership %s", file); - - if (!expected_uid_gid(fd_open_tree_level4, file, 0, info->t_overflowuid, info->t_overflowgid)) - die("failure: check ownership %s", file); - - /* Revert ownership. */ - if (fchownat(fd_open_tree_level1, file, id, id, AT_SYMLINK_NOFOLLOW)) - die("failure: fchownat %s", file); - } - - exit(EXIT_SUCCESS); - } - if (wait_for_pid(pid)) - goto out; - - /* Verify that chown works correctly for callers in the second userns. */ - pid = fork(); - if (pid < 0) { - log_stderr("failure: fork"); - goto out; - } - if (pid == 0) { - if (!switch_userns(attr_level2.userns_fd, 0, 0, false)) - die("failure: switch_userns"); - - for (id = 0; id <= id_file_range; id++) { - bool bret; - unsigned int id_level2, id_level3, id_new; - char file[256]; - - snprintf(file, sizeof(file), FILE1 "_%u", id); - - id_new = id + 1; - if (fchownat(fd_open_tree_level2, file, id_new, id_new, AT_SYMLINK_NOFOLLOW)) - die("failure: fchownat %s", file); - - if (!expected_uid_gid(fd_open_tree_level1, file, 0, info->t_overflowuid, info->t_overflowgid)) - die("failure: check ownership %s", file); - - id_level2 = id_new; - if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2)) - die("failure: check ownership %s", file); - - if (id_new == 999) { - /* This id is unmapped. */ - bret = expected_uid_gid(fd_open_tree_level3, file, 0, info->t_overflowuid, info->t_overflowgid); - } else if (id_new == 1000) { - id_level3 = id_new; /* We punched a hole in the map at 1000. */ - bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3); - } else { - id_level3 = id_new + 1000000; /* Rest is business as usual. */ - bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3); - } - if (!bret) - die("failure: check ownership %s", file); - - if (!expected_uid_gid(fd_open_tree_level4, file, 0, info->t_overflowuid, info->t_overflowgid)) - die("failure: check ownership %s", file); - - /* Revert ownership. */ - if (fchownat(fd_open_tree_level2, file, id, id, AT_SYMLINK_NOFOLLOW)) - die("failure: fchownat %s", file); - } - - exit(EXIT_SUCCESS); - } - if (wait_for_pid(pid)) - goto out; - - /* Verify that chown works correctly for callers in the third userns. */ - pid = fork(); - if (pid < 0) { - log_stderr("failure: fork"); - goto out; - } - if (pid == 0) { - if (!switch_userns(attr_level3.userns_fd, 0, 0, false)) - die("failure: switch_userns"); - - for (id = 0; id <= id_file_range; id++) { - unsigned int id_new; - char file[256]; - - snprintf(file, sizeof(file), FILE1 "_%u", id); - - id_new = id + 1; - if (id_new == 999 || id_new == 1000) { - /* - * We can't change ownership as we can't - * chown from or to an unmapped id. - */ - if (!fchownat(fd_open_tree_level3, file, id_new, id_new, AT_SYMLINK_NOFOLLOW)) - die("failure: fchownat %s", file); - } else { - if (fchownat(fd_open_tree_level3, file, id_new, id_new, AT_SYMLINK_NOFOLLOW)) - die("failure: fchownat %s", file); - } - - if (!expected_uid_gid(fd_open_tree_level1, file, 0, info->t_overflowuid, info->t_overflowgid)) - die("failure: check ownership %s", file); - - /* There's no id 1000 anymore as we changed ownership for id 1000 to 1001 above. */ - if (!expected_uid_gid(fd_open_tree_level2, file, 0, info->t_overflowuid, info->t_overflowgid)) - die("failure: check ownership %s", file); - - if (id_new == 999) { - /* - * We did not change ownership as we can't - * chown to an unmapped id. - */ - if (!expected_uid_gid(fd_open_tree_level3, file, 0, id, id)) - die("failure: check ownership %s", file); - } else if (id_new == 1000) { - /* - * We did not change ownership as we can't - * chown from an unmapped id. - */ - if (!expected_uid_gid(fd_open_tree_level3, file, 0, info->t_overflowuid, info->t_overflowgid)) - die("failure: check ownership %s", file); - } else { - if (!expected_uid_gid(fd_open_tree_level3, file, 0, id_new, id_new)) - die("failure: check ownership %s", file); - } - - if (!expected_uid_gid(fd_open_tree_level4, file, 0, info->t_overflowuid, info->t_overflowgid)) - die("failure: check ownership %s", file); - - /* Revert ownership. */ - if (id_new != 999 && id_new != 1000) { - if (fchownat(fd_open_tree_level3, file, id, id, AT_SYMLINK_NOFOLLOW)) - die("failure: fchownat %s", file); - } - } - - exit(EXIT_SUCCESS); - } - if (wait_for_pid(pid)) - goto out; - - /* Verify that chown works correctly for callers in the fourth userns. */ - pid = fork(); - if (pid < 0) { - log_stderr("failure: fork"); - goto out; - } - if (pid == 0) { - if (setns(attr_level4.userns_fd, CLONE_NEWUSER)) - die("failure: switch_userns"); - - for (id = 0; id <= id_file_range; id++) { - char file[256]; - unsigned long id_new; - - snprintf(file, sizeof(file), FILE1 "_%u", id); - - id_new = id + 1; - if (!fchownat(fd_open_tree_level4, file, id_new, id_new, AT_SYMLINK_NOFOLLOW)) - die("failure: fchownat %s", file); - - if (!expected_uid_gid(fd_open_tree_level1, file, 0, info->t_overflowuid, info->t_overflowgid)) - die("failure: check ownership %s", file); - - if (!expected_uid_gid(fd_open_tree_level2, file, 0, info->t_overflowuid, info->t_overflowgid)) - die("failure: check ownership %s", file); - - if (!expected_uid_gid(fd_open_tree_level3, file, 0, info->t_overflowuid, info->t_overflowgid)) - die("failure: check ownership %s", file); - - if (!expected_uid_gid(fd_open_tree_level4, file, 0, info->t_overflowuid, info->t_overflowgid)) - die("failure: check ownership %s", file); - - } - - exit(EXIT_SUCCESS); - } - if (wait_for_pid(pid)) - goto out; - - fret = 0; - log_debug("Ran test"); - -out: - list_for_each_safe(it, &hierarchy[0].id_map, next) { - list_del(it); - free(it->elem); - free(it); - } - - list_for_each_safe(it, &hierarchy[1].id_map, next) { - list_del(it); - free(it->elem); - free(it); - } - - list_for_each_safe(it, &hierarchy[2].id_map, next) { - list_del(it); - free(it->elem); - free(it); - } - - safe_close(hierarchy[0].fd_userns); - safe_close(hierarchy[1].fd_userns); - safe_close(hierarchy[2].fd_userns); - safe_close(fd_dir1); - safe_close(fd_open_tree_level1); - safe_close(fd_open_tree_level2); - safe_close(fd_open_tree_level3); - safe_close(fd_open_tree_level4); - 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_968219708108 - test for commit 968219708108 ("fs: handle circular mappings 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_968219708108(const struct vfstest_info *info) -{ - 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(info->t_dir1_fd, DIR1, 0777)) { - log_stderr("failure: mkdirat"); - goto out; - } - - if (mknodat(info->t_dir1_fd, DIR1 "/" FILE1, S_IFREG | 0644, 0)) { - log_stderr("failure: mknodat"); - goto out; - } - - if (chown_r(info->t_mnt_fd, T_DIR1, user1_uid, user1_gid)) { - log_stderr("failure: chown_r"); - goto out; - } - - if (mknodat(info->t_dir1_fd, DIR1 "/" FILE2, S_IFREG | 0644, 0)) { - log_stderr("failure: mknodat"); - goto out; - } - - if (fchownat(info->t_dir1_fd, DIR1 "/" FILE2, user2_uid, user2_gid, AT_SYMLINK_NOFOLLOW)) { - log_stderr("failure: fchownat"); - goto out; - } - - print_r(info->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(info->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"); @@ -2941,7 +1702,7 @@ static void usage(void) fprintf(stderr, "--fstype Filesystem type used in the tests\n"); fprintf(stderr, "--help Print help\n"); fprintf(stderr, "--mountpoint Mountpoint of device\n"); - fprintf(stderr, "--idmapped-mounts-supported Test whether idmapped mounts are supported on this filesystem\n"); + fprintf(stderr, "--idmapped-mounts-supported Test whether idmapped mounts are supported on this filesystem\n"); fprintf(stderr, "--scratch-mountpoint Mountpoint of scratch device used in the tests\n"); fprintf(stderr, "--scratch-device Scratch device used in the tests\n"); fprintf(stderr, "--test-core Run core idmapped mount testsuite\n"); @@ -2991,25 +1752,6 @@ static const struct test_suite s_basic = { .nr_tests = ARRAY_SIZE(t_basic), }; -static const struct test_struct t_nested_userns[] = { - { nested_userns, true, "test that nested user namespaces behave correctly when attached to idmapped mounts", }, -}; - -static const struct test_suite s_nested_userns = { - .tests = t_nested_userns, - .nr_tests = ARRAY_SIZE(t_nested_userns), -}; - -/* Test for commit 968219708108 ("fs: handle circular mappings correctly"). */ -static const struct test_struct t_setattr_fix_968219708108[] = { - { setattr_fix_968219708108, true, "test that setattr works correctly", }, -}; - -static const struct test_suite s_setattr_fix_968219708108 = { - .tests = t_setattr_fix_968219708108, - .nr_tests = ARRAY_SIZE(t_setattr_fix_968219708108), -}; - static bool run_test(struct vfstest_info *info, const struct test_struct suite[], size_t suite_size) { int i;