From: Zofia Grzelewska Date: Tue, 27 Feb 2018 15:27:14 +0000 (+0100) Subject: Return ALLOW for non privacy privileges X-Git-Tag: submit/tizen/20180425.043505~9 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d01f64452a3cae3df544cf24b4b0557115c34cea;p=platform%2Fcore%2Fsecurity%2Faskuser.git Return ALLOW for non privacy privileges When application checks/requests permission for given privilege, return ALLOW when this privilege is requested by application in manifest, but isn't privacy for it. Change-Id: Ia36478fce3b9737589c2c130b9247ee3e7a89143 --- diff --git a/src/client/impl/ApiInterfaceImpl.cpp b/src/client/impl/ApiInterfaceImpl.cpp index 79619a2..c653312 100644 --- a/src/client/impl/ApiInterfaceImpl.cpp +++ b/src/client/impl/ApiInterfaceImpl.cpp @@ -17,6 +17,7 @@ /** * @file ApiInterfaceImpl.cpp * @author Piotr Sawicki + * @author Zofia Grzelewska * @brief The definition of ApiInterfaceImpl. */ @@ -26,6 +27,7 @@ #include #include +#include #include #include @@ -98,13 +100,9 @@ int ApiInterfaceImpl::process(int fd, int events) askuser_check_result ApiInterfaceImpl::checkPrivilege(const std::string &privilege) { std::string appId = getOwnAppId(); + PrivilegePolicy privPolicy(appId, privilege); + auto policyLevel = privPolicy.calculatePolicy(); - auto policyLevel = getPrivilegeMappedPolicy(appId, privilege); - - if (policyLevel.empty()) { - ALOGD("Privilege " << privilege << " is not a privacy privilege for app " << appId); - return ASKUSER_CHECK_RESULT_DENY; - } if (policyLevel == "Allow") { return ASKUSER_CHECK_RESULT_ALLOW; } diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 4adb6f8..b43a147 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2014-2017 Samsung Electronics Co., Ltd All Rights Reserved +# Copyright (c) 2014-2018 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. @@ -20,6 +20,7 @@ PKG_CHECK_MODULES(COMMON_DEP REQUIRED security-manager pkgmgr-info + security-privilege-manager ) SET(ASKUSER_COMMON_VERSION_MAJOR 0) @@ -39,6 +40,7 @@ SET(COMMON_SOURCES ${COMMON_PATH}/log/alog.cpp ${COMMON_PATH}/policy/Policy.cpp ${COMMON_PATH}/policy/PrivilegeInfo.cpp + ${COMMON_PATH}/policy/PrivilegePolicy.cpp ${COMMON_PATH}/types/AgentErrorMsg.cpp ${COMMON_PATH}/util/SafeFunction.cpp ${COMMON_PATH}/config/Limits.cpp diff --git a/src/common/policy/Policy.cpp b/src/common/policy/Policy.cpp index 6af0e66..5f1954a 100644 --- a/src/common/policy/Policy.cpp +++ b/src/common/policy/Policy.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017 Samsung Electronics Co. + * Copyright (c) 2016-2018 Samsung Electronics Co. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ */ /** * @file src/agent/main/Policy.cpp - * @author Zofia Abramowska + * @author Zofia Grzelewska * @brief Implementation of Policy wrappers */ @@ -70,41 +70,27 @@ PolicyEntryCopy::PolicyEntryCopy(policy_entry *entry) { m_level = level; } -Policy getMinimumPolicy(const std::vector &policies) { - if (policies.empty()) - return ""; - - Policy minimumPolicy = "Allow"; - - for (auto &policy : policies) { - if (policy == "Deny") { - minimumPolicy = "Deny"; - break; - } else if (policy != minimumPolicy && policy == "Ask user") { - minimumPolicy = "Ask user"; - } +std::set getManifestPrivs(const std::string &appId) +{ + char **privsRaw; + size_t privsCount; + + int ret = security_manager_get_app_manifest_policy(appId.c_str(), geteuid(), + &privsRaw, &privsCount); + if (ret != SECURITY_MANAGER_SUCCESS) { + ALOGE("Failed to fetch manifest privileges for app " << appId << " : " << ret); + return {}; } - return minimumPolicy; -} - -Policy calculatePolicyForPrivacy(const std::string &appId, const Privacy &privacy) { - ALOGD("Calculating privacy " << privacy); - std::vector privsPolicies; - auto privileges = PrivilegeInfo::getPrivacyPrivileges(privacy); - for (const auto &privilege : privileges) { - ALOGD("Calculating policy for privilege " << privilege); - - std::string policyLevel = getPrivilegePolicy(appId, privilege); - - if (policyLevel.empty()) { - ALOGE("Couldn't get policy level, skipping"); - continue; - } - - ALOGD("Fetched policy level : " << policyLevel); - privsPolicies.push_back(std::move(policyLevel)); + auto privsFree = [privsCount](char ** privs) { + security_manager_privileges_free(privs, privsCount); + }; + std::unique_ptr privsPtr(privsRaw, privsFree); + std::set privileges; + + for (size_t i = 0; i < privsCount; i++) { + privileges.insert(privsRaw[i]); } - return getMinimumPolicy(privsPolicies); + return privileges; } Policy getPrivilegePolicy(const std::string &appId, const Privilege &privilege) { @@ -127,15 +113,14 @@ Policy getPrivilegePolicy(const std::string &appId, const Privilege &privilege) return policies[0].getLevel(); } -Policy getPrivaciesPolicy(const std::string &appId, const std::vector &privacies) { - std::vector policies; - for (auto &privacy : privacies) { - Policy privacyPolicy = calculatePolicyForPrivacy(appId, privacy); - if (privacyPolicy.empty()) - continue; - policies.push_back(privacyPolicy); - } - return getMinimumPolicy(policies); +std::vector getAppPolicy(const std::string &appId) { + PolicyEntry filter; + filter.setApp(appId); + filter.setUser(std::to_string(geteuid())); + filter.setPrivilege(SECURITY_MANAGER_ANY); + + PolicyFetchRequest fetch(std::move(filter)); + return fetch.fetchPolicy(); } void identifyApp(const std::string &client, std::string &appId, std::string &pkgLabel) @@ -162,16 +147,6 @@ void identifyApp(const std::string &client, std::string &appId, std::string &pkg pkgLabel = pkgInfo.pkgLabel(); } -Policy getPrivilegeMappedPolicy(const std::string &appId, const std::string &privilege) { - std::vector privacies = PrivilegeInfo::getPrivilegePrivaciesMapping(appId, privilege); - if (privacies.empty()) { - ALOGE("Privilege doesn't map to any privacy"); - return ""; - } - - return getPrivaciesPolicy(appId, privacies); -} - std::string getOwnAppId() { char *pkgName = nullptr; diff --git a/src/common/policy/Policy.h b/src/common/policy/Policy.h index 300fa52..132d067 100644 --- a/src/common/policy/Policy.h +++ b/src/common/policy/Policy.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017 Samsung Electronics Co. + * Copyright (c) 2016-2018 Samsung Electronics Co. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,12 +15,13 @@ */ /** * @file src/agent/main/Policy.h - * @author Zofia Abramowska + * @author Zofia Grzelewska * @brief Definition of Policy wrappers */ #pragma once +#include #include #include @@ -31,16 +32,16 @@ struct policy_update_req; namespace AskUser { +class PolicyEntryCopy; + std::string getOwnAppId(); void identifyApp(const std::string &client, std::string &appId, std::string &pkgLabel); -Policy calculatePolicyForPrivacy(const std::string &appId, const Privacy &privacy); -Policy getMinimumPolicy(const std::vector &policies); -Policy getPrivilegeMappedPolicy(const std::string &appId, const Privilege &privilege); -Policy getPrivaciesPolicy(const std::string &appId, const std::vector &privacies); +std::set getManifestPrivs(const std::string &appId); Policy getPrivilegePolicy(const std::string &appId, const Privilege &corePrivilege); +std::vector getAppPolicy(const std::string &appId); class PolicyEntry { public: diff --git a/src/common/policy/PrivilegeInfo.cpp b/src/common/policy/PrivilegeInfo.cpp index 200e068..9a3e9b7 100644 --- a/src/common/policy/PrivilegeInfo.cpp +++ b/src/common/policy/PrivilegeInfo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Samsung Electronics Co. + * Copyright (c) 2016-2018 Samsung Electronics Co. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ */ /** * @file src/agent/notification-daemon/Privilege.cpp - * @author Zofia Abramowska + * @author Zofia Grzelewska * @brief Implementation of Privilege Info wrappers */ @@ -23,6 +23,7 @@ #include #include +#include "Policy.h" #include "PrivilegeInfo.h" #include @@ -31,10 +32,8 @@ #include #include -#include #include - namespace AskUser { namespace PrivilegeInfo { @@ -69,6 +68,20 @@ private: GList *m_head; }; +Privacy getPrivacyName(const Privilege &privilege) { + char* privacyName = nullptr; + int ret = privilege_info_get_privacy_by_privilege(privilege.c_str(), &privacyName); + if (ret != PRVMGR_ERR_NONE || !privacyName) { + ALOGE("Unable to get privacy group for privilege: <" << privilege << ">, err: <" << ret << ">"); + return privilege; + } + + std::unique_ptr privacyNamePtr(privacyName, free); + return std::string(privacyName); +} + +} //namespace anonymous + std::vector getPrivilegesPrivacies(const std::vector &corePrivileges) { std::set privaciesSet; for (auto &privilege : corePrivileges) { @@ -133,9 +146,6 @@ std::vector getPrivilegeMapping(const std::string &appId, const Privi return privMappedVector; } - -} //namespace anonymous - bool isPrivacy(const Privilege &privilege) { return privilege_info_is_privacy(privilege.c_str()) == 1; } @@ -151,18 +161,6 @@ std::string getPrivacyDisplayName(const Privacy &privacy) { return std::string(displayName); } -Privacy getPrivacyName(const Privilege &privilege) { - char* privacyName = nullptr; - int ret = privilege_info_get_privacy_by_privilege(privilege.c_str(), &privacyName); - if (ret != PRVMGR_ERR_NONE || !privacyName) { - ALOGE("Unable to get privacy group for privilege: <" << privilege << ">, err: <" << ret << ">"); - return privilege; - } - - std::unique_ptr privacyNamePtr(privacyName, free); - return std::string(privacyName); -} - std::vector getPrivacyPrivileges(const Privacy &privacy) { GList *privilegeList = nullptr; @@ -180,16 +178,5 @@ std::vector getPrivacyPrivileges(const Privacy &privacy) { return privVector; } - -std::vector getPrivilegePrivaciesMapping(const std::string &appId, const std::string &privilege) { - std::vector corePrivileges = PrivilegeInfo::getPrivilegeMapping(appId, privilege); - if (corePrivileges.empty()) { - ALOGE("Cannot fetch mapping for application " << appId << " and privilege " << privilege << ", aborting"); - return {}; - } - - return getPrivilegesPrivacies(corePrivileges); -} - } } /* namespace AskUser */ diff --git a/src/common/policy/PrivilegeInfo.h b/src/common/policy/PrivilegeInfo.h index 06d714e..fa651bc 100644 --- a/src/common/policy/PrivilegeInfo.h +++ b/src/common/policy/PrivilegeInfo.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Samsung Electronics Co. + * Copyright (c) 2016-2018 Samsung Electronics Co. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,9 +14,9 @@ * limitations under the License */ /** - * @file src/agent/notification-daemon/Privilege.h - * @author Zofia Abramowska - * @brief Definition of Privilege Info wrappers + * @file PrivilegeInfo.h + * @author Zofia Grzelewska + * @brief Definition of Privilege Info wrappers. */ #pragma once @@ -29,9 +29,11 @@ namespace AskUser { namespace PrivilegeInfo { - std::vector getPrivilegePrivaciesMapping(const std::string &appId, const std::string &privilege); + std::vector getPrivilegeMapping(const std::string &appId, + const Privilege &privilege); + std::vector getPrivilegesPrivacies(const std::vector &corePrivileges); bool isPrivacy(const Privilege &privilege); - Privacy getPrivacyName(const Privacy &privilege); + std::string getPrivacyDisplayName(const Privacy &privacy); std::vector getPrivacyPrivileges(const Privacy &privacy); diff --git a/src/common/policy/PrivilegePolicy.cpp b/src/common/policy/PrivilegePolicy.cpp new file mode 100644 index 0000000..66dc203 --- /dev/null +++ b/src/common/policy/PrivilegePolicy.cpp @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2018 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. + * 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 PrivilegePolicy.cpp + * @author Zofia Grzelewska + * @brief The implementation of PrivilegePolicy class. + */ + + +#include +#include +#include + +#include +#include +#include +#include + +#include "PrivilegePolicy.h" + +namespace AskUser { + +namespace { +bool updateMinimal(const Policy ¤t, Policy &minimal) { + if (current == "Deny") { + minimal = "Deny"; + return false; + } else if (current != minimal && current == "Ask user") { + minimal = "Ask user"; + } + return true; +} + +Policy calculatePrivsPolicy(const std::vector &privs, + const std::unordered_map &policyMap) { + Policy minimalPolicy = "Allow"; + bool policyExists = false; + + for (auto & priv : privs) { + auto it = policyMap.find(priv); + if (it == policyMap.end()) { + ALOGD("Application has no privacy policy for privilege " << priv); + continue; + } + policyExists = true; + if (!updateMinimal(it->second, minimalPolicy)) + break; + } + + if (!policyExists) + return ""; + + return minimalPolicy; +} + +} // anonymous namespace + +PrivilegePolicy::PrivilegePolicy(const std::string &appId, const Privilege &privilege) + : m_appId(appId), + m_privilege(privilege) +{} + +Policy PrivilegePolicy::calculatePolicy() { + std::vector corePrivileges = + PrivilegeInfo::getPrivilegeMapping(m_appId, m_privilege); + if (corePrivileges.empty()) { + ALOGE("Privilege " << m_privilege << " doesn't map to any core privilege"); + return "Deny"; + } + + // Check if application requested core privileges in manifest + std::set manifestPrivs = getManifestPrivs(m_appId); + for (auto &corePriv : corePrivileges) { + if (manifestPrivs.find(corePriv) == manifestPrivs.end()) { + ALOGE("Application " << m_appId << " didn't request privilege " + << corePriv << " in its manifest"); + return "Deny"; + } + } + std::vector privacies = PrivilegeInfo::getPrivilegesPrivacies(corePrivileges); + if (privacies.empty()) { + ALOGE("Privilege doesn't map to any privacy"); + return "Allow"; + } + + return calculatePrivaciesPolicy(privacies); +} + + +Policy PrivilegePolicy::calculatePrivaciesPolicy(const std::vector &privacies) { + std::unordered_map> privacyPrivileges; + std::unordered_map privilegePolicy; + + for (auto &privacy : privacies) { + auto privileges = PrivilegeInfo::getPrivacyPrivileges(privacy); + privacyPrivileges[privacy] = privileges; + } + + auto policies = getAppPolicy(m_appId); + + for (auto &policy : policies) { + privilegePolicy[policy.getPrivilege()] = policy.getLevel(); + } + + m_askablePrivacies.clear(); + Policy totalPolicy = "Allow"; + for (auto &privacy : privacies) { + Policy policy = calculatePrivsPolicy(privacyPrivileges[privacy], privilegePolicy); + if (policy.empty()) { + ALOGD("Privacy group " << privacy << " is not privacy for application " << m_appId); + policy = "Allow"; + } + if (policy == "Ask user") { + m_askablePrivacies.push_back(privacy); + } + if (!updateMinimal(policy, totalPolicy)) + break; + } + + if (totalPolicy == "Deny") + m_askablePrivacies.clear(); + + return totalPolicy; +} + +} diff --git a/src/common/policy/PrivilegePolicy.h b/src/common/policy/PrivilegePolicy.h new file mode 100644 index 0000000..c22e45b --- /dev/null +++ b/src/common/policy/PrivilegePolicy.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2018 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. + * 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 PrivilegePolicy.h + * @author Zofia Grzelewska + * @brief The definition of PrivilegePolicy class. + */ + +#include +#include +#include + +#include + +namespace AskUser { + +class PrivilegePolicy { +public: + PrivilegePolicy(const std::string &appId, const Privilege &privilege); + Policy calculatePolicy(); + std::vector getAskablePrivacies() const { + return m_askablePrivacies; + } +private: + Policy calculatePrivaciesPolicy(const std::vector &privacies); + std::string m_appId; + Privilege m_privilege; + + std::vector m_askablePrivacies; +}; + +} diff --git a/src/notification-daemon/CMakeLists.txt b/src/notification-daemon/CMakeLists.txt index fba96a9..c01f1ea 100644 --- a/src/notification-daemon/CMakeLists.txt +++ b/src/notification-daemon/CMakeLists.txt @@ -12,7 +12,6 @@ PKG_CHECK_MODULES(ASKUSER_NOTIFICATION_DEP glib-2.0 capi-ui-efl-util capi-system-info - security-privilege-manager ) INCLUDE_DIRECTORIES(SYSTEM diff --git a/src/notification-daemon/Logic.cpp b/src/notification-daemon/Logic.cpp index 4967110..8740123 100644 --- a/src/notification-daemon/Logic.cpp +++ b/src/notification-daemon/Logic.cpp @@ -14,9 +14,9 @@ * limitations under the License */ /** - * @file src/agent/notification-daemon/Service.cpp - * @author Zofia Abramowska - * @brief Declaration of Popupper class + * @file Logic.cpp + * @author Zofia Grzelewska + * @brief Declaration of Logic class */ #include "Logic.h" @@ -31,10 +31,10 @@ #include #include #include +#include + #include "PolicyUpdater.h" #include "ServerCallbacks.h" -#include "policy/PrivilegeInfo.h" - namespace AskUser { @@ -225,35 +225,8 @@ void Logic::popup(Protocol::ConnectionFd fd, Protocol::RequestId id, const std:: } ConnectionInfo &conn = it->second; - std::vector privacies = PrivilegeInfo::getPrivilegePrivaciesMapping(conn.appId, privilege); - if (privacies.empty()) { - ALOGE("Privilege " << privilege << " doesn't map to any privacy"); - m_serverChannel->popupResponse(fd, id, ASKUSER_DENY_ONCE); - return; - } - - std::vector policies; - - std::string removePrivacy = "removeme"; - for (auto &privacy : privacies) { - std::string policy = calculatePolicyForPrivacy(conn.appId, privacy); - if (policy == "Allow") { - // Remove privacies which are already allowed - we don't need to spam user more with popups - privacy = removePrivacy; - } - if (policy.empty()) { - ALOGD("Application doesn't use privacy " << privacy); - continue; - } - policies.push_back(policy); - } - - if (policies.empty()) { - ALOGD("Privilege " << privilege << " is not privacy for app : " << conn.appId); - m_serverChannel->popupResponse(fd, id, ASKUSER_DENY_FOREVER); - return; - } - std::string policyLevel = getMinimumPolicy(policies); + PrivilegePolicy privPolicy(conn.appId, privilege); + auto policyLevel = privPolicy.calculatePolicy(); ALOGD("Privilege policy level calculated to : " << policyLevel); if (policyLevel == "Allow") { @@ -271,8 +244,13 @@ void Logic::popup(Protocol::ConnectionFd fd, Protocol::RequestId id, const std:: return; } - auto removeIt = std::remove_if(privacies.begin(), privacies.end(), [&](const Privacy &privacy) {return privacy == removePrivacy;}); - privacies.erase(removeIt, privacies.end()); + auto privacies = privPolicy.getAskablePrivacies(); + if (privacies.empty()) { + ALOGE("All privacies for privilege " << privilege + << " are already allowed"); + m_serverChannel->popupResponse(fd, id, ASKUSER_ALLOW_FOREVER); + return; + } addEvent(fd, id, privacies); processEvents();