/*
- * Copyright (c) 2016 - 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2016 - 2020 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* limitations under the License.
*/
-#include <algorithm>
#include <cstring>
#include <fcntl.h>
#include <ftw.h>
-#include <grp.h>
#include <string>
#include <sys/capability.h>
+#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <unistd.h>
-#include <unordered_map>
#include <cstdlib>
-#include <unordered_set>
+#include <utility>
#include <vector>
+#include <unordered_map>
#include <security-manager-types.h>
#include <app-runtime.h>
-#include <sys/smack.h>
#include <privilege_info.h>
#include <scoped_process_label.h>
-#include <cynara_test_client.h>
#include <dpl/test/test_runner.h>
#include <memory.h>
#include <sm_api.h>
#include <sm_commons.h>
-#include <synchronization_pipe.h>
-#include <sm_request.h>
+
#include <tests_common.h>
-#include <policy_configuration.h>
#include "tzplatform.h"
-#include <label_generator.h>
+#include <template_parser.h>
+#include <temp_test_user.h>
using namespace SecurityManagerTest;
+#define ALLOW 0
+#define DENY -1
+
// Common DB/nftw checks
// nftw doesn't allow passing user data to functions. Work around by using global variable
return 0;
}
-void check_app_permissions(const std::string &app_id, const std::string &pkg_id,
- const std::string &user, const privileges_t &allowed_privs,
- const privileges_t &denied_privs, bool isHybrid)
-{
- (void) pkg_id;
- std::string smackLabel = generateProcessLabel(app_id, pkg_id, isHybrid);
-
- CynaraTestClient::Client ctc;
-
- for (auto &priv : allowed_privs) {
- ctc.check(smackLabel.c_str(), "", user, priv.c_str(), CYNARA_API_ACCESS_ALLOWED);
- }
-
- for (auto &priv : denied_privs) {
- ctc.check(smackLabel.c_str(), "", user, priv.c_str(), CYNARA_API_ACCESS_DENIED);
- }
-}
-
-void sm_app_has_privileges(const AppInstallHelper &app,
- const std::vector<std::string> &privileges,
- int expectedResult)
-{
- for (auto const &privilege : privileges) {
- int result;
- Api::appHasPrivilege(app.getAppId(), privilege, app.getUID(), result);
- RUNNER_ASSERT_MSG(result == expectedResult, "Application " << app.getAppId()
- << " has unexpected access to " << privilege << ", is : "
- << " should be : " << expectedResult );
- }
-}
-
-static void check_app(const std::string &appId, const std::string &pkgId, bool shouldBeInstalled)
-{
- char *retPkgId;
- int ret = security_manager_get_app_pkgid(&retPkgId, appId.c_str());
-
- if (shouldBeInstalled) {
- RUNNER_ASSERT_MSG(ret == SECURITY_MANAGER_SUCCESS, "The given appId is not installed.");
-
- if (ret == SECURITY_MANAGER_SUCCESS) {
- CStringPtr retPkgIdPtr(retPkgId);
- RUNNER_ASSERT_MSG(strcmp(pkgId.c_str(), retPkgId) == 0,
- "The given appId does not belong to the given pkgId.");
- }
- } else {
- RUNNER_ASSERT_MSG(ret == SECURITY_MANAGER_ERROR_NO_SUCH_OBJECT, "The given appId is installed.");
- }
-}
-
-void check_app_after_install(const std::string &app_id, const std::string &pkg_id)
-{
- check_app(app_id, pkg_id, true);
-}
-
-static void check_app_gids(const std::string &app_id, const std::vector<gid_t> &allowed_gids)
-{
- int ret;
- gid_t main_gid = getgid();
- std::unordered_set<gid_t> reference_gids(allowed_gids.begin(), allowed_gids.end());
-
- // Reset supplementary groups
- ret = setgroups(0, NULL);
- RUNNER_ASSERT_MSG(ret != -1, "Unable to set supplementary groups");
-
- Api::setProcessGroups(app_id);
-
- ret = getgroups(0, nullptr);
- RUNNER_ASSERT_MSG(ret != -1, "Unable to get supplementary groups");
-
- std::vector<gid_t> actual_gids(ret);
- ret = getgroups(ret, actual_gids.data());
- RUNNER_ASSERT_MSG(ret != -1, "Unable to get supplementary groups");
-
- for (const auto &gid : actual_gids) {
- RUNNER_ASSERT_MSG(gid == main_gid || reference_gids.count(gid) > 0,
- "Application shouldn't get access to group " << gid);
- reference_gids.erase(gid);
- }
-
- RUNNER_ASSERT_MSG(reference_gids.empty(), "Application didn't get access to some groups");
-}
-
-static const char *const ANY_USER_REPRESENTATION = "anyuser";/*this may be actually any string*/
-
-void check_app_after_install(const std::string &app_id, const std::string &pkg_id,
- const privileges_t &allowed_privs,
- const privileges_t &denied_privs,
- bool isHybrid)
-{
- check_app(app_id, pkg_id, true);
-
- /* Privileges should be granted to all users if root installs app */
- check_app_permissions(app_id, pkg_id, ANY_USER_REPRESENTATION, allowed_privs, denied_privs, isHybrid);
-
- PolicyConfiguration policy;
- const PolicyConfiguration::GroupVector allowed_groups = policy.privToGroup(allowed_privs);
- RUNNER_ASSERT_MSG(allowed_groups.size() == allowed_privs.size(),
- "Some privileges given were not found in the policy");
-
- std::vector<gid_t> allowed_gids;
- for (const auto &groupName : allowed_groups) {
- errno = 0;
- struct group* grp = getgrnam(groupName.c_str());
- RUNNER_ASSERT_ERRNO_MSG(grp, "Group: " << groupName << " not found");
- allowed_gids.push_back(grp->gr_gid);
- }
-
- check_app_gids(app_id, allowed_gids);
-}
-
void check_path(const std::string &path, const std::string &label, bool transmute, bool execute) {
nftw_expected_label = label;
nftw_expected_transmute = transmute;
RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for " << path);
}
-void check_app_after_uninstall(const std::string &app_id, const std::string &pkg_id)
-{
- check_app(app_id, pkg_id, false);
-}
-
-void check_app_after_uninstall(const std::string &app_id, const std::string &pkg_id,
- const privileges_t &privileges, bool isHybrid)
-{
- check_app(app_id, pkg_id, false);
-
- /* Privileges should not be granted anymore to any user */
- check_app_permissions(app_id, pkg_id, ANY_USER_REPRESENTATION, {}, privileges, isHybrid);
-}
-
-std::string access_opposite(std::string &access) {
- static const std::map<char, int> access_mapping = {{'r', 0}, {'w', 1}, {'x', 2}, {'a', 3},
- {'t', 4}, {'l', 5}};
- // May write implies may lock
- if (access.find('w') != std::string::npos && access.find('l') == std::string::npos) {
- access.append("l");
- }
- std::string access_opposite = "rwxatl";
- for (char c : access) {
- access_opposite[access_mapping.at(c)] = '-';
- }
- auto it = std::remove_if(access_opposite.begin(), access_opposite.end(), [](char c) {return c == '-';});
- access_opposite.erase(it, access_opposite.end());
- return access_opposite;
-}
-
-void check_exact_smack_accesses(const std::string &subject, const std::string &object,
- const std::string &access) {
- std::string access_str(access);
- auto no_access = access_opposite(access_str);
- for (char c : access_str) {
- int ret = smack_have_access(subject.c_str(), object.c_str(), std::string(1, c).c_str());
- RUNNER_ASSERT_MSG(ret >= 0, "smack_have_access failed: <" << subject << ">, <" << object
- << ">, <" << c << "> errno=" << strerror(errno));
- RUNNER_ASSERT_MSG(ret == 1, "Access " << c << " from " << subject << " to "
- << object << " not given");
- }
-
- for (char c : no_access) {
- int ret = smack_have_access(subject.c_str(), object.c_str(), std::string(1, c).c_str());
- RUNNER_ASSERT_MSG(ret >= 0, "smack_have_access failed: <" << subject << ">, <" << object
- << ">, <" << c << "> errno=" << strerror(errno));
- RUNNER_ASSERT_MSG(ret == 0, "Access " << c << " from " << subject << " to "
- << object << " unnecessarily given");
- }
-}
-
CapsSetsUniquePtr setCaps(const char *cap_string)
{
CapsSetsUniquePtr caps(cap_init());
<< " (" << accessTypeToString.at(accessType) << ")");
}
+void accessTest(const std::string &id, const std::string &testPath, int accessType) {
+ int oppositeAccessType = getOppositeAccessType(accessType);
+
+ if (accessType != 0) {
+ accessCheck(id, testPath, accessType, ALLOW);
+ }
+ if (oppositeAccessType != 0) {
+ static const std::vector<int> singleAccessTypes = {R_OK, W_OK, X_OK};
+ for (auto singleAccessType : singleAccessTypes) {
+ if (oppositeAccessType & singleAccessType) {
+ accessCheck(id, testPath, singleAccessType, DENY);
+ }
+ }
+ }
+}
+
void runAccessTest(const std::string &label, uid_t uid, gid_t gid,
const std::string &testPath, int accessType) {
auto fun = [&](){
- int oppositeAccessType = getOppositeAccessType(accessType);
ScopedProcessLabel spl(label, false);
RUNNER_ASSERT_ERRNO_MSG(0 == drop_root_privileges(uid, gid),
"drop_root_privileges failed.");
- if (accessType != 0)
- accessCheck(label, testPath, accessType, 0);
- if (oppositeAccessType != 0) {
- std::vector<int> singleAccessTypes = {R_OK, W_OK, X_OK};
- for (auto singleAccessType : singleAccessTypes)
- if (oppositeAccessType & singleAccessType)
- accessCheck(label, testPath, singleAccessType, -1);
- }
+ accessTest(label, testPath, accessType);
};
runInChildParentWait(fun);
void runAccessTest(const AppInstallHelper &app, const std::string &testPath, int accessType) {
auto fun = [&](){
- int oppositeAccessType = getOppositeAccessType(accessType);
Api::setProcessLabel(app.getAppId());
RUNNER_ASSERT_ERRNO_MSG(0 == drop_root_privileges(app.getUID(), app.getGID()),
"drop_root_privileges failed.");
- if (accessType != 0)
- accessCheck(app.getAppId(), testPath, accessType, 0);
- if (oppositeAccessType != 0) {
- std::vector<int> singleAccessTypes = {R_OK, W_OK, X_OK};
- for (auto singleAccessType : singleAccessTypes)
- if (oppositeAccessType & singleAccessType)
- accessCheck(app.getAppId(), testPath, singleAccessType, -1);
- }
+ accessTest(app.getAppId(), testPath, accessType);
};
runInChildParentWait(fun);
return std::count_if(privs.begin(), privs.end(), isPrivilegePrivacy);
}
+int setLauncherSecurityAttributes(uid_t uid, gid_t gid)
+{
+ // Add launcher capabilities (cap_dac_override, cap_setgid, cap_sys_admin, cap_mac_admin),
+ // launcher is user process, we must drop root privileges (cap_setgid, cap_setuid are needed).
+ // By default, the permitted capability set is cleared when credentials change is made
+ // (if a process drops a capability from its permitted set, it can never reacquire that capability),
+ // setting the "keep capabilities" flag prevents it from being cleared.
+ // Effective capability set is always cleared when credential change is made, we need to add them again.
+
+ setCaps("cap_dac_override+ep cap_setgid+ep cap_sys_admin+ep cap_mac_admin+ep cap_setuid+ep");
+ int ret = prctl(PR_SET_KEEPCAPS, 1, 0, 0);
+ if (ret != 0)
+ return ret;
+
+ ret = drop_root_privileges(uid, gid);
+ if (ret != 0)
+ return ret;
+
+ setCaps("cap_dac_override+ep cap_setgid+ep cap_sys_admin+ep cap_mac_admin+ep");
+ return ret;
+}
+int setLauncherSecurityAttributes(TemporaryTestUser &user)
+{
+ return setLauncherSecurityAttributes(user.getUid(), user.getGid());
+}
+