Remove nss plugin IPC with security-manager daemon 99/222099/14
authorTomasz Swierczek <t.swierczek@samsung.com>
Thu, 9 Jan 2020 13:29:43 +0000 (14:29 +0100)
committerTomasz Swierczek <t.swierczek@samsung.com>
Mon, 3 Feb 2020 07:18:38 +0000 (08:18 +0100)
Communication was needed to ensure the GID list is calculated based on
Cynara's privilege DB, which contains also per-user information of allowed
privileges.

It was agreed among security and platform teams that system daemons
have statically defined list of GIDs/privileges that doesn't change
over time and also, that this list is the same regardless of the user type
(gumd defines various user types).

This patch changes meaning of per-user-type policy files and Cynara's
per-user-type policy buckets. From now on, the Cynara policy for given user
is applicable as-is only for that user's applications. The user-level
& system-level daemons that may run with "User", "System" or "System::Privileged"
Smack labels have no longer their policy consulted with Cynara.
Instead, they are being given all the privilege-mapped GIDs, with exception
of GIDs that can be mapped to:

http://tizen.org/privilege/internal/livecoredump (priv_livecoredump)
http://tizen.org/privilege/internal/sysadmin (currently no GID associated)

These privileges are used by system team to control inter-service
access to certain DBus interfaces and if any GID is associated with them,
that GID should not be granted by nss plugin. Instead, that GID should
be added as supplementary group of particular service that should be granted
corresponding privilege (ie. using systemd service file or by assigning GID
as supplementary to UID under which the service is running).

When systemd SupplementaryGroup option in service files will be used
to declare all  "privileges" for all services, the security-manager nss plugin
will not be needed anymore.

Change-Id: I8da6385cfaf502cfd6117b3805e5986ae3c28b80

13 files changed:
policy/CMakeLists.txt
policy/privilege-managed-by-systemd-for-daemons.list [new file with mode: 0644]
policy/security-manager-policy-reload.in
src/client/CMakeLists.txt
src/client/client-security-manager-internal.cpp [deleted file]
src/client/client-security-manager.cpp
src/client/include/client-security-manager-internal.h [deleted file]
src/common/include/config.h
src/common/include/utils.h
src/common/utils.cpp
src/include/app-runtime.h
src/nss/CMakeLists.txt
src/nss/nss_securitymanager.cpp

index 5771f7f00a2f030060d706963d38aa3e2230b1f1..49f80af9dc7ac032864244effb30e5424f62b895 100644 (file)
@@ -10,6 +10,7 @@ INSTALL(FILES "pkg-rules-template.smack" DESTINATION ${POLICY_DIR})
 INSTALL(FILES "author-rules-template.smack" DESTINATION ${POLICY_DIR})
 INSTALL(FILES "privilege-group.list" DESTINATION ${POLICY_DIR})
 INSTALL(FILES "privilege-mount.list" DESTINATION ${POLICY_DIR})
+INSTALL(FILES "privilege-managed-by-systemd-for-daemons.list" DESTINATION ${POLICY_DIR})
 INSTALL(PROGRAMS "update.sh" DESTINATION ${POLICY_DIR})
 INSTALL(DIRECTORY "updates" USE_SOURCE_PERMISSIONS DESTINATION ${POLICY_DIR})
 INSTALL(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/security-manager-policy-reload DESTINATION ${BIN_INSTALL_DIR})
diff --git a/policy/privilege-managed-by-systemd-for-daemons.list b/policy/privilege-managed-by-systemd-for-daemons.list
new file mode 100644 (file)
index 0000000..dd5f507
--- /dev/null
@@ -0,0 +1,15 @@
+# List of privileges that are also used for inter-daemon access control.
+# That access control is done using systemd SupplementaryGroups configuration and DBus GID-based policy,
+# so enforcement of these privileges cannot be configured for a new process using nss plugin
+# (which assigns associated GIDs). Also, Cynara policy for User, System & System::Privileged
+# Cynara clients has to be configured with default "DENY".
+#
+# This file will not be needed anymore once all privileges for daemons will be managed by systemd
+# and not by Security FW (no need for nss, Cynara policy for daemon labels, etc.).
+#
+# Format:
+# - each line stores one privilege "<PRIVILEGE>"
+# - lines starting with '#' are ignored
+# - lines having more than 1 white-space separated items will be ignored too
+http://tizen.org/privilege/internal/sysadmin
+http://tizen.org/privilege/internal/livecoredump
index f15f4c7e92e32c069ba80c3d351014a991a27c53..b6a175f6a3f559e50922a6b75bc8cf522423fc09 100755 (executable)
@@ -3,6 +3,7 @@
 PATH=/bin:/usr/bin:/sbin:/usr/sbin
 POLICY_PATH=@POLICY_DIR@
 PRIVILEGE_GROUP_MAPPING=$POLICY_PATH/privilege-group.list
