Add SM tests covering many apps in single request 95/209295/35
authorAlicja Kluczek <a.kluczek@samsung.com>
Thu, 4 Jul 2019 10:57:32 +0000 (12:57 +0200)
committerTomasz Swierczek <t.swierczek@samsung.com>
Tue, 27 Aug 2019 08:52:35 +0000 (08:52 +0000)
Add tests covering installation & updating many apps in single request.
Add a function checking if an app has proper Smack policy.
Add a function parsing smack rules template files.
Add a function creating a new app in InstallRequest class.
Modify ScopedInstaller class for many apps in single request
compatibility.

Change-Id: I35bb9757f54b111629d45b1769ca4e53ccccd017

src/common/scoped_installer.h
src/common/sm_request.cpp
src/common/sm_request.h
src/security-manager-tests/CMakeLists.txt
src/security-manager-tests/common/sm_commons.cpp
src/security-manager-tests/common/sm_commons.h
src/security-manager-tests/common/template_parser.cpp [new file with mode: 0644]
src/security-manager-tests/common/template_parser.h [new file with mode: 0644]
src/security-manager-tests/test_cases.cpp

index 4a0ff06..82175ce 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2016-2019 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.
@@ -36,7 +36,7 @@
 class ScopedInstaller {
 public:
     ScopedInstaller(const AppInstallHelper &app, bool requestUid = true)
-        : m_appId(app.getAppId()),
+        : m_appIds({app.getAppId()}),
           m_uid(app.getUID()),
           m_installType(app.getInstallType()),
           m_shouldUninstall(true),
@@ -70,9 +70,30 @@ public:
         SecurityManagerTest::Api::install(instReq);
     }
 
+    ScopedInstaller(const std::vector<std::string> &appIds, const std::string &pkgId)
+        : m_appIds(appIds),
+          m_uid(0),
+          m_installType(SM_APP_INSTALL_NONE),
+          m_shouldUninstall(true),
+          m_requestUid(false),
+          m_creatorPid(getpid())
+    {
+        SecurityManagerTest::InstallRequest instReq;
+
+        instReq.setPkgId(pkgId);
+        for (unsigned int i = 0; i < appIds.size(); i++) {
+            if (i > 0)
+                instReq.nextApp();
+
+            instReq.setAppId(appIds[i]);
+        }
+
+        SecurityManagerTest::Api::install(instReq);
+    }
+
     ScopedInstaller(const ScopedInstaller &) = delete;
     ScopedInstaller(ScopedInstaller &&other)
-        : m_appId(std::move(other.m_appId)),
+        : m_appIds(std::move(other.m_appIds)),
           m_uid(other.m_uid),
           m_installType(other.m_installType),
           m_shouldUninstall(other.m_shouldUninstall),
@@ -97,7 +118,12 @@ public:
         if (!m_shouldUninstall)
             return;
         SecurityManagerTest::InstallRequest uninstReq;
-        uninstReq.setAppId(m_appId);
+        for (unsigned int i = 0; i < m_appIds.size(); i++) {
+            if (i > 0)
+                uninstReq.nextApp();
+
+            uninstReq.setAppId(m_appIds[i]);
+        }
         if (m_requestUid)
             uninstReq.setUid(m_uid);
         if (m_installType != SM_APP_INSTALL_NONE)
@@ -107,7 +133,7 @@ public:
     }
 
 protected:
-    std::string m_appId;
+    std::vector<std::string> m_appIds;
     uid_t m_uid;
     app_install_type m_installType;
     bool m_shouldUninstall;
index 6e06150..b6fa1a1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2017 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2019 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.
@@ -70,7 +70,6 @@ void InstallRequest::setAppId(std::string appId, lib_retcode expectedResult)
                           << " App id: " << appId << ";"
                           << " Result: " << result << ";"
                           << " Expected result: " << expectedResult);
-    m_appId = std::move(appId);
 }
 
 void InstallRequest::setPkgId(std::string pkgId, lib_retcode expectedResult)
@@ -167,10 +166,17 @@ void InstallRequest::setHybrid(lib_retcode expectedResult)
                        << " Expected result: " << expectedResult);
 }
 
