Prioritize requests based on cpu boosting level 09/277809/15
authorKonrad Lipinski <k.lipinski2@samsung.com>
Wed, 13 Jul 2022 14:46:48 +0000 (16:46 +0200)
committerKonrad Lipinski <k.lipinski2@samsung.com>
Fri, 22 Jul 2022 13:37:53 +0000 (15:37 +0200)
There are three boosting levels at present, hence three distinct
priorities are introduced. Since the priority space is small, the
priority queue is implemented via an array of FIFO queues.

CPU priority inheritance from client to server is also included.

The boosting level and priority inheritance facilities are provided by
the capi-system-resource module. According to said facilities'
designers, querying the boosting level is most efficient when done
directly in the queried thread. Thus, when making a security manager
client request, the boosting level is obtained and prepended to the
request payload. This is also makes requests atomic and mitigates the
potential for priority races.

Change-Id: Icc10fb5e40fa74eafe16726d28ac66cd8b560810

packaging/security-manager.spec
src/client/CMakeLists.txt
src/client/include/client-request.h
src/common/include/protocols.h
src/common/include/utils.h
src/common/protocols.cpp
src/server/CMakeLists.txt
src/server/main/include/service-thread.h
src/server/main/server-main.cpp
src/server/main/socket-manager.cpp
src/server/rules-loader/security-manager-rules-loader.cpp

index c89efa1c5d8bd1cfd49774bee0af569940c6e3d6..563c5596701f8ea58e7e95597e807d82c0189310 100644 (file)
@@ -29,6 +29,7 @@ BuildRequires: cmake
 BuildRequires: zip
 BuildRequires: pkgconfig(dlog)
 BuildRequires: libattr-devel
+BuildRequires: pkgconfig(capi-system-resource)
 BuildRequires: pkgconfig(libsmack)
 BuildRequires: pkgconfig(libcap)
 BuildRequires: pkgconfig(libsystemd)
