]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
fs/namespace: correctly handle errors returned by grab_requested_mnt_ns
authorAndrei Vagin <avagin@google.com>
Tue, 11 Nov 2025 06:28:15 +0000 (06:28 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 24 Nov 2025 09:35:57 +0000 (10:35 +0100)
[ Upstream commit 78f0e33cd6c939a555aa80dbed2fec6b333a7660 ]

grab_requested_mnt_ns was changed to return error codes on failure, but
its callers were not updated to check for error pointers, still checking
only for a NULL return value.

This commit updates the callers to use IS_ERR() or IS_ERR_OR_NULL() and
PTR_ERR() to correctly check for and propagate errors.

This also makes sure that the logic actually works and mount namespace
file descriptors can be used to refere to mounts.

Christian Brauner <brauner@kernel.org> says:

Rework the patch to be more ergonomic and in line with our overall error
handling patterns.

Fixes: 7b9d14af8777 ("fs: allow mount namespace fd")
Cc: Christian Brauner <brauner@kernel.org>
Signed-off-by: Andrei Vagin <avagin@google.com>
Link: https://patch.msgid.link/20251111062815.2546189-1-avagin@google.com
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/namespace.c
include/uapi/linux/mount.h

index cc4926d53e7deac6d02ffb29768480eb2f5e2e1e..035d6f1f0b6ef12b75cb5ca38d0068c0b780e9aa 100644 (file)
@@ -158,7 +158,8 @@ static void mnt_ns_release(struct mnt_namespace *ns)
                kfree(ns);
        }
 }
-DEFINE_FREE(mnt_ns_release, struct mnt_namespace *, if (_T) mnt_ns_release(_T))
+DEFINE_FREE(mnt_ns_release, struct mnt_namespace *,
+           if (!IS_ERR(_T)) mnt_ns_release(_T))
 
 static void mnt_ns_tree_remove(struct mnt_namespace *ns)
 {
@@ -5325,7 +5326,7 @@ static int copy_mnt_id_req(const struct mnt_id_req __user *req,
        ret = copy_struct_from_user(kreq, sizeof(*kreq), req, usize);
        if (ret)
                return ret;
-       if (kreq->spare != 0)
+       if (kreq->mnt_ns_fd != 0 && kreq->mnt_ns_id)
                return -EINVAL;
        /* The first valid unique mount id is MNT_UNIQUE_ID_OFFSET + 1. */
        if (kreq->mnt_id <= MNT_UNIQUE_ID_OFFSET)
@@ -5342,16 +5343,12 @@ static struct mnt_namespace *grab_requested_mnt_ns(const struct mnt_id_req *kreq
 {
        struct mnt_namespace *mnt_ns;
 
-       if (kreq->mnt_ns_id && kreq->spare)
-               return ERR_PTR(-EINVAL);
-
-       if (kreq->mnt_ns_id)
-               return lookup_mnt_ns(kreq->mnt_ns_id);
-
-       if (kreq->spare) {
+       if (kreq->mnt_ns_id) {
+               mnt_ns = lookup_mnt_ns(kreq->mnt_ns_id);
+       } else if (kreq->mnt_ns_fd) {
                struct ns_common *ns;
 
-               CLASS(fd, f)(kreq->spare);
+               CLASS(fd, f)(kreq->mnt_ns_fd);
                if (fd_empty(f))
                        return ERR_PTR(-EBADF);
 
@@ -5366,6 +5363,8 @@ static struct mnt_namespace *grab_requested_mnt_ns(const struct mnt_id_req *kreq
        } else {
                mnt_ns = current->nsproxy->mnt_ns;
        }
+       if (!mnt_ns)
+               return ERR_PTR(-ENOENT);
 
        refcount_inc(&mnt_ns->passive);
        return mnt_ns;
@@ -5390,8 +5389,8 @@ SYSCALL_DEFINE4(statmount, const struct mnt_id_req __user *, req,
                return ret;
 
        ns = grab_requested_mnt_ns(&kreq);
-       if (!ns)
-               return -ENOENT;
+       if (IS_ERR(ns))
+               return PTR_ERR(ns);
 
        if (kreq.mnt_ns_id && (ns != current->nsproxy->mnt_ns) &&
            !ns_capable_noaudit(ns->user_ns, CAP_SYS_ADMIN))
@@ -5500,8 +5499,8 @@ static void __free_klistmount_free(const struct klistmount *kls)
 static inline int prepare_klistmount(struct klistmount *kls, struct mnt_id_req *kreq,
                                     size_t nr_mnt_ids)
 {
-
        u64 last_mnt_id = kreq->param;
+       struct mnt_namespace *ns;
 
        /* The first valid unique mount id is MNT_UNIQUE_ID_OFFSET + 1. */
        if (last_mnt_id != 0 && last_mnt_id <= MNT_UNIQUE_ID_OFFSET)
@@ -5515,9 +5514,10 @@ static inline int prepare_klistmount(struct klistmount *kls, struct mnt_id_req *
        if (!kls->kmnt_ids)
                return -ENOMEM;
 
-       kls->ns = grab_requested_mnt_ns(kreq);
-       if (!kls->ns)
-               return -ENOENT;
+       ns = grab_requested_mnt_ns(kreq);
+       if (IS_ERR(ns))
+               return PTR_ERR(ns);
+       kls->ns = ns;
 
        kls->mnt_parent_id = kreq->mnt_id;
        return 0;
index 225bc366ffcbf0319929e2f55f1fbea88e4d7b81..dbf65f2ffcf3360574845977e2d530edf5ce12c0 100644 (file)
@@ -186,7 +186,7 @@ struct statmount {
  */
 struct mnt_id_req {
        __u32 size;
-       __u32 spare;
+       __u32 mnt_ns_fd;
        __u64 mnt_id;
        __u64 param;
        __u64 mnt_ns_id;