Simplify and fix code generating SharedRO Smack rules 93/70593/3
authorRafal Krypa <r.krypa@samsung.com>
Fri, 20 May 2016 11:55:04 +0000 (13:55 +0200)
committerRafal Krypa <r.krypa@samsung.com>
Fri, 20 May 2016 11:55:04 +0000 (13:55 +0200)
Smack rules for cross-package access to SharedRO labels are now kept in
a separate file that is fully regenerated after a Tizen 2.x application
is installed or removed.

This also fixes error that the previous implementation had, with superflous
Smack rule from Tizen 2.x applications to SharedRO rule of their own pkg.
Such rules collided with rules of the same subject and object but different
access modes. Each app gets such rule for SharedRO label of own package
from app-rules-template.smack template, but with RW access. Overwrite of
such rule by cross-package RO rule lead to incorrect access.

Change-Id: I70ee47606c7548d1c0d2dee83eacaae4b64cea9c

migration/security-manager-migration.in
src/common/include/privilege_db.h
src/common/include/service_impl.h
src/common/include/smack-rules.h
src/common/privilege_db.cpp
src/common/service_impl.cpp
src/common/smack-rules.cpp

index f08469c..204fb13 100644 (file)
@@ -3,16 +3,23 @@
 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
 
-if [ -e $MRG_PATH ]; then
-    echo "No migration needed. File ${MRG_PATH} already exists."
-    exit 0
+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
 
