File Index
Files and directories
Sign in
FILE

pid_max.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/pid_namespace/pid_max.c C
  1/* SPDX-License-Identifier: GPL-2.0 */
  2#define _GNU_SOURCE
  3#include <assert.h>
  4#include <errno.h>
  5#include <fcntl.h>
  6#include <linux/types.h>
  7#include <sched.h>
  8#include <signal.h>
  9#include <stdio.h>
 10#include <stdlib.h>
 11#include <string.h>
 12#include <syscall.h>
 13#include <sys/mount.h>
 14#include <sys/wait.h>
 15
 16#include "kselftest_harness.h"
 17#include "../pidfd/pidfd.h"
 18
 19#define __STACK_SIZE (8 * 1024 * 1024)
 20static pid_t do_clone(int (*fn)(void *), void *arg, int flags)
 21{
 22	char *stack;
 23	pid_t ret;
 24
 25	stack = malloc(__STACK_SIZE);
 26	if (!stack)
 27		return -ENOMEM;
 28
 29#ifdef __ia64__
 30	ret = __clone2(fn, stack, __STACK_SIZE, flags | SIGCHLD, arg);
 31#else
 32	ret = clone(fn, stack + __STACK_SIZE, flags | SIGCHLD, arg);
 33#endif
 34	free(stack);
 35	return ret;
 36}
 37
 38static int pid_max_cb(void *data)
 39{
 40	int fd, ret;
 41	pid_t pid;
 42
 43	ret = mount("", "/", NULL, MS_PRIVATE | MS_REC, 0);
 44	if (ret) {
 45		fprintf(stderr, "%m - Failed to make rootfs private mount\n");
 46		return -1;
 47	}
 48
 49	umount2("/proc", MNT_DETACH);
 50
 51	ret = mount("proc", "/proc", "proc", 0, NULL);
 52	if (ret) {
 53		fprintf(stderr, "%m - Failed to mount proc\n");
 54		return -1;
 55	}
 56
 57	fd = open("/proc/sys/kernel/pid_max", O_RDWR | O_CLOEXEC | O_NOCTTY);
 58	if (fd < 0) {
 59		fprintf(stderr, "%m - Failed to open pid_max\n");
 60		return -1;
 61	}
 62
 63	ret = write(fd, "500", sizeof("500") - 1);
 64	if (ret < 0) {
 65		fprintf(stderr, "%m - Failed to write pid_max\n");
 66		return -1;
 67	}
 68
 69	for (int i = 0; i < 501; i++) {
 70		pid = fork();
 71		if (pid == 0)
 72			exit(EXIT_SUCCESS);
 73		wait_for_pid(pid);
 74		if (pid > 500) {
 75			fprintf(stderr, "Managed to create pid number beyond limit\n");
 76			return -1;
 77		}
 78	}
 79
 80	return 0;
 81}
 82
 83static int pid_max_nested_inner(void *data)
 84{
 85	int fret = -1;
 86	pid_t pids[2];
 87	int fd, i, ret;
 88
 89	ret = mount("", "/", NULL, MS_PRIVATE | MS_REC, 0);
 90	if (ret) {
 91		fprintf(stderr, "%m - Failed to make rootfs private mount\n");
 92		return fret;
 93	}
 94
 95	umount2("/proc", MNT_DETACH);
 96
 97	ret = mount("proc", "/proc", "proc", 0, NULL);
 98	if (ret) {
 99		fprintf(stderr, "%m - Failed to mount proc\n");
100		return fret;
101	}
102
103	fd = open("/proc/sys/kernel/pid_max", O_RDWR | O_CLOEXEC | O_NOCTTY);
104	if (fd < 0) {
105		fprintf(stderr, "%m - Failed to open pid_max\n");
106		return fret;
107	}
108
109	ret = write(fd, "500", sizeof("500") - 1);
110	close(fd);
111	if (ret < 0) {
112		fprintf(stderr, "%m - Failed to write pid_max\n");
113		return fret;
114	}
115
116	pids[0] = fork();
117	if (pids[0] < 0) {
118		fprintf(stderr, "Failed to create first new process\n");
119		return fret;
120	}
121
122	if (pids[0] == 0)
123		exit(EXIT_SUCCESS);
124
125	pids[1] = fork();
126	wait_for_pid(pids[0]);
127	if (pids[1] >= 0) {
128		if (pids[1] == 0)
129			exit(EXIT_SUCCESS);
130		wait_for_pid(pids[1]);
131
132		fprintf(stderr, "Managed to create process even though ancestor pid namespace had a limit\n");
133		return fret;
134	}
135
136	/* Now make sure that we wrap pids at 400. */
137	for (i = 0; i < 510; i++) {
138		pid_t pid;
139
140		pid = fork();
141		if (pid < 0)
142			return fret;
143
144		if (pid == 0)
145			exit(EXIT_SUCCESS);
146
147		wait_for_pid(pid);
148		if (pid >= 500) {
149			fprintf(stderr, "Managed to create process with pid %d beyond configured limit\n", pid);
150			return fret;
151		}
152	}
153
154	return 0;
155}
156
157static int pid_max_nested_outer(void *data)
158{
159	int fret = -1, nr_procs = 400;
160	pid_t pids[1000];
161	int fd, i, ret;
162	pid_t pid;
163
164	ret = mount("", "/", NULL, MS_PRIVATE | MS_REC, 0);
165	if (ret) {
166		fprintf(stderr, "%m - Failed to make rootfs private mount\n");
167		return fret;
168	}
169
170	umount2("/proc", MNT_DETACH);
171
172	ret = mount("proc", "/proc", "proc", 0, NULL);
173	if (ret) {
174		fprintf(stderr, "%m - Failed to mount proc\n");
175		return fret;
176	}
177
178	fd = open("/proc/sys/kernel/pid_max", O_RDWR | O_CLOEXEC | O_NOCTTY);
179	if (fd < 0) {
180		fprintf(stderr, "%m - Failed to open pid_max\n");
181		return fret;
182	}
183
184	ret = write(fd, "400", sizeof("400") - 1);
185	close(fd);
186	if (ret < 0) {
187		fprintf(stderr, "%m - Failed to write pid_max\n");
188		return fret;
189	}
190
191	/*
192	 * Create 397 processes. This leaves room for do_clone() (398) and
193	 * one more 399. So creating another process needs to fail.
194	 */
195	for (nr_procs = 0; nr_procs < 396; nr_procs++) {
196		pid = fork();
197		if (pid < 0)
198			goto reap;
199
200		if (pid == 0)
201			exit(EXIT_SUCCESS);
202
203		pids[nr_procs] = pid;
204	}
205
206	pid = do_clone(pid_max_nested_inner, NULL, CLONE_NEWPID | CLONE_NEWNS);
207	if (pid < 0) {
208		fprintf(stderr, "%m - Failed to clone nested pidns\n");
209		goto reap;
210	}
211
212	if (wait_for_pid(pid)) {
213		fprintf(stderr, "%m - Nested pid_max failed\n");
214		goto reap;
215	}
216
217	fret = 0;
218
219reap:
220	for (int i = 0; i < nr_procs; i++)
221		wait_for_pid(pids[i]);
222
223	return fret;
224}
225
226static int pid_max_nested_limit_inner(void *data)
227{
228	int fret = -1, nr_procs = 400;
229	int fd, ret;
230	pid_t pid;
231	pid_t pids[1000];
232
233	ret = mount("", "/", NULL, MS_PRIVATE | MS_REC, 0);
234	if (ret) {
235		fprintf(stderr, "%m - Failed to make rootfs private mount\n");
236		return fret;
237	}
238
239	umount2("/proc", MNT_DETACH);
240
241	ret = mount("proc", "/proc", "proc", 0, NULL);
242	if (ret) {
243		fprintf(stderr, "%m - Failed to mount proc\n");
244		return fret;
245	}
246
247	fd = open("/proc/sys/kernel/pid_max", O_RDWR | O_CLOEXEC | O_NOCTTY);
248	if (fd < 0) {
249		fprintf(stderr, "%m - Failed to open pid_max\n");
250		return fret;
251	}
252
253	ret = write(fd, "500", sizeof("500") - 1);
254	close(fd);
255	if (ret < 0) {
256		fprintf(stderr, "%m - Failed to write pid_max\n");
257		return fret;
258	}
259
260	for (nr_procs = 0; nr_procs < 500; nr_procs++) {
261		pid = fork();
262		if (pid < 0)
263			break;
264
265		if (pid == 0)
266			exit(EXIT_SUCCESS);
267
268		pids[nr_procs] = pid;
269	}
270
271	if (nr_procs >= 400) {
272		fprintf(stderr, "Managed to create processes beyond the configured outer limit\n");
273		goto reap;
274	}
275
276	fret = 0;
277
278reap:
279	for (int i = 0; i < nr_procs; i++)
280		wait_for_pid(pids[i]);
281
282	return fret;
283}
284
285static int pid_max_nested_limit_outer(void *data)
286{
287	int fd, ret;
288	pid_t pid;
289
290	ret = mount("", "/", NULL, MS_PRIVATE | MS_REC, 0);
291	if (ret) {
292		fprintf(stderr, "%m - Failed to make rootfs private mount\n");
293		return -1;
294	}
295
296	umount2("/proc", MNT_DETACH);
297
298	ret = mount("proc", "/proc", "proc", 0, NULL);
299	if (ret) {
300		fprintf(stderr, "%m - Failed to mount proc\n");
301		return -1;
302	}
303
304	fd = open("/proc/sys/kernel/pid_max", O_RDWR | O_CLOEXEC | O_NOCTTY);
305	if (fd < 0) {
306		fprintf(stderr, "%m - Failed to open pid_max\n");
307		return -1;
308	}
309
310	ret = write(fd, "400", sizeof("400") - 1);
311	close(fd);
312	if (ret < 0) {
313		fprintf(stderr, "%m - Failed to write pid_max\n");
314		return -1;
315	}
316
317	pid = do_clone(pid_max_nested_limit_inner, NULL, CLONE_NEWPID | CLONE_NEWNS);
318	if (pid < 0) {
319		fprintf(stderr, "%m - Failed to clone nested pidns\n");
320		return -1;
321	}
322
323	if (wait_for_pid(pid)) {
324		fprintf(stderr, "%m - Nested pid_max failed\n");
325		return -1;
326	}
327
328	return 0;
329}
330
331TEST(pid_max_simple)
332{
333	pid_t pid;
334
335
336	pid = do_clone(pid_max_cb, NULL, CLONE_NEWPID | CLONE_NEWNS);
337	ASSERT_GT(pid, 0);
338	ASSERT_EQ(0, wait_for_pid(pid));
339}
340
341TEST(pid_max_nested_limit)
342{
343	pid_t pid;
344
345	pid = do_clone(pid_max_nested_limit_outer, NULL, CLONE_NEWPID | CLONE_NEWNS);
346	ASSERT_GT(pid, 0);
347	ASSERT_EQ(0, wait_for_pid(pid));
348}
349
350TEST(pid_max_nested)
351{
352	pid_t pid;
353
354	pid = do_clone(pid_max_nested_outer, NULL, CLONE_NEWPID | CLONE_NEWNS);
355	ASSERT_GT(pid, 0);
356	ASSERT_EQ(0, wait_for_pid(pid));
357}
358
359TEST_HARNESS_MAIN
~/ Read-only file preview.