From a1be41a7f3c53d98cbb929ced99b174f5c5021ef Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 30 Jun 2022 13:36:55 +0200 Subject: [PATCH] 5.15-stable patches added patches: docs-update-mapping-documentation.patch fs-account-for-filesystem-mappings.patch fs-account-for-group-membership.patch fs-add-i_user_ns-helper.patch fs-add-is_idmapped_mnt-helper.patch fs-fix-acl-translation.patch fs-move-mapping-helpers.patch fs-port-higher-level-mapping-helpers.patch fs-remove-unused-low-level-mapping-helpers.patch fs-support-mapped-mounts-of-mapped-filesystems.patch fs-tweak-fsuidgid_has_mapping.patch fs-use-low-level-mapping-helpers.patch --- .../docs-update-mapping-documentation.patch | 109 ++++++ .../fs-account-for-filesystem-mappings.patch | 349 ++++++++++++++++++ .../fs-account-for-group-membership.patch | 113 ++++++ queue-5.15/fs-add-i_user_ns-helper.patch | 73 ++++ .../fs-add-is_idmapped_mnt-helper.patch | 130 +++++++ queue-5.15/fs-fix-acl-translation.patch | 127 +++++++ queue-5.15/fs-move-mapping-helpers.patch | 322 ++++++++++++++++ ...fs-port-higher-level-mapping-helpers.patch | 153 ++++++++ ...ove-unused-low-level-mapping-helpers.patch | 99 +++++ ...-mapped-mounts-of-mapped-filesystems.patch | 345 +++++++++++++++++ .../fs-tweak-fsuidgid_has_mapping.patch | 58 +++ .../fs-use-low-level-mapping-helpers.patch | 208 +++++++++++ queue-5.15/series | 12 + 13 files changed, 2098 insertions(+) create mode 100644 queue-5.15/docs-update-mapping-documentation.patch create mode 100644 queue-5.15/fs-account-for-filesystem-mappings.patch create mode 100644 queue-5.15/fs-account-for-group-membership.patch create mode 100644 queue-5.15/fs-add-i_user_ns-helper.patch create mode 100644 queue-5.15/fs-add-is_idmapped_mnt-helper.patch create mode 100644 queue-5.15/fs-fix-acl-translation.patch create mode 100644 queue-5.15/fs-move-mapping-helpers.patch create mode 100644 queue-5.15/fs-port-higher-level-mapping-helpers.patch create mode 100644 queue-5.15/fs-remove-unused-low-level-mapping-helpers.patch create mode 100644 queue-5.15/fs-support-mapped-mounts-of-mapped-filesystems.patch create mode 100644 queue-5.15/fs-tweak-fsuidgid_has_mapping.patch create mode 100644 queue-5.15/fs-use-low-level-mapping-helpers.patch diff --git a/queue-5.15/docs-update-mapping-documentation.patch b/queue-5.15/docs-update-mapping-documentation.patch new file mode 100644 index 00000000000..3677020366c --- /dev/null +++ b/queue-5.15/docs-update-mapping-documentation.patch @@ -0,0 +1,109 @@ +From foo@baz Thu Jun 30 01:35:30 PM CEST 2022 +From: Christian Brauner +Date: Tue, 28 Jun 2022 14:16:13 +0200 +Subject: docs: update mapping documentation +To: Greg KH +Cc: Christian Brauner , stable@vger.kernel.org +Message-ID: <20220628121620.188722-6-brauner@kernel.org> + +From: Christian Brauner + +commit 8cc5c54de44c5e8e104d364a627ac4296845fc7f upstream. + +Now that we implement the full remapping algorithms described in our +documentation remove the section about shortcircuting them. + +Link: https://lore.kernel.org/r/20211123114227.3124056-6-brauner@kernel.org (v1) +Link: https://lore.kernel.org/r/20211130121032.3753852-6-brauner@kernel.org (v2) +Link: https://lore.kernel.org/r/20211203111707.3901969-6-brauner@kernel.org +Cc: Seth Forshee +Cc: Amir Goldstein +Cc: Christoph Hellwig +Cc: Al Viro +CC: linux-fsdevel@vger.kernel.org +Reviewed-by: Seth Forshee +Signed-off-by: Christian Brauner +Signed-off-by: Christian Brauner (Microsoft) +Signed-off-by: Greg Kroah-Hartman +--- + Documentation/filesystems/idmappings.rst | 72 ------------------------------- + 1 file changed, 72 deletions(-) + +--- a/Documentation/filesystems/idmappings.rst ++++ b/Documentation/filesystems/idmappings.rst +@@ -952,75 +952,3 @@ The raw userspace id that is put on disk + their home directory back to their home computer where they are assigned + ``u1000`` using the initial idmapping and mount the filesystem with the initial + idmapping they will see all those files owned by ``u1000``. +- +-Shortcircuting +--------------- +- +-Currently, the implementation of idmapped mounts enforces that the filesystem +-is mounted with the initial idmapping. The reason is simply that none of the +-filesystems that we targeted were mountable with a non-initial idmapping. But +-that might change soon enough. As we've seen above, thanks to the properties of +-idmappings the translation works for both filesystems mounted with the initial +-idmapping and filesystem with non-initial idmappings. +- +-Based on this current restriction to filesystem mounted with the initial +-idmapping two noticeable shortcuts have been taken: +- +-1. We always stash a reference to the initial user namespace in ``struct +- vfsmount``. Idmapped mounts are thus mounts that have a non-initial user +- namespace attached to them. +- +- In order to support idmapped mounts this needs to be changed. Instead of +- stashing the initial user namespace the user namespace the filesystem was +- mounted with must be stashed. An idmapped mount is then any mount that has +- a different user namespace attached then the filesystem was mounted with. +- This has no user-visible consequences. +- +-2. The translation algorithms in ``mapped_fs*id()`` and ``i_*id_into_mnt()`` +- are simplified. +- +- Let's consider ``mapped_fs*id()`` first. This function translates the +- caller's kernel id into a kernel id in the filesystem's idmapping via +- a mount's idmapping. The full algorithm is:: +- +- mapped_fsuid(kid): +- /* Map the kernel id up into a userspace id in the mount's idmapping. */ +- from_kuid(mount-idmapping, kid) = uid +- +- /* Map the userspace id down into a kernel id in the filesystem's idmapping. */ +- make_kuid(filesystem-idmapping, uid) = kuid +- +- We know that the filesystem is always mounted with the initial idmapping as +- we enforce this in ``mount_setattr()``. So this can be shortened to:: +- +- mapped_fsuid(kid): +- /* Map the kernel id up into a userspace id in the mount's idmapping. */ +- from_kuid(mount-idmapping, kid) = uid +- +- /* Map the userspace id down into a kernel id in the filesystem's idmapping. */ +- KUIDT_INIT(uid) = kuid +- +- Similarly, for ``i_*id_into_mnt()`` which translated the filesystem's kernel +- id into a mount's kernel id:: +- +- i_uid_into_mnt(kid): +- /* Map the kernel id up into a userspace id in the filesystem's idmapping. */ +- from_kuid(filesystem-idmapping, kid) = uid +- +- /* Map the userspace id down into a kernel id in the mounts's idmapping. */ +- make_kuid(mount-idmapping, uid) = kuid +- +- Again, we know that the filesystem is always mounted with the initial +- idmapping as we enforce this in ``mount_setattr()``. So this can be +- shortened to:: +- +- i_uid_into_mnt(kid): +- /* Map the kernel id up into a userspace id in the filesystem's idmapping. */ +- __kuid_val(kid) = uid +- +- /* Map the userspace id down into a kernel id in the mounts's idmapping. */ +- make_kuid(mount-idmapping, uid) = kuid +- +-Handling filesystems mounted with non-initial idmappings requires that the +-translation functions be converted to their full form. They can still be +-shortcircuited on non-idmapped mounts. This has no user-visible consequences. diff --git a/queue-5.15/fs-account-for-filesystem-mappings.patch b/queue-5.15/fs-account-for-filesystem-mappings.patch new file mode 100644 index 00000000000..c51c3a12202 --- /dev/null +++ b/queue-5.15/fs-account-for-filesystem-mappings.patch @@ -0,0 +1,349 @@ +From foo@baz Thu Jun 30 01:35:30 PM CEST 2022 +From: Christian Brauner +Date: Tue, 28 Jun 2022 14:16:12 +0200 +Subject: fs: account for filesystem mappings +To: Greg KH +Cc: Christian Brauner , stable@vger.kernel.org +Message-ID: <20220628121620.188722-5-brauner@kernel.org> + +From: Christian Brauner + +commit 1ac2a4104968e0a60b4b3572216a92aab5c1b025 upstream. + +Currently we only support idmapped mounts for filesystems mounted +without an idmapping. This was a conscious decision mentioned in +multiple places (cf. e.g. [1]). + +As explained at length in [3] it is perfectly fine to extend support for +idmapped mounts to filesystem's mounted with an idmapping should the +need arise. The need has been there for some time now. Various container +projects in userspace need this to run unprivileged and nested +unprivileged containers (cf. [2]). + +Before we can port any filesystem that is mountable with an idmapping to +support idmapped mounts we need to first extend the mapping helpers to +account for the filesystem's idmapping. This again, is explained at +length in our documentation at [3] but I'll give an overview here again. + +Currently, the low-level mapping helpers implement the remapping +algorithms described in [3] in a simplified manner. Because we could +rely on the fact that all filesystems supporting idmapped mounts are +mounted without an idmapping the translation step from or into the +filesystem idmapping could be skipped. + +In order to support idmapped mounts of filesystem's mountable with an +idmapping the translation step we were able to skip before cannot be +skipped anymore. A filesystem mounted with an idmapping is very likely +to not use an identity mapping and will instead use a non-identity +mapping. So the translation step from or into the filesystem's idmapping +in the remapping algorithm cannot be skipped for such filesystems. More +details with examples can be found in [3]. + +This patch adds a few new and prepares some already existing low-level +mapping helpers to perform the full translation algorithm explained in +[3]. The low-level helpers can be written in a way that they only +perform the additional translation step when the filesystem is indeed +mounted with an idmapping. + +If the low-level helpers detect that they are not dealing with an +idmapped mount they can simply return the relevant k{g,u}id unchanged; +no remapping needs to be performed at all. The no_idmapping() helper +detects whether the shortcut can be used. + +If the low-level helpers detected that they are dealing with an idmapped +mount but the underlying filesystem is mounted without an idmapping we +can rely on the previous shorcut and can continue to skip the +translation step from or into the filesystem's idmapping. + +These checks guarantee that only the minimal amount of work is +performed. As before, if idmapped mounts aren't used the low-level +helpers are idempotent and no work is performed at all. + +This patch adds the helpers mapped_k{g,u}id_fs() and +mapped_k{g,u}id_user(). Following patches will port all places to +replace the old k{g,u}id_into_mnt() and k{g,u}id_from_mnt() with these +two new helpers. After the conversion is done k{g,u}id_into_mnt() and +k{g,u}id_from_mnt() will be removed. This also concludes the renaming of +the mapping helpers we started in [4]. Now, all mapping helpers will +started with the "mapped_" prefix making everything nice and consistent. + +The mapped_k{g,u}id_fs() helpers replace the k{g,u}id_into_mnt() +helpers. They are to be used when k{g,u}ids are to be mapped from the +vfs, e.g. from from struct inode's i_{g,u}id. Conversely, the +mapped_k{g,u}id_user() helpers replace the k{g,u}id_from_mnt() helpers. +They are to be used when k{g,u}ids are to be written to disk, e.g. when +entering from a system call to change ownership of a file. + +This patch only introduces the helpers. It doesn't yet convert the +relevant places to account for filesystem mounted with an idmapping. + +[1]: commit 2ca4dcc4909d ("fs/mount_setattr: tighten permission checks") +[2]: https://github.com/containers/podman/issues/10374 +[3]: Documentations/filesystems/idmappings.rst +[4]: commit a65e58e791a1 ("fs: document and rename fsid helpers") + +Link: https://lore.kernel.org/r/20211123114227.3124056-5-brauner@kernel.org (v1) +Link: https://lore.kernel.org/r/20211130121032.3753852-5-brauner@kernel.org (v2) +Link: https://lore.kernel.org/r/20211203111707.3901969-5-brauner@kernel.org +Cc: Seth Forshee +Cc: Amir Goldstein +Cc: Christoph Hellwig +Cc: Al Viro +CC: linux-fsdevel@vger.kernel.org +Reviewed-by: Seth Forshee +Signed-off-by: Christian Brauner +Signed-off-by: Christian Brauner (Microsoft) +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/fs.h | 4 + include/linux/mnt_idmapping.h | 193 +++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 191 insertions(+), 6 deletions(-) + +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -1638,7 +1638,7 @@ static inline void i_gid_write(struct in + static inline kuid_t i_uid_into_mnt(struct user_namespace *mnt_userns, + const struct inode *inode) + { +- return kuid_into_mnt(mnt_userns, inode->i_uid); ++ return mapped_kuid_fs(mnt_userns, &init_user_ns, inode->i_uid); + } + + /** +@@ -1652,7 +1652,7 @@ static inline kuid_t i_uid_into_mnt(stru + static inline kgid_t i_gid_into_mnt(struct user_namespace *mnt_userns, + const struct inode *inode) + { +- return kgid_into_mnt(mnt_userns, inode->i_gid); ++ return mapped_kgid_fs(mnt_userns, &init_user_ns, inode->i_gid); + } + + /** +--- a/include/linux/mnt_idmapping.h ++++ b/include/linux/mnt_idmapping.h +@@ -6,6 +6,11 @@ + #include + + struct user_namespace; ++/* ++ * Carries the initial idmapping of 0:0:4294967295 which is an identity ++ * mapping. This means that {g,u}id 0 is mapped to {g,u}id 0, {g,u}id 1 is ++ * mapped to {g,u}id 1, [...], {g,u}id 1000 to {g,u}id 1000, [...]. ++ */ + extern struct user_namespace init_user_ns; + + /** +@@ -65,8 +70,188 @@ static inline kgid_t kgid_from_mnt(struc + } + + /** ++ * initial_idmapping - check whether this is the initial mapping ++ * @ns: idmapping to check ++ * ++ * Check whether this is the initial mapping, mapping 0 to 0, 1 to 1, ++ * [...], 1000 to 1000 [...]. ++ * ++ * Return: true if this is the initial mapping, false if not. ++ */ ++static inline bool initial_idmapping(const struct user_namespace *ns) ++{ ++ return ns == &init_user_ns; ++} ++ ++/** ++ * no_idmapping - check whether we can skip remapping a kuid/gid ++ * @mnt_userns: the mount's idmapping ++ * @fs_userns: the filesystem's idmapping ++ * ++ * This function can be used to check whether a remapping between two ++ * idmappings is required. ++ * An idmapped mount is a mount that has an idmapping attached to it that ++ * is different from the filsystem's idmapping and the initial idmapping. ++ * If the initial mapping is used or the idmapping of the mount and the ++ * filesystem are identical no remapping is required. ++ * ++ * Return: true if remapping can be skipped, false if not. ++ */ ++static inline bool no_idmapping(const struct user_namespace *mnt_userns, ++ const struct user_namespace *fs_userns) ++{ ++ return initial_idmapping(mnt_userns) || mnt_userns == fs_userns; ++} ++ ++/** ++ * mapped_kuid_fs - map a filesystem kuid into a mnt_userns ++ * @mnt_userns: the mount's idmapping ++ * @fs_userns: the filesystem's idmapping ++ * @kuid : kuid to be mapped ++ * ++ * Take a @kuid and remap it from @fs_userns into @mnt_userns. Use this ++ * function when preparing a @kuid to be reported to userspace. ++ * ++ * If no_idmapping() determines that this is not an idmapped mount we can ++ * simply return @kuid unchanged. ++ * If initial_idmapping() tells us that the filesystem is not mounted with an ++ * idmapping we know the value of @kuid won't change when calling ++ * from_kuid() so we can simply retrieve the value via __kuid_val() ++ * directly. ++ * ++ * Return: @kuid mapped according to @mnt_userns. ++ * If @kuid has no mapping in either @mnt_userns or @fs_userns INVALID_UID is ++ * returned. ++ */ ++static inline kuid_t mapped_kuid_fs(struct user_namespace *mnt_userns, ++ struct user_namespace *fs_userns, ++ kuid_t kuid) ++{ ++ uid_t uid; ++ ++ if (no_idmapping(mnt_userns, fs_userns)) ++ return kuid; ++ if (initial_idmapping(fs_userns)) ++ uid = __kuid_val(kuid); ++ else ++ uid = from_kuid(fs_userns, kuid); ++ if (uid == (uid_t)-1) ++ return INVALID_UID; ++ return make_kuid(mnt_userns, uid); ++} ++ ++/** ++ * mapped_kgid_fs - map a filesystem kgid into a mnt_userns ++ * @mnt_userns: the mount's idmapping ++ * @fs_userns: the filesystem's idmapping ++ * @kgid : kgid to be mapped ++ * ++ * Take a @kgid and remap it from @fs_userns into @mnt_userns. Use this ++ * function when preparing a @kgid to be reported to userspace. ++ * ++ * If no_idmapping() determines that this is not an idmapped mount we can ++ * simply return @kgid unchanged. ++ * If initial_idmapping() tells us that the filesystem is not mounted with an ++ * idmapping we know the value of @kgid won't change when calling ++ * from_kgid() so we can simply retrieve the value via __kgid_val() ++ * directly. ++ * ++ * Return: @kgid mapped according to @mnt_userns. ++ * If @kgid has no mapping in either @mnt_userns or @fs_userns INVALID_GID is ++ * returned. ++ */ ++static inline kgid_t mapped_kgid_fs(struct user_namespace *mnt_userns, ++ struct user_namespace *fs_userns, ++ kgid_t kgid) ++{ ++ gid_t gid; ++ ++ if (no_idmapping(mnt_userns, fs_userns)) ++ return kgid; ++ if (initial_idmapping(fs_userns)) ++ gid = __kgid_val(kgid); ++ else ++ gid = from_kgid(fs_userns, kgid); ++ if (gid == (gid_t)-1) ++ return INVALID_GID; ++ return make_kgid(mnt_userns, gid); ++} ++ ++/** ++ * mapped_kuid_user - map a user kuid into a mnt_userns ++ * @mnt_userns: the mount's idmapping ++ * @fs_userns: the filesystem's idmapping ++ * @kuid : kuid to be mapped ++ * ++ * Use the idmapping of @mnt_userns to remap a @kuid into @fs_userns. Use this ++ * function when preparing a @kuid to be written to disk or inode. ++ * ++ * If no_idmapping() determines that this is not an idmapped mount we can ++ * simply return @kuid unchanged. ++ * If initial_idmapping() tells us that the filesystem is not mounted with an ++ * idmapping we know the value of @kuid won't change when calling ++ * make_kuid() so we can simply retrieve the value via KUIDT_INIT() ++ * directly. ++ * ++ * Return: @kuid mapped according to @mnt_userns. ++ * If @kuid has no mapping in either @mnt_userns or @fs_userns INVALID_UID is ++ * returned. ++ */ ++static inline kuid_t mapped_kuid_user(struct user_namespace *mnt_userns, ++ struct user_namespace *fs_userns, ++ kuid_t kuid) ++{ ++ uid_t uid; ++ ++ if (no_idmapping(mnt_userns, fs_userns)) ++ return kuid; ++ uid = from_kuid(mnt_userns, kuid); ++ if (uid == (uid_t)-1) ++ return INVALID_UID; ++ if (initial_idmapping(fs_userns)) ++ return KUIDT_INIT(uid); ++ return make_kuid(fs_userns, uid); ++} ++ ++/** ++ * mapped_kgid_user - map a user kgid into a mnt_userns ++ * @mnt_userns: the mount's idmapping ++ * @fs_userns: the filesystem's idmapping ++ * @kgid : kgid to be mapped ++ * ++ * Use the idmapping of @mnt_userns to remap a @kgid into @fs_userns. Use this ++ * function when preparing a @kgid to be written to disk or inode. ++ * ++ * If no_idmapping() determines that this is not an idmapped mount we can ++ * simply return @kgid unchanged. ++ * If initial_idmapping() tells us that the filesystem is not mounted with an ++ * idmapping we know the value of @kgid won't change when calling ++ * make_kgid() so we can simply retrieve the value via KGIDT_INIT() ++ * directly. ++ * ++ * Return: @kgid mapped according to @mnt_userns. ++ * If @kgid has no mapping in either @mnt_userns or @fs_userns INVALID_GID is ++ * returned. ++ */ ++static inline kgid_t mapped_kgid_user(struct user_namespace *mnt_userns, ++ struct user_namespace *fs_userns, ++ kgid_t kgid) ++{ ++ gid_t gid; ++ ++ if (no_idmapping(mnt_userns, fs_userns)) ++ return kgid; ++ gid = from_kgid(mnt_userns, kgid); ++ if (gid == (gid_t)-1) ++ return INVALID_GID; ++ if (initial_idmapping(fs_userns)) ++ return KGIDT_INIT(gid); ++ return make_kgid(fs_userns, gid); ++} ++ ++/** + * mapped_fsuid - return caller's fsuid mapped up into a mnt_userns +- * @mnt_userns: user namespace of the relevant mount ++ * @mnt_userns: the mount's idmapping + * + * Use this helper to initialize a new vfs or filesystem object based on + * the caller's fsuid. A common example is initializing the i_uid field of +@@ -78,12 +263,12 @@ static inline kgid_t kgid_from_mnt(struc + */ + static inline kuid_t mapped_fsuid(struct user_namespace *mnt_userns) + { +- return kuid_from_mnt(mnt_userns, current_fsuid()); ++ return mapped_kuid_user(mnt_userns, &init_user_ns, current_fsuid()); + } + + /** + * mapped_fsgid - return caller's fsgid mapped up into a mnt_userns +- * @mnt_userns: user namespace of the relevant mount ++ * @mnt_userns: the mount's idmapping + * + * Use this helper to initialize a new vfs or filesystem object based on + * the caller's fsgid. A common example is initializing the i_gid field of +@@ -95,7 +280,7 @@ static inline kuid_t mapped_fsuid(struct + */ + static inline kgid_t mapped_fsgid(struct user_namespace *mnt_userns) + { +- return kgid_from_mnt(mnt_userns, current_fsgid()); ++ return mapped_kgid_user(mnt_userns, &init_user_ns, current_fsgid()); + } + + #endif /* _LINUX_MNT_IDMAPPING_H */ diff --git a/queue-5.15/fs-account-for-group-membership.patch b/queue-5.15/fs-account-for-group-membership.patch new file mode 100644 index 00000000000..8134045553c --- /dev/null +++ b/queue-5.15/fs-account-for-group-membership.patch @@ -0,0 +1,113 @@ +From foo@baz Thu Jun 30 01:35:30 PM CEST 2022 +From: Christian Brauner +Date: Tue, 28 Jun 2022 14:16:20 +0200 +Subject: fs: account for group membership +To: Greg KH +Cc: Christian Brauner , stable@vger.kernel.org +Message-ID: <20220628121620.188722-13-brauner@kernel.org> + +From: Christian Brauner + +commit 168f912893407a5acb798a4a58613b5f1f98c717 upstream. + +When calling setattr_prepare() to determine the validity of the +attributes the ia_{g,u}id fields contain the value that will be written +to inode->i_{g,u}id. This is exactly the same for idmapped and +non-idmapped mounts and allows callers to pass in the values they want +to see written to inode->i_{g,u}id. + +When group ownership is changed a caller whose fsuid owns the inode can +change the group of the inode to any group they are a member of. When +searching through the caller's groups we need to use the gid mapped +according to the idmapped mount otherwise we will fail to change +ownership for unprivileged users. + +Consider a caller running with fsuid and fsgid 1000 using an idmapped +mount that maps id 65534 to 1000 and 65535 to 1001. Consequently, a file +owned by 65534:65535 in the filesystem will be owned by 1000:1001 in the +idmapped mount. + +The caller now requests the gid of the file to be changed to 1000 going +through the idmapped mount. In the vfs we will immediately map the +requested gid to the value that will need to be written to inode->i_gid +and place it in attr->ia_gid. Since this idmapped mount maps 65534 to +1000 we place 65534 in attr->ia_gid. + +When we check whether the caller is allowed to change group ownership we +first validate that their fsuid matches the inode's uid. The +inode->i_uid is 65534 which is mapped to uid 1000 in the idmapped mount. +Since the caller's fsuid is 1000 we pass the check. + +We now check whether the caller is allowed to change inode->i_gid to the +requested gid by calling in_group_p(). This will compare the passed in +gid to the caller's fsgid and search the caller's additional groups. + +Since we're dealing with an idmapped mount we need to pass in the gid +mapped according to the idmapped mount. This is akin to checking whether +a caller is privileged over the future group the inode is owned by. And +that needs to take the idmapped mount into account. Note, all helpers +are nops without idmapped mounts. + +New regression test sent to xfstests. + +Link: https://github.com/lxc/lxd/issues/10537 +Link: https://lore.kernel.org/r/20220613111517.2186646-1-brauner@kernel.org +Fixes: 2f221d6f7b88 ("attr: handle idmapped mounts") +Cc: Seth Forshee +Cc: Christoph Hellwig +Cc: Aleksa Sarai +Cc: Al Viro +Cc: stable@vger.kernel.org # 5.15+ +CC: linux-fsdevel@vger.kernel.org +Reviewed-by: Seth Forshee +Signed-off-by: Christian Brauner (Microsoft) +Signed-off-by: Greg Kroah-Hartman +--- + fs/attr.c | 26 ++++++++++++++++++++------ + 1 file changed, 20 insertions(+), 6 deletions(-) + +--- a/fs/attr.c ++++ b/fs/attr.c +@@ -61,9 +61,15 @@ static bool chgrp_ok(struct user_namespa + const struct inode *inode, kgid_t gid) + { + kgid_t kgid = i_gid_into_mnt(mnt_userns, inode); +- if (uid_eq(current_fsuid(), i_uid_into_mnt(mnt_userns, inode)) && +- (in_group_p(gid) || gid_eq(gid, inode->i_gid))) +- return true; ++ if (uid_eq(current_fsuid(), i_uid_into_mnt(mnt_userns, inode))) { ++ kgid_t mapped_gid; ++ ++ if (gid_eq(gid, inode->i_gid)) ++ return true; ++ mapped_gid = mapped_kgid_fs(mnt_userns, i_user_ns(inode), gid); ++ if (in_group_p(mapped_gid)) ++ return true; ++ } + if (capable_wrt_inode_uidgid(mnt_userns, inode, CAP_CHOWN)) + return true; + if (gid_eq(kgid, INVALID_GID) && +@@ -123,12 +129,20 @@ int setattr_prepare(struct user_namespac + + /* Make sure a caller can chmod. */ + if (ia_valid & ATTR_MODE) { ++ kgid_t mapped_gid; ++ + if (!inode_owner_or_capable(mnt_userns, inode)) + return -EPERM; ++ ++ if (ia_valid & ATTR_GID) ++ mapped_gid = mapped_kgid_fs(mnt_userns, ++ i_user_ns(inode), attr->ia_gid); ++ else ++ mapped_gid = i_gid_into_mnt(mnt_userns, inode); ++ + /* Also check the setgid bit! */ +- if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid : +- i_gid_into_mnt(mnt_userns, inode)) && +- !capable_wrt_inode_uidgid(mnt_userns, inode, CAP_FSETID)) ++ if (!in_group_p(mapped_gid) && ++ !capable_wrt_inode_uidgid(mnt_userns, inode, CAP_FSETID)) + attr->ia_mode &= ~S_ISGID; + } + diff --git a/queue-5.15/fs-add-i_user_ns-helper.patch b/queue-5.15/fs-add-i_user_ns-helper.patch new file mode 100644 index 00000000000..85b9426d2d5 --- /dev/null +++ b/queue-5.15/fs-add-i_user_ns-helper.patch @@ -0,0 +1,73 @@ +From foo@baz Thu Jun 30 01:35:30 PM CEST 2022 +From: Christian Brauner +Date: Tue, 28 Jun 2022 14:16:17 +0200 +Subject: fs: add i_user_ns() helper +To: Greg KH +Cc: Christian Brauner , stable@vger.kernel.org +Message-ID: <20220628121620.188722-10-brauner@kernel.org> + +From: Christian Brauner + +commit a1ec9040a2a9122605ac26e5725c6de019184419 upstream. + +Since we'll be passing the filesystem's idmapping in even more places in +the following patches and we do already dereference struct inode to get +to the filesystem's idmapping multiple times add a tiny helper. + +Link: https://lore.kernel.org/r/20211123114227.3124056-10-brauner@kernel.org (v1) +Link: https://lore.kernel.org/r/20211130121032.3753852-10-brauner@kernel.org (v2) +Link: https://lore.kernel.org/r/20211203111707.3901969-10-brauner@kernel.org +Cc: Seth Forshee +Cc: Christoph Hellwig +Cc: Al Viro +CC: linux-fsdevel@vger.kernel.org +Reviewed-by: Amir Goldstein +Reviewed-by: Seth Forshee +Signed-off-by: Christian Brauner +Signed-off-by: Christian Brauner (Microsoft) +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/fs.h | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -1602,6 +1602,11 @@ struct super_block { + struct list_head s_inodes_wb; /* writeback inodes */ + } __randomize_layout; + ++static inline struct user_namespace *i_user_ns(const struct inode *inode) ++{ ++ return inode->i_sb->s_user_ns; ++} ++ + /* Helper functions so that in most cases filesystems will + * not need to deal directly with kuid_t and kgid_t and can + * instead deal with the raw numeric values that are stored +@@ -1609,22 +1614,22 @@ struct super_block { + */ + static inline uid_t i_uid_read(const struct inode *inode) + { +- return from_kuid(inode->i_sb->s_user_ns, inode->i_uid); ++ return from_kuid(i_user_ns(inode), inode->i_uid); + } + + static inline gid_t i_gid_read(const struct inode *inode) + { +- return from_kgid(inode->i_sb->s_user_ns, inode->i_gid); ++ return from_kgid(i_user_ns(inode), inode->i_gid); + } + + static inline void i_uid_write(struct inode *inode, uid_t uid) + { +- inode->i_uid = make_kuid(inode->i_sb->s_user_ns, uid); ++ inode->i_uid = make_kuid(i_user_ns(inode), uid); + } + + static inline void i_gid_write(struct inode *inode, gid_t gid) + { +- inode->i_gid = make_kgid(inode->i_sb->s_user_ns, gid); ++ inode->i_gid = make_kgid(i_user_ns(inode), gid); + } + + /** diff --git a/queue-5.15/fs-add-is_idmapped_mnt-helper.patch b/queue-5.15/fs-add-is_idmapped_mnt-helper.patch new file mode 100644 index 00000000000..2e6e05ec436 --- /dev/null +++ b/queue-5.15/fs-add-is_idmapped_mnt-helper.patch @@ -0,0 +1,130 @@ +From foo@baz Thu Jun 30 01:35:30 PM CEST 2022 +From: Christian Brauner +Date: Tue, 28 Jun 2022 14:16:09 +0200 +Subject: fs: add is_idmapped_mnt() helper +To: Greg KH +Cc: Christian Brauner , stable@vger.kernel.org +Message-ID: <20220628121620.188722-2-brauner@kernel.org> + +From: Christian Brauner + +commit bb49e9e730c2906a958eee273a7819f401543d6c upstream. + +Multiple places open-code the same check to determine whether a given +mount is idmapped. Introduce a simple helper function that can be used +instead. This allows us to get rid of the fragile open-coding. We will +later change the check that is used to determine whether a given mount +is idmapped. Introducing a helper allows us to do this in a single +place instead of doing it for multiple places. + +Link: https://lore.kernel.org/r/20211123114227.3124056-2-brauner@kernel.org (v1) +Link: https://lore.kernel.org/r/20211130121032.3753852-2-brauner@kernel.org (v2) +Link: https://lore.kernel.org/r/20211203111707.3901969-2-brauner@kernel.org +Cc: Seth Forshee +Cc: Christoph Hellwig +Cc: Al Viro +CC: linux-fsdevel@vger.kernel.org +Reviewed-by: Amir Goldstein +Reviewed-by: Seth Forshee +Signed-off-by: Christian Brauner +Signed-off-by: Christian Brauner (Microsoft) +Signed-off-by: Greg Kroah-Hartman +--- + fs/cachefiles/bind.c | 2 +- + fs/ecryptfs/main.c | 2 +- + fs/namespace.c | 2 +- + fs/nfsd/export.c | 2 +- + fs/overlayfs/super.c | 2 +- + fs/proc_namespace.c | 2 +- + include/linux/fs.h | 14 ++++++++++++++ + 7 files changed, 20 insertions(+), 6 deletions(-) + +--- a/fs/cachefiles/bind.c ++++ b/fs/cachefiles/bind.c +@@ -117,7 +117,7 @@ static int cachefiles_daemon_add_cache(s + root = path.dentry; + + ret = -EINVAL; +- if (mnt_user_ns(path.mnt) != &init_user_ns) { ++ if (is_idmapped_mnt(path.mnt)) { + pr_warn("File cache on idmapped mounts not supported"); + goto error_unsupported; + } +--- a/fs/ecryptfs/main.c ++++ b/fs/ecryptfs/main.c +@@ -537,7 +537,7 @@ static struct dentry *ecryptfs_mount(str + goto out_free; + } + +- if (mnt_user_ns(path.mnt) != &init_user_ns) { ++ if (is_idmapped_mnt(path.mnt)) { + rc = -EINVAL; + printk(KERN_ERR "Mounting on idmapped mounts currently disallowed\n"); + goto out_free; +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -3936,7 +3936,7 @@ static int can_idmap_mount(const struct + * mapping. It makes things simpler and callers can just create + * another bind-mount they can idmap if they want to. + */ +- if (mnt_user_ns(m) != &init_user_ns) ++ if (is_idmapped_mnt(m)) + return -EPERM; + + /* The underlying filesystem doesn't support idmapped mounts yet. */ +--- a/fs/nfsd/export.c ++++ b/fs/nfsd/export.c +@@ -427,7 +427,7 @@ static int check_export(struct path *pat + return -EINVAL; + } + +- if (mnt_user_ns(path->mnt) != &init_user_ns) { ++ if (is_idmapped_mnt(path->mnt)) { + dprintk("exp_export: export of idmapped mounts not yet supported.\n"); + return -EINVAL; + } +--- a/fs/overlayfs/super.c ++++ b/fs/overlayfs/super.c +@@ -873,7 +873,7 @@ static int ovl_mount_dir_noesc(const cha + pr_err("filesystem on '%s' not supported\n", name); + goto out_put; + } +- if (mnt_user_ns(path->mnt) != &init_user_ns) { ++ if (is_idmapped_mnt(path->mnt)) { + pr_err("idmapped layers are currently not supported\n"); + goto out_put; + } +--- a/fs/proc_namespace.c ++++ b/fs/proc_namespace.c +@@ -80,7 +80,7 @@ static void show_mnt_opts(struct seq_fil + seq_puts(m, fs_infop->str); + } + +- if (mnt_user_ns(mnt) != &init_user_ns) ++ if (is_idmapped_mnt(mnt)) + seq_puts(m, ",idmapped"); + } + +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -2726,6 +2726,20 @@ static inline struct user_namespace *fil + { + return mnt_user_ns(file->f_path.mnt); + } ++ ++/** ++ * is_idmapped_mnt - check whether a mount is mapped ++ * @mnt: the mount to check ++ * ++ * If @mnt has an idmapping attached to it @mnt is mapped. ++ * ++ * Return: true if mount is mapped, false if not. ++ */ ++static inline bool is_idmapped_mnt(const struct vfsmount *mnt) ++{ ++ return mnt_user_ns(mnt) != &init_user_ns; ++} ++ + extern long vfs_truncate(const struct path *, loff_t); + int do_truncate(struct user_namespace *, struct dentry *, loff_t start, + unsigned int time_attrs, struct file *filp); diff --git a/queue-5.15/fs-fix-acl-translation.patch b/queue-5.15/fs-fix-acl-translation.patch new file mode 100644 index 00000000000..fdc5ac81be3 --- /dev/null +++ b/queue-5.15/fs-fix-acl-translation.patch @@ -0,0 +1,127 @@ +From foo@baz Thu Jun 30 01:35:30 PM CEST 2022 +From: Christian Brauner +Date: Tue, 28 Jun 2022 14:16:19 +0200 +Subject: fs: fix acl translation +To: Greg KH +Cc: Christian Brauner , stable@vger.kernel.org +Message-ID: <20220628121620.188722-12-brauner@kernel.org> + +From: Christian Brauner + +commit 705191b03d507744c7e097f78d583621c14988ac upstream. + +Last cycle we extended the idmapped mounts infrastructure to support +idmapped mounts of idmapped filesystems (No such filesystem yet exist.). +Since then, the meaning of an idmapped mount is a mount whose idmapping +is different from the filesystems idmapping. + +While doing that work we missed to adapt the acl translation helpers. +They still assume that checking for the identity mapping is enough. But +they need to use the no_idmapping() helper instead. + +Note, POSIX ACLs are always translated right at the userspace-kernel +boundary using the caller's current idmapping and the initial idmapping. +The order depends on whether we're coming from or going to userspace. +The filesystem's idmapping doesn't matter at the border. + +Consequently, if a non-idmapped mount is passed we need to make sure to +always pass the initial idmapping as the mount's idmapping and not the +filesystem idmapping. Since it's irrelevant here it would yield invalid +ids and prevent setting acls for filesystems that are mountable in a +userns and support posix acls (tmpfs and fuse). + +I verified the regression reported in [1] and verified that this patch +fixes it. A regression test will be added to xfstests in parallel. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=215849 [1] +Fixes: bd303368b776 ("fs: support mapped mounts of mapped filesystems") +Cc: Seth Forshee +Cc: Christoph Hellwig +Cc: # 5.15+ +Cc: +Signed-off-by: Christian Brauner (Microsoft) +Signed-off-by: Linus Torvalds +Signed-off-by: Christian Brauner (Microsoft) +Signed-off-by: Greg Kroah-Hartman +--- + fs/posix_acl.c | 10 ++++++++++ + fs/xattr.c | 6 ++++-- + include/linux/posix_acl_xattr.h | 4 ++++ + 3 files changed, 18 insertions(+), 2 deletions(-) + +--- a/fs/posix_acl.c ++++ b/fs/posix_acl.c +@@ -760,9 +760,14 @@ static void posix_acl_fix_xattr_userns( + } + + void posix_acl_fix_xattr_from_user(struct user_namespace *mnt_userns, ++ struct inode *inode, + void *value, size_t size) + { + struct user_namespace *user_ns = current_user_ns(); ++ ++ /* Leave ids untouched on non-idmapped mounts. */ ++ if (no_idmapping(mnt_userns, i_user_ns(inode))) ++ mnt_userns = &init_user_ns; + if ((user_ns == &init_user_ns) && (mnt_userns == &init_user_ns)) + return; + posix_acl_fix_xattr_userns(&init_user_ns, user_ns, mnt_userns, value, +@@ -770,9 +775,14 @@ void posix_acl_fix_xattr_from_user(struc + } + + void posix_acl_fix_xattr_to_user(struct user_namespace *mnt_userns, ++ struct inode *inode, + void *value, size_t size) + { + struct user_namespace *user_ns = current_user_ns(); ++ ++ /* Leave ids untouched on non-idmapped mounts. */ ++ if (no_idmapping(mnt_userns, i_user_ns(inode))) ++ mnt_userns = &init_user_ns; + if ((user_ns == &init_user_ns) && (mnt_userns == &init_user_ns)) + return; + posix_acl_fix_xattr_userns(user_ns, &init_user_ns, mnt_userns, value, +--- a/fs/xattr.c ++++ b/fs/xattr.c +@@ -569,7 +569,8 @@ setxattr(struct user_namespace *mnt_user + } + if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) || + (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0)) +- posix_acl_fix_xattr_from_user(mnt_userns, kvalue, size); ++ posix_acl_fix_xattr_from_user(mnt_userns, d_inode(d), ++ kvalue, size); + } + + error = vfs_setxattr(mnt_userns, d, kname, kvalue, size, flags); +@@ -667,7 +668,8 @@ getxattr(struct user_namespace *mnt_user + if (error > 0) { + if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) || + (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0)) +- posix_acl_fix_xattr_to_user(mnt_userns, kvalue, error); ++ posix_acl_fix_xattr_to_user(mnt_userns, d_inode(d), ++ kvalue, error); + if (size && copy_to_user(value, kvalue, error)) + error = -EFAULT; + } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) { +--- a/include/linux/posix_acl_xattr.h ++++ b/include/linux/posix_acl_xattr.h +@@ -34,15 +34,19 @@ posix_acl_xattr_count(size_t size) + + #ifdef CONFIG_FS_POSIX_ACL + void posix_acl_fix_xattr_from_user(struct user_namespace *mnt_userns, ++ struct inode *inode, + void *value, size_t size); + void posix_acl_fix_xattr_to_user(struct user_namespace *mnt_userns, ++ struct inode *inode, + void *value, size_t size); + #else + static inline void posix_acl_fix_xattr_from_user(struct user_namespace *mnt_userns, ++ struct inode *inode, + void *value, size_t size) + { + } + static inline void posix_acl_fix_xattr_to_user(struct user_namespace *mnt_userns, ++ struct inode *inode, + void *value, size_t size) + { + } diff --git a/queue-5.15/fs-move-mapping-helpers.patch b/queue-5.15/fs-move-mapping-helpers.patch new file mode 100644 index 00000000000..893e50dc27d --- /dev/null +++ b/queue-5.15/fs-move-mapping-helpers.patch @@ -0,0 +1,322 @@ +From foo@baz Thu Jun 30 01:35:30 PM CEST 2022 +From: Christian Brauner +Date: Tue, 28 Jun 2022 14:16:10 +0200 +Subject: fs: move mapping helpers +To: Greg KH +Cc: Christian Brauner , stable@vger.kernel.org +Message-ID: <20220628121620.188722-3-brauner@kernel.org> + +From: Christian Brauner + +commit a793d79ea3e041081cd7cbd8ee43d0b5e4914a2b upstream. + +The low-level mapping helpers were so far crammed into fs.h. They are +out of place there. The fs.h header should just contain the higher-level +mapping helpers that interact directly with vfs objects such as struct +super_block or struct inode and not the bare mapping helpers. Similarly, +only vfs and specific fs code shall interact with low-level mapping +helpers. And so they won't be made accessible automatically through +regular {g,u}id helpers. + +Link: https://lore.kernel.org/r/20211123114227.3124056-3-brauner@kernel.org (v1) +Link: https://lore.kernel.org/r/20211130121032.3753852-3-brauner@kernel.org (v2) +Link: https://lore.kernel.org/r/20211203111707.3901969-3-brauner@kernel.org +Cc: Seth Forshee +Cc: Christoph Hellwig +Cc: Al Viro +CC: linux-fsdevel@vger.kernel.org +Reviewed-by: Amir Goldstein +Reviewed-by: Seth Forshee +Signed-off-by: Christian Brauner +Signed-off-by: Christian Brauner (Microsoft) +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smbacl.c | 1 + fs/ksmbd/smbacl.h | 1 + fs/open.c | 1 + fs/posix_acl.c | 1 + fs/xfs/xfs_linux.h | 1 + include/linux/fs.h | 91 ------------------------------------- + include/linux/mnt_idmapping.h | 101 ++++++++++++++++++++++++++++++++++++++++++ + security/commoncap.c | 1 + 8 files changed, 108 insertions(+), 90 deletions(-) + create mode 100644 include/linux/mnt_idmapping.h + +--- a/fs/ksmbd/smbacl.c ++++ b/fs/ksmbd/smbacl.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + + #include "smbacl.h" + #include "smb_common.h" +--- a/fs/ksmbd/smbacl.h ++++ b/fs/ksmbd/smbacl.h +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + #include "mgmt/tree_connect.h" + +--- a/fs/open.c ++++ b/fs/open.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + #include "internal.h" + +--- a/fs/posix_acl.c ++++ b/fs/posix_acl.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + static struct posix_acl **acl_by_type(struct inode *inode, int type) + { +--- a/fs/xfs/xfs_linux.h ++++ b/fs/xfs/xfs_linux.h +@@ -61,6 +61,7 @@ typedef __u32 xfs_nlink_t; + #include + #include + #include ++#include + + #include + #include +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -41,6 +41,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -1627,34 +1628,6 @@ static inline void i_gid_write(struct in + } + + /** +- * kuid_into_mnt - map a kuid down into a mnt_userns +- * @mnt_userns: user namespace of the relevant mount +- * @kuid: kuid to be mapped +- * +- * Return: @kuid mapped according to @mnt_userns. +- * If @kuid has no mapping INVALID_UID is returned. +- */ +-static inline kuid_t kuid_into_mnt(struct user_namespace *mnt_userns, +- kuid_t kuid) +-{ +- return make_kuid(mnt_userns, __kuid_val(kuid)); +-} +- +-/** +- * kgid_into_mnt - map a kgid down into a mnt_userns +- * @mnt_userns: user namespace of the relevant mount +- * @kgid: kgid to be mapped +- * +- * Return: @kgid mapped according to @mnt_userns. +- * If @kgid has no mapping INVALID_GID is returned. +- */ +-static inline kgid_t kgid_into_mnt(struct user_namespace *mnt_userns, +- kgid_t kgid) +-{ +- return make_kgid(mnt_userns, __kgid_val(kgid)); +-} +- +-/** + * i_uid_into_mnt - map an inode's i_uid down into a mnt_userns + * @mnt_userns: user namespace of the mount the inode was found from + * @inode: inode to map +@@ -1683,68 +1656,6 @@ static inline kgid_t i_gid_into_mnt(stru + } + + /** +- * kuid_from_mnt - map a kuid up into a mnt_userns +- * @mnt_userns: user namespace of the relevant mount +- * @kuid: kuid to be mapped +- * +- * Return: @kuid mapped up according to @mnt_userns. +- * If @kuid has no mapping INVALID_UID is returned. +- */ +-static inline kuid_t kuid_from_mnt(struct user_namespace *mnt_userns, +- kuid_t kuid) +-{ +- return KUIDT_INIT(from_kuid(mnt_userns, kuid)); +-} +- +-/** +- * kgid_from_mnt - map a kgid up into a mnt_userns +- * @mnt_userns: user namespace of the relevant mount +- * @kgid: kgid to be mapped +- * +- * Return: @kgid mapped up according to @mnt_userns. +- * If @kgid has no mapping INVALID_GID is returned. +- */ +-static inline kgid_t kgid_from_mnt(struct user_namespace *mnt_userns, +- kgid_t kgid) +-{ +- return KGIDT_INIT(from_kgid(mnt_userns, kgid)); +-} +- +-/** +- * mapped_fsuid - return caller's fsuid mapped up into a mnt_userns +- * @mnt_userns: user namespace of the relevant mount +- * +- * Use this helper to initialize a new vfs or filesystem object based on +- * the caller's fsuid. A common example is initializing the i_uid field of +- * a newly allocated inode triggered by a creation event such as mkdir or +- * O_CREAT. Other examples include the allocation of quotas for a specific +- * user. +- * +- * Return: the caller's current fsuid mapped up according to @mnt_userns. +- */ +-static inline kuid_t mapped_fsuid(struct user_namespace *mnt_userns) +-{ +- return kuid_from_mnt(mnt_userns, current_fsuid()); +-} +- +-/** +- * mapped_fsgid - return caller's fsgid mapped up into a mnt_userns +- * @mnt_userns: user namespace of the relevant mount +- * +- * Use this helper to initialize a new vfs or filesystem object based on +- * the caller's fsgid. A common example is initializing the i_gid field of +- * a newly allocated inode triggered by a creation event such as mkdir or +- * O_CREAT. Other examples include the allocation of quotas for a specific +- * user. +- * +- * Return: the caller's current fsgid mapped up according to @mnt_userns. +- */ +-static inline kgid_t mapped_fsgid(struct user_namespace *mnt_userns) +-{ +- return kgid_from_mnt(mnt_userns, current_fsgid()); +-} +- +-/** + * inode_fsuid_set - initialize inode's i_uid field with callers fsuid + * @inode: inode to initialize + * @mnt_userns: user namespace of the mount the inode was found from +--- /dev/null ++++ b/include/linux/mnt_idmapping.h +@@ -0,0 +1,101 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef _LINUX_MNT_IDMAPPING_H ++#define _LINUX_MNT_IDMAPPING_H ++ ++#include ++#include ++ ++struct user_namespace; ++extern struct user_namespace init_user_ns; ++ ++/** ++ * kuid_into_mnt - map a kuid down into a mnt_userns ++ * @mnt_userns: user namespace of the relevant mount ++ * @kuid: kuid to be mapped ++ * ++ * Return: @kuid mapped according to @mnt_userns. ++ * If @kuid has no mapping INVALID_UID is returned. ++ */ ++static inline kuid_t kuid_into_mnt(struct user_namespace *mnt_userns, ++ kuid_t kuid) ++{ ++ return make_kuid(mnt_userns, __kuid_val(kuid)); ++} ++ ++/** ++ * kgid_into_mnt - map a kgid down into a mnt_userns ++ * @mnt_userns: user namespace of the relevant mount ++ * @kgid: kgid to be mapped ++ * ++ * Return: @kgid mapped according to @mnt_userns. ++ * If @kgid has no mapping INVALID_GID is returned. ++ */ ++static inline kgid_t kgid_into_mnt(struct user_namespace *mnt_userns, ++ kgid_t kgid) ++{ ++ return make_kgid(mnt_userns, __kgid_val(kgid)); ++} ++ ++/** ++ * kuid_from_mnt - map a kuid up into a mnt_userns ++ * @mnt_userns: user namespace of the relevant mount ++ * @kuid: kuid to be mapped ++ * ++ * Return: @kuid mapped up according to @mnt_userns. ++ * If @kuid has no mapping INVALID_UID is returned. ++ */ ++static inline kuid_t kuid_from_mnt(struct user_namespace *mnt_userns, ++ kuid_t kuid) ++{ ++ return KUIDT_INIT(from_kuid(mnt_userns, kuid)); ++} ++ ++/** ++ * kgid_from_mnt - map a kgid up into a mnt_userns ++ * @mnt_userns: user namespace of the relevant mount ++ * @kgid: kgid to be mapped ++ * ++ * Return: @kgid mapped up according to @mnt_userns. ++ * If @kgid has no mapping INVALID_GID is returned. ++ */ ++static inline kgid_t kgid_from_mnt(struct user_namespace *mnt_userns, ++ kgid_t kgid) ++{ ++ return KGIDT_INIT(from_kgid(mnt_userns, kgid)); ++} ++ ++/** ++ * mapped_fsuid - return caller's fsuid mapped up into a mnt_userns ++ * @mnt_userns: user namespace of the relevant mount ++ * ++ * Use this helper to initialize a new vfs or filesystem object based on ++ * the caller's fsuid. A common example is initializing the i_uid field of ++ * a newly allocated inode triggered by a creation event such as mkdir or ++ * O_CREAT. Other examples include the allocation of quotas for a specific ++ * user. ++ * ++ * Return: the caller's current fsuid mapped up according to @mnt_userns. ++ */ ++static inline kuid_t mapped_fsuid(struct user_namespace *mnt_userns) ++{ ++ return kuid_from_mnt(mnt_userns, current_fsuid()); ++} ++ ++/** ++ * mapped_fsgid - return caller's fsgid mapped up into a mnt_userns ++ * @mnt_userns: user namespace of the relevant mount ++ * ++ * Use this helper to initialize a new vfs or filesystem object based on ++ * the caller's fsgid. A common example is initializing the i_gid field of ++ * a newly allocated inode triggered by a creation event such as mkdir or ++ * O_CREAT. Other examples include the allocation of quotas for a specific ++ * user. ++ * ++ * Return: the caller's current fsgid mapped up according to @mnt_userns. ++ */ ++static inline kgid_t mapped_fsgid(struct user_namespace *mnt_userns) ++{ ++ return kgid_from_mnt(mnt_userns, current_fsgid()); ++} ++ ++#endif /* _LINUX_MNT_IDMAPPING_H */ +--- a/security/commoncap.c ++++ b/security/commoncap.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + /* + * If a non-root user executes a setuid-root binary in diff --git a/queue-5.15/fs-port-higher-level-mapping-helpers.patch b/queue-5.15/fs-port-higher-level-mapping-helpers.patch new file mode 100644 index 00000000000..ac97f0ed24e --- /dev/null +++ b/queue-5.15/fs-port-higher-level-mapping-helpers.patch @@ -0,0 +1,153 @@ +From foo@baz Thu Jun 30 01:35:30 PM CEST 2022 +From: Christian Brauner +Date: Tue, 28 Jun 2022 14:16:16 +0200 +Subject: fs: port higher-level mapping helpers +To: Greg KH +Cc: Christian Brauner , stable@vger.kernel.org +Message-ID: <20220628121620.188722-9-brauner@kernel.org> + +From: Christian Brauner + +commit 209188ce75d0d357c292f6bb81d712acdd4e7db7 upstream. + +Enable the mapped_fs{g,u}id() helpers to support filesystems mounted +with an idmapping. Apart from core mapping helpers that use +mapped_fs{g,u}id() to initialize struct inode's i_{g,u}id fields xfs is +the only place that uses these low-level helpers directly. + +The patch only extends the helpers to be able to take the filesystem +idmapping into account. Since we don't actually yet pass the +filesystem's idmapping in no functional changes happen. This will happen +in a final patch. + +Link: https://lore.kernel.org/r/20211123114227.3124056-9-brauner@kernel.org (v1) +Link: https://lore.kernel.org/r/20211130121032.3753852-9-brauner@kernel.org (v2) +Link: https://lore.kernel.org/r/20211203111707.3901969-9-brauner@kernel.org +Cc: Seth Forshee +Cc: Christoph Hellwig +Cc: Al Viro +CC: linux-fsdevel@vger.kernel.org +Reviewed-by: Amir Goldstein +Reviewed-by: Seth Forshee +Signed-off-by: Christian Brauner +Signed-off-by: Christian Brauner (Microsoft) +Signed-off-by: Greg Kroah-Hartman +--- + fs/xfs/xfs_inode.c | 8 ++++---- + fs/xfs/xfs_symlink.c | 4 ++-- + include/linux/fs.h | 8 ++++---- + include/linux/mnt_idmapping.h | 12 ++++++++---- + 4 files changed, 18 insertions(+), 14 deletions(-) + +--- a/fs/xfs/xfs_inode.c ++++ b/fs/xfs/xfs_inode.c +@@ -994,8 +994,8 @@ xfs_create( + /* + * Make sure that we have allocated dquot(s) on disk. + */ +- error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns), +- mapped_fsgid(mnt_userns), prid, ++ error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns, &init_user_ns), ++ mapped_fsgid(mnt_userns, &init_user_ns), prid, + XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, + &udqp, &gdqp, &pdqp); + if (error) +@@ -1148,8 +1148,8 @@ xfs_create_tmpfile( + /* + * Make sure that we have allocated dquot(s) on disk. + */ +- error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns), +- mapped_fsgid(mnt_userns), prid, ++ error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns, &init_user_ns), ++ mapped_fsgid(mnt_userns, &init_user_ns), prid, + XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, + &udqp, &gdqp, &pdqp); + if (error) +--- a/fs/xfs/xfs_symlink.c ++++ b/fs/xfs/xfs_symlink.c +@@ -184,8 +184,8 @@ xfs_symlink( + /* + * Make sure that we have allocated dquot(s) on disk. + */ +- error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns), +- mapped_fsgid(mnt_userns), prid, ++ error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns, &init_user_ns), ++ mapped_fsgid(mnt_userns, &init_user_ns), prid, + XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, + &udqp, &gdqp, &pdqp); + if (error) +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -1666,7 +1666,7 @@ static inline kgid_t i_gid_into_mnt(stru + static inline void inode_fsuid_set(struct inode *inode, + struct user_namespace *mnt_userns) + { +- inode->i_uid = mapped_fsuid(mnt_userns); ++ inode->i_uid = mapped_fsuid(mnt_userns, &init_user_ns); + } + + /** +@@ -1680,7 +1680,7 @@ static inline void inode_fsuid_set(struc + static inline void inode_fsgid_set(struct inode *inode, + struct user_namespace *mnt_userns) + { +- inode->i_gid = mapped_fsgid(mnt_userns); ++ inode->i_gid = mapped_fsgid(mnt_userns, &init_user_ns); + } + + /** +@@ -1701,10 +1701,10 @@ static inline bool fsuidgid_has_mapping( + kuid_t kuid; + kgid_t kgid; + +- kuid = mapped_fsuid(mnt_userns); ++ kuid = mapped_fsuid(mnt_userns, &init_user_ns); + if (!uid_valid(kuid)) + return false; +- kgid = mapped_fsgid(mnt_userns); ++ kgid = mapped_fsgid(mnt_userns, &init_user_ns); + if (!gid_valid(kgid)) + return false; + return kuid_has_mapping(fs_userns, kuid) && +--- a/include/linux/mnt_idmapping.h ++++ b/include/linux/mnt_idmapping.h +@@ -196,6 +196,7 @@ static inline kgid_t mapped_kgid_user(st + /** + * mapped_fsuid - return caller's fsuid mapped up into a mnt_userns + * @mnt_userns: the mount's idmapping ++ * @fs_userns: the filesystem's idmapping + * + * Use this helper to initialize a new vfs or filesystem object based on + * the caller's fsuid. A common example is initializing the i_uid field of +@@ -205,14 +206,16 @@ static inline kgid_t mapped_kgid_user(st + * + * Return: the caller's current fsuid mapped up according to @mnt_userns. + */ +-static inline kuid_t mapped_fsuid(struct user_namespace *mnt_userns) ++static inline kuid_t mapped_fsuid(struct user_namespace *mnt_userns, ++ struct user_namespace *fs_userns) + { +- return mapped_kuid_user(mnt_userns, &init_user_ns, current_fsuid()); ++ return mapped_kuid_user(mnt_userns, fs_userns, current_fsuid()); + } + + /** + * mapped_fsgid - return caller's fsgid mapped up into a mnt_userns + * @mnt_userns: the mount's idmapping ++ * @fs_userns: the filesystem's idmapping + * + * Use this helper to initialize a new vfs or filesystem object based on + * the caller's fsgid. A common example is initializing the i_gid field of +@@ -222,9 +225,10 @@ static inline kuid_t mapped_fsuid(struct + * + * Return: the caller's current fsgid mapped up according to @mnt_userns. + */ +-static inline kgid_t mapped_fsgid(struct user_namespace *mnt_userns) ++static inline kgid_t mapped_fsgid(struct user_namespace *mnt_userns, ++ struct user_namespace *fs_userns) + { +- return mapped_kgid_user(mnt_userns, &init_user_ns, current_fsgid()); ++ return mapped_kgid_user(mnt_userns, fs_userns, current_fsgid()); + } + + #endif /* _LINUX_MNT_IDMAPPING_H */ diff --git a/queue-5.15/fs-remove-unused-low-level-mapping-helpers.patch b/queue-5.15/fs-remove-unused-low-level-mapping-helpers.patch new file mode 100644 index 00000000000..a8b1f4c836a --- /dev/null +++ b/queue-5.15/fs-remove-unused-low-level-mapping-helpers.patch @@ -0,0 +1,99 @@ +From foo@baz Thu Jun 30 01:35:30 PM CEST 2022 +From: Christian Brauner +Date: Tue, 28 Jun 2022 14:16:15 +0200 +Subject: fs: remove unused low-level mapping helpers +To: Greg KH +Cc: Christian Brauner , stable@vger.kernel.org +Message-ID: <20220628121620.188722-8-brauner@kernel.org> + +From: Christian Brauner + +commit 02e4079913500f24ceb082d8d87d8665f044b298 upstream. + +Now that we ported all places to use the new low-level mapping helpers +that are able to support filesystems mounted with an idmapping we can +remove the old low-level mapping helpers. With the removal of these old +helpers we also conclude the renaming of the mapping helpers we started +in commit a65e58e791a1 ("fs: document and rename fsid helpers"). + +Link: https://lore.kernel.org/r/20211123114227.3124056-8-brauner@kernel.org (v1) +Link: https://lore.kernel.org/r/20211130121032.3753852-8-brauner@kernel.org (v2) +Link: https://lore.kernel.org/r/20211203111707.3901969-8-brauner@kernel.org +Cc: Seth Forshee +Cc: Christoph Hellwig +Cc: Al Viro +CC: linux-fsdevel@vger.kernel.org +Reviewed-by: Amir Goldstein +Reviewed-by: Seth Forshee +Signed-off-by: Christian Brauner +Signed-off-by: Christian Brauner (Microsoft) +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/mnt_idmapping.h | 56 ------------------------------------------ + 1 file changed, 56 deletions(-) + +--- a/include/linux/mnt_idmapping.h ++++ b/include/linux/mnt_idmapping.h +@@ -14,62 +14,6 @@ struct user_namespace; + extern struct user_namespace init_user_ns; + + /** +- * kuid_into_mnt - map a kuid down into a mnt_userns +- * @mnt_userns: user namespace of the relevant mount +- * @kuid: kuid to be mapped +- * +- * Return: @kuid mapped according to @mnt_userns. +- * If @kuid has no mapping INVALID_UID is returned. +- */ +-static inline kuid_t kuid_into_mnt(struct user_namespace *mnt_userns, +- kuid_t kuid) +-{ +- return make_kuid(mnt_userns, __kuid_val(kuid)); +-} +- +-/** +- * kgid_into_mnt - map a kgid down into a mnt_userns +- * @mnt_userns: user namespace of the relevant mount +- * @kgid: kgid to be mapped +- * +- * Return: @kgid mapped according to @mnt_userns. +- * If @kgid has no mapping INVALID_GID is returned. +- */ +-static inline kgid_t kgid_into_mnt(struct user_namespace *mnt_userns, +- kgid_t kgid) +-{ +- return make_kgid(mnt_userns, __kgid_val(kgid)); +-} +- +-/** +- * kuid_from_mnt - map a kuid up into a mnt_userns +- * @mnt_userns: user namespace of the relevant mount +- * @kuid: kuid to be mapped +- * +- * Return: @kuid mapped up according to @mnt_userns. +- * If @kuid has no mapping INVALID_UID is returned. +- */ +-static inline kuid_t kuid_from_mnt(struct user_namespace *mnt_userns, +- kuid_t kuid) +-{ +- return KUIDT_INIT(from_kuid(mnt_userns, kuid)); +-} +- +-/** +- * kgid_from_mnt - map a kgid up into a mnt_userns +- * @mnt_userns: user namespace of the relevant mount +- * @kgid: kgid to be mapped +- * +- * Return: @kgid mapped up according to @mnt_userns. +- * If @kgid has no mapping INVALID_GID is returned. +- */ +-static inline kgid_t kgid_from_mnt(struct user_namespace *mnt_userns, +- kgid_t kgid) +-{ +- return KGIDT_INIT(from_kgid(mnt_userns, kgid)); +-} +- +-/** + * initial_idmapping - check whether this is the initial mapping + * @ns: idmapping to check + * diff --git a/queue-5.15/fs-support-mapped-mounts-of-mapped-filesystems.patch b/queue-5.15/fs-support-mapped-mounts-of-mapped-filesystems.patch new file mode 100644 index 00000000000..610b28fae22 --- /dev/null +++ b/queue-5.15/fs-support-mapped-mounts-of-mapped-filesystems.patch @@ -0,0 +1,345 @@ +From foo@baz Thu Jun 30 01:35:30 PM CEST 2022 +From: Christian Brauner +Date: Tue, 28 Jun 2022 14:16:18 +0200 +Subject: fs: support mapped mounts of mapped filesystems +To: Greg KH +Cc: Christian Brauner , stable@vger.kernel.org +Message-ID: <20220628121620.188722-11-brauner@kernel.org> + +From: Christian Brauner + +commit bd303368b776eead1c29e6cdda82bde7128b82a7 upstream. + +In previous patches we added new and modified existing helpers to handle +idmapped mounts of filesystems mounted with an idmapping. In this final +patch we convert all relevant places in the vfs to actually pass the +filesystem's idmapping into these helpers. + +With this the vfs is in shape to handle idmapped mounts of filesystems +mounted with an idmapping. Note that this is just the generic +infrastructure. Actually adding support for idmapped mounts to a +filesystem mountable with an idmapping is follow-up work. + +In this patch we extend the definition of an idmapped mount from a mount +that that has the initial idmapping attached to it to a mount that has +an idmapping attached to it which is not the same as the idmapping the +filesystem was mounted with. + +As before we do not allow the initial idmapping to be attached to a +mount. In addition this patch prevents that the idmapping the filesystem +was mounted with can be attached to a mount created based on this +filesystem. + +This has multiple reasons and advantages. First, attaching the initial +idmapping or the filesystem's idmapping doesn't make much sense as in +both cases the values of the i_{g,u}id and other places where k{g,u}ids +are used do not change. Second, a user that really wants to do this for +whatever reason can just create a separate dedicated identical idmapping +to attach to the mount. Third, we can continue to use the initial +idmapping as an indicator that a mount is not idmapped allowing us to +continue to keep passing the initial idmapping into the mapping helpers +to tell them that something isn't an idmapped mount even if the +filesystem is mounted with an idmapping. + +Link: https://lore.kernel.org/r/20211123114227.3124056-11-brauner@kernel.org (v1) +Link: https://lore.kernel.org/r/20211130121032.3753852-11-brauner@kernel.org (v2) +Link: https://lore.kernel.org/r/20211203111707.3901969-11-brauner@kernel.org +Cc: Seth Forshee +Cc: Amir Goldstein +Cc: Christoph Hellwig +Cc: Al Viro +CC: linux-fsdevel@vger.kernel.org +Reviewed-by: Seth Forshee +Signed-off-by: Christian Brauner +Signed-off-by: Christian Brauner (Microsoft) +Signed-off-by: Greg Kroah-Hartman +--- + fs/namespace.c | 51 ++++++++++++++++++++++++++++++++++++++------------- + fs/open.c | 7 ++++--- + fs/posix_acl.c | 8 ++++---- + include/linux/fs.h | 17 +++++++++-------- + security/commoncap.c | 9 ++++----- + 5 files changed, 59 insertions(+), 33 deletions(-) + +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + + #include "pnode.h" + #include "internal.h" +@@ -561,7 +562,7 @@ static void free_vfsmnt(struct mount *mn + struct user_namespace *mnt_userns; + + mnt_userns = mnt_user_ns(&mnt->mnt); +- if (mnt_userns != &init_user_ns) ++ if (!initial_idmapping(mnt_userns)) + put_user_ns(mnt_userns); + kfree_const(mnt->mnt_devname); + #ifdef CONFIG_SMP +@@ -965,6 +966,7 @@ static struct mount *skip_mnt_tree(struc + struct vfsmount *vfs_create_mount(struct fs_context *fc) + { + struct mount *mnt; ++ struct user_namespace *fs_userns; + + if (!fc->root) + return ERR_PTR(-EINVAL); +@@ -982,6 +984,10 @@ struct vfsmount *vfs_create_mount(struct + mnt->mnt_mountpoint = mnt->mnt.mnt_root; + mnt->mnt_parent = mnt; + ++ fs_userns = mnt->mnt.mnt_sb->s_user_ns; ++ if (!initial_idmapping(fs_userns)) ++ mnt->mnt.mnt_userns = get_user_ns(fs_userns); ++ + lock_mount_hash(); + list_add_tail(&mnt->mnt_instance, &mnt->mnt.mnt_sb->s_mounts); + unlock_mount_hash(); +@@ -1072,7 +1078,7 @@ static struct mount *clone_mnt(struct mo + + atomic_inc(&sb->s_active); + mnt->mnt.mnt_userns = mnt_user_ns(&old->mnt); +- if (mnt->mnt.mnt_userns != &init_user_ns) ++ if (!initial_idmapping(mnt->mnt.mnt_userns)) + mnt->mnt.mnt_userns = get_user_ns(mnt->mnt.mnt_userns); + mnt->mnt.mnt_sb = sb; + mnt->mnt.mnt_root = dget(root); +@@ -3927,11 +3933,19 @@ static unsigned int recalc_flags(struct + static int can_idmap_mount(const struct mount_kattr *kattr, struct mount *mnt) + { + struct vfsmount *m = &mnt->mnt; ++ struct user_namespace *fs_userns = m->mnt_sb->s_user_ns; + + if (!kattr->mnt_userns) + return 0; + + /* ++ * Creating an idmapped mount with the filesystem wide idmapping ++ * doesn't make sense so block that. We don't allow mushy semantics. ++ */ ++ if (kattr->mnt_userns == fs_userns) ++ return -EINVAL; ++ ++ /* + * Once a mount has been idmapped we don't allow it to change its + * mapping. It makes things simpler and callers can just create + * another bind-mount they can idmap if they want to. +@@ -3943,12 +3957,8 @@ static int can_idmap_mount(const struct + if (!(m->mnt_sb->s_type->fs_flags & FS_ALLOW_IDMAP)) + return -EINVAL; + +- /* Don't yet support filesystem mountable in user namespaces. */ +- if (m->mnt_sb->s_user_ns != &init_user_ns) +- return -EINVAL; +- + /* We're not controlling the superblock. */ +- if (!capable(CAP_SYS_ADMIN)) ++ if (!ns_capable(fs_userns, CAP_SYS_ADMIN)) + return -EPERM; + + /* Mount has already been visible in the filesystem hierarchy. */ +@@ -4002,14 +4012,27 @@ out: + + static void do_idmap_mount(const struct mount_kattr *kattr, struct mount *mnt) + { +- struct user_namespace *mnt_userns; ++ struct user_namespace *mnt_userns, *old_mnt_userns; + + if (!kattr->mnt_userns) + return; + ++ /* ++ * We're the only ones able to change the mount's idmapping. So ++ * mnt->mnt.mnt_userns is stable and we can retrieve it directly. ++ */ ++ old_mnt_userns = mnt->mnt.mnt_userns; ++ + mnt_userns = get_user_ns(kattr->mnt_userns); + /* Pairs with smp_load_acquire() in mnt_user_ns(). */ + smp_store_release(&mnt->mnt.mnt_userns, mnt_userns); ++ ++ /* ++ * If this is an idmapped filesystem drop the reference we've taken ++ * in vfs_create_mount() before. ++ */ ++ if (!initial_idmapping(old_mnt_userns)) ++ put_user_ns(old_mnt_userns); + } + + static void mount_setattr_commit(struct mount_kattr *kattr, +@@ -4133,13 +4156,15 @@ static int build_mount_idmapped(const st + } + + /* +- * The init_user_ns is used to indicate that a vfsmount is not idmapped. +- * This is simpler than just having to treat NULL as unmapped. Users +- * wanting to idmap a mount to init_user_ns can just use a namespace +- * with an identity mapping. ++ * The initial idmapping cannot be used to create an idmapped ++ * mount. We use the initial idmapping as an indicator of a mount ++ * that is not idmapped. It can simply be passed into helpers that ++ * are aware of idmapped mounts as a convenient shortcut. A user ++ * can just create a dedicated identity mapping to achieve the same ++ * result. + */ + mnt_userns = container_of(ns, struct user_namespace, ns); +- if (mnt_userns == &init_user_ns) { ++ if (initial_idmapping(mnt_userns)) { + err = -EPERM; + goto out_fput; + } +--- a/fs/open.c ++++ b/fs/open.c +@@ -641,7 +641,7 @@ SYSCALL_DEFINE2(chmod, const char __user + + int chown_common(const struct path *path, uid_t user, gid_t group) + { +- struct user_namespace *mnt_userns; ++ struct user_namespace *mnt_userns, *fs_userns; + struct inode *inode = path->dentry->d_inode; + struct inode *delegated_inode = NULL; + int error; +@@ -653,8 +653,9 @@ int chown_common(const struct path *path + gid = make_kgid(current_user_ns(), group); + + mnt_userns = mnt_user_ns(path->mnt); +- uid = mapped_kuid_user(mnt_userns, &init_user_ns, uid); +- gid = mapped_kgid_user(mnt_userns, &init_user_ns, gid); ++ fs_userns = i_user_ns(inode); ++ uid = mapped_kuid_user(mnt_userns, fs_userns, uid); ++ gid = mapped_kgid_user(mnt_userns, fs_userns, gid); + + retry_deleg: + newattrs.ia_valid = ATTR_CTIME; +--- a/fs/posix_acl.c ++++ b/fs/posix_acl.c +@@ -377,8 +377,8 @@ posix_acl_permission(struct user_namespa + break; + case ACL_USER: + uid = mapped_kuid_fs(mnt_userns, +- &init_user_ns, +- pa->e_uid); ++ i_user_ns(inode), ++ pa->e_uid); + if (uid_eq(uid, current_fsuid())) + goto mask; + break; +@@ -392,8 +392,8 @@ posix_acl_permission(struct user_namespa + break; + case ACL_GROUP: + gid = mapped_kgid_fs(mnt_userns, +- &init_user_ns, +- pa->e_gid); ++ i_user_ns(inode), ++ pa->e_gid); + if (in_group_p(gid)) { + found = 1; + if ((pa->e_perm & want) == want) +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -1643,7 +1643,7 @@ static inline void i_gid_write(struct in + static inline kuid_t i_uid_into_mnt(struct user_namespace *mnt_userns, + const struct inode *inode) + { +- return mapped_kuid_fs(mnt_userns, &init_user_ns, inode->i_uid); ++ return mapped_kuid_fs(mnt_userns, i_user_ns(inode), inode->i_uid); + } + + /** +@@ -1657,7 +1657,7 @@ static inline kuid_t i_uid_into_mnt(stru + static inline kgid_t i_gid_into_mnt(struct user_namespace *mnt_userns, + const struct inode *inode) + { +- return mapped_kgid_fs(mnt_userns, &init_user_ns, inode->i_gid); ++ return mapped_kgid_fs(mnt_userns, i_user_ns(inode), inode->i_gid); + } + + /** +@@ -1671,7 +1671,7 @@ static inline kgid_t i_gid_into_mnt(stru + static inline void inode_fsuid_set(struct inode *inode, + struct user_namespace *mnt_userns) + { +- inode->i_uid = mapped_fsuid(mnt_userns, &init_user_ns); ++ inode->i_uid = mapped_fsuid(mnt_userns, i_user_ns(inode)); + } + + /** +@@ -1685,7 +1685,7 @@ static inline void inode_fsuid_set(struc + static inline void inode_fsgid_set(struct inode *inode, + struct user_namespace *mnt_userns) + { +- inode->i_gid = mapped_fsgid(mnt_userns, &init_user_ns); ++ inode->i_gid = mapped_fsgid(mnt_userns, i_user_ns(inode)); + } + + /** +@@ -1706,10 +1706,10 @@ static inline bool fsuidgid_has_mapping( + kuid_t kuid; + kgid_t kgid; + +- kuid = mapped_fsuid(mnt_userns, &init_user_ns); ++ kuid = mapped_fsuid(mnt_userns, fs_userns); + if (!uid_valid(kuid)) + return false; +- kgid = mapped_fsgid(mnt_userns, &init_user_ns); ++ kgid = mapped_fsgid(mnt_userns, fs_userns); + if (!gid_valid(kgid)) + return false; + return kuid_has_mapping(fs_userns, kuid) && +@@ -2655,13 +2655,14 @@ static inline struct user_namespace *fil + * is_idmapped_mnt - check whether a mount is mapped + * @mnt: the mount to check + * +- * If @mnt has an idmapping attached to it @mnt is mapped. ++ * If @mnt has an idmapping attached different from the ++ * filesystem's idmapping then @mnt is mapped. + * + * Return: true if mount is mapped, false if not. + */ + static inline bool is_idmapped_mnt(const struct vfsmount *mnt) + { +- return mnt_user_ns(mnt) != &init_user_ns; ++ return mnt_user_ns(mnt) != mnt->mnt_sb->s_user_ns; + } + + extern long vfs_truncate(const struct path *, loff_t); +--- a/security/commoncap.c ++++ b/security/commoncap.c +@@ -419,7 +419,7 @@ int cap_inode_getsecurity(struct user_na + kroot = make_kuid(fs_ns, root); + + /* If this is an idmapped mount shift the kuid. */ +- kroot = mapped_kuid_fs(mnt_userns, &init_user_ns, kroot); ++ kroot = mapped_kuid_fs(mnt_userns, fs_ns, kroot); + + /* If the root kuid maps to a valid uid in current ns, then return + * this as a nscap. */ +@@ -556,13 +556,12 @@ int cap_convert_nscap(struct user_namesp + return -EINVAL; + if (!capable_wrt_inode_uidgid(mnt_userns, inode, CAP_SETFCAP)) + return -EPERM; +- if (size == XATTR_CAPS_SZ_2 && (mnt_userns == &init_user_ns)) ++ if (size == XATTR_CAPS_SZ_2 && (mnt_userns == fs_ns)) + if (ns_capable(inode->i_sb->s_user_ns, CAP_SETFCAP)) + /* user is privileged, just write the v2 */ + return size; + +- rootid = rootid_from_xattr(*ivalue, size, task_ns, mnt_userns, +- &init_user_ns); ++ rootid = rootid_from_xattr(*ivalue, size, task_ns, mnt_userns, fs_ns); + if (!uid_valid(rootid)) + return -EINVAL; + +@@ -703,7 +702,7 @@ int get_vfs_caps_from_disk(struct user_n + /* Limit the caps to the mounter of the filesystem + * or the more limited uid specified in the xattr. + */ +- rootkuid = mapped_kuid_fs(mnt_userns, &init_user_ns, rootkuid); ++ rootkuid = mapped_kuid_fs(mnt_userns, fs_ns, rootkuid); + if (!rootid_owns_currentns(rootkuid)) + return -ENODATA; + diff --git a/queue-5.15/fs-tweak-fsuidgid_has_mapping.patch b/queue-5.15/fs-tweak-fsuidgid_has_mapping.patch new file mode 100644 index 00000000000..2f156cef8f3 --- /dev/null +++ b/queue-5.15/fs-tweak-fsuidgid_has_mapping.patch @@ -0,0 +1,58 @@ +From foo@baz Thu Jun 30 01:35:30 PM CEST 2022 +From: Christian Brauner +Date: Tue, 28 Jun 2022 14:16:11 +0200 +Subject: fs: tweak fsuidgid_has_mapping() +To: Greg KH +Cc: Christian Brauner , stable@vger.kernel.org +Message-ID: <20220628121620.188722-4-brauner@kernel.org> + +From: Christian Brauner + +commit 476860b3eb4a50958243158861d5340066df5af2 upstream. + +If the caller's fs{g,u}id aren't mapped in the mount's idmapping we can +return early and skip the check whether the mapped fs{g,u}id also have a +mapping in the filesystem's idmapping. If the fs{g,u}id aren't mapped in +the mount's idmapping they consequently can't be mapped in the +filesystem's idmapping. So there's no point in checking that. + +Link: https://lore.kernel.org/r/20211123114227.3124056-4-brauner@kernel.org (v1) +Link: https://lore.kernel.org/r/20211130121032.3753852-4-brauner@kernel.org (v2) +Link: https://lore.kernel.org/r/20211203111707.3901969-4-brauner@kernel.org +Cc: Seth Forshee +Cc: Christoph Hellwig +Cc: Al Viro +CC: linux-fsdevel@vger.kernel.org +Reviewed-by: Amir Goldstein +Reviewed-by: Seth Forshee +Signed-off-by: Christian Brauner +Signed-off-by: Christian Brauner (Microsoft) +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/fs.h | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -1697,10 +1697,18 @@ static inline void inode_fsgid_set(struc + static inline bool fsuidgid_has_mapping(struct super_block *sb, + struct user_namespace *mnt_userns) + { +- struct user_namespace *s_user_ns = sb->s_user_ns; ++ struct user_namespace *fs_userns = sb->s_user_ns; ++ kuid_t kuid; ++ kgid_t kgid; + +- return kuid_has_mapping(s_user_ns, mapped_fsuid(mnt_userns)) && +- kgid_has_mapping(s_user_ns, mapped_fsgid(mnt_userns)); ++ kuid = mapped_fsuid(mnt_userns); ++ if (!uid_valid(kuid)) ++ return false; ++ kgid = mapped_fsgid(mnt_userns); ++ if (!gid_valid(kgid)) ++ return false; ++ return kuid_has_mapping(fs_userns, kuid) && ++ kgid_has_mapping(fs_userns, kgid); + } + + extern struct timespec64 current_time(struct inode *inode); diff --git a/queue-5.15/fs-use-low-level-mapping-helpers.patch b/queue-5.15/fs-use-low-level-mapping-helpers.patch new file mode 100644 index 00000000000..b7669fb26db --- /dev/null +++ b/queue-5.15/fs-use-low-level-mapping-helpers.patch @@ -0,0 +1,208 @@ +From foo@baz Thu Jun 30 01:35:30 PM CEST 2022 +From: Christian Brauner +Date: Tue, 28 Jun 2022 14:16:14 +0200 +Subject: fs: use low-level mapping helpers +To: Greg KH +Cc: Christian Brauner , stable@vger.kernel.org +Message-ID: <20220628121620.188722-7-brauner@kernel.org> + +From: Christian Brauner + +commit 4472071331549e911a5abad41aea6e3be855a1a4 upstream. + +In a few places the vfs needs to interact with bare k{g,u}ids directly +instead of struct inode. These are just a few. In previous patches we +introduced low-level mapping helpers that are able to support +filesystems mounted an idmapping. This patch simply converts the places +to use these new helpers. + +Link: https://lore.kernel.org/r/20211123114227.3124056-7-brauner@kernel.org (v1) +Link: https://lore.kernel.org/r/20211130121032.3753852-7-brauner@kernel.org (v2) +Link: https://lore.kernel.org/r/20211203111707.3901969-7-brauner@kernel.org +Cc: Seth Forshee +Cc: Amir Goldstein +Cc: Christoph Hellwig +Cc: Al Viro +CC: linux-fsdevel@vger.kernel.org +Reviewed-by: Seth Forshee +Signed-off-by: Christian Brauner +Signed-off-by: Christian Brauner (Microsoft) +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/smbacl.c | 18 ++---------------- + fs/ksmbd/smbacl.h | 4 ++-- + fs/open.c | 4 ++-- + fs/posix_acl.c | 16 ++++++++++------ + security/commoncap.c | 13 ++++++++----- + 5 files changed, 24 insertions(+), 31 deletions(-) + +--- a/fs/ksmbd/smbacl.c ++++ b/fs/ksmbd/smbacl.c +@@ -275,14 +275,7 @@ static int sid_to_id(struct user_namespa + uid_t id; + + id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]); +- /* +- * Translate raw sid into kuid in the server's user +- * namespace. +- */ +- uid = make_kuid(&init_user_ns, id); +- +- /* If this is an idmapped mount, apply the idmapping. */ +- uid = kuid_from_mnt(user_ns, uid); ++ uid = mapped_kuid_user(user_ns, &init_user_ns, KUIDT_INIT(id)); + if (uid_valid(uid)) { + fattr->cf_uid = uid; + rc = 0; +@@ -292,14 +285,7 @@ static int sid_to_id(struct user_namespa + gid_t id; + + id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]); +- /* +- * Translate raw sid into kgid in the server's user +- * namespace. +- */ +- gid = make_kgid(&init_user_ns, id); +- +- /* If this is an idmapped mount, apply the idmapping. */ +- gid = kgid_from_mnt(user_ns, gid); ++ gid = mapped_kgid_user(user_ns, &init_user_ns, KGIDT_INIT(id)); + if (gid_valid(gid)) { + fattr->cf_gid = gid; + rc = 0; +--- a/fs/ksmbd/smbacl.h ++++ b/fs/ksmbd/smbacl.h +@@ -217,7 +217,7 @@ static inline uid_t posix_acl_uid_transl + kuid_t kuid; + + /* If this is an idmapped mount, apply the idmapping. */ +- kuid = kuid_into_mnt(mnt_userns, pace->e_uid); ++ kuid = mapped_kuid_fs(mnt_userns, &init_user_ns, pace->e_uid); + + /* Translate the kuid into a userspace id ksmbd would see. */ + return from_kuid(&init_user_ns, kuid); +@@ -229,7 +229,7 @@ static inline gid_t posix_acl_gid_transl + kgid_t kgid; + + /* If this is an idmapped mount, apply the idmapping. */ +- kgid = kgid_into_mnt(mnt_userns, pace->e_gid); ++ kgid = mapped_kgid_fs(mnt_userns, &init_user_ns, pace->e_gid); + + /* Translate the kgid into a userspace id ksmbd would see. */ + return from_kgid(&init_user_ns, kgid); +--- a/fs/open.c ++++ b/fs/open.c +@@ -653,8 +653,8 @@ int chown_common(const struct path *path + gid = make_kgid(current_user_ns(), group); + + mnt_userns = mnt_user_ns(path->mnt); +- uid = kuid_from_mnt(mnt_userns, uid); +- gid = kgid_from_mnt(mnt_userns, gid); ++ uid = mapped_kuid_user(mnt_userns, &init_user_ns, uid); ++ gid = mapped_kgid_user(mnt_userns, &init_user_ns, gid); + + retry_deleg: + newattrs.ia_valid = ATTR_CTIME; +--- a/fs/posix_acl.c ++++ b/fs/posix_acl.c +@@ -376,7 +376,9 @@ posix_acl_permission(struct user_namespa + goto check_perm; + break; + case ACL_USER: +- uid = kuid_into_mnt(mnt_userns, pa->e_uid); ++ uid = mapped_kuid_fs(mnt_userns, ++ &init_user_ns, ++ pa->e_uid); + if (uid_eq(uid, current_fsuid())) + goto mask; + break; +@@ -389,7 +391,9 @@ posix_acl_permission(struct user_namespa + } + break; + case ACL_GROUP: +- gid = kgid_into_mnt(mnt_userns, pa->e_gid); ++ gid = mapped_kgid_fs(mnt_userns, ++ &init_user_ns, ++ pa->e_gid); + if (in_group_p(gid)) { + found = 1; + if ((pa->e_perm & want) == want) +@@ -736,17 +740,17 @@ static void posix_acl_fix_xattr_userns( + case ACL_USER: + uid = make_kuid(from, le32_to_cpu(entry->e_id)); + if (from_user) +- uid = kuid_from_mnt(mnt_userns, uid); ++ uid = mapped_kuid_user(mnt_userns, &init_user_ns, uid); + else +- uid = kuid_into_mnt(mnt_userns, uid); ++ uid = mapped_kuid_fs(mnt_userns, &init_user_ns, uid); + entry->e_id = cpu_to_le32(from_kuid(to, uid)); + break; + case ACL_GROUP: + gid = make_kgid(from, le32_to_cpu(entry->e_id)); + if (from_user) +- gid = kgid_from_mnt(mnt_userns, gid); ++ gid = mapped_kgid_user(mnt_userns, &init_user_ns, gid); + else +- gid = kgid_into_mnt(mnt_userns, gid); ++ gid = mapped_kgid_fs(mnt_userns, &init_user_ns, gid); + entry->e_id = cpu_to_le32(from_kgid(to, gid)); + break; + default: +--- a/security/commoncap.c ++++ b/security/commoncap.c +@@ -419,7 +419,7 @@ int cap_inode_getsecurity(struct user_na + kroot = make_kuid(fs_ns, root); + + /* If this is an idmapped mount shift the kuid. */ +- kroot = kuid_into_mnt(mnt_userns, kroot); ++ kroot = mapped_kuid_fs(mnt_userns, &init_user_ns, kroot); + + /* If the root kuid maps to a valid uid in current ns, then return + * this as a nscap. */ +@@ -489,6 +489,7 @@ out_free: + * @size: size of @ivalue + * @task_ns: user namespace of the caller + * @mnt_userns: user namespace of the mount the inode was found from ++ * @fs_userns: user namespace of the filesystem + * + * If the inode has been found through an idmapped mount the user namespace of + * the vfsmount must be passed through @mnt_userns. This function will then +@@ -498,7 +499,8 @@ out_free: + */ + static kuid_t rootid_from_xattr(const void *value, size_t size, + struct user_namespace *task_ns, +- struct user_namespace *mnt_userns) ++ struct user_namespace *mnt_userns, ++ struct user_namespace *fs_userns) + { + const struct vfs_ns_cap_data *nscap = value; + kuid_t rootkid; +@@ -508,7 +510,7 @@ static kuid_t rootid_from_xattr(const vo + rootid = le32_to_cpu(nscap->rootid); + + rootkid = make_kuid(task_ns, rootid); +- return kuid_from_mnt(mnt_userns, rootkid); ++ return mapped_kuid_user(mnt_userns, fs_userns, rootkid); + } + + static bool validheader(size_t size, const struct vfs_cap_data *cap) +@@ -559,7 +561,8 @@ int cap_convert_nscap(struct user_namesp + /* user is privileged, just write the v2 */ + return size; + +- rootid = rootid_from_xattr(*ivalue, size, task_ns, mnt_userns); ++ rootid = rootid_from_xattr(*ivalue, size, task_ns, mnt_userns, ++ &init_user_ns); + if (!uid_valid(rootid)) + return -EINVAL; + +@@ -700,7 +703,7 @@ int get_vfs_caps_from_disk(struct user_n + /* Limit the caps to the mounter of the filesystem + * or the more limited uid specified in the xattr. + */ +- rootkuid = kuid_into_mnt(mnt_userns, rootkuid); ++ rootkuid = mapped_kuid_fs(mnt_userns, &init_user_ns, rootkuid); + if (!rootid_owns_currentns(rootkuid)) + return -ENODATA; + diff --git a/queue-5.15/series b/queue-5.15/series index cc90db73ce6..82abb850ff5 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -10,3 +10,15 @@ xfs-check-sb_meta_uuid-for-dabuf-buffer-recovery.patch xfs-prevent-uaf-in-xfs_log_item_in_current_chkpt.patch xfs-only-bother-with-sync_filesystem-during-readonly-remount.patch powerpc-ftrace-remove-ftrace-init-tramp-once-kernel-init-is-complete.patch +fs-add-is_idmapped_mnt-helper.patch +fs-move-mapping-helpers.patch +fs-tweak-fsuidgid_has_mapping.patch +fs-account-for-filesystem-mappings.patch +docs-update-mapping-documentation.patch +fs-use-low-level-mapping-helpers.patch +fs-remove-unused-low-level-mapping-helpers.patch +fs-port-higher-level-mapping-helpers.patch +fs-add-i_user_ns-helper.patch +fs-support-mapped-mounts-of-mapped-filesystems.patch +fs-fix-acl-translation.patch +fs-account-for-group-membership.patch -- 2.47.3