emulator: respawning when elevated
authorMunkyu Im <munkyu.im@samsung.com>
Thu, 13 Oct 2016 13:18:30 +0000 (22:18 +0900)
committerMunkyu Im <munkyu.im@samsung.com>
Fri, 14 Oct 2016 03:07:01 +0000 (12:07 +0900)
In order to prevent potential elevation of privilege attack, lower
privilege processes can't interfere with higher privilege on Windows.
Emulator is usually launched by emulator manager that has high integrity
level, then drag-and-drop from Explorer (mostly medium integrity level)
does not work.

So, when emulator process has elevated integrity level, we try to
respawn emulator with medium integrity level.

Change-Id: I17f29e411252758098304ba25b60219d07aa0d7c
Signed-off-by: Munkyu Im <munkyu.im@samsung.com>
Signed-off-by: SeokYeon Hwang <syeon.hwang@samsung.com>
tizen/src/emulator.c
tizen/src/util/osutil-win32.c
tizen/src/util/osutil.h
version.rc

index 940e0d1..94b0fcc 100644 (file)
 #include "ecs/ecs.h"
 #include "util/device_hotplug.h"
 #include "util/exported_strings.h"
-
+#ifdef CONFIG_WIN32
+#include <windows.h>
+#include <sddl.h>
+#endif
 #ifdef CONFIG_QT
 #include <qt5_supplement.h>
 #endif
@@ -346,6 +349,15 @@ int main(int argc, char *argv[], char **envp)
     init_error_handler();
     return emulator_main(argc, argv, envp);
 }
+#elif defined (CONFIG_WIN32)
+int main(int argc, char *argv[])
+{
+    if (!check_integrity_level_and_respawn()) {
+        init_error_handler();
+        return emulator_main(argc, argv, NULL);
+    }
+    return 0;
+}
 #else
 int main(int argc, char *argv[])
 {
index bced9f8..f733aed 100644 (file)
@@ -96,12 +96,12 @@ void make_vm_lock_os(gchar *vms_path)
                     GetLastError());
     }
     lock_file = CreateFile(lock_filename,
-                           GENERIC_READ | GENERIC_WRITE,
-                           0,       // No share
-                           NULL,
-                           CREATE_ALWAYS,
-                           FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
-                           NULL);
+            GENERIC_READ | GENERIC_WRITE,
+            0,       // No share
+            NULL,
+            CREATE_ALWAYS,
+            FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
+            NULL);
     if (lock_file == INVALID_HANDLE_VALUE) {
         DWORD error = GetLastError();
         // On Windows, the file opened by CreateFile has exclusive lock
@@ -202,12 +202,12 @@ bool make_sdcard_lock_os(char *sdcard)
 
     fname = g_strdup_printf("%s.lck", sdcard);
     h = CreateFile(fname,
-                   GENERIC_READ,
-                   0,               // No share
-                   NULL,
-                   CREATE_ALWAYS,
-                   FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
-                   NULL);
+            GENERIC_READ,
+            0,               // No share
+            NULL,
+            CREATE_ALWAYS,
+            FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
+            NULL);
 
     if (h == INVALID_HANDLE_VALUE) {
         LOG_WARNING("Failed to CreateFile a sdcard lock file: %d\n",
@@ -278,11 +278,11 @@ void get_java_path_win32(const char **java_path)
 
     /* Opens above key to query the current version */
     res = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
-                       strKey,
-                       0,
-                       KEY_QUERY_VALUE |
-                       MY_KEY_WOW64_64KEY,
-                       &hKey);
+            strKey,
+            0,
+            KEY_QUERY_VALUE |
+            MY_KEY_WOW64_64KEY,
+            &hKey);
     if (res != ERROR_SUCCESS) {
         LOG_WARNING("Java Runtime Environment key not found\n");
         goto javahome_not_found;
@@ -290,11 +290,11 @@ void get_java_path_win32(const char **java_path)
 
     /* Queries for the current version */
     res = RegQueryValueEx(hKey,
-                          "CurrentVersion",
-                          NULL,
-                          NULL,
-                          (LPBYTE)strVersion,
-                          &dwBufLen);
+            "CurrentVersion",
+            NULL,
+            NULL,
+            (LPBYTE)strVersion,
+            &dwBufLen);
     RegCloseKey(hKey);
     if (res != ERROR_SUCCESS) {
         LOG_WARNING("JRE CurrentVersion not found\n");
@@ -307,11 +307,11 @@ void get_java_path_win32(const char **java_path)
 
     /* Opens above key to query the JavaHome */
     res = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
-                       strKey,
-                       0,
-                       KEY_QUERY_VALUE |
-                       MY_KEY_WOW64_64KEY,
-                       &hKey);
+            strKey,
+            0,
+            KEY_QUERY_VALUE |
+            MY_KEY_WOW64_64KEY,
+            &hKey);
     if (res == ERROR_SUCCESS) {
         /* Queries for the JavaHome */
         dwBufLen = PATH_MAX;
@@ -337,3 +337,117 @@ javahome_not_found:
 
     *java_path = current_java_path;
 }
