1 /*
2 * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 // tested api in this file: getpid getppid getpgrp setpgrp getpgid setpgid
17
18 #include <unistd.h>
19 #include <sys/types.h>
20 #include <sys/shm.h>
21 #include <gtest/gtest.h>
22 #include "log.h"
23 #include "utils.h"
24 #include "KernelConstants.h"
25
26 using namespace testing::ext;
27
28 class PidTest : public testing::Test {
29 protected:
30 const char* mChildELF = RES_DIR_KERNEL "process/executor";
31 };
32
33 /**
34 * @tc.number SUB_KERNEL_PM_PID_Getppid_0100
35 * @tc.name getpid and getppid test
36 * @tc.desc [C- SOFTWARE -0200]
37 */
HWTEST_F(PidTest, testGetPpid, Function | MediumTest | Level1)38 HWTEST_F(PidTest, testGetPpid, Function | MediumTest | Level1)
39 {
40 pid_t parentPid = getpid();
41 pid_t pid = fork();
42 ASSERT_TRUE(pid >= 0) << "======== Fork Error! =========";
43 if (pid == 0) { // child
44 pid_t pPid = getppid();
45 if (pPid != parentPid) {
46 LOG("getppid fail, expect:%d, but get:%d", parentPid, pPid);
47 exit(1);
48 }
49 exit(0);
50 } else { // parent
51 Msleep(20);
52 WaitProcExitedOK(pid);
53 }
54 }
55
56 /**
57 * @tc.number SUB_KERNEL_PM_PID_Getppid_0200
58 * @tc.name test that a orphaned process will inherite by init.
59 * @tc.desc [C- SOFTWARE -0200]
60 */
HWTEST_F(PidTest, testOrphanProcess, Function | MediumTest | Level1)61 HWTEST_F(PidTest, testOrphanProcess, Function | MediumTest | Level1)
62 {
63 const int retPass = 1;
64 const int retFail = 2;
65 const int memSize = 32;
66 int shmID = shmget(IPC_PRIVATE, memSize, 0666 | IPC_CREAT);
67 ASSERT_NE(shmID, -1) << "get share mem fail, errno = " << errno;
68 int *shared = (int*)(shmat(shmID, nullptr, 0));
69 ASSERT_NE(shared, reinterpret_cast<int*>(-1)) << "shmat fail, errno = " << errno;
70 shared[0] = retPass;
71 shared[1] = 0;
72
73 LOG("parent process id:%d", getpid());
74 pid_t pid = fork();
75 EXPECT_TRUE(pid >= 0) << "======== Fork Error! =========";
76 if (pid == 0) { // child
77 LOG("sub parent process id:%d", getpid());
78 pid_t pid2 = fork();
79 if (pid2 < 0) {
80 LOG("======== Fork Error! =========");
81 exit(1);
82 }
83
84 if (pid2 == 0) { // child
85 LOG("orphane process id:%d", getpid());
86 int *shmAddr = (int*)(shmat(shmID, nullptr, 0));
87 LOG("before while child child %d", shmAddr[1]);
88 while (shmAddr[1] != 1) {
89 Msleep(50);
90 }
91 LOG("after while child child %d", shmAddr[1]);
92 pid_t pPid = getppid();
93 if (pPid != 1) {
94 LOG("getppid orphaned process fail, expect:1, but get:%d", pPid);
95 // transfer result to main process
96 shmAddr[0] = retFail;
97 }
98 shmAddr[1] =2;
99 LOG("child child exit %d", shmAddr[1]);
100 shmdt(shmAddr);
101 exit(0);
102 } else { // sub parent
103 exit(0);
104 }
105 }
106 // parent
107 WaitProcExitedOK(pid);
108 shared[1] = 1;
109 Msleep(200);
110 EXPECT_EQ(shared[0], retPass);
111 LOG("before while paret %d", shared[1]);
112 while (shared[1] != 2) {
113 Msleep(50);
114 }
115 shmdt(shared);
116 shmctl(shmID, IPC_RMID, nullptr);
117 }
118
119 /**
120 * @tc.number SUB_KERNEL_PM_PID_SetGetPgrp_0100
121 * @tc.name setpgrp and getpgrp test
122 * @tc.desc [C- SOFTWARE -0200]
123 */
HWTEST_F(PidTest, testSetGetPgrp, Function | MediumTest | Level1)124 HWTEST_F(PidTest, testSetGetPgrp, Function | MediumTest | Level1)
125 {
126 pid_t parentPid = getpid();
127 int rt = setpgrp();
128 ASSERT_EQ(rt, 0);
129
130 pid_t pgid = getpgrp();
131 ASSERT_EQ(pgid, parentPid);
132
133 pid_t pid = fork();
134 ASSERT_TRUE(pid >= 0) << "======== Fork Error! =========";
135 if (pid == 0) { // child
136 pid_t childPgid = getpgrp();
137 if (childPgid != pgid) {
138 LOG("child getpgrp fail, expect:%d, but get:%d", pgid, childPgid);
139 exit(1);
140 }
141 exit(0);
142 } else { // parent
143 Msleep(20);
144 WaitProcExitedOK(pid);
145 }
146 }
147
148 /**
149 * @tc.number SUB_KERNEL_PM_PID_SetGetPgid_0100
150 * @tc.name setpgid and getpgid basic test
151 * @tc.desc [C- SOFTWARE -0200]
152 */
HWTEST_F(PidTest, testSetGetPgid, Function | MediumTest | Level1)153 HWTEST_F(PidTest, testSetGetPgid, Function | MediumTest | Level1)
154 {
155 pid_t parentPid = getpid();
156 int rt = setpgid(0, parentPid);
157 ASSERT_EQ(rt, 0);
158 rt = setpgid(0, 0);
159 ASSERT_EQ(rt, 0);
160
161 pid_t pgid = getpgid(0);
162 ASSERT_EQ(pgid, parentPid);
163
164 pid_t pid1 = fork();
165 ASSERT_TRUE(pid1 >= 0) << "======== Fork Error! =========";
166 if (pid1 == 0) { // child
167 pid_t childPgid = getpgid(0);
168 if (childPgid != pgid) {
169 LOG("child getpgid fail, expect:%d, but get:%d", pgid, childPgid);
170 exit(1);
171 }
172 Msleep(40);
173 childPgid = getpgid(0);
174 pid_t childPid = getpid();
175 if (childPgid != childPid) {
176 LOG("child new pgid check fail, pid=%d, pgid:%d", childPid, childPgid);
177 exit(1);
178 }
179 exit(0);
180 } else { // parent
181 Msleep(30);
182 rt = setpgid(pid1, pid1);
183 ASSERT_EQ(rt, 0);
184 pid_t pgid2 = getpgid(pid1);
185 ASSERT_EQ(pgid2, pid1);
186 Msleep(50);
187 WaitProcExitedOK(pid1);
188 }
189 }
190 /**
191 * @tc.number SUB_KERNEL_PM_PID_SetGetPgid_0200
192 * @tc.name setpgid and getpgid test for sibling process
193 * @tc.desc [C- SOFTWARE -0200]
194 */
HWTEST_F(PidTest, testSetGetSiblingPgid, Function | MediumTest | Level1)195 HWTEST_F(PidTest, testSetGetSiblingPgid, Function | MediumTest | Level1)
196 {
197 pid_t parentPid = getpid();
198 int rt = setpgid(0, parentPid);
199 ASSERT_EQ(rt, 0);
200 rt = setpgid(0, 0);
201 ASSERT_EQ(rt, 0);
202 pid_t pgid = getpgid(0);
203 ASSERT_EQ(pgid, parentPid);
204
205 pid_t pid1 = fork();
206 ASSERT_TRUE(pid1 >= 0) << "======== Fork Error! =========";
207 if (pid1 == 0) { // child1
208 Msleep(20);
209 exit(0);
210 } else { // parent
211 pid_t pid2 = fork();
212 ASSERT_TRUE(pid2 >= 0) << "======== Fork Error! =========";
213 if (pid2 == 0) { // child2
214 int exitCode = 0;
215 pid_t siblingPgid = getpgid(pid1);
216 if (siblingPgid != parentPid) {
217 LOG("child2: get sibling pgid fail, rt=%d, errno=%d", siblingPgid, errno);
218 exitCode = 1;
219 }
220 rt = setpgid(pid1, pid1);
221 if (rt != -1) {
222 LOG("child2: setpgid for sibling should fail");
223 exitCode = 1;
224 }
225 if (errno != ESRCH) {
226 LOG("child2: setpgid errno fail, expected %d, but get %d", ESRCH, errno);
227 exitCode = 1;
228 }
229 exit(exitCode);
230 }
231 // parent
232 Msleep(50);
233 WaitProcExitedOK(pid1);
234 WaitProcExitedOK(pid2);
235 }
236 }
237 /**
238 * @tc.number SUB_KERNEL_PM_PID_SetGetPgid_0300
239 * @tc.name getpgid fail test
240 * @tc.desc [C- SOFTWARE -0200]
241 */
HWTEST_F(PidTest, testGetpgidFail, Function | MediumTest | Level3)242 HWTEST_F(PidTest, testGetpgidFail, Function | MediumTest | Level3)
243 {
244 pid_t pgid = getpgid(-1);
245 EXPECT_EQ(pgid, -1);
246 EXPECT_EQ(errno, EINVAL);
247
248 pgid = getpgid(-1000001);
249 EXPECT_EQ(pgid, -1);
250 EXPECT_EQ(errno, EINVAL);
251
252 pid_t nonExitPid = GetNonExistPid(); // valid but not exist pid
253 if (nonExitPid != -1) {
254 pgid = getpgid(nonExitPid);
255 EXPECT_EQ(pgid, -1);
256 EXPECT_EQ(errno, ESRCH);
257 }
258
259 pgid = getpgid(MAX_PROCESS_NUMBER + 1);
260 EXPECT_EQ(pgid, -1);
261 EXPECT_EQ(errno, EINVAL);
262
263 pgid = getpgid(100000);
264 EXPECT_EQ(pgid, -1);
265 EXPECT_EQ(errno, EINVAL);
266
267 pgid = getpgid(1);
268 EXPECT_EQ(pgid, 1) << "get init process-groups-ID fail\n";
269 }
270
271 /**
272 * @tc.number SUB_KERNEL_PM_PID_SetGetPgid_0400
273 * @tc.name setpgid fail test
274 * @tc.desc [C- SOFTWARE -0200]
275 */
HWTEST_F(PidTest, testSetpgidFail, Function | MediumTest | Level3)276 HWTEST_F(PidTest, testSetpgidFail, Function | MediumTest | Level3)
277 {
278 pid_t pid = getpid();
279 int rt = setpgrp();
280 ASSERT_EQ(rt, 0);
281
282 LOG("invalid pid test...");
283 rt = setpgid(-1, 0);
284 EXPECT_EQ(rt, -1);
285 EXPECT_EQ(errno, EINVAL);
286
287 rt = setpgid(-1000001, 0);
288 EXPECT_EQ(rt, -1);
289 EXPECT_EQ(errno, EINVAL);
290
291 pid_t nonExitPid = GetNonExistPid(); // valid but not exist pid
292 if (nonExitPid != -1) {
293 rt = setpgid(nonExitPid, 0);
294 EXPECT_EQ(rt, -1);
295 EXPECT_EQ(errno, ESRCH);
296 }
297
298 rt = setpgid(MAX_PROCESS_NUMBER + 1, 0);
299 EXPECT_EQ(rt, -1);
300 EXPECT_EQ(errno, EINVAL);
301
302 rt = setpgid(100000, 0);
303 EXPECT_EQ(rt, -1);
304 EXPECT_EQ(errno, EINVAL);
305
306 rt = setpgid(1, pid); // init
307 EXPECT_EQ(rt, -1);
308 EXPECT_EQ(errno, EPERM);
309
310 rt = setpgid(2, pid); // kProcess
311 EXPECT_EQ(rt, -1);
312 EXPECT_EQ(errno, EPERM);
313
314 LOG("invalid pgid test...");
315 rt = setpgid(0, -1);
316 EXPECT_EQ(rt, -1);
317 EXPECT_EQ(errno, EINVAL);
318
319 nonExitPid = GetNonExistPid(); // valid but not exist pid
320 if (nonExitPid != -1) {
321 rt = setpgid(0, nonExitPid);
322 EXPECT_EQ(rt, -1);
323 EXPECT_EQ(errno, EPERM);
324 }
325
326 rt = setpgid(0, 10001);
327 EXPECT_EQ(rt, -1);
328 EXPECT_EQ(errno, EINVAL);
329
330 rt = setpgid(0, 1); // init
331 EXPECT_EQ(rt, -1);
332 EXPECT_EQ(errno, EPERM);
333
334 rt = setpgid(0, 2); // kProcess
335 EXPECT_EQ(rt, -1);
336 EXPECT_EQ(errno, EPERM);
337 }
338
339 /**
340 * @tc.number SUB_KERNEL_PM_PID_SetGetPgid_0500
341 * @tc.name setpgid fail test: EACCES
342 * @tc.desc [C- SOFTWARE -0200]
343 */
HWTEST_F(PidTest, testSetpgidFailEACCES, Function | MediumTest | Level3)344 HWTEST_F(PidTest, testSetpgidFailEACCES, Function | MediumTest | Level3)
345 {
346 pid_t pid = fork();
347 ASSERT_TRUE(pid >= 0) << "======== Fork Error! =========";
348 if (pid == 0) { // child
349 int rt = execve(mChildELF, NULL, NULL);
350 if (rt == -1) {
351 LOG("ERROR: execve return -1, errno=%d, err=%s\n", errno, strerror(errno));
352 }
353 exit(1);
354 } else { // parent
355 sleep(2);
356 AssertProcAlive(pid);
357 int rt = setpgid(pid, pid);
358 EXPECT_EQ(rt, -1) << "setpgid should fail after child execve.";
359 EXPECT_EQ(errno, EACCES) << "set errno fail.";
360
361 // recycle child
362 int status;
363 waitpid(pid, &status, 0);
364 }
365 }
366