Wrt patch for plugin process labeling to assign a separate label from UI process.
authorTae-Jeong Lee <taejeong.lee@samsung.com>
Mon, 23 Sep 2013 13:17:02 +0000 (22:17 +0900)
committerSoo-Hyun Choi <sh9.choi@samsung.com>
Tue, 29 Oct 2013 01:35:59 +0000 (10:35 +0900)
 - This patch includes 'EXECUTE_ON_WHOLE_THREAD()' utility which can be used
   when tring to execute same routine on whole thread a each.

[Issue#]   N/A
[Problem]  Wrt should assign a separated smack label from UI process to Plugin Process.
[Cause]    Because a child process inherits parent's smack label in linux system,
           We needed a special processing for smack labeling.
[Solution] Using inheritable bit of capability, UI process makes the Plugins process
           be available to have 'CAP_MAC_ADMIN' capabiltity.

[SCMRequest] Depends on https://review.tizendev.org/gerrit/#/c/90502/

Change-Id: I86176b74ad72d749a487e3fab5f705291e464084

packaging/wrt.spec
src/wrt-client/CMakeLists.txt
src/wrt-client/client_security_support.cpp [changed mode: 0644->0755]
src/wrt-client/client_security_support.h
src/wrt-client/wrt-client.cpp
src/wrt-launchpad-daemon/CMakeLists.txt
src/wrt-launchpad-daemon/include/execute_on_whole_thread_util.h [new file with mode: 0644]
src/wrt-launchpad-daemon/include/launchpad_util.h
src/wrt-launchpad-daemon/include/process_pool_launchpad_util.h
src/wrt-launchpad-daemon/launchpad_src/launchpad.c

index 6ee5cf4..737a84c 100644 (file)
@@ -11,8 +11,9 @@ Source0:    %{name}-%{version}.tar.gz
 BuildRequires:  cmake
 BuildRequires:  gettext
 BuildRequires:  edje-tools
-BuildRequires:  pkgconfig(ail)
+BuildRequires:  libcap-devel
 BuildRequires:  pkgconfig(aul)
+BuildRequires:  pkgconfig(ail)
 BuildRequires:  pkgconfig(glib-2.0)
 BuildRequires:  pkgconfig(ewebkit2)
 BuildRequires:  pkgconfig(appcore-efl)
index 43877a8..ae3d212 100644 (file)
@@ -58,6 +58,7 @@ TARGET_LINK_LIBRARIES(${TARGET_WRT_CLIENT}
     ${TARGET_CORE_MODULE_LIB}
     ${SMACK_LABELING_SUPPORT_STATIC}
     ${PROF_LIB}
+    "-lcap"
     "-pie"
 )
 
old mode 100644 (file)
new mode 100755 (executable)
index 27ae17d..5ca77f1
@@ -124,4 +124,27 @@ bool SecuritySupport::setAppPrivilege(const std::string& tizenAppId)
     destroyAppInfoHandle(handle);
     return true;
 }
+
+std::string SecuritySupport::getPluginProcessSoftLinkPath(const std::string& tzAppId)
+{
+    const std::string npruntimePostfix = ".npruntime";
+
+    ail_appinfo_h handle = NULL;
+    std::string appBinPath;
+
+    Try
+    {
+        getAppInfo(tzAppId, &handle);
+        char* path = getExePath(handle);
+        appBinPath = path;
+    }
+    Catch(Exception::Base)
+    {
+        destroyAppInfoHandle(handle);
+        return "";
+    }
+
+    destroyAppInfoHandle(handle);
+    return appBinPath + npruntimePostfix;
+}
 } // ClientModule
index 4a9696d..e62cf4f 100644 (file)
@@ -25,6 +25,7 @@
 namespace ClientModule {
 namespace SecuritySupport {
 bool setAppPrivilege(const std::string& tizenAppId);
+std::string getPluginProcessSoftLinkPath(const std::string& tzAppId);
 } // namespace SecuritySupport
 } // namespace ClientModule
 #endif // CLIENT_SECURITY_SUPPORT_H_
