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 c89efa1..563c559 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 f0df161..c8db938 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 a83e9cd..2d61d2f 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 fdc3c6a..03bcc20 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 099a9fd..b499888 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 f31f76e..b7a8e77 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 e19f8ee..5dac565 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 82d319b..2818a65 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 e6a37e1..2a98a9a 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 08f89cb..c762341 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 b0dc389..dd3eea4 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