CACHE PATH
"Read-only test database directory")
+SET(PRIV_MAPPING_INSTALL_SUBDIR
+ "privilege-mapping"
+ CACHE PATH
+ "Read-only privilege Smack mapping directory")
+
ADD_DEFINITIONS("-DDB_INSTALL_DIR=\"${DB_INSTALL_DIR}\"")
ADD_DEFINITIONS("-DLOCAL_STATE_INSTALL_DIR=\"${LOCAL_STATE_INSTALL_DIR}\"")
ADD_DEFINITIONS("-DDATA_INSTALL_DIR=\"${DATA_INSTALL_DIR}\"")
ADD_DEFINITIONS("-DPOLICY_INSTALL_DIR=\"${POLICY_INSTALL_DIR}\"")
ADD_DEFINITIONS("-DDB_TEST_INSTALL_DIR=\"${DB_TEST_INSTALL_DIR}\"")
+ADD_DEFINITIONS("-DPRIV_MAPPING_INSTALL_SUBDIR=\"${PRIV_MAPPING_INSTALL_SUBDIR}\"")
############################# compiler flags ##################################
CONFIGURE_FILE(security-manager-policy-reload.in security-manager-policy-reload @ONLY)
+SET(PRIV_MAPPING_TEMPLATE_FILES
+ "priv-rules-default-template.smack")
+SET(INSTALL_TEMPLATE_FILES
+ "app-rules-template.smack"
+ "pkg-rules-template.smack"
+ "author-rules-template.smack"
+ )
+
INSTALL(FILES ${USERTYPE_POLICY_FILES} DESTINATION ${POLICY_INSTALL_DIR})
-INSTALL(FILES "app-rules-template.smack" DESTINATION ${POLICY_INSTALL_DIR})
-INSTALL(FILES "pkg-rules-template.smack" DESTINATION ${POLICY_INSTALL_DIR})
-INSTALL(FILES "author-rules-template.smack" DESTINATION ${POLICY_INSTALL_DIR})
+INSTALL(FILES ${PRIV_MAPPING_TEMPLATE_FILES}
+ DESTINATION "${POLICY_INSTALL_DIR}/${PRIV_MAPPING_INSTALL_SUBDIR}")
+INSTALL(FILES ${INSTALL_TEMPLATE_FILES} DESTINATION ${POLICY_INSTALL_DIR})
INSTALL(FILES "privilege-group.list" DESTINATION ${POLICY_INSTALL_DIR})
INSTALL(FILES "privilege-mount.list" DESTINATION ${POLICY_INSTALL_DIR})
+INSTALL(FILES "privilege-smack.list" DESTINATION ${POLICY_INSTALL_DIR})
INSTALL(FILES "privilege-managed-by-systemd-for-daemons.list" DESTINATION ${POLICY_INSTALL_DIR})
INSTALL(PROGRAMS "update.sh" DESTINATION ${POLICY_INSTALL_DIR})
INSTALL(DIRECTORY "updates" USE_SOURCE_PERMISSIONS DESTINATION ${POLICY_INSTALL_DIR})
ADD_CUSTOM_COMMAND(OUTPUT ${GEN_FILE}
COMMAND mkdir -p "${GEN_PATH}"
- COMMAND ${GENERATOR} *.smack > ${GEN_FILE}
- DEPENDS ${GENERATOR} "*.smack"
+ COMMAND ${GENERATOR} ${INSTALL_TEMPLATE_FILES} > ${GEN_FILE}
+ DEPENDS ${GENERATOR} ${INSTALL_TEMPLATE_FILES}
)
ADD_CUSTOM_TARGET(generate_rule_template_code DEPENDS ${GEN_FILE})
--- /dev/null
+~PROCESS~ ~PRIVILEGE~ w
+~PRIVILEGE~ ~PROCESS~ w
--- /dev/null
+# Configuration of Smack label and rules mapping of privileges
+# Format:
+# - Each line of "<PRIVILEGE> <SMACK LABEL> <SMACK RULES TEMPLATE>" describes
+# single mapping
+# * <PRIVILEGE>: name of enforced privilege
+# * <SMACK LABEL>: unique Smack label mapped to given privilege
+# * <SMACK RULES TEMPLATE>: full filename of existing template file in security-manager
+# policy configuration dir (usually /usr/share/security-manager/policy/), which will be
+# used to generate Smack rules
+#
+# - <SMACK RULES TEMPLATE> may be set to special value "default".
+# In such case 'priv-rules-default-template.smack' will be used.
+#
+# - lines starting with '#' or empty lines are ignored
+
+http://tizen.org/privilege/internet System::Privilege::Internet default
#define APPS_LABELS_FILE "apps-labels"
/* Policy files */
+
#define PRIVILEGE_GROUP_LIST_FILE POLICY_INSTALL_DIR "/privilege-group.list"
#define PRIVILEGE_MOUNT_LIST_FILE POLICY_INSTALL_DIR "/privilege-mount.list"
+#define PRIVILEGE_SMACK_LIST_FILE POLICY_INSTALL_DIR "/privilege-smack.list"
#define PRIVILEGE_SYSTEMD_LIST_FILE POLICY_INSTALL_DIR "/privilege-managed-by-systemd-for-daemons.list"
#define SKEL_DIR "/etc/skel"
int policyGetDesc(std::vector<std::string> &descriptions);
/**
+ * Get vector of privileges allowed for given application.
+ *
+ * @param[in] appProcessLabel Smack label of application process
+ * @param[in] uid user id of given application process
+ * @param[out] allowedPrivilege vector of privileges allowed for given application
+ *
+ * @return API return code, as defined in protocols.h
+ */
+ int getAppAllowedPrivileges(const std::string &appProcessLabel, uid_t uid,
+ std::vector<std::string> &allowedPrivileges);
+
+ /**
* Process query for resources group list and supplementary groups allowed for the application.
* For given \ref appProcessLabel and \ref uid, calculate allowed privileges that give
* direct access to file system resources. For each permission Cynara will be
* queried.
* Returns set of group ids that are permitted.
*
- * @param[in] creds credentials of the requesting process
* @param[in] appProcessLabel application name
+ * @param[in] allowedPrivileges privileges allowed for application
* @param[out] forbiddenGroups returned sorted vector of forbidden groups
* @param[out] allowedGroups returned sorted vector of allowed groups
*
* @return API return code, as defined in protocols.h
*/
- int getForbiddenAndAllowedGroups(const Credentials &creds, const std::string &appProcessLabel,
+ int getForbiddenAndAllowedGroups(const std::string &appProcessLabel,
+ const std::vector<std::string> &allowedPrivileges,
std::vector<gid_t> &forbiddenGroups, std::vector<gid_t> &allowedGroups);
/**
/*
- * Copyright (c) 2014-2016 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved
*
* Contact: Rafal Krypa <r.krypa@samsung.com>
*
const std::string &pkgName,
const int authorId);
+ void addFromPrivTemplate(
+ const RuleVector &templateRules,
+ const std::string &appProcessLabel,
+ const std::string &privilegeLabel,
+ const std::string &pkgName,
+ int authorId);
+
+ void addFromPrivTemplateFile(
+ const std::string &templatePath,
+ const std::string &appProcessLabel,
+ const std::string &privilegeLabel,
+ const std::string &pkgName,
+ int authorId);
+
void apply() const;
void clear() const;
const Labels &pkgLabels);
/**
+ * Enable privilege-specific smack rules for given application
+ *
+ * Function creates privilege-specific smack rules using predefined templates.
+ * Rules are applied to the kernel.
+ *
+ * @param[in] appProcessLabel - process label of the application
+ * @param[in] pkgName - package id of given application
+ * @param[in] authorId - author id of given application (if not applicable, set to -1)
+ * @param[in] privileges - a list of privileges allowed for given application
+ */
+ static void enablePrivilegeRules(
+ const std::string &appProcessLabel,
+ const std::string &pkgName,
+ int authorId,
+ const std::vector<std::string> &privileges);
+
+ /**
* Uninstall package-specific smack rules.
*
* Function loads package-specific smack rules, revokes them from the kernel.
bool isPathSharedNoMore,
bool isTargetSharingNoMore);
+ /**
+ * Revoke rules for which label of given \ref appName is a subject.
+ *
+ * @param[in] appProcessLabel = application process label
+ */
+ static void revokeAppSubject(const std::string &appProcessLabel);
+
private:
static void useTemplate(
const std::string &templatePath,
const std::string &replace);
smack_accesses *m_handle;
-
- /**
- * Revoke rules for which label of given \ref appName is a subject.
- *
- * @param[in] appProcessLabel = application process label
- */
- static void revokeAppSubject(const std::string &appProcessLabel);
};
} // namespace SecurityManager
return ret;
}
-int ServiceImpl::getForbiddenAndAllowedGroups(const Credentials &creds, const std::string &appProcessLabel,
- std::vector<gid_t> &forbiddenGroups, std::vector<gid_t> &allowedGroups)
+int ServiceImpl::getAppAllowedPrivileges(const std::string &appProcessLabel,
+ uid_t uid, std::vector<std::string> &allowedPrivileges)
{
try {
- LogDebug("smack label: " << appProcessLabel);
+ LogDebug("Getting allowed privileges for " << appProcessLabel << " and user " << uid);
+ std::string uidStr = std::to_string(uid);
std::vector<std::string> privileges;
-
- std::string uidStr = std::to_string(creds.uid);
m_cynaraAdmin.getAppPolicy(appProcessLabel, uidStr, privileges);
m_cynaraAdmin.getAppPolicy(appProcessLabel, CYNARA_ADMIN_WILDCARD, privileges);
m_cynaraAdmin.getAppPolicy(CYNARA_ADMIN_WILDCARD, CYNARA_ADMIN_WILDCARD, privileges);
vectorRemoveDuplicates(privileges);
+ for (auto &privilege : privileges) {
+ if (m_cynara.check(appProcessLabel, privilege, uidStr, "")) {
+ allowedPrivileges.push_back(privilege);
+ }
+ }
+ } catch (const CynaraException::Base &e) {
+ LogError("Error while querying Cynara for permissions: " << e.DumpToString());
+ return SECURITY_MANAGER_ERROR_SERVER_ERROR;
+ } catch (const std::bad_alloc &e) {
+ LogError("Memory allocation failed " << e.what());
+ return SECURITY_MANAGER_ERROR_MEMORY;
+ }
- std::string pidStr = std::to_string(creds.pid);
- for (const auto &privilege : privileges) {
+ return SECURITY_MANAGER_SUCCESS;
+}
+
+int ServiceImpl::getForbiddenAndAllowedGroups(
+ const std::string &appProcessLabel, const std::vector<std::string> &allowedPrivileges,
+ std::vector<gid_t> &forbiddenGroups, std::vector<gid_t> &allowedGroups)
+{
+
+ try {
+ LogDebug("smack label: " << appProcessLabel);
+
+ for (const auto &privilege : allowedPrivileges) {
const auto &pgids = m_privilegeGids.getGids(privilege);
- LogDebug("Considering privilege " << privilege << " with " <<
+ LogDebug("Using privilege " << privilege << " with " <<
pgids.size() << " groups assigned");
if (pgids.empty())
continue;
- if (m_cynara.check(appProcessLabel, privilege, uidStr, pidStr)) {
- allowedGroups.insert(allowedGroups.end(), pgids.begin(), pgids.end());
- LogDebug("Cynara allowed, adding groups");
- } else {
- LogDebug("Cynara denied, not adding groups");
- }
+ allowedGroups.insert(allowedGroups.end(), pgids.begin(), pgids.end());
+
}
vectorRemoveDuplicates(allowedGroups); // sorted
forbiddenGroups.reserve(gids.size());
std::set_difference(gids.begin(), gids.end(), allowedGroups.begin(), allowedGroups.end(),
std::back_inserter(forbiddenGroups)); // sorted
- } catch (const CynaraException::Base &e) {
- LogError("Error while querying Cynara for permissions: " << e.DumpToString());
- return SECURITY_MANAGER_ERROR_SERVER_ERROR;
} catch (const std::bad_alloc &e) {
LogError("Memory allocation failed: " << e.what());
return SECURITY_MANAGER_ERROR_MEMORY;
return SECURITY_MANAGER_ERROR_UNKNOWN;
label = SmackLabels::generateProcessLabel(appName, pkgName, isHybrid);
- int ret = getForbiddenAndAllowedGroups(creds, label, forbiddenGroups, allowedGroups);
+ std::vector<std::string> allowedPrivileges;
+ int ret = getAppAllowedPrivileges(label, creds.uid, allowedPrivileges);
+ if (ret != SECURITY_MANAGER_SUCCESS) {
+ LogError("Failed to fetch allowed privileges for " << label);
+ return ret;
+ }
+
+ int authorId;
+ m_privilegeDb.GetPkgAuthorId(pkgName, authorId);
+
+ std::vector<std::string> pkgLabels;
+ getPkgLabels(pkgName, pkgLabels);
+
+ SmackRules::revokeAppSubject(label);
+ SmackRules::installApplicationRules(label, pkgName, authorId, pkgLabels);
+ SmackRules::enablePrivilegeRules(label, pkgName, authorId, allowedPrivileges);
+
+ ret = getForbiddenAndAllowedGroups(label, allowedPrivileges, forbiddenGroups,
+ allowedGroups);
return ret != SECURITY_MANAGER_SUCCESS ? ret
: appSetupNamespace(creds, label, privilegeVector, privilegeStatusVector);
}
#include <memory>
#include <algorithm>
+#include "config.h"
#include "config-file.h"
#include "dpl/log/log.h"
#include "dpl/errno_string.h"
const std::string SMACK_PATH_RW_LABEL_TEMPLATE = "~PATH_RW~";
const std::string SMACK_PATH_RO_LABEL_TEMPLATE = "~PATH_RO~";
const std::string SMACK_PATH_TRUSTED_LABEL_TEMPLATE = "~PATH_TRUSTED~";
+const std::string SMACK_PRIVILEGE_LABEL_TEMPLATE = "~PRIVILEGE~";
enum POLICY_FILE {
APP_RULES_TEMPLATE,
PKG_RULES_TEMPLATE,
- AUTHOR_RULES_TEMPLATE
+ AUTHOR_RULES_TEMPLATE,
+ PRIV_DEFAULT_RULES_TEMPLATE,
+ PRIV_RULES_TEMPLATE
};
const std::string POLICY_DIR_STR = POLICY_INSTALL_DIR;
+const std::string PRIV_MAPPING_DIR_STR = POLICY_INSTALL_DIR "/" PRIV_MAPPING_INSTALL_SUBDIR;
std::map<POLICY_FILE, std::string> POLICY_FILE_PATH_MAP = {
{POLICY_FILE::APP_RULES_TEMPLATE, POLICY_DIR_STR + "/app-rules-template.smack"},
{POLICY_FILE::PKG_RULES_TEMPLATE, POLICY_DIR_STR + "/pkg-rules-template.smack"},
- {POLICY_FILE::AUTHOR_RULES_TEMPLATE, POLICY_DIR_STR + "/author-rules-template.smack"}
+ {POLICY_FILE::AUTHOR_RULES_TEMPLATE, POLICY_DIR_STR + "/author-rules-template.smack"},
+ {POLICY_FILE::PRIV_DEFAULT_RULES_TEMPLATE,
+ PRIV_MAPPING_DIR_STR + "/priv-rules-default-template.smack"}
};
-std::string getPolicyFile(enum POLICY_FILE policyFile) {
+std::string getPolicyFile(enum POLICY_FILE policyFile, const std::string &privFile = "") {
+ if (policyFile == POLICY_FILE::PRIV_RULES_TEMPLATE) {
+ return PRIV_MAPPING_DIR_STR + "/" + privFile;
+ }
return POLICY_FILE_PATH_MAP[policyFile];
}
const std::string SMACK_APP_PATH_SYSTEM_PERMS = "rwxat";
const std::string SMACK_APP_PATH_USER_PERMS = "rwxat";
+const std::string PRIV_TEMPLATE_DEFAULT = "default";
+
SmackRules::SmackRules()
{
if (smack_accesses_new(&m_handle) < 0) {
}
}
+void SmackRules::addFromPrivTemplate(
+ const RuleVector &templateRules,
+ const std::string &appProcessLabel,
+ const std::string &privilegeLabel,
+ const std::string &pkgName,
+ int authorId)
+{
+ std::string pathRWLabel, pathROLabel;
+ std::string pathTrustedLabel;
+
+ if (!pkgName.empty()) {
+ pathRWLabel = SmackLabels::generatePathRWLabel(pkgName);
+ pathROLabel = SmackLabels::generatePathROLabel(pkgName);
+ }
+
+ if (authorId >= 0)
+ pathTrustedLabel = SmackLabels::generatePathTrustedLabel(authorId);
+
+ for (auto &rule : templateRules) {
+ if (rule.size() != 3) {
+ LogError("Invalid rule template: " << rule.size() << " tokens");
+ ThrowMsg(SmackException::FileError, "Invalid rule template: " << rule.size() << " tokens");
+ }
+
+ std::string subject = rule[0];
+ std::string object = rule[1];
+ std::string permissions = rule[2];
+
+ strReplace(subject, SMACK_PROCESS_LABEL_TEMPLATE, appProcessLabel);
+ strReplace(subject, SMACK_PRIVILEGE_LABEL_TEMPLATE, privilegeLabel);
+ strReplace(object, SMACK_PROCESS_LABEL_TEMPLATE, appProcessLabel);
+ strReplace(object, SMACK_PRIVILEGE_LABEL_TEMPLATE, privilegeLabel);
+ strReplace(object, SMACK_PATH_RW_LABEL_TEMPLATE, pathRWLabel);
+ strReplace(object, SMACK_PATH_RO_LABEL_TEMPLATE, pathROLabel);
+ strReplace(object, SMACK_PATH_TRUSTED_LABEL_TEMPLATE, pathTrustedLabel);
+
+ if (subject.empty() || object.empty())
+ continue;
+ add(subject, object, permissions);
+ }
+}
+
+void SmackRules::addFromPrivTemplateFile(
+ const std::string &templatePath,
+ const std::string &appProcessLabel,
+ const std::string &privilegeLabel,
+ const std::string &pkgName,
+ int authorId)
+{
+ try {
+ addFromPrivTemplate(ConfigFile(templatePath).read(), appProcessLabel, privilegeLabel,
+ pkgName, authorId);
+ } catch (FS::Exception::Base &) {
+ LogError("Error reading template file: " << templatePath);
+ ThrowMsg(SmackException::FileError, "Error reading template file: " << templatePath);
+ }
+}
+
void SmackRules::generatePackageCrossDeps(const Labels &pkgLabels)
{
LogDebug("Generating cross-package rules");
updatePackageRules(pkgName, pkgLabels);
}
+void SmackRules::enablePrivilegeRules(
+ const std::string &appProcessLabel,
+ const std::string &pkgName,
+ int authorId,
+ const std::vector<std::string> &privileges)
+{
+ if (privileges.empty()) {
+ // No rules to apply
+ return;
+ }
+
+ SmackRules smackRules;
+
+ auto privMapping = ConfigFile(PRIVILEGE_SMACK_LIST_FILE).read();
+
+ for (auto &mapping : privMapping) {
+ if (mapping.size() != 3)
+ continue;
+
+ auto &privName = mapping[0];
+ auto &privLabel = mapping[1];
+ auto &privTemplate = mapping[2];
+
+ if (privTemplate == PRIV_TEMPLATE_DEFAULT) {
+ privTemplate = getPolicyFile(POLICY_FILE::PRIV_DEFAULT_RULES_TEMPLATE);
+ } else {
+ privTemplate = getPolicyFile(POLICY_FILE::PRIV_RULES_TEMPLATE, privTemplate);
+ }
+
+ for (auto &privilege : privileges) {
+ if (privilege == privName) {
+ smackRules.addFromPrivTemplateFile(privTemplate, appProcessLabel, privLabel,
+ pkgName, authorId);
+ break;
+ }
+ }
+ }
+
+ if (smack_check())
+ smackRules.apply();
+}
+
void SmackRules::updatePackageRules(
const std::string &pkgName,
const Labels &pkgLabels)
std::vector<gid_t> forbiddenGroups, allowedGroups;
Deserialization::Deserialize(buffer, appName);
- int ret = serviceImpl.getForbiddenAndAllowedGroups(creds, serviceImpl.getProcessLabel(appName), forbiddenGroups, allowedGroups);
+
+ std::string label = serviceImpl.getProcessLabel(appName);
+ std::vector<std::string> allowedPrivileges;
+ int ret = serviceImpl.getAppAllowedPrivileges(label, creds.uid, allowedPrivileges);
+ if (ret != SECURITY_MANAGER_SUCCESS) {
+ LogError("Failed to fetch allowed privileges for " << label);
+ Serialization::Serialize(send, ret);
+ return;
+ }
+ ret = serviceImpl.getForbiddenAndAllowedGroups(label, allowedPrivileges, forbiddenGroups,
+ allowedGroups);
Serialization::Serialize(send, ret);
if (ret == SECURITY_MANAGER_SUCCESS) {
Serialization::Serialize(send, forbiddenGroups, allowedGroups);