Unverified Commit 75ddaa4d authored by Christian Brauner's avatar Christian Brauner
Browse files

pidfs: protect PIDFD_GET_* ioctls() via ifdef

We originally protected PIDFD_GET_<ns-type>_NAMESPACE ioctls() through
ifdefs and recent rework made it possible to drop them. There was an
oversight though. When the relevant namespace is turned off ns->ops will
be NULL so even though opening a file descriptor is perfectly legitimate
it would fail during inode eviction when the file was closed.

The simple fix would be to check ns->ops for NULL and continue allow to
retrieve namespace fds from pidfds but we don't allow retrieving them
when the relevant namespace type is turned off. So keep the
simplification but add the ifdefs back in.

Link: https://lore.kernel.org/20251222214907.GA189632@quark
Link: https://patch.msgid.link/20251224-ununterbrochen-gagen-ea949b83f8f2@brauner


Fixes: a71e4f10 ("pidfs: simplify PIDFD_GET_<type>_NAMESPACE ioctls")
Tested-by: default avatarBrendan Jackman <jackmanb@kernel.org>
Tested-by: default avatarEric Biggers <ebiggers@kernel.org>
Reported-by: default avatarEric Biggers <ebiggers@kernel.org>
Signed-off-by: default avatarChristian Brauner <brauner@kernel.org>
parent 78c85002
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -517,14 +517,18 @@ 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:
#ifdef CONFIG_CGROUPS
		if (!ns_ref_get(nsp->cgroup_ns))
			break;
		ns_common = to_ns_common(nsp->cgroup_ns);
#endif
		break;
	case PIDFD_GET_IPC_NAMESPACE:
#ifdef CONFIG_IPC_NS
		if (!ns_ref_get(nsp->ipc_ns))
			break;
		ns_common = to_ns_common(nsp->ipc_ns);
#endif
		break;
	case PIDFD_GET_MNT_NAMESPACE:
		if (!ns_ref_get(nsp->mnt_ns))
@@ -532,32 +536,43 @@ static long pidfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
		ns_common = to_ns_common(nsp->mnt_ns);
		break;
	case PIDFD_GET_NET_NAMESPACE:
#ifdef CONFIG_NET_NS
		if (!ns_ref_get(nsp->net_ns))
			break;
		ns_common = to_ns_common(nsp->net_ns);
#endif
		break;
	case PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE:
#ifdef CONFIG_PID_NS
		if (!ns_ref_get(nsp->pid_ns_for_children))
			break;
		ns_common = to_ns_common(nsp->pid_ns_for_children);
#endif
		break;
	case PIDFD_GET_TIME_NAMESPACE:
#ifdef CONFIG_TIME_NS
		if (!ns_ref_get(nsp->time_ns))
			break;
		ns_common = to_ns_common(nsp->time_ns);
#endif
		break;
	case PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE:
#ifdef CONFIG_TIME_NS
		if (!ns_ref_get(nsp->time_ns_for_children))
			break;
		ns_common = to_ns_common(nsp->time_ns_for_children);
#endif
		break;
	case PIDFD_GET_UTS_NAMESPACE:
#ifdef CONFIG_UTS_NS
		if (!ns_ref_get(nsp->uts_ns))
			break;
		ns_common = to_ns_common(nsp->uts_ns);
#endif
		break;
	/* Namespaces that don't hang of nsproxy. */
	case PIDFD_GET_USER_NAMESPACE:
#ifdef CONFIG_USER_NS
		scoped_guard(rcu) {
			struct user_namespace *user_ns;

@@ -566,8 +581,10 @@ static long pidfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
				break;
			ns_common = to_ns_common(user_ns);
		}
#endif
		break;
	case PIDFD_GET_PID_NAMESPACE:
#ifdef CONFIG_PID_NS
		scoped_guard(rcu) {
			struct pid_namespace *pid_ns;

@@ -576,6 +593,7 @@ static long pidfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
				break;
			ns_common = to_ns_common(pid_ns);
		}
#endif
		break;
	default:
		return -ENOIOCTLCMD;