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
21 static struct tst_clone_args clone_args = {
22 .flags = CLONE_NEWPID,
23 .exit_signal = SIGCHLD
24 };
25 static pid_t pid_max;
26
child_func(int * level)27 static 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
find_cinit_pids(pid_t * pids)52 static 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
setup(void)76 static void setup(void)
77 {
78 SAFE_FILE_SCANF("/proc/sys/kernel/pid_max", "%d\n", &pid_max);
79 }
80
run(void)81 static 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
118 static 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