586d82562b7b328361223fd5575114a4eaad8ab1
[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 generatePathSharedROLabel(const std::string &pkgId)
91 {
92     return generatePathRWLabel(pkgId) + "::SharedRO";
93 }
94
95 std::string generatePathTrustedLabel(int64_t authorId)
96 {
97     return "User::Author::" + std::to_string(authorId);
98 }
99
100 std::string getPublicPathLabel()
101 {
102     return "User::Home";
103 }
104
105 static std::string genPath(int app_num, const char *postfix) {
106     char buf[16];
107     sprintf(buf, "%02d", app_num);
108     return TzPlatformConfig::globalAppDir() + "/sm_test_" + std::string(buf) + "_pkg_id_full/" + std::string(postfix);
109 }
110
111 std::string genRWPath(int app_num) {
112     return genPath(app_num, "app_dir");
113 }
114 std::string genROPath(int app_num) {
115     return genPath(app_num, "app_dir_ro");
116 }
117 std::string genPublicROPath(int app_num) {
118     return genPath(app_num, "app_dir_public_ro");
119 }
120
121 std::string genOwnerRWOthersROPath(int app_num) {
122     return genPath(app_num, "app_dir_rw_others_ro");
123 }
124
125 static std::string generatePkgLabelOwnerRWothersRO(const std::string &pkgId)
126 {
127     return "User::Pkg::" + pkgId + "::SharedRO";
128 }
129
130 // Common DB/nftw checks
131
132 // nftw doesn't allow passing user data to functions. Work around by using global variable
133 static std::string nftw_expected_label;
134 bool nftw_expected_transmute;
135 bool nftw_expected_exec;
136
137 static int nftw_check_sm_labels_app_dir(const char *fpath, const struct stat *sb,
138                               const char* correctLabel, bool transmute_test, bool exec_test)
139 {
140     int result;
141     CStringPtr labelPtr;
142     char* label = nullptr;
143
144     /* ACCESS */
145     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_ACCESS);
146     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
147     labelPtr.reset(label);
148     RUNNER_ASSERT_MSG(label != nullptr, "ACCESS label on " << fpath << " is not set");
149     result = strcmp(correctLabel, label);
150     RUNNER_ASSERT_MSG(result == 0, "ACCESS label on " << fpath << " is incorrect"
151             " (should be '" << correctLabel << "' and is '" << label << "')");
152
153
154     /* EXEC */
155     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_EXEC);
156     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
157     labelPtr.reset(label);
158
159     if (S_ISREG(sb->st_mode) && (sb->st_mode & S_IXUSR) && exec_test) {
160         RUNNER_ASSERT_MSG(label != nullptr, "EXEC label on " << fpath << " is not set");
161         result = strcmp(correctLabel, label);
162         RUNNER_ASSERT_MSG(result == 0, "Incorrect EXEC label on executable file " << fpath);
163     } else
164         RUNNER_ASSERT_MSG(label == nullptr, "EXEC label on " << fpath << " is set");
165
166
167     /* TRANSMUTE */
168     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_TRANSMUTE);
169     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
170     labelPtr.reset(label);
171
172     if (S_ISDIR(sb->st_mode) && transmute_test == true) {
173         RUNNER_ASSERT_MSG(label != nullptr, "TRANSMUTE label on " << fpath << " is not set at all");
174         RUNNER_ASSERT_MSG(strcmp(label,"TRUE") == 0,
175                 "TRANSMUTE label on " << fpath << " is not set properly: '"<<label<<"'");
176     } else {
177         RUNNER_ASSERT_MSG(label == nullptr, "TRANSMUTE label on " << fpath << " is set");
178     }
179
180     return 0;
181 }
182
183 static int nftw_check_sm_labels(const char *fpath, const struct stat *sb,
184                                int /*typeflag*/, struct FTW* /*ftwbuf*/)
185 {
186     return nftw_check_sm_labels_app_dir(fpath, sb,
187         nftw_expected_label.c_str(), nftw_expected_transmute, nftw_expected_exec);
188 }
189
190 int nftw_check_labels_non_app_dir(const char *fpath, const struct stat* /*sb*/,
191                                   int /*typeflag*/, struct FTW* /*ftwbuf*/)
192 {
193     int result;
194     CStringPtr labelPtr;
195     char* label = nullptr;
196
197     /* ACCESS */
198     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_ACCESS);
199     labelPtr.reset(label);
200     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
201     result = strcmp("canary_label", labelPtr.get());
202     RUNNER_ASSERT_MSG(result == 0, "ACCESS label on " << fpath << " is overwritten");
203
204     /* EXEC */
205     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_EXEC);
206     labelPtr.reset(label);
207     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
208     result = strcmp("canary_label", labelPtr.get());
209     RUNNER_ASSERT_MSG(result == 0, "EXEC label on " << fpath << " is overwritten");
210
211     /* TRANSMUTE */
212     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_TRANSMUTE);
213     labelPtr.reset(label);
214     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
215     RUNNER_ASSERT_MSG(labelPtr.get() == nullptr, "TRANSMUTE label on " << fpath << " is set");
216
217     return 0;
218 }
219
220 static int nftw_set_labels_non_app_dir(const char *fpath, const struct stat* /*sb*/,
221                                 int /*typeflag*/, struct FTW* /*ftwbuf*/)
222 {
223     smack_lsetlabel(fpath, "canary_label", SMACK_LABEL_ACCESS);
224     smack_lsetlabel(fpath, "canary_label", SMACK_LABEL_EXEC);
225     smack_lsetlabel(fpath, nullptr, SMACK_LABEL_TRANSMUTE);
226
227     return 0;
228 }
229
230 int nftw_remove_labels(const char *fpath, const struct stat* /*sb*/,
231                        int /*typeflag*/, struct FTW* /*ftwbuf*/)
232 {
233     smack_lsetlabel(fpath, nullptr, SMACK_LABEL_ACCESS);
234     smack_lsetlabel(fpath, nullptr, SMACK_LABEL_EXEC);
235     smack_lsetlabel(fpath, nullptr, SMACK_LABEL_TRANSMUTE);
236
237     return 0;
238 }
239
240 static const std::string SM_DENIED_PATH = TzPlatformConfig::globalAppDir() + "/non_app_dir";
241
242 void check_app_permissions(const std::string &app_id, const std::string &pkg_id,
243                            const std::string &user, const privileges_t &allowed_privs,
244                            const privileges_t &denied_privs, bool isHybrid)
245 {
246     (void) pkg_id;
247     std::string smackLabel = generateProcessLabel(app_id, pkg_id, isHybrid);
248
249     CynaraTestClient::Client ctc;
250
251     for (auto &priv : allowed_privs) {
252         ctc.check(smackLabel.c_str(), "", user, priv.c_str(), CYNARA_API_ACCESS_ALLOWED);
253     }
254
255     for (auto &priv : denied_privs) {
256         ctc.check(smackLabel.c_str(), "", user, priv.c_str(), CYNARA_API_ACCESS_DENIED);
257     }
258 }
259
260 void sm_app_has_privileges(const AppInstallHelper &app,
261                            const std::vector<std::string> &privileges,
262                            int expectedResult)
263 {
264     for (auto const &privilege : privileges) {
265         int result;
266         Api::appHasPrivilege(app.getAppId(), privilege, app.getUID(), result);
267         RUNNER_ASSERT_MSG(result == expectedResult, "Application " << app.getAppId()
268                           << " has unexpected access to " << privilege << ", is : "
269                           << " should be : " << expectedResult );
270     }
271 }
272
273 void check_app_after_install(const std::string &app_id, const std::string &pkg_id)
274 {
275     TestSecurityManagerDatabase dbtest;
276     dbtest.test_db_after__app_install(app_id, pkg_id);
277 }
278
279 static void check_app_gids(const std::string &app_id, const std::vector<gid_t> &allowed_gids)
280 {
281     int ret;
282     gid_t main_gid = getgid();
283     std::unordered_set<gid_t> reference_gids(allowed_gids.begin(), allowed_gids.end());
284
285     // Reset supplementary groups
286     ret = setgroups(0, NULL);
287     RUNNER_ASSERT_MSG(ret != -1, "Unable to set supplementary groups");
288
289     Api::setProcessGroups(app_id);
290
291     ret = getgroups(0, nullptr);
292     RUNNER_ASSERT_MSG(ret != -1, "Unable to get supplementary groups");
293
294     std::vector<gid_t> actual_gids(ret);
295     ret = getgroups(ret, actual_gids.data());
296     RUNNER_ASSERT_MSG(ret != -1, "Unable to get supplementary groups");
297
298     for (const auto &gid : actual_gids) {
299         RUNNER_ASSERT_MSG(gid == main_gid || reference_gids.count(gid) > 0,
300             "Application shouldn't get access to group " << gid);
301         reference_gids.erase(gid);
302     }
303
304     RUNNER_ASSERT_MSG(reference_gids.empty(), "Application didn't get access to some groups");
305 }
306
307 static const char *const ANY_USER_REPRESENTATION = "anyuser";/*this may be actually any string*/
308
309 void check_app_after_install(const std::string &app_id, const std::string &pkg_id,
310                              const privileges_t &allowed_privs,
311                              const privileges_t &denied_privs,
312                              const std::vector<std::string> &allowed_groups,
313                              bool isHybrid)
314 {
315     TestSecurityManagerDatabase dbtest;
316     dbtest.test_db_after__app_install(app_id, pkg_id);
317
318     /*Privileges should be granted to all users if root installs app*/
319     check_app_permissions(app_id, pkg_id, ANY_USER_REPRESENTATION, allowed_privs, denied_privs, isHybrid);
320
321     /* Setup mapping of gids to privileges */
322     /* Do this for each privilege for extra check */
323     for (const auto &privilege : allowed_privs) {
324         dbtest.setup_privilege_groups(privilege, allowed_groups);
325     }
326
327     std::vector<gid_t> allowed_gids;
328
329     for (const auto &groupName : allowed_groups) {
330         errno = 0;
331         struct group* grp = getgrnam(groupName.c_str());
332         RUNNER_ASSERT_ERRNO_MSG(grp, "Group: " << groupName << " not found");
333         allowed_gids.push_back(grp->gr_gid);
334     }
335
336     check_app_gids(app_id, allowed_gids);
337 }
338
339 void check_path(const std::string &path, const std::string &label, bool transmute, bool execute) {
340     nftw_expected_label = label;
341     nftw_expected_transmute = transmute;
342     nftw_expected_exec = execute;
343
344     // check labels
345     int result = nftw(path.c_str(), &nftw_check_sm_labels, FTW_MAX_FDS, FTW_PHYS);
346     RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for " << path);
347 }
348
349 void check_app_path_after_install(int app_num, const char *pkgId, bool others_enabled)
350 {
351     std::string SM_RW_PATH = genRWPath(app_num);
352     std::string SM_RO_PATH = genROPath(app_num);
353     std::string SM_PUBLIC_RO_PATH = genPublicROPath(app_num);
354     int result;
355
356     nftw_expected_label = generatePathRWLabel(pkgId);
357     nftw_expected_transmute = true;
358     nftw_expected_exec = false;
359
360     result = nftw(SM_RW_PATH.c_str(), &nftw_check_sm_labels, FTW_MAX_FDS, FTW_PHYS);
361     RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for " << SM_RW_PATH);
362
363     nftw_expected_label = generatePathRWLabel(pkgId) + "::RO";
364     nftw_expected_transmute = false;
365     nftw_expected_exec = false;
366
367     result = nftw(SM_RO_PATH.c_str(), &nftw_check_sm_labels, FTW_MAX_FDS, FTW_PHYS);
368     RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for " << SM_RO_PATH);
369
370     nftw_expected_label = "User::Home";
371     nftw_expected_transmute = true;
372     nftw_expected_exec = false;
373
374     result = nftw(SM_PUBLIC_RO_PATH.c_str(), &nftw_check_sm_labels, FTW_MAX_FDS, FTW_PHYS);
375     RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for " << SM_PUBLIC_RO_PATH);
376
377     result = nftw(SM_DENIED_PATH.c_str(), &nftw_check_labels_non_app_dir, FTW_MAX_FDS, FTW_PHYS);
378     RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for " << SM_DENIED_PATH);
379
380     // owner RW, others RO
381     if(others_enabled) {
382         std::string SM_OWNER_RW_OTHERS_RO_PATH = genOwnerRWOthersROPath(app_num);
383         nftw_expected_label = generatePkgLabelOwnerRWothersRO(pkgId);
384         nftw_expected_transmute = true;
385         nftw_expected_exec = false;
386
387         result = nftw(SM_OWNER_RW_OTHERS_RO_PATH.c_str(), &nftw_check_sm_labels, FTW_MAX_FDS, FTW_PHYS);
388         RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for " << SM_OWNER_RW_OTHERS_RO_PATH);
389     }
390 }
391
392 void check_app_after_uninstall(const std::string &app_id, const std::string &pkg_id,
393                                const bool is_pkg_removed)
394 {
395     TestSecurityManagerDatabase dbtest;
396     dbtest.test_db_after__app_uninstall(app_id, pkg_id, is_pkg_removed);
397 }
398
399 void check_app_after_uninstall(const std::string &app_id, const std::string &pkg_id,
400                                const privileges_t &privileges, const bool is_pkg_removed,
401                                bool isHybrid)
402 {
403     TestSecurityManagerDatabase dbtest;
404     dbtest.test_db_after__app_uninstall(app_id, pkg_id, is_pkg_removed);
405
406
407     /*Privileges should not be granted anymore to any user*/
408     check_app_permissions(app_id, pkg_id, ANY_USER_REPRESENTATION, SM_NO_PRIVILEGES, privileges, isHybrid);
409 }
410
411 std::string access_opposite(std::string &access) {
412     static const std::map<char, int> access_mapping = {{'r', 0}, {'w', 1}, {'x', 2}, {'a', 3},
413                                                        {'t', 4}, {'l', 5}};
414     //May write implies may lock
415     if (access.find('w') != std::string::npos && access.find('l') == std::string::npos) {
416         access.append("l");
417     }
418     std::string access_opposite = "rwxatl";
419     for (char c : access) {
420         access_opposite[access_mapping.at(c)] = '-';
421     }
422     auto it = std::remove_if(access_opposite.begin(), access_opposite.end(), [](char c) {return c == '-';});
423     access_opposite.erase(it, access_opposite.end());
424     return access_opposite;
425 }
426
427 void check_exact_smack_accesses(const std::string &subject, const std::string &object,
428                                 const std::string &access) {
429     std::string access_str(access);
430     auto no_access = access_opposite(access_str);
431     for (char c : access_str) {
432         int ret = smack_have_access(subject.c_str(), object.c_str(), std::string(1, c).c_str());
433         RUNNER_ASSERT_MSG(ret >= 0, "smack_have_access failed: <" << subject << ">, <" << object
434                           << ">, <" << c << "> errno=" << strerror(errno));
435         RUNNER_ASSERT_MSG(ret == 1, "Access " << c << " from " << subject << " to "
436                           << object << " not given");
437     }
438
439     for (char c : no_access) {
440         int ret = smack_have_access(subject.c_str(), object.c_str(), std::string(1, c).c_str());
441         RUNNER_ASSERT_MSG(ret >= 0, "smack_have_access failed: <" << subject << ">, <" << object
442                           << ">, <" << c << "> errno=" << strerror(errno));
443         RUNNER_ASSERT_MSG(ret == 0, "Access " << c << " from " << subject << " to "
444                           << object << " unnecessarily given");
445     }
446 }
447
448 CapsSetsUniquePtr setCaps(const char *cap_string)
449 {
450     CapsSetsUniquePtr caps(cap_init());
451     caps.reset(cap_from_text(cap_string));
452     RUNNER_ASSERT_MSG(caps, "can't convert capabilities from text");
453     int result = cap_set_proc(caps.get());
454     RUNNER_ASSERT_MSG(result == 0, "can't set capabilities. Result: " << result);
455     return caps;
456 }
457
458 static void prepare_app_path(int app_num, bool others_enabled = false)
459 {
460     std::string SM_RW_PATH = genRWPath(app_num);
461     std::string SM_RO_PATH = genROPath(app_num);
462     std::string SM_PUBLIC_RO_PATH = genPublicROPath(app_num);
463     int result;
464
465     result = nftw(SM_RW_PATH.c_str(), &nftw_remove_labels, FTW_MAX_FDS, FTW_PHYS);
466     RUNNER_ASSERT_MSG(result == 0, "Unable to clean Smack labels in " << SM_RW_PATH);
467
468     result = nftw(SM_RO_PATH.c_str(), &nftw_remove_labels, FTW_MAX_FDS, FTW_PHYS);
469     RUNNER_ASSERT_MSG(result == 0, "Unable to clean Smack labels in " << SM_RO_PATH);
470
471     result = nftw(SM_PUBLIC_RO_PATH.c_str(), &nftw_remove_labels, FTW_MAX_FDS, FTW_PHYS);
472     RUNNER_ASSERT_MSG(result == 0, "Unable to clean Smack labels in " << SM_PUBLIC_RO_PATH);
473
474     if(others_enabled) {
475         std::string SM_OWNER_RW_OTHERS_RO_PATH = genOwnerRWOthersROPath(app_num);
476         result = nftw(SM_OWNER_RW_OTHERS_RO_PATH.c_str(), &nftw_remove_labels, FTW_MAX_FDS, FTW_PHYS);
477         RUNNER_ASSERT_MSG(result == 0, "Unable to clean Smack labels in " << SM_OWNER_RW_OTHERS_RO_PATH);
478     }
479
480     result = nftw(SM_DENIED_PATH.c_str(), &nftw_set_labels_non_app_dir, FTW_MAX_FDS, FTW_PHYS);
481     RUNNER_ASSERT_MSG(result == 0, "Unable to set Smack labels in " << SM_DENIED_PATH);
482 }
483
484 void prepare_app_env(int app_num, bool others_enabled)
485 {
486     prepare_app_path(app_num, others_enabled);
487 }
488
489 void install_app(const std::string &app_id, const std::string &pkg_id, uid_t uid, app_install_type type,
490                  bool check_after)
491 {
492     InstallRequest request;
493     request.setAppId(app_id);
494     request.setPkgId(pkg_id);
495     request.setUid(uid);
496     if (type != SM_APP_INSTALL_NONE)
497         request.setInstallType(type);
498     Api::install(request);
499
500     if (check_after)
501         check_app_after_install(app_id, pkg_id);
502 }
503
504 void uninstall_app(const std::string &app_id, const std::string &pkg_id, bool expect_pkg_removed,
505                    app_install_type type, bool check_after)
506 {
507     InstallRequest request;
508     request.setAppId(app_id);
509     if (type != SM_APP_INSTALL_NONE)
510         request.setInstallType(type);
511     Api::uninstall(request);
512
513     if (check_after)
514         check_app_after_uninstall(app_id, pkg_id, expect_pkg_removed);
515 }
516
517 static const std::string EXEC_FILE("exec");
518 static const std::string NORMAL_FILE("normal");
519 static const std::string LINK_PREFIX("link_to_");
520
521 static void createTestDir(const std::string &dir)
522 {
523     mode_t dirMode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
524     mode_t execFileMode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
525     mode_t normalFileMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
526
527     mktreeSafe(dir, dirMode);
528     creatSafe(dir + "/" + EXEC_FILE, execFileMode);
529     creatSafe(dir + "/" + NORMAL_FILE, normalFileMode);
530     symlinkSafe(dir + "/" + EXEC_FILE, dir + "/" + LINK_PREFIX + EXEC_FILE);
531     symlinkSafe(dir + "/" + NORMAL_FILE, dir + "/" + LINK_PREFIX + NORMAL_FILE);
532 }
533
534 static void createInnerAppDir(const std::string &dir, const std::string &nonAppDir)
535 {
536     createTestDir(dir);
537
538     symlinkSafe(nonAppDir, dir + "/" + LINK_PREFIX + "non_app_dir");
539     symlinkSafe(nonAppDir + "/" + EXEC_FILE,
540                 dir + "/" + LINK_PREFIX + "non_app_" + EXEC_FILE);
541     symlinkSafe(nonAppDir + "/" + NORMAL_FILE,
542                 dir + "/" + LINK_PREFIX + "non_app_" + NORMAL_FILE);
543 }
544
545 static const std::string nonAppDirPath(const TemporaryTestUser &user)
546 {
547     return TMP_DIR + "/" + user.getUserName();
548 }
549
550 static void generateAppDir(const TemporaryTestUser &user,
551        const std::string &appId, const std::string &pkgId)
552 {
553     const std::string dir = TzPlatformConfig::appDirPath(user, appId, pkgId);
554     const std::string nonAppDir = nonAppDirPath(user);
555
556     createInnerAppDir(dir, nonAppDir);
557     createInnerAppDir(dir + "/.inner_dir", nonAppDir);
558     createInnerAppDir(dir + "/inner_dir", nonAppDir);
559 }
560
561 static void generateNonAppDir(const TemporaryTestUser &user)
562 {
563     const std::string dir = nonAppDirPath(user);
564
565     createTestDir(dir);
566     createTestDir(dir + "/.inner_dir");
567     createTestDir(dir + "/inner_dir");
568 }
569
570 void createTestDirs(const TemporaryTestUser &user,
571                     const std::string &appId, const std::string &pkgId)
572 {
573     generateAppDir(user, appId, pkgId);
574     generateNonAppDir(user);
575 }
576
577 void removeTestDirs(const TemporaryTestUser &user,
578                     const std::string &appId, const std::string &pkgId)
579 {
580     removeDir(TzPlatformConfig::appDirPath(user, appId, pkgId));
581     removeDir(nonAppDirPath(user));
582 }
583
584 pid_t runInChild(const std::function<void(void)> &process) {
585     pid_t pid = fork();
586     RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "fork failed");
587
588     if (pid == 0) {
589         process();
590         exit(EXIT_SUCCESS);
591     }
592     return pid;
593 }
594
595 void runInChildParentWait(const std::function<void(void)> &process) {
596     SynchronizationPipe pipe;
597     pid_t pid = fork();
598     RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "fork failed");
599
600     if (pid == 0) {
601         pipe.claimChildEp();
602
603         process();
604
605         pipe.post();
606         exit(EXIT_SUCCESS);
607     } else {
608         pipe.claimParentEp();
609         pipe.wait();
610     }
611 }