Merge branch 'ckm' into tizen 99/236199/1
authorDariusz Michaluk <d.michaluk@samsung.com>
Mon, 15 Jun 2020 11:41:41 +0000 (13:41 +0200)
committerDariusz Michaluk <d.michaluk@samsung.com>
Mon, 15 Jun 2020 11:41:41 +0000 (13:41 +0200)
Change-Id: I8e7dbe5e42290ebc991669d6e8405ff65eeb9972

36 files changed:
packaging/security-tests.spec
src/common/app_def_privilege.h
src/common/app_install_helper.cpp
src/common/app_install_helper.h
src/common/scoped_installer.h
src/common/sm_api.cpp
src/common/sm_policy_request.cpp
src/common/sm_policy_request.h
src/common/sm_request.cpp
src/security-manager-tests/CMakeLists.txt
src/security-manager-tests/common/app_install_helper_ext.cpp [new file with mode: 0644]
src/security-manager-tests/common/app_install_helper_ext.h [new file with mode: 0644]
src/security-manager-tests/common/policy_configuration.cpp
src/security-manager-tests/common/policy_configuration.h
src/security-manager-tests/common/privilege_names.h [new file with mode: 0644]
src/security-manager-tests/common/scoped_app_launcher.cpp [new file with mode: 0644]
src/security-manager-tests/common/scoped_app_launcher.h [new file with mode: 0644]
src/security-manager-tests/common/sm_commons.cpp
src/security-manager-tests/common/sm_commons.h
src/security-manager-tests/common/template_parser.h
src/security-manager-tests/smack-privileges/backup/.dummy [new file with mode: 0644]
src/security-manager-tests/smack-privileges/empty/privilege-mapping/.dummy [new file with mode: 0644]
src/security-manager-tests/smack-privileges/internet-only/privilege-mapping/priv-rules-default-template.smack [new file with mode: 0644]
src/security-manager-tests/smack-privileges/internet-only/privilege-smack.list [new file with mode: 0644]
src/security-manager-tests/smack-privileges/malformed/privilege-mapping/priv-rules-default-template.smack [new file with mode: 0644]
src/security-manager-tests/smack-privileges/malformed/privilege-smack.list [new file with mode: 0644]
src/security-manager-tests/smack-privileges/multiple-privs/privilege-mapping/flawed-camera-template.smack [new file with mode: 0644]
src/security-manager-tests/smack-privileges/multiple-privs/privilege-mapping/priv-rules-default-template.smack [new file with mode: 0644]
src/security-manager-tests/smack-privileges/multiple-privs/privilege-smack.list [new file with mode: 0644]
src/security-manager-tests/test_cases.cpp
src/security-manager-tests/test_cases_app_defined_privilege.cpp
src/security-manager-tests/test_cases_app_policy.cpp
src/security-manager-tests/test_cases_nss.cpp
src/security-manager-tests/test_cases_prepare_app.cpp
src/security-manager-tests/test_cases_privacy_manager.cpp
src/security-manager-tests/test_cases_smack_privileges.cpp [new file with mode: 0644]

index 76d554c..d7d6de7 100644 (file)
@@ -30,7 +30,7 @@ BuildRequires: libcynara-creds-dbus-devel
 BuildRequires: libcynara-creds-gdbus-devel
 BuildRequires: libcynara-creds-sd-bus-devel
 BuildRequires: pkgconfig(libtzplatform-config)
-BuildRequires: boost-devel
+BuildRequires: pkgconfig(boost)
 BuildRequires: pkgconfig(vconf)
 BuildRequires: pkgconfig(libgum) >= 1.0.5
 BuildRequires: pkgconfig(security-privilege-manager)
@@ -45,6 +45,7 @@ Requires: toybox-symlinks-ping
 %global ckm_test_dir %{?TZ_SYS_SHARE:%TZ_SYS_SHARE/ckm-test/}%{!?TZ_SYS_SHARE:/usr/share/ckm-test/}
 %global ckm_rw_data_dir %{?TZ_SYS_DATA:%TZ_SYS_DATA/ckm/}%{!?TZ_SYS_DATA:/opt/data/ckm/}
 %global tz_backend_enabled %{?tz_backend:%tz_backend}%{!?tz_backend:OFF}
+%global sm_test_dir %{?TZ_SYS_SHARE:%TZ_SYS_SHARE/security-manager-test}%{!?TZ_SYS_SHARE:/usr/share/security-manager-test}
 
 %description
 Security tests repository - for tests that can't be kept together with code.
@@ -75,7 +76,8 @@ cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} \
         -DCKM_TEST_DIR=%{ckm_test_dir} \
         -DCKM_RW_DATA_DIR=%{ckm_rw_data_dir} \
         -DGLOBAL_APP_DIR=%{TZ_SYS_RW_APP} \
-        -DLOCAL_APP_DIR="%{TZ_SYS_HOME}/security_test_user/apps_rw"
+        -DLOCAL_APP_DIR="%{TZ_SYS_HOME}/security_test_user/apps_rw" \
+        -DSM_TEST_DIR="%{sm_test_dir}"
 make %{?jobs:-j%jobs}
 
 %pre
@@ -135,6 +137,7 @@ echo "security-tests postinst done ..."
 %{_prefix}/share/yaca-test
 %dir %{_prefix}/share/security-tests-cleanup-test
 %{_prefix}/share/security-tests-cleanup-test/*
+%{sm_test_dir}
 
 %postun
 id -u security_test_user 1>/dev/null 2>&1 && gum-utils -o -d --uid=`id -u security_test_user`
index d399dac..40d1d46 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2018 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-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.
@@ -32,6 +32,12 @@ public:
         PRIVACY,
     };
 
+    Privilege(const char* systemPrivilege, Type type = UNSET, std::string license = std::string())
+      : m_name(systemPrivilege)
+      , m_type(type)
+      , m_license(std::move(license))
+    {}
+
     Privilege(std::string systemPrivilege, Type type = UNSET, std::string license = std::string())
       : m_name(std::move(systemPrivilege))
       , m_type(type)
@@ -66,6 +72,8 @@ public:
 
     operator std::string() const { return m_name; }
 
+    bool operator==(const std::string& other) const { return m_name == other; }
+
 private:
     std::string m_name;
     Type m_type;
index 1f6e0e8..cbc6a8d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2019 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-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.
@@ -159,12 +159,12 @@ std::string AppInstallHelper::getSharedROPath(int i, RootType type) const {
     return getPath(SECURITY_MANAGER_PATH_OWNER_RW_OTHER_RO, PathType::FILE, i, type);
 }
 
-std::string AppInstallHelper::getAppId() const {
-    return m_appName + "_app_id";
+const std::string& AppInstallHelper::getAppId() const {
+    return m_appName;
 }
 
-std::string AppInstallHelper::getPkgId() const {
-    return m_pkgName + "_pkg_id";
+const std::string& AppInstallHelper::getPkgId() const {
+    return m_pkgName;
 }
 
 void AppInstallHelper::setVersion(const std::string &version) {
@@ -175,6 +175,10 @@ std::string AppInstallHelper::getVersion() const {
     return m_version;
 }
 
+void AppInstallHelper::setUidGid(int uidGid) {
+    m_uidGid = uidGid;
+}
+
 int AppInstallHelper::getUID() const {
     return m_uidGid;
 }
@@ -279,20 +283,6 @@ bool AppInstallHelper::getIsHybrid() const {
     return m_isHybrid;
 }
 
-void AppInstallHelper::addPrivileges(const std::vector<std::string> &privileges) {
-    for (auto &p : privileges) {
-        addPrivilege(Privilege(p));
-    }
-}
-
-std::vector<std::string> AppInstallHelper::getPrivilegesNames() const {
-    std::vector<std::string> privileges;
-    for (auto &p : m_privileges) {
-        privileges.push_back(p.getName());
-    }
-    return privileges;
-}
-
 void AppInstallHelper::addPrivilege(Privilege privilege) {
     m_privileges.push_back(std::move(privilege));
 }
@@ -368,4 +358,3 @@ void AppInstallHelper::setInstallType(app_install_type type) {
 app_install_type AppInstallHelper::getInstallType() const {
     return m_installType;
 }
-
index cefeb71..cc59bc9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2019 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-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.
@@ -38,7 +38,7 @@ struct AppInstallHelper {
                      bool isLocal,
                      uid_t uid,
                      std::string version = std::string())
-      : m_appName(appNamePrefix), m_pkgName(pkgNamePrefix), m_isLocal(isLocal), m_uidGid(uid), m_version(version),
+      : m_appName(appNamePrefix + "_app_id"), m_pkgName(pkgNamePrefix + "_pkg_id"), m_isLocal(isLocal), m_uidGid(uid), m_version(version),
         m_installType(SM_APP_INSTALL_NONE), m_isHybrid(false), m_creatorPid(getpid())
     {}
 
@@ -74,8 +74,9 @@ struct AppInstallHelper {
     AppInstallHelper(AppInstallHelper &&other);
 
     // App info getters and setters
-    std::string getAppId() const;
-    std::string getPkgId() const;
+    const std::string& getAppId() const;
+    const std::string& getPkgId() const;
+    void setUidGid(int uidGid);
     int getUID() const;
     int getGID() const;
     void setVersion(const std::string &version);
@@ -129,8 +130,6 @@ struct AppInstallHelper {
     const TypePathsMap& getFilesMap() const;
 
     // Privileges
-    std::vector<std::string> getPrivilegesNames() const;             // deprecated
-    void addPrivileges(const std::vector<std::string> &privileges);  // deprecated
     void addPrivilege(Privilege privilege);
     void addPrivileges(const PrivilegeVector &privileges);
     const PrivilegeVector& getPrivileges() const;
@@ -163,8 +162,8 @@ protected:
                        RootType rType = RootType::BASE);
     void createInstallDir(RootType type);
 
-    std::string m_appName;
-    std::string m_pkgName;
+    const std::string m_appName;
+    const std::string m_pkgName;
     bool m_isLocal;
     int m_uidGid;
     std::string m_version;
index 82175ce..2eafe25 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
  *
  *    Licensed under the Apache License, Version 2.0 (the "License");
  *    you may not use this file except in compliance with the License.
 
 class ScopedInstaller {
 public:
-    ScopedInstaller(const AppInstallHelper &app, bool requestUid = true)
+    ScopedInstaller(const AppInstallHelper &app,
+                    bool requestUid = true,
+                    lib_retcode expectedResult = SECURITY_MANAGER_SUCCESS)
         : m_appIds({app.getAppId()}),
           m_uid(app.getUID()),
           m_installType(app.getInstallType()),
-          m_shouldUninstall(true),
+          m_shouldUninstall(expectedResult == SECURITY_MANAGER_SUCCESS),
           m_requestUid(requestUid),
           m_creatorPid(getpid())
     {
@@ -67,7 +69,7 @@ public:
         for (const auto &priv : app.getAppDefinedPrivileges())
             instReq.addAppDefinedPrivilege(priv);
 
-        SecurityManagerTest::Api::install(instReq);
+        SecurityManagerTest::Api::install(instReq, expectedResult);
     }
 
     ScopedInstaller(const std::vector<std::string> &appIds, const std::string &pkgId)
index 4516755..dd1af2c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2019 Samsung Electronics Co., Ltd. All rights reserved
+ * Copyright (c) 2014-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.
@@ -27,33 +27,13 @@ namespace Api {
 
 void install(const InstallRequest &request, lib_retcode expectedResult)
 {
-    uid_t uid = getuid();
-    std::string dbPath = uid == 0 ? "/opt/dbspace/" : "/opt/dbspace/user/" + std::to_string(uid) + "/";
-
-    std::ostringstream command;
-    command << "/usr/bin/sqlite3 "
-            << dbPath << ".pkgmgr_parser.db "
-            << " \"insert into package_info (package, package_type, package_api_version,"
-            << " install_location, mainapp_id, root_path, installed_storage)"
-            << " values ('" << request.getPkgId() << "', 'tpk', '" << request.getAppTizenVersion()
-            << "', 'auto', '" << request.getPkgId() << "', '/opt/usr/globallapps/"
-            << request.getPkgId() << "', 'installed_internal')\"";
-    int result = system(command.str().c_str());
-    RUNNER_ASSERT_MSG(result == 0, "failed to set package_info: " << result);
-
-    result = security_manager_app_install(request.get());
+    int result = security_manager_app_install(request.get());
+
     RUNNER_ASSERT_MSG((lib_retcode)result == expectedResult,
                       "installing app returned wrong value."
-                          << " InstallRequest: [ " << request << "];"
-                          << " Result: " << result << ";"
-                          << " Expected result: " << expectedResult);
-
-    command = std::ostringstream();
-    command << "/usr/bin/sqlite3 "
-            << dbPath << ".pkgmgr_parser.db "
-            << " \"delete from package_info where package='" << request.getPkgId() << "'\"";
-    result = system(command.str().c_str());
-    RUNNER_ASSERT_MSG(result == 0, "failed to unset package_info: " << result);
+                      << " InstallRequest: [ " << request << "];"
+                      << " Result: " << result << ";"
+                      << " Expected result: " << expectedResult);
 }
 
 void update(const InstallRequest &request, lib_retcode expectedResult)
index debda17..c129a76 100644 (file)
 
 namespace SecurityManagerTest {
 
+constexpr char PolicyEntry::LEVEL_ALLOW[];
+constexpr char PolicyEntry::LEVEL_DENY[];
+constexpr char PolicyEntry::LEVEL_ASK_USER[];
+
 PolicyEntry::PolicyEntry()
     : m_appId(true, std::string(SECURITY_MANAGER_ANY))
     , m_user(true, std::string(SECURITY_MANAGER_ANY))
index 4c12102..d1791a7 100644 (file)
@@ -29,6 +29,10 @@ namespace SecurityManagerTest {
 class PolicyEntry
 {
 public:
+    static constexpr char LEVEL_ALLOW[] = "Allow";
+    static constexpr char LEVEL_DENY[] = "Deny";
+    static constexpr char LEVEL_ASK_USER[] = "Ask user";
+
     PolicyEntry();
 
     PolicyEntry(const std::string &appId,
index b6fa1a1..89ec04d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2019 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-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.
@@ -44,6 +44,14 @@ InstallRequest::InstallRequest()
     RUNNER_ASSERT_MSG((lib_retcode)result == SECURITY_MANAGER_SUCCESS,
                       "creation of new request failed. Result: " << result);
     RUNNER_ASSERT_MSG(m_req != nullptr, "creation of new request did not allocate memory");
+    // platform level has the widest possible privilege spectrum available, hence using it for all apps
+    result = security_manager_app_inst_req_set_pkg_privilege_level(m_req, SM_PKG_PRIVILEGE_LEVEL_PLATFORM);
+    RUNNER_ASSERT_MSG((lib_retcode)result == SECURITY_MANAGER_SUCCESS,
+                      "setting privilege level failed. Result: " << result);
+    // core seems to map to TPK, which is what we're mimicking
+    result = security_manager_app_inst_req_set_pkg_type(m_req, SM_PKG_TYPE_CORE);
+    RUNNER_ASSERT_MSG((lib_retcode)result == SECURITY_MANAGER_SUCCESS,
+                      "setting package type. Result: " << result);
 }
 
 InstallRequest::~InstallRequest()
index cf08aa4..703d034 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2017 Samsung Electronics Co., Ltd All Rights Reserved
+# Copyright (c) 2014-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.
 # @brief
 #
 
+IF(NOT DEFINED SM_TEST_DIR)
+    SET(SM_TEST_DIR "${SHARE_INSTALL_PREFIX}/security-manager-test")
+ENDIF(NOT DEFINED SM_TEST_DIR)
+ADD_DEFINITIONS("-DSM_TEST_DIR=\"${SM_TEST_DIR}\"")
+
 INCLUDE(FindPkgConfig)
 
 # Dependencies
@@ -31,7 +36,8 @@ PKG_CHECK_MODULES(SEC_MGR_TESTS_DEP
     sqlite3
     libcap
     dbus-1
-    libgum)
+    libgum
+    boost)
 
 
 SET(TARGET_SEC_MGR_TESTS "security-manager-tests")
@@ -52,12 +58,15 @@ SET(SEC_MGR_SOURCES
     ${PROJECT_SOURCE_DIR}/src/security-manager-tests/test_cases_public_sharing.cpp
     ${PROJECT_SOURCE_DIR}/src/security-manager-tests/test_cases_register_paths.cpp
     ${PROJECT_SOURCE_DIR}/src/security-manager-tests/test_cases_shm.cpp
+    ${PROJECT_SOURCE_DIR}/src/security-manager-tests/test_cases_smack_privileges.cpp
     ${PROJECT_SOURCE_DIR}/src/security-manager-tests/test_cases_trusted_sharing.cpp
     ${PROJECT_SOURCE_DIR}/src/security-manager-tests/test_cases_prepare_app.cpp
     ${PROJECT_SOURCE_DIR}/src/security-manager-tests/security_manager_tests.cpp
     ${PROJECT_SOURCE_DIR}/src/security-manager-tests/common/policy_configuration.cpp
     ${PROJECT_SOURCE_DIR}/src/security-manager-tests/common/sm_commons.cpp
     ${PROJECT_SOURCE_DIR}/src/security-manager-tests/common/template_parser.cpp
+    ${PROJECT_SOURCE_DIR}/src/security-manager-tests/common/scoped_app_launcher.cpp
+    ${PROJECT_SOURCE_DIR}/src/security-manager-tests/common/app_install_helper_ext.cpp
     ${PROJECT_SOURCE_DIR}/src/cynara-tests/common/cynara_test_client.cpp
     ${PROJECT_SOURCE_DIR}/src/cynara-tests/common/cynara_test_admin.cpp
     ${PROJECT_SOURCE_DIR}/src/cynara-tests/plugins/plugins.cpp
@@ -100,4 +109,9 @@ INSTALL(DIRECTORY
 INSTALL(DIRECTORY
     ${PROJECT_SOURCE_DIR}/src/security-manager-tests/app_files/
     DESTINATION ${LOCAL_APP_DIR}
+)
+
+INSTALL(DIRECTORY
+    ${PROJECT_SOURCE_DIR}/src/security-manager-tests/smack-privileges
+    DESTINATION ${SM_TEST_DIR}
 )
\ No newline at end of file
diff --git a/src/security-manager-tests/common/app_install_helper_ext.cpp b/src/security-manager-tests/common/app_install_helper_ext.cpp
new file mode 100644 (file)
index 0000000..734a09f
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 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.
+ *    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.
+ */
+
+#include "app_install_helper_ext.h"
+
+#include <grp.h>
+#include <unistd.h>
+#include <sys/smack.h>
+
+#include <utility>
+#include <string>
+#include <unordered_set>
+#include <algorithm>
+
+#include <security-manager-types.h>
+
+#include <sm_api.h>
+#include <label_generator.h>
+#include <cynara_test_client.h>
+#include <policy_configuration.h>
+
+namespace {
+constexpr char SMACK_RULES_PATH[] = "/sys/fs/smackfs/load2";
+constexpr char ANY_USER_REPRESENTATION[] = "anyuser";/*this may be actually any string*/
+
+void assertNoLabelInRule(const AccessRequest &rule, const std::string &label)
+{
+    RUNNER_ASSERT_MSG(rule.object != label && rule.subject != label,
+                      "Smack rule left after uninstallation process." <<
+                      " Subject: " << rule.subject <<
+                      " object: " << rule.object <<
+                      " access: " << rule.access);
+}
+
+std::string accessOpposite(std::string &access)
+{
+    static const std::map<char, int> accessMapping = {{'r', 0}, {'w', 1}, {'x', 2}, {'a', 3},
+                                                      {'t', 4}, {'l', 5}};
+    // May write implies may lock
+    if (access.find('w') != std::string::npos && access.find('l') == std::string::npos) {
+        access.append("l");
+    }
+    std::string oppositeAccess = "rwxatl";
+    for (char c : access) {
+        oppositeAccess[accessMapping.at(c)] = '-';
+    }
+    auto it = std::remove_if(oppositeAccess.begin(), oppositeAccess.end(), [](char c) {return c == '-';});
+    oppositeAccess.erase(it, oppositeAccess.end());
+    return oppositeAccess;
+}
+
+void checkExactSmackAccesses(const std::string &subject, const std::string &object,
+                             const std::string &access)
+{
+    std::string access_str(access);
+    auto no_access = accessOpposite(access_str);
+    for (char c : access_str) {
+        int ret = smack_have_access(subject.c_str(), object.c_str(), std::string(1, c).c_str());
+        RUNNER_ASSERT_MSG(ret >= 0, "smack_have_access failed: <" << subject << ">, <" << object
+                          << ">, <" << c << "> errno=" << strerror(errno));
+        RUNNER_ASSERT_MSG(ret == 1, "Access " << c << " from " << subject << " to "
+                          << object << " not given");
+    }
+
+    for (char c : no_access) {
+        int ret = smack_have_access(subject.c_str(), object.c_str(), std::string(1, c).c_str());
+        RUNNER_ASSERT_MSG(ret >= 0, "smack_have_access failed: <" << subject << ">, <" << object
+                          << ">, <" << c << "> errno=" << strerror(errno));
+        RUNNER_ASSERT_MSG(ret == 0, "Access " << c << " from " << subject << " to "
+                          << object << " unnecessarily given");
+    }
+}
+
+} // namespace anonymous
+
+namespace SecurityManagerTest
+{
+
+void AppInstallHelperExt::checkPrivileges(const PrivilegeVector &allowedPrivs,
+                                          const PrivilegeVector &deniedPrivs) const
+{
+    /* Privileges should be granted to all users if root installs app */
+    auto user = (m_uidGid == 0 ? ANY_USER_REPRESENTATION : std::to_string(m_uidGid));
+
+    std::string smackLabel = generateProcessLabel(m_appName, m_pkgName, m_isHybrid);
+
+    CynaraTestClient::Client ctc;
+    int result;
+
+    for (auto &priv : allowedPrivs) {
+        ctc.check(smackLabel.c_str(), "", user, priv.getName().c_str(), CYNARA_API_ACCESS_ALLOWED);
+
+        Api::appHasPrivilege(m_appName, priv, m_uidGid, result);
+        RUNNER_ASSERT_MSG(result == 1,
+                          "Application " << m_appName << " has no access to " << priv);
+    }
+
+    for (auto &priv : deniedPrivs) {
+        ctc.check(smackLabel.c_str(), "", user, priv.getName().c_str(), CYNARA_API_ACCESS_DENIED);
+
+        Api::appHasPrivilege(m_appName, priv, m_uidGid, result);
+        RUNNER_ASSERT_MSG(result == 0,
+                          "Application " << m_appName << " has unexpected access to " << priv);
+    }
+}
+
+void AppInstallHelperExt::checkDeniedPrivileges(const PrivilegeVector &deniedPrivs) const
+{
+    checkPrivileges({}, deniedPrivs);
+}
+
+void AppInstallHelperExt::checkGroupPrivileges(const PrivilegeVector &expectedPrivs) const
+{
+    static PolicyConfiguration policy;
+
+    // get expected groups
+    auto expectedGids = policy.groupToGid(policy.privToGroup(expectedPrivs));
+    RUNNER_ASSERT_MSG(expectedGids.size() == expectedPrivs.size(),
+                      "Some privileges given were not found in the policy");
+    std::sort(expectedGids.begin(), expectedGids.end());
+
+    // get current process groups
+    int ret = getgroups(0, nullptr);
+    RUNNER_ASSERT_MSG(ret != -1, "Unable to get supplementary groups");
+
+    std::vector<gid_t> actualGids(ret);
+    ret = getgroups(ret, actualGids.data());
+    RUNNER_ASSERT_MSG(ret != -1, "Unable to get supplementary groups");
+
+    // remove groups unrelated to privileges
+    const auto allPrivGids = policy.getGid();
+    auto notPrivGid = [&](gid_t gid){
+        return std::find(allPrivGids.begin(), allPrivGids.end(), gid) == allPrivGids.end();
+    };
+    actualGids.erase(std::remove_if(actualGids.begin(), actualGids.end(), notPrivGid),
+                     actualGids.end());
+    std::sort(actualGids.begin(), actualGids.end());
+
+    // expected but not allowed
+    std::vector<gid_t> notAllowedGids;
+    std::set_difference(expectedGids.begin(), expectedGids.end(),
+                        actualGids.begin(), actualGids.end(),
+                        std::back_inserter(notAllowedGids));
+
+    RUNNER_ASSERT_MSG(notAllowedGids.empty(),
+                      notAllowedGids.size() << " expected groups were not assigned");
+
+    // allowed but not expected
+    std::vector<gid_t> notDeniedGids;
+    std::set_difference(actualGids.begin(), actualGids.end(),
+                        expectedGids.begin(), expectedGids.end(),
+                        std::back_inserter(notDeniedGids));
+
+    RUNNER_ASSERT_MSG(notDeniedGids.empty(),
+                      notDeniedGids.size() << " unexpected groups were assigned");
+}
+
+void AppInstallHelperExt:: checkSmackPrivileges(const PrivilegeVector &allowedPrivs,
+                                                const PrivilegeVector &deniedPrivs) const
+{
+    auto& smackPrivilegeRules = PolicyConfiguration::getSmackPrivRulesMap();
+
+    auto getPrivilegeRules = [&](const PrivilegeVector &privs) {
+        std::vector<AccessRequest> rules;
+
+        for (auto &priv : privs) {
+            auto it = smackPrivilegeRules.find(priv);
+            RUNNER_ASSERT_MSG(it != smackPrivilegeRules.end(), priv << " is not a smack privilege");
+
+            rules.insert(rules.end(), it->second.begin(), it->second.end());
+        }
+        return rules;
+    };
+
+    checkSmackAccesses(getPrivilegeRules(allowedPrivs));
+    checkSmackAccesses(getPrivilegeRules(deniedPrivs), false);
+}
+
+void AppInstallHelperExt::checkAfterInstall() const
+{
+    static const std::vector<AccessRequest> staticRules[] =
+        {parseSmackRulesFile(PolicyConfiguration::getPkgRulesFilePath()),
+         parseSmackRulesFile(PolicyConfiguration::getAppRulesFilePath())};
+
+    checkAppIdExistence(true);
+
+    checkSmackAccesses(staticRules[m_isHybrid]);
+
+    checkPrivileges(m_privileges, {});
+}
+
+void AppInstallHelperExt::checkAfterUninstall(bool removePkg) const
+{
+    checkAppIdExistence(false);
+
+    if (removePkg) {
+        checkPkgSmackRulesAfterUninstall();
+    }
+    // there should be no hybrid rules regardless of the app type
+    checkHybridAppSmackRulesAterUninstall();
+
+    checkDeniedPrivileges(m_privileges);
+}
+
+void AppInstallHelperExt::checkSmackAccesses(std::vector<AccessRequest> rules, bool hasAccess) const
+{
+    const std::pair<std::string, std::string> switchAliases[] = {
+        {"~PATH_RW~", generatePathRWLabel(m_pkgName)},
+        {"~PATH_RO~", generatePathROLabel(m_pkgName)},
+        {"~PROCESS~", generateProcessLabel(m_appName, m_pkgName, m_isHybrid)}
+    };
+
+    for (auto& rule : rules) {
+        if (rule.object == "~PATH_TRUSTED~") {
+            continue;
+        }
+
+        for (const auto &alias : switchAliases) {
+            if (rule.subject == alias.first) {
+                rule.subject = alias.second;
+            }
+            if (rule.object == alias.first) {
+                rule.object = alias.second;
+            }
+        }
+
+        if (!hasAccess)
+            rule.access = "";
+
+        // Special label that may occur in the template. Other special labels will not be used.
+        if (rule.object == "_") {
+            rule.access = "rx" + rule.access;
+        }
+
+        checkExactSmackAccesses(rule.subject, rule.object, rule.access);
+    }
+}
+
+void AppInstallHelperExt::checkPkgSmackRulesAfterUninstall() const
+{
+    const std::vector<AccessRequest> rules(std::move(parseSmackRulesFile(SMACK_RULES_PATH)));
+    const std::string labels[] = {generatePathRWLabel(m_pkgName),
+                                  generatePathROLabel(m_pkgName),
+                                  generateProcessLabel(m_appName, m_pkgName, true),
+                                  generateProcessLabel(m_appName, m_pkgName)};
+
+    for (const auto &rule : rules) {
+        for (const auto &label : labels) {
+            assertNoLabelInRule(rule, label);
+        }
+    }
+}
+
+void AppInstallHelperExt::checkHybridAppSmackRulesAterUninstall() const
+{
+    const std::vector<AccessRequest> rules(parseSmackRulesFile(SMACK_RULES_PATH));
+    const std::string appLabel = generateProcessLabel(m_appName, m_pkgName, true);
+
+    for (const auto &rule : rules) {
+        assertNoLabelInRule(rule, appLabel);
+    }
+}
+
+void AppInstallHelperExt::checkAppIdExistence(bool expected) const
+{
+    lib_retcode ret = expected ? SECURITY_MANAGER_SUCCESS : SECURITY_MANAGER_ERROR_NO_SUCH_OBJECT;
+    std::string retPkgId = Api::getPkgId(m_appName, ret);
+
+    if (expected) {
+        RUNNER_ASSERT_MSG(m_pkgName == retPkgId,
+                          "The given appId does not belong to the given pkgId.");
+    }
+}
+
+} // namespace SecurityManagerTest
diff --git a/src/security-manager-tests/common/app_install_helper_ext.h b/src/security-manager-tests/common/app_install_helper_ext.h
new file mode 100644 (file)
index 0000000..fd50ae7
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 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.
+ *    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.
+ */
+#pragma once
+
+#include <sys/types.h>
+
+#include <vector>
+
+#include <app_install_helper.h>
+#include <template_parser.h>
+#include <app_def_privilege.h>
+
+namespace SecurityManagerTest {
+
+class AppInstallHelperExt : public AppInstallHelper {
+public:
+    using AppInstallHelper::AppInstallHelper;
+
+    void checkPrivileges(const PrivilegeVector &allowedPrivs,
+                         const PrivilegeVector &deniedPrivs) const;
+    void checkDeniedPrivileges(const PrivilegeVector &deniedPrivs) const;
+    void checkGroupPrivileges(const PrivilegeVector &allowedPrivs) const;
+    void checkSmackPrivileges(const PrivilegeVector &allowedPrivs,
+                              const PrivilegeVector &deniedPrivs = {}) const;
+    void checkAfterInstall() const;
+    void checkAfterUninstall(bool removePkg = true) const;
+
+    void checkSmackAccesses(std::vector<AccessRequest> rules, bool hasAccess = true) const;
+
+private:
+    void checkPkgSmackRulesAfterUninstall() const;
+    void checkHybridAppSmackRulesAterUninstall() const;
+    void checkAppIdExistence(bool expected) const;
+};
+
+} // namespace SecurityManagerTest
index 1259b36..db34767 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2016-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.
@@ -18,6 +18,7 @@
 #include <regex>
 #include <string>
 #include <vector>