-echo "Running migration process"
-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}
-echo "Migration process was finished"
+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"
index 05ffb23..23b969e 100644 (file)
@@ -66,8 +66,7 @@ enum class StmtType {
     EClearPrivatePaths,
     EGetPrivilegeGroups,
     EGetUserApps,
-    EGetAllTizen2XApps,
-    EGetAllTizen2XPackages,
+    EGetTizen2XPackages,
     EGetAppsInPkg,
     EGetGroups,
     EGetPkgAuthorId,
@@ -122,8 +121,7 @@ private:
         { StmtType::EClearPrivatePaths, "DELETE FROM shared_path;"},
         { StmtType::EGetPrivilegeGroups, " SELECT group_name FROM privilege_group_view WHERE privilege_name = ?" },
         { StmtType::EGetUserApps, "SELECT name FROM app WHERE uid=?" },
-        { StmtType::EGetAllTizen2XApps,  "SELECT name FROM app WHERE version LIKE '2.%%' AND name <> ?" },
-        { StmtType::EGetAllTizen2XPackages,  "SELECT DISTINCT pkg_name FROM app_pkg_view WHERE version LIKE '2.%%'" },
+        { StmtType::EGetTizen2XPackages,  "SELECT DISTINCT pkg_name FROM app_pkg_view WHERE version LIKE '2.%%'" },
         { StmtType::EGetAppsInPkg, " SELECT app_name FROM app_pkg_view WHERE pkg_name = ?" },
         { StmtType::EGetGroups, "SELECT DISTINCT group_name FROM privilege_group_view" },
         { StmtType::EGetPkgAuthorId, "SELECT author_id FROM pkg WHERE name = ? AND author_id IS NOT NULL"},
@@ -435,18 +433,6 @@ public:
     void GetPkgApps(const std::string &pkgName, std::vector<std::string> &appNames);
 
     /**
-     * Retrieve list of all apps excluding one specified (typically action originator)
-     *
-     * @param origApp - do not include specific application name in the list
-     * @param[out] apps - vector of application identifiers describing installed 2.x apps,
-     *                    this parameter do not need to be empty, but
-     *                    it is being overwritten during function call.
-     * @exception DB::SqlConnection::Exception::InternalError on internal error
-     * @exception DB::SqlConnection::Exception::ConstraintError on constraint violation
-     */
-    void GetTizen2XApps(const std::string &origApp, std::vector<std::string> &apps);
-
-    /**
      * Retrieve list of all Tizen 2.X packages
      *
      * @param[out] packages - vector of package identifiers describing installed 2.x packages,
index 53917bd..8c9129c 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "credentials.h"
 #include "security-manager.h"
+#include "smack-rules.h"
 #include "protocols.h"
 
 namespace SecurityManager {
@@ -64,6 +65,8 @@ private:
                              app_install_type installationType,
                              const uid_t &uid);
 
+    static void getTizen2XApps(SmackRules::PkgsApps &pkgsApps);
+
     static bool getZoneId(std::string &zoneId);
 
     int dropOnePrivateSharing(const std::string &ownerAppName,
index 2a88b60..4e8962b 100644 (file)
@@ -38,6 +38,7 @@ class SmackRules
 public:
     typedef std::string Rule;
     typedef std::vector<Rule> RuleVector;
+    typedef std::vector<std::pair<std::string, std::vector<std::string>>> PkgsApps;
 
     SmackRules();
     virtual ~SmackRules();
@@ -75,14 +76,24 @@ public:
     void generatePackageCrossDeps(const std::vector<std::string> &pkgContents);
 
     /**
-     * Create cross dependencies for all other 2.X applications
+     * Generate SharedRO rules for Tizen 2.x applications
+     * Each 2.X application gets read-only access to files shared by all other 2.X packages.
      *
-     * @param[in] pkgName - installed package identifier to access it's shared dir
-     * @param[in] other2XApps - list of 2.x apps to grant access
+     * @param[in] pkgsApps    vector of Tizen 2.X applications - each element contains
+     *                        a pair with package name and contents
      */
-    void generateAllowOther2XApplicationDeps(
-            const std::string pkgName,
-            const std::vector<std::string> &other2XApps);
+    static void generateSharedRORules(PkgsApps &pkgsApps);
+
+    /**
+     * Revoke SharedRO rules for Tizen 2.x applications when a package is being removed
+     * Rules from all applications in \ref pkgsApps to SharedRO label of the package
+     * under removal will be revoked from kernel.
+     *
+     * @param[in] pkgsApps    vector of Tizen 2.X applications - each element contains
+     *                        a pair with package name and contents
+     * @param[in] revokePkg   package name being removed
+     */
+    static void revokeSharedRORules(PkgsApps &pkgsApps, const std::string &revokePkg);
 
     /**
      * Install package-specific smack rules plus add rules for specified external apps.
@@ -94,16 +105,12 @@ public:
      * @param[in] pkgName - package identifier
      * @param[in] authorId - author id of application
      * @param[in] pkgContents - list of all applications in the package
-     * @param[in] appsGranted - list of 2.x apps granted access
-     * @param[in] accessPackages - list of 2.x packages to be accessed
      */
     static void installApplicationRules(
             const std::string &appName,
             const std::string &pkgName,
             const int authorId,
-            const std::vector<std::string> &pkgContents,
-            const std::vector<std::string> &appsGranted,
-            const std::vector<std::string> &accessPackages);
+            const std::vector<std::string> &pkgContents);
 
     /**
      * Uninstall package-specific smack rules.
@@ -134,12 +141,10 @@ public:
      *
      * @param[in] pkgName - package identifier that the application is in
      * @param[in] pkgContents - list of all applications in the package
-     * @param[in] appsGranted - list of 2.x apps granted access
      */
     static void updatePackageRules(
             const std::string &pkgName,
-            const std::vector<std::string> &pkgContents,
-            const std::vector<std::string> &appsGranted);
+            const std::vector<std::string> &pkgContents);
 
     /**
      * Uninstall author-specific smack rules.
@@ -194,8 +199,6 @@ public:
                                         bool isPathSharedNoMore,
                                         bool isTargetSharingNoMore);
 
-    static void updatePackageRules(const std::string &pkgName, const std::vector<std::string> &pkgContents);
-
     /**
      * This function will read all rules created by security-manager and
      * save them in one file. This file will be used during next system
@@ -243,16 +246,6 @@ private:
     static void uninstallRules(const std::string &path);
 
     /**
-     * Allow application to access other packages shared directory.
-     *
-     * @param[in] appName - application identifier
-     * @param[in] other2XPackages - list of 2.x packages to be accessed
-     */
-    static void generateAppToOtherPackagesDeps(
-            const std::string appName,
-            const std::vector<std::string> &other2XPackages);
-
-    /**
      * Helper method: replace all occurrences of \ref needle in \ref haystack
      * with \ref replace.
      *
index 3254330..54bc75a 100644 (file)
@@ -434,24 +434,10 @@ void PrivilegeDb::GetUserApps(uid_t uid, std::vector<std::string> &apps)
     });
 }
 
-void PrivilegeDb::GetTizen2XApps(const std::string& origApp, std::vector<std::string> &apps)
-{
-    try_catch<void>([&] {
-        auto command = getStatement(StmtType::EGetAllTizen2XApps);
-        command->BindString(1, origApp);
-        apps.clear();
-        while (command->Step()) {
-            const std::string & tizen2XApp = command->GetColumnString(0);
-            LogDebug("Found " << tizen2XApp << " Tizen 2.X apps installed");
-            apps.push_back(tizen2XApp);
-        };
-     });
-}
-
 void PrivilegeDb::GetTizen2XPackages(std::vector<std::string> &packages)
 {
     try_catch<void>([&] {
-        auto command = getStatement(StmtType::EGetAllTizen2XPackages);
+        auto command = getStatement(StmtType::EGetTizen2XPackages);
         packages.clear();
         while (command->Step()) {
             const std::string & tizen2XPkg = command->GetColumnString(0);
index 9b9b0dc..4ea0baa 100755 (executable)
@@ -375,6 +375,18 @@ int ServiceImpl::labelPaths(const pkg_paths &paths,
     }
 }
 
+void ServiceImpl::getTizen2XApps(SmackRules::PkgsApps &pkgsApps)
+{
+    std::vector<std::string> pkgs;
+    PrivilegeDb::getInstance().GetTizen2XPackages(pkgs);
+
+    pkgsApps.resize(pkgs.size());
+    for (size_t i = 0; i < pkgs.size(); ++i) {
+        pkgsApps[i].first = std::move(pkgs[i]);
+        PrivilegeDb::getInstance().GetPkgApps(pkgsApps[i].first, pkgsApps[i].second);
+    }
+}
+
 int ServiceImpl::appInstall(const Credentials &creds, app_inst_req &&req)
 {
     std::vector<std::string> addedPermissions;
@@ -384,7 +396,7 @@ int ServiceImpl::appInstall(const Credentials &creds, app_inst_req &&req)
     std::string pkgBasePath;
     std::string appLabel;
     std::string pkgLabel;
-    std::vector<std::string> allTizen2XApps, allTizen2XPackages;
+    SmackRules::PkgsApps tizen2XpkgsApps;
     int authorId;
 
     try {
@@ -422,10 +434,8 @@ int ServiceImpl::appInstall(const Credentials &creds, app_inst_req &&req)
         CynaraAdmin::getInstance().UpdateAppPolicy(appLabel, cynaraUserStr, req.privileges);
 
         // if app is targetted to Tizen 2.X, give other 2.X apps RO rules to it's shared dir
-        if(isTizen2XVersion(req.tizenVersion)) {
-            PrivilegeDb::getInstance().GetTizen2XApps(req.appName, allTizen2XApps);
-            PrivilegeDb::getInstance().GetTizen2XPackages(allTizen2XPackages);
-        }
+        if (isTizen2XVersion(req.tizenVersion))
+            getTizen2XApps(tizen2XpkgsApps);
 
         // WTF? Why this commit is here? Shouldn't it be at the end of this function?
         PrivilegeDb::getInstance().CommitTransaction();
@@ -465,7 +475,11 @@ int ServiceImpl::appInstall(const Credentials &creds, app_inst_req &&req)
     try {
         LogDebug("Adding Smack rules for new appName: " << req.appName << " with pkgName: "
                 << req.pkgName << ". Applications in package: " << pkgContents.size());
-        SmackRules::installApplicationRules(req.appName, req.pkgName, authorId, pkgContents, allTizen2XApps, allTizen2XPackages);
+        SmackRules::installApplicationRules(req.appName, req.pkgName, authorId, pkgContents);
+
+        if (isTizen2XVersion(req.tizenVersion))
+            SmackRules::generateSharedRORules(tizen2XpkgsApps);
+
         SmackRules::mergeRules();
     } catch (const SmackException::InvalidParam &e) {
         LogError("Invalid paramater during labeling: " << e.GetMessage());
@@ -486,14 +500,13 @@ int ServiceImpl::appInstall(const Credentials &creds, app_inst_req &&req)
 
 int ServiceImpl::appUninstall(const Credentials &creds, app_inst_req &&req)
 {
-    std::string tizenVersion;
     std::string smackLabel;
     std::vector<std::string> pkgContents;
     bool removeApp = false;
     bool removePkg = false;
     bool removeAuthor = false;
     std::string cynaraUserStr;
-    std::vector<std::string> allTizen2XApps;
+    SmackRules::PkgsApps tizen2XpkgsApps;
     int authorId;
 
     installRequestMangle(req, cynaraUserStr);
@@ -527,16 +540,15 @@ int ServiceImpl::appUninstall(const Credentials &creds, app_inst_req &&req)
             package that the app appears in */
         PrivilegeDb::getInstance().GetPkgAuthorId(req.pkgName, authorId);
         PrivilegeDb::getInstance().GetPkgApps(req.pkgName, pkgContents);
