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.
23 #include <sys/capability.h>
25 #include <sys/types.h>
27 #include <unordered_map>
30 #include <unordered_set>
33 #include <security-manager-types.h>
34 #include <app-runtime.h>
35 #include <sys/smack.h>
36 #include <privilege_info.h>
38 #include <cynara_test_client.h>
39 #include <dpl/test/test_runner.h>
42 #include <sm_commons.h>
43 #include <synchronization_pipe.h>
44 #include <sm_request.h>
45 #include <tests_common.h>
46 #include <policy_configuration.h>
47 #include "tzplatform.h"
49 using namespace SecurityManagerTest;
51 // Common implementation details
53 std::string generateProcessLabel(const std::string &appId, const std::string &pkgId, bool isHybrid)
55 std::string label = "User::Pkg::" + pkgId;
57 label += "::App::" + appId;
62 std::string generatePathRWLabel(const std::string &pkgId)
64 return "User::Pkg::" + pkgId;
67 std::string generatePathROLabel(const std::string &pkgId)
69 return generatePathRWLabel(pkgId) + "::RO";
72 std::string generatePathSharedROLabel(const std::string &pkgId)
74 return generatePathRWLabel(pkgId) + "::SharedRO";
77 std::string generatePathTrustedLabel(int64_t authorId)
79 return "User::Author::" + std::to_string(authorId);
82 std::string getPublicPathLabel()
87 // Common DB/nftw checks
89 // nftw doesn't allow passing user data to functions. Work around by using global variable
90 static std::string nftw_expected_label;
91 bool nftw_expected_transmute;
92 bool nftw_expected_exec;
94 static int nftw_check_sm_labels_app_dir(const char *fpath, const struct stat *sb,
95 const char* correctLabel, bool transmute_test, bool exec_test)
99 char* label = nullptr;
102 result = smack_lgetlabel(fpath, &label, SMACK_LABEL_ACCESS);
103 RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
104 labelPtr.reset(label);
105 RUNNER_ASSERT_MSG(label != nullptr, "ACCESS label on " << fpath << " is not set");
106 result = strcmp(correctLabel, label);
107 RUNNER_ASSERT_MSG(result == 0, "ACCESS label on " << fpath << " is incorrect"
108 " (should be '" << correctLabel << "' and is '" << label << "')");
112 result = smack_lgetlabel(fpath, &label, SMACK_LABEL_EXEC);
113 RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
114 labelPtr.reset(label);
116 if (S_ISREG(sb->st_mode) && (sb->st_mode & S_IXUSR) && exec_test) {
117 RUNNER_ASSERT_MSG(label != nullptr, "EXEC label on " << fpath << " is not set");
118 result = strcmp(correctLabel, label);
119 RUNNER_ASSERT_MSG(result == 0, "Incorrect EXEC label on executable file " << fpath);
121 RUNNER_ASSERT_MSG(label == nullptr, "EXEC label on " << fpath << " is set");
125 result = smack_lgetlabel(fpath, &label, SMACK_LABEL_TRANSMUTE);
126 RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
127 labelPtr.reset(label);
129 if (S_ISDIR(sb->st_mode) && transmute_test == true) {
130 RUNNER_ASSERT_MSG(label != nullptr, "TRANSMUTE label on " << fpath << " is not set at all");
131 RUNNER_ASSERT_MSG(strcmp(label,"TRUE") == 0,
132 "TRANSMUTE label on " << fpath << " is not set properly: '"<<label<<"'");
134 RUNNER_ASSERT_MSG(label == nullptr, "TRANSMUTE label on " << fpath << " is set");
140 static int nftw_check_sm_labels(const char *fpath, const struct stat *sb,
141 int /*typeflag*/, struct FTW* /*ftwbuf*/)
143 return nftw_check_sm_labels_app_dir(fpath, sb,
144 nftw_expected_label.c_str(), nftw_expected_transmute, nftw_expected_exec);
147 int nftw_check_labels_non_app_dir(const char *fpath, const struct stat* /*sb*/,
148 int /*typeflag*/, struct FTW* /*ftwbuf*/)
152 char* label = nullptr;
155 result = smack_lgetlabel(fpath, &label, SMACK_LABEL_ACCESS);
156 labelPtr.reset(label);
157 RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
158 result = strcmp("canary_label", labelPtr.get());
159 RUNNER_ASSERT_MSG(result == 0, "ACCESS label on " << fpath << " is overwritten");
162 result = smack_lgetlabel(fpath, &label, SMACK_LABEL_EXEC);
163 labelPtr.reset(label);
164 RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
165 result = strcmp("canary_label", labelPtr.get());
166 RUNNER_ASSERT_MSG(result == 0, "EXEC label on " << fpath << " is overwritten");
169 result = smack_lgetlabel(fpath, &label, SMACK_LABEL_TRANSMUTE);
170 labelPtr.reset(label);
171 RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
172 RUNNER_ASSERT_MSG(labelPtr.get() == nullptr, "TRANSMUTE label on " << fpath << " is set");
177 int nftw_remove_labels(const char *fpath, const struct stat* /*sb*/,
178 int /*typeflag*/, struct FTW* /*ftwbuf*/)
180 smack_lsetlabel(fpath, nullptr, SMACK_LABEL_ACCESS);
181 smack_lsetlabel(fpath, nullptr, SMACK_LABEL_EXEC);
182 smack_lsetlabel(fpath, nullptr, SMACK_LABEL_TRANSMUTE);
187 void check_app_permissions(const std::string &app_id, const std::string &pkg_id,
188 const std::string &user, const privileges_t &allowed_privs,
189 const privileges_t &denied_privs, bool isHybrid)
192 std::string smackLabel = generateProcessLabel(app_id, pkg_id, isHybrid);
194 CynaraTestClient::Client ctc;
196 for (auto &priv : allowed_privs) {
197 ctc.check(smackLabel.c_str(), "", user, priv.c_str(), CYNARA_API_ACCESS_ALLOWED);
200 for (auto &priv : denied_privs) {
201 ctc.check(smackLabel.c_str(), "", user, priv.c_str(), CYNARA_API_ACCESS_DENIED);
205 void sm_app_has_privileges(const AppInstallHelper &app,
206 const std::vector<std::string> &privileges,
209 for (auto const &privilege : privileges) {
211 Api::appHasPrivilege(app.getAppId(), privilege, app.getUID(), result);
212 RUNNER_ASSERT_MSG(result == expectedResult, "Application " << app.getAppId()
213 << " has unexpected access to " << privilege << ", is : "
214 << " should be : " << expectedResult );
218 static void check_app(const std::string &appId, const std::string &pkgId, bool shouldBeInstalled)
221 int ret = security_manager_get_app_pkgid(&retPkgId, appId.c_str());
223 if (shouldBeInstalled) {
224 RUNNER_ASSERT_MSG(ret == SECURITY_MANAGER_SUCCESS, "The given appId is not installed.");
226 if (ret == SECURITY_MANAGER_SUCCESS) {
227 CStringPtr retPkgIdPtr(retPkgId);
228 RUNNER_ASSERT_MSG(strcmp(pkgId.c_str(), retPkgId) == 0,
229 "The given appId does not belong to the given pkgId.");
232 RUNNER_ASSERT_MSG(ret == SECURITY_MANAGER_ERROR_NO_SUCH_OBJECT, "The given appId is installed.");
236 void check_app_after_install(const std::string &app_id, const std::string &pkg_id)
238 check_app(app_id, pkg_id, true);
241 static void check_app_gids(const std::string &app_id, const std::vector<gid_t> &allowed_gids)
244 gid_t main_gid = getgid();
245 std::unordered_set<gid_t> reference_gids(allowed_gids.begin(), allowed_gids.end());
247 // Reset supplementary groups
248 ret = setgroups(0, NULL);
249 RUNNER_ASSERT_MSG(ret != -1, "Unable to set supplementary groups");
251 Api::setProcessGroups(app_id);
253 ret = getgroups(0, nullptr);
254 RUNNER_ASSERT_MSG(ret != -1, "Unable to get supplementary groups");
256 std::vector<gid_t> actual_gids(ret);
257 ret = getgroups(ret, actual_gids.data());
258 RUNNER_ASSERT_MSG(ret != -1, "Unable to get supplementary groups");
260 for (const auto &gid : actual_gids) {
261 RUNNER_ASSERT_MSG(gid == main_gid || reference_gids.count(gid) > 0,
262 "Application shouldn't get access to group " << gid);
263 reference_gids.erase(gid);
266 RUNNER_ASSERT_MSG(reference_gids.empty(), "Application didn't get access to some groups");
269 static const char *const ANY_USER_REPRESENTATION = "anyuser";/*this may be actually any string*/
271 void check_app_after_install(const std::string &app_id, const std::string &pkg_id,
272 const privileges_t &allowed_privs,
273 const privileges_t &denied_privs,
276 check_app(app_id, pkg_id, true);
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, isHybrid);
281 PolicyConfiguration policy;
282 const PolicyConfiguration::GroupVector allowed_groups = policy.privToGroup(allowed_privs);
283 RUNNER_ASSERT_MSG(allowed_groups.size() == allowed_privs.size(),
284 "Some privileges given were not found in the policy");
286 std::vector<gid_t> allowed_gids;
287 for (const auto &groupName : allowed_groups) {
289 struct group* grp = getgrnam(groupName.c_str());
290 RUNNER_ASSERT_ERRNO_MSG(grp, "Group: " << groupName << " not found");
291 allowed_gids.push_back(grp->gr_gid);
294 check_app_gids(app_id, allowed_gids);
297 void check_path(const std::string &path, const std::string &label, bool transmute, bool execute) {
298 nftw_expected_label = label;
299 nftw_expected_transmute = transmute;
300 nftw_expected_exec = execute;
303 int result = nftw(path.c_str(), &nftw_check_sm_labels, FTW_MAX_FDS, FTW_PHYS);
304 RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for " << path);
307 void check_app_after_uninstall(const std::string &app_id, const std::string &pkg_id)
309 check_app(app_id, pkg_id, false);
312 void check_app_after_uninstall(const std::string &app_id, const std::string &pkg_id,
313 const privileges_t &privileges, bool isHybrid)
315 check_app(app_id, pkg_id, false);
317 /* Privileges should not be granted anymore to any user */
318 check_app_permissions(app_id, pkg_id, ANY_USER_REPRESENTATION, {}, privileges, isHybrid);
321 std::string access_opposite(std::string &access) {
322 static const std::map<char, int> access_mapping = {{'r', 0}, {'w', 1}, {'x', 2}, {'a', 3},
324 // May write implies may lock
325 if (access.find('w') != std::string::npos && access.find('l') == std::string::npos) {
328 std::string access_opposite = "rwxatl";
329 for (char c : access) {
330 access_opposite[access_mapping.at(c)] = '-';
332 auto it = std::remove_if(access_opposite.begin(), access_opposite.end(), [](char c) {return c == '-';});
333 access_opposite.erase(it, access_opposite.end());
334 return access_opposite;
337 void check_exact_smack_accesses(const std::string &subject, const std::string &object,
338 const std::string &access) {
339 std::string access_str(access);
340 auto no_access = access_opposite(access_str);
341 for (char c : access_str) {
342 int ret = smack_have_access(subject.c_str(), object.c_str(), std::string(1, c).c_str());
343 RUNNER_ASSERT_MSG(ret >= 0, "smack_have_access failed: <" << subject << ">, <" << object
344 << ">, <" << c << "> errno=" << strerror(errno));
345 RUNNER_ASSERT_MSG(ret == 1, "Access " << c << " from " << subject << " to "
346 << object << " not given");
349 for (char c : no_access) {
350 int ret = smack_have_access(subject.c_str(), object.c_str(), std::string(1, c).c_str());
351 RUNNER_ASSERT_MSG(ret >= 0, "smack_have_access failed: <" << subject << ">, <" << object
352 << ">, <" << c << "> errno=" << strerror(errno));
353 RUNNER_ASSERT_MSG(ret == 0, "Access " << c << " from " << subject << " to "
354 << object << " unnecessarily given");
358 CapsSetsUniquePtr setCaps(const char *cap_string)
360 CapsSetsUniquePtr caps(cap_init());
361 caps.reset(cap_from_text(cap_string));
362 RUNNER_ASSERT_MSG(caps, "can't convert capabilities from text");
363 int result = cap_set_proc(caps.get());
364 RUNNER_ASSERT_MSG(result == 0, "can't set capabilities. Result: " << result);
368 pid_t runInChild(const std::function<void(void)> &process) {
370 RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "fork failed");
379 void runInChildParentWait(const std::function<void(void)> &process) {
381 RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "fork failed");
390 static int getOppositeAccessType(int accessType) {
391 return accessType ^ (R_OK | W_OK | X_OK);
394 static const std::unordered_map<int, const char* const> accessTypeToString {
395 std::make_pair(0, "F_OK"),
396 std::make_pair(1, "X_OK"),
397 std::make_pair(2, "W_OK"),
398 std::make_pair(3, "W_OK|X_OK"),
399 std::make_pair(4, "R_OK"),
400 std::make_pair(5, "R_OK|X_OK"),
401 std::make_pair(6, "R_OK|W_OK"),
402 std::make_pair(7, "R_OK|W_OK|X_OK")
405 void accessCheck(const std::string &id, const std::string &path, int accessType,
408 RUNNER_ASSERT_MSG(::access(path.c_str(), accessType) == expected,
409 "access from " << id << " to path " << path
410 << (expected == 0 ? " not granted" : " unnecessarily granted")
411 << " (" << accessTypeToString.at(accessType) << ")");
414 void runAccessTest(const std::string &label, uid_t uid, gid_t gid,
415 const std::string &testPath, int accessType) {
417 int oppositeAccessType = getOppositeAccessType(accessType);
418 change_label(label.c_str());
419 RUNNER_ASSERT_ERRNO_MSG(0 == drop_root_privileges(uid, gid),
420 "drop_root_privileges failed.");
423 accessCheck(label, testPath, accessType, 0);
424 if (oppositeAccessType != 0) {
425 std::vector<int> singleAccessTypes = {R_OK, W_OK, X_OK};
426 for (auto singleAccessType : singleAccessTypes)
427 if (oppositeAccessType & singleAccessType)
428 accessCheck(label, testPath, singleAccessType, -1);
432 runInChildParentWait(fun);
435 void runAccessTest(const AppInstallHelper &app, const std::string &testPath, int accessType) {
437 int oppositeAccessType = getOppositeAccessType(accessType);
438 Api::setProcessLabel(app.getAppId());
439 RUNNER_ASSERT_ERRNO_MSG(0 == drop_root_privileges(app.getUID(), app.getGID()),
440 "drop_root_privileges failed.");
442 accessCheck(app.getAppId(), testPath, accessType, 0);
443 if (oppositeAccessType != 0) {
444 std::vector<int> singleAccessTypes = {R_OK, W_OK, X_OK};
445 for (auto singleAccessType : singleAccessTypes)
446 if (oppositeAccessType & singleAccessType)
447 accessCheck(app.getAppId(), testPath, singleAccessType, -1);
451 runInChildParentWait(fun);
454 static const std::vector<std::string> SM_SYSTEM_LABELS = {"System", "System::Privileged", "User"};
456 void runSystemAccessTest(uid_t uid, gid_t gid, const std::string &testPath, int accessType) {
457 for (const auto &label : SM_SYSTEM_LABELS)
458 runAccessTest(label, uid, gid, testPath, accessType);
461 bool isAskuserDisabled() {
462 static bool isAskuserDisabled = false;
463 static bool isChecked = false;
466 return isAskuserDisabled;
468 std::string sysShare = TzPlatformConfig::getPath(TZ_SYS_SHARE);
469 std::string askDisableFile = sysShare + "/askuser_disable";
471 isAskuserDisabled = (access(askDisableFile.c_str(), F_OK) != -1);
473 return isAskuserDisabled;
476 bool isPrivilegePrivacy(const std::string &priv) {
477 return (1 == privilege_info_is_privacy(priv.c_str()));
480 int countPrivacyPrivileges(const PrivilegeVector &privs) {
481 return std::count_if(privs.begin(), privs.end(), isPrivilegePrivacy);
484 int countPrivacyPrivileges(const std::vector<std::string> &privs) {
485 return std::count_if(privs.begin(), privs.end(), isPrivilegePrivacy);