Use process UId & author GId in app preparation
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Mon, 20 Jan 2025 11:12:13 +0000 (12:12 +0100)
committerTomasz Swierczek <t.swierczek@samsung.com>
Wed, 5 Feb 2025 07:56:19 +0000 (08:56 +0100)
* Replace smack label with UId in app preparation
* Add author GId to app supplementary groups if available
* Setuid before capability drop (otherwise supplementary  threads won't
  be able to drop it).
* Don't wait for signal handlers to complete. Capset() should not
  affect inter-thread communication.
* Require CAP_SETUID in pre-check.
* Pass process UId to cynara upon installation & deinstallation.
* Return no-smack label from label generation functions.
* Modify first free process UId and author GId lookup function to ignore
existing smack-enabled apps with lower ids. This is to allow testing on
databases containing smack-enabled apps.
* Add unit tests.

All unit tests should pass in both smack and no-smack modes.

The following security-manager-tests should pass in no-smack mode:
security_manager_100_synchronize_credentials_test
security_manager_100_synchronize_credentials_no_author_test
security_manager_190_prepare_app_threads_malloc
security_manager_300_prepare_app_recursive_threads
security_manager_400_prepare_app_with_concurrent_install
security_manager_400_prepare_app_series_with_concurrent_install_stress

Change-Id: I390e957cc60576f92bd925ff0be227fdb760648a

src/client/client-security-manager.cpp
src/common/credentials.cpp
src/common/include/protocols.h
src/common/include/service_impl.h
src/common/privilege_db.cpp
src/common/service_impl.cpp
src/common/smack-labels.cpp
src/server/service/service.cpp
test/CMakeLists.txt
test/test_process_id.cpp [new file with mode: 0644]
test/test_smack-labels.cpp

index fd6786b54a0bdd8a8a0a2665e3846d90126708b4..100915f068c01ead66afe0042ef7f8b104dee6d6 100644 (file)
@@ -69,6 +69,7 @@
 
 #include "filesystem.h"
 #include "mount-namespace.h"
+#include "protocols.h"
 
 static const char *EMPTY = "";
 static const std::string SMACK_SYSTEM = "System";