index f0df161ebdd08915d07828c15a04431918bc99c9..c8db9388eaadb5b105fbc4fde308af8d22747cd3 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+# Copyright (c) 2014-2022 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.
@@ -21,6 +21,7 @@
 
 PKG_CHECK_MODULES(CLIENT_DEP
     REQUIRED
+    capi-system-resource
     cynara-client-async
     libsmack
     libcap
index a83e9cd79e406f33142f19a353a14428ee6c8c12..2d61d2f32226d7ab2354e6dfb433618525ac89b4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2016-2022 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.
 #pragma once
 
 #include <stdexcept>
+#include <cpu-boosting.h>
 
 #include <connection.h>
 #include <dpl/log/log.h>
 #include <message-buffer.h>
 #include <protocols.h>
 #include <security-manager-types.h>
+#include <utils.h>
 
 namespace SecurityManager {
 
 class ClientRequest {
+
+    static Priority getPriority() {
+        auto priority = Priority::LOW;
+        resource_pid_t proc_data;
+        cpu_boosting_level_info_t info;
+        proc_data.tid = nullptr;
+        proc_data.pid = 0;  // query for current TID - array tid_level gets allocated
+        if (resource_get_cpu_boosting_level(proc_data, &info) != 0) {
+            LogError("resource_get_cpu_boosting_level failed");
+        } else {
+            switch (info.tid_level[0]) {
+            case CPU_BOOSTING_LEVEL_STRONG:
+                priority = Priority::HIGH;
+                break;
+            case CPU_BOOSTING_LEVEL_MEDIUM:
+                priority = Priority::MEDIUM;
+                break;
+            }
+            free(info.tid_level);
+        }
+        return priority;
+    }
 public:
     ClientRequest(SecurityModuleCall action)
     {
         m_buffer.InitForStreaming();
+        Serialization::Serialize(m_buffer, underlying(getPriority()));
         Serialization::Serialize(m_buffer, static_cast<int>(action));
     }
 
@@ -64,7 +89,12 @@ public:
 
         m_sent = true;
 
+        const auto tid = gettid();
+        if (resource_set_cpu_inheritance(tid, RESOURCE_CPU_DEST_NAME, -1) != 0)
+            LogError("resource_set_cpu_inheritance failed");
         m_status = sendToServer(SERVICE_SOCKET, m_buffer);
+        if (resource_clear_cpu_inheritance(tid, RESOURCE_CPU_DEST_NAME) != 0)
+            LogError("resource_clear_cpu_inheritance failed");
         if (!failed())
             Deserialization::Deserialize(m_buffer, m_status);
         else
index fdc3c6a3818388380b91a9b920cc71497ba81cfd..03bcc201225284693d55852a159251f46c63c391 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2022 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.
@@ -106,7 +106,17 @@ struct path_req {
 
 namespace SecurityManager {
 
-extern char const * const SERVICE_SOCKET;
+#define SOCKET_PATH_PREFIX "/run/"
+
+inline constexpr auto SERVICE_SOCKET = SOCKET_PATH_PREFIX "security-manager.socket";
+inline constexpr auto RESOURCE_CPU_DEST_NAME = "SECURITY_MANAGER_DEST";
+
+enum Priority : unsigned char {
+    HIGH,
+    MEDIUM,
+    LOW,
+    END,
+};
 
 enum class SecurityModuleCall
 {
index 099a9fdd241769e67226736c5f1a2dd71d44e8f5..b4998880df5d651b325fa38ec670575dbae6b6bd 100644 (file)
@@ -136,5 +136,10 @@ constexpr auto max(const T &a, const U &b) {
 
 template <class E>
 constexpr auto underlying(const E &e) {
-    return typename std::underlying_type<E>::type(e);
+    return std::underlying_type_t<E>(e);
+}
+
+template <class T, size_t S>
+constexpr size_t arraySize(T (&)[S]) {
+    return S;
 }
index f31f76e0e9ab8a110307c8bd10bc19cb8ff1f794..b7a8e7779aa8a2920538f58ee669f94fbcd0d9f6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2022 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.
 
 namespace SecurityManager {
 
-#define SOCKET_PATH_PREFIX "/run/"
-
-char const * const SERVICE_SOCKET =
-        SOCKET_PATH_PREFIX "security-manager.socket";
-
 #define SM_CODE_DESCRIBE(name) case name: return #name
 const char * SecurityModuleCallToString(SecurityModuleCall call_num) {
     switch (call_num) {
index e19f8eecb3c93367d8c8962da9d160365a80679f..5dac5653d45b8bdebd22e97503f9a04b249d4e88 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013-2020 Samsung Electronics Co., Ltd. All rights reserved.
+# Copyright (c) 2013-2022 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.
@@ -21,6 +21,7 @@
 
 PKG_CHECK_MODULES(SERVER_DEP
     REQUIRED
+    capi-system-resource
     libsystemd
     cynara-client
     mount
index 82d319bf8bec29130a4ab2d90b427c2231d9cf1b..2818a655b83437ab6617b76a0386e527330919c2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2022 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.
 
 #include <cassert>
 #include <condition_variable>
-#include <dpl/exception.h>
 #include <mutex>
 #include <queue>
 #include <thread>
 
+#include <dpl/exception.h>
+#include <protocols.h>  // Priority
+#include <utils.h>
+
 namespace SecurityManager {
 
 template <class DerivedService, class Event>
 class ServiceThread {
     std::thread m_thread;
     std::mutex m_eventQueueMutex;
-    std::queue<Event *> m_eventQueue;
+    std::queue<Event *> m_eventQueues[Priority::END];
     std::condition_variable m_waitCondition;
 
     bool m_quit = false;
@@ -57,18 +60,20 @@ public:
         m_thread.join();
 
         // clear the event queue
-        while (!m_eventQueue.empty()) {
-            delete m_eventQueue.front();
-            m_eventQueue.pop();
-        }
+        for (auto &queue: m_eventQueues)
+            while (!queue.empty()) {
+                delete queue.front();
+                queue.pop();
+            }
     }
 
     template <class...T>
-    void PutEvent(T&&...arg) {
+    void PutEvent(Priority priority, T&&...arg) {
+        assert(priority < arraySize(m_eventQueues));
         const auto event = new Event{ std::forward<T>(arg)... };
         {
             std::lock_guard<std::mutex> lock(m_eventQueueMutex);
-            m_eventQueue.emplace(event);
+            m_eventQueues[priority].emplace(event);
         }
         m_waitCondition.notify_one();
     }
@@ -82,15 +87,17 @@ private:
                 for (;;) {
                     if (m_quit)
                         return;
-                    if (!m_eventQueue.empty()) {
-                        event = m_eventQueue.front();
-                        m_eventQueue.pop();
-                        break;
-                    }
+                    for (auto &queue: m_eventQueues)
+                        if (!queue.empty()) {
+                            event = queue.front();
+                            queue.pop();
+                            goto handleOneEvent;
+                        }
                     m_waitCondition.wait(ulock);
                 }
             }
 
+        handleOneEvent:
             UNHANDLED_EXCEPTION_HANDLER_BEGIN
             {
                 const auto eventGuard = makeUnique(event);
index e6a37e1459f5733cfacca2ff3bd3d50451ee9ae1..2a98a9ab0d65b2ab3d40d59a5859344962c39c67 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2022 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.
@@ -31,6 +31,7 @@
 #include <dpl/log/log.h>
 #include <dpl/singleton.h>
 
+#include <cpu-boosting.h>
 #include <iostream>
 
 #include <channel.h>
@@ -83,12 +84,21 @@ int security_manager(Channel channel)
     LogInfo("Start!");
     SecurityManager::SocketManager manager;
 
+    resource_pid_t self_data;
+    self_data.pid = getpid();
+
+    if (resource_register_cpu_inheritance_destination(RESOURCE_CPU_DEST_NAME, self_data) != 0)
+        LogError("resource_register_cpi_inheritance_destination failed");
+
     if (!REGISTER_SOCKET_SERVICE(manager, SecurityManager::Service, std::move(channel))) {
         LogError("Unable to create socket service. Exiting.");
         return EXIT_FAILURE;
     }
 
     manager.MainLoop();
+
+    if(resource_unregister_cpu_inheritance_destination(RESOURCE_CPU_DEST_NAME) != 0)
+        LogError("resource_unregister_cpu_inheritance_destination failed");
     return 0;
 }
 
index 08f89cb269672f9422f6b53ec329b4508fee3189..c7623412143ad1f0c2e11203bdd649c969f686aa 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2013-2022 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.
@@ -42,6 +42,7 @@
 #include <time.h>
 #include <unistd.h>
 
+#include <cpu-boosting.h>
 #include <systemd/sd-daemon.h>
 
 #include <dpl/log/log.h>
@@ -196,8 +197,21 @@ void SocketManager::ReadyForRead(int sock) {
                 break;
             case MessageBuffer::InputResult::Done:
                 buffer.ModeStreaming();
+
+                if (buffer.DeserializationDone()) {
+                    LogError("No priority, closing socket");
+                    goto close;
+                }
+                std::underlying_type_t<Priority> priority;
+                Deserialization::Deserialize(buffer, priority);
+                if (priority >= Priority::END) {
+                    LogError("Invalid priority: " << priority);
+                    goto close;
+                }
+
                 FD_CLR(sock, &m_readSet); // the one and only call on this socket is complete
-                m_service->PutEvent(ConnectionID{sock, desc.counter},
+                m_service->PutEvent(static_cast<Priority>(priority),
+                        ConnectionID{sock, desc.counter},
                         Credentials::getCredentialsFromSocket(sock),
                         std::move(buffer));
                 break;
index b0dc38931b57c18b4454784721dccda3932b3c5c..dd3eea466ab8f977327bcef64f8a68bcdbce0cbf 100644 (file)
@@ -58,11 +58,6 @@ namespace {
 //  constexpr const char *dbUpdateScript[dbVersion];
 #include "../gen/db.h"
 
-template <class T, size_t S>
-constexpr size_t arraySize(T (&)[S]) {
-    return S;
-}
-
 static_assert(dbSchema);
 // this ensures that parsing the sql files was done correctly and we have proper
 // number of update scripts