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