@@ -96,7 +97,7 @@ static std::map<enum lib_retcode, std::string> lib_retcode_string_map = {
 // Hackish, based on glibc's definition in sysdeps/unix/sysv/linux/nptl-signals.h
 #define SIGSETXID           (__SIGRTMIN + 1)
 #define MAX_THREAD_COUNT    1000 // probably way too big number but we have to live with it somehow
-static const std::string *g_p_app_label;
+static const std::string *g_p_app_label = nullptr;
 
 static std::atomic<int> g_th_barrier;
 
@@ -509,7 +510,7 @@ static int fetchForbiddenAndAllowedGroups(const std::string &appName, std::vecto
     return SECURITY_MANAGER_SUCCESS;
 }
 
-static int prepareAppInitialSetupAndFetch(const std::string &appName, const MountNS::PrivilegePathsMap &privilegePathsMap, std::string &label,
+static int prepareAppInitialSetupAndFetch(const std::string &appName, const MountNS::PrivilegePathsMap &privilegePathsMap, ProcessId &id,
         std::string &pkgName, PrepareAppFlags &prepareAppFlags, std::vector<gid_t> &forbiddenGroups, std::vector<gid_t> &allowedGroups,
         std::vector<bool> &privPathsStatusVector)
 {
@@ -519,7 +520,7 @@ static int prepareAppInitialSetupAndFetch(const std::string &appName, const Moun
         return request.getStatus();
     }
 
-    request.recv(forbiddenGroups, allowedGroups, privPathsStatusVector, label, pkgName, prepareAppFlags);
+    request.recv(forbiddenGroups, allowedGroups, privPathsStatusVector, id, pkgName, prepareAppFlags);
     return SECURITY_MANAGER_SUCCESS;
 }
 
@@ -609,38 +610,46 @@ inline static int label_for_self_internal(int tid)
     return ret < 0 ? -1 : 0;
 }
 
-// Checks if caller has CAP_MAC_ADMIN configured properly.
-// In cases where the capability is missing, this function
+// Checks if caller has required capabilities configured properly.
+// In cases where a capability is missing, this function
 // will write proper error logs for faster debugging.
 //
 // TODO the function would also probably need to check
 // list of "relabel-self" labels set in the process, but
 // libsmack doesn't have such function available (as of Oct 2024).
 //
-// Thats why its a void function & it doesn't abort too
+// Thats why its a void function & it doesn't abort in smack-enabled mode
 // (if capability is missing, we CAN have relabel-self configured).
 static inline void security_manager_pre_check()
 {
-    if (!smack_simple_check())
-        return;
-
     cap_t my_caps = cap_get_proc();
     if (!my_caps) {
         LogError("Unable to allocate capability object");
         return;
     }
-    cap_flag_value_t cap_flags_value;
-    if (cap_get_flag(my_caps, CAP_MAC_ADMIN, CAP_EFFECTIVE, &cap_flags_value) != 0) {
-        LogError("Can't check if process has CAP_MAC_ADMIN!!!");
-        cap_free(my_caps);
-        return;
-    }
-    if(cap_flags_value != CAP_SET) {
-        LogWarning("Process ****doesn't**** have effective CAP_MAC_ADMIN!"
-                   " It can still have dyntransition/relabel-self configured");
-        cap_free(my_caps);
-        return;
+
+    auto cap_check = [&](cap_value_t cap) -> bool {
+        cap_flag_value_t cap_flags_value;
+        if (cap_get_flag(my_caps, cap, CAP_EFFECTIVE, &cap_flags_value) != 0) {
+            LogError("Can't check if process has required capability!!!");
+            return false;
+        }
+        if(cap_flags_value != CAP_SET) {
+            LogWarning("Process ****doesn't**** have required effective capability!");
+            return false;
+        }
+        return true;
+    };
+
+    if (smack_simple_check()) {
+        (void)cap_check(CAP_MAC_ADMIN);
+    } else {
+        if (!cap_check(CAP_SETUID) || !cap_check(CAP_SETGID)) {
+            LogError("Lack of required capabilities. Aborting!");
+            abort();
+        }
     }
+
     cap_free(my_caps);
 }
 
@@ -650,7 +659,7 @@ static bool alive_threads_have_state(int status) noexcept
         if (!g_thread_alive[i])
             continue;
 
-        if (g_thread_state[i] != status)
+        if (g_thread_state[i] < status)
             return false;
     }
     return true;
@@ -658,12 +667,12 @@ static bool alive_threads_have_state(int status) noexcept
 
 static int get_alive_threads(int own_tid, bool abort_on_error) noexcept
 {
-       auto handle_error = [&]{
-               if (abort_on_error)
-                       abort();
+    auto handle_error = [&]{
+        if (abort_on_error)
+            abort();
 
-               return errno;
-       };
+        return errno;
+    };
 
     // reset alive status
     memset(&g_thread_alive, 0, sizeof(g_thread_alive));
@@ -832,10 +841,22 @@ static void sig_handler(int signo)
         usleep(SLEEP_CONST);
 }
 
-static inline int security_manager_sync_threads_internal(const std::string &app_label)
+static inline int security_manager_sync_threads_internal(const ProcessId &process_id)
 {
     static_assert(ATOMIC_INT_LOCK_FREE == 2, "std::atomic<int> is not always lock free");
 
+    // First setuid and setgid. We won't be able to do it when threads drop the caps
+    if (!smack_simple_check()) {
+        while (setuid(process_id.uid) != 0) {
+            if (errno != EAGAIN) {
+                LogErrno("setuid");
+                abort();
+            }
+
+            sleep(SLEEP_CONST);
+        }
+    }
+
     // no need to sync the main thread with signals
     int own_tid = Syscall::gettid();
     const pid_t own_pid = getpid();
@@ -851,7 +872,7 @@ static inline int security_manager_sync_threads_internal(const std::string &app_
     std::unique_ptr<cap_t, decltype(cap_deleter)> scopedCapPtr(&g_cap, cap_deleter);
 
     if (smack_check())
-        g_p_app_label = &app_label;
+        g_p_app_label = &process_id.label;
 
     struct sigaction act;
     struct sigaction old;
@@ -905,6 +926,11 @@ static inline int security_manager_sync_threads_internal(const std::string &app_
     // is currently going on in the process except this thread & waiting signal handlers
 
     g_th_barrier++; // this starts the signal handlers - they will proceed once they wake up
+    if (!smack_simple_check()) {
+        // In no smack mode we don't care about threads with mixed caps talking to each other.
+        // Let the signal handlers return freely.
+        g_th_barrier++;
+    }
 
     bool ready = false;
     for (int i = MAX_SIG_WAIT_TIME; i > 0; --i) {
@@ -924,8 +950,10 @@ static inline int security_manager_sync_threads_internal(const std::string &app_
     /*
      * Change attributes of one last thread, the main thread.
      */
-    if (g_p_app_label && label_for_self_internal(own_tid) != 0)
-        abort();
+    if (smack_simple_check()) {
+        if (g_p_app_label && label_for_self_internal(own_tid) != 0)
+            abort();
+    }
 
     if (cap_set_proc(g_cap))
         abort();
@@ -935,8 +963,11 @@ static inline int security_manager_sync_threads_internal(const std::string &app_
     if (enabled)
         SecurityManager::Log::LogSystemSingleton::Instance().Enable(true);
 
-    g_th_barrier++; // this starts signal handlers to proceed once they wake up - logic in app starts in env where all have changed labels
-
+    if (smack_simple_check()) {
+        // This starts signal handlers to proceed once they wake up - logic in app starts in env
+        // where all have changed labels.
+        g_th_barrier++;
+    }
 
     if (Syscall::sigaction(SIGSETXID, &old, nullptr) < 0) {
         LogError("Error in sigaction()");
@@ -1251,12 +1282,13 @@ int security_manager_prepare_app2(const char *app_name, const char *subsession_i
     return try_catch([&] {
         security_manager_pre_check();
 
-        std::string appLabel, pkgName;
+        std::string pkgName;
+        ProcessId processId;
         PrepareAppFlags prepareAppFlags;
         std::vector<gid_t> forbiddenGroups, allowedGroups;
         std::vector<bool> privPathsStatusVector;
         auto privilegePathMap = MountNS::getPrivilegePathMap(getuid());
-        int ret = prepareAppInitialSetupAndFetch(app_name, privilegePathMap, appLabel, pkgName, prepareAppFlags,
+        int ret = prepareAppInitialSetupAndFetch(app_name, privilegePathMap, processId, pkgName, prepareAppFlags,
                 forbiddenGroups, allowedGroups, privPathsStatusVector);
         if (ret != SECURITY_MANAGER_SUCCESS) {
             LogError("Failed to get app info for appName: " << app_name);
@@ -1269,19 +1301,16 @@ int security_manager_prepare_app2(const char *app_name, const char *subsession_i
             return ret;
         }
 
-        if (!smack_simple_check()) {
-            LogWarning("Running in no-smack mode, exiting with success from prepare_app2 - not setting namespaces any further, or Smack, or caps");
-            return (int)SECURITY_MANAGER_SUCCESS;
-        }
-
-        ret = security_manager_setup_namespace_internal(privilegePathMap, pkgName,
-                prepareAppFlags & PREPARE_APP_SHARED_RO_FLAG, privPathsStatusVector, appLabel, subsession_id);
-        if (ret != SECURITY_MANAGER_SUCCESS) {
-            LogError("Unable to setup namespace for application " << app_name);
-            return ret;
+        if (smack_simple_check()) {
+            ret = security_manager_setup_namespace_internal(privilegePathMap, pkgName,
+                    prepareAppFlags & PREPARE_APP_SHARED_RO_FLAG, privPathsStatusVector, processId.label, subsession_id);
+            if (ret != SECURITY_MANAGER_SUCCESS) {
+                LogError("Unable to setup namespace for application " << app_name);
+                return ret;
+            }
         }
 
-        ret = security_manager_sync_threads_internal(appLabel);
+        ret = security_manager_sync_threads_internal(processId);
         if (ret != SECURITY_MANAGER_SUCCESS) {
             LogError("Can't properly setup application threads (Smack label & capabilities) for application " << app_name);
             return ret;
index f83764b958aa2d1badde7c6a71495de98c5075ca..15fdd4ea12aca58e15d3c1805f45a90cf06d6c10 100644 (file)
@@ -49,7 +49,7 @@ Credentials Credentials::getCredentialsFromSocket(int sock)
     if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &cr, &len) == -1)
         ThrowMsg(Exception::SocketError, "Failed to read peer credentials for sockfd " << sock);
 
-    return Credentials(cr.pid, cr.uid, cr.gid, smack_simple_check() ? SmackLabels::getSmackLabelFromSocket(sock) : "");
+    return Credentials(cr.pid, cr.uid, cr.gid, SmackLabels::getSmackLabelFromSocket(sock));
 }
 
 Credentials Credentials::getCredentialsFromFd(int fd)
@@ -58,7 +58,7 @@ Credentials Credentials::getCredentialsFromFd(int fd)
     if (-1 == fstat(fd, &buf))
         ThrowMsg(Exception::FdError, "Failed to read credentials from filefd " << fd);
 
-    return Credentials(-1, buf.st_uid, buf.st_gid, smack_simple_check() ? SmackLabels::getSmackLabelFromFd(fd) : "");
+    return Credentials(-1, buf.st_uid, buf.st_gid, SmackLabels::getSmackLabelFromFd(fd));
 }
 
 } // namespace SecurityManager
index b378d4f684bfd59967ba76e4953caf36bf62d46a..d02f4cd6362545727e5b440bc05d8b5b9202542d 100644 (file)
@@ -34,6 +34,7 @@
 #include <string>
 #include <dpl/serialization.h>
 #include <security-manager-types.h>
+#include "smack-check.h"
 
 using namespace SecurityManager;
 
@@ -197,3 +198,26 @@ typedef struct policy_entry policy_entry;
 struct policy_update_req {
     std::vector<const policy_entry *> units;
 };
+
+constexpr inline char NO_SMACK_LABEL[] = "User::Pkg::default_app_no_Smack_mode";
+struct ProcessId : public ISerializable {
+    std::string label = NO_SMACK_LABEL;
+    uid_t uid = 0;
+
+    ProcessId() = default;
+    ProcessId(IStream &stream) : ProcessId()
+    {
+        if (smack_simple_check())
+            Deserialization::Deserialize(stream, label);
+        else
+            Deserialization::Deserialize(stream, uid);
+    }
+
+    virtual void Serialize(IStream &stream) const
+    {
+        if (smack_simple_check())
+            Serialization::Serialize(stream, label);
+        else
+            Serialization::Serialize(stream, uid);
+    }
+};
index 2f70328a75f2dc2c8cb6ad78b43655d9103ccf96..1cf61a424bb14bc9ba9edb722c618141f05f0d6f 100644 (file)
@@ -194,20 +194,17 @@ public:
 
     /**
     * Process query for resources group list and supplementary groups allowed for the application.
-    * For given \ref appProcessLabel and \ref uid, calculate allowed privileges that give
-    * direct access to file system resources. For each permission Cynara will be
-    * queried.
+    * Calculate allowed privileges that give direct access to file system resources. For each
+    * permission Cynara will be queried.
     * Returns set of group ids that are permitted.
     *
-    * @param[in]  appProcessLabel application name
     * @param[in]  allowedPrivileges privileges allowed for application
     * @param[out] forbiddenGroups returned sorted vector of forbidden groups
     * @param[out] allowedGroups returned sorted vector of allowed groups
     *
     * @return API return code, as defined in protocols.h
     */
-    int getForbiddenAndAllowedGroups(const Smack::Label &appProcessLabel,
-        const std::vector<std::string> &allowedPrivileges,
+    int getForbiddenAndAllowedGroups(const std::vector<std::string> &allowedPrivileges,
         std::vector<gid_t> &forbiddenGroups, std::vector<gid_t> &allowedGroups);
 
     /**
@@ -371,12 +368,12 @@ public:
     Smack::Label getProcessLabel(const std::string &appName);
 
     /**
-     * Get app info (process label, package name, shared_ro flag)
+     * Get app info (process identifier, package name, shared_ro flag)
      *
      * @param[in] creds                  credentials of the requesting process
      * @param[in] appName                application identifier
      * @param[in] pathPrivVector         paths related privileges to query
-     * @param[out] label                 generated label
+     * @param[out] id                    generated process identifier
      * @param[out] pkgName               application package name
      * @param[out] prepareAppFlags       placeholder for check shared_ro result
      *                                   and checkProperDrop flags
@@ -387,7 +384,7 @@ public:
      * @return API return code, as defined in protocols.h
      */
     int prepareApp(const Credentials &creds, const std::string &appName, const std::vector<std::string> &privPathsVector,
-            Smack::Label &label, std::string &pkgName, PrepareAppFlags &prepareAppFlags,
+            ProcessId &id, std::string &pkgName, PrepareAppFlags &prepareAppFlags,
             std::vector<gid_t> &forbiddenGroups, std::vector<gid_t> &allowedGroups, std::vector<bool> &privPathsStatusVector);
 
     /**
@@ -408,6 +405,8 @@ private:
                               app_inst_req &req,
                               InstallHelper &ih);
 
+    uid_t getProcessUId(app_inst_req::app& app, app_inst_req& req);
+
     void appInstallCynaraPolicies(app_inst_req::app &app,
                                   app_inst_req &req,
                                   InstallHelper &ih);
@@ -425,9 +424,10 @@ private:
                                 app_inst_req &req,
                                 UninstallHelper &uh);
 
-    void appUninstallCynaraPolicies(const std::string &processLabel,
+    void appUninstallCynaraPolicies(app_inst_req::app& app,
                                     app_inst_req &req,
-                                    UninstallHelper &uh);
+                                    UninstallHelper &uh,
+                                    uid_t processUId);
 
     int appUninstallSmackRules(app_inst_req &req, UninstallHelper &uh);
 
index 72192665481a2d97524f4f70cb9dddd64f5b5522..ca9e7606345007e6245eb19a213768f8329143ab 100644 (file)
@@ -856,7 +856,13 @@ int PrivilegeDb::GetFirstFreeId(int startValue, StmtType statement)
     int id = startValue;
 
     while (command->Step()) {
-        if (id != command->GetColumnInteger(0))
+        auto current = command->GetColumnInteger(0);
+
+        // skip existing smack-enabled apps
+        if (current < startValue)
+            continue;
+
+        if (id != current)
             break;
         id++;
     };
index 9ff3122c8e56f6eb52b54eee44e4faacee103085..e61e3005f7baaf76e3c08d0abf2076c30d0dbaa7 100644 (file)
@@ -478,6 +478,19 @@ void ServiceImpl::appInstallPrivileges(app_inst_req::app &app, app_inst_req &req
     }
 }
 
+uid_t ServiceImpl::getProcessUId(app_inst_req::app& app, app_inst_req& req)
+{
+    uid_t uid;
+#ifdef SMACK_ENABLED
+    (void)app;
+    uid = req.uid;
+#else
+    if (!m_privilegeDb.GetProcessUId(req.pkgName, app.appName, uid))
+        ThrowMsg(PrivilegeDb::Exception::InternalError, "Failed to get process UId from the db");
+#endif
+    return uid;
+}
+
 void ServiceImpl::appInstallCynaraPolicies(app_inst_req::app& app, app_inst_req& req,
         InstallHelper &ih)
 {
@@ -505,9 +518,10 @@ void ServiceImpl::appInstallCynaraPolicies(app_inst_req::app& app, app_inst_req&
     Smack::Label oldAppLabel = SmackLabels::generateProcessLabel(
             app.appName, req.pkgName, ih.isOldPkgHybrid);
 
+    auto uid = getProcessUId(app, req);
     m_cynaraAdmin.updateAppPolicy(oldAppLabel, appLabel, global,
-        req.uid, req.pkgType, req.privLevel, privileges);
-    m_cynaraAdmin.updateAppDefinedPolicy(global, req.uid,
+        uid, req.pkgType, req.privLevel, privileges);
+    m_cynaraAdmin.updateAppDefinedPolicy(global, uid,
         ih.oldAppDefinedPrivileges, app.appDefinedPrivileges);
 }
 
@@ -899,9 +913,11 @@ void ServiceImpl::appUninstallPrivileges(app_inst_req::app &app, app_inst_req &r
     m_privilegeDb.GetAppDefinedPrivileges(app.appName, req.uid, uh.oldAppDefinedPrivileges);
 }
 
-void ServiceImpl::appUninstallCynaraPolicies(const std::string &processLabel, app_inst_req &req,
-        UninstallHelper &ui)
+void ServiceImpl::appUninstallCynaraPolicies(app_inst_req::app& app, app_inst_req &req,
+        UninstallHelper &ui, uid_t processUId)
 {
+    auto processLabel = SmackLabels::generateProcessLabel(app.appName, req.pkgName, ui.isPkgHybrid);
+
     LogDebug("Removing Cynara policy for: pkgName=" << req.pkgName
              << " Smack label=" << processLabel);
 
@@ -914,8 +930,8 @@ void ServiceImpl::appUninstallCynaraPolicies(const std::string &processLabel, ap
     // the same Smack label.
     // This bug exists in security-manager since version 1.2.1 (Sep 2016).
     m_cynaraAdmin.updateAppPolicy(processLabel, global,
-        req.uid, req.pkgType, req.privLevel, std::vector<std::string>(), true);
-    m_cynaraAdmin.updateAppDefinedPolicy(global, req.uid,
+            processUId, req.pkgType, req.privLevel, std::vector<std::string>(), true);
+    m_cynaraAdmin.updateAppDefinedPolicy(global, processUId,
         ui.oldAppDefinedPrivileges, AppDefinedPrivilegesVector());
 }
 
@@ -1008,11 +1024,13 @@ int ServiceImpl::appUninstall(const Credentials &creds, app_inst_req &req)
                 // [db] remove app privileges
                 appUninstallPrivileges(app, req, uh);
 
+                auto uid = getProcessUId(app, req);
+
                 // [db] remove app
                 m_privilegeDb.RemoveApplication(app.appName, req.uid, removeApp, uh.removePkg, uh.removeAuthor);
 
                 // [cynara] update app policy
-                appUninstallCynaraPolicies(SmackLabels::generateProcessLabel(app.appName, req.pkgName, uh.isPkgHybrid), req, uh);
+                appUninstallCynaraPolicies(app, req, uh, uid);
             }
             uh.removeApps.push_back(removeApp);
         }
@@ -1233,7 +1251,7 @@ int ServiceImpl::policyUpdate(const Credentials &creds, const std::vector<policy
         std::map<std::string, std::vector<std::string>> appsAllowedPrivileges;
         std::vector<std::string> allPackages;
 
-        if (m_smackRules.isPrivilegeMappingEnabled()) {
+        if (smack_simple_check() && m_smackRules.isPrivilegeMappingEnabled()) {
             auto runningApps = MountNS::getMountNSApps();
             for (auto &appContext: runningApps) {
                 auto &appProcessLabel = appContext.appProcessLabel;
@@ -1245,20 +1263,20 @@ int ServiceImpl::policyUpdate(const Credentials &creds, const std::vector<policy
         // Apply updates
         m_cynaraAdmin.setPolicies(validatedPolicies);
 
-        if (m_smackRules.isPrivilegeMappingEnabled()) {
+        if (smack_simple_check() && m_smackRules.isPrivilegeMappingEnabled()) {
             LogDebug("Updating privilege related Smack rules");
             auto runningApps = MountNS::getMountNSApps();
             for (auto &appContext : runningApps) {
                 if (isMultiUser(appContext, runningApps)) {
                     LogError("Detected multiuser launch for " << appContext.appProcessLabel
                              << ", policy won't be updated for its context.");
-                } else {
-                    try {
-                        updateRunningAppSmackPolicy(appContext, appsAllowedPrivileges);
-                    } catch (const SmackException::InvalidLabel &e) {
-                        LogError("AppContext: " << appContext.appProcessLabel
-                                 << " doesn't describe an application");
-                    }
+                    continue;
+                }
+                try {
+                    updateRunningAppSmackPolicy(appContext, appsAllowedPrivileges);
+                } catch (const SmackException::InvalidLabel &e) {
+                    LogError("AppContext: " << appContext.appProcessLabel
+                             << " doesn't describe an application");
                 }
             }
         }
@@ -1669,13 +1687,12 @@ int ServiceImpl::getAppAllowedPrivileges(const Smack::Label &appProcessLabel,
 }
 
 int ServiceImpl::getForbiddenAndAllowedGroups(
-    const Smack::Label &appProcessLabel, const std::vector<std::string> &allowedPrivileges,
-    std::vector<gid_t> &forbiddenGroups, std::vector<gid_t> &allowedGroups)
+    const std::vector<std::string> &allowedPrivileges,
+    std::vector<gid_t> &forbiddenGroups,
+    std::vector<gid_t> &allowedGroups)
 {
 
     try {
-        LogDebug("smack label: " << appProcessLabel);
-
         for (const auto &privilege : allowedPrivileges) {
             const auto &pgids = m_privilegeGids.getGids(privilege);
 
@@ -2396,7 +2413,7 @@ Smack::Label ServiceImpl::getProcessLabel(const std::string &appName)
 }
 
 int ServiceImpl::prepareApp(const Credentials &creds, const std::string &appName, const std::vector<std::string> &privPathsVector,
-        Smack::Label &label, std::string &pkgName, PrepareAppFlags &prepareAppFlags,
+        ProcessId &id, std::string &pkgName, PrepareAppFlags &prepareAppFlags,
         std::vector<gid_t> &forbiddenGroups, std::vector<gid_t> &allowedGroups, std::vector<bool> &privPathsStatusVector)
 {
     try {
@@ -2407,12 +2424,24 @@ int ServiceImpl::prepareApp(const Credentials &creds, const std::string &appName
             return SECURITY_MANAGER_ERROR_UNKNOWN;
         LogWarning("Package ID: " << pkgName << ", hybrid status: " << isHybrid << ", enabledSharedRO: " << enabledSharedRO);
         prepareAppFlags = m_prepareAppFlags | (enabledSharedRO ? PREPARE_APP_SHARED_RO_FLAG : 0);
-        label = SmackLabels::generateProcessLabel(appName, pkgName, isHybrid);
+
+        id.label = SmackLabels::generateProcessLabel(appName, pkgName, isHybrid);
+        if (smack_simple_check()) {
+            id.uid = creds.uid;
+        } else {
+            if (!m_privilegeDb.GetProcessUId(pkgName, appName, id.uid)) {
+                LogError("Failed to get process UId for " << appName);
+                return SECURITY_MANAGER_ERROR_UNKNOWN;
+            }
+            gid_t authorsGId;
+            if (m_privilegeDb.GetAuthorGId(pkgName, authorsGId))
+                allowedGroups.emplace_back(authorsGId);
+        }
 
         std::vector<std::string> allowedPrivileges;
-        int ret = getAppAllowedPrivileges(label, creds.uid, allowedPrivileges);
+        int ret = getAppAllowedPrivileges(id.label, id.uid, allowedPrivileges);
         if (ret != SECURITY_MANAGER_SUCCESS) {
-            LogError("Failed to fetch allowed privileges for " << label);
+            LogError("Failed to fetch allowed privileges for " << id.label);
             return ret;
         }
 
@@ -2428,21 +2457,21 @@ int ServiceImpl::prepareApp(const Credentials &creds, const std::string &appName
                 // We have to remove all possible privilege related Smack rules, because application
                 // policy might have changed from last prepareApp
                 // (e.g. application new version was installed)
-                m_smackRules.disableAllPrivilegeRules(label, pkgName, authorHash);
+                m_smackRules.disableAllPrivilegeRules(id.label, pkgName, authorHash);
 
                 // TODO: Optimization is welcomed here
                 auto runningApps = MountNS::getMountNSApps();
-                if (isMultiUser( { label, std::to_string(creds.uid) }, runningApps)) {
-                    LogWarning("Detected multiuser instance of " << appName <<
-                            ". Privilege related Smack rules are cleared and won't be reapplied.");
+                if (isMultiUser({id.label, std::to_string(creds.uid)}, runningApps)) {
+                    LogWarning("Detected multiuser instance of " << appName
+                            << ". Privilege related Smack rules are cleared and won't be reapplied.");
                 } else {
-                    m_smackRules.enablePrivilegeRules(label, pkgName, authorHash, allowedPrivileges);
+                    m_smackRules.enablePrivilegeRules(id.label, pkgName, authorHash, allowedPrivileges);
                 }
             }
         }
 
-        ret = getForbiddenAndAllowedGroups(label, allowedPrivileges, forbiddenGroups,
-                                        allowedGroups);
+        ret = getForbiddenAndAllowedGroups(allowedPrivileges, forbiddenGroups, allowedGroups);
+
 
         LogWarning("getForbiddenAndAllowedGroups returned: " << ret);
 
@@ -2452,7 +2481,7 @@ int ServiceImpl::prepareApp(const Credentials &creds, const std::string &appName
         }
 
         return ret != SECURITY_MANAGER_SUCCESS ? ret
-            : appSetupNamespace(creds, label, privPathsVector, privPathsStatusVector);
+            : appSetupNamespace(creds, id.label, privPathsVector, privPathsStatusVector);
     } catch (const FS::Exception::Base &e) {
         LogError("Filesystem error: " << e.DumpToString());
         return SECURITY_MANAGER_ERROR_SERVER_ERROR;
index 0376a5fb744132af2aaafaec3feaa2694a70ca08..b410557d0a2e37c4acbb58959c6887f299a2e0d0 100644 (file)
@@ -48,6 +48,7 @@
 
 #include "security-manager.h"
 #include "service_impl_utils.h"
+#include "smack-check.h"
 #include "smack-labels.h"
 #include "utils.h"
 
@@ -219,6 +220,9 @@ void generateAppPkgNameFromLabel(const Smack::Label &label, std::string &appName
 Smack::Label generateProcessLabel(const std::string &appName, const std::string &pkgName,
                                  bool isHybrid)
 {
+    if (!smack_simple_check())
+        return NO_SMACK_LABEL;
+
     Smack::Label label = "User::Pkg::" + pkgName;
     if (isHybrid)
         label += "::App::" + appName;
@@ -231,11 +235,17 @@ Smack::Label generateProcessLabel(const std::string &appName, const std::string
 
 Smack::Label generatePathSharedROLabel()
 {
+    if (!smack_simple_check())
+        return NO_SMACK_LABEL;
+
     return "User::App::Shared";
 }
 
 Smack::Label generatePathRWLabel(const std::string &pkgName)
 {
+    if (!smack_simple_check())
+        return NO_SMACK_LABEL;
+
     Smack::Label label = "User::Pkg::" + pkgName;
 
     if (smack_label_length(label.c_str()) <= 0)
@@ -246,6 +256,9 @@ Smack::Label generatePathRWLabel(const std::string &pkgName)
 
 Smack::Label generatePathROLabel(const std::string &pkgName)
 {
+    if (!smack_simple_check())
+        return NO_SMACK_LABEL;
+
     Smack::Label label = "User::Pkg::" + pkgName + "::RO";
 
     if (smack_label_length(label.c_str()) <= 0)
@@ -256,6 +269,9 @@ Smack::Label generatePathROLabel(const std::string &pkgName)
 
 Smack::Label generateSharedPrivateLabel(const std::string &pkgName, const std::string &path)
 {
+    if (!smack_simple_check())
+        return NO_SMACK_LABEL;
+
     // Prefix $1$ causes crypt() to use MD5 function
     Smack::Label label = "User::Pkg::";
     std::string salt = "$1$" + pkgName;
@@ -274,6 +290,9 @@ Smack::Label generateSharedPrivateLabel(const std::string &pkgName, const std::s
 template<typename FuncType, typename... ArgsType>
 static Smack::Label getSmackLabel(FuncType func, ArgsType... args)
 {
+    if (!smack_simple_check())
+        return NO_SMACK_LABEL;
+
     char *label;
     ssize_t labelLen = func(args..., &label);
     if (labelLen <= 0)
index 79d317658444dffedf2b583027a985aad18b6f6c..2a2253a416e3f0d674fd393ec200fe376b8e1328 100644 (file)
@@ -352,7 +352,7 @@ void Service::processGetForbiddenAndAllowedGroups(MessageBuffer &buffer, const C
     std::vector<std::string> allowedPrivileges;
     int ret = m_serviceImpl.getAppAllowedPrivileges(label, creds.uid, allowedPrivileges);
     if (ret == SECURITY_MANAGER_SUCCESS)
-        ret = m_serviceImpl.getForbiddenAndAllowedGroups(label, allowedPrivileges, forbiddenGroups,
+        ret = m_serviceImpl.getForbiddenAndAllowedGroups(allowedPrivileges, forbiddenGroups,
                                                        allowedGroups);
     else
         LogError("Failed to fetch allowed privileges for " << label);
@@ -508,18 +508,19 @@ void Service::processGetProcessLabel(MessageBuffer &buffer)
 
 void Service::prepareApp(MessageBuffer &buffer, const Credentials &creds)
 {
-    std::string appName, pkgName, label;
+    std::string appName, pkgName;
+    ProcessId id;
     PrepareAppFlags prepareAppFlags;
     std::vector<std::string> privPathsVector;
     std::vector<gid_t> forbiddenGroups, allowedGroups;
     std::vector<bool> privPathsStatusVector;
     Deserialization::Deserialize(buffer, appName, privPathsVector);
     int ret = m_serviceImpl.prepareApp(creds, appName, privPathsVector,
-            label, pkgName, prepareAppFlags, forbiddenGroups, allowedGroups, privPathsStatusVector);
+            id, pkgName, prepareAppFlags, forbiddenGroups, allowedGroups, privPathsStatusVector);
     buffer.ModeStreaming();
     Serialization::Serialize(buffer, ret);
     if (ret == SECURITY_MANAGER_SUCCESS)
-        Serialization::Serialize(buffer, forbiddenGroups, allowedGroups, privPathsStatusVector, label, pkgName, prepareAppFlags);
+        Serialization::Serialize(buffer, forbiddenGroups, allowedGroups, privPathsStatusVector, id, pkgName, prepareAppFlags);
 }
 
 void Service::processRepairPermissibleFile(MessageBuffer &buffer)
index 413f42d023b466d5125c52a13e0243b81331aaf5..7f31c5748b18104bf8463ba251a1eefba202b9ed 100644 (file)
@@ -91,6 +91,7 @@ SET(SM_TESTS_SOURCES
     ${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_process_id.cpp
     ${SM_TEST_SRC}/test_service_impl_utils.cpp
     ${SM_TEST_SRC}/test_smack-labels.cpp
     ${SM_TEST_SRC}/test_smack-rules.cpp
diff --git a/test/test_process_id.cpp b/test/test_process_id.cpp
new file mode 100644 (file)
index 0000000..766d718
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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 <testmacros.h>
+#include "protocols.h"
+#include "message-buffer.h"
+
+using namespace SecurityManager;
+
+BOOST_AUTO_TEST_SUITE(PROCESS_ID_TEST)
+
+POSITIVE_TEST_CASE(T310_Serialization)
+{
+    ProcessId id;
+    id.label = "test label";
+    id.uid = 1;
+    ProcessId id2;
+    id2.label = "wrong label";
+    id2.uid = 3;
+    MessageBuffer buffer;
+    buffer.InitForStreaming();
+    Serialization::Serialize(buffer, id);
+    buffer.ModeOutput();
+    buffer.ModeStreaming();
+    Deserialization::Deserialize(buffer, id2);
+    if (smack_simple_check()) {
+        BOOST_REQUIRE(id.label == id2.label);
+        BOOST_REQUIRE(id.uid != id2.uid);
+    } else {
+        BOOST_REQUIRE(id.label != id2.label);
+        BOOST_REQUIRE(id.uid == id2.uid);
+    }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
index 2d07bfed914cdead81f9b7efcea6766d27f30d7e..2be5facac8d797f16d0914595d66803f4b256a6c 100644 (file)
@@ -34,6 +34,8 @@
 #include <dpl/log/log.h>
 #include <smack-labels.h>
 
+#include "protocols.h"
+
 #include <testmacros.h>
 
 using namespace SecurityManager;
@@ -376,6 +378,21 @@ POSITIVE_FIXTURE_TEST_CASE(T1060_setup_path_ro, DirectoryFixture)
     BOOST_REQUIRE(labelNotExist(subdirectoryPath, XATTR_NAME_SMACKTRANSMUTE));
     BOOST_REQUIRE(labelNotExist(execPath, XATTR_NAME_SMACKEXEC));
 }
+#else
+POSITIVE_TEST_CASE(T1010_get_smack_label)
+{
+    BOOST_REQUIRE(NO_SMACK_LABEL == getSmackLabelFromSocket(0));
+    BOOST_REQUIRE(NO_SMACK_LABEL == getSmackLabelFromPath(""));
+    BOOST_REQUIRE(NO_SMACK_LABEL == getSmackLabelFromFd(0));
+    BOOST_REQUIRE(NO_SMACK_LABEL == getSmackLabelFromSelf());
+    BOOST_REQUIRE(NO_SMACK_LABEL == getSmackLabelFromPid(0));
+}
+
+POSITIVE_TEST_CASE(T1010_generate_smack_labels)
+{
+    BOOST_REQUIRE(NO_SMACK_LABEL == generateProcessLabel("whatever", "whatever", true));
+    BOOST_REQUIRE(NO_SMACK_LABEL == generateProcessLabel("whatever", "whatever", false));
+}
 #endif
 
 BOOST_AUTO_TEST_SUITE_END()