+#include <stdexcept>
 
 #include <grp.h>
 #include <sys/types.h>
 
 #define CONF_DIR "/usr/share/security-manager/policy/"
 #define CONF_GROUP_FILE "privilege-group.list"
+#define CONF_SYSTEMD_PRIVS_FILE "privilege-managed-by-systemd-for-daemons.list"
 #define CONF_USER_TEMPLATE_FILE "usertype-%s.profile"
 
 namespace SecurityManagerTest {
 
+namespace {
+
+PolicyConfiguration::SmackPrivRulesMap parsePrivilegeSmackList() {
+    constexpr char PRIVILEGE[] = "~PRIVILEGE~";
+    PolicyConfiguration::SmackPrivRulesMap privilegeRules;
+
+    std::ifstream templateFile(CONF_DIR "privilege-smack.list");
+
+    if (templateFile.fail())
+        return privilegeRules;
+
+    try {
+        std::string line;
+        while (getline(templateFile, line)) {
+            if (line.empty() || line[0] == '#')
+                continue;
+
+            std::string privilege, label, rulesFileName;
+            std::istringstream stream(line);
+            stream >> privilege >> label >> rulesFileName;
+
+            if (rulesFileName == "default")
+                rulesFileName = "priv-rules-default-template.smack";
+
+            std::ifstream rulesFile(std::string(CONF_DIR) + "privilege-mapping/" + rulesFileName);
+            std::string object, subject, access;
+            while (rulesFile >> subject >> object >> access) {
+                if (object.empty() || subject.empty())
+                    throw std::runtime_error("Malformed rule");
+
+                // ignore
+                if (object.front() != '~' || subject.front() != '~')
+                    continue;
+
+                if (object == PRIVILEGE)
+                    object = label;
+                if (subject == PRIVILEGE)
+                    subject = label;
+                privilegeRules[privilege].emplace_back(std::move(subject),
+                                                       std::move(object),
+                                                       std::move(access));
+            }
+        }
+    } catch (const std::exception&) {
+        privilegeRules.clear();
+    }
+    return privilegeRules;
+}
+
+} // namespace anonymous
+
 gid_t nameToGid(const char *name) {
     struct group entry, *gresult;
     char buffer[1024];
@@ -139,15 +192,20 @@ PolicyConfiguration::PrivVector PolicyConfiguration::loadPrivFile(const std::str
     return result;
 }
 
-PolicyConfiguration::GroupVector PolicyConfiguration::privToGroup(const PolicyConfiguration::PrivVector &privVector) {
-    GroupVector result;
-    if (m_privGroupMap.empty())
-        loadPrivGroupMap();
-    for (auto &e : privVector) {
-        auto it = m_privGroupMap.find(e);
-        if (it == m_privGroupMap.end())
-            continue;
-        result.push_back(it->second);
+PolicyConfiguration::PrivVector PolicyConfiguration::getSystemdManagedPrivs()
+{
+    PolicyConfiguration::PrivVector result;
+    std::ifstream file(CONF_DIR CONF_SYSTEMD_PRIVS_FILE);
+    if (!file.is_open()) {
+        RUNNER_ASSERT_MSG(file.is_open(),
+          "Unable to read config file " << CONF_DIR CONF_SYSTEMD_PRIVS_FILE);
+    }
+    std::string line;
+    std::regex r("^(http(.*))");
+    while (std::getline(file, line)) {
+        std::smatch m;
+        if (std::regex_search(line, m, r))
+            result.emplace_back(m[1]);
     }
     return result;
 }
@@ -168,5 +226,17 @@ void PolicyConfiguration::loadPrivGroupMap(void) {
     }
 }
 
+std::string PolicyConfiguration::getPkgRulesFilePath() {
+    return CONF_DIR "pkg-rules-template.smack";
+}
+std::string PolicyConfiguration::getAppRulesFilePath() {
+    return CONF_DIR "app-rules-template.smack";
+}
+
+const PolicyConfiguration::SmackPrivRulesMap& PolicyConfiguration::getSmackPrivRulesMap() {
+    const static auto smackPrivRulesMap = parsePrivilegeSmackList();
+    return smackPrivRulesMap;
+}
+
 } // namespace SecurityManagerTest
 
index d7bc1c1..cd89dc9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2016-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.
 #include <map>
 #include <string>
 #include <vector>
+#include <unordered_map>
 
 #include <sys/types.h>
 
+#include <template_parser.h>
+
 namespace SecurityManagerTest {
 
 gid_t nameToGid(const char *name);
@@ -32,6 +35,7 @@ public:
     typedef std::vector<std::string> GroupVector;
     typedef std::vector<std::string> PrivVector;
     typedef std::map<std::string, std::string> PrivGroupMap;
+    typedef std::unordered_map<std::string, std::vector<AccessRequest>> SmackPrivRulesMap;
 
     struct UserDescription {
         PrivVector privVector;
@@ -50,12 +54,18 @@ public:
     UserDescription& getUserDescription(UserType userType);
     gid_t groupToGid(const std::string &gname);
     PrivGroupMap getPrivGroupMap();
-    GroupVector privToGroup(const PrivVector &privVector);
+    PrivVector getSystemdManagedPrivs();
+
+    template <typename T>
+    GroupVector privToGroup(const T &privVector);
+    GidVector groupToGid(const GroupVector &groupVector);
 
-static bool getIsAskuserEnabled();
+    static bool getIsAskuserEnabled();
+    static std::string getPkgRulesFilePath();
+    static std::string getAppRulesFilePath();
+    static const SmackPrivRulesMap& getSmackPrivRulesMap();
 
 private:
-    GidVector groupToGid(const GroupVector &groupVector);
     UserDescription loadUserDescription(UserType userType);
     PrivVector loadPrivFile(const std::string &path);
     void loadPrivGroupMap(void);
@@ -65,6 +75,21 @@ private:
     std::map<UserType, UserDescription> m_userDescriptionMap;
 };
 
+template <typename T>
+PolicyConfiguration::GroupVector PolicyConfiguration::privToGroup(const T &privVector) {
+    GroupVector result;
+    if (m_privGroupMap.empty())
+        loadPrivGroupMap();
+    for (auto &e : privVector) {
+        auto it = m_privGroupMap.find(e);
+        if (it == m_privGroupMap.end())
+            continue;
+        result.push_back(it->second);
+    }
+    return result;
+}
+
+
 } // namespace SecurityManagerTest
 
 #endif
diff --git a/src/security-manager-tests/common/privilege_names.h b/src/security-manager-tests/common/privilege_names.h
new file mode 100644 (file)
index 0000000..2c6e418
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 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.
+ *    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.
+ */
+
+#pragma once
+
+namespace PrivilegeNames {
+
+constexpr char PRIV_INTERNAL_AUDIO[] = "http://tizen.org/privilege/internal/device/audio";
+constexpr char PRIV_INTERNAL_DISPLAY[] = "http://tizen.org/privilege/internal/device/display";
+constexpr char PRIV_INTERNAL_USERMANAGEMENT[] = "http://tizen.org/privilege/internal/usermanagement";
+constexpr char PRIV_INTERNAL_VIDEO[] = "http://tizen.org/privilege/internal/device/video";
+
+constexpr char PRIV_ACCOUNT_READ[] = "http://tizen.org/privilege/account.read";
+constexpr char PRIV_BLUETOOTH[] = "http://tizen.org/privilege/bluetooth";
+constexpr char PRIV_CALENDAR_READ[] = "http://tizen.org/privilege/calendar.read";
+constexpr char PRIV_CALENDAR_WRITE[] = "http://tizen.org/privilege/calendar.write";
+constexpr char PRIV_CALLHISTORY_READ[] = "http://tizen.org/privilege/callhistory.read";
+constexpr char PRIV_CAMERA[] = "http://tizen.org/privilege/camera";
+constexpr char PRIV_CONTACTS_READ[] = "http://tizen.org/privilege/contacts.read";
+constexpr char PRIV_CONTENT_WRITE[] = "http://tizen.org/privilege/content.write";
+constexpr char PRIV_DATASHARING[] = "http://tizen.org/privilege/datasharing";
+constexpr char PRIV_DISPLAY[] = "http://tizen.org/privilege/display";
+constexpr char PRIV_EMAIL[] = "http://tizen.org/privilege/email";
+constexpr char PRIV_EXTERNALSTORAGE[] = "http://tizen.org/privilege/externalstorage";
+constexpr char PRIV_HEALTHINFO[] = "http://tizen.org/privilege/healthinfo";
+constexpr char PRIV_INTERNET[] = "http://tizen.org/privilege/internet";
+constexpr char PRIV_LED[] = "http://tizen.org/privilege/led";
+constexpr char PRIV_LOCATION[] = "http://tizen.org/privilege/location";
+constexpr char PRIV_MEDIASTORAGE[] = "http://tizen.org/privilege/mediastorage";
+constexpr char PRIV_NFC[] = "http://tizen.org/privilege/nfc";
+constexpr char PRIV_NOTEXIST[] = "http://tizen.org/privilege/notexist";
+constexpr char PRIV_NOTIFICATION[] = "http://tizen.org/privilege/notification";
+constexpr char PRIV_POWER[] = "http://tizen.org/privilege/power";
+constexpr char PRIV_PUSH[] = "http://tizen.org/privilege/push";
+constexpr char PRIV_SYSTEMMONITOR[] = "http://tizen.org/privilege/systemmonitor";
+constexpr char PRIV_TELEPHONY[] = "http://tizen.org/privilege/telephony";
+constexpr char PRIV_VOLUME_SET[] = "http://tizen.org/privilege/volume.set";
+constexpr char PRIV_VPNSERVICE[] = "http://tizen.org/privilege/vpnservice";
+constexpr char PRIV_WIFIDIRECT[] = "http://tizen.org/privilege/wifidirect";
+
+}
diff --git a/src/security-manager-tests/common/scoped_app_launcher.cpp b/src/security-manager-tests/common/scoped_app_launcher.cpp
new file mode 100644 (file)
index 0000000..bde5681
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 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.
+ *    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.
+ */
+
+#include <scoped_app_launcher.h>
+#include <sm_api.h>
+#include <sm_commons.h>
+#include <tests_common.h>
+#include <dpl/test/safe_cleanup.h>
+
+using namespace SecurityManagerTest;
+
+ScopedAppLauncher::ScopedAppLauncher(const AppInstallHelper& app,
+                                     const std::function<void(void)>& runInAppContext) :
+    m_uid(app.getUID()),
+    m_appId(app.getAppId())
+{
+    m_pid = fork();
+    RUNNER_ASSERT_ERRNO_MSG(m_pid >= 0, "Fork failed");
+    if (m_pid != 0) {
+        m_syncPipe.claimParentEp();
+        m_syncPipe.wait();
+    } else {
+        m_syncPipe.claimChildEp();
+
+        try {
+            RUNNER_ASSERT_ERRNO_MSG(setLauncherSecurityAttributes(app.getUID(), app.getGID()) == 0,
+                                    "launcher failed");
+            Api::prepareAppCandidate();
+            Api::prepareApp(app.getAppId().c_str());
+            runInAppContext();
+        } catch (...) {
+            m_syncPipe.post();
+            throw;
+        }
+        m_syncPipe.post();
+        m_syncPipe.wait();
+        exit(0);
+    }
+}
+
+ScopedAppLauncher::~ScopedAppLauncher()
+{
+    SafeCleanup::run([this]{
+        m_syncPipe.post();
+        waitPid(m_pid);
+        Api::cleanupApp(m_appId, m_uid, m_pid);
+    });
+}
diff --git a/src/security-manager-tests/common/scoped_app_launcher.h b/src/security-manager-tests/common/scoped_app_launcher.h
new file mode 100644 (file)
index 0000000..133e7c8
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 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.
+ *    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.
+ */
+#pragma once
+
+#include <functional>
+
+#include <app_install_helper.h>
+#include <synchronization_pipe.h>
+
+class ScopedAppLauncher final {
+public:
+    explicit ScopedAppLauncher(const AppInstallHelper& app,
+                               const std::function<void(void)>& runInAppContext = []{});
+    ~ScopedAppLauncher();
+
+    ScopedAppLauncher(const ScopedAppLauncher&) = delete;
+    ScopedAppLauncher& operator=(const ScopedAppLauncher&) = delete;
+
+private:
+    SynchronizationPipe m_syncPipe;
+    pid_t m_pid;
+    const uid_t m_uid;
+    const std::string m_appId;
+};
index 16db76c..ce822cd 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
  *
  *    Licensed under the Apache License, Version 2.0 (the "License");
  *    you may not use this file except in compliance with the License.
  *    limitations under the License.
  */
 
-#include <algorithm>
 #include <cstring>
 #include <fcntl.h>
 #include <ftw.h>
-#include <grp.h>
 #include <string>
 #include <sys/capability.h>
 #include <sys/prctl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <unistd.h>
-#include <unordered_map>
 #include <cstdlib>
 
-#include <array>
-#include <unordered_set>
 #include <utility>
 #include <vector>
+#include <unordered_map>
 
 #include <security-manager-types.h>
 #include <app-runtime.h>
-#include <sys/smack.h>
 #include <privilege_info.h>
 #include <scoped_process_label.h>
 
-#include <cynara_test_client.h>
 #include <dpl/test/test_runner.h>
 #include <memory.h>
 #include <sm_api.h>
 #include <sm_commons.h>
-#include <synchronization_pipe.h>
-#include <sm_request.h>
+
 #include <tests_common.h>
-#include <policy_configuration.h>
 #include "tzplatform.h"
-#include <label_generator.h>
 #include <template_parser.h>
 #include <temp_test_user.h>
 
 using namespace SecurityManagerTest;
 
-#define CONF_DIR "/usr/share/security-manager/policy/"
-#define SMACK_RULES_PATH "/sys/fs/smackfs/load2"
-
 #define ALLOW 0
 #define DENY -1
 
@@ -161,190 +148,6 @@ int nftw_remove_labels(const char *fpath, const struct stat* /*sb*/,
     return 0;
 }
 
-void check_app_permissions(const std::string &app_id, const std::string &pkg_id,
-                           const std::string &user, const privileges_t &allowed_privs,
-                           const privileges_t &denied_privs, bool isHybrid)
-{
-    (void) pkg_id;
-    std::string smackLabel = generateProcessLabel(app_id, pkg_id, isHybrid);
-
-    CynaraTestClient::Client ctc;
-
-    for (auto &priv : allowed_privs) {
-        ctc.check(smackLabel.c_str(), "", user, priv.c_str(), CYNARA_API_ACCESS_ALLOWED);
-    }
-
-    for (auto &priv : denied_privs) {
-        ctc.check(smackLabel.c_str(), "", user, priv.c_str(), CYNARA_API_ACCESS_DENIED);
-    }
-}
-
-void sm_app_has_privileges(const AppInstallHelper &app,
-                           const std::vector<std::string> &privileges,
-                           int expectedResult)
-{
-    for (auto const &privilege : privileges) {
-        int result;
-        Api::appHasPrivilege(app.getAppId(), privilege, app.getUID(), result);
-        RUNNER_ASSERT_MSG(result == expectedResult, "Application " << app.getAppId()
-                          << " has unexpected access to " << privilege << ", is : "
-                          << " should be : " << expectedResult );
-    }
-}
-
-static void check_app_smack_accesses(const std::string &appId, const std::string &pkgId,
-                                     bool isHybrid = false)
-{
-    static const std::vector<AccessRequest> rules[] =
-        {parseSmackRulesFile(CONF_DIR "pkg-rules-template.smack"),
-         parseSmackRulesFile(CONF_DIR "app-rules-template.smack")};
-
-    const std::pair<std::string, std::string> switchAliases[] =
-        {std::make_pair("~PATH_RW~", generatePathRWLabel(pkgId)),
-         std::make_pair("~PATH_RO~", generatePathROLabel(pkgId)),
-         std::make_pair("~PATH_SHARED_RO~", getSharedROPathLabel()),
-         std::make_pair("~PROCESS~", generateProcessLabel(appId, pkgId, isHybrid))};
-
-    for (auto rule : rules[isHybrid]) {
-        if (rule.object == "~PATH_TRUSTED~") {
-            continue;
-        }
-
-        for (const auto &alias : switchAliases) {
-            if (rule.subject == alias.first) {
-                rule.subject = alias.second;
-            }
-            if (rule.object == alias.first) {
-                rule.object = alias.second;
-            }
-        }
-
-        if (rule.object == "_") {
-            rule.access = "rx" + rule.access;
-        }
-
-        check_exact_smack_accesses(rule.subject, rule.object, rule.access);
-    }
-}
-
-static void assert_no_label_in_rule(const AccessRequest &rule, const std::string &label)
-{
-    RUNNER_ASSERT_MSG(rule.object != label && rule.subject != label,
-                      "Smack rule left after uninstallation process." <<
-                      " Subject: " << rule.subject <<
-                      " object: " << rule.object <<
-                      " access: " << rule.access);
-}
-
-static void check_pkg_smack_rules_after_uninstall(const std::string &appId, const std::string &pkgId)
-{
-    const std::vector<AccessRequest> rules(std::move(parseSmackRulesFile(SMACK_RULES_PATH)));
-    const std::string labels[] = {generatePathRWLabel(pkgId),
-                                  generatePathROLabel(pkgId),
-                                  generateProcessLabel(appId, pkgId, true),
-                                  generateProcessLabel(appId, pkgId)};
-    for (const auto &rule : rules) {
-        for (const auto &label : labels) {
-            assert_no_label_in_rule(rule, label);
-        }
-    }
-}
-
-static void check_hybrid_app_smack_rules_after_uninstall(const std::string &appId, const std::string &pkgId)
-{
-    const std::vector<AccessRequest> rules(std::move(parseSmackRulesFile(SMACK_RULES_PATH)));
-    const std::string appLabel = generateProcessLabel(appId, pkgId, true);
-    for (const auto &rule : rules) {
-        assert_no_label_in_rule(rule, appLabel);
-    }
-}
-
-static void check_app(const std::string &appId, const std::string &pkgId,
-                      bool shouldBeInstalled, bool isHybrid, bool removePkg)
-{
-    char *retPkgId;
-    int ret = security_manager_get_app_pkgid(&retPkgId, appId.c_str());
-
-    if (shouldBeInstalled) {
-        RUNNER_ASSERT_MSG(ret == SECURITY_MANAGER_SUCCESS, "The given appId is not installed.");
-
-        if (ret == SECURITY_MANAGER_SUCCESS) {
-            CStringPtr retPkgIdPtr(retPkgId);
-            RUNNER_ASSERT_MSG(strcmp(pkgId.c_str(), retPkgId) == 0,
-                              "The given appId does not belong to the given pkgId.");
-        }
-        check_app_smack_accesses(appId, pkgId, isHybrid);
-    } else {
-        RUNNER_ASSERT_MSG(ret == SECURITY_MANAGER_ERROR_NO_SUCH_OBJECT, "The given appId is installed.");
-
-        if (removePkg) {
-            check_pkg_smack_rules_after_uninstall(appId, pkgId);
-        } else if (isHybrid) {
-            check_hybrid_app_smack_rules_after_uninstall(appId, pkgId);
-        }
-    }
-}
-
-void check_app_after_install(const std::string &app_id, const std::string &pkg_id, bool isHybrid)
-{
-    check_app(app_id, pkg_id, true, isHybrid, false);
-}
-
-static void check_app_gids(const std::string &app_id, const std::vector<gid_t> &allowed_gids)
-{
-    int ret;
-    gid_t main_gid = getgid();
-    std::unordered_set<gid_t> reference_gids(allowed_gids.begin(), allowed_gids.end());
-
-    // Reset supplementary groups
-    ret = setgroups(0, NULL);
-    RUNNER_ASSERT_MSG(ret != -1, "Unable to set supplementary groups");
-
-    Api::setProcessGroups(app_id);
-
-    ret = getgroups(0, nullptr);
-    RUNNER_ASSERT_MSG(ret != -1, "Unable to get supplementary groups");
-
-    std::vector<gid_t> actual_gids(ret);
-    ret = getgroups(ret, actual_gids.data());
-    RUNNER_ASSERT_MSG(ret != -1, "Unable to get supplementary groups");
-
-    for (const auto &gid : actual_gids) {
-        RUNNER_ASSERT_MSG(gid == main_gid || reference_gids.count(gid) > 0,
-            "Application shouldn't get access to group " << gid);
-        reference_gids.erase(gid);
-    }
-
-    RUNNER_ASSERT_MSG(reference_gids.empty(), "Application didn't get access to some groups");
-}
-
-static const char *const ANY_USER_REPRESENTATION = "anyuser";/*this may be actually any string*/
-
-void check_app_after_install(const std::string &app_id, const std::string &pkg_id,
-                             const privileges_t &allowed_privs,
-                             const privileges_t &denied_privs,
-                             bool isHybrid)
-{
-    check_app(app_id, pkg_id, true, isHybrid, false);
-    /* Privileges should be granted to all users if root installs app */
-    check_app_permissions(app_id, pkg_id, ANY_USER_REPRESENTATION, allowed_privs, denied_privs, isHybrid);
-
-    PolicyConfiguration policy;
-    const PolicyConfiguration::GroupVector allowed_groups = policy.privToGroup(allowed_privs);
-    RUNNER_ASSERT_MSG(allowed_groups.size() == allowed_privs.size(),
-                      "Some privileges given were not found in the policy");
-
-    std::vector<gid_t> allowed_gids;
-    for (const auto &groupName : allowed_groups) {
-        errno = 0;
-        struct group* grp = getgrnam(groupName.c_str());
-        RUNNER_ASSERT_ERRNO_MSG(grp, "Group: " << groupName << " not found");
-        allowed_gids.push_back(grp->gr_gid);
-    }
-
-    check_app_gids(app_id, allowed_gids);
-}
-
 void check_path(const std::string &path, const std::string &label, bool transmute, bool execute) {
     nftw_expected_label = label;
     nftw_expected_transmute = transmute;
@@ -355,59 +158,6 @@ void check_path(const std::string &path, const std::string &label, bool transmut
     RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for " << path);
 }
 
-void check_app_after_uninstall(const std::string &app_id, const std::string &pkg_id,
-                               bool isHybrid, bool removePkg)
-{
-    check_app(app_id, pkg_id, false, isHybrid, removePkg);
-}
-
-void check_app_after_uninstall(const std::string &app_id, const std::string &pkg_id,
-                               const privileges_t &privileges, bool isHybrid,
-                               bool removePkg)
-{
-    check_app(app_id, pkg_id, false, isHybrid, removePkg);
-
-    /* Privileges should not be granted anymore to any user */
-    check_app_permissions(app_id, pkg_id, ANY_USER_REPRESENTATION, {}, privileges, isHybrid);
-}
-
-std::string access_opposite(std::string &access) {
-    static const std::map<char, int> access_mapping = {{'r', 0}, {'w', 1}, {'x', 2}, {'a', 3},
-                                                       {'t', 4}, {'l', 5}};
-    // May write implies may lock
-    if (access.find('w') != std::string::npos && access.find('l') == std::string::npos) {
-        access.append("l");
-    }
-    std::string access_opposite = "rwxatl";
-    for (char c : access) {
-        access_opposite[access_mapping.at(c)] = '-';
-    }
-    auto it = std::remove_if(access_opposite.begin(), access_opposite.end(), [](char c) {return c == '-';});
-    access_opposite.erase(it, access_opposite.end());
-    return access_opposite;
-}
-
-void check_exact_smack_accesses(const std::string &subject, const std::string &object,
-                                const std::string &access) {
-    std::string access_str(access);
-    auto no_access = access_opposite(access_str);
-    for (char c : access_str) {
-        int ret = smack_have_access(subject.c_str(), object.c_str(), std::string(1, c).c_str());
-        RUNNER_ASSERT_MSG(ret >= 0, "smack_have_access failed: <" << subject << ">, <" << object
-                          << ">, <" << c << "> errno=" << strerror(errno));
-        RUNNER_ASSERT_MSG(ret == 1, "Access " << c << " from " << subject << " to "
-                          << object << " not given");
-    }
-
-    for (char c : no_access) {
-        int ret = smack_have_access(subject.c_str(), object.c_str(), std::string(1, c).c_str());
-        RUNNER_ASSERT_MSG(ret >= 0, "smack_have_access failed: <" << subject << ">, <" << object
-                          << ">, <" << c << "> errno=" << strerror(errno));
-        RUNNER_ASSERT_MSG(ret == 0, "Access " << c << " from " << subject << " to "
-                          << object << " unnecessarily given");
-    }
-}
-
 CapsSetsUniquePtr setCaps(const char *cap_string)
 {
     CapsSetsUniquePtr caps(cap_init());
index 6840281..427657d 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
  *
  *    Licensed under the Apache License, Version 2.0 (the "License");
  *    you may not use this file except in compliance with the License.
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <vector>
-#include <functional>
-
-#include <security-manager-types.h>
 
 #include <app_install_helper.h>
 #include <memory.h>
 #include <temp_test_user.h>
-#include <tzplatform.h>
 
 DEFINE_SMARTPTR(cap_free, _cap_struct, CapsSetsUniquePtr);
 
 const int FTW_MAX_FDS = 16;
 
-typedef std::vector<std::string> privileges_t;
-
 int nftw_remove_labels(const char *fpath, const struct stat* /*sb*/,
                        int /*typeflag*/, struct FTW* /*ftwbuf*/);
-void check_app_permissions(const std::string &app_id, const std::string &pkg_id,
-                           const std::string &user, const privileges_t &allowed_privs,
-                           const privileges_t &denied_privs, bool isHybrid = false);
-void sm_app_has_privileges(const AppInstallHelper &app,
-                           const std::vector<std::string> &privileges,
-                           int result);
-void check_app_after_install(const std::string &app_id, const std::string &pkg_id,
-                             bool isHybrid = false);
-void check_app_after_install(const std::string &app_id, const std::string &pkg_id,
-                             const privileges_t &allowed_privs,
-                             const privileges_t &denied_privs,
-                             bool isHybrid = false);
 void check_path(const std::string &path, const std::string &label,
                 bool transmute = true, bool execute = false);
-void check_app_after_uninstall(const std::string &app_id, const std::string &pkg_id,
-                               bool isHybrid = false, bool removePkg = false);
-void check_app_after_uninstall(const std::string &app_id, const std::string &pkg_id,
-                               const privileges_t &privileges, bool isHybrid = false,
-                               bool removePkg = false);
-std::string access_opposite(std::string &access);
-void check_exact_smack_accesses(const std::string &subject,
-                                const std::string &object,
-                                const std::string &access);
 
 CapsSetsUniquePtr setCaps(const char *cap_string);
 
index 81a3674..a1bad46 100644 (file)
@@ -18,6 +18,8 @@
  * @author      Alicja Kluczek <a.kluczek@samsung.com>
  * @brief       Parsing function for smack rules templates
  */
+#pragma once
+
 #include <vector>
 #include <string>
 
diff --git a/src/security-manager-tests/smack-privileges/backup/.dummy b/src/security-manager-tests/smack-privileges/backup/.dummy
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/security-manager-tests/smack-privileges/empty/privilege-mapping/.dummy b/src/security-manager-tests/smack-privileges/empty/privilege-mapping/.dummy
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/security-manager-tests/smack-privileges/internet-only/privilege-mapping/priv-rules-default-template.smack b/src/security-manager-tests/smack-privileges/internet-only/privilege-mapping/priv-rules-default-template.smack
new file mode 100644 (file)
index 0000000..09c5be6
--- /dev/null
@@ -0,0 +1,2 @@
+~PROCESS~ ~PRIVILEGE~ w
+~PRIVILEGE~ ~PROCESS~ w
diff --git a/src/security-manager-tests/smack-privileges/internet-only/privilege-smack.list b/src/security-manager-tests/smack-privileges/internet-only/privilege-smack.list
new file mode 100644 (file)
index 0000000..933b073
--- /dev/null
@@ -0,0 +1 @@
+http://tizen.org/privilege/internet System::Privilege::Internet default
\ No newline at end of file
diff --git a/src/security-manager-tests/smack-privileges/malformed/privilege-mapping/priv-rules-default-template.smack b/src/security-manager-tests/smack-privileges/malformed/privilege-mapping/priv-rules-default-template.smack
new file mode 100644 (file)
index 0000000..09c5be6
--- /dev/null
@@ -0,0 +1,2 @@
+~PROCESS~ ~PRIVILEGE~ w
+~PRIVILEGE~ ~PROCESS~ w
diff --git a/src/security-manager-tests/smack-privileges/malformed/privilege-smack.list b/src/security-manager-tests/smack-privileges/malformed/privilege-smack.list
new file mode 100644 (file)
index 0000000..04ab381
--- /dev/null
@@ -0,0 +1,3 @@
+http://tizen.org/privilege/internet System::Privilege::Internet default
+http://tizen.org/privilege/camera System::Privilege::Camera the-fault
+http://tizen.org/privilege/camera System::Privilege::Camera
diff --git a/src/security-manager-tests/smack-privileges/multiple-privs/privilege-mapping/flawed-camera-template.smack b/src/security-manager-tests/smack-privileges/multiple-privs/privilege-mapping/flawed-camera-template.smack
new file mode 100644 (file)
index 0000000..fb35c52
--- /dev/null
@@ -0,0 +1,3 @@
+~PROCESS~ System::TEF r
+~PROCESS~ ~PRIVILEGE~ w
+~PRIVILEGE~ ~PROCESS~ w
diff --git a/src/security-manager-tests/smack-privileges/multiple-privs/privilege-mapping/priv-rules-default-template.smack b/src/security-manager-tests/smack-privileges/multiple-privs/privilege-mapping/priv-rules-default-template.smack
new file mode 100644 (file)
index 0000000..09c5be6
--- /dev/null
@@ -0,0 +1,2 @@
+~PROCESS~ ~PRIVILEGE~ w
+~PRIVILEGE~ ~PROCESS~ w
diff --git a/src/security-manager-tests/smack-privileges/multiple-privs/privilege-smack.list b/src/security-manager-tests/smack-privileges/multiple-privs/privilege-smack.list
new file mode 100644 (file)
index 0000000..8a0bc4f
--- /dev/null
@@ -0,0 +1,2 @@
+http://tizen.org/privilege/internet System::Privilege::Internet default
+http://tizen.org/privilege/camera System::Privilege::Camera flawed-camera-template.smack
index 8b7a7fc..c46e6e0 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
  *
  *    Licensed under the Apache License, Version 2.0 (the "License");
  *    you may not use this file except in compliance with the License.
@@ -28,7 +28,6 @@
 
 #include <cynara-admin.h>
 
-#include <app_install_helper.h>
 #include <cynara_test_admin.h>
 #include <dpl/test/test_runner.h>
 #include <label_generator.h>
 #include <tzplatform.h>
 #include <uds.h>
 #include <scoped_process_label.h>
+#include <scoped_app_launcher.h>
+#include <app_install_helper_ext.h>
+#include <privilege_names.h>
+#include <app_def_privilege.h>
 
 using namespace SecurityManagerTest;
-
-namespace {
-std::vector<std::string> merge(const std::vector<std::string> &one, const std::vector<std::string> &two) {
-    std::vector<std::string> sum;
-    sum.reserve(one.size() + two.size());
-    sum.insert(sum.end(), one.begin(), one.end());
-    sum.insert(sum.end(), two.begin(), two.end());
-    return sum;
-}
-}
+using namespace PrivilegeNames;
 
 RUNNER_TEST_GROUP_INIT(SECURITY_MANAGER)
 
 RUNNER_TEST(security_manager_01a_app_double_install_double_uninstall)
 {
-    AppInstallHelper app("sm_test_01a_app");
+    AppInstallHelperExt app("sm_test_01a_app");
     {
         ScopedInstaller appInstall(app);
-        check_app_after_install(app.getAppId(), app.getPkgId());
+        app.checkAfterInstall();
         {
             ScopedInstaller appInstall2(app);
-            check_app_after_install(app.getAppId(), app.getPkgId());
+            app.checkAfterInstall();
         }
-        check_app_after_uninstall(app.getAppId(), app.getPkgId());
+        app.checkAfterUninstall();
     }
 }
 
 RUNNER_TEST(security_manager_01b_app_double_install_wrong_pkg_id)
 {
-    AppInstallHelper app("sm_test_01b");
+    AppInstallHelperExt app("sm_test_01b");
     {
         ScopedInstaller appInstall(app);
 
@@ -86,17 +80,17 @@ RUNNER_TEST(security_manager_01b_app_double_install_wrong_pkg_id)
 
         Api::install(requestInst2, SECURITY_MANAGER_ERROR_INPUT_PARAM);
 
-        check_app_after_install(app.getAppId(), app.getPkgId());
+        app.checkAfterInstall();
     }
-    check_app_after_uninstall(app.getAppId(), app.getPkgId());
+    app.checkAfterUninstall();
 }
 
 RUNNER_TEST(security_manager_01c_app_uninstall_wrong_pkg_id)
 {
-    AppInstallHelper app("sm_test_01c");
+    AppInstallHelperExt app("sm_test_01c");
     ScopedInstaller appInstall(app);
 
-    check_app_after_install(app.getAppId(), app.getPkgId());
+    app.checkAfterInstall();
 
     InstallRequest requestUninst;
     requestUninst.setAppId(app.getAppId());
@@ -142,26 +136,20 @@ RUNNER_TEST(security_manager_01d_app_install_complicated_dir_tree)
     check_path(sharedRODir, getSharedROPathLabel());
 }
 
-RUNNER_TEST(security_manager_02_app_install_uninstall_full)
+RUNNER_CHILD_TEST(security_manager_02_app_install_uninstall_full)
 {
-    privileges_t defaultPrivs = {
-        "http://tizen.org/privilege/internal/device/audio",
-        "http://tizen.org/privilege/internal/device/display",
-        "http://tizen.org/privilege/internal/device/video"
-    };
-    privileges_t allowedPrivs = {
-        "http://tizen.org/privilege/camera",
-        "http://tizen.org/privilege/mediastorage"
-    };
-    privileges_t someDeniedPrivs = {
-        "http://tizen.org/privilege/internet",
-        "http://tizen.org/privilege/externalstorage"
+    const PrivilegeVector defaultPrivs = {
+        PRIV_INTERNAL_AUDIO,
+        PRIV_INTERNAL_DISPLAY,
+        PRIV_INTERNAL_VIDEO,
     };
+    const PrivilegeVector allowedPrivs = {PRIV_CAMERA, PRIV_MEDIASTORAGE};
+    const PrivilegeVector someDeniedPrivs = {PRIV_INTERNET, PRIV_EXTERNALSTORAGE};
 
-    privileges_t defaultAllowedPrivs = defaultPrivs;
+    PrivilegeVector defaultAllowedPrivs = defaultPrivs;
     defaultAllowedPrivs.insert(defaultAllowedPrivs.end(), allowedPrivs.begin(), allowedPrivs.end());
 
-    AppInstallHelper app("sm_test_02");
+    AppInstallHelperExt app("sm_test_02");
     app.createPrivateDir();
     app.createPrivateRODir();
     app.createPublicDir();
@@ -170,8 +158,11 @@ RUNNER_TEST(security_manager_02_app_install_uninstall_full)
     {
         ScopedInstaller appInstall(app);
 
-        check_app_after_install(app.getAppId(), app.getPkgId(),
-                                defaultAllowedPrivs, someDeniedPrivs);
+        app.checkAfterInstall();
+        app.checkDeniedPrivileges(someDeniedPrivs);
+        {
+            ScopedAppLauncher launcher(app, [&]{ app.checkGroupPrivileges(defaultAllowedPrivs); });
+        }
 
         check_path(app.getPrivateDir(), generatePathRWLabel(app.getPkgId()));
         check_path(app.getPrivateRODir(), generatePathROLabel(app.getPkgId()), false);
@@ -179,7 +170,39 @@ RUNNER_TEST(security_manager_02_app_install_uninstall_full)
         check_path(app.getSharedRODir(), getSharedROPathLabel());
     }
 
-    check_app_after_uninstall(app.getAppId(), app.getPkgId(), app.getPrivilegesNames());
+    app.checkAfterUninstall();
+}
+
+RUNNER_CHILD_TEST(security_manager_02a_set_process_groups)
+{
+    const PrivilegeVector defaultPrivs = {
+        PRIV_INTERNAL_AUDIO,
+        PRIV_INTERNAL_DISPLAY,
+        PRIV_INTERNAL_VIDEO,
+    };
+    const PrivilegeVector allowedPrivs = {PRIV_CAMERA, PRIV_MEDIASTORAGE};
+
+    auto defaultAllowedPrivs = defaultPrivs;
+    defaultAllowedPrivs.insert(defaultAllowedPrivs.end(), allowedPrivs.begin(), allowedPrivs.end());
+
+    AppInstallHelperExt app("sm_test_02a");
+    app.addPrivileges(allowedPrivs);
+    {
+        ScopedInstaller appInstall(app);
+
+        app.checkAfterInstall();
+
+        pid_t pid = fork();
+        RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "Fork failed");
+        if (pid != 0) {
+            waitPid(pid);
+        } else {
+            Api::setProcessGroups(app.getAppId());
+            app.checkGroupPrivileges(defaultAllowedPrivs);
+            exit(0);
+        }
+    }
+    app.checkAfterUninstall();
 }
 
 RUNNER_CHILD_TEST_SMACK(security_manager_03_set_label_from_appid)
@@ -242,58 +265,46 @@ RUNNER_CHILD_TEST_SMACK(security_manager_03_set_label_from_appid)
 
 RUNNER_CHILD_TEST(security_manager_04a_app_install_uninstall_by_app_user_for_self)
 {
-    const std::vector<std::string> allowedPrivs = {
-        "http://tizen.org/privilege/bluetooth",
-        "http://tizen.org/privilege/power"
-    };
-    const std::vector<std::string> someDeniedPrivs = {
-        "http://tizen.org/privilege/display",
-        "http://tizen.org/privilege/nfc"
-    };
+    const PrivilegeVector allowedPrivs = {PRIV_BLUETOOTH, PRIV_POWER};
+    const PrivilegeVector someDeniedPrivs = {PRIV_DISPLAY, PRIV_NFC};
 
     TemporaryTestUser testUser("sm_test_04a_user_name", GUM_USERTYPE_NORMAL);
     testUser.create();
 
-    AppInstallHelper app("sm_test_04a", testUser.getUid());
+    AppInstallHelperExt app("sm_test_04a", testUser.getUid());
     app.addPrivileges(allowedPrivs);
 
     RUNNER_ASSERT_ERRNO_MSG(drop_root_privileges(testUser.getUid(), testUser.getGid()) == 0,
                             "drop_root_privileges failed");
     {
         ScopedInstaller appInstall(app, false);
-        check_app_permissions(app.getAppId(), app.getPkgId(), testUser.getUidString(),
-                              allowedPrivs, someDeniedPrivs);
+        app.checkAfterInstall();
+        app.checkDeniedPrivileges(someDeniedPrivs);
     }
-    check_app_permissions(app.getAppId(), app.getPkgId(), testUser.getUidString(),
-                          {}, merge(allowedPrivs, someDeniedPrivs));
+    app.checkAfterUninstall();
+    app.checkDeniedPrivileges(someDeniedPrivs);
 }
 
 RUNNER_CHILD_TEST(security_manager_04b_app_install_by_root_for_app_user) {
-    const std::vector<std::string> allowedPrivs = {
-        "http://tizen.org/privilege/internet",
-        "http://tizen.org/privilege/led"
-    };
-    const std::vector<std::string> someDeniedPrivs = {
-        "http://tizen.org/privilege/location",
-        "http://tizen.org/privilege/notification"
-    };
+    const PrivilegeVector allowedPrivs = {PRIV_INTERNET, PRIV_LED};
+    const PrivilegeVector someDeniedPrivs = {PRIV_LOCATION, PRIV_NOTIFICATION};
 
     TemporaryTestUser testUser("sm_test_04b_user_name", GUM_USERTYPE_NORMAL);
     testUser.create();
 
-    AppInstallHelper app("sm_test_04b", testUser.getUid());
+    AppInstallHelperExt app("sm_test_04b", testUser.getUid());
     app.addPrivileges(allowedPrivs);
 
     {
         ScopedInstaller appInstall(app);
-        check_app_permissions(app.getAppId(), app.getPkgId(), testUser.getUidString(),
-                              allowedPrivs, someDeniedPrivs);
+        app.checkAfterInstall();
+        app.checkDeniedPrivileges(someDeniedPrivs);
 
         RUNNER_ASSERT_ERRNO_MSG(drop_root_privileges(testUser.getUid(), testUser.getGid()) == 0,
                                 "drop_root_privileges failed");
     }
-    check_app_permissions(app.getAppId(), app.getPkgId(), testUser.getUidString(),
-                          {}, merge(allowedPrivs, someDeniedPrivs));
+    app.checkAfterUninstall();
+    app.checkDeniedPrivileges(someDeniedPrivs);
 }
 
 RUNNER_CHILD_TEST(security_manager_05_drop_process_capabilities)
@@ -327,21 +338,15 @@ RUNNER_TEST(security_manager_06_install_app_offline)
     // TODO - check if app is uninstalled properly
 }
 
-RUNNER_TEST(security_manager_07a_user_add_app_install)
+RUNNER_CHILD_TEST(security_manager_07a_user_add_app_install)
 {
-    const std::vector<std::string> allowedPrivs = {
-        "http://tizen.org/privilege/internet",
-        "http://tizen.org/privilege/led"
-    };
-    const std::vector<std::string> someDeniedPrivs = {
-        "http://tizen.org/privilege/location",
-        "http://tizen.org/privilege/notification"
-    };
+    const PrivilegeVector allowedPrivs = {PRIV_INTERNET, PRIV_LED};
+    const PrivilegeVector someDeniedPrivs = {PRIV_LOCATION, PRIV_NOTIFICATION};
 
     TemporaryTestUser testUser("sm_test_07a_user_name", GUM_USERTYPE_NORMAL);
     testUser.create();
 
-    AppInstallHelper app("sm_test_07a", testUser.getUid());
+    AppInstallHelperExt app("sm_test_07a", testUser.getUid());
     app.addPrivileges(allowedPrivs);
 
     InstallRequest req;
@@ -352,16 +357,13 @@ RUNNER_TEST(security_manager_07a_user_add_app_install)
         req.addPrivilege(priv);
     }
     Api::install(req);
-
-    check_app_permissions(app.getAppId(), app.getPkgId(), testUser.getUidString(),
-                          allowedPrivs, someDeniedPrivs);
+    app.checkAfterInstall();
+    app.checkDeniedPrivileges(someDeniedPrivs);
 
     testUser.remove();
 
-    check_app_permissions(app.getAppId(), app.getPkgId(), testUser.getUidString(),
-                          {}, merge(allowedPrivs, someDeniedPrivs));
-
-    // TODO - check if app is uninstalled
+    app.checkAfterUninstall();
+    app.checkDeniedPrivileges(someDeniedPrivs);
 }
 
 RUNNER_TEST(security_manager_07b_user_add_offline)
@@ -374,22 +376,20 @@ RUNNER_TEST(security_manager_07b_user_add_offline)
     TemporaryTestUser testUser("sm_test_07b_user_name", GUM_USERTYPE_NORMAL, true);
     testUser.create();
 
-    AppInstallHelper app("sm_test_07b", testUser.getUid());
+    AppInstallHelperExt app("sm_test_07b", testUser.getUid());
     ScopedInstaller appInstall(app);
 
     serviceManager.startService();
-    check_app_after_install(app.getAppId(), app.getPkgId());
+    app.checkAfterInstall();
 
     testUser.remove();
-    check_app_after_uninstall(app.getAppId(), app.getPkgId());
+    app.checkAfterUninstall();
 }
 
 RUNNER_TEST(security_manager_08_user_double_add_double_remove)
 {
-    std::vector<std::string> somePrivs = {
-        "http://tizen.org/privilege/internet", "http://tizen.org/privilege/led",
-        "http://tizen.org/privilege/location", "http://tizen.org/privilege/notification"
-    };
+    const PrivilegeVector somePrivs = {PRIV_LED, PRIV_NOTIFICATION};
+
     // gumd
     TemporaryTestUser testUser("sm_test_08_user_name", GUM_USERTYPE_NORMAL);
     testUser.create();
@@ -400,17 +400,16 @@ RUNNER_TEST(security_manager_08_user_double_add_double_remove)
     addUserRequest.setUserType(SM_USER_TYPE_NORMAL);
     Api::addUser(addUserRequest);
 
-    AppInstallHelper app("sm_test_08", testUser.getUid());
+    AppInstallHelperExt app("sm_test_08", testUser.getUid());
     ScopedInstaller appInstall(app);
 
-    check_app_after_install(app.getAppId(), app.getPkgId());
-    check_app_permissions(app.getAppId(), app.getPkgId(), testUser.getUidString(), {}, somePrivs);
+    app.checkAfterInstall();
+    app.checkDeniedPrivileges(somePrivs);
 
     // gumd
     testUser.remove();
 
-    check_app_after_uninstall(app.getAppId(), app.getPkgId());
-    check_app_permissions(app.getAppId(), app.getPkgId(), testUser.getUidString(), {}, somePrivs);
+    app.checkAfterUninstall();
 
     // security-manager
     UserRequest deleteUserRequest;
@@ -420,168 +419,207 @@ RUNNER_TEST(security_manager_08_user_double_add_double_remove)
 
 RUNNER_TEST(security_manager_09_app_install_constraint_check)
 {
-    auto install = [](const TemporaryTestUser& user,
-                      const char *pkgId,
-                      const char *appId,
-                      const char *version,
-                      const char *author,
-                      bool isHybrid,
-                      enum lib_retcode expected,
-                      bool uninstall = true)
+    auto install = [](const AppInstallHelperExt& app, bool success)
     {
-        InstallRequest request;
-        request.setAppId(appId);
-        request.setPkgId(pkgId);
-        request.setAppTizenVersion(version);
-        request.setAuthorId(author);
-        request.setUid(user.getUid());
-        if (isHybrid)
-            request.setHybrid();
-        Api::install(request, expected);
-
-        if(expected == SECURITY_MANAGER_SUCCESS && uninstall) {
-            Api::uninstall(request);
-        }
+        auto expected = success ? SECURITY_MANAGER_SUCCESS : SECURITY_MANAGER_ERROR_INPUT_PARAM;
+        ScopedInstaller appInstall(app, true, expected);
+        if (success)
+            app.checkAfterInstall();
+        return appInstall;
     };
 
-    auto update = [](const TemporaryTestUser& user,
-                     const char *pkgId,
-                     const char *appId,
-                     const char *version,
-                     const char *author,
-                     bool isHybrid,
-                     enum lib_retcode expected,
-                     bool uninstall = true)
+    auto update = [](const AppInstallHelperExt& app)
     {
         InstallRequest request;
-        request.setAppId(appId);
-        request.setPkgId(pkgId);
-        request.setAppTizenVersion(version);
-        request.setAuthorId(author);
-        request.setUid(user.getUid());
-        if (isHybrid)
+        request.setAppId(app.getAppId());
+        request.setPkgId(app.getPkgId());
+        request.setAppTizenVersion(app.getVersion());
+        request.setAuthorId(app.getAuthor());
+        request.setUid(app.getUID());
+        if (app.getIsHybrid())
             request.setHybrid();
-        Api::update(request, expected);
-
-        if(expected == SECURITY_MANAGER_SUCCESS && uninstall) {
-            Api::uninstall(request);
-        }
+        Api::update(request);
     };
 
-    std::array<TemporaryTestUser, 2> users{
-        TemporaryTestUser{"sm_test_09_user_name_0", GUM_USERTYPE_NORMAL, false},
-        TemporaryTestUser{"sm_test_09_user_name_1", GUM_USERTYPE_NORMAL, false}
+    TemporaryTestUser users[] = {
+        {"sm_test_09_user_name_0", GUM_USERTYPE_NORMAL, false},
+        {"sm_test_09_user_name_1", GUM_USERTYPE_NORMAL, false}
     };
 
-    for(auto& gu : users)
+    for (auto& gu : users)
         gu.create();
 
-    const char *const pkgId[] =   {"sm_test_09_pkg_id_0",  "sm_test_09_pkg_id_1"};
-    const char *const appId[] =   {"sm_test_09_app_id_0",  "sm_test_09_app_id_1"};
-    const char *const version[] = {"sm_test_09_version_0", "sm_test_09_version_1"};
-    const char *const author[] =  {"sm_test_09_author_0",  "sm_test_09_author_1"};
+    const char *const pkgIdPrefix[] =   {"sm_test_09_0",            "sm_test_09_1"};
+    const char *const appIdPrefix[] =   {"sm_test_09_0",            "sm_test_09_1"};
+    const char *const version[] =       {"sm_test_09_0_version",    "sm_test_09_1_version"};
+    const char *const author[] =        {"sm_test_09_0_author",     "sm_test_09_1_author"};
     bool hybrid[] = {false, true};
 
-    // uid_0, pkg_0, app_0, version_0, author_0, not hybrid
-    install(users[0], pkgId[0], appId[0], version[0], author[0], hybrid[0], SECURITY_MANAGER_SUCCESS, false);
+    std::list<AppInstallHelperExt> apps;
+
+    auto make_helper = [&](size_t userIdx,
+                           size_t pkgIdx,
+                           size_t appIdx,
+                           size_t verIdx,
+                           size_t authorIdx,
+                           size_t hybridIdx) -> AppInstallHelperExt&
+    {
+        apps.emplace_back(appIdPrefix[appIdx], pkgIdPrefix[pkgIdx], users[userIdx].getUid());
+        apps.back().setAuthor(author[authorIdx]);
+        apps.back().setVersion(version[verIdx]);
+        if (hybrid[hybridIdx])
+            apps.back().setHybrid();
+        return apps.back();
+    };
+
+    // uid_0, pkg_0, app_0, version_0, author_0, not hybrid -> ok
+    auto &app000000 = make_helper(0, 0, 0, 0, 0, 0);
+    auto i1 = install(app000000, true);
+
     // uid_1, pkg_0, app_0, version_0, author_0, not hybrid -> ok (different uid)
-    install(users[1], pkgId[0], appId[0], version[0], author[0], hybrid[0], SECURITY_MANAGER_SUCCESS);
-    // uid_0, pkg_0, app_0, version_0, author_0, hybrid -> ok for update (different hybrid setting)
-    install(users[0], pkgId[0], appId[0], version[0], author[0], hybrid[1], SECURITY_MANAGER_ERROR_INPUT_PARAM);
-    update(users[0], pkgId[0], appId[0], version[0], author[0], hybrid[1], SECURITY_MANAGER_SUCCESS, false);
+    auto& app100000 = make_helper(1, 0, 0, 0, 0, 0);
+    install(app100000, true);
+
+    // uid_0, pkg_0, app_0, version_0, author_0, hybrid -> conflicts with existing non hybrid app
+    auto& app000001 = make_helper(0, 0, 0, 0, 0, 1);
+    install(app000001, false);
+
+    // uid_0, pkg_0, app_0, version_0, author_0, hybrid -> ok (app updated to hybrid)
+    update(app000001);
+
+    // uid_0, pkg_0, app_0, version_0, author_0, hybrid -> ok (app installed again)
+    auto i2 = install(app000001, true);
+
+    // uid_0, pkg_0, app_0, version_0, author_0, not hybrid -> conflicts with existing hybrid app
+    install(app000000, false);
+
     // uid_0, pkg_0, app_1, version_0, author_0, hybrid -> ok (new app id)
-    install(users[0], pkgId[0], appId[1], version[0], author[0], hybrid[1], SECURITY_MANAGER_SUCCESS, false);
-    // uid_1, pkg_0, app_0, version_0, author_0, hybrid -> ok (different hybrid setting)
-    install(users[1], pkgId[0], appId[0], version[0], author[0], hybrid[1], SECURITY_MANAGER_SUCCESS, false);
-    // uid_1, pkg_0, app_0, version_0, author_1, not hybrid -> fail (author of app_0 must be the same)
-    install(users[1], pkgId[0], appId[0], version[0], author[1], hybrid[0], SECURITY_MANAGER_ERROR_INPUT_PARAM);
-    // uid_1, pkg_0, app_0, version_1, author_0, not hybrid -> ok (version upgrade and different hybrid setting)
-    install(users[1], pkgId[0], appId[0], version[1], author[0], hybrid[0], SECURITY_MANAGER_ERROR_INPUT_PARAM);
-    update(users[1], pkgId[0], appId[0], version[1], author[0], hybrid[0], SECURITY_MANAGER_SUCCESS);
-    // uid_1, pkg_1, app_0, version_0, author_0, not hybrid -> fail (pkg of app_0 must be the same)
-    install(users[1], pkgId[1], appId[0], version[0], author[0], hybrid[0], SECURITY_MANAGER_ERROR_INPUT_PARAM);
-    // uid_0, pkg_0, app_0, version_0, author_0, not hybrid -> ok (the same app again)
-    install(users[0], pkgId[0], appId[0], version[0], author[0], hybrid[0], SECURITY_MANAGER_SUCCESS, false);
-    // uid_0, pkg_1, app_0, version_0, author_0, not hybrid -> fail (app_name + uid must be unique)
-    install(users[0], pkgId[1], appId[0], version[0], author[0], hybrid[0], SECURITY_MANAGER_ERROR_INPUT_PARAM);
-    // uid_0, pkg_0, app_0, version_0, author_1, not hybrid -> fail (app_name + uid must be unique)
-    install(users[0], pkgId[0], appId[0], version[0], author[1], hybrid[0], SECURITY_MANAGER_ERROR_INPUT_PARAM);
+    auto& app001001 = make_helper(0, 0, 1, 0, 0, 1);
+    auto i3 = install(app001001, true);
+
+    // uid_1, pkg_0, app_0, version_0, author_0, hybrid -> ok (hybrid, different uid)
+    auto& app100001 = make_helper(1, 0, 0, 0, 0, 1);
+    auto i4 = install(app100001, true);
+
+    // uid_1, pkg_0, app_0, version_0, author_1, not hybrid -> author of app_0 must be the same
+    auto& app100010 = make_helper(1, 0, 0, 0, 1, 0);
+    install(app100010, false);
+
+    // uid_1, pkg_0, app_0, version_1, author_0, not hybrid -> ok (app version and hybridity changed)
+    auto& app100100 = make_helper(1, 0, 0, 1, 0, 0);
+    update(app100100);
+
+    // uid_1, pkg_1, app_0, version_1, author_0, not hybrid -> pkg of app_0 must be the same
+    auto& app110100 = make_helper(1, 1, 0, 1, 0, 0);
+    install(app110100, false);
+
+    for (auto& gu : users)
+        gu.remove();
+
+    RUNNER_IGNORED_MSG("Disabled until hybridity update works properly for all users");
+    for (auto& app : apps)
+        app.checkAfterUninstall();
 }
 
 RUNNER_TEST(security_manager_09a_install_many_apps_in_single_request)
 {
-    const std::string pkgId = "sm_test_09a_pkg_id_0";
-    const std::vector<std::string> appIds = {"sm_test_09a_app_id_0", "sm_test_09a_app_id_1", "sm_test_09a_app_id_2"};
+    constexpr char pkgIdPrefix[] = "sm_test_09a";
+    const AppInstallHelperExt apps[] = {{"sm_test_09a_0", pkgIdPrefix},
+                                        {"sm_test_09a_1", pkgIdPrefix},
+                                        {"sm_test_09a_2", pkgIdPrefix}};
+    static_assert(sizeof(apps) > 0);
+
+    std::vector<std::string> appIds;
+    for (auto &app : apps)
+        appIds.push_back(app.getAppId());
 
     {
-        ScopedInstaller appsInstall(appIds, pkgId);
+        ScopedInstaller appsInstall(appIds, apps[0].getPkgId());
         // Installing many applications in single request
-        for (const auto &appId : appIds) {
-            check_app_after_install(appId, pkgId);
+        for (auto &app : apps) {
+            app.checkAfterInstall();
         }
     }
 
-    for (const auto &appId : appIds) {
-        check_app_after_uninstall(appId, pkgId);
+    for (auto &app : apps) {
+        app.checkAfterUninstall();
     }
 }
 
 RUNNER_TEST(security_manager_09b_install_many_apps_in_single_request_duplicated_ids)
 {
-    const std::string pkgId = "sm_test_09b_pkg_id_0";
-    const std::string appId = "sm_test_09b_app_id_0";
-
+    AppInstallHelperExt app("sm_test_09b");
     {
-        ScopedInstaller appsInstall({appId, appId}, pkgId);
-        check_app_after_install(appId, pkgId);
+        ScopedInstaller appsInstall({app.getAppId(), app.getAppId()}, app.getPkgId());
+        app.checkAfterInstall();
     }
 
-    check_app_after_uninstall(appId, pkgId);
+    app.checkAfterUninstall();
 }
 
 RUNNER_TEST(security_manager_09c_update_many_apps_in_single_request_hybrid_package)
 {
-    const std::vector<std::string> appIds = {"sm_test_09c_app_id_0", "sm_test_09c_app_id_1", "sm_test_09c_app_id_2"};
-    const std::string pkgId = "sm_test_09c_pkg_id_0";
+    constexpr char pkgIdPrefix[] = "sm_test_09c";
+    AppInstallHelperExt apps[] = {{"sm_test_09c_0", pkgIdPrefix},
+                                  {"sm_test_09c_1", pkgIdPrefix},
+                                  {"sm_test_09c_2", pkgIdPrefix}};
+    static_assert(sizeof(apps) > 0);
+
+    std::vector<std::string> appIds;
+    for (const auto &app : apps)
+        appIds.push_back(app.getAppId());
 
     {
-        ScopedInstaller appsInstall(appIds, pkgId);
+        ScopedInstaller appsInstall(appIds, apps[0].getPkgId());
         // Package is not hybrid, every app has same policy.
-        for (const auto &appId : appIds) {
-            check_app_after_install(appId, pkgId);
+        for (const auto &app : apps) {
+            app.checkAfterInstall();
         }
 
         // Updating package -- changing set of apps in package and setting hybrid mode
         InstallRequest updateRequest;
-        updateRequest.setPkgId(pkgId);
+        updateRequest.setPkgId(apps[0].getPkgId());
         updateRequest.setAppId(appIds[0]);
         updateRequest.nextApp();
         updateRequest.setAppId(appIds[1]);
         updateRequest.setHybrid();
 
         Api::update(updateRequest);
+
         // Package became hybrid, so every app has its own Smack label
-        check_app_after_install(appIds[0], pkgId, true);
-        check_app_after_install(appIds[1], pkgId, true);
+        for (auto &app : apps) {
+            app.setHybrid();
+        }
+        apps[0].checkAfterInstall();
+        apps[1].checkAfterInstall();
+
         // Package became hybrid properly,
         // so app not included in updated version of package was uninstalled.
-        check_app_after_uninstall(appIds[2], pkgId);
+        apps[2].checkAfterUninstall(false);
     }
 
-    for (const auto &appId : appIds) {
-        check_app_after_uninstall(appId, pkgId, true, true);
+    for (const auto &app : apps) {
+        app.checkAfterUninstall();
     }
 }
 
 RUNNER_TEST(security_manager_09d_uninstall_app_from_hybrid_package)
 {
-    const std::vector<std::string> appIds = {"sm_test_09d_app_id_0", "sm_test_09d_app_id_1", "sm_test_09d_app_id_2"};
-    const std::string pkgId = "sm_test_09d_pkg_id_0";
+    constexpr char pkgIdPrefix[] = "sm_test_09d";
+    AppInstallHelperExt apps[] = {{"sm_test_09d_0", pkgIdPrefix},
+                                  {"sm_test_09d_1", pkgIdPrefix},
+                                  {"sm_test_09d_2", pkgIdPrefix}};
+    static_assert(sizeof(apps) > 0);
+
+    std::vector<std::string> appIds;
+    for (const auto &app : apps)
+        appIds.push_back(app.getAppId());
+
     {
-        ScopedInstaller appsInstall(appIds, pkgId);
+        ScopedInstaller appsInstall(appIds, apps[0].getPkgId());
 
         InstallRequest updateRequest;
-        updateRequest.setPkgId(pkgId);
+        updateRequest.setPkgId(apps[0].getPkgId());
         for (unsigned int i = 0; i < appIds.size(); i++) {
             if (i > 0) {
                 updateRequest.nextApp();
@@ -592,31 +630,32 @@ RUNNER_TEST(security_manager_09d_uninstall_app_from_hybrid_package)
         Api::update(updateRequest);
 
         InstallRequest uninstRequest;
-        uninstRequest.setPkgId(pkgId);
+        uninstRequest.setPkgId(apps[0].getPkgId());
         uninstRequest.setAppId(appIds[0]);
         Api::uninstall(uninstRequest);
 
-        check_app_after_uninstall(appIds[0], pkgId, true);
+        for (auto &app : apps) {
+            app.setHybrid();
+        }
+        apps[0].checkAfterUninstall(false);
+    }
+    for (const auto &app : apps) {
+        app.checkAfterUninstall();
     }
 }
 
 RUNNER_CHILD_TEST(security_manager_10_app_has_privilege)
 {
-    const std::vector<std::string> allowedPrivs = {
-        "http://tizen.org/privilege/wifidirect",
-        "http://tizen.org/privilege/telephony"
-    };
-    const std::vector<std::string> someDeniedPrivs = {
-        "http://tizen.org/privilege/vpnservice",
-        "http://tizen.org/privilege/notification"
-    };
-    AppInstallHelper app("sm_test_10");
+    const PrivilegeVector allowedPrivs = {PRIV_WIFIDIRECT, PRIV_TELEPHONY};
+    const PrivilegeVector someDeniedPrivs = {PRIV_VPNSERVICE, PRIV_NOTIFICATION};
+
+    AppInstallHelperExt app("sm_test_10");
     app.addPrivileges(allowedPrivs);
     ScopedInstaller appInstall(app);
 
-    sm_app_has_privileges(app, allowedPrivs, 1);
+    app.checkAfterInstall();
+    app.checkDeniedPrivileges(someDeniedPrivs);
     // FIXME - all other existing privileges should be checked
-    sm_app_has_privileges(app, someDeniedPrivs, 0);
 }
 
 RUNNER_TEST_GROUP_INIT(SECURITY_MANAGER_POLICY)
@@ -651,40 +690,31 @@ RUNNER_TEST(security_manager_20_user_cynara_policy)
 
 RUNNER_CHILD_TEST(security_manager_21_security_manager_admin_deny_user_priv)
 {
-    const privileges_t adminRequiredPrivs = {
-        "http://tizen.org/privilege/notexist",
-        "http://tizen.org/privilege/internal/usermanagement"
-    };
-    const privileges_t manifestPrivs = {
-         "http://tizen.org/privilege/internet",
-         "http://tizen.org/privilege/datasharing"
-    };
-    const privileges_t allowedPrivsAfterChange = {"http://tizen.org/privilege/datasharing"};
-    const privileges_t deniedPrivsAfterChange = {"http://tizen.org/privilege/internet"};
+    const PrivilegeVector adminRequiredPrivs = {PRIV_NOTEXIST, PRIV_INTERNAL_USERMANAGEMENT};
+    const PrivilegeVector manifestPrivs = {PRIV_INTERNET, PRIV_DATASHARING};
+    const PrivilegeVector allowedPrivsAfterChange = {PRIV_DATASHARING};
+    const PrivilegeVector deniedPrivsAfterChange = {PRIV_INTERNET};
+
     TemporaryTestUser adminUser("sm_test_21_admin_user_name", GUM_USERTYPE_ADMIN, false);
     TemporaryTestUser normalUser("sm_test_21_normal_user_name", GUM_USERTYPE_NORMAL, false);
 
     adminUser.create();
     normalUser.create();
-    std::string childUidStr = normalUser.getUidString();
 
     AppInstallHelper adminApp("sm_test_21_admin", adminUser.getUid());
     adminApp.addPrivileges(adminRequiredPrivs);
     ScopedInstaller adminAppInstall(adminApp);
 
-    AppInstallHelper normalApp("sm_test_21_normal", normalUser.getUid());
+    AppInstallHelperExt normalApp("sm_test_21_normal", normalUser.getUid());
     normalApp.addPrivileges(manifestPrivs);
     ScopedInstaller normalAppInstall(normalApp);
-
-    check_app_permissions(normalApp.getAppId(), normalApp.getPkgId(), childUidStr,
-                          manifestPrivs, {});
+    normalApp.checkAfterInstall();
 
     pid_t pid = fork();
     RUNNER_ASSERT_MSG(pid >= 0, "fork failed");
     if (pid != 0) { //parent process
         waitPid(pid);
-        check_app_permissions(normalApp.getAppId(), normalApp.getPkgId(), childUidStr,
-                              allowedPrivsAfterChange, deniedPrivsAfterChange);
+        normalApp.checkPrivileges(allowedPrivsAfterChange, deniedPrivsAfterChange);
     } else {
         Api::setProcessLabel(adminApp.getAppId());
         RUNNER_ASSERT_ERRNO_MSG(drop_root_privileges(adminUser.getUid(),adminUser.getGid()) == 0,
@@ -693,7 +723,7 @@ RUNNER_CHILD_TEST(security_manager_21_security_manager_admin_deny_user_priv)
         PolicyRequest addPolicyReq;
         for (auto &deniedPriv : deniedPrivsAfterChange) {
             PolicyEntry entry(SECURITY_MANAGER_ANY, normalUser.getUidString(), deniedPriv);
-            entry.setMaxLevel("Deny");
+            entry.setMaxLevel(PolicyEntry::LEVEL_DENY);
             addPolicyReq.addEntry(entry);
         }
         Api::sendPolicy(addPolicyReq);
@@ -819,16 +849,16 @@ RUNNER_TEST_GROUP_INIT(SECURITY_MANAGER_INSTALL_TYPE)
 
 RUNNER_TEST(security_manager_25a_global_user_set_install_type_global)
 {
-    AppInstallHelper app("sm_test_25a");
+    AppInstallHelperExt app("sm_test_25a");
     app.setInstallType(SM_APP_INSTALL_GLOBAL);
     {
         ScopedInstaller appInstall(app);
 
-        check_app_after_install(app.getAppId(), app.getPkgId());
+        app.checkAfterInstall();
     }
 
     // Check records in the security-manager database
-    check_app_after_uninstall(app.getAppId(), app.getPkgId());
+    app.checkAfterUninstall();
 }
 
 RUNNER_TEST(security_manager_25b_global_user_set_install_type_local)
@@ -845,13 +875,13 @@ RUNNER_TEST(security_manager_25b_global_user_set_install_type_local)
 
 RUNNER_TEST(security_manager_25c_global_user_set_install_type_preloaded)
 {
-    AppInstallHelper app("sm_test_25c");
+    AppInstallHelperExt app("sm_test_25c");
     app.setInstallType(SM_APP_INSTALL_PRELOADED);
     {
         ScopedInstaller appInstall(app);
-        check_app_after_install(app.getAppId(), app.getPkgId());
+        app.checkAfterInstall();
     }
-    check_app_after_uninstall(app.getAppId(), app.getPkgId());
+    app.checkAfterUninstall();
 }
 
 RUNNER_TEST(security_manager_25d_local_user_set_install_type_invalid)
@@ -907,21 +937,13 @@ RUNNER_CHILD_TEST(security_manager_25f_unprivileged_install_type_preloaded)
 
 RUNNER_CHILD_TEST(security_manager_25g_local_user_set_install_type_local)
 {
-    std::vector<std::string> allowedPrivs = {
-        "http://tizen.org/privilege/volume.set",
-        "http://tizen.org/privilege/systemmonitor",
-        "http://tizen.org/privilege/internet"
-    };
-    std::vector<std::string> someDeniedPrivs = {
-        "http://tizen.org/privilege/push",
-        "http://tizen.org/privilege/power",
-        "http://tizen.org/privilege/notification"
-    };
+    const PrivilegeVector allowedPrivs = {PRIV_VOLUME_SET, PRIV_SYSTEMMONITOR, PRIV_INTERNET};
+    const PrivilegeVector someDeniedPrivs = {PRIV_PUSH, PRIV_POWER, PRIV_NOTIFICATION};
 
     TemporaryTestUser testUser("sm_test_25g_user_name", GUM_USERTYPE_NORMAL);
     testUser.create();
 
-    AppInstallHelper app("sm_test_25g", testUser.getUid());
+    AppInstallHelperExt app("sm_test_25g", testUser.getUid());
     app.createPrivateDir();
     app.setInstallType(SM_APP_INSTALL_LOCAL);
     app.addPrivileges(allowedPrivs);
@@ -930,13 +952,10 @@ RUNNER_CHILD_TEST(security_manager_25g_local_user_set_install_type_local)
                             "drop_root_privileges failed");
     {
         ScopedInstaller appInstall(app);
-        check_app_permissions(app.getAppId(), app.getPkgId(), testUser.getUidString(),
-                              allowedPrivs, someDeniedPrivs);
-
+        app.checkAfterInstall();
+        app.checkDeniedPrivileges(someDeniedPrivs);
     }
-    check_app_permissions(app.getAppId(), app.getPkgId(), testUser.getUidString(),
-                          {}, merge(allowedPrivs, someDeniedPrivs));
-    // TODO - check if app is properly uninstalled
+    app.checkAfterUninstall();
 }
 
 RUNNER_CHILD_TEST(security_manager_25h_local_path_global_install)
@@ -998,30 +1017,23 @@ RUNNER_CHILD_TEST(security_manager_26_hybrid_pkg_uninstall_artifacts_check)
     TemporaryTestUser testUser("sm_test_26_user_name", GUM_USERTYPE_NORMAL);
     testUser.create();
 
-    const std::vector<std::string> allowedPrivs = {
-        "http://tizen.org/privilege/wifidirect",
-        "http://tizen.org/privilege/telephony"
-    };
+    const PrivilegeVector allowedPrivs = {PRIV_WIFIDIRECT, PRIV_TELEPHONY};
 
-    AppInstallHelper app1("sm_test_26_1", "sm_test_26", testUser.getUid());
+    AppInstallHelperExt app1("sm_test_26_1", "sm_test_26", testUser.getUid());
     app1.addPrivileges(allowedPrivs);
     app1.setHybrid();
 
-    AppInstallHelper app2("sm_test_26_2", "sm_test_26", testUser.getUid());
+    AppInstallHelperExt app2("sm_test_26_2", "sm_test_26", testUser.getUid());
     app2.addPrivileges(allowedPrivs);
     app2.setHybrid();
 
     {
         ScopedInstaller appInstall1(app1);
         ScopedInstaller appInstall2(app2);
-        check_app_permissions(app1.getAppId(), app1.getPkgId(), testUser.getUidString(),
-                              allowedPrivs, {}, app1.getIsHybrid());
-        check_app_permissions(app2.getAppId(), app2.getPkgId(), testUser.getUidString(),
-                              allowedPrivs, {}, app2.getIsHybrid());
+        app1.checkAfterInstall();
+        app2.checkAfterInstall();
 
     }
-    check_app_permissions(app1.getAppId(), app1.getPkgId(), testUser.getUidString(),
-                          {}, allowedPrivs, app1.getIsHybrid());
-    check_app_permissions(app2.getAppId(), app2.getPkgId(), testUser.getUidString(),
-                          {}, allowedPrivs, app2.getIsHybrid());
+    app1.checkAfterUninstall(false);
+    app2.checkAfterUninstall();
 }
index a72a7d6..2e8965c 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.
 #include <tzplatform.h>
 #include <app_install_helper.h>
 #include <scoped_installer.h>
+#include <privilege_names.h>
 
 RUNNER_TEST_GROUP_INIT(SECURITY_MANAGER_APP_DEFINED_PRIVILEGE)
 
 using namespace SecurityManagerTest;
+using namespace PrivilegeNames;
 
 RUNNER_CHILD_TEST(app_defined_01_global_install_untrusted)
 {
@@ -544,7 +546,7 @@ RUNNER_CHILD_TEST(app_defined_09_add_get_client_license)
 RUNNER_CHILD_TEST(app_defined_10_check_system_privileges)
 {
     const std::string providerAppId = "app_def_09_provider";
-    const Privilege privilege("http://tizen.org/privilege/internet", Privilege::UNTRUSTED);
+    const Privilege privilege(PRIV_INTERNET, Privilege::UNTRUSTED);
 
     InstallRequest requestInst;
     requestInst.setAppId(providerAppId);
@@ -608,4 +610,4 @@ RUNNER_CHILD_TEST(app_defined_12_invalid_common_name)
 
     CynaraTestClient::Client cynara;
     cynara.check(clientLabel, session, ownerId, clientPrivilegeLicense, CYNARA_API_ACCESS_DENIED);
-}
\ No newline at end of file
+}
index bb3ab94..27267f8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2018 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2016-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.
 
 #include <dpl/test/test_runner.h>
 #include <dpl/test/test_runner_child.h>
+#include <privilege_names.h>
+
+using namespace PrivilegeNames;
 
 const PrivilegeVector TEST_PRIVACY_PRIVILEGES = {
-    Privilege("http://tizen.org/privilege/callhistory.read", Privilege::PRIVACY),
-    Privilege("http://tizen.org/privilege/account.read", Privilege::PRIVACY),
-    Privilege("http://tizen.org/privilege/healthinfo", Privilege::PRIVACY) };
+    Privilege(PRIV_CALLHISTORY_READ, Privilege::PRIVACY),
+    Privilege(PRIV_ACCOUNT_READ, Privilege::PRIVACY),
+    Privilege(PRIV_HEALTHINFO, Privilege::PRIVACY) };
 
 using namespace SecurityManagerTest;
 
index 90099e2..152f4b5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2016-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.
 #include <sm_policy_request.h>
 #include <sm_user_request.h>
 #include <temp_test_user.h>
+#include <privilege_names.h>
 
 #include <security-manager.h>
 
 using namespace SecurityManagerTest;
+using namespace PrivilegeNames;
 
 RUNNER_TEST_GROUP_INIT(SECURITY_MANAGER_NSS_PLUGIN)
 
-RUNNER_CHILD_TEST(nss_01_unknown_user) {
+RUNNER_CHILD_TEST(nss_01_normal_user_without_inter_daemon_groups) {
     const std::string newUserName = "nss_01_user";
-    PolicyConfiguration pc;
-    TemporaryTestUser testUser(newUserName, GUM_USERTYPE_NORMAL, false);
-    testUser.create();
-
-    auto gidVector = pc.getGid();
-
-    RUNNER_ASSERT_MSG(0 == initgroups(newUserName.c_str(), 0), "Init groups failed");
-
-    gid_t list[64];
-    int grsize = getgroups(64, list);
-    size_t counter = 0;
-
-    for (size_t i=0; i<gidVector.size(); ++i) {
-        for (int j=0; j<grsize; ++j)
-            if(list[j] == gidVector[i]) {
-                counter++;
-                break;
-            }
-    }
-
-    RUNNER_ASSERT_MSG(gidVector.size() == counter,
-        "Process should have all groups related with privileges but it have only " <<
-        counter << " of " << gidVector.size() << " required groups");
-}
-
-RUNNER_CHILD_TEST(nss_02_normal_user_all_priv) {
-    const std::string newUserName = "nss_02_user";
-    PolicyConfiguration pc;
     TemporaryTestUser testUser(newUserName, GUM_USERTYPE_NORMAL, false);
     testUser.create();
 
-    auto gidVector = pc.getUserGid(PolicyConfiguration::NORMAL);
-
     UserRequest addUserRequest;
     addUserRequest.setUid(testUser.getUid());
     addUserRequest.setUserType(SM_USER_TYPE_NORMAL);
@@ -77,79 +49,55 @@ RUNNER_CHILD_TEST(nss_02_normal_user_all_priv) {
 
     RUNNER_ASSERT_MSG(0 == initgroups(newUserName.c_str(), 0), "Init groups failed");
 
-    gid_t list[64];
-    int grsize = getgroups(64, list);
-    size_t counter = 0;
+    gid_t list[NGROUPS_MAX + 1];
+    int grsize = getgroups(NGROUPS_MAX + 1, list);
 
-    for (size_t i=0; i<gidVector.size(); ++i) {
-        for (int j=0; j<grsize; ++j)
-            if(list[j] == gidVector[i]) {
-                counter++;
-                break;
-            }
+    PolicyConfiguration pc;
+    auto sysdGidVec = pc.groupToGid(pc.privToGroup(pc.getSystemdManagedPrivs()));
+    auto allPrivGids = pc.getGid();
+    unsigned int privGidsOther = 0;
+    for (int i = 0; i < grsize; ++i) {
+        RUNNER_ASSERT_MSG(std::find(sysdGidVec.begin(), sysdGidVec.end(), list[i]) == sysdGidVec.end() , "Process should not get gid " << list[i]);
+        if (std::find(allPrivGids.begin(), allPrivGids.end(), list[i]) != allPrivGids.end())
+            ++privGidsOther;
     }
 
-    RUNNER_ASSERT_MSG(gidVector.size() == counter,
-        "Process should have all groups related with privileges but it have only " <<
-        counter << " of " << gidVector.size() << " required groups");
+    RUNNER_ASSERT_MSG(privGidsOther + sysdGidVec.size() == allPrivGids.size(), "Improper GID setup for process, has priv_*: " <<
+                      privGidsOther << ", systemd managed all: " << sysdGidVec.size() << " , all: " << allPrivGids.size() );
 }
 
-RUNNER_CHILD_TEST(nss_03_normal_user_without_camera) {
-    const std::string newUserName = "nss_03_user";
-    TemporaryTestUser testUser(newUserName, GUM_USERTYPE_NORMAL, false);
+RUNNER_CHILD_TEST(nss_02_guest_user_without_inter_daemon_groups) {
+    const std::string newUserName = "nss_02_user";
+    TemporaryTestUser testUser(newUserName, GUM_USERTYPE_GUEST, false);
     testUser.create();
-    gid_t cameraPrivId = nameToGid("priv_camera");
 
     UserRequest addUserRequest;
     addUserRequest.setUid(testUser.getUid());
-    addUserRequest.setUserType(SM_USER_TYPE_NORMAL);
+    addUserRequest.setUserType(SM_USER_TYPE_GUEST);
     Api::addUser(addUserRequest);
 
-    PolicyRequest policyRequest;
-    PolicyEntry entry(
-        SECURITY_MANAGER_ANY,
-        std::to_string(static_cast<int>(testUser.getUid())),
-        "http://tizen.org/privilege/camera");
-    entry.setMaxLevel("Deny");
-    policyRequest.addEntry(entry);
-    Api::sendPolicy(policyRequest);
-
     RUNNER_ASSERT_MSG(0 == initgroups(newUserName.c_str(), 0), "Init groups failed");
 
-    gid_t list[64];
-    int grsize = getgroups(64, list);
-    size_t counter = 0;
-
-    for (int i=0; i<grsize; ++i) {
-        if (list[i] == cameraPrivId) {
-            counter++;
-            break;
-        }
-    }
-
-    RUNNER_ASSERT_MSG(0 == counter, "Process should not have priv_camera group");
+    gid_t list[NGROUPS_MAX + 1];
+    int grsize = getgroups(NGROUPS_MAX + 1, list);
 
     PolicyConfiguration pc;
-    auto gidVector = pc.getUserGid(PolicyConfiguration::NORMAL);
-    gidVector.erase(
-        std::remove_if(gidVector.begin(), gidVector.end(), [=](gid_t g) { return g == cameraPrivId; }),
-        gidVector.end());
-
-    for (size_t i=0; i<gidVector.size(); ++i) {
-        for (int j=0; j<grsize; ++j)
-            if(list[j] == gidVector[i]) {
-                counter++;
-                break;
-            }
+    auto sysdGidVec = pc.groupToGid(pc.privToGroup(pc.getSystemdManagedPrivs()));
+    auto allPrivGids = pc.getGid();
+    unsigned int privGidsOther = 0;
+    for (int i = 0; i < grsize; ++i) {
+        RUNNER_ASSERT_MSG(std::find(sysdGidVec.begin(), sysdGidVec.end(), list[i]) == sysdGidVec.end() , "Process should not get gid " << list[i]);
+        if (std::find(allPrivGids.begin(), allPrivGids.end(), list[i]) != allPrivGids.end())
+            ++privGidsOther;
     }
 
-    RUNNER_ASSERT_MSG(gidVector.size() == counter,
-        "Process should have all groups related with privileges but it have only " <<
-        counter << " of " << gidVector.size() << " required groups");
+    RUNNER_ASSERT_MSG(privGidsOther + sysdGidVec.size() == allPrivGids.size(), "Improper GID setup for process, has priv_*: " <<
+                      privGidsOther << ", systemd managed all: " << sysdGidVec.size() << " , all: " << allPrivGids.size() );
 }
 
-RUNNER_CHILD_TEST(nss_04_guest_user) {
-    const std::string newUserName = "nss_04_user";
+
+RUNNER_CHILD_TEST(nss_03_guest_user_without_inter_daemon_groups_unaffected_by_cynara) {
+    const std::string newUserName = "nss_03_user";
     TemporaryTestUser testUser(newUserName, GUM_USERTYPE_GUEST, false);
     testUser.create();
 
@@ -158,26 +106,30 @@ RUNNER_CHILD_TEST(nss_04_guest_user) {
     addUserRequest.setUserType(SM_USER_TYPE_GUEST);
     Api::addUser(addUserRequest);
 
+    // Removing one more privilege from policy (that has GID associated), which should not affect nss daemon groups
+    PolicyRequest policyRequest;
+
+    PolicyEntry entry(SECURITY_MANAGER_ANY, testUser.getUidString(), PRIV_CAMERA);
+    entry.setMaxLevel(PolicyEntry::LEVEL_DENY);
+
+    policyRequest.addEntry(entry);
+    Api::sendPolicy(policyRequest);
+
     RUNNER_ASSERT_MSG(0 == initgroups(newUserName.c_str(), 0), "Init groups failed");
 
-    gid_t list[64];
-    int grsize = getgroups(64, list);
-    size_t counter = 0;
+    gid_t list[NGROUPS_MAX + 1];
+    int grsize = getgroups(NGROUPS_MAX + 1, list);
 
     PolicyConfiguration pc;
-    auto gidVector = pc.getUserGid(PolicyConfiguration::GUEST);
-
-    for (size_t i=0; i<gidVector.size(); ++i) {
-        for (int j=0; j<grsize; ++j)
-            if(list[j] == gidVector[i]) {
-                counter++;
-                break;
-            }
+    auto sysdGidVec = pc.groupToGid(pc.privToGroup(pc.getSystemdManagedPrivs()));
+    auto allPrivGids = pc.getGid();
+    unsigned int privGidsOther = 0;
+    for (int i = 0; i < grsize; ++i) {
+        RUNNER_ASSERT_MSG(std::find(sysdGidVec.begin(), sysdGidVec.end(), list[i]) == sysdGidVec.end() , "Process should not get gid " << list[i]);
+        if (std::find(allPrivGids.begin(), allPrivGids.end(), list[i]) != allPrivGids.end())
+            ++privGidsOther;
     }
 
-    RUNNER_ASSERT_MSG(gidVector.size() == counter,
-        "Process should have all groups related with privileges but it have only " <<
-        counter << " of " << gidVector.size() << " required groups");
+    RUNNER_ASSERT_MSG(privGidsOther + sysdGidVec.size() == allPrivGids.size(), "Improper GID setup for process, has priv_*: " <<
+                      privGidsOther << ", systemd managed all: " << sysdGidVec.size() << " , all: " << allPrivGids.size() );
 }
-
-
index 9ff9179..4ad16d4 100644 (file)
 #include <sm_commons.h>
 #include <memory.h>
 #include <tests_common.h>
+#include <privilege_names.h>
 
 using namespace SecurityManagerTest;
+using namespace PrivilegeNames;
 
 namespace {
 bool finish = false;
@@ -45,9 +47,6 @@ const size_t THREADS = 10;
 
 const std::string APP_TEST_USER = "app_test_user";
 
-const std::string EXTERNAL_STORAGE_PRIVILEGE = "http://tizen.org/privilege/externalstorage";
-const std::string MEDIA_STORAGE_PRIVILEGE = "http://tizen.org/privilege/mediastorage";
-
 const std::string ACCESS_DENIED_DIR_PATH = "/usr/share/security-manager/dummy";
 const std::string EXTERNAL_STORAGE_DIR_PATH = "/opt/media";
 const std::string MEDIA_STORAGE_RW_DIR_PATH = "/opt/usr/media";
@@ -235,7 +234,7 @@ RUNNER_CHILD_TEST(security_manager_101_create_namespace_test)
         synchPipe.claimChildEp();
         synchPipe.wait();
 
-        std::string appBindPath = std::string("/var/run/user/") + std::to_string(tmpUser.getUid())
+        std::string appBindPath = std::string("/var/run/user/") + tmpUser.getUidString()
                                   + "/apps/" + app.generateAppLabel() + "/" + std::to_string(pid);
         std::string appProcPath = std::string("/proc/") + std::to_string(pid) + "/ns/mnt";
         std::string launcherProcPath = std::string("/proc/") + std::to_string(getpid()) + "/ns/mnt";
@@ -307,8 +306,7 @@ RUNNER_CHILD_TEST(security_manager_103_policy_change_test)
     tmpUser.create();
 
     AppInstallHelper app("app103", tmpUser.getUid());
-    app.addPrivilege(EXTERNAL_STORAGE_PRIVILEGE);
-    app.addPrivilege(MEDIA_STORAGE_PRIVILEGE);
+    app.addPrivileges({PRIV_EXTERNALSTORAGE, PRIV_MEDIASTORAGE});
     ScopedInstaller appInstall(app);
 
     SynchronizationPipe synchPipe;
@@ -335,12 +333,12 @@ RUNNER_CHILD_TEST(security_manager_103_policy_change_test)
         RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
 
         PolicyRequest policyRequest;
-        PolicyEntry policyEntry(app.getAppId(), std::to_string(tmpUser.getUid()), EXTERNAL_STORAGE_PRIVILEGE);
-        policyEntry.setLevel("Deny");
+        PolicyEntry policyEntry(app.getAppId(), tmpUser.getUidString(), PRIV_EXTERNALSTORAGE);
+        policyEntry.setLevel(PolicyEntry::LEVEL_DENY);
         policyRequest.addEntry(policyEntry);
 
-        policyEntry = PolicyEntry(app.getAppId(), std::to_string(tmpUser.getUid()), MEDIA_STORAGE_PRIVILEGE);
-        policyEntry.setLevel("Deny");
+        policyEntry = PolicyEntry(app.getAppId(), tmpUser.getUidString(), PRIV_MEDIASTORAGE);
+        policyEntry.setLevel(PolicyEntry::LEVEL_DENY);
         policyRequest.addEntry(policyEntry);
         Api::sendPolicy(policyRequest);
 
@@ -351,12 +349,12 @@ RUNNER_CHILD_TEST(security_manager_103_policy_change_test)
         result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RO_DIR_PATH, pid);
         RUNNER_ASSERT_ERRNO_MSG(result == true, "path is not bound");
 
-        policyEntry = PolicyEntry(app.getAppId(),  std::to_string(tmpUser.getUid()), EXTERNAL_STORAGE_PRIVILEGE);
-        policyEntry.setLevel("Allow");
+        policyEntry = PolicyEntry(app.getAppId(), tmpUser.getUidString(), PRIV_EXTERNALSTORAGE);
+        policyEntry.setLevel(PolicyEntry::LEVEL_ALLOW);
         policyRequest.addEntry(policyEntry);
 
-        policyEntry = PolicyEntry(app.getAppId(),  std::to_string(tmpUser.getUid()), MEDIA_STORAGE_PRIVILEGE);
-        policyEntry.setLevel("Allow");
+        policyEntry = PolicyEntry(app.getAppId(), tmpUser.getUidString(), PRIV_MEDIASTORAGE);
+        policyEntry.setLevel(PolicyEntry::LEVEL_ALLOW);
         policyRequest.addEntry(policyEntry);
         Api::sendPolicy(policyRequest);
 
@@ -373,6 +371,45 @@ RUNNER_CHILD_TEST(security_manager_103_policy_change_test)
     }
 }
 
+RUNNER_CHILD_TEST(security_manager_104_policy_change_kill_app_test)
+{
+    TemporaryTestUser tmpUser(APP_TEST_USER, GUM_USERTYPE_NORMAL, false);
+    tmpUser.create();
+
+    AppInstallHelper app("app104", tmpUser.getUid());
+    app.addPrivileges({PRIV_EXTERNALSTORAGE, PRIV_MEDIASTORAGE});
+    ScopedInstaller appInstall(app);
+
+    SynchronizationPipe synchPipe;
+    pid_t pid = fork();
+    RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "Fork failed");
+    if (pid == 0) {
+        synchPipe.claimParentEp();
+        try {
+            RUNNER_ASSERT_ERRNO_MSG(setLauncherSecurityAttributes(tmpUser) == 0, "launcher failed");
+            Api::prepareAppCandidate();
+            Api::prepareApp(app.getAppId());
+        } catch (...) {
+            synchPipe.post();
+            throw;
+        }
+        synchPipe.post();
+        exit(0);
+    } else {
+        synchPipe.claimChildEp();
+        synchPipe.wait();
+
+        PolicyRequest policyRequest;
+        PolicyEntry policyEntry(app.getAppId(), tmpUser.getUidString(), PRIV_EXTERNALSTORAGE);
+        policyEntry.setLevel(PolicyEntry::LEVEL_DENY);
+        policyRequest.addEntry(policyEntry);
+        Api::sendPolicy(policyRequest);
+
+        waitPid(pid);
+        Api::cleanupApp(app.getAppId(), tmpUser.getUid(), pid);
+    }
+}
+
 namespace {
 class Timestamp {
     uint64_t _;
@@ -469,10 +506,7 @@ RUNNER_TEST(security_manager_200_prepare_app_perf)
     for (int i = 0; i < nAppsMax; i++) {
         apps.emplace_back(App{AppInstallHelper("app200_" + std::to_string(i), uid), 0});
         auto &hlp = apps.back().hlp;
-        for (const auto &p : { EXTERNAL_STORAGE_PRIVILEGE, MEDIA_STORAGE_PRIVILEGE,
-                std::string("http://tizen.org/privilege/camera"),
-                std::string("http://tizen.org/privilege/internet") })
-            hlp.addPrivilege(p);
+        hlp.addPrivileges({PRIV_EXTERNALSTORAGE, PRIV_MEDIASTORAGE, PRIV_CAMERA, PRIV_INTERNET});
         hlp.createSharedRODir();
         appInstalls.emplace_back(ScopedInstaller(hlp));
     }
index c354041..ac72b73 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2018 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2016-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.
 #include <synchronization_pipe.h>
 #include <temp_test_user.h>
 #include <tests_common.h>
+#include <privilege_names.h>
+#include <app_def_privilege.h>
 
 using namespace SecurityManagerTest;
+using namespace PrivilegeNames;
 namespace {
 struct UserInfo {
     std::string userName;
@@ -47,50 +50,29 @@ struct UserInfo {
 };
 
 // Privileges required for having permission to self/admin get/set policies.
-const std::string SELF_PRIVILEGE = "http://tizen.org/privilege/notexist";
-const std::string ADMIN_PRIVILEGE = "http://tizen.org/privilege/internal/usermanagement";
-
-typedef std::vector<std::string> Privileges;
-const std::vector<Privileges> TEST_PRIVILEGES = {
-    {
-        "http://tizen.org/privilege/internet",
-        "http://tizen.org/privilege/display"
-    },
-    {
-        "http://tizen.org/privilege/telephony",
-        "http://tizen.org/privilege/datasharing"
-    },
-    {
-        "http://tizen.org/privilege/content.write",
-        "http://tizen.org/privilege/led",
-        "http://tizen.org/privilege/email"
-    },
-    {
-        "http://tizen.org/privilege/led",
-        "http://tizen.org/privilege/email",
-        "http://tizen.org/privilege/telephony",
-        "http://tizen.org/privilege/datasharing"
-    },
-    {
-        "http://tizen.org/privilege/internet",
-        "http://tizen.org/privilege/display",
-        "http://tizen.org/privilege/led",
-        "http://tizen.org/privilege/email"
-    }
+const std::string& SELF_PRIVILEGE = PRIV_NOTEXIST;
+const std::string& ADMIN_PRIVILEGE = PRIV_INTERNAL_USERMANAGEMENT;
+
+const std::vector<PrivilegeVector> TEST_PRIVILEGES = {
+    {PRIV_INTERNET, PRIV_DISPLAY},
+    {PRIV_TELEPHONY, PRIV_DATASHARING},
+    {PRIV_CONTENT_WRITE, PRIV_LED, PRIV_EMAIL},
+    {PRIV_LED, PRIV_EMAIL, PRIV_TELEPHONY, PRIV_DATASHARING},
+    {PRIV_INTERNET, PRIV_DISPLAY, PRIV_LED, PRIV_EMAIL}
 };
 
 const PrivilegeVector TEST_PRIVACY_PRIVILEGES[] = {
     {
-        Privilege("http://tizen.org/privilege/telephony"),
-        Privilege("http://tizen.org/privilege/led"),
-        Privilege("http://tizen.org/privilege/callhistory.read", Privilege::PRIVACY),
-        Privilege("http://tizen.org/privilege/account.read", Privilege::PRIVACY),
-        Privilege("http://tizen.org/privilege/healthinfo", Privilege::PRIVACY),
+        Privilege(PRIV_TELEPHONY),
+        Privilege(PRIV_LED),
+        Privilege(PRIV_CALLHISTORY_READ, Privilege::PRIVACY),
+        Privilege(PRIV_ACCOUNT_READ, Privilege::PRIVACY),
+        Privilege(PRIV_HEALTHINFO, Privilege::PRIVACY),
     },
     {
-        Privilege("http://tizen.org/privilege/telephony"),
-        Privilege("http://tizen.org/privilege/led"),
-        Privilege("http://tizen.org/privilege/callhistory.read", Privilege::PRIVACY),
+        Privilege(PRIV_TELEPHONY),
+        Privilege(PRIV_LED),
+        Privilege(PRIV_CALLHISTORY_READ, Privilege::PRIVACY),
     }
 };
 
@@ -151,7 +133,7 @@ RUNNER_CHILD_TEST(security_manager_10_privacy_manager_fetch_whole_policy_for_sel
             RUNNER_ASSERT_MSG(appIt != appIdToAIH.end(), "Policy returned unexpected app: " << app);
 
             AppInstallHelper &aih = appIt->second;
-            auto appPrivileges = aih.getPrivilegesNames();
+            auto& appPrivileges = aih.getPrivileges();
             auto privIt = std::find(appPrivileges.begin(), appPrivileges.end(), privilege);
             RUNNER_ASSERT_MSG(privIt != appPrivileges.end(),
                               "Unexpected privilege " << privilege << " for app " << app);
@@ -232,7 +214,7 @@ RUNNER_CHILD_TEST(security_manager_11_privacy_manager_fetch_whole_policy_for_adm
             AppInstallHelper &aih = userAppIdToAIHIt->second;
             auto privs = aih.getPrivileges();
 
-            auto appPrivileges = aih.getPrivilegesNames();
+            auto& appPrivileges = aih.getPrivileges();
             auto privIt = std::find(appPrivileges.begin(), appPrivileges.end(), privilege);
             RUNNER_ASSERT_MSG(privIt != appPrivileges.end(),
                               "Unexpected privilege " << privilege << " for app " << app);
@@ -324,7 +306,7 @@ RUNNER_CHILD_TEST(security_manager_12_privacy_manager_fetch_whole_policy_for_adm
             AppInstallHelper &aih = userAppIdToAIHIt->second;
             auto privs = aih.getPrivileges();
 
-            auto appPrivileges = aih.getPrivilegesNames();
+            auto& appPrivileges = aih.getPrivileges();
             auto privIt = std::find(appPrivileges.begin(), appPrivileges.end(), privilege);
             RUNNER_ASSERT_MSG(privIt != appPrivileges.end(),
                               "Unexpected privilege " << privilege << " for app " << app);
@@ -389,7 +371,7 @@ RUNNER_CHILD_TEST(security_manager_13_privacy_manager_fetch_policy_after_update_
                 normalUser.getUidString(),
                 app1.getPrivileges()[0]
                 );
-        policyEntry.setLevel("Deny");
+        policyEntry.setLevel(PolicyEntry::LEVEL_DENY);
 
         policyRequest.addEntry(policyEntry);
         policyEntry = PolicyEntry(
@@ -397,7 +379,7 @@ RUNNER_CHILD_TEST(security_manager_13_privacy_manager_fetch_policy_after_update_
                 normalUser.getUidString(),
                 app1.getPrivileges()[1]
                 );
-        policyEntry.setLevel("Deny");
+        policyEntry.setLevel(PolicyEntry::LEVEL_DENY);
         policyRequest.addEntry(policyEntry);
         Api::sendPolicy(policyRequest);
 
@@ -464,15 +446,12 @@ RUNNER_CHILD_TEST(security_manager_14_privacy_manager_fetch_and_update_policy_fo
         PolicyRequest setPolicyRequest;
         std::vector<PolicyEntry> policyEntries;
 
-        const std::string internetPriv = "http://tizen.org/privilege/internet";
-        const std::string displayPriv = "http://tizen.org/privilege/display";
-
-        PolicyEntry internetPolicyEntry(SECURITY_MANAGER_ANY, SECURITY_MANAGER_ANY, internetPriv);
-        internetPolicyEntry.setMaxLevel("Deny");
+        PolicyEntry internetPolicyEntry(SECURITY_MANAGER_ANY, SECURITY_MANAGER_ANY, PRIV_INTERNET);
+        internetPolicyEntry.setMaxLevel(PolicyEntry::LEVEL_DENY);
         setPolicyRequest.addEntry(internetPolicyEntry);
 
-        PolicyEntry displayPolicyEntry(SECURITY_MANAGER_ANY, SECURITY_MANAGER_ANY, displayPriv);
-        displayPolicyEntry.setMaxLevel("Deny");
+        PolicyEntry displayPolicyEntry(SECURITY_MANAGER_ANY, SECURITY_MANAGER_ANY, PRIV_DISPLAY);
+        displayPolicyEntry.setMaxLevel(PolicyEntry::LEVEL_DENY);
         setPolicyRequest.addEntry(displayPolicyEntry);
 
         Api::sendPolicy(setPolicyRequest);
@@ -501,7 +480,7 @@ RUNNER_CHILD_TEST(security_manager_14_privacy_manager_fetch_and_update_policy_fo
 
 RUNNER_CHILD_TEST(security_manager_15_privacy_manager_send_policy_update_for_admin)
 {
-    const std::string updatePriv = "http://tizen.org/privilege/led";
+    const std::string& updatePriv = PRIV_LED;
 
     TemporaryTestUser adminUser("sm_test_15_username", GUM_USERTYPE_ADMIN);
     adminUser.create();
@@ -528,7 +507,7 @@ RUNNER_CHILD_TEST(security_manager_15_privacy_manager_send_policy_update_for_adm
                                 "drop_root_privileges failed");
 
         PolicyEntry entry(updatedApp.getAppId(), adminUser.getUidString(), updatePriv);
-        entry.setMaxLevel("Allow");
+        entry.setMaxLevel(PolicyEntry::LEVEL_ALLOW);
         PolicyRequest addPolicyRequest;
         addPolicyRequest.addEntry(entry);
         Api::sendPolicy(addPolicyRequest);
@@ -538,7 +517,7 @@ RUNNER_CHILD_TEST(security_manager_15_privacy_manager_send_policy_update_for_adm
 
 RUNNER_CHILD_TEST(security_manager_15_privacy_manager_send_policy_update_for_admin_wildcard)
 {
-    const std::string updatePriv = "http://tizen.org/privilege/led";
+    const std::string& updatePriv = PRIV_LED;
 
     TemporaryTestUser adminUser("sm_test_15_username", GUM_USERTYPE_ADMIN);
     adminUser.create();
@@ -564,7 +543,7 @@ RUNNER_CHILD_TEST(security_manager_15_privacy_manager_send_policy_update_for_adm
                           "drop_root_privileges failed");
 
         PolicyEntry entry(SECURITY_MANAGER_ANY, adminUser.getUidString(), updatePriv);
-        entry.setMaxLevel("Allow");
+        entry.setMaxLevel(PolicyEntry::LEVEL_ALLOW);
 
         PolicyRequest addPolicyRequest;
         addPolicyRequest.addEntry(entry);
@@ -575,7 +554,7 @@ RUNNER_CHILD_TEST(security_manager_15_privacy_manager_send_policy_update_for_adm
 
 RUNNER_CHILD_TEST(security_manager_15_privacy_manager_send_policy_update_for_self)
 {
-    const std::string updatePriv = "http://tizen.org/privilege/led";
+    const std::string& updatePriv = PRIV_LED;
 
     TemporaryTestUser user("sm_test_15_username", GUM_USERTYPE_NORMAL);
     user.create();
@@ -600,7 +579,7 @@ RUNNER_CHILD_TEST(security_manager_15_privacy_manager_send_policy_update_for_sel
                           "drop_root_privileges failed");
 
         PolicyEntry entry(app.getAppId(), user.getUidString(), updatePriv);
-        entry.setLevel("Allow");
+        entry.setLevel(PolicyEntry::LEVEL_ALLOW);
 
         PolicyRequest addPolicyRequest;
         addPolicyRequest.addEntry(entry);
@@ -637,11 +616,11 @@ RUNNER_CHILD_TEST(security_manager_16_policy_levels_get)
         std::string allowPolicy = std::string(levels[count-1]);
 
         // first should always be Deny
-        RUNNER_ASSERT_MSG(denyPolicy.compare("Deny") == 0,
+        RUNNER_ASSERT_MSG(denyPolicy.compare(PolicyEntry::LEVEL_DENY) == 0,
                 "Invalid first policy level. Should be Deny, instead there is: " << levels[0]);
 
         // last should always be Allow
-        RUNNER_ASSERT_MSG(allowPolicy.compare("Allow") == 0,
+        RUNNER_ASSERT_MSG(allowPolicy.compare(PolicyEntry::LEVEL_ALLOW) == 0,
                 "Invalid last policy level. Should be Allow, instead there is: " << levels[count-1]);
         exit(0);
     }
@@ -649,7 +628,7 @@ RUNNER_CHILD_TEST(security_manager_16_policy_levels_get)
 
 RUNNER_CHILD_TEST(security_manager_17a_privacy_manager_delete_policy_for_self)
 {
-    const std::string updatePriv = "http://tizen.org/privilege/led";
+    const std::string& updatePriv = PRIV_LED;
 
     TemporaryTestUser user("sm_test_17a_username", GUM_USERTYPE_NORMAL);
     user.create();
@@ -679,7 +658,7 @@ RUNNER_CHILD_TEST(security_manager_17a_privacy_manager_delete_policy_for_self)
                                             "drop_root_privileges failed");
 
         PolicyEntry entry(app.getAppId(), user.getUidString(), updatePriv);
-        entry.setLevel("Allow");
+        entry.setLevel(PolicyEntry::LEVEL_ALLOW);
         PolicyRequest addPolicyRequest;
         addPolicyRequest.addEntry(entry);
         Api::sendPolicy(addPolicyRequest);
@@ -699,7 +678,7 @@ RUNNER_CHILD_TEST(security_manager_17a_privacy_manager_delete_policy_for_self)
 
 RUNNER_CHILD_TEST(security_manager_17b_privacy_manager_delete_policy_for_self)
 {
-    const std::string updatePriv = "http://tizen.org/privilege/led";
+    const std::string& updatePriv = PRIV_LED;
 
     TemporaryTestUser user("sm_test_17b_username", GUM_USERTYPE_NORMAL);
     user.create();
@@ -734,7 +713,7 @@ RUNNER_CHILD_TEST(security_manager_17b_privacy_manager_delete_policy_for_self)
                                 "drop_root_privileges failed");
 
         PolicyEntry entry(app.getAppId(), user.getUidString(), updatePriv);
-        entry.setLevel("Allow");
+        entry.setLevel(PolicyEntry::LEVEL_ALLOW);
         PolicyRequest addPolicyRequest;
         addPolicyRequest.addEntry(entry);
         Api::sendPolicy(addPolicyRequest);
@@ -827,7 +806,6 @@ RUNNER_CHILD_TEST(security_manager_17_privacy_manager_fetch_whole_policy_for_sel
 
 RUNNER_CHILD_TEST(security_manager_18_privacy_manager_privacy_related_privileges_policy_install_remove)
 {
-    const std::string askUserDescription = "Ask user";
     TemporaryTestUser user("sm_test_18_username", GUM_USERTYPE_NORMAL);
     user.create();
 
@@ -851,7 +829,7 @@ RUNNER_CHILD_TEST(security_manager_18_privacy_manager_privacy_related_privileges
             unsigned int privacyActNum = 0;
             for (auto &entry : policyEntries)
                 if (isPrivilegePrivacy(entry.getPrivilege())) {
-                    RUNNER_ASSERT_MSG(entry.getCurrentLevel() == askUserDescription,
+                    RUNNER_ASSERT_MSG(entry.getCurrentLevel() == PolicyEntry::LEVEL_ASK_USER,
                                       "Invalid policy setup; policy should be \"Ask user\" but is "
                                       << entry.getCurrentLevel());
                     ++privacyActNum;
@@ -870,7 +848,6 @@ RUNNER_CHILD_TEST(security_manager_18_privacy_manager_privacy_related_privileges
 }
 
 void test_privacy_related_privileges(bool isHybrid) {
-    const std::string askUserDescription = "Ask user";
     TemporaryTestUser user("sm_test_19_username", GUM_USERTYPE_NORMAL);
     user.create();
 
@@ -911,7 +888,7 @@ void test_privacy_related_privileges(bool isHybrid) {
                           "Invalid appId: should be either " << app1.getAppId() << " or "
                           << app2.getAppId() << " but is " << entry.getAppId());
         if (PolicyConfiguration::getIsAskuserEnabled() && isPrivilegePrivacy(entry.getPrivilege())) {
-            RUNNER_ASSERT_MSG(entry.getCurrentLevel() == askUserDescription,
+            RUNNER_ASSERT_MSG(entry.getCurrentLevel() == PolicyEntry::LEVEL_ASK_USER,
                               "Invalid policy setup; policy should be \"Ask user\" but is "
                               << entry.getCurrentLevel());
             if (entry.getAppId() == app1.getAppId())
@@ -938,7 +915,6 @@ RUNNER_CHILD_TEST(security_manager_19b_privacy_manager_privacy_related_privilege
 
 RUNNER_CHILD_TEST(security_manager_20_privacy_manager_privacy_related_privileges_policy_admin_check)
 {
-    const std::string askUserDescription = "Ask user";
     TemporaryTestUser user("sm_test_20_username", GUM_USERTYPE_NORMAL);
     user.create();
 
@@ -952,7 +928,7 @@ RUNNER_CHILD_TEST(security_manager_20_privacy_manager_privacy_related_privileges
     int policyType = CYNARA_ADMIN_ALLOW;
     int privacyPolicyType = -1;
     if (PolicyConfiguration::getIsAskuserEnabled())
-        admin.getPolicyTypeForDescription(askUserDescription, privacyPolicyType);
+        admin.getPolicyTypeForDescription(PolicyEntry::LEVEL_ASK_USER, privacyPolicyType);
 
     for (auto &priv : app.getPrivileges()) {
         if (PolicyConfiguration::getIsAskuserEnabled() && isPrivilegePrivacy(priv)) {
@@ -1001,7 +977,7 @@ RUNNER_CHILD_TEST(security_manager_23_fetch_app_manifest_invalid_user)
 
 static void check_privileges_from_manifest(const AppInstallHelper &aih, char **privileges, size_t nPrivs)
 {
-    std::vector<std::string> aihPrivs = aih.getPrivilegesNames();
+    auto& aihPrivs = aih.getPrivileges();
     RUNNER_ASSERT_MSG(nPrivs == aihPrivs.size(), "Expected privileges number: " << aihPrivs.size() << ", got " << nPrivs);
     for (size_t i = 0; i < nPrivs; ++i) {
         RUNNER_ASSERT_MSG(std::find(aihPrivs.begin(), aihPrivs.end(), std::string(privileges[i])) != aihPrivs.end(),
@@ -1016,8 +992,7 @@ RUNNER_CHILD_TEST(security_manager_24_fetch_app_manifest_global_app)
 
     AppInstallHelper app("security_manager_24_fetch");
     app.setInstallType(SM_APP_INSTALL_GLOBAL);
-    app.addPrivilege(std::string("http://tizen.org/privilege/calendar.read"));
-    app.addPrivilege(std::string("http://tizen.org/privilege/calendar.write"));
+    app.addPrivileges({PRIV_CALENDAR_READ, PRIV_CALENDAR_WRITE});
     ScopedInstaller appInstall(app);
 
     char **privileges;
@@ -1043,8 +1018,7 @@ RUNNER_CHILD_TEST(security_manager_25_fetch_app_manifest_local_app)
 
     AppInstallHelper app("security_manager_25_fetch", user.getUid());
     app.setInstallType(SM_APP_INSTALL_LOCAL);
-    app.addPrivilege(std::string("http://tizen.org/privilege/calendar.read"));
-    app.addPrivilege(std::string("http://tizen.org/privilege/calendar.write"));
+    app.addPrivileges({PRIV_CALENDAR_READ, PRIV_CALENDAR_WRITE});
     ScopedInstaller appInstall(app);
 
     char **privileges;
@@ -1069,15 +1043,12 @@ RUNNER_CHILD_TEST(security_manager_26_fetch_app_manifest_both_apps)
 
     AppInstallHelper appGlobal("security_manager_26_fetch");
     appGlobal.setInstallType(SM_APP_INSTALL_GLOBAL);
-    appGlobal.addPrivilege(std::string("http://tizen.org/privilege/calendar.read"));
-    appGlobal.addPrivilege(std::string("http://tizen.org/privilege/calendar.write"));
-    appGlobal.addPrivilege(std::string("http://tizen.org/privielge/contacts.read"));
+    appGlobal.addPrivileges({PRIV_CALENDAR_READ, PRIV_CALENDAR_WRITE, PRIV_CONTACTS_READ});
     ScopedInstaller appGlobalInstall(appGlobal);
 
     AppInstallHelper appLocal("security_manager_26_fetch", user.getUid());
     appLocal.setInstallType(SM_APP_INSTALL_LOCAL);
-    appLocal.addPrivilege(std::string("http://tizen.org/privilege/calendar.read"));
-    appLocal.addPrivilege(std::string("http://tizen.org/privilege/calendar.write"));
+    appLocal.addPrivileges({PRIV_CALENDAR_READ, PRIV_CALENDAR_WRITE});
     ScopedInstaller appLocalInstall(appLocal);
 
 
@@ -1103,8 +1074,7 @@ RUNNER_CHILD_TEST(security_manager_27_fetch_app_manifest_app_context_local_posit
 
     AppInstallHelper app("security_manager_27_fetch", user.getUid());
     app.setInstallType(SM_APP_INSTALL_LOCAL);
-    app.addPrivilege(std::string("http://tizen.org/privilege/calendar.read"));
-    app.addPrivilege(std::string("http://tizen.org/privilege/calendar.write"));
+    app.addPrivileges({PRIV_CALENDAR_READ, PRIV_CALENDAR_WRITE});
     ScopedInstaller appInstall(app);
 
     pid_t pid = fork();
@@ -1133,8 +1103,7 @@ RUNNER_CHILD_TEST(security_manager_28_fetch_app_manifest_app_context_global_posi
 
     AppInstallHelper app("security_manager_28_fetch");
     app.setInstallType(SM_APP_INSTALL_GLOBAL);
-    app.addPrivilege(std::string("http://tizen.org/privilege/calendar.read"));
-    app.addPrivilege(std::string("http://tizen.org/privilege/calendar.write"));
+    app.addPrivileges({PRIV_CALENDAR_READ, PRIV_CALENDAR_WRITE});
     ScopedInstaller appInstall(app);
 
     pid_t pid = fork();
@@ -1166,15 +1135,12 @@ RUNNER_CHILD_TEST(security_manager_29_fetch_app_manifest_app_context_local_diffe
 
     AppInstallHelper app("security_manager_29_fetch", user.getUid());
     app.setInstallType(SM_APP_INSTALL_LOCAL);
-    app.addPrivilege(std::string("http://tizen.org/privilege/calendar.read"));
-    app.addPrivilege(std::string("http://tizen.org/privilege/calendar.write"));
+    app.addPrivileges({PRIV_CALENDAR_READ, PRIV_CALENDAR_WRITE});
     ScopedInstaller appInstall(app);
 
     AppInstallHelper app1("security_manager_29_fetch", user1.getUid());
     app1.setInstallType(SM_APP_INSTALL_LOCAL);
-    app1.addPrivilege(std::string("http://tizen.org/privilege/calendar.read"));
-    app1.addPrivilege(std::string("http://tizen.org/privilege/calendar.write"));
-    app1.addPrivilege(std::string("http://tizen.org/privilege/contacts.read"));
+    app1.addPrivileges({PRIV_CALENDAR_READ, PRIV_CALENDAR_WRITE, PRIV_CONTACTS_READ});
     ScopedInstaller appInstall1(app1);
 
 
@@ -1208,15 +1174,12 @@ RUNNER_CHILD_TEST(security_manager_30_fetch_app_manifest_app_context_local_diffe
 
     AppInstallHelper app("security_manager_30_fetch", user.getUid());
     app.setInstallType(SM_APP_INSTALL_LOCAL);
-    app.addPrivilege(std::string("http://tizen.org/privilege/calendar.read"));
-    app.addPrivilege(std::string("http://tizen.org/privilege/calendar.write"));
+    app.addPrivileges({PRIV_CALENDAR_READ, PRIV_CALENDAR_WRITE});
     ScopedInstaller appInstall(app);
 
     AppInstallHelper app1("security_manager_30_fetch_1", user.getUid());
     app1.setInstallType(SM_APP_INSTALL_LOCAL);
-    app1.addPrivilege(std::string("http://tizen.org/privilege/calendar.read"));
-    app1.addPrivilege(std::string("http://tizen.org/privilege/calendar.write"));
-    app1.addPrivilege(std::string("http://tizen.org/privilege/contacts.read"));
+    app1.addPrivileges({PRIV_CALENDAR_READ, PRIV_CALENDAR_WRITE, PRIV_CONTACTS_READ});
     ScopedInstaller appInstall1(app1);
 
 
@@ -1250,16 +1213,15 @@ RUNNER_CHILD_TEST(security_manager_31_fetch_app_manifest_app_context_local_diffe
 
     AppInstallHelper app("security_manager_31_fetch", user.getUid());
     app.setInstallType(SM_APP_INSTALL_LOCAL);
-    app.addPrivilege(std::string("http://tizen.org/privilege/calendar.read"));
-    app.addPrivilege(std::string("http://tizen.org/privilege/calendar.write"));
+    app.addPrivileges({PRIV_CALENDAR_READ, PRIV_CALENDAR_WRITE});
     ScopedInstaller appInstall(app);
 
     AppInstallHelper app1("security_manager_31_fetch_1", user.getUid());
     app1.setInstallType(SM_APP_INSTALL_LOCAL);
-    app1.addPrivilege(std::string("http://tizen.org/privilege/calendar.read"));
-    app1.addPrivilege(std::string("http://tizen.org/privilege/calendar.write"));
-    app1.addPrivilege(std::string("http://tizen.org/privilege/contacts.read"));
-    app1.addPrivilege(std::string("http://tizen.org/privilege/internal/usermanagement"));
+    app1.addPrivileges({PRIV_CALENDAR_READ,
+                        PRIV_CALENDAR_WRITE,
+                        PRIV_CONTACTS_READ,
+                        PRIV_INTERNAL_USERMANAGEMENT});
     ScopedInstaller appInstall1(app1);
 
 
diff --git a/src/security-manager-tests/test_cases_smack_privileges.cpp b/src/security-manager-tests/test_cases_smack_privileges.cpp
new file mode 100644 (file)
index 0000000..0aba4f7
--- /dev/null
@@ -0,0 +1,961 @@
+/*
+ * Copyright (c) 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.
+ *    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.
+ */
+
+#include <memory>
+#include <map>
+#include <cassert>
+
+#include <boost/filesystem.hpp>
+
+#include <tzplatform_config.h>
+
+#include <dpl/test/test_runner.h>
+#include <dpl/test/test_runner_child.h>
+
+#include <scoped_installer.h>
+#include <scoped_app_launcher.h>
+#include <temp_test_user.h>
+#include <app_install_helper_ext.h>
+#include <sm_policy_request.h>
+#include <privilege_names.h>
+#include <sm_commons.h>
+#include <service_manager.h>
+
+using namespace SecurityManagerTest;
+using namespace PrivilegeNames;
+
+namespace {
+
+namespace fs = boost::filesystem;
+
+const uid_t OWNER_ID = tzplatform_getuid(TZ_SYS_DEFAULT_USER);
+
+const fs::path TEST_SETUP_PATH = SM_TEST_DIR "/smack-privileges";
+const fs::path BACKUP_SETUP_PATH = TEST_SETUP_PATH / "backup";
+
+constexpr char SM_POLICY_PATH[] = "/usr/share/security-manager/policy";
+constexpr char SM_SMACK_PRIV_MAPPING_SUBDIR[] = "/privilege-mapping";
+constexpr char SM_SMACK_PRIV_CONFIG[] = "privilege-smack.list";
+
+void changePolicy(const AppInstallHelper& app, const std::string& priv, const std::string &level) {
+    PolicyRequest policyRequest;
+    PolicyEntry entry(app.getAppId(), std::to_string(app.getUID()), priv);
+    entry.setLevel(level);
+    policyRequest.addEntry(entry);
+    Api::sendPolicy(policyRequest);
+}
+
+const std::vector<AccessRequest> INTERNET_RULES = {
+    {"~PROCESS~", "System::Privilege::Internet", "w"},
+    {"System::Privilege::Internet", "~PROCESS~", "w"}
+};
+const std::vector<AccessRequest> CAMERA_RULES = {
+    {"~PROCESS~", "System::Privilege::Camera", "w"},
+    {"System::Privilege::Camera", "~PROCESS~", "w"}
+};
+const std::vector<AccessRequest> CAMERA_IGNORED_RULES = {
+    {"~PROCESS~", "System::TEF", "r"}
+};
+
+enum class SmackPrivSetup {
+    ORIGINAL,
+    EMPTY,
+    INTERNET_ONLY,
+    MULTIPLE_PRIVS,
+    MALFORMED
+};
+
+// This is to ensure that original security-manager policy is restored after the group is finished
+class SmackPrivGroupEnv final : public DPL::Test::TestGroup {
+private:
+    class SmackPrivSetupMgr final {
+    public:
+        SmackPrivSetupMgr() :
+            m_currentSetup(SmackPrivSetup::ORIGINAL),
+            m_serviceManager("security-manager.service"),
+            m_setupMap({{ SmackPrivSetup::EMPTY, "empty" },
+                        { SmackPrivSetup::INTERNET_ONLY, "internet-only" },
+                        { SmackPrivSetup::MULTIPLE_PRIVS, "multiple-privs" },
+                        { SmackPrivSetup::MALFORMED, "malformed" }})
+        {
+        }
+        SmackPrivSetupMgr(const SmackPrivSetupMgr&) = delete;
+        SmackPrivSetupMgr& operator=(const SmackPrivSetupMgr&) = delete;
+        ~SmackPrivSetupMgr()
+        {
+            // restore setup
+            if (m_currentSetup != SmackPrivSetup::ORIGINAL) {
+                try {
+                    copySetup(BACKUP_SETUP_PATH, SM_POLICY_PATH);
+
+                    m_serviceManager.restartService();
+                } catch (...) {
+                    RUNNER_ERROR_MSG("Unknown exception occurred during backup restore.");
+                }
+            }
+        }
+
+        void install(SmackPrivSetup setup)
+        {
+            if (setup == m_currentSetup)
+                return;
+
+            // backup setup
+            if (m_currentSetup == SmackPrivSetup::ORIGINAL)
+                copySetup(SM_POLICY_PATH, BACKUP_SETUP_PATH);
+
+            copySetup(TEST_SETUP_PATH / m_setupMap.at(setup), SM_POLICY_PATH);
+            m_currentSetup = setup;
+
+            // restart SM
+            m_serviceManager.restartService();
+        }
+
+    private:
+        void copySetup(const boost::filesystem::path& src, const boost::filesystem::path& dst)
+        {
+            const auto srcConfig = src / SM_SMACK_PRIV_CONFIG;
+            const auto dstConfig = dst / SM_SMACK_PRIV_CONFIG;
+            const auto srcMappingSubdir = src / SM_SMACK_PRIV_MAPPING_SUBDIR;
+            const auto dstMappingSubdir = dst / SM_SMACK_PRIV_MAPPING_SUBDIR;
+
+            // remove dst
+            fs::remove(dstConfig);
+            fs::remove_all(dstMappingSubdir);
+
+            // copy
+            if (fs::exists(srcConfig))
+                fs::copy_file(srcConfig, dstConfig);
+
+            if (fs::exists(srcMappingSubdir)) {
+                fs::create_directory(dstMappingSubdir);
+                for (const auto& e: fs::recursive_directory_iterator(srcMappingSubdir))
+                    fs::copy(e.path(), dstMappingSubdir / fs::relative(e.path(), srcMappingSubdir));
+            }
+        }
+
+        SmackPrivSetup m_currentSetup;
+        ServiceManager m_serviceManager;
+        const std::map<SmackPrivSetup, std::string> m_setupMap;
+    };
+
+    static SmackPrivSetupMgr* m_setupMgr;
+
+public:
+    void Init() override {
+        assert(!m_setupMgr);
+
+        m_setupMgr = new SmackPrivSetupMgr();
+    }
+
+    static void Install(SmackPrivSetup setup)
+    {
+        assert(m_setupMgr);
+
+        m_setupMgr->install(setup);
+    }
+
+    void Finish() override {
+        assert(m_setupMgr);
+
+        delete(m_setupMgr);
+        m_setupMgr = nullptr;
+    }
+};
+
+SmackPrivGroupEnv::SmackPrivSetupMgr* SmackPrivGroupEnv::m_setupMgr = nullptr;
+
+template<SmackPrivSetup T>
+class TestSetup
+{
+public:
+    void init(const std::string &) {
+        SmackPrivGroupEnv::Install(T);
+    }
+    void finish() {}
+};
+
+typedef TestSetup<SmackPrivSetup::EMPTY> EmptySetup;
+typedef TestSetup<SmackPrivSetup::INTERNET_ONLY> InternetOnlySetup;
+typedef TestSetup<SmackPrivSetup::MULTIPLE_PRIVS> MultiplePrivsSetup;
+typedef TestSetup<SmackPrivSetup::MALFORMED> MalformedSetup;
+
+} // namespace anonymous
+
+RUNNER_TEST_GROUP_INIT_ENV(SECURITY_MANAGER_SMACK_PRIVILEGES, SmackPrivGroupEnv)
+
+RUNNER_CHILD_TEST(smack_privileges_10_no_privileges, InternetOnlySetup)
+{
+    AppInstallHelperExt app("sm_test_sp_10_app");
+    {
+        ScopedInstaller appInstall(app);
+        app.checkAfterInstall();
+        app.checkDeniedPrivileges({PRIV_INTERNET});
+        app.checkSmackPrivileges({}, {PRIV_INTERNET});
+        app.checkSmackAccesses(CAMERA_RULES, false);
+        {
+            ScopedAppLauncher appLaunch(app);
+            app.checkSmackPrivileges({}, {PRIV_INTERNET});
+            app.checkSmackAccesses(CAMERA_RULES, false);
+        }
+    }
+    app.checkAfterUninstall();
+}
+
+RUNNER_CHILD_TEST(smack_privileges_20_internet_privilege, InternetOnlySetup)
+{
+    AppInstallHelperExt app("sm_test_sp_20_app");
+    app.addPrivileges({PRIV_INTERNET, PRIV_CAMERA});
+    {
+        ScopedInstaller appInstall(app);
+        app.checkAfterInstall();
+
+        // rules absent before app is launched
+        app.checkSmackPrivileges({}, {PRIV_INTERNET});
+        app.checkSmackAccesses(CAMERA_RULES, false);
+        {
+            ScopedAppLauncher appLaunch(app);
+            app.checkSmackPrivileges({PRIV_INTERNET}, {});
+            app.checkSmackAccesses(CAMERA_RULES, false);
+        }
+        // rules present after app is terminated
+        app.checkSmackPrivileges({PRIV_INTERNET}, {});
+    }
+    app.checkAfterUninstall();
+    // rules removed after app uninstallation
+    app.checkSmackPrivileges({}, {PRIV_INTERNET});
+}
+
+RUNNER_CHILD_TEST(smack_privileges_30_one_after_another, InternetOnlySetup)
+{
+    AppInstallHelperExt app("sm_test_sp_30_app");
+    app.addPrivileges({PRIV_INTERNET});
+    {
+        ScopedInstaller appInstall(app);
+        app.checkAfterInstall();
+
+        // rules absent before app is launched
+        app.checkSmackPrivileges({}, {PRIV_INTERNET});
+        {
+            ScopedAppLauncher appLaunch(app);
+            app.checkSmackPrivileges({PRIV_INTERNET}, {});
+        }
+        // rules present after app is terminated
+        app.checkSmackPrivileges({PRIV_INTERNET}, {});
+
+        {
+            ScopedAppLauncher appLaunch(app);
+            app.checkSmackPrivileges({PRIV_INTERNET}, {});
+        }
+        // rules present after app is terminated
+        app.checkSmackPrivileges({PRIV_INTERNET}, {});
+    }
+    app.checkAfterUninstall();
+    // rules removed after app uninstallation
+    app.checkSmackPrivileges({}, {PRIV_INTERNET});
+}
+
+RUNNER_CHILD_TEST(smack_privileges_40_different_users_one_after_another, InternetOnlySetup)
+{
+    TemporaryTestUser testUser("sm_test_40_user_name", GUM_USERTYPE_NORMAL, true);
+    testUser.create();
+
+    AppInstallHelperExt app("sm_test_sp_40_app");
+    app.addPrivileges({PRIV_INTERNET});
+    {
+        // global install
+        ScopedInstaller appInstall(app);
+        app.checkAfterInstall();
+
+        app.checkSmackPrivileges({}, {PRIV_INTERNET});
+
+        // owner launch
+        {
+            app.setUidGid(OWNER_ID);
+            ScopedAppLauncher appLaunch(app);
+            app.checkSmackPrivileges({PRIV_INTERNET}, {});
+        }
+
+        app.checkSmackPrivileges({PRIV_INTERNET}, {});
+
+        // test user launch
+        {
+            app.setUidGid(testUser.getUid());
+            ScopedAppLauncher appLaunch(app);
+            app.checkSmackPrivileges({PRIV_INTERNET}, {});
+        }
+
+        app.checkSmackPrivileges({PRIV_INTERNET}, {});
+    }
+    app.checkAfterUninstall();
+    app.checkSmackPrivileges({}, {PRIV_INTERNET});
+}
+
+RUNNER_CHILD_TEST(smack_privileges_50_same_user_simultaneously, InternetOnlySetup)
+{
+    AppInstallHelperExt app("sm_test_sp_50_app", OWNER_ID);
+    app.addPrivileges({PRIV_INTERNET});
+    {
+        ScopedInstaller appInstall(app);
+        app.checkAfterInstall();
+
+        app.checkSmackPrivileges({}, {PRIV_INTERNET});
+        {
+            ScopedAppLauncher appLaunch1(app);
+            app.checkSmackPrivileges({PRIV_INTERNET}, {});
+            {
+                ScopedAppLauncher appLaunch2(app);
+                app.checkSmackPrivileges({PRIV_INTERNET}, {});
+            }
+            app.checkSmackPrivileges({PRIV_INTERNET}, {});
+        }
+        app.checkSmackPrivileges({PRIV_INTERNET}, {});
+    }
+    app.checkAfterUninstall();
+    app.checkSmackPrivileges({}, {PRIV_INTERNET});
+}
+
+RUNNER_CHILD_TEST(smack_privileges_60_same_user_interchangeably, InternetOnlySetup)
+{
+    AppInstallHelperExt app("sm_test_sp_60_app", OWNER_ID);
+    app.addPrivileges({PRIV_INTERNET});
+    {
+        // local install
+        ScopedInstaller appInstall(app);
+        app.checkAfterInstall();
+
+        app.checkSmackPrivileges({}, {PRIV_INTERNET});
+
+        // owner launch 1
+        auto appLaunch1 = std::make_unique<ScopedAppLauncher>(app);
+
+        app.checkSmackPrivileges({PRIV_INTERNET}, {});
+
+        // owner launch 2
+        auto appLaunch2 = std::make_unique<ScopedAppLauncher>(app);
+
+        app.checkSmackPrivileges({PRIV_INTERNET}, {});
+
+        // owner terminate 1
+        appLaunch1.reset();
+
+        app.checkSmackPrivileges({PRIV_INTERNET}, {});
+
+        // owner terminate 2
+        appLaunch2.reset();
+    }
+    app.checkAfterUninstall();
+    app.checkSmackPrivileges({}, {PRIV_INTERNET});
+}
+
+RUNNER_CHILD_TEST(smack_privileges_70_different_users_simultaneously, InternetOnlySetup)
+{
+    TemporaryTestUser testUser("sm_test_70_user_name", GUM_USERTYPE_NORMAL, true);
+    testUser.create();
+
+    AppInstallHelperExt app("sm_test_sp_70_app");
+    app.addPrivileges({PRIV_INTERNET});
+    {
+        // global install
+        ScopedInstaller appInstall(app);
+        app.checkAfterInstall();
+
+        app.checkSmackPrivileges({}, {PRIV_INTERNET});
+
+        // owner launch
+        {
+            app.setUidGid(OWNER_ID);
+            ScopedAppLauncher appLaunch(app);
+            app.checkSmackPrivileges({PRIV_INTERNET}, {});
+
+            // test user launch
+            {
+                app.setUidGid(testUser.getUid());
+                ScopedAppLauncher appLaunch(app);
+
+                // multiuser detected -> rules removed
+                app.checkSmackPrivileges({}, {PRIV_INTERNET});
+            }
+            app.checkSmackPrivileges({}, {PRIV_INTERNET});
+        }
+        app.checkSmackPrivileges({}, {PRIV_INTERNET});
+
+        // owner launch
+        {
+            app.setUidGid(OWNER_ID);
+            ScopedAppLauncher appLaunch(app);
+
+            // rules restored
+            app.checkSmackPrivileges({PRIV_INTERNET}, {});
+        }
+    }
+    app.checkAfterUninstall();
+    app.checkSmackPrivileges({}, {PRIV_INTERNET});
+}
+
+RUNNER_CHILD_TEST(smack_privileges_80_uninstall_local_while_running, InternetOnlySetup)
+{
+    AppInstallHelperExt app("sm_test_sp_80_app");
+    app.addPrivileges({PRIV_INTERNET});
+    {
+        // global install
+        ScopedInstaller appInstall1(app);
+        app.checkAfterInstall();
+
+        app.checkSmackPrivileges({}, {PRIV_INTERNET});
+
+        // local install
+        AppInstallHelperExt app2("sm_test_sp_80_app", OWNER_ID);
+        auto appInstall2 = std::make_unique<ScopedInstaller>(app2);
+        app2.checkAfterInstall();
+
+        // global launch
+        ScopedAppLauncher appLaunch(app);
+        app.checkSmackPrivileges({PRIV_INTERNET}, {});
+
+        // local uninstall
+        appInstall2.reset();
+
+        app.checkSmackPrivileges({PRIV_INTERNET}, {});
+    }
+    app.checkAfterUninstall();
+    app.checkSmackPrivileges({}, {PRIV_INTERNET});
+}
+
+RUNNER_CHILD_TEST(smack_privileges_90_user_removal, InternetOnlySetup)
+{
+    TemporaryTestUser testUser("sm_test_90_user_name", GUM_USERTYPE_NORMAL, true);
+    testUser.create();
+
+    AppInstallHelperExt app("sm_test_sp_90_app", testUser.getUid());
+    app.addPrivileges({PRIV_INTERNET});
+    {
+        // local install
+        ScopedInstaller appInstall(app);
+        app.checkAfterInstall();
+
+        app.checkSmackPrivileges({}, {PRIV_INTERNET});
+
+        // local launch
+        {
+            ScopedAppLauncher appLaunch(app);
+            app.checkSmackPrivileges({PRIV_INTERNET}, {});
+        }
+
+        app.checkSmackPrivileges({PRIV_INTERNET}, {});
+
+        // user removal
+        testUser.remove();
+
+        app.checkAfterUninstall();
+        app.checkSmackPrivileges({}, {PRIV_INTERNET});
+    }
+}
+
+RUNNER_CHILD_TEST(smack_privileges_100_hybrid_app, InternetOnlySetup)
+{
+    AppInstallHelperExt app("sm_test_sp_100_app");
+    app.addPrivileges({PRIV_INTERNET});
+    app.setHybrid();
+    {
+        ScopedInstaller appInstall(app);
+        app.checkAfterInstall();
+
+        app.checkSmackPrivileges({}, {PRIV_INTERNET});
+
+        // launch
+        {
+            ScopedAppLauncher appLaunch(app);
+            app.checkSmackPrivileges({PRIV_INTERNET}, {});
+        }
+
+        app.checkSmackPrivileges({PRIV_INTERNET}, {});
+    }
+    app.checkAfterUninstall();
+    app.checkSmackPrivileges({}, {PRIV_INTERNET});
+}
+
+RUNNER_CHILD_TEST(smack_privileges_110_hybridity_change, InternetOnlySetup)
+{
+    AppInstallHelperExt app("sm_test_sp_110_app");
+    app.addPrivileges({PRIV_INTERNET});
+    {
+        ScopedInstaller appInstall(app);
+        app.checkAfterInstall();
+
+        app.checkSmackPrivileges({}, {PRIV_INTERNET});
+
+        // launch
+        {
+            ScopedAppLauncher appLaunch(app);
+            app.checkSmackPrivileges({PRIV_INTERNET}, {});
+        }
+
+        app.checkSmackPrivileges({PRIV_INTERNET}, {});
+
+        app.setHybrid();
+
+        // make it hybrid
+        InstallRequest request;
+        request.setAppId(app.getAppId());
+        request.setPkgId(app.getPkgId());
+        request.setUid(app.getUID());
+        request.setHybrid();
+        for (const auto &priv: app.getPrivileges()) {
+            request.addPrivilege(priv);
+        }
+        Api::update(request);
+
+        app.checkSmackPrivileges({}, {PRIV_INTERNET});
+
+        // launch
+        {
+            ScopedAppLauncher appLaunch(app);
+            app.checkSmackPrivileges({PRIV_INTERNET}, {});
+        }
+
+        app.checkSmackPrivileges({PRIV_INTERNET}, {});
+    }
+    app.checkAfterUninstall();
+    app.checkSmackPrivileges({}, {PRIV_INTERNET});
+}
+
+RUNNER_CHILD_TEST(smack_privileges_120_policy_change_while_running, InternetOnlySetup)
+{
+    TemporaryTestUser testUser("sm_test_120_user_name", GUM_USERTYPE_NORMAL, true);
+    testUser.create();
+
+    AppInstallHelperExt app("sm_test_sp_120_app", testUser.getUid());
+    app.addPrivileges({PRIV_INTERNET});
+    {
+        ScopedInstaller appInstall(app);
+        app.checkAfterInstall();
+
+        app.checkSmackPrivileges({}, {PRIV_INTERNET});
+
+        // launch
+        {
+            ScopedAppLauncher appLaunch(app);
+            app.checkSmackPrivileges({PRIV_INTERNET}, {});
+
+            // change policy
+            changePolicy(app, PRIV_INTERNET, PolicyEntry::LEVEL_DENY);
+
+            app.checkSmackPrivileges({}, {PRIV_INTERNET});
+
+            // change policy
+            changePolicy(app, PRIV_INTERNET, PolicyEntry::LEVEL_ALLOW);
+
+            app.checkSmackPrivileges({PRIV_INTERNET}, {});
+        }
+        app.checkSmackPrivileges({PRIV_INTERNET}, {});
+    }
+    app.checkAfterUninstall();
+    app.checkSmackPrivileges({}, {PRIV_INTERNET});
+}
+
+RUNNER_CHILD_TEST(smack_privileges_130_different_users_and_policies, InternetOnlySetup)
+{
+    TemporaryTestUser testUser("sm_test_130_user_name", GUM_USERTYPE_NORMAL, true);
+    testUser.create();
+
+    AppInstallHelperExt app("sm_test_sp_130_app");
+    app.addPrivileges({PRIV_INTERNET});
+    {
+        // global install
+        ScopedInstaller appInstall(app);
+        app.checkAfterInstall();
+
+        app.checkSmackPrivileges({}, {PRIV_INTERNET});
+
+        // test user launch with denied policy
+        {
+            app.setUidGid(testUser.getUid());
+            changePolicy(app, PRIV_INTERNET, PolicyEntry::LEVEL_DENY);
+            ScopedAppLauncher appLaunch(app);
+            app.checkSmackPrivileges({}, {PRIV_INTERNET});
+        }
+
+        app.checkSmackPrivileges({}, {PRIV_INTERNET});
+
+        // owner launch
+        {
+            app.setUidGid(OWNER_ID);
+            ScopedAppLauncher appLaunch(app);
+            app.checkSmackPrivileges({PRIV_INTERNET}, {});
+        }
+
+        app.checkSmackPrivileges({PRIV_INTERNET}, {});
+    }
+    app.checkAfterUninstall();
+    app.checkSmackPrivileges({}, {PRIV_INTERNET});
+}
+
+RUNNER_CHILD_TEST(smack_privileges_140_two_users_sequence, InternetOnlySetup)
+{
+    TemporaryTestUser testUser("sm_test_140_user_name", GUM_USERTYPE_NORMAL, true);
+    testUser.create();
+
+    AppInstallHelperExt app("sm_test_sp_140_app");
+    app.addPrivileges({PRIV_INTERNET});
+    {
+        // global install
+        ScopedInstaller appInstall(app);
+        app.checkAfterInstall();
+        app.checkSmackPrivileges({}, {PRIV_INTERNET});
+        {
+            // owner launch -> allowed
+            app.setUidGid(OWNER_ID);
+            ScopedAppLauncher appLaunch1(app);
+            app.checkSmackPrivileges({PRIV_INTERNET}, {});
+            {
+                // test user launch -> denied
+                app.setUidGid(testUser.getUid());
+                ScopedAppLauncher appLaunch2(app);
+                app.checkSmackPrivileges({}, {PRIV_INTERNET});
+
+                // owner launch -> denied
+                app.setUidGid(OWNER_ID);
+                ScopedAppLauncher appLaunch3(app);
+                app.checkSmackPrivileges({}, {PRIV_INTERNET});
+            }
+            // test user launch -> still denied
+            app.setUidGid(testUser.getUid());
+            ScopedAppLauncher appLaunch4(app);
+            app.checkSmackPrivileges({}, {PRIV_INTERNET});
+        }
+
+        // test user launch -> allowed
+        app.setUidGid(testUser.getUid());
+        ScopedAppLauncher appLaunch5(app);
+        app.checkSmackPrivileges({PRIV_INTERNET}, {});
+    }
+    app.checkAfterUninstall();
+    app.checkSmackPrivileges({}, {PRIV_INTERNET});
+}
+
+RUNNER_CHILD_TEST(smack_privileges_150_independent_apps, InternetOnlySetup)
+{
+    TemporaryTestUser testUser("sm_test_150_user_name", GUM_USERTYPE_NORMAL, true);
+    testUser.create();
+
+    AppInstallHelperExt app1("sm_test_sp_150_app1", testUser.getUid());
+    AppInstallHelperExt app2("sm_test_sp_150_app2", testUser.getUid());
+    app1.addPrivileges({PRIV_INTERNET});
+    {
+        ScopedInstaller appInstall1(app1);
+        ScopedInstaller appInstall2(app2);
+
+        app1.checkAfterInstall();
+        app2.checkAfterInstall();
+
+        app1.checkSmackPrivileges({}, {PRIV_INTERNET});
+        app2.checkSmackPrivileges({}, {PRIV_INTERNET});
+
+        // launch
+        {
+            ScopedAppLauncher appLaunch1(app1);
+            ScopedAppLauncher appLaunch2(app2);
+
+            app1.checkSmackPrivileges({PRIV_INTERNET}, {});
+            app2.checkSmackPrivileges({}, {PRIV_INTERNET});
+        }
+    }
+    app1.checkAfterUninstall();
+    app2.checkAfterUninstall();
+    app1.checkSmackPrivileges({}, {PRIV_INTERNET});
+    app2.checkSmackPrivileges({}, {PRIV_INTERNET});
+}
+
+RUNNER_CHILD_TEST(smack_privileges_160_nonhybrid_package, InternetOnlySetup)
+{
+    TemporaryTestUser testUser("sm_test_160_user_name", GUM_USERTYPE_NORMAL, true);
+    testUser.create();
+
+    constexpr char pkgPrefix[] = "sm_test_sp_160_pkg";
+
+    AppInstallHelperExt app1("sm_test_sp_160_app1", pkgPrefix, testUser.getUid());
+    app1.addPrivileges({PRIV_INTERNET});
+
+    AppInstallHelperExt app2("sm_test_sp_160_app2", pkgPrefix, testUser.getUid());
+    app2.addPrivileges({PRIV_INTERNET});
+    {
+        ScopedInstaller appInstall1(app1);
+        ScopedInstaller appInstall2(app2);
+
+        app1.checkAfterInstall();
+        app2.checkAfterInstall();
+
+        app1.checkSmackPrivileges({}, {PRIV_INTERNET});
+        app2.checkSmackPrivileges({}, {PRIV_INTERNET});
+
+        // launch
+        {
+            ScopedAppLauncher appLaunch1(app1);
+            ScopedAppLauncher appLaunch2(app2);
+
+            // both have access in non-hybrid package
+            app1.checkSmackPrivileges({PRIV_INTERNET}, {});
+            app2.checkSmackPrivileges({PRIV_INTERNET}, {});
+
+            // change policy of single app
+            changePolicy(app1, PRIV_INTERNET, PolicyEntry::LEVEL_DENY);
+
+            // both should lose the access
+            app1.checkSmackPrivileges({}, {PRIV_INTERNET});
+            app2.checkSmackPrivileges({}, {PRIV_INTERNET});
+
+            changePolicy(app1, PRIV_INTERNET, PolicyEntry::LEVEL_ALLOW);
+
+            app1.checkSmackPrivileges({PRIV_INTERNET}, {});
+            app2.checkSmackPrivileges({PRIV_INTERNET}, {});
+        }
+    }
+    app1.checkAfterUninstall();
+    app2.checkAfterUninstall();
+    app1.checkSmackPrivileges({}, {PRIV_INTERNET});
+    app2.checkSmackPrivileges({}, {PRIV_INTERNET});
+}
+
+
+RUNNER_CHILD_TEST(smack_privileges_170_hybrid_package, InternetOnlySetup)
+{
+    TemporaryTestUser testUser("sm_test_170_user_name", GUM_USERTYPE_NORMAL, true);
+    testUser.create();
+
+    constexpr char pkgPrefix[] = "sm_test_sp_170_pkg";
+
+    AppInstallHelperExt app1("sm_test_sp_170_app1", pkgPrefix, testUser.getUid());
+    app1.addPrivileges({PRIV_INTERNET});
+    app1.setHybrid();
+
+    AppInstallHelperExt app2("sm_test_sp_170_app2", pkgPrefix, testUser.getUid());
+    app2.setHybrid();
+    {
+        ScopedInstaller appInstall1(app1);
+        ScopedInstaller appInstall2(app2);
+
+        app1.checkAfterInstall();
+        app2.checkAfterInstall();
+
+        app1.checkSmackPrivileges({}, {PRIV_INTERNET});
+        app2.checkSmackPrivileges({}, {PRIV_INTERNET});
+
+        // launch
+        {
+            ScopedAppLauncher appLaunch1(app1);
+            ScopedAppLauncher appLaunch2(app2);
+
+            // only one have access in a hybrid package
+            app1.checkSmackPrivileges({PRIV_INTERNET}, {});
+            app2.checkSmackPrivileges({}, {PRIV_INTERNET});
+
+            // change policy of single app
+            changePolicy(app1, PRIV_INTERNET, PolicyEntry::LEVEL_DENY);
+
+            // both should have no access
+            app1.checkSmackPrivileges({}, {PRIV_INTERNET});
+            app2.checkSmackPrivileges({}, {PRIV_INTERNET});
+
+            changePolicy(app1, PRIV_INTERNET, PolicyEntry::LEVEL_ALLOW);
+
+            app1.checkSmackPrivileges({PRIV_INTERNET}, {});
+            app2.checkSmackPrivileges({}, {PRIV_INTERNET});
+        }
+    }
+    app1.checkAfterUninstall();
+    app2.checkAfterUninstall();
+    app1.checkSmackPrivileges({}, {PRIV_INTERNET});
+    app2.checkSmackPrivileges({}, {PRIV_INTERNET});
+}
+
+RUNNER_CHILD_TEST(smack_privileges_180_hybrid_package_both_apps_privileged, InternetOnlySetup)
+{
+    TemporaryTestUser testUser("sm_test_180_user_name", GUM_USERTYPE_NORMAL, true);
+    testUser.create();
+
+    constexpr char pkgPrefix[] = "sm_test_sp_180_pkg";
+
+    AppInstallHelperExt app1("sm_test_sp_180_app1", pkgPrefix, testUser.getUid());
+    app1.addPrivileges({PRIV_INTERNET});
+    app1.setHybrid();
+
+    AppInstallHelperExt app2("sm_test_sp_180_app2", pkgPrefix, testUser.getUid());
+    app2.addPrivileges({PRIV_INTERNET});
+    app2.setHybrid();
+    {
+        ScopedInstaller appInstall1(app1);
+        ScopedInstaller appInstall2(app2);
+
+        app1.checkAfterInstall();
+        app2.checkAfterInstall();
+
+        app1.checkSmackPrivileges({}, {PRIV_INTERNET});
+        app2.checkSmackPrivileges({}, {PRIV_INTERNET});
+
+        // launch
+        {
+            ScopedAppLauncher appLaunch1(app1);
+            ScopedAppLauncher appLaunch2(app2);
+
+            // only one have access in a hybrid package
+            app1.checkSmackPrivileges({PRIV_INTERNET}, {});
+            app2.checkSmackPrivileges({PRIV_INTERNET}, {});
+
+            // change policy of single app
+            changePolicy(app1, PRIV_INTERNET, PolicyEntry::LEVEL_DENY);
+
+            // both should have no access
+            app1.checkSmackPrivileges({}, {PRIV_INTERNET});
+            app2.checkSmackPrivileges({PRIV_INTERNET}, {});
+
+            changePolicy(app1, PRIV_INTERNET, PolicyEntry::LEVEL_ALLOW);
+
+            app1.checkSmackPrivileges({PRIV_INTERNET}, {});
+            app2.checkSmackPrivileges({PRIV_INTERNET}, {});
+        }
+    }
+    app1.checkAfterUninstall();
+    app2.checkAfterUninstall();
+    app1.checkSmackPrivileges({}, {PRIV_INTERNET});
+    app2.checkSmackPrivileges({}, {PRIV_INTERNET});
+}
+
+RUNNER_CHILD_TEST(smack_privileges_200_empty_policy, EmptySetup)
+{
+    AppInstallHelperExt app("sm_test_sp_200_app");
+    app.addPrivileges({PRIV_INTERNET, PRIV_CAMERA});
+    {
+        ScopedInstaller appInstall(app);
+
+        app.checkAfterInstall();
+
+        app.checkSmackAccesses(INTERNET_RULES, false);
+        app.checkSmackAccesses(CAMERA_RULES, false);
+        {
+            ScopedAppLauncher appLaunch(app);
+
+            // no config -> no access
+            app.checkSmackAccesses(INTERNET_RULES, false);
+            app.checkSmackAccesses(CAMERA_RULES, false);
+        }
+    }
+    app.checkAfterUninstall();
+    app.checkSmackAccesses(INTERNET_RULES, false);
+    app.checkSmackAccesses(CAMERA_RULES, false);
+}
+
+RUNNER_CHILD_TEST(smack_privileges_300_multi_policy_no_privs, MultiplePrivsSetup)
+{
+    AppInstallHelperExt app("sm_test_sp_300_app");
+    {
+        ScopedInstaller appInstall(app);
+
+        app.checkAfterInstall();
+        app.checkSmackPrivileges({}, {PRIV_INTERNET, PRIV_CAMERA});
+        app.checkSmackAccesses(CAMERA_IGNORED_RULES, false);
+        {
+            ScopedAppLauncher appLaunch(app);
+
+            app.checkSmackPrivileges({}, {PRIV_INTERNET, PRIV_CAMERA});
+            app.checkSmackAccesses(CAMERA_IGNORED_RULES, false);
+        }
+    }
+    app.checkAfterUninstall();
+    app.checkSmackPrivileges({}, {PRIV_INTERNET, PRIV_CAMERA});
+}
+
+RUNNER_CHILD_TEST(smack_privileges_310_multi_policy_single_priv, MultiplePrivsSetup)
+{
+    AppInstallHelperExt app("sm_test_sp_310_app");
+    app.addPrivilege(PRIV_CAMERA);
+    {
+        ScopedInstaller appInstall(app);
+
+        app.checkAfterInstall();
+        app.checkSmackPrivileges({}, {PRIV_INTERNET, PRIV_CAMERA});
+        app.checkSmackAccesses(CAMERA_IGNORED_RULES, false);
+        {
+            ScopedAppLauncher appLaunch(app);
+
+            app.checkSmackPrivileges({PRIV_CAMERA}, {PRIV_INTERNET});
+            app.checkSmackAccesses(CAMERA_IGNORED_RULES, false);
+        }
+    }
+    app.checkAfterUninstall();
+    app.checkSmackPrivileges({}, {PRIV_INTERNET, PRIV_CAMERA});
+}
+
+RUNNER_CHILD_TEST(smack_privileges_320_multi_policy_all_privs, MultiplePrivsSetup)
+{
+    TemporaryTestUser testUser("sm_test_320_user_name", GUM_USERTYPE_NORMAL, true);
+    testUser.create();
+
+    AppInstallHelperExt app("sm_test_sp_320_app", testUser.getUid());
+    app.addPrivileges({PRIV_CAMERA, PRIV_INTERNET});
+    {
+        ScopedInstaller appInstall(app);
+
+        app.checkAfterInstall();
+        app.checkSmackPrivileges({}, {PRIV_INTERNET, PRIV_CAMERA});
+        app.checkSmackAccesses(CAMERA_IGNORED_RULES, false);
+        {
+            ScopedAppLauncher appLaunch(app);
+
+            app.checkSmackPrivileges({PRIV_CAMERA, PRIV_INTERNET}, {});
+            app.checkSmackAccesses(CAMERA_IGNORED_RULES, false);
+
+            // change policy
+            changePolicy(app, PRIV_INTERNET, PolicyEntry::LEVEL_DENY);
+
+            app.checkSmackPrivileges({PRIV_CAMERA}, {PRIV_INTERNET});
+            app.checkSmackAccesses(CAMERA_IGNORED_RULES, false);
+
+            // change policy
+            changePolicy(app, PRIV_INTERNET, PolicyEntry::LEVEL_ALLOW);
+            changePolicy(app, PRIV_CAMERA, PolicyEntry::LEVEL_DENY);
+
+            app.checkSmackPrivileges({PRIV_INTERNET}, {PRIV_CAMERA});
+            app.checkSmackAccesses(CAMERA_IGNORED_RULES, false);
+        }
+    }
+    app.checkAfterUninstall();
+    app.checkSmackPrivileges({}, {PRIV_INTERNET, PRIV_CAMERA});
+}
+
+RUNNER_CHILD_TEST(smack_privileges_400_malformed, MalformedSetup)
+{
+    AppInstallHelperExt app("sm_test_sp_400_app");
+    app.addPrivileges({PRIV_INTERNET, PRIV_CAMERA});
+    {
+        ScopedInstaller appInstall(app);
+
+        app.checkAfterInstall();
+
+        app.checkSmackAccesses(INTERNET_RULES, false);
+        app.checkSmackAccesses(CAMERA_RULES, false);
+        {
+            ScopedAppLauncher appLaunch(app);
+
+            // malformed config -> no access
+            app.checkSmackAccesses(INTERNET_RULES, false);
+            app.checkSmackAccesses(CAMERA_RULES, false);
+        }
+    }
+    app.checkAfterUninstall();
+    app.checkSmackAccesses(INTERNET_RULES, false);
+    app.checkSmackAccesses(CAMERA_RULES, false);
+}