2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 #include <sys/capability.h>
24 #include <sys/types.h>
28 #include <unordered_set>
31 #include <security-manager-types.h>
32 #include <sys/smack.h>
34 #include <cynara_test_client.h>
35 #include <dpl/test/test_runner.h>
38 #include <sm_commons.h>
40 #include <synchronization_pipe.h>
41 #include <sm_request.h>
42 #include <tests_common.h>
43 #include "tzplatform.h"
45 using namespace SecurityManagerTest;
47 // Common const values
49 const privileges_t SM_ALLOWED_PRIVILEGES = {
50 "http://tizen.org/privilege/display",
51 "http://tizen.org/privilege/nfc"
54 const privileges_t SM_DENIED_PRIVILEGES = {
55 "http://tizen.org/privilege/bluetooth",
56 "http://tizen.org/privilege/power"
59 const privileges_t SM_NO_PRIVILEGES = {
62 const std::vector<std::string> SM_ALLOWED_GROUPS = {"db_browser", "db_alarm"};
64 const std::string uidToStr(const uid_t uid)
66 return std::to_string(static_cast<unsigned int>(uid));
69 // Common implementation details
71 std::string generateProcessLabel(const std::string &appId, const std::string &pkgId, bool isHybrid)
73 std::string label = "User::Pkg::" + pkgId;
75 label += "::App::" + appId;
80 std::string generatePathRWLabel(const std::string &pkgId)
82 return "User::Pkg::" + pkgId;
85 std::string generatePathROLabel(const std::string &pkgId)
87 return generatePathRWLabel(pkgId) + "::RO";
90 std::string generatePathSharedROLabel(const std::string &pkgId)
92 return generatePathRWLabel(pkgId) + "::SharedRO";
95 std::string generatePathTrustedLabel(int64_t authorId)
97 return "User::Author::" + std::to_string(authorId);
100 std::string getPublicPathLabel()
105 static std::string genPath(int app_num, const char *postfix) {
107 sprintf(buf, "%02d", app_num);
108 return TzPlatformConfig::globalAppDir() + "/sm_test_" + std::string(buf) + "_pkg_id_full/" + std::string(postfix);
111 std::string genRWPath(int app_num) {
112 return genPath(app_num, "app_dir");
114 std::string genROPath(int app_num) {
115 return genPath(app_num, "app_dir_ro");
117 std::string genPublicROPath(int app_num) {
118 return genPath(app_num, "app_dir_public_ro");
121 std::string genOwnerRWOthersROPath(int app_num) {
122 return genPath(app_num, "app_dir_rw_others_ro");
125 static std::string generatePkgLabelOwnerRWothersRO(const std::string &pkgId)
127 return "User::Pkg::" + pkgId + "::SharedRO";
130 // Common DB/nftw checks
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;
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)
142 char* label = nullptr;
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 << "')");
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);
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);
164 RUNNER_ASSERT_MSG(label == nullptr, "EXEC label on " << fpath << " is set");
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);
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<<"'");
177 RUNNER_ASSERT_MSG(label == nullptr, "TRANSMUTE label on " << fpath << " is set");
183 static int nftw_check_sm_labels(const char *fpath, const struct stat *sb,
184 int /*typeflag*/, struct FTW* /*ftwbuf*/)
186 return nftw_check_sm_labels_app_dir(fpath, sb,
187 nftw_expected_label.c_str(), nftw_expected_transmute, nftw_expected_exec);
190 int nftw_check_labels_non_app_dir(const char *fpath, const struct stat* /*sb*/,
191 int /*typeflag*/, struct FTW* /*ftwbuf*/)
195 char* label = nullptr;
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");
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");
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");
220 static int nftw_set_labels_non_app_dir(const char *fpath, const struct stat* /*sb*/,
221 int /*typeflag*/, struct FTW* /*ftwbuf*/)
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);
230 int nftw_remove_labels(const char *fpath, const struct stat* /*sb*/,
231 int /*typeflag*/, struct FTW* /*ftwbuf*/)
233 smack_lsetlabel(fpath, nullptr, SMACK_LABEL_ACCESS);
234 smack_lsetlabel(fpath, nullptr, SMACK_LABEL_EXEC);
235 smack_lsetlabel(fpath, nullptr, SMACK_LABEL_TRANSMUTE);
240 static const std::string SM_DENIED_PATH = TzPlatformConfig::globalAppDir() + "/non_app_dir";
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)
247 std::string smackLabel = generateProcessLabel(app_id, pkg_id, isHybrid);
249 CynaraTestClient::Client ctc;
251 for (auto &priv : allowed_privs) {
252 ctc.check(smackLabel.c_str(), "", user, priv.c_str(), CYNARA_API_ACCESS_ALLOWED);
255 for (auto &priv : denied_privs) {
256 ctc.check(smackLabel.c_str(), "", user, priv.c_str(), CYNARA_API_ACCESS_DENIED);
260 void sm_app_has_privileges(const AppInstallHelper &app,
261 const std::vector<std::string> &privileges,
264 for (auto const &privilege : privileges) {
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 );
273 void check_app_after_install(const std::string &app_id, const std::string &pkg_id)
275 TestSecurityManagerDatabase dbtest;
276 dbtest.test_db_after__app_install(app_id, pkg_id);
279 static void check_app_gids(const std::string &app_id, const std::vector<gid_t> &allowed_gids)
282 gid_t main_gid = getgid();
283 std::unordered_set<gid_t> reference_gids(allowed_gids.begin(), allowed_gids.end());
285 // Reset supplementary groups
286 ret = setgroups(0, NULL);
287 RUNNER_ASSERT_MSG(ret != -1, "Unable to set supplementary groups");
289 Api::setProcessGroups(app_id);
291 ret = getgroups(0, nullptr);
292 RUNNER_ASSERT_MSG(ret != -1, "Unable to get supplementary groups");
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");
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);
304 RUNNER_ASSERT_MSG(reference_gids.empty(), "Application didn't get access to some groups");
307 static const char *const ANY_USER_REPRESENTATION = "anyuser";/*this may be actually any string*/
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,
315 TestSecurityManagerDatabase dbtest;
316 dbtest.test_db_after__app_install(app_id, pkg_id);
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);
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);
327 std::vector<gid_t> allowed_gids;
329 for (const auto &groupName : allowed_groups) {
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);
336 check_app_gids(app_id, allowed_gids);
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;
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);
349 void check_app_path_after_install(int app_num, const char *pkgId, bool others_enabled)
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);
356 nftw_expected_label = generatePathRWLabel(pkgId);
357 nftw_expected_transmute = true;
358 nftw_expected_exec = false;
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);
363 nftw_expected_label = generatePathRWLabel(pkgId) + "::RO";
364 nftw_expected_transmute = false;
365 nftw_expected_exec = false;
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);
370 nftw_expected_label = "User::Home";
371 nftw_expected_transmute = true;
372 nftw_expected_exec = false;
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);
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);
380 // owner RW, others RO
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;
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);
392 void check_app_after_uninstall(const std::string &app_id, const std::string &pkg_id,
393 const bool is_pkg_removed)
395 TestSecurityManagerDatabase dbtest;
396 dbtest.test_db_after__app_uninstall(app_id, pkg_id, is_pkg_removed);
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,
403 TestSecurityManagerDatabase dbtest;
404 dbtest.test_db_after__app_uninstall(app_id, pkg_id, is_pkg_removed);
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);
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},
414 //May write implies may lock
415 if (access.find('w') != std::string::npos && access.find('l') == std::string::npos) {
418 std::string access_opposite = "rwxatl";
419 for (char c : access) {
420 access_opposite[access_mapping.at(c)] = '-';
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;
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");
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");
448 CapsSetsUniquePtr setCaps(const char *cap_string)
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);
458 static void prepare_app_path(int app_num, bool others_enabled = false)
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);
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);
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);
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);
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);
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);
484 void prepare_app_env(int app_num, bool others_enabled)
486 prepare_app_path(app_num, others_enabled);
489 void install_app(const std::string &app_id, const std::string &pkg_id, uid_t uid, app_install_type type,
492 InstallRequest request;
493 request.setAppId(app_id);
494 request.setPkgId(pkg_id);
496 if (type != SM_APP_INSTALL_NONE)
497 request.setInstallType(type);
498 Api::install(request);
501 check_app_after_install(app_id, pkg_id);
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)
507 InstallRequest request;
508 request.setAppId(app_id);
509 if (type != SM_APP_INSTALL_NONE)
510 request.setInstallType(type);
511 Api::uninstall(request);
514 check_app_after_uninstall(app_id, pkg_id, expect_pkg_removed);
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_");
521 static void createTestDir(const std::string &dir)
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;
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);
534 static void createInnerAppDir(const std::string &dir, const std::string &nonAppDir)
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);
545 static const std::string nonAppDirPath(const TemporaryTestUser &user)
547 return TMP_DIR + "/" + user.getUserName();
550 static void generateAppDir(const TemporaryTestUser &user,
551 const std::string &appId, const std::string &pkgId)
553 const std::string dir = TzPlatformConfig::appDirPath(user, appId, pkgId);
554 const std::string nonAppDir = nonAppDirPath(user);
556 createInnerAppDir(dir, nonAppDir);
557 createInnerAppDir(dir + "/.inner_dir", nonAppDir);
558 createInnerAppDir(dir + "/inner_dir", nonAppDir);
561 static void generateNonAppDir(const TemporaryTestUser &user)
563 const std::string dir = nonAppDirPath(user);
566 createTestDir(dir + "/.inner_dir");
567 createTestDir(dir + "/inner_dir");
570 void createTestDirs(const TemporaryTestUser &user,
571 const std::string &appId, const std::string &pkgId)
573 generateAppDir(user, appId, pkgId);
574 generateNonAppDir(user);
577 void removeTestDirs(const TemporaryTestUser &user,
578 const std::string &appId, const std::string &pkgId)
580 removeDir(TzPlatformConfig::appDirPath(user, appId, pkgId));
581 removeDir(nonAppDirPath(user));
584 pid_t runInChild(const std::function<void(void)> &process) {
586 RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "fork failed");
595 void runInChildParentWait(const std::function<void(void)> &process) {
596 SynchronizationPipe pipe;
598 RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "fork failed");
608 pipe.claimParentEp();