1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) Veerendra C <[email protected]>, 2008
4 * Copyright (C) 2023 SUSE LLC Andrea Cervesato <[email protected]>
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(const int level)27 static void child_func(const 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 - 1) {
38 TST_CHECKPOINT_WAKE(0);
39 return;
40 }
41
42 if (!SAFE_CLONE(&clone_args)) {
43 child_func(level + 1);
44 return;
45 }
46
47 pause();
48 }
49
find_cinit_pids(pid_t * pids)50 static int find_cinit_pids(pid_t *pids)
51 {
52 int pid;
53 int next = 0;
54 pid_t parentpid, pgid, pgid2;
55
56 parentpid = tst_getpid();
57 pgid = SAFE_GETPGID(parentpid);
58
59 for (pid = 2; pid < pid_max; pid++) {
60 if (pid == parentpid)
61 continue;
62
63 pgid2 = getpgid(pid);
64
65 if (pgid2 == pgid) {
66 pids[next] = pid;
67 next++;
68 }
69 }
70
71 return next;
72 }
73
setup(void)74 static void setup(void)
75 {
76 SAFE_FILE_SCANF("/proc/sys/kernel/pid_max", "%d\n", &pid_max);
77 }
78
run(void)79 static void run(void)
80 {
81 int i, status, children;
82 pid_t pids_new[MAX_DEPTH];
83 pid_t pids[MAX_DEPTH];
84 pid_t pid;
85
86 pid = SAFE_CLONE(&clone_args);
87 if (!pid) {
88 child_func(0);
89 return;
90 }
91
92 TST_CHECKPOINT_WAIT(0);
93
94 TST_EXP_POSITIVE(find_cinit_pids(pids));
95
96 SAFE_KILL(pid, SIGKILL);
97 SAFE_WAITPID(0, &status, 0);
98
99 children = find_cinit_pids(pids_new);
100
101 if (children > 0) {
102 tst_res(TFAIL, "%d children left after sending SIGKILL", children);
103
104 for (i = 0; i < MAX_DEPTH; i++) {
105 kill(pids[i], SIGKILL);
106 waitpid(pids[i], &status, 0);
107 }
108
109 return;
110 }
111
112 tst_res(TPASS, "No children left after sending SIGKILL to the first child");
113 }
114
115 static struct tst_test test = {
116 .test_all = run,
117 .setup = setup,
118 .needs_root = 1,
119 .needs_checkpoints = 1,
120 .forks_child = 1,
121 };
122