#include <dirent.h>
#include <cstring>
#include <algorithm>
+#include <memory>
#include <dpl/log/log.h>
#include <dpl/errno_string.h>
+#include <app_manager.h>
#include <sys/smack.h>
#include <config.h>
return ret;
}
+typedef std::map<std::string, std::vector<std::string>> AppsAllowedPrivilegesMap;
+
+namespace {
+
+struct AppManagerCallbackContext {
+ ServiceImpl *impl;
+ AppsAllowedPrivilegesMap *appsAllowedPrivileges;
+};
+
+std::string getAppIdFromContext(app_context_h app_context)
+{
+ char *appId;
+ int ret = app_context_get_app_id (app_context, &appId);
+ if (ret != APP_MANAGER_ERROR_NONE) {
+ LogError("Failed to get appId from app_context: " << ret);
+ return "";
+ }
+ std::unique_ptr<char, decltype(std::free) *> appIdPtr(appId, std::free);
+ std::string appIdStr(appId);
+ appIdPtr.release();
+ return appIdStr;
+}
+
+} // namespace anonymous
+
+bool ServiceImpl::updateRunningAppSmackPolicy(app_context_h app_context, void *user_data) {
+ AppManagerCallbackContext *context = reinterpret_cast<AppManagerCallbackContext*>(user_data);
+
+ std::string appId = getAppIdFromContext(app_context);
+ if (appId.empty()) {
+ LogDebug("No appId from running context");
+ return true;
+ }
+
+ LogDebug("Found " << appId << " running");
+
+ std::string pkgName;
+ context->impl->getPkgName(appId, pkgName);
+
+ bool isPkgHybrid = context->impl->m_privilegeDb.IsPackageHybrid(pkgName);
+
+ auto oldAllowedPrivs = context->appsAllowedPrivileges->operator[](appId);
+
+ auto it = context->impl->m_appIdUidMap.find(appId);
+ if (it == context->impl->m_appIdUidMap.end()) {
+ LogError("THIS IS VERY VERY BAD. RUNNING APPLICATION HAS NO SAVED UID!!!");
+ return true;
+ }
+ uid_t uid = it->second;
+ std::vector<std::string> newAllowedPrivs;
+ auto appProcessLabel = SmackLabels::generateProcessLabel(appId, pkgName, isPkgHybrid);
+ context->impl->getAppAllowedPrivileges(appProcessLabel, uid, newAllowedPrivs);
+
+ std::vector<std::string> inter;
+ std::sort(oldAllowedPrivs.begin(), oldAllowedPrivs.end());
+ std::sort(newAllowedPrivs.begin(), newAllowedPrivs.end());
+
+ std::vector<std::string> denied, allowed;
+ // Deny privileges which were in old allowed privs, but are not in new ones
+ std::set_difference(oldAllowedPrivs.begin(), oldAllowedPrivs.end(),
+ newAllowedPrivs.begin(), newAllowedPrivs.end(),
+ std::back_inserter(denied));
+ // Allow privileges which are in new allowed privs, but were not in old ones
+ std::set_difference(newAllowedPrivs.begin(), newAllowedPrivs.end(),
+ oldAllowedPrivs.begin(), oldAllowedPrivs.end(),
+ std::back_inserter(allowed));
+ int authorId;
+ context->impl->m_privilegeDb.GetPkgAuthorId(pkgName, authorId);
+
+ context->impl->m_smackRules.disablePrivilegeRules(appProcessLabel, pkgName, authorId, denied);
+ context->impl->m_smackRules.enablePrivilegeRules(appProcessLabel, pkgName, authorId, allowed);
+
+ return true;
+}
int ServiceImpl::policyUpdate(const Credentials &creds, const std::vector<policy_entry> &policyEntries)
{
validatedPolicies.push_back(std::move(cyap));
};
+ std::map<std::string, std::vector<std::string>> appsAllowedPrivileges;
+ std::vector<std::string> allPackages;
+
+ // TODO: Can this be optimized to: if policy entries contain either wildcard
+ // in place of privilege or if any of the privileges has smack mapping?
+ if (m_smackRules.isPrivilegeMappingEnabled()) {
+ // Get policy of all installed application so we can recalculate it after update
+ m_privilegeDb.GetAllPackages(allPackages);
+ for (auto &package : allPackages) {
+ std::vector<std::string> packageApps;
+ m_privilegeDb.GetPkgApps(package, packageApps);
+ bool isPkgHybrid = m_privilegeDb.IsPackageHybrid(package);
+ for (auto &app : packageApps) {
+ auto it = m_appIdUidMap.find(app);
+ if (it == m_appIdUidMap.end()) {
+ // TODO: Move app -> uid mapping to database
+ LogDebug("App " << app << " has never been run in security-manager instance");
+ continue;
+ }
+ uid_t uid = it->second;
+ auto appProcessLabel = SmackLabels::generateProcessLabel(app, package, isPkgHybrid);
+ getAppAllowedPrivileges(appProcessLabel, uid, appsAllowedPrivileges[app]);
+ }
+ }
+ }
// Apply updates
m_cynaraAdmin.setPolicies(validatedPolicies);
+ if (m_smackRules.isPrivilegeMappingEnabled()) {
+ LogDebug("Updating privilege related Smack rules");
+ AppManagerCallbackContext context{this, &appsAllowedPrivileges};
+ int ret = app_manager_foreach_running_app_context(&ServiceImpl::updateRunningAppSmackPolicy,
+ &context);
+ if (ret != APP_MANAGER_ERROR_NONE) {
+ LogError("Failed to update Smack policy for running apps");
+ }
+ }
+
// Update mount namespaces
// TODO: Don't update all users, apps and privileges, filter by policyEntries
if (!m_NSMountLogic.check())
std::vector<gid_t> &forbiddenGroups, std::vector<gid_t> &allowedGroups, std::vector<bool> &privPathsStatusVector)
{
LogDebug("Requested prepareApp for application " << appName);
+
bool isHybrid;
if (!m_privilegeDb.GetAppPkgInfo(appName, pkgName, isHybrid, enabledSharedRO))
return SECURITY_MANAGER_ERROR_UNKNOWN;
getPkgLabels(pkgName, pkgLabels);
if (m_smackRules.isPrivilegeMappingEnabled()) {
+ m_appIdUidMap[appName] = creds.uid;
+
m_smackRules.disableAllPrivilegeRules(label, pkgName, authorId);
m_smackRules.enablePrivilegeRules(label, pkgName, authorId, allowedPrivileges);
}
}
void SmackRules::disableAllPrivilegeRules(
+ const Smack::Label &appProcessLabel,
+ const std::string &pkgName,
+ int authorId)
+{
+ LogDebug("Disabling all privilege rules for " << appProcessLabel);
+ disablePrivilegeRules(appProcessLabel, pkgName, authorId, m_templateMgr.getAllMappedPrivs());
+}
+
+void SmackRules::disablePrivilegeRules(
const Smack::Label &appProcessLabel,
const std::string &pkgName,
- int authorId)
+ int authorId,
+ const std::vector<std::string> &privileges)
{
- LogDebug("Disabling all privilege rules for " << appProcessLabel);
+ if (privileges.empty()) {
+ // No rules to apply
+ return;
+ }
+
+ LogDebug("Disabling privilege rules for " << appProcessLabel);
SmackAccesses smackRules;
- addPrivilegesRules(smackRules, appProcessLabel, pkgName, authorId,
- m_templateMgr.getAllMappedPrivs());
+ addPrivilegesRules(smackRules, appProcessLabel, pkgName, authorId, privileges);
if (smack_check())
smackRules.clear();