55dd522e61429a16d043eb851efc7cb459487804
[platform/core/test/security-tests.git] / src / security-manager-tests / common / sm_commons.cpp
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16
17 #include <algorithm>
18 #include <cstring>
19 #include <ftw.h>
20 #include <grp.h>
21 #include <string>
22 #include <sys/capability.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 #include <cstdlib>
27
28 #include <unordered_set>
29 #include <vector>
30
31 #include <security-manager-types.h>
32 #include <sys/smack.h>
33
34 #include <cynara_test_client.h>
35 #include <dpl/test/test_runner.h>
36 #include <memory.h>
37 #include <sm_api.h>
38 #include <sm_commons.h>
39 #include <sm_db.h>
40 #include <synchronization_pipe.h>
41 #include <sm_request.h>
42 #include <tests_common.h>
43 #include "tzplatform.h"
44
45 using namespace SecurityManagerTest;
46
47 // Common const values
48
49 const privileges_t SM_ALLOWED_PRIVILEGES = {
50     "http://tizen.org/privilege/display",
51     "http://tizen.org/privilege/nfc"
52 };
53
54 const privileges_t SM_DENIED_PRIVILEGES  = {
55     "http://tizen.org/privilege/bluetooth",
56     "http://tizen.org/privilege/power"
57 };
58
59 const privileges_t SM_NO_PRIVILEGES  = {
60 };
61
62 const std::vector<std::string> SM_ALLOWED_GROUPS = {"db_browser", "db_alarm"};
63
64 const std::string uidToStr(const uid_t uid)
65 {
66     return std::to_string(static_cast<unsigned int>(uid));
67 }
68
69 // Common implementation details
70
71 std::string generateProcessLabel(const std::string &appId, const std::string &pkgId, bool isHybrid)
72 {
73     std::string label = "User::Pkg::" + pkgId;
74     if (isHybrid) {
75         label += "::App::" + appId;
76     }
77     return label;
78 }
79
80 std::string generatePathRWLabel(const std::string &pkgId)
81 {
82     return "User::Pkg::" + pkgId;
83 }
84
85 std::string generatePathROLabel(const std::string &pkgId)
86 {
87     return generatePathRWLabel(pkgId) + "::RO";
88 }
89
90 std::string getPublicPathLabel()
91 {
92     return "User::Home";
93 }
94
95 static std::string genPath(int app_num, const char *postfix) {
96     char buf[16];
97     sprintf(buf, "%02d", app_num);
98     return TzPlatformConfig::globalAppDir() + "/sm_test_" + std::string(buf) + "_pkg_id_full/" + std::string(postfix);
99 }
100
101 std::string genRWPath(int app_num) {
102     return genPath(app_num, "app_dir");
103 }
104 std::string genROPath(int app_num) {
105     return genPath(app_num, "app_dir_ro");
106 }
107 std::string genPublicROPath(int app_num) {
108     return genPath(app_num, "app_dir_public_ro");
109 }
110
111 std::string genOwnerRWOthersROPath(int app_num) {
112     return genPath(app_num, "app_dir_rw_others_ro");
113 }
114
115 static std::string generatePkgLabelOwnerRWothersRO(const std::string &pkgId)
116 {
117     return "User::Pkg::" + pkgId + "::SharedRO";
118 }
119
120 // Common DB/nftw checks
121
122 // nftw doesn't allow passing user data to functions. Work around by using global variable
123 static std::string nftw_expected_label;
124 bool nftw_expected_transmute;
125 bool nftw_expected_exec;
126
127 static int nftw_check_sm_labels_app_dir(const char *fpath, const struct stat *sb,
128                               const char* correctLabel, bool transmute_test, bool exec_test)
129 {
130     int result;
131     CStringPtr labelPtr;
132     char* label = nullptr;
133
134     /* ACCESS */
135     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_ACCESS);
136     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
137     labelPtr.reset(label);
138     RUNNER_ASSERT_MSG(label != nullptr, "ACCESS label on " << fpath << " is not set");
139     result = strcmp(correctLabel, label);
140     RUNNER_ASSERT_MSG(result == 0, "ACCESS label on " << fpath << " is incorrect"
141             " (should be '" << correctLabel << "' and is '" << label << "')");
142
143
144     /* EXEC */
145     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_EXEC);
146     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
147     labelPtr.reset(label);
148
149     if (S_ISREG(sb->st_mode) && (sb->st_mode & S_IXUSR) && exec_test) {
150         RUNNER_ASSERT_MSG(label != nullptr, "EXEC label on " << fpath << " is not set");
151         result = strcmp(correctLabel, label);
152         RUNNER_ASSERT_MSG(result == 0, "Incorrect EXEC label on executable file " << fpath);
153     } else
154         RUNNER_ASSERT_MSG(label == nullptr, "EXEC label on " << fpath << " is set");
155
156
157     /* TRANSMUTE */
158     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_TRANSMUTE);
159     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
160     labelPtr.reset(label);
161
162     if (S_ISDIR(sb->st_mode) && transmute_test == true) {
163         RUNNER_ASSERT_MSG(label != nullptr, "TRANSMUTE label on " << fpath << " is not set at all");
164         RUNNER_ASSERT_MSG(strcmp(label,"TRUE") == 0,
165                 "TRANSMUTE label on " << fpath << " is not set properly: '"<<label<<"'");
166     } else {
167         RUNNER_ASSERT_MSG(label == nullptr, "TRANSMUTE label on " << fpath << " is set");
168     }
169
170     return 0;
171 }
172
173 static int nftw_check_sm_labels(const char *fpath, const struct stat *sb,
174                                int /*typeflag*/, struct FTW* /*ftwbuf*/)
175 {
176     return nftw_check_sm_labels_app_dir(fpath, sb,
177         nftw_expected_label.c_str(), nftw_expected_transmute, nftw_expected_exec);
178 }
179
180 int nftw_check_labels_non_app_dir(const char *fpath, const struct stat* /*sb*/,
181                                   int /*typeflag*/, struct FTW* /*ftwbuf*/)
182 {
183     int result;
184     CStringPtr labelPtr;
185     char* label = nullptr;
186
187     /* ACCESS */
188     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_ACCESS);
189     labelPtr.reset(label);
190     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
191     result = strcmp("canary_label", labelPtr.get());
192     RUNNER_ASSERT_MSG(result == 0, "ACCESS label on " << fpath << " is overwritten");
193
194     /* EXEC */
195     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_EXEC);
196     labelPtr.reset(label);
197     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
198     result = strcmp("canary_label", labelPtr.get());
199     RUNNER_ASSERT_MSG(result == 0, "EXEC label on " << fpath << " is overwritten");
200
201     /* TRANSMUTE */
202     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_TRANSMUTE);
203     labelPtr.reset(label);
204     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
205     RUNNER_ASSERT_MSG(labelPtr.get() == nullptr, "TRANSMUTE label on " << fpath << " is set");
206
207     return 0;
208 }
209
210 static int nftw_set_labels_non_app_dir(const char *fpath, const struct stat* /*sb*/,
211                                 int /*typeflag*/, struct FTW* /*ftwbuf*/)
212 {
213     smack_lsetlabel(fpath, "canary_label", SMACK_LABEL_ACCESS);
214     smack_lsetlabel(fpath, "canary_label", SMACK_LABEL_EXEC);
215     smack_lsetlabel(fpath, nullptr, SMACK_LABEL_TRANSMUTE);
216
217     return 0;
218 }
219
220 int nftw_remove_labels(const char *fpath, const struct stat* /*sb*/,
221                        int /*typeflag*/, struct FTW* /*ftwbuf*/)
222 {
223     smack_lsetlabel(fpath, nullptr, SMACK_LABEL_ACCESS);
224     smack_lsetlabel(fpath, nullptr, SMACK_LABEL_EXEC);
225     smack_lsetlabel(fpath, nullptr, SMACK_LABEL_TRANSMUTE);
226
227     return 0;
228 }
229
230 static const std::string SM_DENIED_PATH = TzPlatformConfig::globalAppDir() + "/non_app_dir";
231
232 void check_app_permissions(const std::string &app_id, const std::string &pkg_id,
233                            const std::string &user, const privileges_t &allowed_privs,
234                            const privileges_t &denied_privs, bool isHybrid)
235 {
236     (void) pkg_id;
237     std::string smackLabel = generateProcessLabel(app_id, pkg_id, isHybrid);
238
239     CynaraTestClient::Client ctc;
240
241     for (auto &priv : allowed_privs) {
242         ctc.check(smackLabel.c_str(), "", user, priv.c_str(), CYNARA_API_ACCESS_ALLOWED);
243     }
244
245     for (auto &priv : denied_privs) {
246         ctc.check(smackLabel.c_str(), "", user, priv.c_str(), CYNARA_API_ACCESS_DENIED);
247     }
248 }
249
250
251 void check_app_after_install(const std::string &app_id, const std::string &pkg_id)
252 {
253     TestSecurityManagerDatabase dbtest;
254     dbtest.test_db_after__app_install(app_id, pkg_id);
255 }
256
257 static void check_app_gids(const std::string &app_id, const std::vector<gid_t> &allowed_gids)
258 {
259     int ret;
260     gid_t main_gid = getgid();
261     std::unordered_set<gid_t> reference_gids(allowed_gids.begin(), allowed_gids.end());
262
263     // Reset supplementary groups
264     ret = setgroups(0, NULL);
265     RUNNER_ASSERT_MSG(ret != -1, "Unable to set supplementary groups");
266
267     Api::setProcessGroups(app_id);
268
269     ret = getgroups(0, nullptr);
270     RUNNER_ASSERT_MSG(ret != -1, "Unable to get supplementary groups");
271
272     std::vector<gid_t> actual_gids(ret);
273     ret = getgroups(ret, actual_gids.data());
274     RUNNER_ASSERT_MSG(ret != -1, "Unable to get supplementary groups");
275
276     for (const auto &gid : actual_gids) {
277         RUNNER_ASSERT_MSG(gid == main_gid || reference_gids.count(gid) > 0,
278             "Application shouldn't get access to group " << gid);
279         reference_gids.erase(gid);
280     }
281
282     RUNNER_ASSERT_MSG(reference_gids.empty(), "Application didn't get access to some groups");
283 }
284
285 static const char *const ANY_USER_REPRESENTATION = "anyuser";/*this may be actually any string*/
286
287 void check_app_after_install(const std::string &app_id, const std::string &pkg_id,
288                              const privileges_t &allowed_privs,
289                              const privileges_t &denied_privs,
290                              const std::vector<std::string> &allowed_groups,
291                              bool isHybrid)
292 {
293     TestSecurityManagerDatabase dbtest;
294     dbtest.test_db_after__app_install(app_id, pkg_id);
295
296     /*Privileges should be granted to all users if root installs app*/
297     check_app_permissions(app_id, pkg_id, ANY_USER_REPRESENTATION, allowed_privs, denied_privs, isHybrid);
298
299     /* Setup mapping of gids to privileges */
300     /* Do this for each privilege for extra check */
301     for (const auto &privilege : allowed_privs) {
302         dbtest.setup_privilege_groups(privilege, allowed_groups);
303     }
304
305     std::vector<gid_t> allowed_gids;
306
307     for (const auto &groupName : allowed_groups) {
308         errno = 0;
309         struct group* grp = getgrnam(groupName.c_str());
310         RUNNER_ASSERT_ERRNO_MSG(grp, "Group: " << groupName << " not found");
311         allowed_gids.push_back(grp->gr_gid);
312     }
313
314     check_app_gids(app_id, allowed_gids);
315 }
316
317 void check_path(const std::string &path, const std::string &label) {
318     nftw_expected_label = label;
319     nftw_expected_transmute = true;
320     nftw_expected_exec = false;
321
322     // check labels
323     int result = nftw(path.c_str(), &nftw_check_sm_labels, FTW_MAX_FDS, FTW_PHYS);
324     RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for " << path);
325 }
326
327 void check_app_path_after_install(int app_num, const char *pkgId, bool others_enabled)
328 {
329     std::string SM_RW_PATH = genRWPath(app_num);
330     std::string SM_RO_PATH = genROPath(app_num);
331     std::string SM_PUBLIC_RO_PATH = genPublicROPath(app_num);
332     int result;
333
334     nftw_expected_label = generatePathRWLabel(pkgId);
335     nftw_expected_transmute = true;
336     nftw_expected_exec = false;
337
338     result = nftw(SM_RW_PATH.c_str(), &nftw_check_sm_labels, FTW_MAX_FDS, FTW_PHYS);
339     RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for " << SM_RW_PATH);
340
341     nftw_expected_label = generatePathRWLabel(pkgId) + "::RO";
342     nftw_expected_transmute = false;
343     nftw_expected_exec = false;
344
345     result = nftw(SM_RO_PATH.c_str(), &nftw_check_sm_labels, FTW_MAX_FDS, FTW_PHYS);
346     RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for " << SM_RO_PATH);
347
348     nftw_expected_label = "User::Home";
349     nftw_expected_transmute = true;
350     nftw_expected_exec = false;
351
352     result = nftw(SM_PUBLIC_RO_PATH.c_str(), &nftw_check_sm_labels, FTW_MAX_FDS, FTW_PHYS);
353     RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for " << SM_PUBLIC_RO_PATH);
354
355     result = nftw(SM_DENIED_PATH.c_str(), &nftw_check_labels_non_app_dir, FTW_MAX_FDS, FTW_PHYS);
356     RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for " << SM_DENIED_PATH);
357
358     // owner RW, others RO
359     if(others_enabled) {
360         std::string SM_OWNER_RW_OTHERS_RO_PATH = genOwnerRWOthersROPath(app_num);
361         nftw_expected_label = generatePkgLabelOwnerRWothersRO(pkgId);
362         nftw_expected_transmute = true;
363         nftw_expected_exec = false;
364
365         result = nftw(SM_OWNER_RW_OTHERS_RO_PATH.c_str(), &nftw_check_sm_labels, FTW_MAX_FDS, FTW_PHYS);
366         RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for " << SM_OWNER_RW_OTHERS_RO_PATH);
367     }
368 }
369
370 void check_app_after_uninstall(const std::string &app_id, const std::string &pkg_id,
371                                const bool is_pkg_removed)
372 {
373     TestSecurityManagerDatabase dbtest;
374     dbtest.test_db_after__app_uninstall(app_id, pkg_id, is_pkg_removed);
375 }
376
377 void check_app_after_uninstall(const std::string &app_id, const std::string &pkg_id,
378                                const privileges_t &privileges, const bool is_pkg_removed,
379                                bool isHybrid)
380 {
381     TestSecurityManagerDatabase dbtest;
382     dbtest.test_db_after__app_uninstall(app_id, pkg_id, is_pkg_removed);
383
384
385     /*Privileges should not be granted anymore to any user*/
386     check_app_permissions(app_id, pkg_id, ANY_USER_REPRESENTATION, SM_NO_PRIVILEGES, privileges, isHybrid);
387 }
388
389 std::string access_opposite(std::string &access) {
390     static const std::map<char, int> access_mapping = {{'r', 0}, {'w', 1}, {'x', 2}, {'a', 3},
391                                                        {'t', 4}, {'l', 5}};
392     //May write implies may lock
393     if (access.find('w') != std::string::npos && access.find('l') == std::string::npos) {
394         access.append("l");
395     }
396     std::string access_opposite = "rwxatl";
397     for (char c : access) {
398         access_opposite[access_mapping.at(c)] = '-';
399     }
400     auto it = std::remove_if(access_opposite.begin(), access_opposite.end(), [](char c) {return c == '-';});
401     access_opposite.erase(it, access_opposite.end());
402     return access_opposite;
403 }
404
405 void check_exact_smack_accesses(const std::string &subject, const std::string &object,
406                                 const std::string &access) {
407     std::string access_str(access);
408     auto no_access = access_opposite(access_str);
409     for (char c : access_str) {
410         int ret = smack_have_access(subject.c_str(), object.c_str(), std::string(1, c).c_str());
411         RUNNER_ASSERT_MSG(ret >= 0, "smack_have_access failed: <" << subject << ">, <" << object
412                           << ">, <" << c << "> errno=" << strerror(errno));
413         RUNNER_ASSERT_MSG(ret == 1, "Access " << c << " from " << subject << " to "
414                           << object << " not given");
415     }
416
417     for (char c : no_access) {
418         int ret = smack_have_access(subject.c_str(), object.c_str(), std::string(1, c).c_str());
419         RUNNER_ASSERT_MSG(ret >= 0, "smack_have_access failed: <" << subject << ">, <" << object
420                           << ">, <" << c << "> errno=" << strerror(errno));
421         RUNNER_ASSERT_MSG(ret == 0, "Access " << c << " from " << subject << " to "
422                           << object << " unnecessarily given");
423     }
424 }
425
426 CapsSetsUniquePtr setCaps(const char *cap_string)
427 {
428     CapsSetsUniquePtr caps(cap_init());
429     caps.reset(cap_from_text(cap_string));
430     RUNNER_ASSERT_MSG(caps, "can't convert capabilities from text");
431     int result = cap_set_proc(caps.get());
432     RUNNER_ASSERT_MSG(result == 0, "can't set capabilities. Result: " << result);
433     return caps;
434 }
435
436 static void prepare_app_path(int app_num, bool others_enabled = false)
437 {
438     std::string SM_RW_PATH = genRWPath(app_num);
439     std::string SM_RO_PATH = genROPath(app_num);
440     std::string SM_PUBLIC_RO_PATH = genPublicROPath(app_num);
441     int result;
442
443     result = nftw(SM_RW_PATH.c_str(), &nftw_remove_labels, FTW_MAX_FDS, FTW_PHYS);
444     RUNNER_ASSERT_MSG(result == 0, "Unable to clean Smack labels in " << SM_RW_PATH);
445
446     result = nftw(SM_RO_PATH.c_str(), &nftw_remove_labels, FTW_MAX_FDS, FTW_PHYS);
447     RUNNER_ASSERT_MSG(result == 0, "Unable to clean Smack labels in " << SM_RO_PATH);
448
449     result = nftw(SM_PUBLIC_RO_PATH.c_str(), &nftw_remove_labels, FTW_MAX_FDS, FTW_PHYS);
450     RUNNER_ASSERT_MSG(result == 0, "Unable to clean Smack labels in " << SM_PUBLIC_RO_PATH);
451
452     if(others_enabled) {
453         std::string SM_OWNER_RW_OTHERS_RO_PATH = genOwnerRWOthersROPath(app_num);
454         result = nftw(SM_OWNER_RW_OTHERS_RO_PATH.c_str(), &nftw_remove_labels, FTW_MAX_FDS, FTW_PHYS);
455         RUNNER_ASSERT_MSG(result == 0, "Unable to clean Smack labels in " << SM_OWNER_RW_OTHERS_RO_PATH);
456     }
457
458     result = nftw(SM_DENIED_PATH.c_str(), &nftw_set_labels_non_app_dir, FTW_MAX_FDS, FTW_PHYS);
459     RUNNER_ASSERT_MSG(result == 0, "Unable to set Smack labels in " << SM_DENIED_PATH);
460 }
461
462 void prepare_app_env(int app_num, bool others_enabled)
463 {
464     prepare_app_path(app_num, others_enabled);
465 }
466
467 void install_app(const std::string &app_id, const std::string &pkg_id, uid_t uid, app_install_type type,
468                  bool check_after)
469 {
470     InstallRequest request;
471     request.setAppId(app_id);
472     request.setPkgId(pkg_id);
473     request.setUid(uid);
474     if (type != SM_APP_INSTALL_NONE)
475         request.setInstallType(type);
476     Api::install(request);
477
478     if (check_after)
479         check_app_after_install(app_id, pkg_id);
480 }
481
482 void uninstall_app(const std::string &app_id, const std::string &pkg_id, bool expect_pkg_removed,
483                    app_install_type type, bool check_after)
484 {
485     InstallRequest request;
486     request.setAppId(app_id);
487     if (type != SM_APP_INSTALL_NONE)
488         request.setInstallType(type);
489     Api::uninstall(request);
490
491     if (check_after)
492         check_app_after_uninstall(app_id, pkg_id, expect_pkg_removed);
493 }
494
495 static const std::string EXEC_FILE("exec");
496 static const std::string NORMAL_FILE("normal");
497 static const std::string LINK_PREFIX("link_to_");
498
499 static void createTestDir(const std::string &dir)
500 {
501     mode_t dirMode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
502     mode_t execFileMode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
503     mode_t normalFileMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
504
505     mktreeSafe(dir, dirMode);
506     creatSafe(dir + "/" + EXEC_FILE, execFileMode);
507     creatSafe(dir + "/" + NORMAL_FILE, normalFileMode);
508     symlinkSafe(dir + "/" + EXEC_FILE, dir + "/" + LINK_PREFIX + EXEC_FILE);
509     symlinkSafe(dir + "/" + NORMAL_FILE, dir + "/" + LINK_PREFIX + NORMAL_FILE);
510 }
511
512 static void createInnerAppDir(const std::string &dir, const std::string &nonAppDir)
513 {
514     createTestDir(dir);
515
516     symlinkSafe(nonAppDir, dir + "/" + LINK_PREFIX + "non_app_dir");
517     symlinkSafe(nonAppDir + "/" + EXEC_FILE,
518                 dir + "/" + LINK_PREFIX + "non_app_" + EXEC_FILE);
519     symlinkSafe(nonAppDir + "/" + NORMAL_FILE,
520                 dir + "/" + LINK_PREFIX + "non_app_" + NORMAL_FILE);
521 }
522
523 static const std::string nonAppDirPath(const TemporaryTestUser &user)
524 {
525     return TMP_DIR + "/" + user.getUserName();
526 }
527
528 static void generateAppDir(const TemporaryTestUser &user,
529        const std::string &appId, const std::string &pkgId)
530 {
531     const std::string dir = TzPlatformConfig::appDirPath(user, appId, pkgId);
532     const std::string nonAppDir = nonAppDirPath(user);
533
534     createInnerAppDir(dir, nonAppDir);
535     createInnerAppDir(dir + "/.inner_dir", nonAppDir);
536     createInnerAppDir(dir + "/inner_dir", nonAppDir);
537 }
538
539 static void generateNonAppDir(const TemporaryTestUser &user)
540 {
541     const std::string dir = nonAppDirPath(user);
542
543     createTestDir(dir);
544     createTestDir(dir + "/.inner_dir");
545     createTestDir(dir + "/inner_dir");
546 }
547
548 void createTestDirs(const TemporaryTestUser &user,
549                     const std::string &appId, const std::string &pkgId)
550 {
551     generateAppDir(user, appId, pkgId);
552     generateNonAppDir(user);
553 }
554
555 void removeTestDirs(const TemporaryTestUser &user,
556                     const std::string &appId, const std::string &pkgId)
557 {
558     removeDir(TzPlatformConfig::appDirPath(user, appId, pkgId));
559     removeDir(nonAppDirPath(user));
560 }
561
562 pid_t runInChild(const std::function<void(void)> &process) {
563     pid_t pid = fork();
564     RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "fork failed");
565
566     if (pid == 0) {
567         process();
568         exit(EXIT_SUCCESS);
569     }
570     return pid;
571 }
572
573 void runInChildParentWait(const std::function<void(void)> &process) {
574     SynchronizationPipe pipe;
575     pid_t pid = fork();
576     RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "fork failed");
577
578     if (pid == 0) {
579         pipe.claimChildEp();
580
581         process();
582
583         pipe.post();
584         exit(EXIT_SUCCESS);
585     } else {
586         pipe.claimParentEp();
587         pipe.wait();
588     }
589 }