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>
26 #include <unordered_set>
29 #include <security-manager-types.h>
30 #include <sys/smack.h>
32 #include <cynara_test_client.h>
33 #include <dpl/test/test_runner.h>
36 #include <sm_commons.h>
38 #include <sm_request.h>
39 #include <tests_common.h>
40 #include "tzplatform.h"
42 using namespace SecurityManagerTest;
44 // Common const values
46 const privileges_t SM_ALLOWED_PRIVILEGES = {
47 "http://tizen.org/privilege/display",
48 "http://tizen.org/privilege/nfc"
51 const privileges_t SM_DENIED_PRIVILEGES = {
52 "http://tizen.org/privilege/bluetooth",
53 "http://tizen.org/privilege/power"
56 const privileges_t SM_NO_PRIVILEGES = {
59 const std::vector<std::string> SM_ALLOWED_GROUPS = {"db_browser", "db_alarm"};
61 const std::string uidToStr(const uid_t uid)
63 return std::to_string(static_cast<unsigned int>(uid));
66 // Common implementation details
68 std::string generateAppLabel(const std::string &appId)
70 return "User::App::" + appId;
73 std::string generatePkgLabel(const std::string &pkgId)
75 return "User::Pkg::" + pkgId;
78 static std::string genPath(int app_num, const char *postfix) {
80 sprintf(buf, "%02d", app_num);
81 return std::string("/opt/usr/globalapps/sm_test_") + std::string(buf) + std::string("_pkg_id_full/") + std::string(postfix);
84 std::string genRWPath(int app_num) {
85 return genPath(app_num, "app_dir");
87 std::string genROPath(int app_num) {
88 return genPath(app_num, "app_dir_ro");
90 std::string genPublicROPath(int app_num) {
91 return genPath(app_num, "app_dir_public_ro");
94 std::string genOwnerRWOthersROPath(int app_num) {
95 return genPath(app_num, "app_dir_rw_others_ro");
98 static std::string generatePkgLabelOwnerRWothersRO(const std::string &pkgId)
100 return "User::Pkg::" + pkgId + "::SharedRO";
103 // Common DB/nftw checks
105 // nftw doesn't allow passing user data to functions. Work around by using global variable
106 static std::string nftw_expected_label;
107 bool nftw_expected_transmute;
108 bool nftw_expected_exec;
110 static int nftw_check_sm_labels_app_dir(const char *fpath, const struct stat *sb,
111 const char* correctLabel, bool transmute_test, bool exec_test)
115 char* label = nullptr;
118 result = smack_lgetlabel(fpath, &label, SMACK_LABEL_ACCESS);
119 RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
120 labelPtr.reset(label);
121 RUNNER_ASSERT_MSG(label != nullptr, "ACCESS label on " << fpath << " is not set");
122 result = strcmp(correctLabel, label);
123 RUNNER_ASSERT_MSG(result == 0, "ACCESS label on " << fpath << " is incorrect"
124 " (should be '" << correctLabel << "' and is '" << label << "')");
128 result = smack_lgetlabel(fpath, &label, SMACK_LABEL_EXEC);
129 RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
130 labelPtr.reset(label);
132 if (S_ISREG(sb->st_mode) && (sb->st_mode & S_IXUSR) && exec_test) {
133 RUNNER_ASSERT_MSG(label != nullptr, "EXEC label on " << fpath << " is not set");
134 result = strcmp(correctLabel, label);
135 RUNNER_ASSERT_MSG(result == 0, "Incorrect EXEC label on executable file " << fpath);
137 RUNNER_ASSERT_MSG(label == nullptr, "EXEC label on " << fpath << " is set");
141 result = smack_lgetlabel(fpath, &label, SMACK_LABEL_TRANSMUTE);
142 RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
143 labelPtr.reset(label);
145 if (S_ISDIR(sb->st_mode) && transmute_test == true) {
146 RUNNER_ASSERT_MSG(label != nullptr, "TRANSMUTE label on " << fpath << " is not set at all");
147 RUNNER_ASSERT_MSG(strcmp(label,"TRUE") == 0,
148 "TRANSMUTE label on " << fpath << " is not set properly: '"<<label<<"'");
150 RUNNER_ASSERT_MSG(label == nullptr, "TRANSMUTE label on " << fpath << " is set");
156 static int nftw_check_sm_labels(const char *fpath, const struct stat *sb,
157 int /*typeflag*/, struct FTW* /*ftwbuf*/)
159 return nftw_check_sm_labels_app_dir(fpath, sb,
160 nftw_expected_label.c_str(), nftw_expected_transmute, nftw_expected_exec);
163 int nftw_check_labels_non_app_dir(const char *fpath, const struct stat* /*sb*/,
164 int /*typeflag*/, struct FTW* /*ftwbuf*/)
168 char* label = nullptr;
171 result = smack_lgetlabel(fpath, &label, SMACK_LABEL_ACCESS);
172 labelPtr.reset(label);
173 RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
174 result = strcmp("canary_label", labelPtr.get());
175 RUNNER_ASSERT_MSG(result == 0, "ACCESS label on " << fpath << " is overwritten");
178 result = smack_lgetlabel(fpath, &label, SMACK_LABEL_EXEC);
179 labelPtr.reset(label);
180 RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
181 result = strcmp("canary_label", labelPtr.get());
182 RUNNER_ASSERT_MSG(result == 0, "EXEC label on " << fpath << " is overwritten");
185 result = smack_lgetlabel(fpath, &label, SMACK_LABEL_TRANSMUTE);
186 labelPtr.reset(label);
187 RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
188 RUNNER_ASSERT_MSG(labelPtr.get() == nullptr, "TRANSMUTE label on " << fpath << " is set");
193 static int nftw_set_labels_non_app_dir(const char *fpath, const struct stat* /*sb*/,
194 int /*typeflag*/, struct FTW* /*ftwbuf*/)
196 smack_lsetlabel(fpath, "canary_label", SMACK_LABEL_ACCESS);
197 smack_lsetlabel(fpath, "canary_label", SMACK_LABEL_EXEC);
198 smack_lsetlabel(fpath, nullptr, SMACK_LABEL_TRANSMUTE);
203 int nftw_remove_labels(const char *fpath, const struct stat* /*sb*/,
204 int /*typeflag*/, struct FTW* /*ftwbuf*/)
206 smack_lsetlabel(fpath, nullptr, SMACK_LABEL_ACCESS);
207 smack_lsetlabel(fpath, nullptr, SMACK_LABEL_EXEC);
208 smack_lsetlabel(fpath, nullptr, SMACK_LABEL_TRANSMUTE);
213 static const char *const SM_DENIED_PATH = "/opt/usr/globalapps/non_app_dir";
215 void check_app_permissions(const char *const app_id, const char *const pkg_id,
216 const char *const user, const privileges_t &allowed_privs,
217 const privileges_t &denied_privs)
220 std::string smackLabel = generateAppLabel(app_id);
222 CynaraTestClient::Client ctc;
224 for (auto &priv : allowed_privs) {
225 ctc.check(smackLabel.c_str(), "", user, priv.c_str(), CYNARA_API_ACCESS_ALLOWED);
228 for (auto &priv : denied_privs) {
229 ctc.check(smackLabel.c_str(), "", user, priv.c_str(), CYNARA_API_ACCESS_DENIED);
234 void check_app_after_install(const char *const app_id, const char *const pkg_id)
236 TestSecurityManagerDatabase dbtest;
237 dbtest.test_db_after__app_install(app_id, pkg_id);
240 static void check_app_gids(const char *const app_id, const std::vector<gid_t> &allowed_gids)
243 gid_t main_gid = getgid();
244 std::unordered_set<gid_t> reference_gids(allowed_gids.begin(), allowed_gids.end());
246 // Reset supplementary groups
247 ret = setgroups(0, NULL);
248 RUNNER_ASSERT_MSG(ret != -1, "Unable to set supplementary groups");
250 Api::setProcessGroups(app_id);
252 ret = getgroups(0, nullptr);
253 RUNNER_ASSERT_MSG(ret != -1, "Unable to get supplementary groups");
255 std::vector<gid_t> actual_gids(ret);
256 ret = getgroups(ret, actual_gids.data());
257 RUNNER_ASSERT_MSG(ret != -1, "Unable to get supplementary groups");
259 for (const auto &gid : actual_gids) {
260 RUNNER_ASSERT_MSG(gid == main_gid || reference_gids.count(gid) > 0,
261 "Application shouldn't get access to group " << gid);
262 reference_gids.erase(gid);
265 RUNNER_ASSERT_MSG(reference_gids.empty(), "Application didn't get access to some groups");
268 static const char *const ANY_USER_REPRESENTATION = "anyuser";/*this may be actually any string*/
270 void check_app_after_install(const char *const app_id, const char *const pkg_id,
271 const privileges_t &allowed_privs,
272 const privileges_t &denied_privs,
273 const std::vector<std::string> &allowed_groups)
275 TestSecurityManagerDatabase dbtest;
276 dbtest.test_db_after__app_install(app_id, pkg_id);
278 /*Privileges should be granted to all users if root installs app*/
279 check_app_permissions(app_id, pkg_id, ANY_USER_REPRESENTATION, allowed_privs, denied_privs);
281 /* Setup mapping of gids to privileges */
282 /* Do this for each privilege for extra check */
283 for (const auto &privilege : allowed_privs) {
284 dbtest.setup_privilege_groups(privilege, allowed_groups);
287 std::vector<gid_t> allowed_gids;
289 for (const auto &groupName : allowed_groups) {
291 struct group* grp = getgrnam(groupName.c_str());
292 RUNNER_ASSERT_ERRNO_MSG(grp, "Group: " << groupName << " not found");
293 allowed_gids.push_back(grp->gr_gid);
296 check_app_gids(app_id, allowed_gids);
299 void check_path(const std::string &path, const std::string &label) {
300 nftw_expected_label = label;
301 nftw_expected_transmute = true;
302 nftw_expected_exec = false;
305 int result = nftw(path.c_str(), &nftw_check_sm_labels, FTW_MAX_FDS, FTW_PHYS);
306 RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for " << path);
309 void check_app_path_after_install(int app_num, const char *pkgId, bool others_enabled)
311 std::string SM_RW_PATH = genRWPath(app_num);
312 std::string SM_RO_PATH = genROPath(app_num);
313 std::string SM_PUBLIC_RO_PATH = genPublicROPath(app_num);
316 nftw_expected_label = generatePkgLabel(pkgId);
317 nftw_expected_transmute = true;
318 nftw_expected_exec = false;
320 result = nftw(SM_RW_PATH.c_str(), &nftw_check_sm_labels, FTW_MAX_FDS, FTW_PHYS);
321 RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for " << SM_RW_PATH);
323 nftw_expected_label = generatePkgLabel(pkgId) + "::RO";
324 nftw_expected_transmute = false;
325 nftw_expected_exec = false;
327 result = nftw(SM_RO_PATH.c_str(), &nftw_check_sm_labels, FTW_MAX_FDS, FTW_PHYS);
328 RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for " << SM_RO_PATH);
330 nftw_expected_label = "User::Home";
331 nftw_expected_transmute = true;
332 nftw_expected_exec = false;
334 result = nftw(SM_PUBLIC_RO_PATH.c_str(), &nftw_check_sm_labels, FTW_MAX_FDS, FTW_PHYS);
335 RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for " << SM_PUBLIC_RO_PATH);
337 result = nftw(SM_DENIED_PATH, &nftw_check_labels_non_app_dir, FTW_MAX_FDS, FTW_PHYS);
338 RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for " << SM_DENIED_PATH);
340 // owner RW, others RO
342 std::string SM_OWNER_RW_OTHERS_RO_PATH = genOwnerRWOthersROPath(app_num);
343 nftw_expected_label = generatePkgLabelOwnerRWothersRO(pkgId);
344 nftw_expected_transmute = true;
345 nftw_expected_exec = false;
347 result = nftw(SM_OWNER_RW_OTHERS_RO_PATH.c_str(), &nftw_check_sm_labels, FTW_MAX_FDS, FTW_PHYS);
348 RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for " << SM_OWNER_RW_OTHERS_RO_PATH);
352 void check_app_after_uninstall(const char *const app_id, const char *const pkg_id,
353 const bool is_pkg_removed)
355 TestSecurityManagerDatabase dbtest;
356 dbtest.test_db_after__app_uninstall(app_id, pkg_id, is_pkg_removed);
359 void check_app_after_uninstall(const char *const app_id, const char *const pkg_id,
360 const privileges_t &privileges, const bool is_pkg_removed)
362 TestSecurityManagerDatabase dbtest;
363 dbtest.test_db_after__app_uninstall(app_id, pkg_id, is_pkg_removed);
366 /*Privileges should not be granted anymore to any user*/
367 check_app_permissions(app_id, pkg_id, ANY_USER_REPRESENTATION, SM_NO_PRIVILEGES, privileges);
370 std::string access_opposite(std::string &access) {
371 static const std::map<char, int> access_mapping = {{'r', 0}, {'w', 1}, {'x', 2}, {'a', 3},
373 //May write implies may lock
374 if (access.find('w') != std::string::npos && access.find('l') == std::string::npos) {
377 std::string access_opposite = "rwxatl";
378 for (char c : access) {
379 access_opposite[access_mapping.at(c)] = '-';
381 auto it = std::remove_if(access_opposite.begin(), access_opposite.end(), [](char c) {return c == '-';});
382 access_opposite.erase(it, access_opposite.end());
383 return access_opposite;
386 void check_exact_smack_accesses(const std::string &subject, const std::string &object,
387 const std::string &access) {
388 std::string access_str(access);
389 auto no_access = access_opposite(access_str);
390 for (char c : access_str) {
391 int ret = smack_have_access(subject.c_str(), object.c_str(), std::string(1, c).c_str());
392 RUNNER_ASSERT_MSG(ret >= 0, "smack_have_access failed: <" << subject << ">, <" << object
393 << ">, <" << c << "> errno=" << strerror(errno));
394 RUNNER_ASSERT_MSG(ret == 1, "Access " << c << " from " << subject << " to "
395 << object << " not given");
398 for (char c : no_access) {
399 int ret = smack_have_access(subject.c_str(), object.c_str(), std::string(1, c).c_str());
400 RUNNER_ASSERT_MSG(ret >= 0, "smack_have_access failed: <" << subject << ">, <" << object
401 << ">, <" << c << "> errno=" << strerror(errno));
402 RUNNER_ASSERT_MSG(ret == 0, "Access " << c << " from " << subject << " to "
403 << object << " unnecessarily given");
407 CapsSetsUniquePtr setCaps(const char *cap_string)
409 CapsSetsUniquePtr caps(cap_init());
410 caps.reset(cap_from_text(cap_string));
411 RUNNER_ASSERT_MSG(caps, "can't convert capabilities from text");
412 int result = cap_set_proc(caps.get());
413 RUNNER_ASSERT_MSG(result == 0, "can't set capabilities. Result: " << result);
417 static void prepare_app_path(int app_num, bool others_enabled = false)
419 std::string SM_RW_PATH = genRWPath(app_num);
420 std::string SM_RO_PATH = genROPath(app_num);
421 std::string SM_PUBLIC_RO_PATH = genPublicROPath(app_num);
424 result = nftw(SM_RW_PATH.c_str(), &nftw_remove_labels, FTW_MAX_FDS, FTW_PHYS);
425 RUNNER_ASSERT_MSG(result == 0, "Unable to clean Smack labels in " << SM_RW_PATH);
427 result = nftw(SM_RO_PATH.c_str(), &nftw_remove_labels, FTW_MAX_FDS, FTW_PHYS);
428 RUNNER_ASSERT_MSG(result == 0, "Unable to clean Smack labels in " << SM_RO_PATH);
430 result = nftw(SM_PUBLIC_RO_PATH.c_str(), &nftw_remove_labels, FTW_MAX_FDS, FTW_PHYS);
431 RUNNER_ASSERT_MSG(result == 0, "Unable to clean Smack labels in " << SM_PUBLIC_RO_PATH);
434 std::string SM_OWNER_RW_OTHERS_RO_PATH = genOwnerRWOthersROPath(app_num);
435 result = nftw(SM_OWNER_RW_OTHERS_RO_PATH.c_str(), &nftw_remove_labels, FTW_MAX_FDS, FTW_PHYS);
436 RUNNER_ASSERT_MSG(result == 0, "Unable to clean Smack labels in " << SM_OWNER_RW_OTHERS_RO_PATH);
439 result = nftw(SM_DENIED_PATH, &nftw_set_labels_non_app_dir, FTW_MAX_FDS, FTW_PHYS);
440 RUNNER_ASSERT_MSG(result == 0, "Unable to set Smack labels in " << SM_DENIED_PATH);
443 void prepare_app_env(int app_num, bool others_enabled)
445 prepare_app_path(app_num, others_enabled);
448 void install_app(const char *app_id, const char *pkg_id, uid_t uid, app_install_type type,
451 InstallRequest request;
452 request.setAppId(app_id);
453 request.setPkgId(pkg_id);
455 if (type != SM_APP_INSTALL_NONE)
456 request.setInstallType(type);
457 Api::install(request);
460 check_app_after_install(app_id, pkg_id);
463 void uninstall_app(const char *app_id, const char *pkg_id, bool expect_pkg_removed,
464 app_install_type type, bool check_after)
466 InstallRequest request;
467 request.setAppId(app_id);
468 if (type != SM_APP_INSTALL_NONE)
469 request.setInstallType(type);
470 Api::uninstall(request);
473 check_app_after_uninstall(app_id, pkg_id, expect_pkg_removed);
476 static const std::string EXEC_FILE("exec");
477 static const std::string NORMAL_FILE("normal");
478 static const std::string LINK_PREFIX("link_to_");
480 static void createTestDir(const std::string &dir)
482 mode_t dirMode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
483 mode_t execFileMode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
484 mode_t normalFileMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
486 mktreeSafe(dir, dirMode);
487 creatSafe(dir + "/" + EXEC_FILE, execFileMode);
488 creatSafe(dir + "/" + NORMAL_FILE, normalFileMode);
489 symlinkSafe(dir + "/" + EXEC_FILE, dir + "/" + LINK_PREFIX + EXEC_FILE);
490 symlinkSafe(dir + "/" + NORMAL_FILE, dir + "/" + LINK_PREFIX + NORMAL_FILE);
493 static void createInnerAppDir(const std::string &dir, const std::string &nonAppDir)
497 symlinkSafe(nonAppDir, dir + "/" + LINK_PREFIX + "non_app_dir");
498 symlinkSafe(nonAppDir + "/" + EXEC_FILE,
499 dir + "/" + LINK_PREFIX + "non_app_" + EXEC_FILE);
500 symlinkSafe(nonAppDir + "/" + NORMAL_FILE,
501 dir + "/" + LINK_PREFIX + "non_app_" + NORMAL_FILE);
504 static const std::string nonAppDirPath(const TemporaryTestUser &user)
506 return TMP_DIR + "/" + user.getUserName();
509 static void generateAppDir(const TemporaryTestUser &user,
510 const std::string &appId, const std::string &pkgId)
512 const std::string dir = TzPlatformConfig::appDirPath(user, appId, pkgId);
513 const std::string nonAppDir = nonAppDirPath(user);
515 createInnerAppDir(dir, nonAppDir);
516 createInnerAppDir(dir + "/.inner_dir", nonAppDir);
517 createInnerAppDir(dir + "/inner_dir", nonAppDir);
520 static void generateNonAppDir(const TemporaryTestUser &user)
522 const std::string dir = nonAppDirPath(user);
525 createTestDir(dir + "/.inner_dir");
526 createTestDir(dir + "/inner_dir");
529 void createTestDirs(const TemporaryTestUser &user,
530 const std::string &appId, const std::string &pkgId)
532 generateAppDir(user, appId, pkgId);
533 generateNonAppDir(user);
536 void removeTestDirs(const TemporaryTestUser &user,
537 const std::string &appId, const std::string &pkgId)
539 removeDir(TzPlatformConfig::appDirPath(user, appId, pkgId));
540 removeDir(nonAppDirPath(user));