\ No newline at end of file
index c991822..205446f 100644 (file)
@@ -1025,6 +1025,15 @@ int main(int argc,
 
             std::string tizenId =
                 ClientModule::CommandLineParser::getTizenId(argc, argv);
+
+            // CapabilitySupport
+            std::string pluginProcessPath =
+                ClientModule::SecuritySupport::getPluginProcessSoftLinkPath(tizenId);
+            setenv("PLUGIN_PROCESS_EXECUTABLE_PATH_FOR_PROCESS_POOL",
+                    pluginProcessPath.c_str(), 1);
+            LogDebug("PLUGIN_PROCESS_EXECUTABLE_PATH_FOR_PROCESS_POOL = " <<
+                     pluginProcessPath);
+
             ewk_context_message_post_to_injected_bundle(
                 s_preparedEwkContext,
                 MESSAGE_NAME_INITIALIZE,
@@ -1052,6 +1061,15 @@ int main(int argc,
                 appcore_set_i18n("wrt-client", NULL);
                 ewk_set_arguments(argc, argv);
                 setenv("WRT_LAUNCHING_PERFORMANCE", "1", 1);
+
+                // CapabilitySupport
+                std::string pluginProcessPath =
+                    ClientModule::SecuritySupport::getPluginProcessSoftLinkPath(tizenId);
+                setenv("PLUGIN_PROCESS_EXECUTABLE_PATH",
+                       pluginProcessPath.c_str(), 1);
+                LogDebug("PLUGIN_PROCESS_EXECUTABLE_PATH = " <<
+                         pluginProcessPath);
+
                 s_preparedEwkContext = ewk_context_new_with_injected_bundle_path(
                         BUNDLE_PATH);
 
index bb53a58..e47129e 100644 (file)
@@ -59,6 +59,7 @@ ADD_EXECUTABLE( ${WRT_LAUNCH_PAD_NAME}
 TARGET_LINK_LIBRARIES( ${WRT_LAUNCH_PAD_NAME}
     ${WRT_LAUNCH_PAD_DEPS_LIBRARIES}
     ${CMAKE_DL_LIBS}
+    "-lcap"
 )
 
 #install
diff --git a/src/wrt-launchpad-daemon/include/execute_on_whole_thread_util.h b/src/wrt-launchpad-daemon/include/execute_on_whole_thread_util.h
new file mode 100644 (file)
index 0000000..fde4e68
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    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.
+ */
+/**
+ * @file    execute_on_whole_thread_util.h
+ * @author  Tae-Jeong Lee (taejeong.lee@samsung.com)
+ * @version 1.0
+ */
+
+#ifndef __EXECUTE_ON_WHOLE_THREAD_UTIL_H__
+#define __EXECUTE_ON_WHOLE_THREAD_UTIL_H__
+
+#include <assert.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/syscall.h>
+
+// define
+#define _EXEC_FILE_MAX_LEN 1024
+#define _EXEC_MAX_RETRY_CNT 1000
+
+// typedef
+typedef void (*exec_func_t)();
+
+// static variable
+static exec_func_t  _s_exec_func    = NULL;
+static sighandler_t _s_prev_handler = NULL;
+static int _s_exec_waiting_task_cnt = 0;
+
+// internal function
+static void _exec_signal_handler(int signum)
+{
+    (void) signum;
+
+    if (_s_exec_func)
+    {
+        _s_exec_func();
+    }
+
+    _s_exec_waiting_task_cnt--;
+}
+
+static int _set_exec_signal_handler(int signum)
+{
+    sighandler_t ret;
+
+    ret = signal(signum, _exec_signal_handler);
+
+    if (ret == SIG_ERR)
+    {
+        return -1;
+    }
+    else
+    {
+        _s_prev_handler = ret;
+    }
+
+    return 0;
+}
+
+static int _restore_signal_handler(int signum)
+{
+    if (_s_prev_handler)
+    {
+        if (signal(signum, _s_prev_handler) == SIG_ERR)
+        {
+            return -1;
+        }
+
+        _s_prev_handler = NULL;
+    }
+    else
+    {
+        if (signal(signum, SIG_DFL) == SIG_ERR)
+        {
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+static int _send_signal_to_whole_thread(int signum)
+{
+    int ret;
+    DIR *dir;
+    struct dirent entry, *result;
+    char proc_self_task_path[_EXEC_FILE_MAX_LEN + 1] = {0, };
+
+    sprintf(proc_self_task_path, "/proc/self/task");
+
+    dir = opendir(proc_self_task_path);
+
+    if (dir)
+    {
+        for (ret = readdir_r(dir, &entry, &result);
+             result != NULL && ret == 0;
+             ret = readdir_r(dir, &entry, &result))
+        {
+            if (strncmp(entry.d_name, ".", 2) == 0 ||
+                strncmp(entry.d_name, "..", 3) == 0)
+            {
+                continue;
+            }
+
+            _s_exec_waiting_task_cnt++;
+            if (syscall(__NR_tkill, atoi(entry.d_name), signum) != 0)
+            {
+                // syscall failed
+                _s_exec_waiting_task_cnt--;
+            }
+        }
+
+        closedir(dir);
+    }
+    else
+    {
+        return -1;
+    }
+
+    return 0;
+}
+
+static int _is_main_thread()
+{
+    int pid = getpid();
+    int tid = syscall(__NR_gettid);
+
+    return (pid == tid);
+}
+
+static int _waiting_for_done()
+{
+    int i;
+
+    for (i=0; _s_exec_waiting_task_cnt && i < _EXEC_MAX_RETRY_CNT; i++)
+    {
+        usleep(100); // 0.1ms
+    }
+
+    if (i == _EXEC_MAX_RETRY_CNT)
+    {
+        // time over
+        return -1;
+    }
+
+    return 0;
+}
+
+// external API
+int EXECUTE_ON_WHOLE_THREAD(exec_func_t exec_func, int using_signum)
+{
+    int signum;
+
+    assert(_s_exec_waiting_task_cnt == 0 && exec_func != NULL);
+    assert(using_signum == SIGUSR1 || using_signum == SIGUSR2);
+
+    // check main thread
+    if (!_is_main_thread())
+    {
+        return -1;
+    }
+
+    signum       = using_signum;
+    _s_exec_func = exec_func;
+
+    // set signal handler
+    if (_set_exec_signal_handler(signum) != 0)
+    {
+        goto onerr_EXECUTE_ON_WHOLE_THREAD;
+    }
+
+    // send signal
+    if (_send_signal_to_whole_thread(signum) != 0)
+    {
+        goto onerr_EXECUTE_ON_WHOLE_THREAD;
+    }
+
+    // waiting
+    if (_waiting_for_done() != 0)
+    {
+        goto onerr_EXECUTE_ON_WHOLE_THREAD;
+    }
+
+    // restore signal handler to previous
+    _restore_signal_handler(signum);
+    _s_exec_waiting_task_cnt = 0;
+    _s_exec_func    = NULL;
+    _s_prev_handler = NULL;
+
+    return 0;
+
+
+onerr_EXECUTE_ON_WHOLE_THREAD:
+    _restore_signal_handler(signum);
+    _s_exec_waiting_task_cnt = 0;
+    _s_exec_func    = NULL;
+    _s_prev_handler = NULL;
+
+    return -1;
+}
+
+#endif // __EXECUTE_ON_WHOLE_THREAD_UTIL_H__
index 26edc7e..53abebd 100644 (file)
 
 #include <aul.h>
 #include <bundle.h>
+#include <errno.h>
 #include <privilege-control.h>
 #include <sys/prctl.h>
+#include <sys/capability.h>
+#include <unistd.h>
 
 #include "config.h"
 #include "gl.h"
@@ -51,6 +54,7 @@ _static_ int    __parser(const char *arg, char *out, int out_size);
 _static_ void   __modify_bundle(bundle * kb, int caller_pid, app_info_from_db * menu_info, int cmd);
 _static_ void   __set_oom();
 _static_ void   __set_env(app_info_from_db * menu_info, bundle * kb);
+_static_ void   __set_inherit_bit_for_CAP_MAC_ADMIN();
 
 // Implementation
 _static_ char** __create_argc_argv(bundle * kb, int *margc)
@@ -294,4 +298,41 @@ _static_ void __set_env(app_info_from_db * menu_info, bundle * kb)
     }
 }
 
+_static_ void __set_inherit_bit_for_CAP_MAC_ADMIN()
+{
+    cap_t caps = NULL;
+    cap_value_t target_caps[] = { CAP_MAC_ADMIN };
+
+    caps = cap_init();
+
+    if (caps == NULL) {
+        goto err_set_inherit_bit_for_CAP_MAC_ADMIN;
+    }
+
+    if (cap_set_flag(caps, CAP_INHERITABLE,
+                     sizeof(target_caps)/sizeof(cap_value_t),
+                     target_caps, CAP_SET)) {
+        _E("cap_set_flag() failed!! : %s", strerror(errno));
+        goto err_set_inherit_bit_for_CAP_MAC_ADMIN;
+    }
+
+    if (cap_set_proc(caps)) {
+        _E("cap_set_proc() failed!! : %s", strerror(errno));
+        goto err_set_inherit_bit_for_CAP_MAC_ADMIN;
+    }
+
+    if (cap_free(caps)) {
+        _E("cap_free() failed!!");
+    }
+
+    return;
+
+err_set_inherit_bit_for_CAP_MAC_ADMIN:
+    if (caps != NULL) {
+        cap_free(caps);
+    }
+
+    return;
+}
+
 #endif // __LAUNCHPAD_UTIL_H_
index ce4cd97..cb6fea8 100644 (file)
@@ -26,6 +26,7 @@
 #include <stdlib.h>
 #include <launchpad_util.h>
 #include <smack_labeling_support.h>
+#include <execute_on_whole_thread_util.h>
 
 // Prototype
 _static_ int    __process_pool_prepare_exec(const char *pkg_name, const char *app_path, app_info_from_db * menu_info, bundle * kb);
@@ -54,6 +55,9 @@ _static_ int __process_pool_prepare_exec(const char *pkg_name,
         return -1;
     }
 
+    /* SET INHERIT BIT FOR CAP_MAC_ADMIN TO WHOLE THREAD */
+    EXECUTE_ON_WHOLE_THREAD(__set_inherit_bit_for_CAP_MAC_ADMIN, SIGUSR1);
+
     /* SET PROCESS NAME*/
     if (app_path == NULL) {
         _D("app_path should not be NULL - check menu db");
index 4171cf1..fd50743 100644 (file)
@@ -121,11 +121,18 @@ _static_ int __prepare_exec(const char *pkg_name,
     memset(pkg_id, '\0', PKG_ID_LENGTH);
     snprintf(pkg_id, PKG_ID_LENGTH, "%s", pkg_name);
 
+    /* SET PR_SET_KEEPCAPS */
+    if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
+        _E("prctl(PR_SET_KEEPCAPS) failed.");
+    }
+
     if (__set_access(pkg_id, menu_info->pkg_type, app_path) < 0) {
         _D("fail to set privileges - check your package's credential\n");
         return -1;
     }
 
+    __set_inherit_bit_for_CAP_MAC_ADMIN();
+
     /* SET DUMPABLE - for coredump*/
     prctl(PR_SET_DUMPABLE, 1);
 
@@ -474,6 +481,11 @@ _static_ void __launchpad_exec_dummy(int main_fd, int pool_fd, int client_fd)
         __signal_unset_sigchld();
         __signal_fini();
 
+        /* SET PR_SET_KEEPCAPS */
+        if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
+            _E("prctl(PR_SET_KEEPCAPS) failed.");
+        }
+
         /* SET DUMPABLE - for coredump*/
         prctl(PR_SET_DUMPABLE, 1);