+PRIVILEGE_SYSTEMD_LIST=$POLICY_PATH/privilege-managed-by-systemd-for-daemons.list
 
 DB_FILE=`tzplatform-get TZ_SYS_DB | cut -d= -f2`/.security-manager.db
 
@@ -58,13 +59,20 @@ do
     cyad --set-policy --bulk=-
 done
 
-# Non-application programs get access to all privileges
+# Non-application programs get access to all privileges...
 for client in User System System::Privileged
 do
     cyad --set-policy --bucket=MANIFESTS_GLOBAL --client="$client" --user="*" --privilege="*" --type=ALLOW
-# Non-application programs will have these privileges disabled in order NOT to get it automatically
-    cyad --set-policy --bucket=MANIFESTS_GLOBAL --client="$client" --user="*" --privilege="http://tizen.org/privilege/internal/sysadmin" --type=DENY
-    cyad --set-policy --bucket=MANIFESTS_GLOBAL --client="$client" --user="*" --privilege="http://tizen.org/privilege/internal/livecoredump" --type=DENY
+done
+
+# ...except these that have their GIDs managed by systemd
+grep -v '^#' "$PRIVILEGE_SYSTEMD_LIST" |
+while read privilege
+do
+    for client in User System System::Privileged
+    do
+        cyad --set-policy --bucket=MANIFESTS_GLOBAL --client="$client" --user="*" --privilege="$privilege" --type=DENY
+    done
 done
 
 # Root shell get access to all privileges
index d99027b237163485e7d5724b361fd012e83e5699..8862ca0bb8f4d9ba0cc69c285307154a76dbc512 100644 (file)
@@ -25,7 +25,6 @@ INCLUDE_DIRECTORIES(
 
 SET(CLIENT_SOURCES
     ${CLIENT_PATH}/client-security-manager.cpp
-    ${CLIENT_PATH}/client-security-manager-internal.cpp
     ${CLIENT_PATH}/client-common.cpp
     ${CLIENT_PATH}/client-offline.cpp
     ${CLIENT_PATH}/client-label-monitor.cpp
diff --git a/src/client/client-security-manager-internal.cpp b/src/client/client-security-manager-internal.cpp
deleted file mode 100644 (file)
index e5b8827..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- *  Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
- *
- *  Contact: Tomasz Swierczek <t.swierczek@samsung.com>
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License
- */
-/*
- * @file        client-security-manager-internal.cpp
- * @author      Tomasz Swierczek <t.swierczek@samsung.com>
- * @version     1.0
- * @brief       This file contains implementation of SM APIs needed to be linked separately into NSS module
- */
-
-#include <client-security-manager-internal.h>
-
-#include <grp.h>
-
-#include <client-request.h>
-#include <security-manager-types.h>
-#include <utils.h>
-
-int security_manager_groups_get_internal(gid_t **groups, size_t *groups_count)
-{
-    using namespace SecurityManager;
-    if (!groups || !groups_count)
-        return SECURITY_MANAGER_ERROR_INPUT_PARAM;
-    return try_catch([&]() -> int {
-        std::vector<gid_t> vgroups;
-        loadGroups(vgroups);
-        return group_vector_to_array(vgroups, groups, groups_count);
-    });
-}
-
-int security_manager_groups_get_for_user_internal(uid_t uid, gid_t **groups, size_t *groups_count)
-{
-    using namespace SecurityManager;
-    if (!groups || !groups_count)
-        return SECURITY_MANAGER_ERROR_INPUT_PARAM;
-
-    // Security manager does not manage platform system daemons
-    // This 5000 value is defined only in this document:
-    // https://wiki.tizen.org/wiki/Security/User_and_group_ID_assignment_policy
-    // TODO: Value 5000 should be defined in tizen-platform-config
-
-    if (uid < 5000) {
-        return SECURITY_MANAGER_ERROR_NO_SUCH_OBJECT;
-    }
-
-    return try_catch([&]() -> int {
-        ClientRequest request(SecurityModuleCall::GROUPS_FOR_UID);
-        if (request.send(uid).failed())
-            return request.getStatus();
-
-        std::vector<gid_t> vgroups;
-        request.recv(vgroups);
-
-        return group_vector_to_array(vgroups, groups, groups_count);
-    });
-}
index 635fdcb9d352de7f81a012c81ac8a49d58a628b6..d0a3cf77994c6ead810e7a09ece3a292511f488a 100644 (file)
@@ -54,7 +54,6 @@
 #include <smack-check.h>
 #include <smack-labels.h>
 #include <client-request.h>
-#include <client-security-manager-internal.h>
 #include <service_impl.h>
 #include <check-proper-drop.h>
 #include <utils.h>
@@ -1357,13 +1356,42 @@ void security_manager_policy_levels_free(char **levels, size_t levels_count)
 SECURITY_MANAGER_API
 int security_manager_groups_get(gid_t **groups, size_t *groups_count)
 {
-    return security_manager_groups_get_internal(groups, groups_count);
+    using namespace SecurityManager;
+    if (!groups || !groups_count)
+        return SECURITY_MANAGER_ERROR_INPUT_PARAM;
+    return try_catch([&]() -> int {
+        std::vector<gid_t> vgroups;
+        loadGroups(vgroups);
+        return group_vector_to_array(vgroups, groups, groups_count);
+    });
 }
 
 SECURITY_MANAGER_API
 int security_manager_groups_get_for_user(uid_t uid, gid_t **groups, size_t *groups_count)
 {
-    return security_manager_groups_get_for_user_internal(uid, groups, groups_count);
+    using namespace SecurityManager;
+    if (!groups || !groups_count)
+        return SECURITY_MANAGER_ERROR_INPUT_PARAM;
+
+    // Security manager does not manage platform system daemons
+    // This 5000 value is defined only in this document:
+    // https://wiki.tizen.org/wiki/Security/User_and_group_ID_assignment_policy
+    // TODO: Value 5000 should be defined in tizen-platform-config
+
+    if (uid < 5000) {
+        return SECURITY_MANAGER_ERROR_NO_SUCH_OBJECT;
+    }
+
+    return try_catch([&]() -> int {
+        ClientRequest request(SecurityModuleCall::GROUPS_FOR_UID);
+        if (request.send(uid).failed())
+            return request.getStatus();
+
+        std::vector<gid_t> vgroups;
+        request.recv(vgroups);
+
+        return group_vector_to_array(vgroups, groups, groups_count);
+    });
 }
 
 static lib_retcode get_app_and_pkg_id_from_smack_label(
diff --git a/src/client/include/client-security-manager-internal.h b/src/client/include/client-security-manager-internal.h
deleted file mode 100644 (file)
index 1815e44..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- *  Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
- *
- *  Contact: Tomasz Swierczek <t.swierczek@samsung.com>
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License
- */
-/*
- * @file        client-security-manager-internal.h
- * @author      Tomasz Swierczek <t.swierczek@samsung.com>
- * @version     1.0
- * @brief       This file contains declaration of SM APIs needed to be linked separately into NSS module
- */
-
-#pragma once
-
-#include <sys/types.h>
-
-int security_manager_groups_get_internal(gid_t **groups, size_t *groups_count);
-int security_manager_groups_get_for_user_internal(uid_t uid, gid_t **groups, size_t *groups_count);
index 24e0eac8cb4fa41f652713b137ea472f6a738f38..336d128ccc82cd01b39e27de8b19bc2659af5af6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2015 - 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2015 - 2020 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *  Contact: Rafal Krypa <r.krypa@samsung.com>
  *
@@ -44,6 +44,7 @@
 /* Policy files */
 #define PRIVILEGE_GROUP_LIST_FILE  POLICY_DIR "/privilege-group.list"
 #define PRIVILEGE_MOUNT_LIST_FILE  POLICY_DIR "/privilege-mount.list"
+#define PRIVILEGE_SYSTEMD_LIST_FILE  POLICY_DIR "/privilege-managed-by-systemd-for-daemons.list"
 
 #define SKEL_DIR                   "/etc/skel"
 
index 60e02006d03d0187165182225686a9cf554e2e53..807942f210d4217ea199b275878ebfbe7093edbd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2016 - 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2016 - 2020 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *  Contact: Rafal Krypa <r.krypa@samsung.com>
  *
@@ -66,9 +66,12 @@ private:
 #endif
 
 // Group operations
-void loadGroups(std::vector<gid_t> &vgroups);
+void loadGroups(std::vector<gid_t> &vgroups, std::vector<std::string> *privileges = NULL);
 int group_vector_to_array(const std::vector<gid_t> &vgroups, gid_t **groups, size_t *groups_count);
 
+// Loading list of privileges that have GIDs managed by systemd for inter-daemon access control
+void loadSystemdManagedPrivileges(std::vector<std::string> &privileges);
+
 // Pointer
 template<typename T>
 std::unique_ptr<T> makeUnique(T *ptr)
index 32b06d6a5e44eb899dcc5dab18ad3c537ef65cc0..7f4480be51f4558fa5b8573ae062ea80f189dcf7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2019 - 2020 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *  Contact: Tomasz Swierczek <t.swierczek@samsung.com>
  *
@@ -103,10 +103,10 @@ ScopedTimeStamper::~ScopedTimeStamper()
     LogDebug("Execution of " << m_locationStr << " took " << sec << " seconds");
 }
 
-void loadGroups(std::vector<gid_t> &vgroups)
+void loadGroups(std::vector<gid_t> &vgroups, std::vector<std::string> *privileges)
 {
     auto groupsMapData = ConfigFile(PRIVILEGE_GROUP_LIST_FILE).read();
-    for (const auto &groupsMapEntry : groupsMapData) {
+    for (auto &groupsMapEntry : groupsMapData) {
         if (groupsMapEntry.size() != 2)
             continue;
 
@@ -131,6 +131,18 @@ void loadGroups(std::vector<gid_t> &vgroups)
             break;
         }
         vgroups.push_back(result->gr_gid);
+        if (privileges)
+            privileges->emplace_back(std::move(groupsMapEntry[0]));
+    }
+}
+
+void loadSystemdManagedPrivileges(std::vector<std::string> &privileges)
+{
+    auto groupsMapData = ConfigFile(PRIVILEGE_SYSTEMD_LIST_FILE).read();
+    for (auto &privEntry : groupsMapData) {
+        if (privEntry.size() != 1)
+            continue;
+        privileges.emplace_back(std::move(privEntry[0]));
     }
 }
 
index 96c7b46dd75d2ccd642c038aaf93647dd5575b4a..d193358db1c09d7ff8cc205a848e11af9d6d3b89 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000 - 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2000 - 2020 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *  Contact: Rafal Krypa <r.krypa@samsung.com>
  *
@@ -132,8 +132,8 @@ int security_manager_cleanup_app(const char *app_id, uid_t uid, pid_t pid);
 int security_manager_groups_get(gid_t **groups, size_t *groups_count);
 
 /**
- * This function returns array of groups bound to privileges, the process
- * run by particular user should get.
+ * This function returns maximum array of groups bound to privileges that
+ * the application run by particular user is able to get.
  *
  * Caller needs to free memory allocated for the list using free().
  *
index 29f855615d40f2661805442d2dbb35bf7edcd006..9e22671da0ea784025447ee2eaeabd34889298b9 100644 (file)
@@ -36,7 +36,6 @@ SET(NSS_SOURCES
     ${COMMON_PATH}/protocols.cpp
     ${COMMON_PATH}/message-buffer.cpp
     ${COMMON_PATH}/utils.cpp
-    ${CLIENT_PATH}/client-security-manager-internal.cpp
     )
 
 IF(CMAKE_BUILD_TYPE MATCHES "DEBUG" AND DPL_WITH_DLOG)
index 873622d26b151c56743b0befcc0d8582f81ca7ca..333e9e06b37b1677cb34fc6169604997d95d4e28 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2016 - 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2016 - 2020 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *  Contact: Rafal Krypa <r.krypa@samsung.com>
  *
@@ -27,7 +27,6 @@
 #include <cerrno>
 #include <cstddef>
 #include <sys/types.h>
-#include <pwd.h>
 #include <nss.h>
 #include <cxxabi.h>
 #include <unistd.h>
@@ -35,7 +34,7 @@
 #include <vector>
 #include <algorithm>
 
-#include <client-security-manager-internal.h>
+#include <config-file.h>
 #include <dpl/log/log.h>
 #include <dpl/singleton.h>
 #include <security-manager-types.h>
 
 namespace {
 
-size_t getBufferSize()
+int security_manager_groups_get_for_daemons_internal(gid_t *&groups, size_t &groups_count)
 {
-    size_t max = 4096, tmp;
-    max = max < (tmp = sysconf(_SC_GETPW_R_SIZE_MAX)) ? tmp : max;
-    return max < (tmp = sysconf(_SC_GETGR_R_SIZE_MAX)) ? tmp : max;
+    using namespace SecurityManager;
+    return try_catch([&]() -> int {
+        std::vector<gid_t> vgroups, vdaemongroups;
+        std::vector<std::string> privileges;
+        loadGroups(vgroups, &privileges);
+        if (vgroups.size() != privileges.size())
+            return SECURITY_MANAGER_ERROR_UNKNOWN;  // this should not happen
+        std::vector<std::string> systemdPrivileges;
+        loadSystemdManagedPrivileges(systemdPrivileges);
+        for (unsigned i = 0; i < privileges.size(); ++i) {
+            bool skip = false;
+            for (auto systemPriv: systemdPrivileges)
+                if (privileges[i] == systemPriv) {
+                    skip = true;
+                    break;
+                }
+            if (!skip)
+                vdaemongroups.push_back(vgroups[i]);
+        }
+        return group_vector_to_array(vdaemongroups, &groups, &groups_count);
+    });
+
 }
 
-} // anonymous namespace
+} // namespace anonymous
 
 extern "C" {
 
@@ -77,7 +95,7 @@ extern "C" {
  * | | - space not allocated by groupsp
  */
 __attribute__((visibility("default")))
-enum nss_status _nss_securitymanager_initgroups_dyn(const char *user, gid_t group_gid, long int *start,
+enum nss_status _nss_securitymanager_initgroups_dyn(const char */*user*/, gid_t group_gid, long int *start,
                                                     long int *size, gid_t **groupsp,
                                                     long int limit, int *errnop)
 {
@@ -85,39 +103,13 @@ enum nss_status _nss_securitymanager_initgroups_dyn(const char *user, gid_t grou
         (void) group_gid;
 
         int ret;
-        const static size_t BUFFER_SIZE = getBufferSize();
-        const static size_t MEMORY_LIMIT = BUFFER_SIZE << 3;
-        std::vector<char> buffer(BUFFER_SIZE);
-        passwd pwnambuffer;
-        passwd *pwnam = NULL;
         auto& logSystem = SecurityManager::Singleton<SecurityManager::Log::LogSystem>::Instance();
 
         logSystem.SetTag("SECURITY_MANAGER_NSS");
 
-        while (ERANGE == (ret = TEMP_FAILURE_RETRY(getpwnam_r(user, &pwnambuffer, buffer.data(), buffer.size(), &pwnam)))
-               && buffer.size() < MEMORY_LIMIT)
-        {
-            buffer.resize(buffer.size() << 1);
-        }
-
-        if (ret == ERANGE) {
-            *errnop = ENOMEM;
-            return NSS_STATUS_UNAVAIL;
-        }
-
-        if (ret || pwnam == NULL) {
-            *errnop = ENOENT;
-            return NSS_STATUS_NOTFOUND;
-        }
-
         gid_t *groups = NULL;
         size_t groupsCount;
-        ret = security_manager_groups_get_for_user_internal(pwnam->pw_uid, &groups, &groupsCount);
-
-        if (ret == SECURITY_MANAGER_ERROR_NO_SUCH_OBJECT) {
-            // If user is not managed by Security Manager, we want to apply all the groups
-            ret = security_manager_groups_get_internal(&groups, &groupsCount);
-        }
+        ret = security_manager_groups_get_for_daemons_internal(groups, groupsCount);
 
         if (ret == SECURITY_MANAGER_ERROR_MEMORY) {
             *errnop = ENOMEM;