xref: /aosp_15_r20/external/ltp/testcases/kernel/containers/pidns/pidns05.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
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