#include <cstdlib>
#include <functional>
#include <memory>
-#include <unordered_set>
#include <utility>
#include <atomic>
#include <system_error>
return SECURITY_MANAGER_SUCCESS;
}
-static int getProcessGroups(std::vector<gid_t> &groups)
-{
- int ret = getgroups(0, nullptr);
- if (ret == -1) {
- LogError("Unable to get number of current supplementary groups: " <<
- GetErrnoString(errno));
- return SECURITY_MANAGER_ERROR_UNKNOWN;
- }
- int cnt = ret;
-
- auto groupsPtr = makeUnique<gid_t[]>(cnt);
- if (!groupsPtr) {
- LogError("Memory allocation failed.");
- return SECURITY_MANAGER_ERROR_MEMORY;
- }
-
- ret = getgroups(cnt, groupsPtr.get());
- if (ret == -1) {
- LogError("Unable to get list of current supplementary groups: " <<
- GetErrnoString(errno));
- return SECURITY_MANAGER_ERROR_UNKNOWN;
- }
-
- groups.assign(groupsPtr.get(), groupsPtr.get() + cnt);
- return SECURITY_MANAGER_SUCCESS;
-}
-
-static int setProcessGroups(const std::vector<gid_t> &groups)
-{
- int ret = setgroups(groups.size(), groups.data());
- if (ret == -1) {
- LogError("Unable to set list of current supplementary groups: " <<
- GetErrnoString(errno));
- return SECURITY_MANAGER_ERROR_UNKNOWN;
- }
-
- return SECURITY_MANAGER_SUCCESS;
-}
-
-static int getPrivilegedAndAppGroups(const std::string &appName, std::vector<gid_t> &privilegedGroups, std::vector<gid_t> &appGroups)
+// respective group vectors come sorted
+static int fetchForbiddenAndAllowedGroups(const std::string &appName, std::vector<gid_t> &forbiddenGroups, std::vector<gid_t> &allowedGroups)
{
ClientRequest request(SecurityModuleCall::GROUPS_GET);
return request.getStatus();
}
- request.recv(privilegedGroups, appGroups);
+ request.recv(forbiddenGroups, allowedGroups);
return SECURITY_MANAGER_SUCCESS;
}
static int prepareAppInitialSetupAndFetch(const std::string &appName, const MountNS::PrivilegePathsMap &privilegePathsMap, std::string &label,
- std::string &pkgName, bool &enabledSharedRO, std::vector<gid_t> &privilegedGroups, std::vector<gid_t> &appGroups,
+ std::string &pkgName, bool &enabledSharedRO, std::vector<gid_t> &forbiddenGroups, std::vector<gid_t> &allowedGroups,
std::vector<bool> &privilegeStatusVector)
{
ClientRequest request(SecurityModuleCall::PREPARE_APP);
return request.getStatus();
}
- request.recv(privilegedGroups, appGroups, privilegeStatusVector, label, pkgName, enabledSharedRO);
+ request.recv(forbiddenGroups, allowedGroups, privilegeStatusVector, label, pkgName, enabledSharedRO);
return SECURITY_MANAGER_SUCCESS;
}
return SECURITY_MANAGER_ERROR_UNKNOWN;
}
-static int security_manager_set_process_groups_internal(const std::vector<gid_t> &privilegedGroups, std::vector<gid_t> &allowedGroups)
+// respective group vectors come sorted
+static int security_manager_set_process_groups_internal(const std::vector<gid_t> &forbiddenGroups, const std::vector<gid_t> &allowedGroups)
{
- using namespace SecurityManager;
+ const size_t forbiddenGroupsSize = forbiddenGroups.size();
+ const size_t allowedGroupsSize = allowedGroups.size();
+ size_t fi = 0, ai = 0, size = 0;
+ gid_t forbg = -1, allog = -1;
+ int ret;
+ gid_t grp[NGROUPS_MAX+1];
- return try_catch([&]() -> int {
+ ret = getgroups(sizeof grp / sizeof *grp, grp);
+ if (ret < 0) {
+ LogError("Unable to get list of current supplementary groups: " <<
+ GetErrnoString(errno));
+ return SECURITY_MANAGER_ERROR_UNKNOWN;
+ }
- std::vector<gid_t> currentGroups;
- int ret = getProcessGroups(currentGroups);
- if (ret != SECURITY_MANAGER_SUCCESS)
- return ret;
- LogDebug("Current supplementary groups count: " << currentGroups.size());
+ LogDebug("Current supplementary groups count: " << ret);
+ LogDebug("All privileged supplementary groups count: " << forbiddenGroupsSize);
+ LogDebug("Allowed privileged supplementary groups count: " << allowedGroupsSize);
+
+ std::sort(grp, grp+ret);
+
+ if (forbiddenGroupsSize)
+ forbg = forbiddenGroups[fi++];
+ if (allowedGroupsSize)
+ allog = allowedGroups[ai++];
+
+ // remove grp elements already in either forbiddenGroups or allowedGroups, in place
+ for (int i = 0; i < ret; i++) {
+ const auto outg = grp[i];
- LogDebug("All privileged supplementary groups count: " << privilegedGroups.size());
- LogDebug("Allowed privileged supplementary groups count: " << allowedGroups.size());
+ using ugid_t = std::make_unsigned_t<gid_t>;
- std::unordered_set<gid_t> groupsSet(currentGroups.begin(), currentGroups.end());
// Remove all groups that are mapped to privileges, so if app is not granted
// the privilege, the group will be dropped from current process
- for (gid_t group : privilegedGroups)
- groupsSet.erase(group);
+ while (ugid_t(forbg) < ugid_t(outg))
+ forbg = fi < forbiddenGroupsSize ? forbiddenGroups[fi++] : -1;
+ if (outg == forbg)
+ continue;
+
+ // Skip allowed groups too - they'll be added at the end
+ while (ugid_t(allog) < ugid_t(outg))
+ allog = ai < allowedGroupsSize ? allowedGroups[ai++] : -1;
+ if (outg == allog)
+ continue;
+
+ grp[size++] = outg;
+ }
+
+ if (size + allowedGroupsSize > NGROUPS_MAX) {
+ LogError("Too many supplementary groups");
+ return SECURITY_MANAGER_ERROR_UNKNOWN;
+ }
- // Re-add those privileged groups that an app is entitled to
- groupsSet.insert(allowedGroups.begin(), allowedGroups.end());
- LogDebug("Final supplementary groups count: " << groupsSet.size());
+ // Append allowedGroups
+ memcpy(grp + size, allowedGroups.data(), allowedGroupsSize * sizeof *grp);
+ size += allowedGroupsSize;
- return setProcessGroups(std::vector<gid_t>(groupsSet.begin(), groupsSet.end()));
- });
+ LogDebug("Final supplementary groups count: " << size);
+
+ if (setgroups(size, grp) < 0) {
+ LogError("Unable to set list of current supplementary groups: " <<
+ GetErrnoString(errno));
+ return SECURITY_MANAGER_ERROR_UNKNOWN;
+ }
+
+ return SECURITY_MANAGER_SUCCESS;
}
SECURITY_MANAGER_API
return SECURITY_MANAGER_ERROR_INPUT_PARAM;
}
- std::vector<gid_t> privilegedGroups, allowedGroups;
- int ret = getPrivilegedAndAppGroups(app_name, privilegedGroups, allowedGroups);
+ std::vector<gid_t> forbiddenGroups, allowedGroups;
+ int ret = fetchForbiddenAndAllowedGroups(app_name, forbiddenGroups, allowedGroups);
if (ret != SECURITY_MANAGER_SUCCESS) {
LogError("Failed to generate smack label for appName: " << app_name);
return ret;
}
- return security_manager_set_process_groups_internal(privilegedGroups, allowedGroups);
+ return security_manager_set_process_groups_internal(forbiddenGroups, allowedGroups);
});
}
std::string appLabel, pkgName;
bool enabledSharedRO;
- std::vector<gid_t> privilegedGroups, allowedGroups;
+ std::vector<gid_t> forbiddenGroups, allowedGroups;
std::vector<bool> privilegeStatusVector;
auto privilegePathMap = MountNS::getPrivilegePathMap(getuid());
- int ret = prepareAppInitialSetupAndFetch(app_name, privilegePathMap, appLabel, pkgName, enabledSharedRO, privilegedGroups,
- allowedGroups, privilegeStatusVector);
+ int ret = prepareAppInitialSetupAndFetch(app_name, privilegePathMap, appLabel, pkgName, enabledSharedRO,
+ forbiddenGroups, allowedGroups, privilegeStatusVector);
if (ret != SECURITY_MANAGER_SUCCESS) {
LogError("Failed to get app info for appName: " << app_name);
return ret;
}
- ret = security_manager_set_process_groups_internal(privilegedGroups, allowedGroups);
+ ret = security_manager_set_process_groups_internal(forbiddenGroups, allowedGroups);
if (ret != SECURITY_MANAGER_SUCCESS) {
LogError("Unable to setup process groups for application " << app_name);
return ret;
/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2017-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.
// get gids by privilege
const std::vector<gid_t>& getGids(const std::string& privilege) const;
- // get all gids
+ // get all gids (sorted)
const std::vector<gid_t>& getGids() const;
// get all privileges
const std::vector<std::string>& getPrivileges() const;
private:
std::unordered_map<std::string, std::vector<gid_t>> m_priv2gids;
- std::vector<gid_t> m_gids;
+ std::vector<gid_t> m_gids; // sorted
std::vector<std::string> m_privileges;
};
*
* @param[in] creds credentials of the requesting process
* @param[in] appProcessLabel application name
- * @param[out] privilegedGroups returned vector of privileged groups
- * @param[out] appGroups returned vector of allowed groups
+ * @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 getPrivilegedAndAppGroups(const Credentials &creds, const std::string &appProcessLabel,
- std::vector<gid_t> &privilegedGroups, std::vector<gid_t> &appGroups);
+ int getForbiddenAndAllowedGroups(const Credentials &creds, const std::string &appProcessLabel,
+ std::vector<gid_t> &forbiddenGroups, std::vector<gid_t> &allowedGroups);
/**
* Receive groups connected with uid and add them
* @param[out] label generated label
* @param[out] pkgName application package name
* @param[out] enabledSharedRO placeholder for check shared_ro result
- * @param[out] privilegedGroups returned vector of privileged groups
- * @param[out] appGroups returned vector of allowed groups
- * @param[out] privilegeStatusVector returned result of privilege queries
+ * @param[out] forbiddenGroups sorted vector of forbidden groups
+ * @param[out] allowedGroups sorted vector of allowed groups
+ * @param[out] privilegeStatusVector results of respective privilege queries
*
* @return API return code, as defined in protocols.h
*/
int prepareApp(const Credentials &creds, const std::string &appName, const std::vector<std::string> &privilegeVector,
std::string &label, std::string &pkgName, bool &enabledSharedRO,
- std::vector<gid_t> &privilegedGroups, std::vector<gid_t> &appGroups, std::vector<bool> &privilegeStatusVector);
+ std::vector<gid_t> &forbiddenGroups, std::vector<gid_t> &allowedGroups, std::vector<bool> &privilegeStatusVector);
private:
int appInstallInitialChecks(const Credentials &creds,
/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2017-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.
}
// remove duplicates
- vectorRemoveDuplicates(m_gids);
+ vectorRemoveDuplicates(m_gids); // sorted
vectorRemoveDuplicates(m_privileges);
}
const std::vector<gid_t>& PrivilegeGids::getGids() const
{
- return m_gids;
+ return m_gids; // sorted
}
const std::vector<std::string>& PrivilegeGids::getPrivileges() const
return ret;
}
-int ServiceImpl::getPrivilegedAndAppGroups(const Credentials &creds, const std::string &appProcessLabel,
- std::vector<gid_t> &privilegedGroups, std::vector<gid_t> &appGroups)
+int ServiceImpl::getForbiddenAndAllowedGroups(const Credentials &creds, const std::string &appProcessLabel,
+ std::vector<gid_t> &forbiddenGroups, std::vector<gid_t> &allowedGroups)
{
try {
LogDebug("smack label: " << appProcessLabel);
- auto &gids = m_privilegeGids.getGids();
- privilegedGroups.insert(privilegedGroups.end(), gids.begin(), gids.end());
-
std::vector<std::string> privileges;
std::string uidStr = std::to_string(creds.uid);
continue;
if (m_cynara.check(appProcessLabel, privilege, uidStr, pidStr)) {
- appGroups.insert(appGroups.end(), pgids.begin(), pgids.end());
+ allowedGroups.insert(allowedGroups.end(), pgids.begin(), pgids.end());
LogDebug("Cynara allowed, adding groups");
} else {
LogDebug("Cynara denied, not adding groups");
}
}
- vectorRemoveDuplicates(appGroups);
+ vectorRemoveDuplicates(allowedGroups); // sorted
+
+ auto &gids = m_privilegeGids.getGids(); // 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;
int ServiceImpl::prepareApp(const Credentials &creds, const std::string &appName, const std::vector<std::string> &privilegeVector,
std::string &label, std::string &pkgName, bool &enabledSharedRO,
- std::vector<gid_t> &privilegedGroups, std::vector<gid_t> &appGroups, std::vector<bool> &privilegeStatusVector)
+ std::vector<gid_t> &forbiddenGroups, std::vector<gid_t> &allowedGroups, std::vector<bool> &privilegeStatusVector)
{
LogDebug("Requested prepareApp for application " << appName);
bool isHybrid;
return SECURITY_MANAGER_ERROR_UNKNOWN;
label = SmackLabels::generateProcessLabel(appName, pkgName, isHybrid);
- int ret = getPrivilegedAndAppGroups(creds, label, privilegedGroups, appGroups);
+ int ret = getForbiddenAndAllowedGroups(creds, label, forbiddenGroups, allowedGroups);
return ret != SECURITY_MANAGER_SUCCESS ? ret
: appSetupNamespace(creds, label, privilegeVector, privilegeStatusVector);
}
* @param send Raw data buffer to be sent
* @param creds credentials of the requesting process
*/
- void processGetPrivilegedAndAppGroups(MessageBuffer &buffer, MessageBuffer &send, const Credentials &creds);
+ void processGetForbiddenAndAllowedGroups(MessageBuffer &buffer, MessageBuffer &send, const Credentials &creds);
/**
* Process getting groups bound with privileges for given uid
break;
case SecurityModuleCall::GROUPS_GET:
LogDebug("call_type: SecurityModuleCall::GROUPS_GET");
- processGetPrivilegedAndAppGroups(buffer, send, creds);
+ processGetForbiddenAndAllowedGroups(buffer, send, creds);
break;
case SecurityModuleCall::GROUPS_FOR_UID:
processGroupsForUid(buffer, send);
}
}
-void Service::processGetPrivilegedAndAppGroups(MessageBuffer &buffer, MessageBuffer &send, const Credentials &creds)
+void Service::processGetForbiddenAndAllowedGroups(MessageBuffer &buffer, MessageBuffer &send, const Credentials &creds)
{
std::string appName;
- std::vector<gid_t> privilegedGroups, appGroups;
+ std::vector<gid_t> forbiddenGroups, allowedGroups;
Deserialization::Deserialize(buffer, appName);
- int ret = serviceImpl.getPrivilegedAndAppGroups(creds, serviceImpl.getProcessLabel(appName), privilegedGroups, appGroups);
+ int ret = serviceImpl.getForbiddenAndAllowedGroups(creds, serviceImpl.getProcessLabel(appName), forbiddenGroups, allowedGroups);
Serialization::Serialize(send, ret);
if (ret == SECURITY_MANAGER_SUCCESS) {
- Serialization::Serialize(send, privilegedGroups, appGroups);
+ Serialization::Serialize(send, forbiddenGroups, allowedGroups);
}
}
std::string appName, pkgName, label;
bool enabledSharedRO;
std::vector<std::string> privilegeVector;
- std::vector<gid_t> privilegedGroups, appGroups;
+ std::vector<gid_t> forbiddenGroups, allowedGroups;
std::vector<bool> privilegeStatusVector;
Deserialization::Deserialize(buffer, appName, privilegeVector);
int ret = serviceImpl.prepareApp(creds, appName, privilegeVector,
- label, pkgName, enabledSharedRO, privilegedGroups, appGroups, privilegeStatusVector);
+ label, pkgName, enabledSharedRO, forbiddenGroups, allowedGroups, privilegeStatusVector);
Serialization::Serialize(send, ret);
if (ret == SECURITY_MANAGER_SUCCESS)
- Serialization::Serialize(send, privilegedGroups, appGroups, privilegeStatusVector, label, pkgName, enabledSharedRO);
+ Serialization::Serialize(send, forbiddenGroups, allowedGroups, privilegeStatusVector, label, pkgName, enabledSharedRO);
}
} // namespace SecurityManager