From 0667b0a1f5c6f236b5ace84ebc7333571a21adf5 Mon Sep 17 00:00:00 2001 From: "jin-gyu.kim" Date: Thu, 24 May 2018 17:23:07 +0900 Subject: [PATCH 01/16] Retrieve package manager privilege from User::Shell client When user uses dbus-send in the shell process, these privileges can be allowed. Therefore, privilege checks for these were meaningless. pkgcmd tools will have "System" execute label, so we can remove these privileges from User:Shell client. Change-Id: I56bb4c3d2ef270fada6ce8725eccb4390e2b718f --- policy/security-manager-policy-reload.in | 6 ------ 1 file changed, 6 deletions(-) diff --git a/policy/security-manager-policy-reload.in b/policy/security-manager-policy-reload.in index 2611327..4afc004 100755 --- a/policy/security-manager-policy-reload.in +++ b/policy/security-manager-policy-reload.in @@ -67,12 +67,6 @@ done # Root shell get access to all privileges cyad --set-policy --bucket=MANIFESTS_GLOBAL --client="User::Shell" --user="0" --privilege="*" --type=ALLOW -# Shell process get access to packagemanager.admin privilege to install applications -cyad --set-policy --bucket=MANIFESTS_GLOBAL --client="User::Shell" --user="*" --privilege="http://tizen.org/privilege/packagemanager.admin" --type=ALLOW - -# Shell process get access to packagemanager.info privilege to debug applications -cyad --set-policy --bucket=MANIFESTS_GLOBAL --client="User::Shell" --user="*" --privilege="http://tizen.org/privilege/packagemanager.info" --type=ALLOW - # Load privilege-group mappings ( echo "BEGIN;" -- 2.7.4 From 338627f2263a30c4a298b7bc7a63608dff230258 Mon Sep 17 00:00:00 2001 From: "jin-gyu.kim" Date: Wed, 1 Aug 2018 16:57:05 +0900 Subject: [PATCH 02/16] Add /opt/usr/media to privilege-mount.list again "/opt/usr/media" was removed in commit 23b4001. It was wrong, because app's mount namespace is set as SLAVE after unshare(). In case of SLAVE, "/opt/usr/media" is not changed by dummy mount to TZ_USER_CONTENT. Therefore, it should be added in the list again. Change-Id: I504c3c8dcdac8e9b31a61dfc03c66abf09a386bc --- policy/privilege-mount.list | 1 + 1 file changed, 1 insertion(+) diff --git a/policy/privilege-mount.list b/policy/privilege-mount.list index b2826ad..8aea6d8 100644 --- a/policy/privilege-mount.list +++ b/policy/privilege-mount.list @@ -15,3 +15,4 @@ http://tizen.org/privilege/externalstorage TZ_SYS_STORAGE - /usr/share/security-manager/dummy http://tizen.org/privilege/mediastorage TZ_USER_CONTENT - /usr/share/security-manager/dummy http://tizen.org/privilege/mediastorage TZ_SYS_MEDIASHARED - /usr/share/security-manager/dummy +http://tizen.org/privilege/mediastorage /opt/usr/media - /usr/share/security-manager/dummy -- 2.7.4 From 8212d362ba456fc6ab71f88076128eb17514fa13 Mon Sep 17 00:00:00 2001 From: Radoslaw Bartosiak Date: Thu, 22 Sep 2016 12:23:48 +0200 Subject: [PATCH 03/16] Cleanup: remove unused and duplicated macros Change-Id: I2ded9109ae8b68c8879f649f0abf86eb4c0062d8 Signed-off-by: Radoslaw Bartosiak --- src/client/include/client-common.h | 1 - src/dpl/log/src/abstract_log_provider.cpp | 5 ++--- src/dpl/log/src/dlog_log_provider.cpp | 2 -- src/dpl/log/src/sd_journal_provider.cpp | 2 -- 4 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/client/include/client-common.h b/src/client/include/client-common.h index 659acfa..e9ff18e 100644 --- a/src/client/include/client-common.h +++ b/src/client/include/client-common.h @@ -28,7 +28,6 @@ #include #define SECURITY_MANAGER_API __attribute__((visibility("default"))) -#define SECURITY_MANAGER_UNUSED __attribute__((unused)) namespace SecurityManager { diff --git a/src/dpl/log/src/abstract_log_provider.cpp b/src/dpl/log/src/abstract_log_provider.cpp index 5b7574c..53d5416 100644 --- a/src/dpl/log/src/abstract_log_provider.cpp +++ b/src/dpl/log/src/abstract_log_provider.cpp @@ -20,15 +20,14 @@ * @brief This file is the implementation file of abstract log provider */ #include +#include #include #include -#define UNUSED __attribute__((unused)) - namespace SecurityManager { namespace Log { -void AbstractLogProvider::SetTag(const char *tag UNUSED) {} +void AbstractLogProvider::SetTag(const char *tag SECURITY_MANAGER_UNUSED) {} const char *AbstractLogProvider::LocateSourceFileName(const char *filename) { diff --git a/src/dpl/log/src/dlog_log_provider.cpp b/src/dpl/log/src/dlog_log_provider.cpp index 3341eeb..a8995ed 100644 --- a/src/dpl/log/src/dlog_log_provider.cpp +++ b/src/dpl/log/src/dlog_log_provider.cpp @@ -25,8 +25,6 @@ #include #include -#define UNUSED __attribute__((unused)) - namespace SecurityManager { namespace Log { std::string DLOGLogProvider::FormatMessage(const char *message, diff --git a/src/dpl/log/src/sd_journal_provider.cpp b/src/dpl/log/src/sd_journal_provider.cpp index bd570ca..b9f07cd 100644 --- a/src/dpl/log/src/sd_journal_provider.cpp +++ b/src/dpl/log/src/sd_journal_provider.cpp @@ -25,8 +25,6 @@ #include #include -#define UNUSED __attribute__((unused)) - namespace SecurityManager { namespace Log { std::string SdJournalProvider::FormatMessage(const char *message, -- 2.7.4 From 92c7dbf8b2f794fc0406e161e14cf0f75b0134d1 Mon Sep 17 00:00:00 2001 From: Rafal Krypa Date: Mon, 22 Jan 2018 12:54:14 +0100 Subject: [PATCH 04/16] Remove dependency on libslp-db-util DPL class SqlConnection had some small dependency on db-util, but this code path was never used in security-manager. Remove dependency to reduce memory requirements. Change-Id: I5551f71a7f665886aa6717bb3b39f0ce8e30ffb5 Signed-off-by: Rafal Krypa --- packaging/security-manager.spec | 3 +-- src/common/CMakeLists.txt | 2 +- src/dpl/db/src/sql_connection.cpp | 11 ++++++++++- test/CMakeLists.txt | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packaging/security-manager.spec b/packaging/security-manager.spec index 7f92776..35d85e8 100644 --- a/packaging/security-manager.spec +++ b/packaging/security-manager.spec @@ -19,7 +19,7 @@ Requires(post): sqlite3 Requires(post): smack BuildRequires: cmake BuildRequires: zip -# BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(dlog) BuildRequires: libattr-devel BuildRequires: pkgconfig(libprocps) BuildRequires: pkgconfig(libsmack) @@ -29,7 +29,6 @@ BuildRequires: pkgconfig(libsystemd-journal) BuildRequires: pkgconfig(libtzplatform-config) BuildRequires: tizen-platform-config-tools BuildRequires: pkgconfig(sqlite3) -BuildRequires: pkgconfig(db-util) BuildRequires: pkgconfig(cynara-admin) BuildRequires: pkgconfig(cynara-client-async) BuildRequires: pkgconfig(security-privilege-manager) diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 0f8f431..9a2f044 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -5,7 +5,7 @@ PKG_CHECK_MODULES(COMMON_DEP REQUIRED libsystemd libsmack - db-util + sqlite3 cynara-admin cynara-client-async libtzplatform-config diff --git a/src/dpl/db/src/sql_connection.cpp b/src/dpl/db/src/sql_connection.cpp index 0c70925..f6c5363 100644 --- a/src/dpl/db/src/sql_connection.cpp +++ b/src/dpl/db/src/sql_connection.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +//#include #include #include #include @@ -598,6 +598,7 @@ void SqlConnection::Connect(const std::string &address, // Connect to database int result; if (type & Flag::UseLucene) { +#ifdef DB_UTIL_LUCENE_INDEX result = db_util_open_with_options( address.c_str(), &m_connection, @@ -606,6 +607,10 @@ void SqlConnection::Connect(const std::string &address, m_usingLucene = true; LogDB("Lucene index enabled"); +#else + LogDB("Lucene support not compiled in!"); + Throw(Exception::InternalError); +#endif } else { result = sqlite3_open_v2( address.c_str(), @@ -644,9 +649,13 @@ void SqlConnection::Disconnect() int result; +#ifdef DB_UTIL_LUCENE_INDEX if (m_usingLucene) { result = db_util_close(m_connection); } else { +#else + { +#endif result = sqlite3_close(m_connection); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index edbce4a..c06fc5c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -21,7 +21,7 @@ PKG_CHECK_MODULES(COMMON_DEP REQUIRED libtzplatform-config libsystemd libsmack - db-util + sqlite3 cynara-admin cynara-client-async libtzplatform-config -- 2.7.4 From 27cd6f91c17d4d07322ecb26739384941cff72b2 Mon Sep 17 00:00:00 2001 From: Konrad Lipinski Date: Fri, 13 Jul 2018 13:21:59 +0200 Subject: [PATCH 05/16] Fix memleak in PrivilegeDb() PrivilegeDb::mSqlConnection would leak if an exception was thrown during PrivilegeDb(). Solved by: * making PrivilegeDb::mSqlConnection a member * making SqlConnection() noexcept * making SqlConnection::Connect() public Devirtualized and simplified some parts while at it. Change-Id: I48947fd63b6ea4a72fcd86491417f83a303ec238 --- src/common/include/privilege_db.h | 7 +++--- src/common/privilege_db.cpp | 18 +++++--------- src/dpl/db/include/dpl/db/sql_connection.h | 40 +++++++++++++++++------------- src/dpl/db/src/sql_connection.cpp | 21 +++------------- 4 files changed, 37 insertions(+), 49 deletions(-) diff --git a/src/common/include/privilege_db.h b/src/common/include/privilege_db.h index db40412..357379b 100644 --- a/src/common/include/privilege_db.h +++ b/src/common/include/privilege_db.h @@ -1,7 +1,7 @@ /* * security-manager, database access * - * Copyright (c) 2000 - 2016 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2018 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Rafal Krypa * @@ -110,7 +110,7 @@ private: DB::SqlConnection::DataCommandAutoPtr &m_ref; }; - SecurityManager::DB::SqlConnection *mSqlConnection; + SecurityManager::DB::SqlConnection mSqlConnection; const std::map Queries = { { StmtType::EAddApplication, "INSERT INTO user_app_pkg_view (app_name, pkg_name, uid, version, author_name, is_hybrid)" " VALUES (?, ?, ?, ?, ?, ?)" }, @@ -156,6 +156,8 @@ private: /** * Container for initialized DataCommands, prepared for binding. + * + * Destroyed before mSqlConnection. */ std::vector m_commands; @@ -187,7 +189,6 @@ public: DECLARE_EXCEPTION_TYPE(Base, ConstraintError) }; - ~PrivilegeDb(void); /** * Constructor * @exception PrivilegeDb::Exception::IOError on problems with database access diff --git a/src/common/privilege_db.cpp b/src/common/privilege_db.cpp index 644ad78..73f5c91 100644 --- a/src/common/privilege_db.cpp +++ b/src/common/privilege_db.cpp @@ -1,7 +1,7 @@ /* * security-manager, database access * - * Copyright (c) 2000 - 2016 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2018 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Rafal Krypa * @@ -80,7 +80,7 @@ PrivilegeDb::PrivilegeDb() : PrivilegeDb(getPrivilegeDbPath()) PrivilegeDb::PrivilegeDb(const std::string &path) { try { - mSqlConnection = new DB::SqlConnection(path, + mSqlConnection.Connect(path, DB::SqlConnection::Flag::None, DB::SqlConnection::Flag::RW); initDataCommands(); @@ -95,7 +95,7 @@ PrivilegeDb::PrivilegeDb(const std::string &path) void PrivilegeDb::initDataCommands() { for (auto &it : Queries) { - m_commands.push_back(mSqlConnection->PrepareDataCommand(it.second)); + m_commands.push_back(mSqlConnection.PrepareDataCommand(it.second)); } } @@ -117,12 +117,6 @@ PrivilegeDb::StatementWrapper PrivilegeDb::getStatement(StmtType queryType) return StatementWrapper(m_commands.at(static_cast(queryType))); } -PrivilegeDb::~PrivilegeDb() -{ - m_commands.clear(); - delete mSqlConnection; -} - PrivilegeDb &PrivilegeDb::getInstance() { static PrivilegeDb privilegeDb; @@ -132,21 +126,21 @@ PrivilegeDb &PrivilegeDb::getInstance() void PrivilegeDb::BeginTransaction(void) { try_catch([&] { - mSqlConnection->BeginTransaction(); + mSqlConnection.BeginTransaction(); }); } void PrivilegeDb::CommitTransaction(void) { try_catch([&] { - mSqlConnection->CommitTransaction(); + mSqlConnection.CommitTransaction(); }); } void PrivilegeDb::RollbackTransaction(void) { try_catch([&] { - mSqlConnection->RollbackTransaction(); + mSqlConnection.RollbackTransaction(); }); } diff --git a/src/dpl/db/include/dpl/db/sql_connection.h b/src/dpl/db/include/dpl/db/sql_connection.h index b86a65c..635572b 100644 --- a/src/dpl/db/include/dpl/db/sql_connection.h +++ b/src/dpl/db/include/dpl/db/sql_connection.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 - 2016 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2011 - 2018 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,7 +38,7 @@ namespace DB { /** * SQL connection class */ -class SqlConnection +class SqlConnection final { public: /** @@ -61,7 +61,7 @@ class SqlConnection /* * SQL processed data command */ - class DataCommand : + class DataCommand final : private Noncopyable { private: @@ -76,7 +76,7 @@ class SqlConnection friend class SqlConnection; public: - virtual ~DataCommand(); + ~DataCommand(); /** * Bind null to the prepared statement argument @@ -398,7 +398,7 @@ class SqlConnection virtual void NotifyAll() = 0; }; - protected: + private: sqlite3 *m_connection; // Options @@ -410,9 +410,7 @@ class SqlConnection // Synchronization object std::unique_ptr m_synchronizationObject; - virtual void Connect(const std::string &address, - Flag::Type = Flag::None, Flag::Option = Flag::RO); - virtual void Disconnect(); + void Disconnect(); void TurnOnForeignKeys(); @@ -428,27 +426,35 @@ class SqlConnection public: /** - * Open SQL connection + * Construct a disconnected SQL connection object * * Synchronization is archieved by using provided asynchronization object. * If synchronizationObject is set to NULL, so synchronization is performed. * Ownership of the synchronization object is transfered to sql connection * object. * - * @param address Database file name - * @param flags Open flags * @param synchronizationObject A synchronization object to use. */ - explicit SqlConnection(const std::string &address = std::string(), - Flag::Type flags = Flag::None, - Flag::Option options = Flag::RO, - SynchronizationObject *synchronizationObject = - AllocDefaultSynchronizationObject()); + explicit SqlConnection(SynchronizationObject *synchronizationObject = + AllocDefaultSynchronizationObject()) noexcept; + + /** + * Open SQL connection + * + * Called exactly once on a newly constructed object before using it. + * + * @param address Database file name + * @param type Open options (ie. use Lucene index or not) + * @param flag Open flags (ie. RO) + */ + void Connect(const std::string &address, + Flag::Type type = Flag::None, + Flag::Option flag = Flag::RO); /** * Destructor */ - virtual ~SqlConnection(); + ~SqlConnection(); /** * Execute BEGIN; command to start new transaction diff --git a/src/dpl/db/src/sql_connection.cpp b/src/dpl/db/src/sql_connection.cpp index f6c5363..9a9033e 100644 --- a/src/dpl/db/src/sql_connection.cpp +++ b/src/dpl/db/src/sql_connection.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2011 - 2018 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -589,10 +589,7 @@ void SqlConnection::Connect(const std::string &address, Flag::Type type, Flag::Option flag) { - if (m_connection != NULL) { - LogDB("Already connected."); - return; - } + Assert(!m_connection); LogDB("Connecting to DB: " << address << "..."); // Connect to database @@ -691,23 +688,13 @@ bool SqlConnection::CheckTableExist(const char *tableName) return command->GetColumnString(0) == tableName; } -SqlConnection::SqlConnection(const std::string &address, - Flag::Type flag, - Flag::Option option, - SynchronizationObject *synchronizationObject) : +SqlConnection::SqlConnection(SynchronizationObject *synchronizationObject) noexcept : m_connection(NULL), m_usingLucene(false), m_dataCommandsCount(0), m_synchronizationObject(synchronizationObject) { - LogDB("Opening database connection to: " << address); - - // Connect to DB - SqlConnection::Connect(address, flag, option); - - if (!m_synchronizationObject) { - LogDB("No synchronization object defined"); - } + Assert(m_synchronizationObject != NULL); } SqlConnection::~SqlConnection() -- 2.7.4 From 3aaf9f125ccd4bf762953981c47ebfae6b447d34 Mon Sep 17 00:00:00 2001 From: Konrad Lipinski Date: Thu, 12 Jul 2018 17:28:29 +0200 Subject: [PATCH 06/16] Sanitize privilege_db query storage * replace PrivilegeDb::Queries map with a static array * replace PrivilegeDb::m_commands vector with a fixed size array * make module require C++ 14 Rationale: * safety * efficiency * memory footprint Change-Id: If69ab4525c293ae836c1d35af19b8cebf7bbff57 --- CMakeLists.txt | 10 ++--- src/common/include/privilege_db.h | 48 ++-------------------- src/common/privilege_db.cpp | 83 ++++++++++++++++++++++++++++++++++----- 3 files changed, 83 insertions(+), 58 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dd6649c..a076ca5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,11 +49,11 @@ ADD_DEFINITIONS("-DPOLICY_DIR=\"${POLICY_DIR}\"") ############################# compiler flags ################################## -SET(CMAKE_CXX_FLAGS_PROFILING "-g -std=c++0x -O0 -pg -Wp,-U_FORTIFY_SOURCE") -SET(CMAKE_CXX_FLAGS_DEBUG "-g -std=c++0x -O0 -ggdb -Wp,-U_FORTIFY_SOURCE") -SET(CMAKE_CXX_FLAGS_RELEASE "-g -std=c++0x -O2") -SET(CMAKE_CXX_FLAGS_CCOV "-g -std=c++0x -O2 --coverage") -SET(CMAKE_CXX_FLAGS_VALGRIND "-ggdb -std=c++0x -O0 -fno-inline -Wp,-U_FORTIFY_SOURCE") +SET(CMAKE_CXX_FLAGS_PROFILING "-g -std=c++14 -O0 -pg -Wp,-U_FORTIFY_SOURCE") +SET(CMAKE_CXX_FLAGS_DEBUG "-g -std=c++14 -O0 -ggdb -Wp,-U_FORTIFY_SOURCE") +SET(CMAKE_CXX_FLAGS_RELEASE "-g -std=c++14 -O2") +SET(CMAKE_CXX_FLAGS_CCOV "-g -std=c++14 -O2 --coverage") +SET(CMAKE_CXX_FLAGS_VALGRIND "-ggdb -std=c++14 -O0 -fno-inline -Wp,-U_FORTIFY_SOURCE") # Force PIE SET(CMAKE_POSITION_INDEPENDENT_CODE "True") diff --git a/src/common/include/privilege_db.h b/src/common/include/privilege_db.h index 357379b..010c605 100644 --- a/src/common/include/privilege_db.h +++ b/src/common/include/privilege_db.h @@ -31,6 +31,7 @@ #pragma once +#include #include #include #include @@ -46,7 +47,7 @@ namespace SecurityManager { -enum class StmtType { +enum class StmtType : uint8_t { EAddApplication, ERemoveApplication, EPkgNameExists, @@ -87,6 +88,7 @@ enum class StmtType { EGetLicenseForClientPrivilegeAndPkg, EIsUserPkgInstalled, }; +enum : uint8_t { StmtTypeCount = static_cast(StmtType::EIsUserPkgInstalled) + 1 }; // privilege, app_defined_privilege_type, license typedef std::tuple AppDefinedPrivilege; @@ -111,55 +113,13 @@ private: }; SecurityManager::DB::SqlConnection mSqlConnection; - const std::map Queries = { - { StmtType::EAddApplication, "INSERT INTO user_app_pkg_view (app_name, pkg_name, uid, version, author_name, is_hybrid)" - " VALUES (?, ?, ?, ?, ?, ?)" }, - { StmtType::ERemoveApplication, "DELETE FROM user_app_pkg_view WHERE app_name=? AND uid=?" }, - { StmtType::EPkgNameExists, "SELECT count(*) FROM pkg WHERE name=?" }, - { StmtType::EAppNameExists, "SELECT count(*) FROM app WHERE name=?" }, - { StmtType::EGetAppPkgName, "SELECT pkg_name FROM user_app_pkg_view WHERE app_name = ?" }, - { StmtType::EGetAppVersion, "SELECT version FROM app WHERE name = ?" }, - { StmtType::EGetPathSharedCount, "SELECT COUNT(*) FROM app_private_sharing_view WHERE path = ?"}, - { StmtType::EGetTargetPathSharedCount, "SELECT COUNT(*) FROM app_private_sharing_view WHERE target_app_name = ? AND path = ?"}, - { StmtType::EGetOwnerTargetSharedCount, "SELECT COUNT(*) FROM app_private_sharing_view WHERE owner_app_name = ? AND target_app_name = ?"}, - { StmtType::EAddPrivatePathSharing, "INSERT INTO app_private_sharing_view(owner_app_name, target_app_name, path, path_label) VALUES(?, ?, ?, ?)"}, - { StmtType::ERemovePrivatePathSharing, "DELETE FROM app_private_sharing_view WHERE owner_app_name = ? AND target_app_name = ? AND path = ?"}, - { StmtType::EGetAllSharedPaths, "SELECT DISTINCT owner_app_name, path FROM app_private_sharing_view ORDER BY owner_app_name"}, - { StmtType::EGetSharingForOwner, "SELECT target_app_name, path FROM app_private_sharing_view WHERE owner_app_name = ?"}, - { StmtType::EGetSharingForTarget, "SELECT owner_app_name, path FROM app_private_sharing_view WHERE target_app_name = ?"}, - { StmtType::ESquashSharing, "UPDATE app_private_sharing_view SET counter = 1 WHERE target_app_name = ? AND path = ?"}, - { StmtType::EClearSharing, "DELETE FROM app_private_sharing;"}, - { StmtType::EClearPrivatePaths, "DELETE FROM shared_path;"}, - { StmtType::EGetUserApps, "SELECT app_name FROM user_app_pkg_view WHERE uid=?" }, - { StmtType::EGetUserAppsFromPkg, "SELECT app_name FROM user_app_pkg_view WHERE uid = ? AND pkg_name = ?" }, - { StmtType::EGetUserPkgs, "SELECT DISTINCT pkg_name FROM user_app_pkg_view WHERE uid=?" }, - { StmtType::EGetAllPackages, "SELECT DISTINCT pkg_name FROM user_app_pkg_view" }, - { StmtType::EGetAppsInPkg, " SELECT app_name FROM user_app_pkg_view WHERE pkg_name = ?" }, - { StmtType::EGetGroupsRelatedPrivileges, "SELECT DISTINCT group_name, privilege_name FROM privilege_group" }, - { StmtType::EGetPkgAuthorId, "SELECT author_id FROM pkg WHERE name = ? AND author_id IS NOT NULL"}, - { StmtType::EAuthorIdExists, "SELECT count(*) FROM author where author_id=?"}, - { StmtType::EGetAuthorIdByName, "SELECT author_id FROM author WHERE name=?"}, - { StmtType::ESetPackageSharedRO, "UPDATE pkg SET shared_ro=1 WHERE name=?"}, - { StmtType::EIsPackageSharedRO, "SELECT shared_ro FROM pkg WHERE name=?"}, - { StmtType::EIsPackageHybrid, "SELECT is_hybrid FROM pkg WHERE name=?"}, - { StmtType::EGetPackagesInfo, "SELECT name, shared_ro, is_hybrid FROM pkg"}, - { StmtType::EAddAppDefinedPrivilege, "INSERT INTO app_defined_privilege_view (app_name, uid, privilege, type, license) VALUES (?, ?, ?, ?, ?)"}, - { StmtType::EAddClientPrivilege, "INSERT INTO client_license_view (app_name, uid, privilege, license) VALUES (?, ?, ?, ?)"}, - { StmtType::ERemoveAppDefinedPrivileges, "DELETE FROM app_defined_privilege_view WHERE app_name = ? AND uid = ?"}, - { StmtType::ERemoveClientPrivileges, "DELETE FROM client_license_view WHERE app_name = ? AND uid = ?"}, - { StmtType::EGetAppDefinedPrivileges, "SELECT privilege, type, license FROM app_defined_privilege_view WHERE app_name = ? AND uid = ?"}, - { StmtType::EGetAppPkgLicenseForAppDefinedPrivilege, "SELECT app_name, pkg_name, license FROM app_defined_privilege_view WHERE uid = ? AND privilege = ?"}, - { StmtType::EGetLicenseForClientPrivilegeAndApp, "SELECT license FROM client_license_view WHERE app_name = ? AND uid = ? AND privilege = ? "}, - { StmtType::EGetLicenseForClientPrivilegeAndPkg, "SELECT license FROM client_license_view WHERE pkg_name = ? AND uid = ? AND privilege = ? "}, - { StmtType::EIsUserPkgInstalled, "SELECT count(*) FROM user_app_pkg_view WHERE pkg_name = ? AND uid = ?"}, - }; /** * Container for initialized DataCommands, prepared for binding. * * Destroyed before mSqlConnection. */ - std::vector m_commands; + std::array m_commands; /** * Fills empty m_commands map with sql commands prepared for binding. diff --git a/src/common/privilege_db.cpp b/src/common/privilege_db.cpp index 73f5c91..9e36e97 100644 --- a/src/common/privilege_db.cpp +++ b/src/common/privilege_db.cpp @@ -39,6 +39,70 @@ #include "filesystem.h" namespace SecurityManager { +namespace { + +constexpr const char *g_queries[StmtTypeCount] = { + [int(StmtType::EAddApplication)] = "INSERT INTO user_app_pkg_view (app_name, pkg_name, uid, version, author_name, is_hybrid)" + " VALUES (?, ?, ?, ?, ?, ?)", + [int(StmtType::ERemoveApplication)] = "DELETE FROM user_app_pkg_view WHERE app_name=? AND uid=?", + [int(StmtType::EPkgNameExists)] = "SELECT count(*) FROM pkg WHERE name=?", + [int(StmtType::EAppNameExists)] = "SELECT count(*) FROM app WHERE name=?", + [int(StmtType::EGetAppPkgName)] = "SELECT pkg_name FROM user_app_pkg_view WHERE app_name = ?", + [int(StmtType::EGetAppVersion)] = "SELECT version FROM app WHERE name = ?", + [int(StmtType::EGetPathSharedCount)] = "SELECT COUNT(*) FROM app_private_sharing_view WHERE path = ?", + [int(StmtType::EGetTargetPathSharedCount)] = "SELECT COUNT(*) FROM app_private_sharing_view WHERE target_app_name = ? AND path = ?", + [int(StmtType::EGetOwnerTargetSharedCount)] = "SELECT COUNT(*) FROM app_private_sharing_view WHERE owner_app_name = ? AND target_app_name = ?", + [int(StmtType::EAddPrivatePathSharing)] = "INSERT INTO app_private_sharing_view(owner_app_name, target_app_name, path, path_label) VALUES(?, ?, ?, ?)", + [int(StmtType::ERemovePrivatePathSharing)] = "DELETE FROM app_private_sharing_view WHERE owner_app_name = ? AND target_app_name = ? AND path = ?", + [int(StmtType::EGetAllSharedPaths)] = "SELECT DISTINCT owner_app_name, path FROM app_private_sharing_view ORDER BY owner_app_name", + [int(StmtType::EGetSharingForOwner)] = "SELECT target_app_name, path FROM app_private_sharing_view WHERE owner_app_name = ?", + [int(StmtType::EGetSharingForTarget)] = "SELECT owner_app_name, path FROM app_private_sharing_view WHERE target_app_name = ?", + [int(StmtType::ESquashSharing)] = "UPDATE app_private_sharing_view SET counter = 1 WHERE target_app_name = ? AND path = ?", + [int(StmtType::EClearSharing)] = "DELETE FROM app_private_sharing;", + [int(StmtType::EClearPrivatePaths)] = "DELETE FROM shared_path;", + [int(StmtType::EGetUserApps)] = "SELECT app_name FROM user_app_pkg_view WHERE uid=?", + [int(StmtType::EGetUserAppsFromPkg)] = "SELECT app_name FROM user_app_pkg_view WHERE uid = ? AND pkg_name = ?", + [int(StmtType::EGetUserPkgs)] = "SELECT DISTINCT pkg_name FROM user_app_pkg_view WHERE uid=?", + [int(StmtType::EGetAllPackages)] = "SELECT DISTINCT pkg_name FROM user_app_pkg_view", + [int(StmtType::EGetAppsInPkg)] = " SELECT app_name FROM user_app_pkg_view WHERE pkg_name = ?", + [int(StmtType::EGetGroupsRelatedPrivileges)] = "SELECT DISTINCT group_name, privilege_name FROM privilege_group", + [int(StmtType::EGetPkgAuthorId)] = "SELECT author_id FROM pkg WHERE name = ? AND author_id IS NOT NULL", + [int(StmtType::EAuthorIdExists)] = "SELECT count(*) FROM author where author_id=?", + [int(StmtType::EGetAuthorIdByName)] = "SELECT author_id FROM author WHERE name=?", + [int(StmtType::ESetPackageSharedRO)] = "UPDATE pkg SET shared_ro=1 WHERE name=?", + [int(StmtType::EIsPackageSharedRO)] = "SELECT shared_ro FROM pkg WHERE name=?", + [int(StmtType::EIsPackageHybrid)] = "SELECT is_hybrid FROM pkg WHERE name=?", + [int(StmtType::EGetPackagesInfo)] = "SELECT name, shared_ro, is_hybrid FROM pkg", + [int(StmtType::EAddAppDefinedPrivilege)] = "INSERT INTO app_defined_privilege_view (app_name, uid, privilege, type, license) VALUES (?, ?, ?, ?, ?)", + [int(StmtType::EAddClientPrivilege)] = "INSERT INTO client_license_view (app_name, uid, privilege, license) VALUES (?, ?, ?, ?)", + [int(StmtType::ERemoveAppDefinedPrivileges)] = "DELETE FROM app_defined_privilege_view WHERE app_name = ? AND uid = ?", + [int(StmtType::ERemoveClientPrivileges)] = "DELETE FROM client_license_view WHERE app_name = ? AND uid = ?", + [int(StmtType::EGetAppDefinedPrivileges)] = "SELECT privilege, type, license FROM app_defined_privilege_view WHERE app_name = ? AND uid = ?", + [int(StmtType::EGetAppPkgLicenseForAppDefinedPrivilege)] = "SELECT app_name, pkg_name, license FROM app_defined_privilege_view WHERE uid = ? AND privilege = ?", + [int(StmtType::EGetLicenseForClientPrivilegeAndApp)] = "SELECT license FROM client_license_view WHERE app_name = ? AND uid = ? AND privilege = ? ", + [int(StmtType::EGetLicenseForClientPrivilegeAndPkg)] = "SELECT license FROM client_license_view WHERE pkg_name = ? AND uid = ? AND privilege = ? ", + [int(StmtType::EIsUserPkgInstalled)] = "SELECT count(*) FROM user_app_pkg_view WHERE pkg_name = ? AND uid = ?", +}; + +template +constexpr bool allTrue(T (&array)[S]) { + for (auto &a : array) { + if (!a) + return false; + } + return true; +} + +static_assert(allTrue(g_queries)); + +template +constexpr const char *query = g_queries[size_t(i)]; + +template +constexpr void destroyAt(T *p) { + p->~T(); +} +} //namespace /* Common code for handling SqlConnection exceptions */ template @@ -94,8 +158,9 @@ PrivilegeDb::PrivilegeDb(const std::string &path) void PrivilegeDb::initDataCommands() { - for (auto &it : Queries) { - m_commands.push_back(mSqlConnection.PrepareDataCommand(it.second)); + for (size_t i = 0; i < StmtTypeCount; i++) { + m_commands[i] = mSqlConnection.PrepareDataCommand(g_queries[i]); + Assert(m_commands[i]); } } @@ -114,7 +179,7 @@ DB::SqlConnection::DataCommand* PrivilegeDb::StatementWrapper::operator->() PrivilegeDb::StatementWrapper PrivilegeDb::getStatement(StmtType queryType) { - return StatementWrapper(m_commands.at(static_cast(queryType))); + return StatementWrapper(m_commands[int(queryType)]); } PrivilegeDb &PrivilegeDb::getInstance() @@ -221,7 +286,7 @@ void PrivilegeDb::AddApplication( if (command->Step()) { LogDebug("Unexpected SQLITE_ROW answer to query: " << - Queries.at(StmtType::EAddApplication)); + query); }; LogDebug("Added appName: " << appName << ", pkgName: " << pkgName); @@ -251,7 +316,7 @@ void PrivilegeDb::RemoveApplication( if (command->Step()) { LogDebug("Unexpected SQLITE_ROW answer to query: " << - Queries.at(StmtType::ERemoveApplication)); + query); }; LogDebug("Removed appName: " << appName); @@ -600,7 +665,7 @@ void PrivilegeDb::AddAppDefinedPrivilege(const std::string &appName, uid_t uid, if (command->Step()) { LogDebug("Unexpected SQLITE_ROW answer to query: " << - Queries.at(StmtType::EAddAppDefinedPrivilege)); + query); } LogDebug("Added privilege: " << std::get<0>(privilege) << " defined by: " << appName << @@ -627,7 +692,7 @@ void PrivilegeDb::AddClientPrivilege(const std::string &appName, uid_t uid, cons if (command->Step()) { LogDebug("Unexpected SQLITE_ROW answer to query: " << - Queries.at(StmtType::EAddClientPrivilege)); + query); } LogDebug("Added privilege: " << privilege << " license: " << license << @@ -644,7 +709,7 @@ void PrivilegeDb::RemoveAppDefinedPrivileges(const std::string &appName, uid_t u if (command->Step()) { LogDebug("Unexpected SQLITE_ROW answer to query: " << - Queries.at(StmtType::ERemoveAppDefinedPrivileges)); + query); }; LogDebug("Removed privileges defined by: " << appName << " and user: " << uid); @@ -660,7 +725,7 @@ void PrivilegeDb::RemoveClientPrivileges(const std::string &appName, uid_t uid) if (command->Step()) { LogDebug("Unexpected SQLITE_ROW answer to query: " << - Queries.at(StmtType::ERemoveClientPrivileges)); + query); }; LogDebug("Removed privileges used by: " << appName << " and user: " << uid); -- 2.7.4 From 751ae6b9269514e49419580ed7d61e276ead4403 Mon Sep 17 00:00:00 2001 From: Konrad Lipinski Date: Mon, 16 Jul 2018 11:28:14 +0200 Subject: [PATCH 07/16] Pull db migration into manager binary at startup Done at VD's request to make concurrent db access less likely. Update scripts and the schema are no longer present at runtime. Migration is performed in privilege_db.h instead, based on src/gen/db.h generated at build time from db/{db.sql,updates/*}. Change-Id: I35e09390b45b4b82a892f92f356eba6f55287268 --- CMakeLists.txt | 3 +- db/240.security-manager.db-update.sh | 7 -- db/CMakeLists.txt | 28 +++-- db/db_test_v0.sql | 185 +++++++++++++++++++++++++++++ db/generate.sh | 42 +++++++ db/update.sh | 53 --------- packaging/security-manager.spec | 18 ++- src/common/CMakeLists.txt | 4 + src/common/privilege_db.cpp | 72 +++++++++-- src/dpl/db/include/dpl/db/sql_connection.h | 16 +-- test/CMakeLists.txt | 8 ++ test/privilege_db_fixture.cpp | 42 ++++--- test/privilege_db_fixture.h | 10 +- test/test_privilege_db_migration.cpp | 146 +++++++++++++++++++++++ 14 files changed, 518 insertions(+), 116 deletions(-) delete mode 100755 db/240.security-manager.db-update.sh create mode 100644 db/db_test_v0.sql create mode 100755 db/generate.sh delete mode 100755 db/update.sh create mode 100644 test/test_privilege_db_migration.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a076ca5..0812b0e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2011 - 2016 Samsung Electronics Co., Ltd All Rights Reserved +# Copyright (c) 2011 - 2018 Samsung Electronics Co., Ltd All Rights Reserved # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -95,6 +95,7 @@ SET(DPL_PATH ${PROJECT_SOURCE_DIR}/src/dpl) SET(CMD_PATH ${PROJECT_SOURCE_DIR}/src/cmd) SET(NSS_PATH ${PROJECT_SOURCE_DIR}/src/nss) SET(LM_COMMON_PATH ${PROJECT_SOURCE_DIR}/src/license-manager/common) +SET(GEN_PATH ${PROJECT_SOURCE_DIR}/src/gen) SET(TARGET_SERVER "security-manager") SET(TARGET_CLIENT "security-manager-client") diff --git a/db/240.security-manager.db-update.sh b/db/240.security-manager.db-update.sh deleted file mode 100755 index a330b32..0000000 --- a/db/240.security-manager.db-update.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -e - -PATH=/bin:/usr/bin:/sbin:/usr/sbin - -. /etc/tizen-platform.conf - -exec "$TZ_SYS_RO_SHARE/security-manager/db/update.sh" diff --git a/db/CMakeLists.txt b/db/CMakeLists.txt index e1d8f57..ae81fe0 100644 --- a/db/CMakeLists.txt +++ b/db/CMakeLists.txt @@ -1,10 +1,22 @@ -SET(DB_SCRIPT_DIR "${DATA_ROOT_DIR}/${PROJECT_NAME}/db") -SET(FOTA_DIR "${SYSCONF_INSTALL_DIR}/opt/upgrade") +# Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. -# Update scrpipts -INSTALL(FILES update.sh DESTINATION ${DB_SCRIPT_DIR}) -INSTALL(DIRECTORY updates DESTINATION ${DB_SCRIPT_DIR}) -INSTALL(FILES db.sql DESTINATION ${DB_SCRIPT_DIR}) +SET(GEN_FILE ${GEN_PATH}/db.h) +SET(GENERATOR "./generate.sh") -# FOTA updater -INSTALL(FILES 240.security-manager.db-update.sh DESTINATION ${FOTA_DIR}) +ADD_CUSTOM_COMMAND(OUTPUT ${GEN_FILE} + COMMAND ${GENERATOR} ${GEN_FILE} + DEPENDS ${GENERATOR} "db.sql" "updates/*" +) +ADD_CUSTOM_TARGET(generate DEPENDS ${GEN_FILE}) diff --git a/db/db_test_v0.sql b/db/db_test_v0.sql new file mode 100644 index 0000000..b1d3630 --- /dev/null +++ b/db/db_test_v0.sql @@ -0,0 +1,185 @@ +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE pkg ( +pkg_id INTEGER PRIMARY KEY, +name VARCHAR NOT NULL, +UNIQUE (name) +); +CREATE TABLE app ( +app_id INTEGER PRIMARY KEY, +pkg_id INTEGER NOT NULL, +uid INTEGER NOT NULL, +name VARCHAR NOT NULL, +version VARCHAR NOT NULL, +author_id INTEGER, +UNIQUE (name, uid), +FOREIGN KEY (pkg_id) REFERENCES pkg (pkg_id) +FOREIGN KEY (author_id) REFERENCES author (author_id) +); +CREATE TABLE privilege ( +privilege_id INTEGER PRIMARY KEY, +name VARCHAR NOT NULL, +UNIQUE (name) +); +INSERT INTO privilege VALUES(1,'http://tizen.org/privilege/camera'); +INSERT INTO privilege VALUES(2,'http://tizen.org/privilege/recorder'); +INSERT INTO privilege VALUES(3,'http://tizen.org/privilege/mediastorage'); +INSERT INTO privilege VALUES(4,'http://tizen.org/privilege/externalstorage'); +INSERT INTO privilege VALUES(5,'http://tizen.org/privilege/message.read'); +CREATE TABLE version ( +version_id INTEGER PRIMARY KEY, +name VARCHAR NOT NULL, +UNIQUE (name) +); +CREATE TABLE app_privilege ( +app_id INTEGER NOT NULL, +privilege_id INTEGER NOT NULL , +PRIMARY KEY (app_id, privilege_id), +FOREIGN KEY (app_id) REFERENCES app (app_id) +FOREIGN KEY (privilege_id) REFERENCES privilege (privilege_id) +); +CREATE TABLE shared_path ( +path_id INTEGER PRIMARY KEY, +path VARCHAR NOT NULL, +path_label VARCHAR NOT NULL, +UNIQUE (path) +); +CREATE TABLE app_private_sharing ( +owner_app_id INTEGER NOT NULL, +target_app_id INTEGER NOT NULL, +path_id INTEGER NOT NULL, +counter INTEGER NOT NULL, +PRIMARY KEY (owner_app_id, target_app_id, path_id) +FOREIGN KEY (owner_app_id) REFERENCES app (app_id) +FOREIGN KEY (target_app_id) REFERENCES app (app_id) +FOREIGN KEY (path_id) REFERENCES shared_path (path_id) +); +CREATE TABLE privilege_group ( +privilege_id INTEGER NOT NULL, +group_name VARCHAR NOT NULL, +PRIMARY KEY (privilege_id, group_name), +FOREIGN KEY (privilege_id) REFERENCES privilege (privilege_id) +); +INSERT INTO privilege_group VALUES(1,'priv_camera'); +INSERT INTO privilege_group VALUES(2,'priv_recorder'); +INSERT INTO privilege_group VALUES(3,'priv_mediastorage'); +INSERT INTO privilege_group VALUES(4,'priv_externalstorage'); +INSERT INTO privilege_group VALUES(5,'priv_message_read'); +CREATE TABLE author ( + author_id INTEGER PRIMARY KEY, + name VARCHAR NOT NULL, + UNIQUE (name) +); +CREATE VIEW app_privilege_view AS +SELECT + app_privilege.app_id as app_id, + app.name as app_name, + app.uid as uid, + app.pkg_id as pkg_id, + pkg.name as pkg_name, + app_privilege.privilege_id as privilege_id, + privilege.name as privilege_name +FROM app_privilege +LEFT JOIN app USING (app_id) +LEFT JOIN pkg USING (pkg_id) +LEFT JOIN privilege USING (privilege_id); +CREATE VIEW app_pkg_view AS +SELECT + app.app_id, + app.name as app_name, + app.pkg_id, + app.uid, + pkg.name as pkg_name, + app.version as version, + app.author_id, + author.name as author_name +FROM app +LEFT JOIN pkg USING (pkg_id) +LEFT JOIN author USING (author_id); +CREATE TRIGGER app_privilege_view_insert_trigger +INSTEAD OF INSERT ON app_privilege_view +BEGIN + INSERT OR IGNORE INTO privilege(name) VALUES (NEW.privilege_name); + INSERT OR IGNORE INTO app_privilege(app_id, privilege_id) VALUES + ((SELECT app_id FROM app WHERE name=NEW.app_name AND uid=NEW.uid), + (SELECT privilege_id FROM privilege WHERE name=NEW.privilege_name)); +END; +CREATE TRIGGER app_privilege_view_delete_trigger +INSTEAD OF DELETE ON app_privilege_view +BEGIN + DELETE FROM app_privilege WHERE app_id=OLD.app_id AND privilege_id=OLD.privilege_id; +END; +CREATE TRIGGER app_pkg_view_insert_trigger +INSTEAD OF INSERT ON app_pkg_view +BEGIN + INSERT OR IGNORE INTO author(name) VALUES (NEW.author_name); + INSERT OR IGNORE INTO pkg(name) VALUES (NEW.pkg_name); + INSERT OR IGNORE INTO app(pkg_id, name, uid, version, author_id) VALUES ( + (SELECT pkg_id FROM pkg WHERE name=NEW.pkg_name), + NEW.app_name, + NEW.uid, + NEW.version, + (SELECT author_id FROM author WHERE name=NEW.author_name)); +END; +CREATE TRIGGER app_pkg_view_delete_trigger +INSTEAD OF DELETE ON app_pkg_view +BEGIN + DELETE FROM app WHERE app_id=OLD.app_id AND uid=OLD.uid; + DELETE FROM pkg WHERE pkg_id NOT IN (SELECT DISTINCT pkg_id from app); +END; +CREATE VIEW app_private_sharing_view AS +SELECT + app1.name AS owner_app_name, + app2.name AS target_app_name, + path, + path_label, + counter +FROM app_private_sharing +LEFT JOIN app AS app1 ON app1.app_id = owner_app_id +LEFT JOIN app AS app2 ON app2.app_id = target_app_id +LEFT JOIN shared_path USING (path_id); +CREATE TRIGGER app_private_sharing_view_insert_trigger +INSTEAD OF INSERT ON app_private_sharing_view +BEGIN + INSERT OR IGNORE INTO shared_path(path, path_label) VALUES (NEW.path, NEW.path_label); + INSERT OR REPLACE INTO app_private_sharing VALUES ( + (SELECT app_id FROM app WHERE NEW.owner_app_name = name), + (SELECT app_id FROM app WHERE NEW.target_app_name = name), + (SELECT path_id FROM shared_path WHERE NEW.path = path), + COALESCE((SELECT counter FROM app_private_sharing + WHERE target_app_id = (SELECT app_id FROM app + WHERE NEW.target_app_name = name) + AND path_id = (SELECT path_id FROM shared_path WHERE NEW.path = path)), + 0) + 1); +END; +CREATE TRIGGER app_private_sharing_view_remove_delete_trigger +INSTEAD OF DELETE ON app_private_sharing_view +WHEN OLD.counter = 1 +BEGIN + DELETE FROM app_private_sharing + WHERE path_id = (SELECT path_id FROM shared_path WHERE path = OLD.path) + AND target_app_id = (SELECT app_id FROM app WHERE name = OLD.target_app_name); + DELETE FROM shared_path WHERE path_id NOT IN (SELECT path_id FROM app_private_sharing) AND path = OLD.path; +END; +CREATE TRIGGER app_private_sharing_view_decrement_delete_trigger +INSTEAD OF DELETE ON app_private_sharing_view +WHEN OLD.counter > 1 +BEGIN + UPDATE app_private_sharing SET counter = OLD.counter - 1 + WHERE target_app_id = (SELECT app_id FROM app WHERE name = OLD.target_app_name) + AND path_id = (SELECT path_id FROM shared_path WHERE path = OLD.path); +END; +CREATE VIEW privilege_group_view AS +SELECT + privilege_id, + privilege.name as privilege_name, + privilege_group.group_name +FROM privilege_group +LEFT JOIN privilege USING (privilege_id); +CREATE TRIGGER privilege_group_view_insert_trigger +INSTEAD OF INSERT ON privilege_group_view +BEGIN + INSERT OR IGNORE INTO privilege(name) VALUES (NEW.privilege_name); + INSERT OR IGNORE INTO privilege_group(privilege_id, group_name) VALUES ((SELECT privilege_id FROM privilege WHERE name=NEW.privilege_name), NEW.group_name); +END; +COMMIT; diff --git a/db/generate.sh b/db/generate.sh new file mode 100755 index 0000000..6674a59 --- /dev/null +++ b/db/generate.sh @@ -0,0 +1,42 @@ +#!/bin/sh -e + +# Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +die() { + echo "Error: $@" + exit 2 +} +[ $# -eq 1 ] || die "Need exactly one argument" +outfile="$1" + +db_main='db.sql' +db_version="$(grep 'PRAGMA user_version' "$db_main" | sed -r 's/.* ([1-9][0-9]+).*/\1/')" +[ -z "$db_version" ] && die "Unable to retrieve database version" + +transliterate() { + echo -n '"' + hexdump -ve '/1 " x%02x"' | tr ' ' '\\' + echo -n '"' +} + +mkdir -p "$(dirname "$outfile")" +printf 'constexpr int32_t dbVersion = %d;\n' $db_version >"$outfile" +printf 'constexpr char dbSchema[] = %s;\n' "$(transliterate <"$db_main")" >>"$outfile" +echo 'constexpr const char *dbUpdateScript[] = {' >>"$outfile" +for i in $(seq 1 $db_version); do + db_update_file="updates/update-db-to-v$i.sql" + printf '%s,\n' "$(transliterate <"updates/update-db-to-v$i.sql")" >>"$outfile" +done +echo '};' >>"$outfile" diff --git a/db/update.sh b/db/update.sh deleted file mode 100755 index 7caa474..0000000 --- a/db/update.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/sh -e - -# @file -# @author Lukasz Kostyra (l.kostyra@samsung.com) -# @brief Security-manager Database Updater script - -source /etc/tizen-platform.conf - -# Some useful constants -PATH=/bin:/usr/bin:/sbin:/usr/sbin -db="$TZ_SYS_DB/.security-manager.db" -db_journal="$db-journal" -sm_dir="/usr/share/security-manager/db" -db_updates="$sm_dir/updates" -db_update_file_prefix="update-db-to-v" -db_main="$sm_dir/db.sql" -sqlitecmd="sqlite3" - -[ ! -f $db_main ] && echo "Main DB schema not found!" && exit 1 -[ ! -e $db ] && echo "Database not found!" && exit 1 - -if [ `stat -c %s $db` -eq 0 ] -then - echo "Database empty, creating from scratch." - $sqlitecmd "$db" < "$db_main" - exit -fi - -[ ! -d $db_updates ] && echo "Update scripts are not found!" && exit 1 - -# Extract current db version and target version -db_version="`\"$sqlitecmd\" \"$db\" 'PRAGMA user_version;'`" -db_pragma_user="`grep 'PRAGMA user_version' $db_main`" -db_version_new="`echo \"$db_pragma_user\" | sed -r 's/.* ([0-9]+).*/\1/'`" - -echo "Current version: $db_version; version to update: $db_version_new" - -[ -z "$db_version_new" ] && echo "Unable to parse new DB version - missing PRAGMA user_version?" && exit 1 -[ $db_version -eq $db_version_new ] && echo "Database is already up to date." && exit -[ $db_version -gt $db_version_new ] && echo "Downgrading is not possible with this tool." && exit 1 - -# Update loop - apply all updates in order -for i in `seq $((db_version+1)) $db_version_new` -do - echo "Updating $db to v$i (target version is $db_version_new)" - db_update="$db_updates/$db_update_file_prefix$i.sql" - [ ! -e "$db_update" ] && echo "Missing update script $db_update" && exit 1 - $sqlitecmd "$db" < "$db_update" -done - -# Finally, introduce our main db.sql to update views and others -echo "Applying new views and changes from main schema" -$sqlitecmd "$db" < "$db_main" diff --git a/packaging/security-manager.spec b/packaging/security-manager.spec index 35d85e8..73fe3ed 100644 --- a/packaging/security-manager.spec +++ b/packaging/security-manager.spec @@ -84,6 +84,7 @@ Set of security rules that constitute security policy in the system %package -n security-manager-tests Summary: Security manager unit test binaries Group: Security/Development +Requires: boost-iostreams Requires: boost-test %description -n security-manager-tests @@ -143,6 +144,9 @@ install -m 0444 /dev/null %{buildroot}%{TZ_SYS_VAR}/security-manager/policy-vers mkdir -p %{buildroot}/%{db_test_dir} sqlite3 %{buildroot}/%{db_test_dir}/.security-manager-test.db < db/db.sql +sqlite3 %{buildroot}/%{db_test_dir}/.security-manager-test-v0.db < db/db_test_v0.sql +echo -n > %{buildroot}/%{db_test_dir}/.security-manager-test-empty.db +echo -n > %{buildroot}/%{db_test_dir}/.security-manager-test-empty.db-journal cp -a %{SOURCE1} %{SOURCE3} %{SOURCE4} %{SOURCE5} %{buildroot}%{_datadir}/ @@ -154,7 +158,6 @@ rm -rf %{buildroot} systemctl daemon-reload if [ $1 = 1 ]; then # installation - %{_datadir}/security-manager/db/update.sh systemctl start security-manager.socket systemctl start security-manager.service fi @@ -164,7 +167,6 @@ if [ $1 = 2 ]; then systemctl stop security-manager.socket systemctl stop security-manager.service %{_bindir}/security-manager-migration - %{_datadir}/security-manager/db/update.sh systemctl start security-manager.socket systemctl start security-manager.service fi @@ -236,6 +238,10 @@ fi %post -n security-manager-tests chsmack -a System %{db_test_dir}/.security-manager-test.db chsmack -a System %{db_test_dir}/.security-manager-test.db-journal +chsmack -a System %{db_test_dir}/.security-manager-test-v0.db +chsmack -a System %{db_test_dir}/.security-manager-test-v0.db-journal +chsmack -a System %{db_test_dir}/.security-manager-test-empty.db +chsmack -a System %{db_test_dir}/.security-manager-test-empty.db-journal %files -n security-manager %manifest %{_datadir}/security-manager.manifest @@ -263,10 +269,6 @@ chsmack -a System %{db_test_dir}/.security-manager-test.db-journal %config(noreplace) %attr(0600,root,root) %{TZ_SYS_DB}/.security-manager.db %config(noreplace) %attr(0600,root,root) %{TZ_SYS_DB}/.security-manager.db-journal -%{_datadir}/security-manager/db -%attr(755,root,root) %{_datadir}/%{name}/db/update.sh -%attr(755,root,root) %{_sysconfdir}/opt/upgrade/240.security-manager.db-update.sh - %dir %attr(700,root,root) %{_datadir}/%{name}/dummy/ %files -n libsecurity-manager-client @@ -304,6 +306,10 @@ chsmack -a System %{db_test_dir}/.security-manager-test.db-journal %attr(755,root,root) %{_bindir}/security-manager-performance-tests %attr(0600,root,root) %{db_test_dir}/.security-manager-test.db %attr(0600,root,root) %{db_test_dir}/.security-manager-test.db-journal +%attr(0600,root,root) %{db_test_dir}/.security-manager-test-v0.db +%attr(0600,root,root) %{db_test_dir}/.security-manager-test-v0.db-journal +%attr(0600,root,root) %{db_test_dir}/.security-manager-test-empty.db +%attr(0600,root,root) %{db_test_dir}/.security-manager-test-empty.db-journal %files -n security-license-manager %{_libdir}/cynara/plugin/client/liblicense-manager-plugin-client.so diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 9a2f044..e8b72cd 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -73,6 +73,7 @@ SET(COMMON_SOURCES ${COMMON_PATH}/mount-namespace.cpp ${COMMON_PATH}/mount-monitor.cpp ${COMMON_PATH}/service-file-locker.cpp + ${GEN_PATH}/db.h ) IF(DPL_WITH_DLOG) @@ -91,6 +92,9 @@ LINK_DIRECTORIES(${COMMON_DEP_LIBRARY_DIRS} ${DLOG_DEP_LIBRARY_DIRS}) ADD_LIBRARY(${TARGET_COMMON} SHARED ${COMMON_SOURCES}) +SET_SOURCE_FILES_PROPERTIES(${GEN_PATH}/db.h PROPERTIES GENERATED 1) +ADD_DEPENDENCIES(${TARGET_COMMON} generate) + SET_TARGET_PROPERTIES(${TARGET_COMMON} PROPERTIES COMPILE_FLAGS "-D_GNU_SOURCE -fvisibility=default" diff --git a/src/common/privilege_db.cpp b/src/common/privilege_db.cpp index 9e36e97..408a9c9 100644 --- a/src/common/privilege_db.cpp +++ b/src/common/privilege_db.cpp @@ -23,6 +23,7 @@ * @file privilege_db.cpp * @author Krzysztof Sasiak * @author Rafal Krypa + * @author Konrad Lipinski * @version 0.1 * @brief This file contains declaration of the API to privileges database. */ @@ -32,8 +33,10 @@ #include #include #include +#include #include +#include "../gen/db.h" #include "privilege_db.h" #include "tzplatform-config.h" #include "filesystem.h" @@ -41,6 +44,16 @@ namespace SecurityManager { namespace { +namespace detail { +template +uint8_t(&arraySizeHelper(T (&)[S]))[S]; + +template +uint8_t(&arraySizeHelper(std::array const &))[S]; +} //namespace detail + +#define arraySize(A) (sizeof(detail::arraySizeHelper((A)))) + constexpr const char *g_queries[StmtTypeCount] = { [int(StmtType::EAddApplication)] = "INSERT INTO user_app_pkg_view (app_name, pkg_name, uid, version, author_name, is_hybrid)" " VALUES (?, ?, ?, ?, ?, ?)", @@ -102,6 +115,52 @@ template constexpr void destroyAt(T *p) { p->~T(); } + +static_assert(dbSchema); +// this ensures that parsing the sql files was done correctly and we have proper +// number of update scripts +static_assert(dbVersion == arraySize(dbUpdateScript)); +static_assert(allTrue(dbUpdateScript)); + +auto prepare(DB::SqlConnection &db, const char *fmt) { + Assert(fmt); + auto cmd = db.PrepareDataCommand(fmt); + Assert(cmd); + return cmd; +} + +std::string getPrivilegeDbPath() +{ + static std::string path = TizenPlatformConfig::makePath(TZ_SYS_DB, ".security-manager.db"); + return path; +} + +bool dbEmpty(const std::string &dbPath) { + struct stat buf; + if (-1 == stat(dbPath.c_str(), &buf)) + ThrowMsg(DB::SqlConnection::Exception::Base, "Failed to stat db file"); + return !buf.st_size; +} + +void migrate(DB::SqlConnection &db, const std::string &path) { + using Ex = DB::SqlConnection::Exception::Base; + int32_t version; + { + auto cmd = prepare(db, "PRAGMA user_version"); + if (!cmd->Step()) + ThrowMsg(Ex, "Error getting database version"); + version = cmd->GetColumnInt32(0); + } + if (version != dbVersion) { + if (version < 0) + ThrowMsg(Ex, "Corrupted database version: " << version); + if (version > dbVersion) + ThrowMsg(Ex, "Database downgrade not supported; db version: " << version << ", manager binary version: " << dbVersion); + if (version || !dbEmpty(path)) + do db.ExecCommand(dbUpdateScript[version]); while (++version < dbVersion); + db.ExecCommand(dbSchema); + } +} } //namespace /* Common code for handling SqlConnection exceptions */ @@ -125,12 +184,6 @@ T try_catch(const std::function &func) } } -std::string getPrivilegeDbPath() -{ - static std::string path = TizenPlatformConfig::makePath(TZ_SYS_DB, ".security-manager.db"); - return path; -} - std::string getPrivilegeDbFailFlagPath() { static std::string path = TizenPlatformConfig::makePath(TZ_SYS_DB, ".security-manager.db-broken"); @@ -147,6 +200,7 @@ PrivilegeDb::PrivilegeDb(const std::string &path) mSqlConnection.Connect(path, DB::SqlConnection::Flag::None, DB::SqlConnection::Flag::RW); + migrate(mSqlConnection, path); initDataCommands(); } catch (DB::SqlConnection::Exception::Base &e) { LogError("Database initialization error: " << e.DumpToString()); @@ -158,10 +212,8 @@ PrivilegeDb::PrivilegeDb(const std::string &path) void PrivilegeDb::initDataCommands() { - for (size_t i = 0; i < StmtTypeCount; i++) { - m_commands[i] = mSqlConnection.PrepareDataCommand(g_queries[i]); - Assert(m_commands[i]); - } + for (size_t i = 0; i < StmtTypeCount; i++) + m_commands[i] = prepare(mSqlConnection, g_queries[i]); } PrivilegeDb::StatementWrapper::StatementWrapper(DB::SqlConnection::DataCommandAutoPtr &ref) diff --git a/src/dpl/db/include/dpl/db/sql_connection.h b/src/dpl/db/include/dpl/db/sql_connection.h index 635572b..d5ac797 100644 --- a/src/dpl/db/include/dpl/db/sql_connection.h +++ b/src/dpl/db/include/dpl/db/sql_connection.h @@ -416,14 +416,6 @@ class SqlConnection final static SynchronizationObject *AllocDefaultSynchronizationObject(); - /** - * Execute SQL command without result - * - * @param format - * @param ... - */ - void ExecCommand(const std::string &format); - public: /** * Construct a disconnected SQL connection object @@ -483,6 +475,14 @@ class SqlConnection final DataCommandAutoPtr PrepareDataCommand(const std::string &format); /** + * Execute SQL command without result + * + * @param format + * @param ... + */ + void ExecCommand(const std::string &format); + + /** * Check whether given table exists * * @param tableName Name of the table to check diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c06fc5c..e1fcd2d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -59,6 +59,7 @@ SET(SM_TESTS_SOURCES ${SM_TEST_SRC}/test_privilege_db_privilege.cpp ${SM_TEST_SRC}/test_privilege_db_sharing.cpp ${SM_TEST_SRC}/test_privilege_db_app_defined_privileges.cpp + ${SM_TEST_SRC}/test_privilege_db_migration.cpp ${SM_TEST_SRC}/test_smack-labels.cpp ${SM_TEST_SRC}/test_smack-rules.cpp ${DPL_PATH}/core/src/assert.cpp @@ -79,6 +80,7 @@ SET(SM_TESTS_SOURCES ${PROJECT_SOURCE_DIR}/src/common/smack-rules.cpp ${PROJECT_SOURCE_DIR}/src/common/filesystem.cpp ${PROJECT_SOURCE_DIR}/src/common/tzplatform-config.cpp + ${GEN_PATH}/db.h ) SET(SM_PERFORMANCE_TESTS_SOURCES @@ -104,6 +106,7 @@ SET(SM_PERFORMANCE_TESTS_SOURCES #${PROJECT_SOURCE_DIR}/src/common/smack-rules.cpp ${PROJECT_SOURCE_DIR}/src/common/filesystem.cpp ${PROJECT_SOURCE_DIR}/src/common/tzplatform-config.cpp + ${GEN_PATH}/db.h ) IF(DPL_WITH_DLOG) @@ -142,10 +145,15 @@ INCLUDE_DIRECTORIES( ADD_EXECUTABLE(${TARGET_SM_TESTS} ${SM_TESTS_SOURCES}) ADD_EXECUTABLE(${TARGET_SM_PERFORMANCE_TESTS} ${SM_PERFORMANCE_TESTS_SOURCES}) +SET_SOURCE_FILES_PROPERTIES(${GEN_PATH}/db.h PROPERTIES GENERATED 1) +ADD_DEPENDENCIES(${TARGET_SM_TESTS} generate) +ADD_DEPENDENCIES(${TARGET_SM_PERFORMANCE_TESTS} generate) + TARGET_LINK_LIBRARIES(${TARGET_SM_TESTS} ${COMMON_DEP_LIBRARIES} ${DLOG_DEP_LIBRARIES} boost_unit_test_framework + boost_iostreams -ldl -lcrypt ) diff --git a/test/privilege_db_fixture.cpp b/test/privilege_db_fixture.cpp index 4cb0206..b470290 100644 --- a/test/privilege_db_fixture.cpp +++ b/test/privilege_db_fixture.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2016 - 2018 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,43 +34,47 @@ using namespace SecurityManager; -static const uid_t FirstUidForTests = 9900; +namespace { +constexpr uid_t FirstUidForTests = 9900; -static void putFile(const std::string &source, const std::string &destination) -{ - if (std::ifstream(destination)) - BOOST_WARN_MESSAGE(remove(destination.c_str()) == 0, - "Could not delete file" << destination); - std::ifstream src(source.c_str(), std::ios::binary); - std::ofstream dst(destination.c_str(), std::ios::binary); - dst << src.rdbuf(); - src.close(); - dst.close(); +void putFile(const std::string &srcPath, const std::string &dstPath) { + std::ifstream src(srcPath, std::ios::binary); + std::ofstream dst(dstPath, std::ios::binary|std::ios::trunc); + if (src.peek() != std::ifstream::traits_type::eof()) // otherwise dst.fail() + dst << src.rdbuf(); + BOOST_REQUIRE(src && dst); } -static std::string genName(const std::string &prefix, int i) +std::string genName(const std::string &prefix, int i) { std::string caseName(boost::unit_test::framework::current_test_case().p_name); return prefix + std::to_string(i) + "_" + caseName; } +} //namespace +std::string genJournalPath(const char *dbPath) { + Assert(dbPath); + return dbPath + std::string("-journal"); +} -PrivilegeDBFixture::PrivilegeDBFixture() +PrivilegeDBFixture::PrivilegeDBFixture(char const *src) { - putFile(std::string(PRIVILEGE_DB_TEMPLATE), std::string(TEST_PRIVILEGE_DB_PATH)); - putFile(std::string(PRIVILEGE_DB_JOURNAL_TEMPLATE), std::string(TEST_PRIVILEGE_DB_JOURNAL_PATH)); + Assert(src); + putFile(src, TEST_PRIVILEGE_DB_PATH); + putFile(genJournalPath(src), genJournalPath(TEST_PRIVILEGE_DB_PATH)); testPrivDb = new PrivilegeDb(TEST_PRIVILEGE_DB_PATH); }; PrivilegeDBFixture::~PrivilegeDBFixture() { + auto journalPath = genJournalPath(TEST_PRIVILEGE_DB_PATH); if (std::ifstream(TEST_PRIVILEGE_DB_PATH)) BOOST_WARN_MESSAGE(remove(TEST_PRIVILEGE_DB_PATH) == 0, "Could not delete test database file: " << TEST_PRIVILEGE_DB_PATH); - if (std::ifstream(TEST_PRIVILEGE_DB_JOURNAL_PATH)) - BOOST_WARN_MESSAGE(remove(TEST_PRIVILEGE_DB_JOURNAL_PATH) == 0, - "Could not delete test database file: " << TEST_PRIVILEGE_DB_JOURNAL_PATH); + if (std::ifstream(journalPath)) + BOOST_WARN_MESSAGE(remove(journalPath.c_str()) == 0, + "Could not delete test database file: " << journalPath); delete testPrivDb; } diff --git a/test/privilege_db_fixture.h b/test/privilege_db_fixture.h index 9b56ed3..6b77483 100644 --- a/test/privilege_db_fixture.h +++ b/test/privilege_db_fixture.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2016 - 2018 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,16 +24,18 @@ #include "privilege_db.h" #define PRIVILEGE_DB_TEMPLATE DB_TEST_DIR"/.security-manager-test.db" -#define PRIVILEGE_DB_JOURNAL_TEMPLATE DB_TEST_DIR"/.security-manager-test.db-journal" +#define PRIVILEGE_DB_EXAMPLE_V0 DB_TEST_DIR"/.security-manager-test-v0.db" +#define PRIVILEGE_DB_EMPTY DB_TEST_DIR"/.security-manager-test-empty.db" #define TEST_PRIVILEGE_DB_PATH "/tmp/.security-manager-test.db" -#define TEST_PRIVILEGE_DB_JOURNAL_PATH "/tmp/.security-manager-test.db-journal" using namespace SecurityManager; +std::string genJournalPath(const char *dbPath); + struct PrivilegeDBFixture { public: - PrivilegeDBFixture(); + explicit PrivilegeDBFixture(char const *src = PRIVILEGE_DB_TEMPLATE); ~PrivilegeDBFixture(); PrivilegeDb* getPrivDb(); diff --git a/test/test_privilege_db_migration.cpp b/test/test_privilege_db_migration.cpp new file mode 100644 index 0000000..10d23cb --- /dev/null +++ b/test/test_privilege_db_migration.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +#include + +#include +#include +#include + +#include "privilege_db.h" +#include "privilege_db_fixture.h" + +namespace { +bool fileContentsSame(const std::string &aPath, const std::string &bPath) { + boost::iostreams::mapped_file_source a(aPath), b(bPath); + auto s = a.size(); + return s == b.size() && !memcmp(a.data(), b.data(), s); +} + +void translateIOError(PrivilegeDb::Exception::IOError e) { + BOOST_FAIL("IOError: " + e.DumpToString()); +} + +class Config { +public: + Config() { + boost::unit_test::unit_test_monitor.register_exception_translator(&translateIOError); + } +}; + +struct PrivilegeV0DBFixture : PrivilegeDBFixture { + PrivilegeV0DBFixture() : PrivilegeDBFixture(PRIVILEGE_DB_EXAMPLE_V0) {} +}; +struct PrivilegeEmptyDBFixture : PrivilegeDBFixture { + PrivilegeEmptyDBFixture() : PrivilegeDBFixture(PRIVILEGE_DB_EMPTY) {} +}; +} //namespace + +BOOST_GLOBAL_FIXTURE(Config) + +BOOST_FIXTURE_TEST_SUITE(PRIVILEGE_DB_TEST_EMPTY, PrivilegeEmptyDBFixture) + +BOOST_AUTO_TEST_CASE(T1500_schema_application) +{ + BOOST_REQUIRE(fileContentsSame(PRIVILEGE_DB_TEMPLATE, TEST_PRIVILEGE_DB_PATH)); + BOOST_REQUIRE(fileContentsSame(genJournalPath(PRIVILEGE_DB_TEMPLATE), genJournalPath(TEST_PRIVILEGE_DB_PATH))); +} + +BOOST_AUTO_TEST_SUITE_END() + +//TODO +// Tests below are arbitrarily copy-pasted from test_privilege_db_transaction.cpp +// but applied to a migrated V0 database instead. The pragmatic way of doing this +// would be to compile all PrivilegeDBFixture-dependent tests twice: +// * normally +// * s/\/PrivilegeV0DBFixture/ + test case renaming to avoid +// linking collisions +// +// This would yield a comprehensive migration correctness check without copy-paste. +// It's a big task however and we're reportedly pressed for time now so there. +// +// Boost-Test provides no graceful alternative: +// * BOOST_FIXTURE_TEST_SUITE_TEMPLATE doesn't exist +// * BOOST_*_TEST_CASE_TEMPLATE and friends are fun but all test bodies would have +// to be rewritten because of the dreaded two-phase lookup +// (s/\getPrivDb()/ and so on to make member names dependent) + +BOOST_FIXTURE_TEST_SUITE(PRIVILEGE_DB_TEST, PrivilegeV0DBFixture) + +BOOST_AUTO_TEST_CASE(T1600_transaction_rollback_commit) +{ + BOOST_REQUIRE_NO_THROW(getPrivDb()->BeginTransaction()); + addAppSuccess(app(1), pkg(1), uid(1), tizenVer(1), author(1), NotHybrid); + + BOOST_REQUIRE_NO_THROW(getPrivDb()->RollbackTransaction()); + BOOST_REQUIRE_MESSAGE(!getPrivDb()->AppNameExists(app(1)), + "AppNameExists wrongly reported " << app(1) << " as existing, despite a rollback"); + BOOST_REQUIRE_THROW(getPrivDb()->CommitTransaction(), + PrivilegeDb::Exception::InternalError); +} + +BOOST_AUTO_TEST_CASE(T1610_transaction_double_rollback) +{ + BOOST_REQUIRE_NO_THROW(getPrivDb()->BeginTransaction()); + addAppSuccess(app(1), pkg(1), uid(1), tizenVer(1), author(1), NotHybrid); + + BOOST_REQUIRE_NO_THROW(getPrivDb()->RollbackTransaction()); + BOOST_REQUIRE_THROW(getPrivDb()->RollbackTransaction(), + PrivilegeDb::Exception::InternalError); +} + +BOOST_AUTO_TEST_CASE(T1620_commit_without_begin) +{ + BOOST_REQUIRE_THROW(getPrivDb()->CommitTransaction(), PrivilegeDb::Exception::InternalError); +} + +BOOST_AUTO_TEST_CASE(T1630_rollback_without_begin) +{ + BOOST_REQUIRE_THROW(getPrivDb()->RollbackTransaction(), PrivilegeDb::Exception::InternalError); +} + +BOOST_AUTO_TEST_CASE(T1640_transaction) +{ + BOOST_REQUIRE_NO_THROW(getPrivDb()->BeginTransaction()); + addAppSuccess(app(1), pkg(1), uid(1), tizenVer(1), author(1), NotHybrid); + + BOOST_REQUIRE_NO_THROW(getPrivDb()->CommitTransaction()); + BOOST_REQUIRE_NO_THROW(getPrivDb()->BeginTransaction()); + BOOST_REQUIRE_NO_THROW(getPrivDb()->RollbackTransaction()); + BOOST_REQUIRE_MESSAGE(getPrivDb()->AppNameExists(app(1)), + "AppNameExists wrongly not reported " << app(1) << " as existing application name"); +} + +BOOST_AUTO_TEST_CASE(T1650_transaction_double_begin) +{ + BOOST_REQUIRE_NO_THROW(getPrivDb()->BeginTransaction()); + addAppSuccess(app(1), pkg(1), uid(1), tizenVer(1), author(1), NotHybrid); + + BOOST_REQUIRE_THROW(getPrivDb()->BeginTransaction(), + PrivilegeDb::Exception::InternalError); +} + +BOOST_AUTO_TEST_CASE(T1660_transaction_double_commit) +{ + BOOST_REQUIRE_NO_THROW(getPrivDb()->BeginTransaction()); + addAppSuccess(app(1), pkg(1), uid(1), tizenVer(1), author(1), NotHybrid); + + BOOST_REQUIRE_NO_THROW(getPrivDb()->CommitTransaction()); + BOOST_REQUIRE_THROW(getPrivDb()->CommitTransaction(), + PrivilegeDb::Exception::InternalError); +} + +BOOST_AUTO_TEST_SUITE_END() -- 2.7.4 From 50f9c815398b2ebc23ca921e1fe27bd654534d22 Mon Sep 17 00:00:00 2001 From: Konrad Lipinski Date: Fri, 20 Jul 2018 15:29:00 +0200 Subject: [PATCH 08/16] Add database snapshotting and recovery A snapshot of a working database can be established by running security-manager-cmd --backup This effectively copies "$TZ_SYS_DB/.security-manager.db" over "$TZ_SYS_RO_SHARE/security-manager/.security-manager.db" (journal is not being copied). NOTE: backup does not check for concurrent access of the db file so the user has to make sure no concurrent modification takes place in the interim. The manager performs an integrity check of the database at every startup (see below). If the check fails, it truncates the database journal and overwrites the database file with the latest snapshot, then reattempts connection, migration and redoes the integrity check on the resulting database. As a first shot, integrity check uses the most aggressive possible form achievable by sqlite pragmas by * checking if the file exists (to prevent sqlite autovivifying it) * checking 'pragma intergrity_check' * checking 'pragma foreign_key_check' TODO: for product acceptance, actual latency introduced by the integrity check should be measured. If too high, the check can be made faster by * dropping foreign_key_check * replacing integrity_check with quick_check To help make the decision, lax measurement were taken using time sqlite3 >/dev/null /opt/dbspace/.security-manager.db 'pragma..' time[ms] foreign_key_check integrity_check quick_check TM1 17 20 18 emulator 5 2 2 Change-Id: I01a4ed0879b10bdcadde78ab086776420850e13c --- packaging/security-manager.spec | 6 ++ src/cmd/security-manager-cmd.cpp | 9 ++- src/common/config.cpp | 9 ++- src/common/filesystem.cpp | 27 ++++++++- src/common/include/config.h | 8 ++- src/common/include/filesystem.h | 5 +- src/common/include/privilege_db.h | 4 +- src/common/privilege_db.cpp | 92 +++++++++++++++++++++--------- src/dpl/db/include/dpl/db/sql_connection.h | 9 ++- test/CMakeLists.txt | 2 + test/privilege_db_fixture.cpp | 53 +++++++++-------- test/privilege_db_fixture.h | 12 +++- test/test_privilege_db_migration.cpp | 67 +++++++++++++++++++--- test/test_privilege_db_transactions.cpp | 31 +++++++--- 14 files changed, 257 insertions(+), 77 deletions(-) diff --git a/packaging/security-manager.spec b/packaging/security-manager.spec index 73fe3ed..cb417c7 100644 --- a/packaging/security-manager.spec +++ b/packaging/security-manager.spec @@ -145,6 +145,8 @@ install -m 0444 /dev/null %{buildroot}%{TZ_SYS_VAR}/security-manager/policy-vers mkdir -p %{buildroot}/%{db_test_dir} sqlite3 %{buildroot}/%{db_test_dir}/.security-manager-test.db < db/db.sql sqlite3 %{buildroot}/%{db_test_dir}/.security-manager-test-v0.db < db/db_test_v0.sql +dd bs=1K count=$(($(stat -c%s %{buildroot}/%{db_test_dir}/.security-manager-test.db) / 1024 - 1)) if=%{buildroot}/%{db_test_dir}/.security-manager-test.db of=%{buildroot}/%{db_test_dir}/.security-manager-test-corrupted.db +cp -a %{buildroot}/%{db_test_dir}/.security-manager-test.db-journal %{buildroot}/%{db_test_dir}/.security-manager-test-corrupted.db-journal echo -n > %{buildroot}/%{db_test_dir}/.security-manager-test-empty.db echo -n > %{buildroot}/%{db_test_dir}/.security-manager-test-empty.db-journal @@ -240,6 +242,8 @@ chsmack -a System %{db_test_dir}/.security-manager-test.db chsmack -a System %{db_test_dir}/.security-manager-test.db-journal chsmack -a System %{db_test_dir}/.security-manager-test-v0.db chsmack -a System %{db_test_dir}/.security-manager-test-v0.db-journal +chsmack -a System %{db_test_dir}/.security-manager-test-corrupted.db +chsmack -a System %{db_test_dir}/.security-manager-test-corrupted.db-journal chsmack -a System %{db_test_dir}/.security-manager-test-empty.db chsmack -a System %{db_test_dir}/.security-manager-test-empty.db-journal @@ -308,6 +312,8 @@ chsmack -a System %{db_test_dir}/.security-manager-test-empty.db-journal %attr(0600,root,root) %{db_test_dir}/.security-manager-test.db-journal %attr(0600,root,root) %{db_test_dir}/.security-manager-test-v0.db %attr(0600,root,root) %{db_test_dir}/.security-manager-test-v0.db-journal +%attr(0600,root,root) %{db_test_dir}/.security-manager-test-corrupted.db +%attr(0600,root,root) %{db_test_dir}/.security-manager-test-corrupted.db-journal %attr(0600,root,root) %{db_test_dir}/.security-manager-test-empty.db %attr(0600,root,root) %{db_test_dir}/.security-manager-test-empty.db-journal diff --git a/src/cmd/security-manager-cmd.cpp b/src/cmd/security-manager-cmd.cpp index 18bde87..120bf05 100644 --- a/src/cmd/security-manager-cmd.cpp +++ b/src/cmd/security-manager-cmd.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2018 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Rafal Krypa * @@ -38,6 +38,9 @@ #include #include +#include +#include + namespace po = boost::program_options; static std::map app_install_path_type_map = { @@ -71,6 +74,7 @@ static po::options_description getGenericOptions() ("manage-apps,n", po::value(), "add or remove app, parameter is either a/add or r/remove") ("manage-users,m", po::value(), "add or remove user, parameter is either a/add or r/remove") ("manage-privilege,o", po::value(), "allow or deny privilege, parameter is either a/allow or d/deny") + ("backup,b", "make a backup of the database file") ; return opts; } @@ -475,6 +479,9 @@ int main(int argc, char *argv[]) auto policy_ptr = makeUnique(policy_update, security_manager_policy_update_req_free); parsePrivilegeOptions(argc, argv, *req, vm); return managePrivilegeOperation(*req, policy_update, operation); + } else if (vm.count("backup")) { + if (SECURITY_MANAGER_SUCCESS == FS::overwriteFile(Config::privilegeDbPath, Config::privilegeDbFallbackPath)) + return EXIT_SUCCESS; } else { std::cout << "No command argument was given." << std::endl; usage(std::string(argv[0])); diff --git a/src/common/config.cpp b/src/common/config.cpp index d153b4f..b7411df 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2015 - 2018 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Rafal Krypa * @@ -51,6 +51,13 @@ const bool IS_ASKUSER_ENABLED = true; #else const bool IS_ASKUSER_ENABLED = false; #endif + +const std::string privilegeDbPath = TizenPlatformConfig::makePath(TZ_SYS_DB, ".security-manager.db"); +const std::string privilegeDbFallbackPath = TizenPlatformConfig::makePath(TZ_SYS_RO_SHARE, "security-manager", ".security-manager.db"); + +std::string dbBrokenFlagFileName(const std::string &dbPath) { + return dbPath + "-broken"; +} }; } /* namespace SecurityManager */ diff --git a/src/common/filesystem.cpp b/src/common/filesystem.cpp index 36d7808..29c019b 100644 --- a/src/common/filesystem.cpp +++ b/src/common/filesystem.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2016 - 2018 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Rafal Krypa * @@ -217,5 +217,30 @@ int symLink(const std::string &src, const std::string &dst) return SECURITY_MANAGER_SUCCESS; } +int overwriteFile(const std::string &srcPath, const std::string &dstPath) { + std::ifstream src(srcPath, std::ios::binary); + if (!src) + return SECURITY_MANAGER_ERROR_FILE_OPEN_FAILED; + std::ofstream dst(dstPath, std::ios::binary|std::ios::trunc); + if (src.peek() != std::ifstream::traits_type::eof()) // otherwise dst.fail() + dst << src.rdbuf(); + src.close(); + dst.close(); + return src && dst ? SECURITY_MANAGER_SUCCESS : SECURITY_MANAGER_ERROR_FILE_CREATE_FAILED; +} + +int truncateFile(const std::string &path) { + std::ofstream dst(path, std::ios::binary|std::ios::trunc); + dst.close(); + return dst ? SECURITY_MANAGER_SUCCESS : SECURITY_MANAGER_ERROR_FILE_CREATE_FAILED; +} + +off_t fileSize(const std::string &path) { + struct stat st; + static_assert(std::is_same::value); + static_assert(std::is_signed::value); + return -1 == lstat(path.c_str(), &st) || !S_ISREG(st.st_mode) ? -1 : st.st_size; +} + } // namespace FS } // namespace SecurityManager diff --git a/src/common/include/config.h b/src/common/include/config.h index 1431446..a04bfe1 100644 --- a/src/common/include/config.h +++ b/src/common/include/config.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2015 - 2018 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Rafal Krypa * @@ -25,6 +25,7 @@ #pragma once #include +#include namespace SecurityManager { @@ -57,6 +58,11 @@ extern const std::string PRIVACY_POLICY_DESC; /* true if privacy-related privileges should result in UI-popup question*/ extern const bool IS_ASKUSER_ENABLED; + +extern const std::string privilegeDbPath; +extern const std::string privilegeDbFallbackPath; + +std::string dbBrokenFlagFileName(const std::string &dbPath); }; } /* namespace SecurityManager */ diff --git a/src/common/include/filesystem.h b/src/common/include/filesystem.h index 13b1d0b..6bb97d3 100644 --- a/src/common/include/filesystem.h +++ b/src/common/include/filesystem.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2016 - 2018 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Rafal Krypa * @@ -48,6 +48,9 @@ int fileStatus(const std::string &path); int createFile(const std::string &path); int removeFile(const std::string &path); int symLink(const std::string &src, const std::string &dst); +int overwriteFile(const std::string &src, const std::string &dst); +int truncateFile(const std::string &path); +off_t fileSize(const std::string &path); // < 0 on error } // namespace FS } // namespace SecurityManager diff --git a/src/common/include/privilege_db.h b/src/common/include/privilege_db.h index 010c605..eac2d7d 100644 --- a/src/common/include/privilege_db.h +++ b/src/common/include/privilege_db.h @@ -47,6 +47,8 @@ namespace SecurityManager { +std::string genJournalPath(const std::string &dbPath); + enum class StmtType : uint8_t { EAddApplication, ERemoveApplication, @@ -162,7 +164,7 @@ public: * @exception PrivilegeDb::Exception::IOError on problems with database access * */ - explicit PrivilegeDb(const std::string &path); + explicit PrivilegeDb(const std::string &path, const std::string &roFallbackPath); static PrivilegeDb &getInstance(); diff --git a/src/common/privilege_db.cpp b/src/common/privilege_db.cpp index 408a9c9..f3e1f19 100644 --- a/src/common/privilege_db.cpp +++ b/src/common/privilege_db.cpp @@ -36,6 +36,7 @@ #include #include +#include #include "../gen/db.h" #include "privilege_db.h" #include "tzplatform-config.h" @@ -129,20 +130,15 @@ auto prepare(DB::SqlConnection &db, const char *fmt) { return cmd; } -std::string getPrivilegeDbPath() -{ - static std::string path = TizenPlatformConfig::makePath(TZ_SYS_DB, ".security-manager.db"); - return path; -} - bool dbEmpty(const std::string &dbPath) { - struct stat buf; - if (-1 == stat(dbPath.c_str(), &buf)) + auto s = FS::fileSize(dbPath); + if (s < 0) ThrowMsg(DB::SqlConnection::Exception::Base, "Failed to stat db file"); - return !buf.st_size; + return !s; } -void migrate(DB::SqlConnection &db, const std::string &path) { +void connectMigrateVerify(DB::SqlConnection &db, const std::string &path) { + db.Connect(path, DB::SqlConnection::Flag::None, DB::SqlConnection::Flag::RW); using Ex = DB::SqlConnection::Exception::Base; int32_t version; { @@ -160,8 +156,19 @@ void migrate(DB::SqlConnection &db, const std::string &path) { do db.ExecCommand(dbUpdateScript[version]); while (++version < dbVersion); db.ExecCommand(dbSchema); } + + { + auto cmd = prepare(db, "PRAGMA integrity_check"); + if (!cmd->Step()) + ThrowMsg(Ex, "Integrity check returned no result"); + if (cmd->GetColumnString(0) != "ok") + ThrowMsg(Ex, "Integrity check failed"); + } + + auto cmd = prepare(db, "PRAGMA foreign_key_check"); + if (cmd->Step()) + ThrowMsg(Ex, "Foreign key check failed"); } -} //namespace /* Common code for handling SqlConnection exceptions */ template @@ -184,30 +191,59 @@ T try_catch(const std::function &func) } } -std::string getPrivilegeDbFailFlagPath() -{ - static std::string path = TizenPlatformConfig::makePath(TZ_SYS_DB, ".security-manager.db-broken"); - return path; +void throwDbInitEx(const std::string &errDesc) { + auto s = "Database initialization error: " + errDesc; + LogError(s); + ThrowMsg(PrivilegeDb::Exception::IOError, s); +} + +void createBrokenFlagFile(const std::string &dbPath) { + if (SECURITY_MANAGER_SUCCESS != FS::createFile(Config::dbBrokenFlagFileName(dbPath))) + throwDbInitEx("Error creating db broken flag file"); } -PrivilegeDb::PrivilegeDb() : PrivilegeDb(getPrivilegeDbPath()) +template +void tryCatchDbInit(F &&f) { + try { + f(); + } catch (DB::SqlConnection::Exception::Base &e) { + throwDbInitEx(e.DumpToString()); + } +} + +void applyFallbackDb(DB::SqlConnection &conn, const std::string &dbPath, const std::string &roFallbackPath) { + if (SECURITY_MANAGER_SUCCESS != FS::overwriteFile(roFallbackPath, dbPath)) + throwDbInitEx("Error overwriting database with fallback: " + roFallbackPath); + if (SECURITY_MANAGER_SUCCESS != FS::truncateFile(genJournalPath(dbPath))) + throwDbInitEx("Error truncating journal"); + tryCatchDbInit([&]{ connectMigrateVerify(conn, dbPath); }); +} +} //namespace + +std::string genJournalPath(const std::string &dbPath) { + return dbPath + "-journal"; +} + +PrivilegeDb::PrivilegeDb() + : PrivilegeDb(Config::privilegeDbPath, Config::privilegeDbFallbackPath) { } -PrivilegeDb::PrivilegeDb(const std::string &path) +PrivilegeDb::PrivilegeDb(const std::string &path, const std::string &roFallbackPath) { - try { - mSqlConnection.Connect(path, - DB::SqlConnection::Flag::None, - DB::SqlConnection::Flag::RW); - migrate(mSqlConnection, path); - initDataCommands(); + if (!FS::fileStatus(path)) { + createBrokenFlagFile(path); + LogError("Database file missing, attempting fallback"); + applyFallbackDb(mSqlConnection, path, roFallbackPath); + } else try { + connectMigrateVerify(mSqlConnection, path); } catch (DB::SqlConnection::Exception::Base &e) { - LogError("Database initialization error: " << e.DumpToString()); - FS::createFile(getPrivilegeDbFailFlagPath()); - ThrowMsg(PrivilegeDb::Exception::IOError, - "Database initialization error:" << e.DumpToString()); - }; + createBrokenFlagFile(path); + LogError("Database initialization error (" << e.DumpToString() << "), attempting fallback"); + tryCatchDbInit([&]{ mSqlConnection.Disconnect(); }); + applyFallbackDb(mSqlConnection, path, roFallbackPath); + } + tryCatchDbInit([&]{ initDataCommands(); }); } void PrivilegeDb::initDataCommands() diff --git a/src/dpl/db/include/dpl/db/sql_connection.h b/src/dpl/db/include/dpl/db/sql_connection.h index d5ac797..7bb5c3c 100644 --- a/src/dpl/db/include/dpl/db/sql_connection.h +++ b/src/dpl/db/include/dpl/db/sql_connection.h @@ -410,8 +410,6 @@ class SqlConnection final // Synchronization object std::unique_ptr m_synchronizationObject; - void Disconnect(); - void TurnOnForeignKeys(); static SynchronizationObject *AllocDefaultSynchronizationObject(); @@ -433,7 +431,7 @@ class SqlConnection final /** * Open SQL connection * - * Called exactly once on a newly constructed object before using it. + * Called exactly once on a disconnected object before using it. * * @param address Database file name * @param type Open options (ie. use Lucene index or not) @@ -444,6 +442,11 @@ class SqlConnection final Flag::Option flag = Flag::RO); /** + * Disconnect SQL connection + */ + void Disconnect(); + + /** * Destructor */ ~SqlConnection(); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e1fcd2d..a7046df 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -72,6 +72,7 @@ SET(SM_TESTS_SOURCES ${DPL_PATH}/log/src/abstract_log_provider.cpp ${DPL_PATH}/log/src/log.cpp ${DPL_PATH}/log/src/old_style_log_provider.cpp + ${PROJECT_SOURCE_DIR}/src/common/config.cpp ${PROJECT_SOURCE_DIR}/src/common/config-file.cpp ${PROJECT_SOURCE_DIR}/src/common/file-lock.cpp ${PROJECT_SOURCE_DIR}/src/common/privilege_db.cpp @@ -98,6 +99,7 @@ SET(SM_PERFORMANCE_TESTS_SOURCES ${DPL_PATH}/log/src/abstract_log_provider.cpp ${DPL_PATH}/log/src/log.cpp ${DPL_PATH}/log/src/old_style_log_provider.cpp + ${PROJECT_SOURCE_DIR}/src/common/config.cpp ${PROJECT_SOURCE_DIR}/src/common/config-file.cpp #${PROJECT_SOURCE_DIR}/src/common/file-lock.cpp ${PROJECT_SOURCE_DIR}/src/common/privilege_db.cpp diff --git a/test/privilege_db_fixture.cpp b/test/privilege_db_fixture.cpp index b470290..05d2d77 100644 --- a/test/privilege_db_fixture.cpp +++ b/test/privilege_db_fixture.cpp @@ -29,6 +29,9 @@ #include #include +#include +#include + #include "privilege_db.h" #include "privilege_db_fixture.h" @@ -38,11 +41,7 @@ namespace { constexpr uid_t FirstUidForTests = 9900; void putFile(const std::string &srcPath, const std::string &dstPath) { - std::ifstream src(srcPath, std::ios::binary); - std::ofstream dst(dstPath, std::ios::binary|std::ios::trunc); - if (src.peek() != std::ifstream::traits_type::eof()) // otherwise dst.fail() - dst << src.rdbuf(); - BOOST_REQUIRE(src && dst); + BOOST_REQUIRE(SECURITY_MANAGER_SUCCESS == FS::overwriteFile(srcPath, dstPath)); } std::string genName(const std::string &prefix, int i) @@ -52,30 +51,38 @@ std::string genName(const std::string &prefix, int i) } } //namespace -std::string genJournalPath(const char *dbPath) { - Assert(dbPath); - return dbPath + std::string("-journal"); +void requireNoDb(const std::string &dbPath) { + BOOST_REQUIRE(!FS::fileStatus(dbPath)); + BOOST_REQUIRE(!FS::fileStatus(genJournalPath(dbPath))); + BOOST_REQUIRE(!FS::fileStatus(Config::dbBrokenFlagFileName(dbPath))); } -PrivilegeDBFixture::PrivilegeDBFixture(char const *src) +PrivilegeDBFixture::PrivilegeDBFixture(const std::string &src, const std::string &fallback, + HaveBrokenFlagFile haveBrokenFlagFile, const std::string &dst) + : dbPath(dst) { - Assert(src); - putFile(src, TEST_PRIVILEGE_DB_PATH); - putFile(genJournalPath(src), genJournalPath(TEST_PRIVILEGE_DB_PATH)); - - testPrivDb = new PrivilegeDb(TEST_PRIVILEGE_DB_PATH); -}; + requireNoDb(dst); + putFile(src, dst); + putFile(genJournalPath(src), genJournalPath(dst)); + + testPrivDb = new PrivilegeDb(dst, fallback); + const auto brokenFlagFileName = Config::dbBrokenFlagFileName(dst); + const auto flagFileStatus = FS::fileStatus(brokenFlagFileName); + if (haveBrokenFlagFile == HaveBrokenFlagFile::no) { + BOOST_REQUIRE(!flagFileStatus); + } else { + BOOST_REQUIRE(flagFileStatus > 0); + BOOST_REQUIRE(!FS::fileSize(brokenFlagFileName)); + BOOST_REQUIRE(!remove(brokenFlagFileName.c_str())); + } +} PrivilegeDBFixture::~PrivilegeDBFixture() { - auto journalPath = genJournalPath(TEST_PRIVILEGE_DB_PATH); - if (std::ifstream(TEST_PRIVILEGE_DB_PATH)) - BOOST_WARN_MESSAGE(remove(TEST_PRIVILEGE_DB_PATH) == 0, - "Could not delete test database file: " << TEST_PRIVILEGE_DB_PATH); - if (std::ifstream(journalPath)) - BOOST_WARN_MESSAGE(remove(journalPath.c_str()) == 0, - "Could not delete test database file: " << journalPath); - + BOOST_REQUIRE_MESSAGE(remove(dbPath.c_str()) == 0, "Could not delete test database file: " << dbPath); + auto journalPath = genJournalPath(dbPath); + BOOST_REQUIRE_MESSAGE(remove(journalPath.c_str()) == 0, "Could not delete test database journal file: " << journalPath); + BOOST_REQUIRE(!FS::fileStatus(Config::dbBrokenFlagFileName(dbPath))); delete testPrivDb; } diff --git a/test/privilege_db_fixture.h b/test/privilege_db_fixture.h index 6b77483..06c771b 100644 --- a/test/privilege_db_fixture.h +++ b/test/privilege_db_fixture.h @@ -25,17 +25,22 @@ #define PRIVILEGE_DB_TEMPLATE DB_TEST_DIR"/.security-manager-test.db" #define PRIVILEGE_DB_EXAMPLE_V0 DB_TEST_DIR"/.security-manager-test-v0.db" +#define PRIVILEGE_DB_CORRUPTED DB_TEST_DIR"/.security-manager-test-corrupted.db" #define PRIVILEGE_DB_EMPTY DB_TEST_DIR"/.security-manager-test-empty.db" #define TEST_PRIVILEGE_DB_PATH "/tmp/.security-manager-test.db" +#define TEST_PRIVILEGE_DB_PATH_2 "/tmp/.security-manager-test-2.db" using namespace SecurityManager; -std::string genJournalPath(const char *dbPath); +void requireNoDb(const std::string &dbPath); struct PrivilegeDBFixture { public: - explicit PrivilegeDBFixture(char const *src = PRIVILEGE_DB_TEMPLATE); + enum class HaveBrokenFlagFile : bool { no, yes }; + explicit PrivilegeDBFixture(const std::string &src = PRIVILEGE_DB_TEMPLATE, + const std::string &fallback = PRIVILEGE_DB_TEMPLATE, + HaveBrokenFlagFile = HaveBrokenFlagFile::no, const std::string &dst = TEST_PRIVILEGE_DB_PATH); ~PrivilegeDBFixture(); PrivilegeDb* getPrivDb(); @@ -68,4 +73,7 @@ public: protected: PrivilegeDb *testPrivDb; + +private: + std::string dbPath; }; diff --git a/test/test_privilege_db_migration.cpp b/test/test_privilege_db_migration.cpp index 10d23cb..6f40655 100644 --- a/test/test_privilege_db_migration.cpp +++ b/test/test_privilege_db_migration.cpp @@ -14,12 +14,15 @@ * limitations under the License */ +#include #include #include #include #include +#include +#include #include "privilege_db.h" #include "privilege_db_fixture.h" @@ -30,13 +33,22 @@ bool fileContentsSame(const std::string &aPath, const std::string &bPath) { return s == b.size() && !memcmp(a.data(), b.data(), s); } +void requireTestDbContents(const std::string &db) { + BOOST_REQUIRE(fileContentsSame(TEST_PRIVILEGE_DB_PATH, db)); +} + +void requireTestDbAndJournalContents(const std::string &db) { + requireTestDbContents(db); + BOOST_REQUIRE(fileContentsSame(genJournalPath(TEST_PRIVILEGE_DB_PATH), genJournalPath(db))); +} + void translateIOError(PrivilegeDb::Exception::IOError e) { BOOST_FAIL("IOError: " + e.DumpToString()); } -class Config { +class TestConfig { public: - Config() { + TestConfig() { boost::unit_test::unit_test_monitor.register_exception_translator(&translateIOError); } }; @@ -47,16 +59,57 @@ struct PrivilegeV0DBFixture : PrivilegeDBFixture { struct PrivilegeEmptyDBFixture : PrivilegeDBFixture { PrivilegeEmptyDBFixture() : PrivilegeDBFixture(PRIVILEGE_DB_EMPTY) {} }; +struct PrivilegeFallbackDBFixture : PrivilegeDBFixture { + PrivilegeFallbackDBFixture() : PrivilegeDBFixture(PRIVILEGE_DB_CORRUPTED, PRIVILEGE_DB_TEMPLATE, HaveBrokenFlagFile::yes) {} +}; +struct PrivilegeFallbackV0DBFixture : PrivilegeDBFixture { + PrivilegeFallbackV0DBFixture() : PrivilegeDBFixture(PRIVILEGE_DB_CORRUPTED, PRIVILEGE_DB_EXAMPLE_V0, HaveBrokenFlagFile::yes) {} +}; +struct PrivilegeFallbackEmptyDBFixture : PrivilegeDBFixture { + PrivilegeFallbackEmptyDBFixture() : PrivilegeDBFixture(PRIVILEGE_DB_CORRUPTED, PRIVILEGE_DB_EMPTY, HaveBrokenFlagFile::yes) {} +}; } //namespace -BOOST_GLOBAL_FIXTURE(Config) +BOOST_GLOBAL_FIXTURE(TestConfig) BOOST_FIXTURE_TEST_SUITE(PRIVILEGE_DB_TEST_EMPTY, PrivilegeEmptyDBFixture) +BOOST_AUTO_TEST_CASE(T1500_schema_application) { + requireTestDbAndJournalContents(PRIVILEGE_DB_TEMPLATE); +} +BOOST_AUTO_TEST_SUITE_END() -BOOST_AUTO_TEST_CASE(T1500_schema_application) -{ - BOOST_REQUIRE(fileContentsSame(PRIVILEGE_DB_TEMPLATE, TEST_PRIVILEGE_DB_PATH)); - BOOST_REQUIRE(fileContentsSame(genJournalPath(PRIVILEGE_DB_TEMPLATE), genJournalPath(TEST_PRIVILEGE_DB_PATH))); +BOOST_FIXTURE_TEST_SUITE(PRIVILEGE_DB_TEST_FALLBACK, PrivilegeFallbackDBFixture) +BOOST_AUTO_TEST_CASE(T1510_fallback) { + requireTestDbContents(PRIVILEGE_DB_TEMPLATE); + BOOST_REQUIRE(!FS::fileSize(genJournalPath(TEST_PRIVILEGE_DB_PATH))); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_FIXTURE_TEST_SUITE(PRIVILEGE_DB_TEST_FALLBACK_EMPTY, PrivilegeFallbackEmptyDBFixture) +BOOST_AUTO_TEST_CASE(T1520_fallback_schema_application) { + requireTestDbAndJournalContents(PRIVILEGE_DB_TEMPLATE); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_FIXTURE_TEST_SUITE(PRIVILEGE_DB_TEST_FALLBACK_V0, PrivilegeFallbackV0DBFixture) + +BOOST_AUTO_TEST_CASE(T1530_fallback_migration) { + PrivilegeDBFixture v0(PRIVILEGE_DB_EXAMPLE_V0, PRIVILEGE_DB_TEMPLATE, + PrivilegeDBFixture::HaveBrokenFlagFile::no, TEST_PRIVILEGE_DB_PATH_2); + requireTestDbContents(TEST_PRIVILEGE_DB_PATH_2); +} + +BOOST_AUTO_TEST_CASE(T1540_db_missing_fallback_migration) { + const std::string missingDbPath("/tmp/thisNotExists.db"); + requireNoDb(missingDbPath); + const auto missingDbPathJournal = genJournalPath(missingDbPath); + const auto missingDbPathFlag = Config::dbBrokenFlagFileName(missingDbPath); + BOOST_REQUIRE_NO_THROW(PrivilegeDb(missingDbPath, PRIVILEGE_DB_EXAMPLE_V0)); + requireTestDbContents(missingDbPath); + BOOST_REQUIRE(!remove(missingDbPath.c_str())); + BOOST_REQUIRE(!remove(missingDbPathJournal.c_str())); + BOOST_REQUIRE(!FS::fileSize(missingDbPathFlag)); + BOOST_REQUIRE(!remove(missingDbPathFlag.c_str())); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/test_privilege_db_transactions.cpp b/test/test_privilege_db_transactions.cpp index 7b65dbe..68aed11 100644 --- a/test/test_privilege_db_transactions.cpp +++ b/test/test_privilege_db_transactions.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2016 - 2018 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,9 @@ #include #include +#include +#include + #include "privilege_db.h" #include "privilege_db_fixture.h" @@ -39,14 +42,26 @@ BOOST_FIXTURE_TEST_SUITE(PRIVILEGE_DB_TEST_TRANSACTIONS, PrivilegeDBFixture) BOOST_FIXTURE_TEST_CASE(T100_privilegedb_constructor, Empty) { - PrivilegeDb *testPrivDb = nullptr; + std::unique_ptr testPrivDb; + + BOOST_REQUIRE_NO_THROW(testPrivDb.reset(new PrivilegeDb())); - BOOST_REQUIRE_NO_THROW(testPrivDb = new PrivilegeDb()); - delete testPrivDb; - testPrivDb = nullptr; - BOOST_REQUIRE_THROW(testPrivDb = new PrivilegeDb("/this/not/exists"), + std::string nExist("/tmp/thisNotExists"), nExist2("/tmp/neitherDoesThis"); + requireNoDb(nExist); + requireNoDb(nExist2); + BOOST_REQUIRE_THROW(testPrivDb.reset(new PrivilegeDb(nExist, nExist2)), PrivilegeDb::Exception::IOError); - delete testPrivDb; + const auto flagFile = Config::dbBrokenFlagFileName(nExist); + BOOST_REQUIRE(!FS::fileSize(flagFile)); + BOOST_REQUIRE(!remove(flagFile.c_str())); + requireNoDb(nExist); + + // fallback existent but db can't be created w/out mkdir -p + std::string nExistDeep("/this/not/exists"); + requireNoDb(nExistDeep); + BOOST_REQUIRE_THROW(testPrivDb.reset(new PrivilegeDb(nExistDeep, PRIVILEGE_DB_TEMPLATE)), + PrivilegeDb::Exception::IOError); + requireNoDb(nExistDeep); } // Transactions @@ -86,7 +101,7 @@ BOOST_AUTO_TEST_CASE(T230_rollback_without_begin) BOOST_AUTO_TEST_CASE(T240_transaction) { BOOST_REQUIRE_NO_THROW(getPrivDb()->BeginTransaction()); - addAppSuccess(app(1),pkg(1), uid(1), tizenVer(1), author(1), NotHybrid); + addAppSuccess(app(1), pkg(1), uid(1), tizenVer(1), author(1), NotHybrid); BOOST_REQUIRE_NO_THROW(getPrivDb()->CommitTransaction()); BOOST_REQUIRE_NO_THROW(getPrivDb()->BeginTransaction()); -- 2.7.4 From 102a00fb844ed24846ca6338c727558353f5d5fa Mon Sep 17 00:00:00 2001 From: Tomasz Swierczek Date: Tue, 7 Aug 2018 07:26:55 +0200 Subject: [PATCH 09/16] Add removal of DB broken flag before atempt to setup DB This way, we ensure that on next booting there will be no information on previous problems (the flag exists to tell other system components that user-installed applications require re-registration in security-manager). Change-Id: I5c7a9962adeb66125664f9a6c293355136456ded --- src/common/privilege_db.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/common/privilege_db.cpp b/src/common/privilege_db.cpp index f3e1f19..50bb6e5 100644 --- a/src/common/privilege_db.cpp +++ b/src/common/privilege_db.cpp @@ -202,6 +202,11 @@ void createBrokenFlagFile(const std::string &dbPath) { throwDbInitEx("Error creating db broken flag file"); } +void removeBrokenFlagFile(const std::string &dbPath) { + if (SECURITY_MANAGER_SUCCESS == FS::removeFile(Config::dbBrokenFlagFileName(dbPath))) + LogWarning("Broken DB flag file removed - booting 1st time after DB recovery"); +} + template void tryCatchDbInit(F &&f) { try { @@ -231,6 +236,7 @@ PrivilegeDb::PrivilegeDb() PrivilegeDb::PrivilegeDb(const std::string &path, const std::string &roFallbackPath) { + removeBrokenFlagFile(path); if (!FS::fileStatus(path)) { createBrokenFlagFile(path); LogError("Database file missing, attempting fallback"); -- 2.7.4 From 40609ab24f22491d2fbd52ecfbd80f693dbe3047 Mon Sep 17 00:00:00 2001 From: Tomasz Swierczek Date: Tue, 7 Aug 2018 08:43:56 +0200 Subject: [PATCH 10/16] Release 1.4.3 * Add removal of DB broken flag before atempt to setup DB * Add database snapshotting and recovery * Pull db migration into manager binary at startup * Sanitize privilege_db query storage * Fix memleak in PrivilegeDb() * Add /opt/usr/media to privilege-mount.list again * Retrieve package manager privilege from User::Shell client * Make spec compliant with gbs --incremental * Add TZ_SYS_MEDIASHARED to privilege-mount.list * Change log message in realPath * Make server keep its original log tag * Fix hybrid pkg uninstallation Change-Id: I9b410a6c9ceed3d63a13265aad7d33e858e37c8c --- packaging/security-manager.changes | 19 +++++++++++++++++++ packaging/security-manager.spec | 2 +- pc/security-manager.pc.in | 2 +- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/packaging/security-manager.changes b/packaging/security-manager.changes index c44ec3f..c3f2e3e 100644 --- a/packaging/security-manager.changes +++ b/packaging/security-manager.changes @@ -1,3 +1,22 @@ +Release: 1.4.3 +Date: 2018.08.07 +Name: Release 1.4.3 +Description: +Add removal of DB broken flag before atempt to setup DB +Add database snapshotting and recovery +Pull db migration into manager binary at startup +Sanitize privilege_db query storage +Fix memleak in PrivilegeDb() +Add /opt/usr/media to privilege-mount.list again +Retrieve package manager privilege from User::Shell client +Make spec compliant with gbs --incremental +Add TZ_SYS_MEDIASHARED to privilege-mount.list +Change log message in realPath +Make server keep its original log tag +Fix hybrid pkg uninstallation + +############################### + Release: 1.4.2 Date: 2018.06.20 Name: Release 1.4.2 diff --git a/packaging/security-manager.spec b/packaging/security-manager.spec index cb417c7..1398a43 100644 --- a/packaging/security-manager.spec +++ b/packaging/security-manager.spec @@ -1,6 +1,6 @@ Name: security-manager Summary: Security manager and utilities -Version: 1.4.2 +Version: 1.4.3 Release: 0 Group: Security/Service License: Apache-2.0 diff --git a/pc/security-manager.pc.in b/pc/security-manager.pc.in index 329ca7c..4a7e477 100644 --- a/pc/security-manager.pc.in +++ b/pc/security-manager.pc.in @@ -5,7 +5,7 @@ includedir=${prefix}/include Name: security-manager Description: Security Manager Package -Version: 1.4.2 +Version: 1.4.3 Requires: Libs: -L${libdir} -lsecurity-manager-client Cflags: -I${includedir}/security-manager -- 2.7.4 From f378db9ec6624b8feda6a643fe60fc506c980bf0 Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Tue, 7 Aug 2018 13:27:58 +0200 Subject: [PATCH 11/16] Remove unused source code Change-Id: I40230e07b459d73907986ba916e1e15628e5d9cb --- src/license-manager/common/translator.cpp | 144 ------------------------------ src/license-manager/common/translator.h | 64 ------------- 2 files changed, 208 deletions(-) delete mode 100644 src/license-manager/common/translator.cpp delete mode 100644 src/license-manager/common/translator.h diff --git a/src/license-manager/common/translator.cpp b/src/license-manager/common/translator.cpp deleted file mode 100644 index 7bbc927..0000000 --- a/src/license-manager/common/translator.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2014-2017 Samsung Electronics Co. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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 translator.cpp - * @author Zofia Abramowska - * @author Oskar Świtalski - * @author Bartlomiej Grzelewski - * @brief Implementation of Translator methods - */ - -#include - -#include - -#include -#include -#include - -namespace LicenseManager { -namespace Translator { - -//RequestData dataToRequest(const Cynara::PluginData &data) { -// std::stringstream stream(data); -// std::size_t strSize; -// std::string members[3]; -// -// for (auto &member : members) { -// stream >> strSize; -// std::vector buffer(strSize, '\0'); -// char separator; -// //Consume separator -// stream.read(&separator, 1); -// stream.read(buffer.data(), strSize); -// //read doesn't append null -// member.assign(buffer.begin(), buffer.end()); -// } -// return RequestData{members[0], members[1], members[2]}; -//} -// -//Cynara::PluginData answerToData(Cynara::PolicyType answer, const std::string &errMsg) { -// if (errMsg.empty()) -// return std::to_string(answer); -// else -// return errMsg; -//} -// - -Cynara::PolicyType dataToAnswer(const Cynara::PluginData &data) { - // data is an error string - if (data == AgentErrorMsg::Error || data == AgentErrorMsg::Timeout) - return AskUser::SupportedTypes::Client::DENY_ONCE; - // data is policy type - long long policyType; - try { - policyType = std::stoll(data); - } catch (const std::exception &e) { - throw TranslateErrorException("Could not convert response to PolicyType : " + - data); - } - auto maxPolicyType = std::numeric_limits::max(); - if (policyType > maxPolicyType) { - throw TranslateErrorException("Value of response exceeds max value of PolicyType : " - + std::to_string(policyType)); - } - return static_cast(policyType); -} - -Cynara::PluginData requestToData(const std::string &client, - const std::string &user, - const std::string &privilege) -{ - const char separator = ' '; - return std::to_string(client.length()) + separator + client + separator - + std::to_string(user.length()) + separator + user + separator - + std::to_string(privilege.length()) + separator + privilege + separator; -} - -//std::string responseToString(NResponseType response) -//{ -// switch (response) { -// case NResponseType::Allow: -// return "Allow once"; -// case NResponseType::Deny: -// return "Deny once"; -// case NResponseType::AllowAlways: -// return "Allow always"; -// case NResponseType::DenyAlways: -// return "Deny always"; -// case NResponseType::Error: -// return "Error"; -// default: -// return "None"; -// } -//} -// -//NotificationRequest dataToNotificationRequest(const std::string &data) { -// std::stringstream stream(data); -// std::size_t strSize; -// char separator; -// -// cynara_agent_req_id id; -// std::string members[2]; -// -// stream >> id; -// stream.read(&separator, 1); -// -// for (auto &member : members) { -// stream >> strSize; -// std::vector buffer(strSize, '\0'); -// char separator; -// //Consume separator -// stream.read(&separator, 1); -// stream.read(buffer.data(), strSize); -// //read doesn't append null -// member.assign(buffer.begin(), buffer.end()); -// } -// -// return NotificationRequest({id, std::move(members[0]), "", std::move(members[1])}); -//} -// -//std::string notificationRequestToData(RequestId id, const std::string &client, -// const std::string &privilege) -//{ -// const char separator = ' '; -// return std::to_string(id) + separator + -// std::to_string(client.length()) + separator + client + separator + -// std::to_string(privilege.length()) + separator + privilege + separator + separator; -//} - -} //namespace Translator -} //namespace LicenseManager diff --git a/src/license-manager/common/translator.h b/src/license-manager/common/translator.h deleted file mode 100644 index 172d452..0000000 --- a/src/license-manager/common/translator.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2014-2017 Samsung Electronics Co. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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 translator.h - * @author Zofia Abramowska - * @author Oskar Świtalski - * @author Bartlomiej Grzelewski - * @brief Definition of Translator methods and TranslateErrorException class - */ - -#pragma once - -//#include -//#include -//#include -//#include -#include - -#include -#include - -namespace LicenseManager { -namespace Translator { - -class TranslateErrorException : std::exception { -public: - TranslateErrorException(const std::string &msg) : m_what(msg) {}; - virtual const char* what() const noexcept { - return m_what.c_str(); - } -private: - std::string m_what; -}; - -// RequestData dataToRequest(const Cynara::PluginData &data); -// Cynara::PluginData answerToData(Cynara::PolicyType answer, const std::string &errMsg); - - Cynara::PolicyType dataToAnswer(const Cynara::PluginData &data); - Cynara::PluginData requestToData(const std::string &client, - const std::string &user, - const std::string &privilege); - - -//std::string responseToString(NResponseType response); -//NotificationRequest dataToNotificationRequest(const std::string &data); -//std::string notificationRequestToData(RequestId id, const std::string &client, -// const std::string &privilege); - -} // namespace Translator -} // namespace LicenseManager - -- 2.7.4 From a73a174b9617b0ea9db436fe67ca05be7adbf071 Mon Sep 17 00:00:00 2001 From: Rafal Krypa Date: Mon, 30 Oct 2017 15:39:36 +0100 Subject: [PATCH 12/16] Rework security-manager-migration script as a policy update script This original framework was first policy migration script that appeared in security-manager. It should be adopted by the policy update framework, that was introduced later, but it was overlooked. In order to merge these update infrastructures, migration directory is removed and the original migration script is renamed and adapted as a version 1 policy update, which was previously a no-op. Change-Id: I96c84103d9eda0746bd8d919bc6dd42c3a50a232 Signed-off-by: Rafal Krypa --- CMakeLists.txt | 1 - migration/CMakeLists.txt | 29 ----------------------------- migration/security-manager-migration.in | 26 -------------------------- packaging/security-manager.spec | 2 -- policy/updates/update-policy-to-v1.sh | 24 +++++++++++++++++++++++- 5 files changed, 23 insertions(+), 59 deletions(-) delete mode 100644 migration/CMakeLists.txt delete mode 100644 migration/security-manager-migration.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 0812b0e..93a5e63 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,5 +109,4 @@ ADD_SUBDIRECTORY(pc) ADD_SUBDIRECTORY(systemd) ADD_SUBDIRECTORY(db) ADD_SUBDIRECTORY(policy) -ADD_SUBDIRECTORY(migration) ADD_SUBDIRECTORY(test) diff --git a/migration/CMakeLists.txt b/migration/CMakeLists.txt deleted file mode 100644 index 0094aa6..0000000 --- a/migration/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2016 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 CMakeLists.txt -# @author Bartlomiej Grzelewski -# @brief CMake for migration script -# - -CONFIGURE_FILE(security-manager-migration.in security-manager-migration @ONLY) - -INSTALL(PROGRAMS - ${CMAKE_BINARY_DIR}/migration/security-manager-migration - DESTINATION - ${BIN_INSTALL_DIR} - ) - - - diff --git a/migration/security-manager-migration.in b/migration/security-manager-migration.in deleted file mode 100644 index b435a36..0000000 --- a/migration/security-manager-migration.in +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -PATH=/bin:/usr/bin:/sbin:/usr/sbin -SRC_PATH=/etc/smack/accesses.d -DSC_PATH=@LOCAL_STATE_DIR@/security-manager/rules -MRG_PATH=@LOCAL_STATE_DIR@/security-manager/rules-merged/rules.merged -SHARED_RO_PATH=$DSC_PATH/2x_shared_ro - -echo "Running migration process" - -if [ ! -e $MRG_PATH ] -then - echo "Moving files from ${SRC_PATH} to ${DSC_PATH}" - mv ${SRC_PATH}/app_* ${SRC_PATH}/pkg_* ${SRC_PATH}/author_* ${DSC_PATH} - echo "Merging files from ${DSC_PATH} to ${MRG_PATH}" - cat ${DSC_PATH}/* > ${MRG_PATH} -fi - -if [ ! -e $SHARED_RO_PATH ] -then - echo "Moving SharedRO rules to ${SHARED_RO_PATH}" - cat ${DSC_PATH}/pkg_* | grep 'User::App.*SharedRO' >${SHARED_RO_PATH} - sed '/User::App.*SharedRO/d' -i ${DSC_PATH}/pkg_* -fi - -echo "Migration process was finished" diff --git a/packaging/security-manager.spec b/packaging/security-manager.spec index 1398a43..0485a52 100644 --- a/packaging/security-manager.spec +++ b/packaging/security-manager.spec @@ -168,7 +168,6 @@ if [ $1 = 2 ]; then # update systemctl stop security-manager.socket systemctl stop security-manager.service - %{_bindir}/security-manager-migration systemctl start security-manager.socket systemctl start security-manager.service fi @@ -251,7 +250,6 @@ chsmack -a System %{db_test_dir}/.security-manager-test-empty.db-journal %manifest %{_datadir}/security-manager.manifest %license LICENSE %defattr(-,root,root,-) -%attr(755,root,root) %{_bindir}/security-manager-migration %attr(755,root,root) %{_bindir}/security-manager %attr(755,root,root) %{_bindir}/security-manager-cmd %attr(755,root,root) %{_bindir}/security-manager-cleanup diff --git a/policy/updates/update-policy-to-v1.sh b/policy/updates/update-policy-to-v1.sh index e705cad..d40fb77 100755 --- a/policy/updates/update-policy-to-v1.sh +++ b/policy/updates/update-policy-to-v1.sh @@ -4,4 +4,26 @@ export PATH=/sbin:/usr/sbin:/bin:/usr/bin . /etc/tizen-platform.conf -echo "Initial version, nothing to do" +SRC_PATH=$TZ_SYS_SMACK/accesses.d +DSC_PATH=$TZ_SYS_VAR/security-manager/rules +MRG_PATH=$TZ_SYS_VAR/security-manager/rules-merged/rules.merged +SHARED_RO_PATH=$DSC_PATH/2x_shared_ro + +echo "Running migration process" + +if [ ! -e $MRG_PATH ] +then + echo "Moving files from ${SRC_PATH} to ${DSC_PATH}" + mv ${SRC_PATH}/app_* ${SRC_PATH}/pkg_* ${SRC_PATH}/author_* ${DSC_PATH} + echo "Merging files from ${DSC_PATH} to ${MRG_PATH}" + cat ${DSC_PATH}/* > ${MRG_PATH} +fi + +if [ ! -e $SHARED_RO_PATH ] +then + echo "Moving SharedRO rules to ${SHARED_RO_PATH}" + cat ${DSC_PATH}/pkg_* | grep 'User::App.*SharedRO' > ${SHARED_RO_PATH} + sed '/User::App.*SharedRO/d' -i ${DSC_PATH}/pkg_* +fi + +echo "Migration process was finished" -- 2.7.4 From 624164e35894c4bcffba8f5f3f2b6a0f189180eb Mon Sep 17 00:00:00 2001 From: Zofia Grzelewska Date: Mon, 19 Feb 2018 18:51:47 +0100 Subject: [PATCH 13/16] Change way of displaying performance test results Performance tests didn't show enough info about test parameters. Ratios differ greatly between test cases, it is nice to have more infomation, as to why it might be this way. Added displaying of initial db size and for how many apps app defined privileges were installed. Also changed tests names to better describe test case. Change-Id: Icd1816ec56fd70d15d717231c0b70dc25964741e --- test/test_performance_db.cpp | 112 +++++++++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 52 deletions(-) diff --git a/test/test_performance_db.cpp b/test/test_performance_db.cpp index 385adc4..e148cae 100644 --- a/test/test_performance_db.cpp +++ b/test/test_performance_db.cpp @@ -148,15 +148,21 @@ double getRatio(const duration &largeDbAvgTime, const duration & (duration_cast(smallDbAvgTime).count()); } -void displayResult(const std::string &msg, const duration &largeDbAvgTime, - const duration &smallDbAvgTime, - int fullCount = AVG_LOOPS) +void displayResult(const duration &avgTime, int count, int dbSize, int privs = 0) { - double ratio = getRatio(largeDbAvgTime, smallDbAvgTime); - BOOST_TEST_MESSAGE("\tAverage time for " << msg << convertDurationToString(smallDbAvgTime) - << "\n\tAverage time for " << fullCount - << " apps: " << convertDurationToString(largeDbAvgTime) - << "\n\tRatio: " << ratio); + std::string privsStat = ""; + if (privs != 0) { + privsStat = ", apps with privs : " + std::to_string(privs); + } + BOOST_TEST_MESSAGE("Average time for " << count << " iterations (initial db size : " << dbSize + << privsStat + << ") : " << convertDurationToString(avgTime)); +} + +void displayRatio(const duration &largeDbAvgTime, + const duration &smallDbAvgTime) +{ + BOOST_TEST_MESSAGE("Ratio : " << getRatio(largeDbAvgTime, smallDbAvgTime)); } std::string durationToMicroseconds(const duration &time) @@ -166,40 +172,41 @@ std::string durationToMicroseconds(const duration &time) BOOST_AUTO_TEST_SUITE(PERFORMANCE_DB_TEST) -BOOST_AUTO_TEST_CASE(TXX_db_perf_add) +BOOST_AUTO_TEST_CASE(TXX_db_perf_add_apps) { duration addAppTimeSmallDb, addAppTimeLargeDb; { PrivilegeDBFixture pdf; addAppTimeSmallDb = measureAddAppTime(FEW_LOOPS, pdf) / FEW_LOOPS; + displayResult(addAppTimeSmallDb, FEW_LOOPS, 0); } { PrivilegeDBFixture pdf; - addAppTimeLargeDb = measureAddAppTime(AVG_LOOPS, pdf); - displayResult("adding " + std::to_string(FEW_LOOPS) + " apps: ", addAppTimeLargeDb / AVG_LOOPS, - addAppTimeSmallDb); + addAppTimeLargeDb = measureAddAppTime(AVG_LOOPS, pdf) / AVG_LOOPS; + displayResult(addAppTimeLargeDb, AVG_LOOPS, 0); } + displayRatio(addAppTimeLargeDb, addAppTimeSmallDb); } -BOOST_AUTO_TEST_CASE(TXX_db_perf_priv) +BOOST_AUTO_TEST_CASE(TXX_db_perf_add_app_defined_priv) { duration addPrivTimeSmallDb, addPrivTimeLargeDb; { PrivilegeDBFixture pdf; measureAddAppTime(FEW_LOOPS, pdf); addPrivTimeSmallDb = measureAddPrivilegeTime(FEW_LOOPS, pdf) / FEW_LOOPS; + displayResult(addPrivTimeSmallDb, FEW_LOOPS, FEW_LOOPS); } { PrivilegeDBFixture pdf; measureAddAppTime(AVG_LOOPS, pdf); - addPrivTimeLargeDb = measureAddPrivilegeTime(AVG_LOOPS, pdf); - - displayResult("adding privileges to " + std::to_string(FEW_LOOPS) + " apps: ", - addPrivTimeLargeDb / AVG_LOOPS, addPrivTimeSmallDb); + addPrivTimeLargeDb = measureAddPrivilegeTime(AVG_LOOPS, pdf) / AVG_LOOPS; + displayResult(addPrivTimeLargeDb, AVG_LOOPS, AVG_LOOPS); } + displayRatio(addPrivTimeLargeDb, addPrivTimeSmallDb); } -BOOST_AUTO_TEST_CASE(TXX_db_perf_remove) +BOOST_AUTO_TEST_CASE(TXX_db_perf_remove_app) { duration rmAppTimeSmallDb, rmAppTimeLargeDb; { @@ -207,19 +214,19 @@ BOOST_AUTO_TEST_CASE(TXX_db_perf_remove) measureAddAppTime(FEW_LOOPS, pdf); measureAddPrivilegeTime(FEW_LOOPS, pdf); rmAppTimeSmallDb = measureRemoveTime(FEW_LOOPS, pdf) / FEW_LOOPS; + displayResult(rmAppTimeSmallDb, FEW_LOOPS, FEW_LOOPS, FEW_LOOPS); } { PrivilegeDBFixture pdf; measureAddAppTime(AVG_LOOPS, pdf); measureAddPrivilegeTime(AVG_LOOPS, pdf); - rmAppTimeLargeDb = measureRemoveTime(AVG_LOOPS, pdf); - - displayResult("removing " + std::to_string(FEW_LOOPS) + " apps: ", - rmAppTimeLargeDb / AVG_LOOPS, rmAppTimeSmallDb); + rmAppTimeLargeDb = measureRemoveTime(AVG_LOOPS, pdf) / AVG_LOOPS; + displayResult(rmAppTimeLargeDb, AVG_LOOPS, AVG_LOOPS, AVG_LOOPS); } + displayRatio(rmAppTimeLargeDb, rmAppTimeSmallDb); } -BOOST_AUTO_TEST_CASE(TXX_db_perf_add_custom_author) +BOOST_AUTO_TEST_CASE(TXX_db_perf_add_app_same_author) { duration addAppTimeSmallDb, addAppTimeLargeDb; @@ -233,16 +240,17 @@ BOOST_AUTO_TEST_CASE(TXX_db_perf_add_custom_author) { PrivilegeDBFixture pdf; addAppTimeSmallDb = measureAddAppTime(FEW_LOOPS, pdf, 0, incrementSetAuthor) / FEW_LOOPS; + displayResult(addAppTimeSmallDb, FEW_LOOPS, 0); } { PrivilegeDBFixture pdf; - addAppTimeLargeDb = measureAddAppTime(AVG_LOOPS, pdf, 0, incrementSetAuthor); - displayResult("adding " + std::to_string(FEW_LOOPS) + " apps: ", - addAppTimeLargeDb / AVG_LOOPS, addAppTimeSmallDb); + addAppTimeLargeDb = measureAddAppTime(AVG_LOOPS, pdf, 0, incrementSetAuthor) / AVG_LOOPS; + displayResult(addAppTimeLargeDb, AVG_LOOPS, 0); } + displayRatio(addAppTimeLargeDb, addAppTimeSmallDb); } -BOOST_AUTO_TEST_CASE(TXX_db_perf_priv_custom_author) +BOOST_AUTO_TEST_CASE(TXX_db_perf_add_app_defined_priv_same_author) { duration addPrivTimeSmallDb, addPrivTimeLargeDb; @@ -257,18 +265,18 @@ BOOST_AUTO_TEST_CASE(TXX_db_perf_priv_custom_author) PrivilegeDBFixture pdf; measureAddAppTime(FEW_LOOPS, pdf, 0, incrementSetAuthor); addPrivTimeSmallDb = measureAddPrivilegeTime(FEW_LOOPS, pdf) / FEW_LOOPS; + displayResult(addPrivTimeSmallDb, FEW_LOOPS, FEW_LOOPS); } { PrivilegeDBFixture pdf; measureAddAppTime(AVG_LOOPS, pdf, 0, incrementSetAuthor); - addPrivTimeLargeDb = measureAddPrivilegeTime(AVG_LOOPS, pdf); - - displayResult("adding privileges to " + std::to_string(FEW_LOOPS) + " apps: ", - addPrivTimeLargeDb / AVG_LOOPS, addPrivTimeSmallDb); + addPrivTimeLargeDb = measureAddPrivilegeTime(AVG_LOOPS, pdf) / AVG_LOOPS; + displayResult(addPrivTimeLargeDb, AVG_LOOPS, AVG_LOOPS); } + displayRatio(addPrivTimeLargeDb, addPrivTimeSmallDb); } -BOOST_AUTO_TEST_CASE(TXX_db_perf_remove_custom_author) +BOOST_AUTO_TEST_CASE(TXX_db_perf_remove_app_same_author) { duration rmAppTimeSmallDb, rmAppTimeLargeDb; @@ -284,19 +292,19 @@ BOOST_AUTO_TEST_CASE(TXX_db_perf_remove_custom_author) measureAddAppTime(FEW_LOOPS, pdf, 0, incrementSetAuthor); measureAddPrivilegeTime(FEW_LOOPS, pdf); rmAppTimeSmallDb = measureRemoveTime(FEW_LOOPS, pdf) / FEW_LOOPS; + displayResult(rmAppTimeSmallDb, FEW_LOOPS, FEW_LOOPS, FEW_LOOPS); } { PrivilegeDBFixture pdf; measureAddAppTime(AVG_LOOPS, pdf, 0, incrementSetAuthor); measureAddPrivilegeTime(AVG_LOOPS, pdf); - rmAppTimeLargeDb = measureRemoveTime(AVG_LOOPS, pdf); - - displayResult("removing " + std::to_string(FEW_LOOPS) + " apps: ", - rmAppTimeLargeDb / AVG_LOOPS, rmAppTimeSmallDb); + rmAppTimeLargeDb = measureRemoveTime(AVG_LOOPS, pdf) / AVG_LOOPS; + displayResult(rmAppTimeLargeDb, AVG_LOOPS, AVG_LOOPS, AVG_LOOPS); } + displayRatio(rmAppTimeLargeDb, rmAppTimeSmallDb); } -BOOST_AUTO_TEST_CASE(TXX_db_perf_add_large) +BOOST_AUTO_TEST_CASE(TXX_db_perf_add_app_large_db) { //measures average add time of adding 300 apps when there is 2700 apps installed. duration addAppTimeSmallDb, addAppTimeLargeDb; @@ -305,18 +313,18 @@ BOOST_AUTO_TEST_CASE(TXX_db_perf_add_large) { PrivilegeDBFixture pdf; addAppTimeSmallDb = measureAddAppTime(FEW_LOOPS, pdf) / FEW_LOOPS; + displayResult(addAppTimeSmallDb, FEW_LOOPS, 0); } { PrivilegeDBFixture pdf; measureAddAppTime(EXISTING_APP_COUNT, pdf); - addAppTimeLargeDb = measureAddAppTime(ADD_APP_COUNT, pdf); - - displayResult("adding " + std::to_string(FEW_LOOPS) + " apps: ", - addAppTimeLargeDb / ADD_APP_COUNT, addAppTimeSmallDb, ADD_APP_COUNT); + addAppTimeLargeDb = measureAddAppTime(ADD_APP_COUNT, pdf) / ADD_APP_COUNT; + displayResult(addAppTimeLargeDb, ADD_APP_COUNT, EXISTING_APP_COUNT); } + displayRatio(addAppTimeLargeDb, addAppTimeSmallDb); } -BOOST_AUTO_TEST_CASE(TXX_db_perf_priv_large) +BOOST_AUTO_TEST_CASE(TXX_db_perf_add_app_defined_priv_large_db) { //measures average adding privileges time of adding 300 apps privileges when there is 2700 apps with privileges installed. duration addPrivTimeSmallDb, addPrivTimeLargeDb; @@ -326,38 +334,38 @@ BOOST_AUTO_TEST_CASE(TXX_db_perf_priv_large) PrivilegeDBFixture pdf; measureAddAppTime(FEW_LOOPS, pdf); addPrivTimeSmallDb = measureAddPrivilegeTime(FEW_LOOPS, pdf) / FEW_LOOPS; + displayResult(addPrivTimeSmallDb, FEW_LOOPS, FEW_LOOPS); } { PrivilegeDBFixture pdf; measureAddAppTime(MANY_LOOPS, pdf); measureAddPrivilegeTime(EXISTING_PRIV_COUNT, pdf); - addPrivTimeLargeDb = measureAddPrivilegeTime(ADD_PRIV_COUNT, pdf); - - displayResult("adding privileges to " + std::to_string(FEW_LOOPS) + " apps: ", - addPrivTimeLargeDb / ADD_PRIV_COUNT, addPrivTimeSmallDb, ADD_PRIV_COUNT); + addPrivTimeLargeDb = measureAddPrivilegeTime(ADD_PRIV_COUNT, pdf) / ADD_PRIV_COUNT; + displayResult(addPrivTimeLargeDb, MANY_LOOPS, EXISTING_PRIV_COUNT, ADD_PRIV_COUNT); } + displayRatio(addPrivTimeLargeDb, addPrivTimeSmallDb); } -BOOST_AUTO_TEST_CASE(TXX_db_perf_remove_large) +BOOST_AUTO_TEST_CASE(TXX_db_perf_remove_app_large_db) { //measures average remove time of 10% apps when there is 3000 apps installed. duration rmAppTimeSmallDb, rmAppTimeLargeDb; - const int REMOVE_APP_COUNT = MANY_LOOPS * 0.1; + const int RM_APP_COUNT = MANY_LOOPS * 0.1; { PrivilegeDBFixture pdf; measureAddAppTime(FEW_LOOPS, pdf); measureAddPrivilegeTime(FEW_LOOPS, pdf); rmAppTimeSmallDb = measureRemoveTime(FEW_LOOPS, pdf) / FEW_LOOPS; + displayResult(rmAppTimeSmallDb, FEW_LOOPS, FEW_LOOPS, FEW_LOOPS); } { PrivilegeDBFixture pdf; measureAddAppTime(MANY_LOOPS, pdf); measureAddPrivilegeTime(MANY_LOOPS, pdf); - rmAppTimeLargeDb = measureRemoveTime(REMOVE_APP_COUNT, pdf); - - displayResult("removing " + std::to_string(FEW_LOOPS) + " apps: ", - rmAppTimeLargeDb / REMOVE_APP_COUNT, rmAppTimeSmallDb, REMOVE_APP_COUNT); + rmAppTimeLargeDb = measureRemoveTime(RM_APP_COUNT, pdf) / RM_APP_COUNT; + displayResult(rmAppTimeLargeDb, RM_APP_COUNT, MANY_LOOPS, MANY_LOOPS); } + displayRatio(rmAppTimeLargeDb, rmAppTimeSmallDb); } BOOST_AUTO_TEST_SUITE_END() -- 2.7.4 From 41ead416d525eeb0fe0dbaa575d474cebc968b1c Mon Sep 17 00:00:00 2001 From: Pawel Kowalski Date: Thu, 16 Aug 2018 11:41:20 +0200 Subject: [PATCH 14/16] Add Apache 2.0 license header Change-Id: I43fefb11a6998097c778d76e6d08cab211206d20 --- src/common/smack-check.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/common/smack-check.cpp b/src/common/smack-check.cpp index efc36d7..496a742 100644 --- a/src/common/smack-check.cpp +++ b/src/common/smack-check.cpp @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2013 - 2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + #include #include -- 2.7.4 From 37009a3f744def44cd19b8139a1fdca15e3255b2 Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Thu, 16 Aug 2018 11:49:30 +0200 Subject: [PATCH 15/16] Remove fileExists() duplicates Change-Id: I1ec14dd6d1a60bc481dbe04ec21e70be70c8715e --- src/common/filesystem.cpp | 5 +++++ src/common/include/filesystem.h | 1 + src/common/service_impl.cpp | 10 +--------- src/server/cleanup/security-manager-cleanup.cpp | 9 ++------- 4 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/common/filesystem.cpp b/src/common/filesystem.cpp index 29c019b..33be2e0 100644 --- a/src/common/filesystem.cpp +++ b/src/common/filesystem.cpp @@ -186,6 +186,11 @@ int fileStatus(const std::string &path) return -1; // this is not a file -> error } +bool fileExists(const std::string &path) +{ + return fileStatus(path) == 1; +} + int createFile(const std::string &path) { int fd = open(path.c_str(), O_RDONLY|O_CREAT, 0644); diff --git a/src/common/include/filesystem.h b/src/common/include/filesystem.h index 6bb97d3..d1ba711 100644 --- a/src/common/include/filesystem.h +++ b/src/common/include/filesystem.h @@ -45,6 +45,7 @@ int directoryStatus(const std::string &path); int createDirectory(const std::string &path); int removeDirectory(const std::string &path); int fileStatus(const std::string &path); +bool fileExists(const std::string &path); int createFile(const std::string &path); int removeFile(const std::string &path); int symLink(const std::string &src, const std::string &dst); diff --git a/src/common/service_impl.cpp b/src/common/service_impl.cpp index fe80436..74cccd5 100644 --- a/src/common/service_impl.cpp +++ b/src/common/service_impl.cpp @@ -30,9 +30,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -76,11 +73,6 @@ UninstallHelper::UninstallHelper() { namespace { -bool fileExists(const std::string &path) { - struct stat buffer; - return (stat(path.c_str(), &buffer) == 0) && S_ISREG(buffer.st_mode); -} - std::string realPath(const std::string &path) { auto real_pathPtr = makeUnique(realpath(path.c_str(), nullptr), free); @@ -1732,7 +1724,7 @@ int ServiceImpl::dropOnePrivateSharing( return SECURITY_MANAGER_SUCCESS; } //This function can be also called when application is uninstalled, so path won't exist - if (pathCount < 1 && fileExists(path)) { + if (pathCount < 1 && FS::fileExists(path)) { SmackLabels::setupPath(ownerPkgName, path, SECURITY_MANAGER_PATH_RW); } std::string pathLabel = SmackLabels::generateSharedPrivateLabel(ownerPkgName, path); diff --git a/src/server/cleanup/security-manager-cleanup.cpp b/src/server/cleanup/security-manager-cleanup.cpp index cbb1f13..20986bd 100644 --- a/src/server/cleanup/security-manager-cleanup.cpp +++ b/src/server/cleanup/security-manager-cleanup.cpp @@ -31,16 +31,11 @@ #include #include #include +#include namespace { const std::string tmp_flag = "/tmp/sm-cleanup-tmp-flag"; -bool fileExists(const std::string &path) -{ - struct stat buffer; - return stat(path.c_str(), &buffer) == 0 && S_ISREG(buffer.st_mode); -} - bool createFile(const std::string &path) { int fd; @@ -61,7 +56,7 @@ int main(void) { using namespace SecurityManager; - if (fileExists(tmp_flag)) + if (FS::fileExists(tmp_flag)) return EXIT_SUCCESS; try { -- 2.7.4 From b4de88478c72de430740f0badd680f1a5170d817 Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Tue, 3 Jul 2018 16:06:10 +0200 Subject: [PATCH 16/16] Fix: launch security-manager-cleanup after /opt/usr is mounted. Change-Id: I1f6f4b2a9b9712ee5ed1a1a539a3059249a90b04 --- packaging/security-manager.spec | 6 +++--- systemd/security-manager-cleanup.service.in | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packaging/security-manager.spec b/packaging/security-manager.spec index 0485a52..473098d 100644 --- a/packaging/security-manager.spec +++ b/packaging/security-manager.spec @@ -122,12 +122,12 @@ rm -rf %{buildroot} %make_install mkdir -p %{buildroot}/%{_unitdir}/sockets.target.wants -mkdir -p %{buildroot}/%{_unitdir}/sysinit.target.wants +mkdir -p %{buildroot}/%{_unitdir}/multi-user.target.wants mkdir -p %{buildroot}/%{_unitdir}/basic.target.wants mkdir -p %{buildroot}/%{_unitdir}/dbus.service.wants mkdir -p %{buildroot}/%{_unitdir}/cynara.service.wants ln -s ../security-manager.socket %{buildroot}/%{_unitdir}/sockets.target.wants/security-manager.socket -ln -s ../security-manager-cleanup.service %{buildroot}/%{_unitdir}/sysinit.target.wants/security-manager-cleanup.service +ln -s ../security-manager-cleanup.service %{buildroot}/%{_unitdir}/multi-user.target.wants/security-manager-cleanup.service ln -s ../security-manager-rules-loader.service %{buildroot}/%{_unitdir}/basic.target.wants/security-manager-rules-loader.service ln -s ../security-manager.service %{buildroot}/%{_unitdir}/dbus.service.wants/security-manager.service ln -s ../license-manager-agent.service %{buildroot}/%{_unitdir}/cynara.service.wants/license-manager-agent.service @@ -267,7 +267,7 @@ chsmack -a System %{db_test_dir}/.security-manager-test-empty.db-journal %attr(-,root,root) %{_unitdir}/security-manager-rules-loader.service %attr(-,root,root) %{_unitdir}/basic.target.wants/security-manager-rules-loader.service %attr(-,root,root) %{_unitdir}/sockets.target.wants/security-manager.* -%attr(-,root,root) %{_unitdir}/sysinit.target.wants/security-manager-cleanup.* +%attr(-,root,root) %{_unitdir}/multi-user.target.wants/security-manager-cleanup.* %config(noreplace) %attr(0600,root,root) %{TZ_SYS_DB}/.security-manager.db %config(noreplace) %attr(0600,root,root) %{TZ_SYS_DB}/.security-manager.db-journal diff --git a/systemd/security-manager-cleanup.service.in b/systemd/security-manager-cleanup.service.in index 59d27a4..a82263d 100644 --- a/systemd/security-manager-cleanup.service.in +++ b/systemd/security-manager-cleanup.service.in @@ -1,8 +1,8 @@ [Unit] Description=Cleanup private sharing -DefaultDependencies=no -After=sysinit.target -Requires=sysinit.target +RequiresMountsFor=/tmp +Wants=wait-mount@opt-usr.service +After=wait-mount@opt-usr.service [Service] Type=oneshot -- 2.7.4