Add new APIs for loader process 34/287034/2
authorHwankyu Jhun <h.jhun@samsung.com>
Thu, 19 Jan 2023 01:47:28 +0000 (01:47 +0000)
committerHwankyu Jhun <h.jhun@samsung.com>
Thu, 19 Jan 2023 01:59:32 +0000 (01:59 +0000)
Before calling the loader_launch_cb() callback function, the loader process
has to make blocking all sub threads if a new thread is able to be created by
the sub thread. This patch adds new functions for the loader process.
Some loader process creates a new process while calling the security_manager_prepare_app2().
It makes an application launch failure issue.

When calling the loader_prelaunch_cb() callback function, the loader should call
the launchpad_loader_block_threads() to make blocking all sub threads.
And then, the loader calls the launchpad_loader_unblock_threads() while calling
the launchpad_launch_cb() callback function.

Even if the sub thread creates a new thread while calling the launchpad_loader_block_threads(),
it handles by the security_manager_prepare_app2() function.
This is not complete solution. But, this patch is able to reduce the risk about
the launch failure issues.

Adds:
 - launchpad_loader_block_threads()
 - launchpad_loader_unblock_threads()

Change-Id: Ib98d435507abbb0d3ebe0a5617d7fcb2509c154e
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
src/lib/launchpad/inc/launchpad.h
src/lib/launchpad/src/launchpad_lib.c

index 86ea976..b7d6c21 100644 (file)
@@ -81,6 +81,27 @@ int launchpad_loader_set_priority(int prio);
 
 bundle *launchpad_loader_get_bundle(void);
 
+/**
+ * @brief Blocks all sub threads of the loader.
+ * @remarks This function has to be called in the main thread.
+ *
+ * @return @c on success,
+ *         otherwise a negative error value
+ *
+ * @see #launchpad_loader_unblock_threads()
+ */
+int launchpad_loader_block_threads(void);
+
+/**
+ * @brief Unblocks all sub threads of the loader.
+ * @remarks This function has to be called in the main thread.
+ *
+ * @return @c on success,
+ *         otherwise a negative error value
+ * @see #launchpad_loader_block_threads()
+ */
+int launchpad_loader_unblock_threads(void);
+
 #ifdef __cplusplus
 }
 #endif
index 0c7dd27..7c4512f 100644 (file)
 #endif
 
 #define AUL_PR_NAME 16
+#define SIGRTINT (SIGRTMIN + 2)
+
+typedef struct thread_handler_s {
+       struct sigaction old;
+       GMutex mutex;
+       GCond cond;
+       gint count;
+       gint num;
+       bool blocked;
+       bool done;
+} thread_handler_t;
 
 static loader_lifecycle_callback_s *__loader_callbacks;
 static loader_adapter_s *__loader_adapter;
@@ -54,6 +65,7 @@ static bundle *__bundle;
 static int __loader_type = LAUNCHPAD_TYPE_UNSUPPORTED;
 static int __loader_id;
 static bool __loop_quit;
+static thread_handler_t __thread_handler;
 
 static void __at_exit_to_release_bundle(void)
 {
@@ -580,3 +592,102 @@ API int launchpad_loader_set_priority(int prio)
 {
        return _set_priority(prio);
 }
+
+static void __signal_handler(int signo)
+{
+       _D("Block thread");
+       g_mutex_lock(&__thread_handler.mutex);
+       g_atomic_int_set(&__thread_handler.count,
+                       g_atomic_int_get(&__thread_handler.count) - 1);
+       while (!__thread_handler.done)
+               g_cond_wait(&__thread_handler.cond, &__thread_handler.mutex);
+       g_mutex_unlock(&__thread_handler.mutex);
+       g_atomic_int_inc(&__thread_handler.count);
+       _D("Unblock thread");
+}
+
+API int launchpad_loader_block_threads(void)
+{
+       struct sigaction act;
+       struct dirent *dentry;
+       DIR *dp;
+       pid_t pid = getpid();
+       pid_t tid;
+       gint i;
+
+       if (__thread_handler.blocked) {
+               _D("Already blocked");
+               return 0;
+       }
+
+       g_mutex_init(&__thread_handler.mutex);
+       g_cond_init(&__thread_handler.cond);
+
+       memset(&act, '\0', sizeof(act));
+       sigemptyset(&act.sa_mask);
+       act.sa_flags = SA_RESTART;
+       act.sa_handler = __signal_handler;
+
+       if (sigaction(SIGRTINT, &act, &__thread_handler.old) != 0) {
+               _E("sigaction() is failed. errno(%d)", errno);
+               return -1;
+       }
+
+       __thread_handler.done = false;
+       __thread_handler.count = 0;
+       __thread_handler.num = 0;
+
+       dp = opendir("/proc/self/task");
+       if (dp == NULL) {
+               _E("opendir() is failed. errno(%d)", errno);
+               sigaction(SIGRTINT, &__thread_handler.old, NULL);
+               return -1;
+       }
+
+       while ((dentry = readdir(dp)) != NULL) {
+               if (!isdigit(dentry->d_name[0]))
+                       continue;
+
+               tid = atoi(dentry->d_name);
+               if (tid != pid) {
+                       _D("Send signal to thread(%d)", tid);
+                       if (tgkill(pid, tid, SIGRTINT) != 0) {
+                               _E("tgkill() is failed. errno(%d)", errno);
+                       } else {
+                               g_atomic_int_inc(&__thread_handler.count);
+                               __thread_handler.num++;
+                       }
+               }
+       }
+       closedir(dp);
+
+       for (i = 1000; g_atomic_int_get(&__thread_handler.count) && i; --i)
+               usleep(2000);
+
+       __thread_handler.blocked = true;
+
+       return 0;
+}
+
+API int launchpad_loader_unblock_threads(void)
+{
+       gint i;
+
+       if (!__thread_handler.blocked)
+               return 0;
+
+       g_mutex_lock(&__thread_handler.mutex);
+       __thread_handler.done = true;
+       g_cond_broadcast(&__thread_handler.cond);
+       g_mutex_unlock(&__thread_handler.mutex);
+
+       for (i = 1000; g_atomic_int_get(&__thread_handler.count) != __thread_handler.num && i; --i)
+               usleep(2000);
+
+       sigaction(SIGRTINT, &__thread_handler.old, NULL);
+       g_mutex_clear(&__thread_handler.mutex);
+       g_cond_clear(&__thread_handler.cond);
+       __thread_handler.blocked = false;
+
+       return 0;
+}