+        PrivilegeDb::getInstance().GetAppVersion(req.appName, req.tizenVersion);
         PrivilegeDb::getInstance().UpdateAppPrivileges(req.appName, req.uid, std::vector<std::string>());
         PrivilegeDb::getInstance().RemoveApplication(req.appName, req.uid, removeApp, removePkg, removeAuthor);
 
         // if uninstalled app is targetted to Tizen 2.X, remove other 2.X apps RO rules it's shared dir
-        PrivilegeDb::getInstance().GetAppVersion(req.appName, tizenVersion);
-        if (isTizen2XVersion(tizenVersion))
-            PrivilegeDb::getInstance().GetTizen2XApps(req.appName, allTizen2XApps);
+        if (isTizen2XVersion(req.tizenVersion))
+            getTizen2XApps(tizen2XpkgsApps);
 
         CynaraAdmin::getInstance().UpdateAppPolicy(smackLabel, cynaraUserStr, std::vector<std::string>());
-
         PrivilegeDb::getInstance().CommitTransaction();
         LogDebug("Application uninstallation commited to database");
     } catch (const PrivilegeDb::Exception::IOError &e) {
@@ -569,7 +581,13 @@ int ServiceImpl::appUninstall(const Credentials &creds, app_inst_req &&req)
             if (!removePkg) {
                 LogDebug("Recreating Smack rules for pkgName " << req.pkgName);
                 pkgContents.erase(std::remove(pkgContents.begin(), pkgContents.end(),req.appName), pkgContents.end());
-                SmackRules::updatePackageRules(req.pkgName, pkgContents, allTizen2XApps);
+                SmackRules::updatePackageRules(req.pkgName, pkgContents);
+            }
+
+            if (isTizen2XVersion(req.tizenVersion)) {
+                SmackRules::generateSharedRORules(tizen2XpkgsApps);
+                if (removePkg)
+                    SmackRules::revokeSharedRORules(tizen2XpkgsApps, req.pkgName);
             }
         }
 
