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