prepare_app: refactor supplementary group assignment 12/222512/7
authorKonrad Lipinski <k.lipinski2@samsung.com>
Thu, 19 Dec 2019 14:44:33 +0000 (15:44 +0100)
committerTomasz Swierczek <t.swierczek@samsung.com>
Thu, 23 Jan 2020 06:58:09 +0000 (06:58 +0000)
* use a stack array for syscalls
* stream forbiddenGroups = privilegedGroups \ allowedGroups instead of
  privilegedGroups, making IPC thinner

Change-Id: I343af0052fd90f1ed4fd37d41b7b8c7a1a5a7858

src/client/client-security-manager.cpp
src/common/include/privilege-gids.h
src/common/include/service_impl.h
src/common/privilege-gids.cpp
src/common/service_impl.cpp
src/server/service/include/service.h
src/server/service/service.cpp

index 38c65c13579eff95a682b8f92094a41732a4aa9d..635fdcb9d352de7f81a012c81ac8a49d58a628b6 100644 (file)
@@ -29,7 +29,6 @@
 #include <cstdlib>
 #include <functional>
 #include <memory>
-#include <unordered_set>
 #include <utility>
 #include <atomic>
 #include <system_error>
@@ -452,46 +451,8 @@ int security_manager_set_process_label_from_appid(const char *app_name)
     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);
 
@@ -500,12 +461,12 @@ static int getPrivilegedAndAppGroups(const std::string &appName, std::vector<gid
         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);
@@ -514,7 +475,7 @@ static int prepareAppInitialSetupAndFetch(const std::string &appName, const Moun
         return request.getStatus();
     }
 
-    request.recv(privilegedGroups, appGroups, privilegeStatusVector, label, pkgName, enabledSharedRO);
+    request.recv(forbiddenGroups, allowedGroups, privilegeStatusVector, label, pkgName, enabledSharedRO);
     return SECURITY_MANAGER_SUCCESS;
 }
 
@@ -697,33 +658,74 @@ err:
     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
@@ -741,14 +743,14 @@ int security_manager_set_process_groups_from_appid(const char *app_name)
             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);
     });
 }
 
@@ -902,17 +904,17 @@ int security_manager_prepare_app(const char *app_name)
 
         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;
index d4c898817a97a84cf5118054c289868b48c661ca..65bfd889804fd117ba274451771108e8ddf16a4f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  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.
@@ -39,14 +39,14 @@ public:
 
     // 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;
 };
 
index 7fd917cd49c9260b06a51ebd92a4c47cbb207c65..80c0a8250099b711cddf51f9a04208feba1744bb 100644 (file)
@@ -183,13 +183,13 @@ public:
     *
     * @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
@@ -360,15 +360,15 @@ public:
      * @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,
index 6dfc0d47861cf1606cc3685354df9fba53abaf98..0ba427d37b51612973b8df3418bf450866eca132 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  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.
@@ -52,7 +52,7 @@ void PrivilegeGids::init(const GroupPrivileges &group_privs)
     }
 
     // remove duplicates
-    vectorRemoveDuplicates(m_gids);
+    vectorRemoveDuplicates(m_gids); // sorted
     vectorRemoveDuplicates(m_privileges);
 }
 
@@ -68,7 +68,7 @@ const std::vector<gid_t>& PrivilegeGids::getGids(const std::string &privilege) c
 
 const std::vector<gid_t>& PrivilegeGids::getGids() const
 {
-    return m_gids;
+    return m_gids; // sorted
 }
 
 const std::vector<std::string>& PrivilegeGids::getPrivileges() const
index ac5eb9298aba14b5352b8bef706933179ab1cb1b..3d5e0cb82296934186f973e411e9fd3eb0121914 100644 (file)
@@ -1401,15 +1401,12 @@ int ServiceImpl::policyGetDesc(std::vector<std::string> &levels)
     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);
@@ -1430,13 +1427,18 @@ int ServiceImpl::getPrivilegedAndAppGroups(const Credentials &creds, const std::
                 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;
@@ -2125,7 +2127,7 @@ std::string ServiceImpl::getProcessLabel(const std::string &appName)
 
 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;
@@ -2133,7 +2135,7 @@ int ServiceImpl::prepareApp(const Credentials &creds, const std::string &appName
         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);
 }
index 4935f4e3350ef3259f6c543b3d05dd8f5cfd957e..3834e8e032831d790811e785214690bb41f6de60 100644 (file)
@@ -157,7 +157,7 @@ private:
      * @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
index 5cf783831e268172ab3e64868c229539d119080d..e29a807581d0243c564b2088e6acfd65266ce091 100644 (file)
@@ -124,7 +124,7 @@ bool Service::processOne(const ConnectionID &conn, MessageBuffer &buffer,
                     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);
@@ -345,16 +345,16 @@ void Service::processPolicyGetDesc(MessageBuffer &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);
     }
 }
 
@@ -494,14 +494,14 @@ void Service::prepareApp(MessageBuffer &buffer, MessageBuffer &send, const Crede
     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