]> www.infradead.org Git - users/willy/pagecache.git/commitdiff
pidfs: handle kernels without namespaces cleanly
authorChristian Brauner <brauner@kernel.org>
Mon, 22 Jul 2024 13:13:54 +0000 (15:13 +0200)
committerChristian Brauner <brauner@kernel.org>
Wed, 24 Jul 2024 08:53:13 +0000 (10:53 +0200)
The nsproxy structure contains nearly all of the namespaces associated
with a task. When a given namespace type is not supported by this kernel
the rules whether the corresponding pointer in struct nsproxy is NULL or
always init_<ns_type>_ns differ per namespace. Ideally, that wouldn't be
the case and for all namespace types we'd always set it to
init_<ns_type>_ns when the corresponding namespace type isn't supported.

Make sure we handle all namespaces where the pointer in struct nsproxy
can be NULL when the namespace type isn't supported.

Link: https://lore.kernel.org/r/20240722-work-pidfs-e6a83030f63e@brauner
Fixes: 5b08bd408534 ("pidfs: allow retrieval of namespace file descriptors") # mainline only
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/pidfs.c

index fe0ddab48f574d885a1cb6662a0ae616f79759fd..7ffdc88dfb527d9cf8a133955c9379f8f89a1788 100644 (file)
@@ -119,7 +119,7 @@ static long pidfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        struct task_struct *task __free(put_task) = NULL;
        struct nsproxy *nsp __free(put_nsproxy) = NULL;
        struct pid *pid = pidfd_pid(file);
-       struct ns_common *ns_common;
+       struct ns_common *ns_common = NULL;
 
        if (arg)
                return -EINVAL;
@@ -146,54 +146,73 @@ static long pidfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        switch (cmd) {
        /* Namespaces that hang of nsproxy. */
        case PIDFD_GET_CGROUP_NAMESPACE:
-               get_cgroup_ns(nsp->cgroup_ns);
-               ns_common = to_ns_common(nsp->cgroup_ns);
+               if (IS_ENABLED(CONFIG_CGROUPS)) {
+                       get_cgroup_ns(nsp->cgroup_ns);
+                       ns_common = to_ns_common(nsp->cgroup_ns);
+               }
                break;
        case PIDFD_GET_IPC_NAMESPACE:
-               get_ipc_ns(nsp->ipc_ns);
-               ns_common = to_ns_common(nsp->ipc_ns);
+               if (IS_ENABLED(CONFIG_IPC_NS)) {
+                       get_ipc_ns(nsp->ipc_ns);
+                       ns_common = to_ns_common(nsp->ipc_ns);
+               }
                break;
        case PIDFD_GET_MNT_NAMESPACE:
                get_mnt_ns(nsp->mnt_ns);
                ns_common = to_ns_common(nsp->mnt_ns);
                break;
        case PIDFD_GET_NET_NAMESPACE:
-               ns_common = to_ns_common(nsp->net_ns);
-               get_net_ns(ns_common);
+               if (IS_ENABLED(CONFIG_NET_NS)) {
+                       ns_common = to_ns_common(nsp->net_ns);
+                       get_net_ns(ns_common);
+               }
                break;
        case PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE:
-               get_pid_ns(nsp->pid_ns_for_children);
-               ns_common = to_ns_common(nsp->pid_ns_for_children);
+               if (IS_ENABLED(CONFIG_PID_NS)) {
+                       get_pid_ns(nsp->pid_ns_for_children);
+                       ns_common = to_ns_common(nsp->pid_ns_for_children);
+               }
                break;
        case PIDFD_GET_TIME_NAMESPACE:
-               get_time_ns(nsp->time_ns);
-               ns_common = to_ns_common(nsp->time_ns);
-               if (!nsp->time_ns)
-                       return -EINVAL;
+               if (IS_ENABLED(CONFIG_TIME_NS)) {
+                       get_time_ns(nsp->time_ns);
+                       ns_common = to_ns_common(nsp->time_ns);
+               }
                break;
        case PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE:
-               get_time_ns(nsp->time_ns_for_children);
-               ns_common = to_ns_common(nsp->time_ns_for_children);
+               if (IS_ENABLED(CONFIG_TIME_NS)) {
+                       get_time_ns(nsp->time_ns_for_children);
+                       ns_common = to_ns_common(nsp->time_ns_for_children);
+               }
                break;
        case PIDFD_GET_UTS_NAMESPACE:
-               get_uts_ns(nsp->uts_ns);
-               ns_common = to_ns_common(nsp->uts_ns);
+               if (IS_ENABLED(CONFIG_UTS_NS)) {
+                       get_uts_ns(nsp->uts_ns);
+                       ns_common = to_ns_common(nsp->uts_ns);
+               }
                break;
        /* Namespaces that don't hang of nsproxy. */
        case PIDFD_GET_USER_NAMESPACE:
-               rcu_read_lock();
-               ns_common = to_ns_common(get_user_ns(task_cred_xxx(task, user_ns)));
-               rcu_read_unlock();
+               if (IS_ENABLED(CONFIG_USER_NS)) {
+                       rcu_read_lock();
+                       ns_common = to_ns_common(get_user_ns(task_cred_xxx(task, user_ns)));
+                       rcu_read_unlock();
+               }
                break;
        case PIDFD_GET_PID_NAMESPACE:
-               rcu_read_lock();
-               ns_common = to_ns_common(get_pid_ns(task_active_pid_ns(task)));
-               rcu_read_unlock();
+               if (IS_ENABLED(CONFIG_PID_NS)) {
+                       rcu_read_lock();
+                       ns_common = to_ns_common( get_pid_ns(task_active_pid_ns(task)));
+                       rcu_read_unlock();
+               }
                break;
        default:
                return -ENOIOCTLCMD;
        }
 
+       if (!ns_common)
+               return -EOPNOTSUPP;
+
        /* open_namespace() unconditionally consumes the reference */
        return open_namespace(ns_common);
 }