From nobody Thu Sep 24 20:37:47 2026 Received: from oss.cyber.gouv.fr (oss.cyber.gouv.fr [51.159.188.251]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2A8C4371899; Sun, 20 Sep 2026 20:33:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=51.159.188.251 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789936394; cv=none; b=LFr/AH/hInymGX7fAbCPTr0d330S2i0rrT7XKfqn8JjI1zUv6hVtJdtBNAIrRSWmJ6I0dJjgRNgf+XbalEGpl3aOGV3Xfr3imzwbAykqE0xxnAB8o4MvHrezRxvOBhUkxGDajbuZTYZKasQdnNcZqD2NoZHjmV+1l6BIxtu6R5Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789936394; c=relaxed/simple; bh=2HcUXrPWcY2MRUwFNoiyScoj6Z70eSofDPKZKwh5VAE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=baNhn23uDjESc7lXh1Io8A/D0HVUqkDP+LnW/ONw9QlCQd4bszZpma7Qj8oKeHzZ2tGzM5VJS6qZM6TbqWr+KQRif/5/G6Ip/KWGvhnzIZO7mkGzCU0OSuAr+Zq218mG5JLBbXzXMNPSdF60z3AZdy9pqtOzi0PW6d1Vp7DuSMM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=oss.cyber.gouv.fr; spf=pass smtp.mailfrom=oss.cyber.gouv.fr; dkim=pass (2048-bit key) header.d=oss.cyber.gouv.fr header.i=@oss.cyber.gouv.fr header.b=K7HGFt82; arc=none smtp.client-ip=51.159.188.251 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=oss.cyber.gouv.fr Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.cyber.gouv.fr Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=oss.cyber.gouv.fr header.i=@oss.cyber.gouv.fr header.b="K7HGFt82" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=oss.cyber.gouv.fr; s=default; h=Content-Transfer-Encoding:Content-Type: MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Sender :Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help: List-Unsubscribe:List-Unsubscribe-Post:List-Subscribe:List-Post:List-Owner: List-Archive; bh=9nvjs5kid5o66sq+VhpnI+9MVB4yoXW2FEr6PNvo6lg=; b=K7HGFt82e38J SpjuqMkQJnAbAhCHIfbHmrcPorSOgM8fV61RHffBM8v/jTMYkCo85B0Xvf8ONqzXGYigNcid/+BwQ YFayXbjJB3jzF6FuRjpqA+Gu90MJ0ZGSvcl+ZGCMDukHXx4o9PK/bFu/mRg1WFwl4c8XL1NFQ3RDg JODEunchaGMCNeTJ1mUJnln8OypHr35EybAIT9x+1OaPKnAL07u7ltFk6HBijp7PCJ+5ZG95xnEYJ I+PL6QHUjS2bbo6EG3375ZmDmt959Kfza8Yolpoa2M7B2eNBgPOLN8Z7GuW+OvO8Sx6u1lz7RHBHX FEisu/dcA+PJr//h5OZawA==; Received: from [151.115.150.205] (port=50122 helo=gepetto..) by pf-012.whm.fr-par.scw.cloud with esmtpsa (TLS1.3) tls TLS_AES_256_GCM_SHA384 (Exim 4.100) (envelope-from ) id 1x8ODm-0000000BX7T-29hV; Sun, 20 Sep 2026 22:33:10 +0200 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Jean?= To: miklos@szeredi.hu, amir73il@gmail.com Cc: linux-unionfs@vger.kernel.org, linux-kernel@vger.kernel.org, brauner@kernel.org, =?UTF-8?q?J=C3=A9r=C3=A9my=20Jean?= Subject: [PATCH v2 1/3] ovl: disable nfs_export for same-sb lower layers with different idmaps Date: Sun, 20 Sep 2026 20:32:38 +0000 Message-ID: <20260920203239.2876221-3-Jeremy.Jean@oss.cyber.gouv.fr> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260920203239.2876221-2-Jeremy.Jean@oss.cyber.gouv.fr> References: <20260920203239.2876221-2-Jeremy.Jean@oss.cyber.gouv.fr> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - pf-012.whm.fr-par.scw.cloud X-AntiAbuse: Original Domain - vger.kernel.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - oss.cyber.gouv.fr X-Get-Message-Sender-Via: pf-012.whm.fr-par.scw.cloud: authenticated_id: jeremy.jean@oss.cyber.gouv.fr X-Authenticated-Sender: pf-012.whm.fr-par.scw.cloud: jeremy.jean@oss.cyber.gouv.fr X-Source: X-Source-Args: X-Source-Dir: Overlay file handles identify a backing filesystem, but not the lower mount used to decode it. If lower layers share a superblock and use different idmaps, a file handle can decode through the wrong layer and initialize the overlay inode with the wrong owner. Track the first lower idmap seen for each ovl_sb and disable nfs_export when another lower layer on the same backing superblock uses a different idmap. Keep index enabled: copy up starts from the overlay dentry selected by lookup and does not need to decode a lower file handle through another layer. Fixes: bc70682a497c ("ovl: support idmapped layers") Assisted-by: Codex:gpt-5 Signed-off-by: J=C3=A9r=C3=A9my Jean Reviewed-by: Amir Goldstein --- fs/overlayfs/ovl_entry.h | 2 ++ fs/overlayfs/super.c | 28 +++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h index 80cad4ea96a3..2a6e12a0d4dd 100644 --- a/fs/overlayfs/ovl_entry.h +++ b/fs/overlayfs/ovl_entry.h @@ -24,6 +24,8 @@ struct ovl_config { struct ovl_sb { struct super_block *sb; dev_t pseudo_dev; + /* Idmap of the first lower layer on this fs */ + struct mnt_idmap *lower_idmap; /* Unusable (conflicting) uuid */ bool bad_uuid; /* Used as a lower layer (but maybe also as upper) */ diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index bd0a3f9039d2..8e78da420b75 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -944,6 +944,24 @@ static bool ovl_lower_uuid_ok(struct ovl_fs *ofs, cons= t uuid_t *uuid) return true; } =20 +/* + * Lower file handles identify a lower fs, but not the mount whose idmap w= as + * used to decode them. Remember the first lower idmap seen for each fs so + * decodable export handles can be disabled if another one appears. + */ +static bool ovl_lower_mnt_idmap_mismatch(struct ovl_sb *fs, + const struct path *path) +{ + struct mnt_idmap *idmap =3D mnt_idmap(path->mnt); + + if (!fs->lower_idmap) { + fs->lower_idmap =3D idmap; + return false; + } + + return fs->lower_idmap !=3D idmap; +} + /* Get a unique fsid for the layer */ static int ovl_get_fsid(struct ovl_fs *ofs, const struct path *path) { @@ -956,8 +974,15 @@ static int ovl_get_fsid(struct ovl_fs *ofs, const stru= ct path *path) bool warn =3D false; =20 for (i =3D 0; i < ofs->numfs; i++) { - if (ofs->fs[i].sb =3D=3D sb) + if (ofs->fs[i].sb =3D=3D sb) { + if (ofs->config.nfs_export && + ovl_lower_mnt_idmap_mismatch(&ofs->fs[i], path)) { + ofs->config.nfs_export =3D false; + pr_warn("different idmaps in same lower fs '%pd2', falling back to nfs= _export=3Doff.\n", + path->dentry); + } return i; + } } =20 if (!ovl_lower_uuid_ok(ofs, uuid)) { @@ -987,6 +1012,7 @@ static int ovl_get_fsid(struct ovl_fs *ofs, const stru= ct path *path) ofs->fs[ofs->numfs].sb =3D sb; ofs->fs[ofs->numfs].pseudo_dev =3D dev; ofs->fs[ofs->numfs].bad_uuid =3D bad_uuid; + ovl_lower_mnt_idmap_mismatch(&ofs->fs[ofs->numfs], path); =20 return ofs->numfs++; } --=20 2.47.3 From nobody Thu Sep 24 20:37:47 2026 Received: from oss.cyber.gouv.fr (oss.cyber.gouv.fr [51.159.188.251]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B7357386435; Sun, 20 Sep 2026 20:33:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=51.159.188.251 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789936394; cv=none; b=uLGruf2/zRnjFzS++tXmuMa23np+qJeJvat2cZN6WHvCQ9Uv2bP/WqX3/gbyhUje/KTlxrdAUpN09USdxxCjInhO7Q4lcU6K/YHrhXr2+Bv8IGJV1ItQfW2n2cJqtl0TcelkHjYR48jj2lXJILDpZBzsIja57LmaUxqCl7odTfU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789936394; c=relaxed/simple; bh=+Z6R4JPI0HfvrQX5YZUZQ8/tqSlpbk6OUkHn2GB+0Nw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=BFTNNYXvISmABejS+wSj2UczQy3O0NP4TJfGWcoVNPzscU0A6Kzkt1UBAhAFLuqL2FNRSe+rYCg6brCT2TGk/bpF8fX1G23e88ursvhDV+Xp/nG6tkIiuQPzP3OejaAf/HbqZOpIiFd7PCdHiZTsfsOt6xpRsHbF6TyHMPRrnYc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=oss.cyber.gouv.fr; spf=pass smtp.mailfrom=oss.cyber.gouv.fr; dkim=pass (2048-bit key) header.d=oss.cyber.gouv.fr header.i=@oss.cyber.gouv.fr header.b=rDDRz09s; arc=none smtp.client-ip=51.159.188.251 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=oss.cyber.gouv.fr Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.cyber.gouv.fr Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=oss.cyber.gouv.fr header.i=@oss.cyber.gouv.fr header.b="rDDRz09s" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=oss.cyber.gouv.fr; s=default; h=Content-Transfer-Encoding:Content-Type: MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Sender :Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help: List-Unsubscribe:List-Unsubscribe-Post:List-Subscribe:List-Post:List-Owner: List-Archive; bh=MhjTpSlr5gmWChbZz2KA69jFx1VHVzTNspVHfVseYbQ=; b=rDDRz09sywPZ D7+iOI7sioRCgQuSPiaX7HNKGBRsMtyy2ukF++fxdyqBuLF4odjx3JkKvYCkm3lJ2k4ShzERiSCuy kaqT1zhyTPQL4FKtir/QRUVm5V+5UC11/YRrC8bySyLqD/eI+kjvheQ+qZpgNON4L8rwnfsQ+yAMx AGVXbYsuFVROdIvDb1fHlWztq2ii5RoQUrcU+LkOTu1hLmFsabzzFS6xM33UUsvJ7Nph1ql9TRLBQ XqPO6n0zvjpx0jm8DbsflbnMR75LkuKrC0JkIPPlkmalIMjy21cGp+4Zr4F8HkPedrgZlJgNC4pzm 339rk3MW4JvnFgMQhOmonA==; Received: from [151.115.150.205] (port=50122 helo=gepetto..) by pf-012.whm.fr-par.scw.cloud with esmtpsa (TLS1.3) tls TLS_AES_256_GCM_SHA384 (Exim 4.100) (envelope-from ) id 1x8ODn-0000000BX7T-0Nsk; Sun, 20 Sep 2026 22:33:11 +0200 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Jean?= To: miklos@szeredi.hu, amir73il@gmail.com Cc: linux-unionfs@vger.kernel.org, linux-kernel@vger.kernel.org, brauner@kernel.org, =?UTF-8?q?J=C3=A9r=C3=A9my=20Jean?= Subject: [PATCH v2 2/3] selftests: overlayfs: reject handles for mixed lower idmaps Date: Sun, 20 Sep 2026 20:32:39 +0000 Message-ID: <20260920203239.2876221-4-Jeremy.Jean@oss.cyber.gouv.fr> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260920203239.2876221-2-Jeremy.Jean@oss.cyber.gouv.fr> References: <20260920203239.2876221-2-Jeremy.Jean@oss.cyber.gouv.fr> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - pf-012.whm.fr-par.scw.cloud X-AntiAbuse: Original Domain - vger.kernel.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - oss.cyber.gouv.fr X-Get-Message-Sender-Via: pf-012.whm.fr-par.scw.cloud: authenticated_id: jeremy.jean@oss.cyber.gouv.fr X-Authenticated-Sender: pf-012.whm.fr-par.scw.cloud: jeremy.jean@oss.cyber.gouv.fr X-Source: X-Source-Args: X-Source-Dir: Add an idmapped overlay test for two lower layers that share a backing superblock but use different idmaps. Mount with index=3Don,nfs_export=3Don = and verify decodable handle requests fail with EOPNOTSUPP after overlayfs falls back to nfs_export=3Doff. Signed-off-by: J=C3=A9r=C3=A9my Jean Reviewed-by: Amir Goldstein --- .../filesystems/overlayfs/idmapped_mounts.c | 98 ++++++++++++++++++- 1 file changed, 94 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/filesystems/overlayfs/idmapped_mounts.= c b/tools/testing/selftests/filesystems/overlayfs/idmapped_mounts.c index 44a75839f4ed..0e94bd464f1c 100644 --- a/tools/testing/selftests/filesystems/overlayfs/idmapped_mounts.c +++ b/tools/testing/selftests/filesystems/overlayfs/idmapped_mounts.c @@ -159,8 +159,16 @@ static int idmapped_layer_fd(const char *path, int nsi= d, int hostid, int range) return fd_tree; } =20 -/* Overlay with a layer passed by fd (idmapped) plus a plain upper/work. */ -static int ovl_mount_lower_fd(const char *upper, const char *work, int fd_= lower) +static int layer_fd(const char *path) +{ + return sys_open_tree(AT_FDCWD, path, + OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC); +} + +/* Overlay with lower layers passed by fd plus a plain upper/work. */ +static int ovl_mount_lower_fds(const char *upper, const char *work, + int fd_lower1, int fd_lower2, + const char *index, const char *nfs_export) { int fsfd, ovl; =20 @@ -171,8 +179,19 @@ static int ovl_mount_lower_fd(const char *upper, const= char *work, int fd_lower) if (sys_fsconfig(fsfd, FSCONFIG_SET_STRING, "source", "test", 0) || sys_fsconfig(fsfd, FSCONFIG_SET_STRING, "upperdir", upper, 0) || sys_fsconfig(fsfd, FSCONFIG_SET_STRING, "workdir", work, 0) || - sys_fsconfig(fsfd, FSCONFIG_SET_FD, "lowerdir+", NULL, fd_lower) || - sys_fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0)) + sys_fsconfig(fsfd, FSCONFIG_SET_FD, "lowerdir+", NULL, fd_lower1)) + goto err; + if (fd_lower2 >=3D 0 && + sys_fsconfig(fsfd, FSCONFIG_SET_FD, "lowerdir+", NULL, fd_lower2)) + goto err; + if (index && + sys_fsconfig(fsfd, FSCONFIG_SET_STRING, "index", index, 0)) + goto err; + if (nfs_export && + sys_fsconfig(fsfd, FSCONFIG_SET_STRING, "nfs_export", + nfs_export, 0)) + goto err; + if (sys_fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0)) goto err; =20 ovl =3D sys_fsmount(fsfd, 0, 0); @@ -183,6 +202,23 @@ static int ovl_mount_lower_fd(const char *upper, const= char *work, int fd_lower) return -1; } =20 +static int ovl_mount_lower_fd(const char *upper, const char *work, int fd_= lower) +{ + return ovl_mount_lower_fds(upper, work, fd_lower, -1, NULL, NULL); +} + +static int setup_extra_layer(const char *base, const char *name) +{ + char path[PATH_MAX]; + + snprintf(path, sizeof(path), "%s/%s", base, name); + if (mkdir(path, 0755) && errno !=3D EEXIST) + return -1; + if (chown(path, ID_HOST, ID_HOST)) + return -1; + return 0; +} + /* * Mount an overlay inside user namespace @u1 (so the overlay sb's s_user_= ns is * not the initial namespace) and idmap that overlay mount with @u2. Runs= in a @@ -498,4 +534,58 @@ TEST_F(idmapped_overlay, nfs_export_handles) EXPECT_EQ(close(ovl), 0); } =20 +/* + * Lower file handles cannot be decoded safely when two lower layers share= a + * superblock but use different idmaps. nfs_export should be disabled for= that + * layout, so a normal decodable handle request must fail with EOPNOTSUPP. + */ +TEST_F(idmapped_overlay, nfs_export_same_sb_mixed_idmaps) +{ + char lower1[PATH_MAX], lower2[PATH_MAX], upper[PATH_MAX], work[PATH_MAX]; + char path[PATH_MAX], mnt[128]; + union { + struct file_handle fh; + char buf[sizeof(struct file_handle) + MAX_HANDLE_SZ]; + } fhu; + struct file_handle *fh =3D &fhu.fh; + int fd_lower1, fd_lower2, ovl, mount_id; + + if (!ovl_supported()) + SKIP(return, "overlayfs not supported"); + + snprintf(lower1, sizeof(lower1), "%s/l", self->base); + snprintf(lower2, sizeof(lower2), "%s/l2", self->base); + snprintf(upper, sizeof(upper), "%s/u", self->base); + snprintf(work, sizeof(work), "%s/w", self->base); + ASSERT_EQ(setup_extra_layer(self->base, "l2"), 0); + + snprintf(path, sizeof(path), "%s/l2/file", self->base); + ASSERT_EQ(mknod(path, S_IFREG | 0644, 0), 0); + ASSERT_EQ(chown(path, ID_HOST + 7, ID_HOST + 7), 0); + + fd_lower1 =3D idmapped_layer_fd(lower1, ID_HOST, ID_NS, ID_RANGE); + ASSERT_GE(fd_lower1, 0); + fd_lower2 =3D layer_fd(lower2); + ASSERT_GE(fd_lower2, 0); + + ovl =3D ovl_mount_lower_fds(upper, work, fd_lower1, fd_lower2, "on", "on"= ); + if (ovl < 0) + SKIP(return, "overlayfs nfs_export not supported"); + EXPECT_EQ(close(fd_lower1), 0); + EXPECT_EQ(close(fd_lower2), 0); + + snprintf(mnt, sizeof(mnt), "%s/mnt", self->base); + ASSERT_EQ(mkdir(mnt, 0755), 0); + ASSERT_EQ(sys_move_mount(ovl, "", AT_FDCWD, mnt, + MOVE_MOUNT_F_EMPTY_PATH), 0); + + snprintf(path, sizeof(path), "%s/file", mnt); + fh->handle_bytes =3D MAX_HANDLE_SZ; + errno =3D 0; + EXPECT_EQ(name_to_handle_at(AT_FDCWD, path, fh, &mount_id, 0), -1); + EXPECT_EQ(errno, EOPNOTSUPP); + + EXPECT_EQ(close(ovl), 0); +} + TEST_HARNESS_MAIN --=20 2.47.3 From nobody Thu Sep 24 20:37:47 2026 Received: from oss.cyber.gouv.fr (oss.cyber.gouv.fr [51.159.188.251]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 27B5B38A299; Sun, 20 Sep 2026 20:33:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=51.159.188.251 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789936394; cv=none; b=eZS3GJHGcR9t+IYVqS4Om0cDZ9zulQlOEHiSsBC0+5bXRGgd3g/9wQ0kwIjJyaz5+84yD3UphDnqhZXn0IoTa8lbJYfG1Ll8mmunhxlnapqc2IlgzZXWhHmvP8WjS7pJjCRbRlnbqOvExLW5vTvMHqUZaZpcDOaIJTI2so9oiuI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789936394; c=relaxed/simple; bh=Z/Dt8cvfGRnIXf6nNFWeW2ZqedX6xPyoZeBUpEJwk8Y=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=K71u1ULcTnAHSSPfQ6Mottkj8mPJQePd1C7eaBa+7yuKh7HxAYx6mHaL8tDyLgVCA7dlG4T6rCC9NGOMhfmArghsTRNISzf5TW6jdQof/YKf9I3MEEXNsEKAULyYtjXF0xIRFBJixyF+cA9q4sGu//S5YSlxPuWECTzviC4gFjc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=oss.cyber.gouv.fr; spf=pass smtp.mailfrom=oss.cyber.gouv.fr; dkim=pass (2048-bit key) header.d=oss.cyber.gouv.fr header.i=@oss.cyber.gouv.fr header.b=W/wSXlLV; arc=none smtp.client-ip=51.159.188.251 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=oss.cyber.gouv.fr Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.cyber.gouv.fr Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=oss.cyber.gouv.fr header.i=@oss.cyber.gouv.fr header.b="W/wSXlLV" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=oss.cyber.gouv.fr; s=default; h=Content-Transfer-Encoding:Content-Type: MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Sender :Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help: List-Unsubscribe:List-Unsubscribe-Post:List-Subscribe:List-Post:List-Owner: List-Archive; bh=fYwd/oBcaSjxIlM0fBEuECJkcNn0BzAjYxEbToDhPhE=; b=W/wSXlLV7zyI Z6J/aaRn2pUUzk3BDld9zk5TxeaipK6OB5ookkbTp0AQKckscCe49GRSapoB9MPk5uAcZOqTOyTxj p7NM6JEoF0sP3ybuv76zVSD1Pjq2xe2vBGZWYI3aTQMgQVKC/54IyqVzyN/sLlf5fzRvHqNIXUwUK mkIJWJe8uzuoUF0CT+zdqo89dsrT5K4EzWjpGTtl6fEMECPszKX0O+ttCrOPB3hvYGCl34oA4rG3f rmHXuj6GbO7j9FvKqJfPahDRwa9jCr+kYEExteGOv91HAt9P/woJ2UBT3H5JfBjQ7E4Bq8SP5dv9n w6xFtkh2JVeHq46e1G9Oag==; Received: from [151.115.150.205] (port=50122 helo=gepetto..) by pf-012.whm.fr-par.scw.cloud with esmtpsa (TLS1.3) tls TLS_AES_256_GCM_SHA384 (Exim 4.100) (envelope-from ) id 1x8ODn-0000000BX7T-2SJH; Sun, 20 Sep 2026 22:33:11 +0200 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Jean?= To: miklos@szeredi.hu, amir73il@gmail.com Cc: linux-unionfs@vger.kernel.org, linux-kernel@vger.kernel.org, brauner@kernel.org, =?UTF-8?q?J=C3=A9r=C3=A9my=20Jean?= Subject: [PATCH v2 3/3] selftests: overlayfs: keep index copy up with mixed lower idmaps Date: Sun, 20 Sep 2026 20:32:40 +0000 Message-ID: <20260920203239.2876221-5-Jeremy.Jean@oss.cyber.gouv.fr> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260920203239.2876221-2-Jeremy.Jean@oss.cyber.gouv.fr> References: <20260920203239.2876221-2-Jeremy.Jean@oss.cyber.gouv.fr> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - pf-012.whm.fr-par.scw.cloud X-AntiAbuse: Original Domain - vger.kernel.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - oss.cyber.gouv.fr X-Get-Message-Sender-Via: pf-012.whm.fr-par.scw.cloud: authenticated_id: jeremy.jean@oss.cyber.gouv.fr X-Authenticated-Sender: pf-012.whm.fr-par.scw.cloud: jeremy.jean@oss.cyber.gouv.fr X-Source: X-Source-Args: X-Source-Dir: Add a copy-up test for mixed-idmap lower layers with index=3Don,nfs_export=3Doff. Write through one hardlink alias and read through the other. Check that both aliases still point to the same copied-up inode. Check that the copied-up inode keeps the expected mapped owner. Signed-off-by: J=C3=A9r=C3=A9my Jean Reviewed-by: Amir Goldstein --- .../filesystems/overlayfs/idmapped_mounts.c | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/tools/testing/selftests/filesystems/overlayfs/idmapped_mounts.= c b/tools/testing/selftests/filesystems/overlayfs/idmapped_mounts.c index 0e94bd464f1c..ae99698c280a 100644 --- a/tools/testing/selftests/filesystems/overlayfs/idmapped_mounts.c +++ b/tools/testing/selftests/filesystems/overlayfs/idmapped_mounts.c @@ -219,6 +219,42 @@ static int setup_extra_layer(const char *base, const c= har *name) return 0; } =20 +static int write_path(const char *path, const char *buf) +{ + size_t len =3D strlen(buf); + int fd; + + fd =3D open(path, O_CREAT | O_TRUNC | O_WRONLY, 0644); + if (fd < 0) + return -1; + if (write(fd, buf, len) !=3D len) { + close(fd); + return -1; + } + if (close(fd)) + return -1; + return 0; +} + +static int read_fd_contents(int dirfd, const char *name, char *buf, size_t= len) +{ + ssize_t n; + int fd; + + fd =3D openat(dirfd, name, O_RDONLY); + if (fd < 0) + return -1; + n =3D read(fd, buf, len - 1); + if (n < 0) { + close(fd); + return -1; + } + buf[n] =3D '\0'; + if (close(fd)) + return -1; + return 0; +} + /* * Mount an overlay inside user namespace @u1 (so the overlay sb's s_user_= ns is * not the initial namespace) and idmap that overlay mount with @u2. Runs= in a @@ -588,4 +624,71 @@ TEST_F(idmapped_overlay, nfs_export_same_sb_mixed_idma= ps) EXPECT_EQ(close(ovl), 0); } =20 +/* + * index=3Don without nfs_export still preserves lower hardlinks on copy u= p when + * same-superblock lower layers use different idmaps. The copied-up alias= must + * keep the same contents, inode identity, and owner as the path-selected = lower. + */ +TEST_F(idmapped_overlay, index_copy_up_same_sb_mixed_idmaps) +{ + static const char lower_data[] =3D "lower\n"; + static const char upper_data[] =3D "upper\n"; + char lower1[PATH_MAX], lower2[PATH_MAX], upper[PATH_MAX], work[PATH_MAX]; + char path[PATH_MAX], alias[PATH_MAX], buf[32]; + struct stat st_file, st_alias, st_upper; + int fd_lower1, fd_lower2, ovl, fd; + + if (!ovl_supported()) + SKIP(return, "overlayfs not supported"); + + snprintf(lower1, sizeof(lower1), "%s/l", self->base); + snprintf(lower2, sizeof(lower2), "%s/l2", self->base); + snprintf(upper, sizeof(upper), "%s/u", self->base); + snprintf(work, sizeof(work), "%s/w", self->base); + ASSERT_EQ(setup_extra_layer(self->base, "l2"), 0); + + snprintf(path, sizeof(path), "%s/l2/file", self->base); + snprintf(alias, sizeof(alias), "%s/l2/alias", self->base); + ASSERT_EQ(write_path(path, lower_data), 0); + ASSERT_EQ(chown(path, ID_HOST + 7, ID_HOST + 7), 0); + ASSERT_EQ(link(path, alias), 0); + + fd_lower1 =3D idmapped_layer_fd(lower1, ID_HOST, ID_NS, ID_RANGE); + ASSERT_GE(fd_lower1, 0); + fd_lower2 =3D layer_fd(lower2); + ASSERT_GE(fd_lower2, 0); + + ovl =3D ovl_mount_lower_fds(upper, work, fd_lower1, fd_lower2, "on", "off= "); + ASSERT_GE(ovl, 0); + EXPECT_EQ(close(fd_lower1), 0); + EXPECT_EQ(close(fd_lower2), 0); + ASSERT_EQ(ovl_idmap(ovl), 0); + + fd =3D openat(ovl, "file", O_WRONLY | O_TRUNC); + ASSERT_GE(fd, 0); + ASSERT_EQ(write(fd, upper_data, sizeof(upper_data) - 1), + sizeof(upper_data) - 1); + EXPECT_EQ(close(fd), 0); + + ASSERT_EQ(read_fd_contents(ovl, "alias", buf, sizeof(buf)), 0); + EXPECT_STREQ(upper_data, buf); + + ASSERT_EQ(fstatat(ovl, "file", &st_file, 0), 0); + ASSERT_EQ(fstatat(ovl, "alias", &st_alias, 0), 0); + EXPECT_EQ(st_file.st_ino, st_alias.st_ino); + EXPECT_EQ(st_file.st_nlink, 2); + EXPECT_EQ(st_alias.st_nlink, 2); + EXPECT_EQ(st_file.st_uid, ID_NS + 7); + EXPECT_EQ(st_file.st_gid, ID_NS + 7); + EXPECT_EQ(st_alias.st_uid, ID_NS + 7); + EXPECT_EQ(st_alias.st_gid, ID_NS + 7); + + snprintf(path, sizeof(path), "%s/u/file", self->base); + ASSERT_EQ(stat(path, &st_upper), 0); + EXPECT_EQ(st_upper.st_uid, ID_HOST + 7); + EXPECT_EQ(st_upper.st_gid, ID_HOST + 7); + + EXPECT_EQ(close(ovl), 0); +} + TEST_HARNESS_MAIN --=20 2.47.3