1/* SPDX-License-Identifier: GPL-2.0 */
2
3#define _GNU_SOURCE
4#include <errno.h>
5#include <linux/sched.h>
6#include <linux/types.h>
7#include <signal.h>
8#include <stdint.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <sched.h>
12#include <string.h>
13#include <sys/resource.h>
14#include <sys/time.h>
15#include <sys/types.h>
16#include <sys/wait.h>
17#include <unistd.h>
18
19#include "pidfd.h"
20#include "../kselftest_harness.h"
21
22#define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr)))
23
24/* Attempt to de-conflict with the selftests tree. */
25#ifndef SKIP
26#define SKIP(s, ...)	XFAIL(s, ##__VA_ARGS__)
27#endif
28
29static pid_t sys_clone3(struct clone_args *args)
30{
31	return syscall(__NR_clone3, args, sizeof(struct clone_args));
32}
33
34static int sys_waitid(int which, pid_t pid, siginfo_t *info, int options,
35		      struct rusage *ru)
36{
37	return syscall(__NR_waitid, which, pid, info, options, ru);
38}
39
40TEST(wait_simple)
41{
42	int pidfd = -1;
43	pid_t parent_tid = -1;
44	struct clone_args args = {
45		.parent_tid = ptr_to_u64(&parent_tid),
46		.pidfd = ptr_to_u64(&pidfd),
47		.flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
48		.exit_signal = SIGCHLD,
49	};
50	pid_t pid;
51	siginfo_t info = {
52		.si_signo = 0,
53	};
54
55	pidfd = open("/proc/self", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
56	ASSERT_GE(pidfd, 0);
57
58	pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
59	ASSERT_NE(pid, 0);
60	EXPECT_EQ(close(pidfd), 0);
61	pidfd = -1;
62
63	pidfd = open("/dev/null", O_RDONLY | O_CLOEXEC);
64	ASSERT_GE(pidfd, 0);
65
66	pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
67	ASSERT_NE(pid, 0);
68	EXPECT_EQ(close(pidfd), 0);
69	pidfd = -1;
70
71	pid = sys_clone3(&args);
72	ASSERT_GE(pid, 0);
73
74	if (pid == 0)
75		exit(EXIT_SUCCESS);
76
77	pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
78	ASSERT_GE(pid, 0);
79	ASSERT_EQ(WIFEXITED(info.si_status), true);
80	ASSERT_EQ(WEXITSTATUS(info.si_status), 0);
81	EXPECT_EQ(close(pidfd), 0);
82
83	ASSERT_EQ(info.si_signo, SIGCHLD);
84	ASSERT_EQ(info.si_code, CLD_EXITED);
85	ASSERT_EQ(info.si_pid, parent_tid);
86}
87
88TEST(wait_states)
89{
90	int pidfd = -1;
91	pid_t parent_tid = -1;
92	struct clone_args args = {
93		.parent_tid = ptr_to_u64(&parent_tid),
94		.pidfd = ptr_to_u64(&pidfd),
95		.flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
96		.exit_signal = SIGCHLD,
97	};
98	int ret;
99	pid_t pid;
100	siginfo_t info = {
101		.si_signo = 0,
102	};
103
104	pid = sys_clone3(&args);
105	ASSERT_GE(pid, 0);
106
107	if (pid == 0) {
108		kill(getpid(), SIGSTOP);
109		kill(getpid(), SIGSTOP);
110		exit(EXIT_SUCCESS);
111	}
112
113	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL), 0);
114	ASSERT_EQ(info.si_signo, SIGCHLD);
115	ASSERT_EQ(info.si_code, CLD_STOPPED);
116	ASSERT_EQ(info.si_pid, parent_tid);
117
118	ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0), 0);
119
120	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WCONTINUED, NULL), 0);
121	ASSERT_EQ(info.si_signo, SIGCHLD);
122	ASSERT_EQ(info.si_code, CLD_CONTINUED);
123	ASSERT_EQ(info.si_pid, parent_tid);
124
125	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WUNTRACED, NULL), 0);
126	ASSERT_EQ(info.si_signo, SIGCHLD);
127	ASSERT_EQ(info.si_code, CLD_STOPPED);
128	ASSERT_EQ(info.si_pid, parent_tid);
129
130	ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0), 0);
131
132	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL), 0);
133	ASSERT_EQ(info.si_signo, SIGCHLD);
134	ASSERT_EQ(info.si_code, CLD_KILLED);
135	ASSERT_EQ(info.si_pid, parent_tid);
136
137	EXPECT_EQ(close(pidfd), 0);
138}
139
140TEST(wait_nonblock)
141{
142	int pidfd, status = 0;
143	unsigned int flags = 0;
144	pid_t parent_tid = -1;
145	struct clone_args args = {
146		.parent_tid = ptr_to_u64(&parent_tid),
147		.flags = CLONE_PARENT_SETTID,
148		.exit_signal = SIGCHLD,
149	};
150	int ret;
151	pid_t pid;
152	siginfo_t info = {
153		.si_signo = 0,
154	};
155
156	/*
157	 * Callers need to see ECHILD with non-blocking pidfds when no child
158	 * processes exists.
159	 */
160	pidfd = sys_pidfd_open(getpid(), PIDFD_NONBLOCK);
161	EXPECT_GE(pidfd, 0) {
162		/* pidfd_open() doesn't support PIDFD_NONBLOCK. */
163		ASSERT_EQ(errno, EINVAL);
164		SKIP(return, "Skipping PIDFD_NONBLOCK test");
165	}
166
167	ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
168	ASSERT_LT(ret, 0);
169	ASSERT_EQ(errno, ECHILD);
170	EXPECT_EQ(close(pidfd), 0);
171
172	pid = sys_clone3(&args);
173	ASSERT_GE(pid, 0);
174
175	if (pid == 0) {
176		kill(getpid(), SIGSTOP);
177		exit(EXIT_SUCCESS);
178	}
179
180	pidfd = sys_pidfd_open(pid, PIDFD_NONBLOCK);
181	EXPECT_GE(pidfd, 0) {
182		/* pidfd_open() doesn't support PIDFD_NONBLOCK. */
183		ASSERT_EQ(errno, EINVAL);
184		SKIP(return, "Skipping PIDFD_NONBLOCK test");
185	}
186
187	flags = fcntl(pidfd, F_GETFL, 0);
188	ASSERT_GT(flags, 0);
189	ASSERT_GT((flags & O_NONBLOCK), 0);
190
191	/*
192	 * Callers need to see EAGAIN/EWOULDBLOCK with non-blocking pidfd when
193	 * child processes exist but none have exited.
194	 */
195	ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
196	ASSERT_LT(ret, 0);
197	ASSERT_EQ(errno, EAGAIN);
198
199	/*
200	 * Callers need to continue seeing 0 with non-blocking pidfd and
201	 * WNOHANG raised explicitly when child processes exist but none have
202	 * exited.
203	 */
204	ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED | WNOHANG, NULL);
205	ASSERT_EQ(ret, 0);
206
207	ASSERT_EQ(fcntl(pidfd, F_SETFL, (flags & ~O_NONBLOCK)), 0);
208
209	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL), 0);
210	ASSERT_EQ(info.si_signo, SIGCHLD);
211	ASSERT_EQ(info.si_code, CLD_STOPPED);
212	ASSERT_EQ(info.si_pid, parent_tid);
213
214	ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0), 0);
215
216	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL), 0);
217	ASSERT_EQ(info.si_signo, SIGCHLD);
218	ASSERT_EQ(info.si_code, CLD_EXITED);
219	ASSERT_EQ(info.si_pid, parent_tid);
220
221	EXPECT_EQ(close(pidfd), 0);
222}
223
224TEST_HARNESS_MAIN
225