• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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