Commit 9b3e1504 authored by Christian Brauner's avatar Christian Brauner

pidfs: handle kernels without namespaces cleanly

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: 5b08bd40 ("pidfs: allow retrieval of namespace file descriptors") # mainline only
Signed-off-by: default avatarChristian Brauner <brauner@kernel.org>
parent f60d38cb
...@@ -119,7 +119,7 @@ static long pidfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -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 task_struct *task __free(put_task) = NULL;
struct nsproxy *nsp __free(put_nsproxy) = NULL; struct nsproxy *nsp __free(put_nsproxy) = NULL;
struct pid *pid = pidfd_pid(file); struct pid *pid = pidfd_pid(file);
struct ns_common *ns_common; struct ns_common *ns_common = NULL;
if (arg) if (arg)
return -EINVAL; return -EINVAL;
...@@ -146,54 +146,73 @@ static long pidfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -146,54 +146,73 @@ static long pidfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
switch (cmd) { switch (cmd) {
/* Namespaces that hang of nsproxy. */ /* Namespaces that hang of nsproxy. */
case PIDFD_GET_CGROUP_NAMESPACE: case PIDFD_GET_CGROUP_NAMESPACE:
get_cgroup_ns(nsp->cgroup_ns); if (IS_ENABLED(CONFIG_CGROUPS)) {
ns_common = to_ns_common(nsp->cgroup_ns); get_cgroup_ns(nsp->cgroup_ns);
ns_common = to_ns_common(nsp->cgroup_ns);
}
break; break;
case PIDFD_GET_IPC_NAMESPACE: case PIDFD_GET_IPC_NAMESPACE:
get_ipc_ns(nsp->ipc_ns); if (IS_ENABLED(CONFIG_IPC_NS)) {
ns_common = to_ns_common(nsp->ipc_ns); get_ipc_ns(nsp->ipc_ns);
ns_common = to_ns_common(nsp->ipc_ns);
}
break; break;
case PIDFD_GET_MNT_NAMESPACE: case PIDFD_GET_MNT_NAMESPACE:
get_mnt_ns(nsp->mnt_ns); get_mnt_ns(nsp->mnt_ns);
ns_common = to_ns_common(nsp->mnt_ns); ns_common = to_ns_common(nsp->mnt_ns);
break; break;
case PIDFD_GET_NET_NAMESPACE: case PIDFD_GET_NET_NAMESPACE:
ns_common = to_ns_common(nsp->net_ns); if (IS_ENABLED(CONFIG_NET_NS)) {
get_net_ns(ns_common); ns_common = to_ns_common(nsp->net_ns);
get_net_ns(ns_common);
}
break; break;
case PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE: case PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE:
get_pid_ns(nsp->pid_ns_for_children); if (IS_ENABLED(CONFIG_PID_NS)) {
ns_common = to_ns_common(nsp->pid_ns_for_children); get_pid_ns(nsp->pid_ns_for_children);
ns_common = to_ns_common(nsp->pid_ns_for_children);
}
break; break;
case PIDFD_GET_TIME_NAMESPACE: case PIDFD_GET_TIME_NAMESPACE:
get_time_ns(nsp->time_ns); if (IS_ENABLED(CONFIG_TIME_NS)) {
ns_common = to_ns_common(nsp->time_ns); get_time_ns(nsp->time_ns);
if (!nsp->time_ns) ns_common = to_ns_common(nsp->time_ns);
return -EINVAL; }
break; break;
case PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE: case PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE:
get_time_ns(nsp->time_ns_for_children); if (IS_ENABLED(CONFIG_TIME_NS)) {
ns_common = to_ns_common(nsp->time_ns_for_children); get_time_ns(nsp->time_ns_for_children);
ns_common = to_ns_common(nsp->time_ns_for_children);
}
break; break;
case PIDFD_GET_UTS_NAMESPACE: case PIDFD_GET_UTS_NAMESPACE:
get_uts_ns(nsp->uts_ns); if (IS_ENABLED(CONFIG_UTS_NS)) {
ns_common = to_ns_common(nsp->uts_ns); get_uts_ns(nsp->uts_ns);
ns_common = to_ns_common(nsp->uts_ns);
}
break; break;
/* Namespaces that don't hang of nsproxy. */ /* Namespaces that don't hang of nsproxy. */
case PIDFD_GET_USER_NAMESPACE: case PIDFD_GET_USER_NAMESPACE:
rcu_read_lock(); if (IS_ENABLED(CONFIG_USER_NS)) {
ns_common = to_ns_common(get_user_ns(task_cred_xxx(task, user_ns))); rcu_read_lock();
rcu_read_unlock(); ns_common = to_ns_common(get_user_ns(task_cred_xxx(task, user_ns)));
rcu_read_unlock();
}
break; break;
case PIDFD_GET_PID_NAMESPACE: case PIDFD_GET_PID_NAMESPACE:
rcu_read_lock(); if (IS_ENABLED(CONFIG_PID_NS)) {
ns_common = to_ns_common(get_pid_ns(task_active_pid_ns(task))); rcu_read_lock();
rcu_read_unlock(); ns_common = to_ns_common( get_pid_ns(task_active_pid_ns(task)));
rcu_read_unlock();
}
break; break;
default: default:
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
} }
if (!ns_common)
return -EOPNOTSUPP;
/* open_namespace() unconditionally consumes the reference */ /* open_namespace() unconditionally consumes the reference */
return open_namespace(ns_common); return open_namespace(ns_common);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment