From: Tomasz Swierczek Date: Thu, 9 Jan 2020 13:29:43 +0000 (+0100) Subject: Remove nss plugin IPC with security-manager daemon X-Git-Tag: submit/tizen/20200203.111649~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=de6d5b326feeb025fbf628b0d08e2f727ff3e51c;p=platform%2Fcore%2Fsecurity%2Fsecurity-manager.git Remove nss plugin IPC with security-manager daemon 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 --- diff --git a/policy/CMakeLists.txt b/policy/CMakeLists.txt index 5771f7f0..49f80af9 100644 --- a/policy/CMakeLists.txt +++ b/policy/CMakeLists.txt @@ -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 index 00000000..dd5f5072 --- /dev/null +++ b/policy/privilege-managed-by-systemd-for-daemons.list @@ -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 "" +# - 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 diff --git a/policy/security-manager-policy-reload.in b/policy/security-manager-policy-reload.in index f15f4c7e..b6a175f6 100755 --- a/policy/security-manager-policy-reload.in +++ b/policy/security-manager-policy-reload.in @@ -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 diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index d99027b2..8862ca0b 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -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 index e5b88272..00000000 --- a/src/client/client-security-manager-internal.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved - * - * Contact: Tomasz Swierczek - * - * 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 - * @version 1.0 - * @brief This file contains implementation of SM APIs needed to be linked separately into NSS module - */ - -#include - -#include - -#include -#include -#include - -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 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 vgroups; - request.recv(vgroups); - - return group_vector_to_array(vgroups, groups, groups_count); - }); -} diff --git a/src/client/client-security-manager.cpp b/src/client/client-security-manager.cpp index 635fdcb9..d0a3cf77 100644 --- a/src/client/client-security-manager.cpp +++ b/src/client/client-security-manager.cpp @@ -54,7 +54,6 @@ #include #include #include -#include #include #include #include @@ -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 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 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 index 1815e446..00000000 --- a/src/client/include/client-security-manager-internal.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved - * - * Contact: Tomasz Swierczek - * - * 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 - * @version 1.0 - * @brief This file contains declaration of SM APIs needed to be linked separately into NSS module - */ - -#pragma once - -#include - -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); diff --git a/src/common/include/config.h b/src/common/include/config.h index 24e0eac8..336d128c 100644 --- a/src/common/include/config.h +++ b/src/common/include/config.h @@ -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 * @@ -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" diff --git a/src/common/include/utils.h b/src/common/include/utils.h index 60e02006..807942f2 100644 --- a/src/common/include/utils.h +++ b/src/common/include/utils.h @@ -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 * @@ -66,9 +66,12 @@ private: #endif // Group operations -void loadGroups(std::vector &vgroups); +void loadGroups(std::vector &vgroups, std::vector *privileges = NULL); int group_vector_to_array(const std::vector &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 &privileges); + // Pointer template std::unique_ptr makeUnique(T *ptr) diff --git a/src/common/utils.cpp b/src/common/utils.cpp index 32b06d6a..7f4480be 100644 --- a/src/common/utils.cpp +++ b/src/common/utils.cpp @@ -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 * @@ -103,10 +103,10 @@ ScopedTimeStamper::~ScopedTimeStamper() LogDebug("Execution of " << m_locationStr << " took " << sec << " seconds"); } -void loadGroups(std::vector &vgroups) +void loadGroups(std::vector &vgroups, std::vector *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 &vgroups) break; } vgroups.push_back(result->gr_gid); + if (privileges) + privileges->emplace_back(std::move(groupsMapEntry[0])); + } +} + +void loadSystemdManagedPrivileges(std::vector &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])); } } diff --git a/src/include/app-runtime.h b/src/include/app-runtime.h index 96c7b46d..d193358d 100644 --- a/src/include/app-runtime.h +++ b/src/include/app-runtime.h @@ -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 * @@ -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(). * diff --git a/src/nss/CMakeLists.txt b/src/nss/CMakeLists.txt index 29f85561..9e22671d 100644 --- a/src/nss/CMakeLists.txt +++ b/src/nss/CMakeLists.txt @@ -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) diff --git a/src/nss/nss_securitymanager.cpp b/src/nss/nss_securitymanager.cpp index 873622d2..333e9e06 100644 --- a/src/nss/nss_securitymanager.cpp +++ b/src/nss/nss_securitymanager.cpp @@ -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 * @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -35,7 +34,7 @@ #include #include -#include +#include #include #include #include @@ -43,14 +42,33 @@ 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 vgroups, vdaemongroups; + std::vector privileges; + loadGroups(vgroups, &privileges); + if (vgroups.size() != privileges.size()) + return SECURITY_MANAGER_ERROR_UNKNOWN; // this should not happen + std::vector 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 buffer(BUFFER_SIZE); - passwd pwnambuffer; - passwd *pwnam = NULL; auto& logSystem = SecurityManager::Singleton::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;