Keep a pid->owner mapping 53/322853/14
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Wed, 23 Apr 2025 12:22:59 +0000 (14:22 +0200)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Thu, 24 Apr 2025 08:14:23 +0000 (08:14 +0000)
Global applications are installed as a tizenglobalapp user (201) but are
launched as regular user (e.g. owner=5001). In smack-enabled image,
security_manager_get_app_owner_uid() returns the uid of the running app
(e.g. 5001) and not the uid of the user for whom the app was installed
(201).

This patch adds pid->owner mapping that keeps track of the original
process uid of each running app to be able to return it from above
function.

Change-Id: Ia190bb52d1dca61039eab0f879da8bb19cb04bd7

src/client/client-security-manager.cpp
src/common/CMakeLists.txt
src/common/include/pid-to-owner.h [new file with mode: 0644]
src/common/include/privilege_db.h
src/common/include/service_impl.h
src/common/pid-to-owner.cpp [new file with mode: 0644]
src/common/privilege_db.cpp
src/common/service_impl.cpp
src/include/app-runtime.h
src/server/service/include/service.h
src/server/service/service.cpp

index e11632502eac8dd62d0162c58c695c13eb596d2d..c9f540e60f3e93b9360bccedc13e10e235844cea 100644 (file)
@@ -2042,7 +2042,7 @@ int security_manager_get_app_owner_uid(pid_t pid, uid_t *uid)
     using namespace SecurityManager;
     return try_catch([&]() -> int {
         ClientRequest request(SecurityModuleCall::APP_GET_OWNER);
-        request.send(puid);
+        request.send();
         if (!request.failed()) {
             request.recv(ownerId);
             LogInfo("Received ownerId: " << ownerId << " for app PID " << pid);
index 84658c239dd3be61c501fc577987c4369fa67d72..7e3c92a85b17cbd11d38588ffa7b02bd2bf552f7 100644 (file)
@@ -86,6 +86,7 @@ SET(COMMON_SOURCES
     ${COMMON_PATH}/protocols.cpp
     ${COMMON_PATH}/nsmount-logic.cpp
     ${COMMON_PATH}/path-setup.cpp
+    ${COMMON_PATH}/pid-to-owner.cpp
     ${COMMON_PATH}/privilege_db.cpp
     ${COMMON_PATH}/smack-labels.cpp
     ${COMMON_PATH}/smack-accesses.cpp
diff --git a/src/common/include/pid-to-owner.h b/src/common/include/pid-to-owner.h
new file mode 100644 (file)
index 0000000..36326e8
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ * This file is licensed under the terms of MIT License or the Apache License
+ * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
+ * See the LICENSE file or the notice below for Apache License Version 2.0
+ * details.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <mutex>
+#include <optional>
+#include <unordered_map>
+
+#include <sys/types.h>
+
+namespace SecurityManager {
+
+class PidToOwner {
+public:
+    void add(pid_t pid, uid_t owner);
+    void remove(pid_t pid);
+    std::optional<uid_t> get(pid_t pid) const;
+
+private:
+    std::unordered_map<pid_t, uid_t> m_pid2Owner;
+    mutable std::mutex m_apiMutex;
+};
+
+} // namespace SecurityManager
index 6850783f0a0a9be52a22507c06fb46a160c5e766..df85303a16fdec86055dd775debde0999d16791d 100644 (file)
@@ -56,7 +56,6 @@ enum class StmtType : uint8_t {
     EPkgNameExists,
     EAppNameExists,
     EGetAppNameAndPkg,
-    EGetAppOwner,
     EGetAppPkgName,
     EGetAppPkgInfo,
     EGetAppPuidAndAgid,
@@ -264,17 +263,6 @@ public:
      */
     void GetAppNameAndPkg(uid_t puid, std::string &appName, std::string &pkgName);
 
-    /**
-     * Return the uid of and application's owner given its puid
-     *
-     * @param puid - the puid identifying the application
-     * @param[out] ownerId - return application's owner's id
-     * @exception PrivilegeDb::Exception::InternalError on internal error
-     * @exception PrivilegeDb::Exception::ConstraintError on constraint violation
-     * @return true if owner is found in the database
-     */
-    bool GetAppOwner(uid_t puid, uid_t &ownerId);
-
     /**
      * Return package id associated with a given application id
      *
index 0b8636120227925955423fb89674d33f390fbdfd..bc13702d8005cdbf46caf693d7209965da4ba481 100644 (file)
@@ -43,6 +43,7 @@
 #include "security-manager.h"
 #include "smack-common.h"
 #include "smack-rules.h"
+#include "pid-to-owner.h"
 #include "protocols.h"
 #include "privilege_db.h"
 #include "privilege-gids.h"
@@ -121,12 +122,12 @@ public:
     * Process a request to get an application's owner uid.
     * Retrieves the uid of and application's owner given its puid.
     *
-    * @param[in] puid application process identifier
+    * @param[in] pid application process identifier
     * @param[out] ownerId returned application owner uid
     *
     * @return API return code, as defined in protocols.h
     */
-    int getAppOwner(uid_t puid, uid_t &ownerId);
+    int getAppOwner(pid_t pid, uid_t &ownerId);
 
     /**
     * Process package id query.
@@ -535,6 +536,7 @@ private:
     SmackRules m_smackRules;    // seems to work out of the box, assuming that libsmack can be used from many threads at once
     PrivilegeDb m_privilegeDb;  // added api mutex -> if one thread only does RW ScopedTransactions (from service_impl), its okay
     CynaraAdmin m_cynaraAdmin;  // added api mutex
+    PidToOwner m_pidToOwner;    // added api mutex
     PrivilegeGids m_privilegeGids;  // seems to work out of the box, all accessed methods are const
     NSMountLogic m_NSMountLogic;// is okay, used only on policy update
     // below elements are set once and not changed, can be read from many threads
diff --git a/src/common/pid-to-owner.cpp b/src/common/pid-to-owner.cpp
new file mode 100644 (file)
index 0000000..6234132
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ * This file is licensed under the terms of MIT License or the Apache License
+ * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
+ * See the LICENSE file or the notice below for Apache License Version 2.0
+ * details.
+ *
+ * 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 "pid-to-owner.h"
+
+#include "smack-check.h"
+
+namespace SecurityManager {
+
+void PidToOwner::add(pid_t pid, uid_t owner)
+{
+    if (smack_simple_check())
+        return;
+
+    std::lock_guard guard(m_apiMutex);
+    m_pid2Owner[pid] = owner;
+}
+
+void PidToOwner::remove(pid_t pid)
+{
+    if (smack_simple_check())
+        return;
+
+    std::lock_guard guard(m_apiMutex);
+    m_pid2Owner.erase(pid);
+}
+
+std::optional<uid_t> PidToOwner::get(pid_t pid) const
+{
+    if (smack_simple_check())
+        return std::nullopt;
+
+    std::lock_guard guard(m_apiMutex);
+
+    auto it = m_pid2Owner.find(pid);
+    if (it == m_pid2Owner.end())
+        return std::nullopt;
+
+    return it->second;
+}
+
+} // namespace SecurityManager
index 7f3d1eb0b7a6ce27d8889f45146b3f3707993b0d..761c180fe97c79bf4032daa397b15dd1c6a2b1d3 100644 (file)
@@ -55,7 +55,6 @@ constexpr const char *g_queries[StmtTypeCount] = {
     [underlying(StmtType::EPkgNameExists)] = "SELECT count(*) FROM pkg WHERE name=?",
     [underlying(StmtType::EAppNameExists)] = "SELECT count(*) FROM app WHERE name=?",
     [underlying(StmtType::EGetAppNameAndPkg)] = "SELECT is_hybrid, app_name, pkg_name FROM user_app_pkg_view WHERE (is_hybrid = 1 AND app_id = ?) OR (is_hybrid = 0 AND pkg_id = ?)",
-    [underlying(StmtType::EGetAppOwner)] = "SELECT uid, sum(is_hybrid) FROM user_app_pkg_view WHERE (is_hybrid = 1 AND app_id = ?) OR (is_hybrid = 0 AND pkg_id = ?) GROUP BY uid",
     [underlying(StmtType::EGetAppPkgName)] = "SELECT pkg_name FROM user_app_pkg_view WHERE app_name = ?",
     [underlying(StmtType::EGetAppPkgInfo)] = "SELECT pkg.name, pkg.is_hybrid, pkg.shared_ro FROM app, pkg WHERE app.name = ? AND app.pkg_id = pkg.pkg_id",
     [underlying(StmtType::EGetAppPuidAndAgid)] = "SELECT CASE WHEN (is_hybrid = 1) THEN app_id ELSE pkg_id END, author_id FROM user_app_pkg_view WHERE app_name = ?",
@@ -278,37 +277,6 @@ void PrivilegeDb::GetAppNameAndPkg(uid_t puid, std::string &appName, std::string
     });
 }
 
-bool PrivilegeDb::GetAppOwner(uid_t puid, uid_t &ownerId)
-{
-    return try_catch_db(m_api_mutex, [&] {
-        auto command = getStatement(StmtType::EGetAppOwner);
-        command->BindInteger(1, puid);
-        command->BindInteger(2, puid);
-
-        if (command->Step())
-            ownerId = command->GetColumnInteger(0);
-        else {
-            LogError("Could not find an owner UID for the PUID given: " << puid);
-            return false;
-        }
-
-        // Check how many hybrid apps with the same owner UID and PUID there are.
-        // In case there is more than 1, an error must have occured.
-        int hybridSum = command->GetColumnInteger(1);
-        if (hybridSum > 1)
-            ThrowMsg(PrivilegeDb::Exception::InternalError,
-            "More than 1 hybrid app with given PUID found");
-
-        // Check the next rows.
-        // There should not be any more entries with the same PUID but a diferent owner UID.
-        if (command->Step())
-            ThrowMsg(PrivilegeDb::Exception::InternalError,
-            "More than 1 owner UID found for the app with given PUID");
-
-        return true;
-    });
-}
-
 void PrivilegeDb::GetAppPkgName(const std::string &appName, std::string &pkgName)
 {
     return try_catch_db(m_api_mutex, [&] {
index 759ee26f505e44c30010416bc75fc8f1020afbad..edd615b092a73a2b56d79439ff49bc7d05a506d1 100644 (file)
@@ -1198,18 +1198,15 @@ int ServiceImpl::getAppNameAndPkg(uid_t puid, std::string &appName, std::string
     return SECURITY_MANAGER_SUCCESS;
 }
 
-int ServiceImpl::getAppOwner(uid_t puid, uid_t &ownerId)
+int ServiceImpl::getAppOwner(pid_t pid, uid_t &ownerId)
 {
-    try {
-        if (!m_privilegeDb.GetAppOwner(puid, ownerId)) {
-            LogWarning("Application with uid: " << puid << " not found in database");
-            return SECURITY_MANAGER_ERROR_NO_SUCH_OBJECT;
-        } else {
-            LogDebug("ownerId: " << ownerId);
-        }
-    } catch (const PrivilegeDb::Exception::Base &e) {
-        LogError("Error while getting ownerId from database: " << e.DumpToString());
-        return SECURITY_MANAGER_ERROR_SERVER_ERROR;
+    auto uid = m_pidToOwner.get(pid);
+    if (!uid) {
+        LogWarning("No app for pid " <<  pid << " found in owner mapping");
+        return SECURITY_MANAGER_ERROR_NO_SUCH_OBJECT;
+    } else {
+        ownerId = *uid;
+        LogInfo("ownerId: " << ownerId);
     }
 
     return SECURITY_MANAGER_SUCCESS;
@@ -2726,6 +2723,7 @@ int ServiceImpl::appCleanNamespace(const Credentials &creds, const std::string &
     if (pids.empty())
         ret = FS::removeDirectory(appDir);
 
+    m_pidToOwner.remove(pid);
     return ret;
 }
 
@@ -2802,11 +2800,15 @@ int ServiceImpl::prepareApp(const Credentials &creds, const std::string &appName
 
         ret = getForbiddenAndAllowedGroups(allowedPrivileges, forbiddenGroups, allowedGroups);
 
-
         LogWarning("getForbiddenAndAllowedGroups returned: " << ret);
 
-        return ret != SECURITY_MANAGER_SUCCESS ? ret
-            : appSetupNamespace(creds, id.uid, id.label, privPathsVector, privPathsStatusVector);
+        if (ret != SECURITY_MANAGER_SUCCESS)
+            return ret;
+        ret = appSetupNamespace(creds, id.uid, id.label, privPathsVector, privPathsStatusVector);
+        if (ret != SECURITY_MANAGER_SUCCESS)
+            return ret;
+        m_pidToOwner.add(creds.pid, creds.uid);
+        return SECURITY_MANAGER_SUCCESS;
     } catch (const FS::Exception::Base &e) {
         LogError("Filesystem error: " << e.DumpToString());
         return SECURITY_MANAGER_ERROR_SERVER_ERROR;
index 5e851064e7f853bb0550c484efc079f5da75c747..d2a101e5eb776551dc4ab6a3429fa6b550a9116c 100644 (file)
@@ -227,7 +227,7 @@ int security_manager_self_is_app(bool *app);
 int security_manager_is_app_from_pid(pid_t pid, bool *app);
 
 /**
- * Return the UID of the user for which the app was installed.
+ * Return the UID of the user on behalf of which the app has been started.
  * Only in No-Smack mode does this function check if the PID is an actual app.
  *
  * \param[out]  uid the user ID of application user
index 607dda0f9d1a463956e4a2d51cfdfe300e52cffd..a0224c7e9f3a6f8111fb21f0db3760c5051e90f5 100644 (file)
@@ -126,8 +126,9 @@ private:
      * Process getting owner uid identifier from an app puid
      *
      * @param buffer Input/output message buffer
+     * @param creds  credentials of the requesting process
      */
-    void processGetAppOwner(MessageBuffer &buffer);
+    void processGetAppOwner(MessageBuffer &buffer, const Credentials &creds);
 
     /**
      * Process getting package identifier from an app identifier
index cf4062bb870bd8906befff7afdbf6640e068d2a2..d7dd5994f73ddbe11c35a6ff466828b5c1c93dd7 100644 (file)
@@ -85,7 +85,7 @@ void Service::processEvent(Event &&msg)
                 break;
             case SecurityModuleCall::APP_GET_OWNER:
                 LogDebug("call_type: SecurityModuleCall::APP_GET_OWNER");
-                processGetAppOwner(msg.buffer);
+                processGetAppOwner(msg.buffer, msg.creds);
                 break;
             case SecurityModuleCall::APP_GET_PKG_NAME:
                 LogDebug("call_type: SecurityModuleCall::APP_GET_PKG_NAME");
@@ -259,13 +259,11 @@ void Service::processGetAppNameAndPkg(MessageBuffer &buffer)
         Serialization::Serialize(buffer, appName, pkgName);
 }
 
-void Service::processGetAppOwner(MessageBuffer &buffer)
+void Service::processGetAppOwner(MessageBuffer &buffer, const Credentials &creds)
 {
-    uid_t puid;
     uid_t ownerUid;
 
-    Deserialization::Deserialize(buffer, puid);
-    int ret = m_serviceImpl.getAppOwner(puid, ownerUid);
+    int ret = m_serviceImpl.getAppOwner(creds.pid, ownerUid);
     buffer.ModeStreaming();
     Serialization::Serialize(buffer, ret);
     if (ret == SECURITY_MANAGER_SUCCESS)