+void InstallRequest::nextApp(lib_retcode expectedResult)
+{
+    int result = security_manager_app_inst_req_next(m_req);
+    RUNNER_ASSERT_MSG((lib_retcode)result == expectedResult,
+                        "security_manager_app_inst_req_next() returned wrong value."
+                        << " Result: " << result << ";"
+                        << " Expected result: " << expectedResult);
+}
+
 std::ostream& operator<<(std::ostream &os, const InstallRequest &request)
 {
-    if (!request.m_appId.empty())
-        os << "app id: " << request.m_appId << "; ";
     if (!request.m_pkgId.empty())
         os << "pkg id: " << request.m_pkgId << "; ";
     if (!request.m_privileges.empty()) {
index 4efb5c9..d58d43e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2017 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2019 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.
@@ -42,7 +42,6 @@ public:
     InstallRequest& operator=(const InstallRequest&) = delete;
     InstallRequest(InstallRequest &&other)
         : m_req(std::move(other.m_req)),
-          m_appId(std::move(other.m_appId)),
           m_pkgId(std::move(other.m_pkgId)),
           m_authorId(std::move(other.m_authorId)),
           m_privileges(std::move(other.m_privileges)),
@@ -67,6 +66,7 @@ public:
     void setAuthorId(std::string authorId, lib_retcode expectedResult= SECURITY_MANAGER_SUCCESS);
     void setInstallType(const enum app_install_type &type, lib_retcode expectedResult = SECURITY_MANAGER_SUCCESS);
     void setHybrid(lib_retcode expectedResult = SECURITY_MANAGER_SUCCESS);
+    void nextApp(lib_retcode expectedResult = SECURITY_MANAGER_SUCCESS);
     std::string getPkgId() const { return m_pkgId; }
     std::string getAppTizenVersion() const { return m_tizenVer; }
     app_inst_req *get() { return m_req; }
@@ -77,7 +77,6 @@ private:
     app_inst_req *m_req;
 
     std::string m_tizenVer;
-    std::string m_appId;
     std::string m_pkgId;
     std::string m_authorId;
     PrivilegeVector m_privileges;
index 46e51d8..cf08aa4 100644 (file)
@@ -57,6 +57,7 @@ SET(SEC_MGR_SOURCES
     ${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/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
index b8b389b..f70a825 100644 (file)
@@ -27,7 +27,9 @@
 #include <unordered_map>
 #include <cstdlib>
 
+#include <array>
 #include <unordered_set>
+#include <utility>
 #include <vector>
 
 #include <security-manager-types.h>
 #include <policy_configuration.h>
 #include "tzplatform.h"
 #include <label_generator.h>
+#include <template_parser.h>
 
 using namespace SecurityManagerTest;
 
+#define CONF_DIR "/usr/share/security-manager/policy/"
+
 // Common DB/nftw checks
 
 // nftw doesn't allow passing user data to functions. Work around by using global variable
@@ -181,7 +186,43 @@ void sm_app_has_privileges(const AppInstallHelper &app,
     }
 }
 
-static void check_app(const std::string &appId, const std::string &pkgId, bool shouldBeInstalled)
+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~", generatePathSharedROLabel(pkgId)),
+         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 check_app(const std::string &appId, const std::string &pkgId,
+                      bool shouldBeInstalled, bool isHybrid)
 {
     char *retPkgId;
     int ret = security_manager_get_app_pkgid(&retPkgId, appId.c_str());
@@ -194,14 +235,15 @@ static void check_app(const std::string &appId, const std::string &pkgId, bool s
             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.");
     }
 }
 
-void check_app_after_install(const std::string &app_id, const std::string &pkg_id)
+void check_app_after_install(const std::string &app_id, const std::string &pkg_id, bool isHybrid)
 {
-    check_app(app_id, pkg_id, true);
+    check_app(app_id, pkg_id, true, isHybrid);
 }
 
 static void check_app_gids(const std::string &app_id, const std::vector<gid_t> &allowed_gids)
@@ -239,8 +281,7 @@ void check_app_after_install(const std::string &app_id, const std::string &pkg_i
                              const privileges_t &denied_privs,
                              bool isHybrid)
 {
-    check_app(app_id, pkg_id, true);
-
+    check_app(app_id, pkg_id, true, isHybrid);
     /* 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);
 
@@ -270,15 +311,16 @@ 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)
+void check_app_after_uninstall(const std::string &app_id, const std::string &pkg_id,
+                               bool isHybrid)
 {
-    check_app(app_id, pkg_id, false);
+    check_app(app_id, pkg_id, false, isHybrid);
 }
 
 void check_app_after_uninstall(const std::string &app_id, const std::string &pkg_id,
                                const privileges_t &privileges, bool isHybrid)
 {
-    check_app(app_id, pkg_id, false);
+    check_app(app_id, pkg_id, false, isHybrid);
 
     /* Privileges should not be granted anymore to any user */
     check_app_permissions(app_id, pkg_id, ANY_USER_REPRESENTATION, {}, privileges, isHybrid);
index 902d70c..8cd7538 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2016-2019 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.
@@ -45,14 +45,16 @@ void check_app_permissions(const std::string &app_id, const std::string &pkg_id,
 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);
+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);
+void check_app_after_uninstall(const std::string &app_id, const std::string &pkg_id,
+                               bool isHybrid = false);
 void check_app_after_uninstall(const std::string &app_id, const std::string &pkg_id,
                                const privileges_t &privileges, bool isHybrid = false);
 
diff --git a/src/security-manager-tests/common/template_parser.cpp b/src/security-manager-tests/common/template_parser.cpp
new file mode 100644 (file)
index 0000000..83c5b46
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        template_parser.cpp
+ * @author      Alicja Kluczek <a.kluczek@samsung.com>
+ * @brief       Parsing function for smack rules templates
+ */
+#include "template_parser.h"
+#include <fstream>
+
+std::vector<AccessRequest> parseSmackRulesFile(const std::string &path)
+{
+    std::vector<AccessRequest> rules;
+    std::ifstream rulesFile(path);
+    std::string object, subject, access;
+    while (rulesFile >> subject >> object >> access) {
+        rules.emplace_back(std::move(subject), std::move(object), std::move(access));
+    }
+    return rules;
+}
+
diff --git a/src/security-manager-tests/common/template_parser.h b/src/security-manager-tests/common/template_parser.h
new file mode 100644 (file)
index 0000000..81a3674
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        template_parser.h
+ * @author      Alicja Kluczek <a.kluczek@samsung.com>
+ * @brief       Parsing function for smack rules templates
+ */
+#include <vector>
+#include <string>
+
+struct AccessRequest {
+    AccessRequest(std::string sub, std::string obj, std::string acc)
+    : subject(std::move(sub)),
+      object(std::move(obj)),
+      access(std::move(acc))
+    {}
+    std::string subject;
+    std::string object;
+    std::string access;
+};
+
+std::vector<AccessRequest> parseSmackRulesFile(const std::string &path);
+
index 5bde91d..3195de3 100644 (file)
@@ -508,6 +508,71 @@ RUNNER_TEST(security_manager_09_app_install_constraint_check)
     install(users[0], pkgId[0], appId[0], version[0], author[1], hybrid[0], SECURITY_MANAGER_ERROR_INPUT_PARAM);
 }
 
+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"};
+
+    {
+        ScopedInstaller appsInstall(appIds, pkgId);
+        // Installing many applications in single request
+        for (const auto &appId : appIds) {
+            check_app_after_install(appId, pkgId);
+        }
+    }
+
+    for (const auto &appId : appIds) {
+        check_app_after_uninstall(appId, pkgId);
+    }
+}
+
+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";
+
+    {
+        ScopedInstaller appsInstall({appId, appId}, pkgId);
+        check_app_after_install(appId, pkgId);
+    }
+
+    check_app_after_uninstall(appId, pkgId);
+}
+
+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";
+
+    {
+        ScopedInstaller appsInstall(appIds, pkgId);
+        // Package is not hybrid, every app has same policy.
+        for (const auto &appId : appIds) {
+            check_app_after_install(appId, pkgId);
+        }
+
+        // Updating package -- changing set of apps in package and setting hybrid mode
+        InstallRequest updateRequest;
+        updateRequest.setPkgId(pkgId);
+        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);
+        // Package became hybrid properly,
+        // so app not included in updated version of package was uninstalled.
+        check_app_after_uninstall(appIds[2], pkgId, false);
+    }
+
+    for (const auto &appId : appIds) {
+        check_app_after_uninstall(appId, pkgId, true);
+    }
+}
+
 RUNNER_CHILD_TEST(security_manager_10_app_has_privilege)
 {
     const std::vector<std::string> allowedPrivs = {