tools/testing/selftests/pidfd/pidfd_setns_test.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/pidfd/pidfd_setns_test.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/pidfd/pidfd_setns_test.c
Extension
.c
Size
19522 bytes
Lines
672
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

if (self->nsfds[i] < 0) {
			EXPECT_EQ(errno, ENOENT) {
				TH_LOG("%m - Failed to open %s namespace for process %d",
				       info->name, self->pid);
			}
		}

		self->child_pidfd_derived_nsfds[i] = ioctl(self->pidfd, info->pidfd_ioctl, 0);
		if (self->child_pidfd_derived_nsfds[i] < 0) {
			EXPECT_EQ(errno, EOPNOTSUPP) {
				TH_LOG("%m - Failed to derive %s namespace from pidfd of process %d",
				       info->name, self->pid);
			}
		}
	}

	/* Create task that exits right away. */
	self->child_pid_exited = create_child(&self->child_pidfd_exited, 0);
	EXPECT_GE(self->child_pid_exited, 0);

	if (self->child_pid_exited == 0) {
		if (self->nsfds[PIDFD_NS_USER] >= 0 && unshare(CLONE_NEWUSER) < 0)
			_exit(EXIT_FAILURE);
		if (self->nsfds[PIDFD_NS_NET] >= 0 && unshare(CLONE_NEWNET) < 0)
			_exit(EXIT_FAILURE);
		_exit(EXIT_SUCCESS);
	}

	ASSERT_EQ(sys_waitid(P_PID, self->child_pid_exited, NULL, WEXITED | WNOWAIT), 0);

	self->pidfd = sys_pidfd_open(self->pid, 0);
	EXPECT_GE(self->pidfd, 0) {
		TH_LOG("%m - Failed to open pidfd for process %d", self->pid);
	}

	ret = socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
	EXPECT_EQ(ret, 0);

	/* Create tasks that will be stopped. */
	if (self->nsfds[PIDFD_NS_USER] >= 0 && self->nsfds[PIDFD_NS_PID] >= 0)
		self->child_pid1 = create_child(&self->child_pidfd1, CLONE_NEWUSER | CLONE_NEWPID);
	else if (self->nsfds[PIDFD_NS_PID] >= 0)
		self->child_pid1 = create_child(&self->child_pidfd1, CLONE_NEWPID);
	else if (self->nsfds[PIDFD_NS_USER] >= 0)
		self->child_pid1 = create_child(&self->child_pidfd1, CLONE_NEWUSER);
	else
		self->child_pid1 = create_child(&self->child_pidfd1, 0);
	EXPECT_GE(self->child_pid1, 0);

	if (self->child_pid1 == 0) {
		close(ipc_sockets[0]);

		if (self->nsfds[PIDFD_NS_MNT] >= 0 && unshare(CLONE_NEWNS) < 0) {
			TH_LOG("%m - Failed to unshare mount namespace for process %d", self->pid);
			_exit(EXIT_FAILURE);
		}
		if (self->nsfds[PIDFD_NS_CGROUP] >= 0 && unshare(CLONE_NEWCGROUP) < 0) {
			TH_LOG("%m - Failed to unshare cgroup namespace for process %d", self->pid);
			_exit(EXIT_FAILURE);
		}
		if (self->nsfds[PIDFD_NS_IPC] >= 0 && unshare(CLONE_NEWIPC) < 0) {
			TH_LOG("%m - Failed to unshare ipc namespace for process %d", self->pid);
			_exit(EXIT_FAILURE);
		}
		if (self->nsfds[PIDFD_NS_UTS] >= 0 && unshare(CLONE_NEWUTS) < 0) {
			TH_LOG("%m - Failed to unshare uts namespace for process %d", self->pid);
			_exit(EXIT_FAILURE);
		}
		if (self->nsfds[PIDFD_NS_NET] >= 0 && unshare(CLONE_NEWNET) < 0) {
			TH_LOG("%m - Failed to unshare net namespace for process %d", self->pid);
			_exit(EXIT_FAILURE);
		}
		if (self->nsfds[PIDFD_NS_TIME] >= 0 && !switch_timens()) {
			TH_LOG("%m - Failed to unshare time namespace for process %d", self->pid);
			_exit(EXIT_FAILURE);
		}

		if (write_nointr(ipc_sockets[1], "1", 1) < 0)
			_exit(EXIT_FAILURE);

		close(ipc_sockets[1]);

		pause();
		_exit(EXIT_SUCCESS);
	}

	close(ipc_sockets[1]);
	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
	close(ipc_sockets[0]);

Annotation

Implementation Notes