fs/namespace: correctly handle errors returned by grab_requested_mnt_ns

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: 7b9d14af87 ("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>
This commit is contained in:
Andrei Vagin 2025-11-11 06:28:15 +00:00 committed by Christian Brauner
parent a3f8f86627
commit 78f0e33cd6
No known key found for this signature in database
GPG Key ID: 91C61BC06578DCA2
2 changed files with 17 additions and 17 deletions

View File

@ -141,7 +141,8 @@ static void mnt_ns_release(struct mnt_namespace *ns)
kfree(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_release_rcu(struct rcu_head *rcu) static void mnt_ns_release_rcu(struct rcu_head *rcu)
{ {
@ -5726,7 +5727,7 @@ static int copy_mnt_id_req(const struct mnt_id_req __user *req,
ret = copy_struct_from_user(kreq, sizeof(*kreq), req, usize); ret = copy_struct_from_user(kreq, sizeof(*kreq), req, usize);
if (ret) if (ret)
return ret; return ret;
if (kreq->spare != 0) if (kreq->mnt_ns_fd != 0 && kreq->mnt_ns_id)
return -EINVAL; return -EINVAL;
/* The first valid unique mount id is MNT_UNIQUE_ID_OFFSET + 1. */ /* The first valid unique mount id is MNT_UNIQUE_ID_OFFSET + 1. */
if (kreq->mnt_id <= MNT_UNIQUE_ID_OFFSET) if (kreq->mnt_id <= MNT_UNIQUE_ID_OFFSET)
@ -5743,16 +5744,12 @@ static struct mnt_namespace *grab_requested_mnt_ns(const struct mnt_id_req *kreq
{ {
struct mnt_namespace *mnt_ns; struct mnt_namespace *mnt_ns;
if (kreq->mnt_ns_id && kreq->spare) if (kreq->mnt_ns_id) {
return ERR_PTR(-EINVAL); mnt_ns = lookup_mnt_ns(kreq->mnt_ns_id);
} else if (kreq->mnt_ns_fd) {
if (kreq->mnt_ns_id)
return lookup_mnt_ns(kreq->mnt_ns_id);
if (kreq->spare) {
struct ns_common *ns; struct ns_common *ns;
CLASS(fd, f)(kreq->spare); CLASS(fd, f)(kreq->mnt_ns_fd);
if (fd_empty(f)) if (fd_empty(f))
return ERR_PTR(-EBADF); return ERR_PTR(-EBADF);
@ -5767,6 +5764,8 @@ static struct mnt_namespace *grab_requested_mnt_ns(const struct mnt_id_req *kreq
} else { } else {
mnt_ns = current->nsproxy->mnt_ns; mnt_ns = current->nsproxy->mnt_ns;
} }
if (!mnt_ns)
return ERR_PTR(-ENOENT);
refcount_inc(&mnt_ns->passive); refcount_inc(&mnt_ns->passive);
return mnt_ns; return mnt_ns;
@ -5791,8 +5790,8 @@ SYSCALL_DEFINE4(statmount, const struct mnt_id_req __user *, req,
return ret; return ret;
ns = grab_requested_mnt_ns(&kreq); ns = grab_requested_mnt_ns(&kreq);
if (!ns) if (IS_ERR(ns))
return -ENOENT; return PTR_ERR(ns);
if (kreq.mnt_ns_id && (ns != current->nsproxy->mnt_ns) && if (kreq.mnt_ns_id && (ns != current->nsproxy->mnt_ns) &&
!ns_capable_noaudit(ns->user_ns, CAP_SYS_ADMIN)) !ns_capable_noaudit(ns->user_ns, CAP_SYS_ADMIN))
@ -5902,8 +5901,8 @@ static void __free_klistmount_free(const struct klistmount *kls)
static inline int prepare_klistmount(struct klistmount *kls, struct mnt_id_req *kreq, static inline int prepare_klistmount(struct klistmount *kls, struct mnt_id_req *kreq,
size_t nr_mnt_ids) size_t nr_mnt_ids)
{ {
u64 last_mnt_id = kreq->param; u64 last_mnt_id = kreq->param;
struct mnt_namespace *ns;
/* The first valid unique mount id is MNT_UNIQUE_ID_OFFSET + 1. */ /* The first valid unique mount id is MNT_UNIQUE_ID_OFFSET + 1. */
if (last_mnt_id != 0 && last_mnt_id <= MNT_UNIQUE_ID_OFFSET) if (last_mnt_id != 0 && last_mnt_id <= MNT_UNIQUE_ID_OFFSET)
@ -5917,9 +5916,10 @@ static inline int prepare_klistmount(struct klistmount *kls, struct mnt_id_req *
if (!kls->kmnt_ids) if (!kls->kmnt_ids)
return -ENOMEM; return -ENOMEM;
kls->ns = grab_requested_mnt_ns(kreq); ns = grab_requested_mnt_ns(kreq);
if (!kls->ns) if (IS_ERR(ns))
return -ENOENT; return PTR_ERR(ns);
kls->ns = ns;
kls->mnt_parent_id = kreq->mnt_id; kls->mnt_parent_id = kreq->mnt_id;
return 0; return 0;

View File

@ -197,7 +197,7 @@ struct statmount {
*/ */
struct mnt_id_req { struct mnt_id_req {
__u32 size; __u32 size;
__u32 spare; __u32 mnt_ns_fd;
__u64 mnt_id; __u64 mnt_id;
__u64 param; __u64 param;
__u64 mnt_ns_id; __u64 mnt_ns_id;