1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) Veerendra C <vechandr@in.ibm.com>, 2008
4 * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
5 */
6
7/*\
8 * [Description]
9 *
10 * Clone a process with CLONE_NEWPID flag and create many levels of child
11 * containers. Then kill container init process from parent and check if all
12 * containers have been killed.
13 */
14
15#include <sys/wait.h>
16#include "tst_test.h"
17#include "lapi/sched.h"
18
19#define MAX_DEPTH	5
20
21static struct tst_clone_args clone_args = {
22	.flags = CLONE_NEWPID,
23	.exit_signal = SIGCHLD
24};
25static pid_t pid_max;
26
27static void child_func(int *level)
28{
29	pid_t cpid, ppid;
30
31	cpid = tst_getpid();
32	ppid = getppid();
33
34	TST_EXP_EQ_LI(cpid, 1);
35	TST_EXP_EQ_LI(ppid, 0);
36
37	if (*level >= MAX_DEPTH) {
38		TST_CHECKPOINT_WAKE(0);
39		return;
40	}
41
42	(*level)++;
43
44	if (!SAFE_CLONE(&clone_args)) {
45		child_func(level);
46		return;
47	}
48
49	pause();
50}
51
52static int find_cinit_pids(pid_t *pids)
53{
54	int pid;
55	int next = 0;
56	pid_t parentpid, pgid, pgid2;
57
58	parentpid = tst_getpid();
59	pgid = SAFE_GETPGID(parentpid);
60
61	for (pid = 2; pid < pid_max; pid++) {
62		if (pid == parentpid)
63			continue;
64
65		pgid2 = getpgid(pid);
66
67		if (pgid2 == pgid) {
68			pids[next] = pid;
69			next++;
70		}
71	}
72
73	return next;
74}
75
76static void setup(void)
77{
78	SAFE_FILE_SCANF("/proc/sys/kernel/pid_max", "%d\n", &pid_max);
79}
80
81static void run(void)
82{
83	int i, status, children;
84	int level = 0;
85	pid_t pids_new[MAX_DEPTH];
86	pid_t pids[MAX_DEPTH];
87	pid_t pid;
88
89	pid = SAFE_CLONE(&clone_args);
90	if (!pid) {
91		child_func(&level);
92		return;
93	}
94
95	TST_CHECKPOINT_WAIT(0);
96
97	TST_EXP_POSITIVE(find_cinit_pids(pids));
98
99	SAFE_KILL(pid, SIGKILL);
100	SAFE_WAITPID(0, &status, 0);
101
102	children = find_cinit_pids(pids_new);
103
104	if (children > 0) {
105		tst_res(TFAIL, "%d children left after sending SIGKILL", children);
106
107		for (i = 0; i < MAX_DEPTH; i++) {
108			kill(pids[i], SIGKILL);
109			waitpid(pids[i], &status, 0);
110		}
111
112		return;
113	}
114
115	tst_res(TPASS, "No children left after sending SIGKILL to the first child");
116}
117
118static struct tst_test test = {
119	.test_all = run,
120	.setup = setup,
121	.needs_root = 1,
122	.needs_checkpoints = 1,
123	.forks_child = 1,
124};
125