+
+bool check_integrity_level_and_respawn(void)
+{
+    BOOL                    bResult = false;
+    HANDLE                  hToken = NULL;
+    HANDLE                  hNewToken = NULL;
+    PSID                    pIntegritySid = NULL;
+    TOKEN_MANDATORY_LABEL   TIL = { { 0, }, };
+    PTOKEN_MANDATORY_LABEL  pTIL = NULL;
+    PROCESS_INFORMATION     ProcInfo = { 0, };
+    STARTUPINFO             StartupInfo = { 0, };
+    SID_IDENTIFIER_AUTHORITY
+                            MLAuthority = { SECURITY_MANDATORY_LABEL_AUTHORITY };
+    DWORD                   dwIntegrityLevel, dwSize = 0;
+
+    if(!OpenProcessToken(GetCurrentProcess(),
+                TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT | TOKEN_QUERY |
+                TOKEN_ASSIGN_PRIMARY, &hToken)) {
+        LOG_WARNING("OpenProcessToken Error %lu\n", GetLastError());
+        goto CleanExit;
+    }
+
+    if (!GetTokenInformation(hToken, TokenGroups, NULL, 0, &dwSize)) {
+        DWORD dwResult = GetLastError();
+        if (dwResult != ERROR_INSUFFICIENT_BUFFER) {
+            LOG_WARNING("GetTokenInformation Error %lu\n", dwResult);
+            goto CleanExit;
+        }
+    }
+
+    pTIL = (PTOKEN_MANDATORY_LABEL)LocalAlloc(0, dwSize);
+    if (!pTIL) {
+        LOG_WARNING("LocalAlloc Error %lu\n", GetLastError());
+        goto CleanExit;
+    }
+
+    if (!GetTokenInformation(hToken, TokenIntegrityLevel, pTIL,
+                dwSize, &dwSize)) {
+        LOG_WARNING("GetTokenInformation Error %lu\n", GetLastError());
+        goto CleanExit;
+    }
+
+    dwIntegrityLevel = *GetSidSubAuthority(pTIL->Label.Sid,
+            (DWORD)(UCHAR)(*GetSidSubAuthorityCount(pTIL->Label.Sid) - 1));
+
+    if (dwIntegrityLevel >= SECURITY_MANDATORY_MEDIUM_RID &&
+            dwIntegrityLevel < SECURITY_MANDATORY_HIGH_RID) {
+        // We have medium integrity level. So keep going on.
+        goto CleanExit;
+    }
+
+    LOG_INFO("Running with elevated integrity level. Try to respawn.\n");
+
+    if (!DuplicateTokenEx(hToken, 0, NULL, SecurityImpersonation,
+            TokenPrimary, &hNewToken)) {
+        LOG_WARNING("DuplicateTokenEx Error %lu\n", GetLastError());
+        goto CleanExit;
+    }
+
+    if (!AllocateAndInitializeSid(&MLAuthority, 1, SECURITY_MANDATORY_MEDIUM_RID,
+                0, 0, 0, 0, 0, 0, 0, &pIntegritySid)) {
+        LOG_WARNING("AllocateAndInitializeSid Error %lu\n", GetLastError());
+        goto CleanExit;
+    }
+
+    TIL.Label.Attributes = SE_GROUP_INTEGRITY;
+    TIL.Label.Sid = pIntegritySid;
+
+    if (!SetTokenInformation(hNewToken,
+            TokenIntegrityLevel,
+            &TIL,
+            sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(pIntegritySid))) {
+        LOG_WARNING("SetTokenInformation Error %lu\n", GetLastError());
+        goto CleanExit;
+    }
+
+    if (!CreateProcessAsUser(hNewToken, 0, GetCommandLine(),
+            NULL, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &ProcInfo)) {
+        LOG_WARNING( "CreateProcessAsUser Error %lu\n", GetLastError());
+        goto CleanExit;
+    }
+
+    LOG_INFO("Respawning success. Waiting for child process.\n");
+    bResult = true;
+    WaitForSingleObject(ProcInfo.hProcess, INFINITE);
+
+CleanExit:
+    if (ProcInfo.hProcess != NULL) {
+        CloseHandle(ProcInfo.hProcess);
+    }
+
+    if (ProcInfo.hThread != NULL) {
+        CloseHandle(ProcInfo.hThread);
+    }
+
+    if (pIntegritySid != NULL) {
+        LocalFree(pIntegritySid);
+    }
+
+    if (hNewToken != NULL) {
+        CloseHandle(hNewToken);
+    }
+
+    if (hToken != NULL) {
+        CloseHandle(hToken);
+    }
+
+    if (pTIL != NULL) {
+        LocalFree(pTIL);
+    }
+
+    return bResult;
+}
+
index 7dc9fea..d478155 100644 (file)
@@ -57,6 +57,7 @@ bool make_sdcard_lock_posix(char *sdcard);
 int remove_sdcard_lock_posix(char *sdcard);
 #else
 void get_java_path_win32(const char **java_path);
+bool check_integrity_level_and_respawn(void);
 #endif
 
 void set_bin_path_os(char const *const);
index c7922d5..86455bb 100644 (file)
@@ -14,7 +14,11 @@ FILESUBTYPE VFT2_UNKNOWN
     BLOCK "040904E4"
     {
       VALUE "CompanyName", "http://www.qemu-project.org"
+#ifdef CONFIG_MARU
+      VALUE "FileDescription", "Tizen Emulator"
+#else
       VALUE "FileDescription", "QEMU machine emulators and tools"
+#endif
       VALUE "FileVersion", QEMU_VERSION
       VALUE "LegalCopyright", "Copyright various authors. Released under the GNU General Public License."
       VALUE "LegalTrademarks", "QEMU is a trademark of Fabrice Bellard."