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