Fix possible issue with lazy-symbol binding 24/318424/5
authorTomasz Swierczek <t.swierczek@samsung.com>
Thu, 16 Jan 2025 12:30:17 +0000 (13:30 +0100)
committerTomasz Swierczek <t.swierczek@samsung.com>
Thu, 16 Jan 2025 13:30:52 +0000 (14:30 +0100)
It seems possible that lazy binding of the SO symbols loaded by linker can cause problems
when the SIGSETXID arrives in some thread at the precise moment that a symbol in a thread
is being lazy-initialized. By doing calls below we're ensuring that symbols used inside
our handler are already loaded - lazy symbols (or any not-loaded) should not be called inside
a handler.

Also, changed the handler to be a regular function for easier debugging in kernel team.

Change-Id: I6a293374c38f47b18af86166d8b150af55469739

src/client/client-security-manager.cpp

index bb1b80fe125c6168045495dd63ba9f135dae8fb6..d65d6626f385bcc634abd87edfb8de5dc025f473 100644 (file)
@@ -811,6 +811,24 @@ static void signal_and_wait_for_handlers(pid_t own_pid, int own_tid) noexcept
     } while (true);
 }
 
+static void sig_handler(int signo)
+{
+    (void)signo;
+    std::atomic_thread_fence(std::memory_order_acquire);
+    int tid = Syscall::gettid();
+    set_tid_state(tid, 1);
+    while(g_th_barrier == 0)
+        usleep(SLEEP_CONST);
+    if (g_p_app_label)
+        if (label_for_self_internal(tid) != 0)
+            return;
+    if (cap_set_proc(g_cap))
+        return;
+    set_tid_state(tid, 2);
+    while(g_th_barrier == 1)
+        usleep(SLEEP_CONST);
+}
+
 static inline int security_manager_sync_threads_internal(const std::string &app_label)
 {
     static_assert(ATOMIC_INT_LOCK_FREE == 2, "std::atomic<int> is not always lock free");
@@ -838,22 +856,7 @@ static inline int security_manager_sync_threads_internal(const std::string &app_
 
     sigemptyset(&act.sa_mask);
     act.sa_flags = SA_RESTART;
-    act.sa_handler = [](int signo) {
-        (void)signo;
-        std::atomic_thread_fence(std::memory_order_acquire);
-        int tid = Syscall::gettid();
-        set_tid_state(tid, 1);
-        while(g_th_barrier == 0)
-            usleep(SLEEP_CONST);
-        if (g_p_app_label)
-            if (label_for_self_internal(tid) != 0)
-                return;
-        if (cap_set_proc(g_cap))
-            return;
-        set_tid_state(tid, 2);
-        while(g_th_barrier == 1)
-            usleep(SLEEP_CONST);
-    };
+    act.sa_handler = sig_handler;
 
     if (Syscall::sigaction(SIGSETXID, &act, &old) < 0) {
         LogError("Error in sigaction()");
@@ -863,6 +866,27 @@ static inline int security_manager_sync_threads_internal(const std::string &app_
     initialize_tid_states();
     std::atomic_thread_fence(std::memory_order_release);
 
+    // It seems possible that lazy binding of the SO symbols loaded by linker can cause problems
+    // when the SIGSETXID arrives in some thread at the precise moment that a symbol in a thread
+    // is being lazy-initialized. By doing calls below we're ensuring that symbols used inside
+    // our handler are already loaded.
+    // not calling open/read/write/close/std::string anywyere as these are already used before,
+    // including openning connection to the daemon that uses sockets.
+    // <begin of calling functions to load symbols>
+    (void)syscall(-1);
+    usleep(SLEEP_CONST);
+    char buffer [10];
+    int a = 1;
+    (void)sprintf(buffer, "%d", a);
+    cap_t tmp_cap = cap_get_proc();
+    if (!tmp_cap) {
+        LogError("Unable to allocate capability object");
+        return SECURITY_MANAGER_ERROR_MEMORY;
+    }
+    (void)cap_set_proc(tmp_cap);
+    (void)cap_free(tmp_cap);
+    // <end of calling functions just to load them>
+
     g_th_barrier = 0;
 
     auto enabled = SecurityManager::Log::LogSystemSingleton::Instance().IsLoggingEnabled();