1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved.
4 * Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
5 *
6 * Test PR_SET_CHILD_SUBREAPER and PR_GET_CHILD_SUBREAPER of prctl(2).
7 * 1) If PR_SET_CHILD_SUBREAPER marks a process as a child subreaper, it
8 * fulfills the role of init(1) for its descendant orphaned process.
9 * The PPID of its orphaned process will be reparented to the subreaper
10 * process, and the subreaper process can receive a SIGCHLD signal and
11 * wait(2) on the orphaned process to discover corresponding termination
12 * status.
13 * 2) The setting of PR_SET_CHILD_SUBREAPER is not inherited by children
14 * created by fork(2).
15 * 3) PR_GET_CHILD_SUBREAPER can get the setting of PR_SET_CHILD_SUBREAPER.
16 *
17 * These flags was added by kernel commit ebec18a6d3aa:
18 * "prctl: add PR_{SET,GET}_CHILD_SUBREAPER to allow simple process supervision"
19 */
20
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <sys/wait.h>
26 #include <signal.h>
27 #include <sys/prctl.h>
28
29 #include "tst_test.h"
30 #include "lapi/prctl.h"
31
32 static volatile int sigchild_recv;
33
check_get_subreaper(int exp_val)34 static void check_get_subreaper(int exp_val)
35 {
36 int get_val;
37
38 TEST(prctl(PR_GET_CHILD_SUBREAPER, &get_val));
39 if (TST_RET == -1) {
40 tst_res(TFAIL | TTERRNO, "prctl(PR_GET_CHILD_SUBREAPER) failed");
41 return;
42 }
43
44 if (get_val == exp_val) {
45 tst_res(TPASS, "prctl(PR_GET_CHILD_SUBREAPER) got expected %d",
46 get_val);
47 } else {
48 tst_res(TFAIL, "prctl(PR_GET_CHILD_SUBREAPER) got %d, expected %d",
49 get_val, exp_val);
50 }
51 }
52
verify_prctl(void)53 static void verify_prctl(void)
54 {
55 int status, ret;
56 pid_t pid;
57 pid_t ppid = getpid();
58
59 sigchild_recv = 0;
60
61 TEST(prctl(PR_SET_CHILD_SUBREAPER, 1));
62 if (TST_RET == -1) {
63 if (TST_ERR == EINVAL) {
64 tst_res(TCONF,
65 "prctl() doesn't support PR_SET_CHILD_SUBREAPER");
66 } else {
67 tst_res(TFAIL | TTERRNO,
68 "prctl(PR_SET_CHILD_SUBREAPER) failed");
69 }
70 return;
71 }
72
73 tst_res(TPASS, "prctl(PR_SET_CHILD_SUBREAPER) succeeded");
74
75 pid = SAFE_FORK();
76 if (!pid) {
77 pid_t cpid;
78
79 cpid = SAFE_FORK();
80 if (!cpid) {
81 TST_CHECKPOINT_WAIT(0);
82 if (getppid() != ppid) {
83 tst_res(TFAIL,
84 "PPID of orphaned process was not reparented");
85 exit(0);
86 }
87
88 tst_res(TPASS, "PPID of orphaned process was reparented");
89 exit(0);
90 }
91
92 check_get_subreaper(0);
93 exit(0);
94 }
95
96 SAFE_WAITPID(pid, NULL, 0);
97 TST_CHECKPOINT_WAKE(0);
98 ret = wait(&status);
99 if (ret > 0) {
100 tst_res(TPASS, "wait() got orphaned process, pid %d, status %d",
101 ret, status);
102 } else {
103 tst_res(TFAIL | TERRNO,
104 "wait() failed to get orphaned process");
105 }
106
107 if (sigchild_recv == 2)
108 tst_res(TPASS, "received SIGCHLD from orphaned process");
109 else
110 tst_res(TFAIL, "didn't receive SIGCHLD from orphaned process");
111
112 check_get_subreaper(1);
113 }
114
sighandler(int sig LTP_ATTRIBUTE_UNUSED)115 static void sighandler(int sig LTP_ATTRIBUTE_UNUSED)
116 {
117 sigchild_recv++;
118 }
119
setup(void)120 static void setup(void)
121 {
122 SAFE_SIGNAL(SIGCHLD, sighandler);
123 }
124
125 static struct tst_test test = {
126 .setup = setup,
127 .forks_child = 1,
128 .needs_checkpoints = 1,
129 .test_all = verify_prctl,
130 };
131