index f00fd33..6630fcd 100755 (executable)
@@ -55,6 +55,7 @@ const char *const AUTHOR_RULES_TEMPLATE_FILE_PATH =
 const char *const SMACK_RULES_PATH_MERGED      = LOCAL_STATE_DIR "/security-manager/rules-merged/rules.merged";
 const char *const SMACK_RULES_PATH_MERGED_T    = LOCAL_STATE_DIR "/security-manager/rules-merged/rules.merged.temp";
 const char *const SMACK_RULES_PATH             = LOCAL_STATE_DIR "/security-manager/rules";
+const char *const SMACK_RULES_SHARED_RO_PATH   = LOCAL_STATE_DIR "/security-manager/rules/2x_shared_ro";
 const char *const SMACK_APP_IN_PACKAGE_PERMS   = "rwxat";
 const char *const SMACK_APP_CROSS_PKG_PERMS    = "rx";
 const char *const SMACK_APP_PATH_OWNER_PERMS = "rwxat";
@@ -255,48 +256,49 @@ void SmackRules::generatePackageCrossDeps(const std::vector<std::string> &pkgCon
     }
 }
 
-void SmackRules::generateAppToOtherPackagesDeps(
-        const std::string appName,
-        const std::vector<std::string> &other2XPackages)
+void SmackRules::generateSharedRORules(PkgsApps &pkgsApps)
 {
-    // reverse: allow installed app to access others' contents
-    // for every 2.X package
-    for (const auto &object : other2XPackages) {
-        std::string otherObjectLabel = SmackLabels::generatePkgLabelOwnerRWothersRO(object);
-
-        SmackRules packageRules;
-        std::string accessPackageRulesPath = getPackageRulesFilePath(object);
-        packageRules.loadFromFile(accessPackageRulesPath);
-
-        std::string subjectLabel = SmackLabels::generateAppLabel(appName);
-        LogDebug("Addding cross app rule for newly installed subject " << subjectLabel << " to already installed 2.x package object: " << otherObjectLabel << " perms: " << SMACK_APP_CROSS_PKG_PERMS);
-        packageRules.add(subjectLabel, otherObjectLabel, SMACK_APP_CROSS_PKG_PERMS);
-        packageRules.saveToFile(accessPackageRulesPath);
-        if (smack_smackfs_path() != NULL)
-            packageRules.apply();
+    LogDebug("Generating SharedRO rules");
+
+    SmackRules rules;
+    for (size_t i = 0; i < pkgsApps.size(); ++i) {
+        for (const std::string &appName : pkgsApps[i].second) {
+            std::string appLabel = SmackLabels::generateAppLabel(appName);
+            for (size_t j = 0; j < pkgsApps.size(); ++j) {
+                if (j != i) { // Rules for SharedRO files from own pkg are generated elsewhere
+                    std::string &pkgName = pkgsApps[j].first;
+                    rules.add(appLabel,
+                        SmackLabels::generatePkgLabelOwnerRWothersRO(pkgName),
+                        SMACK_APP_CROSS_PKG_PERMS);
+                }
+            }
+        }
     }
+
+    if (smack_smackfs_path() != NULL)
+        rules.apply();
+
+    rules.saveToFile(SMACK_RULES_SHARED_RO_PATH);
 }
 
-/**
- * this below works in N^2 and should be replaced by an alternative mechanism
- */
-void SmackRules::generateAllowOther2XApplicationDeps(
-        const std::string pkgName,
-        const std::vector<std::string> &other2XApps)
+void SmackRules::revokeSharedRORules(PkgsApps &pkgsApps, const std::string &revokePkg)
 {
-    LogDebug("Generating cross-package rules");
-
-    std::string objectLabel = SmackLabels::generatePkgLabelOwnerRWothersRO(pkgName);
-    std::string appsInPackagePerms = SMACK_APP_IN_PACKAGE_PERMS;
+    LogDebug("Revoking SharedRO rules for target pkg " << revokePkg);
 
-    // allow other app to access installed package contents
-    for (const auto &subject : other2XApps) {
-        std::string subjectLabel = SmackLabels::generateAppLabel(subject);
+    if (smack_smackfs_path() == NULL)
+        return;
 
-        LogDebug("Addding cross 2.x app rule subject: " << subjectLabel << " to newly installed object: "
-            << objectLabel << " perms: " << SMACK_APP_CROSS_PKG_PERMS);
-        add(subjectLabel, objectLabel, SMACK_APP_CROSS_PKG_PERMS);
+    SmackRules rules;
+    for (size_t i = 0; i < pkgsApps.size(); ++i) {
+        for (const std::string &appName : pkgsApps[i].second) {
+            std::string appLabel = SmackLabels::generateAppLabel(appName);
+            rules.add(appLabel,
+                SmackLabels::generatePkgLabelOwnerRWothersRO(revokePkg),
+                SMACK_APP_CROSS_PKG_PERMS);
+        }
     }
+
+    rules.clear();
 }
 
 std::string SmackRules::getPackageRulesFilePath(const std::string &pkgName)
@@ -408,23 +410,19 @@ void SmackRules::installApplicationRules(
         const std::string &appName,
         const std::string &pkgName,
         const int authorId,
-        const std::vector<std::string> &pkgContents,
-        const std::vector<std::string> &appsGranted,
-        const std::vector<std::string> &accessPackages)
+        const std::vector<std::string> &pkgContents)
 {
     useTemplate(APP_RULES_TEMPLATE_FILE_PATH, getApplicationRulesFilePath(appName), appName, pkgName, authorId);
 
     if (authorId >= 0)
         useTemplate(AUTHOR_RULES_TEMPLATE_FILE_PATH, getAuthorRulesFilePath(authorId), appName, pkgName, authorId);
 
-    updatePackageRules(pkgName, pkgContents, appsGranted);
-    generateAppToOtherPackagesDeps(appName, accessPackages);
+    updatePackageRules(pkgName, pkgContents);
 }
 
 void SmackRules::updatePackageRules(
         const std::string &pkgName,
-        const std::vector<std::string> &pkgContents,
-        const std::vector<std::string> &appsGranted)
+        const std::vector<std::string> &pkgContents)
 {
     SmackRules smackRules;
     smackRules.addFromTemplateFile(
@@ -434,7 +432,6 @@ void SmackRules::updatePackageRules(
             -1);
 
     smackRules.generatePackageCrossDeps(pkgContents);
-    smackRules.generateAllowOther2XApplicationDeps(pkgName, appsGranted);
 
     if (smack_smackfs_path() != NULL)
         smackRules.apply();