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 940e0d1409e7ec694010ef5db100bef86196be9e..94b0fcc2e9705a89a4ef5128d8febd41804ac236 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 bced9f8e7a7d16958db5164fefaf2fa8c3603ee7..f733aedc6793d0f5aee0394337cb1149d0f62b6a 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 7dc9fea2f4a3a2dff8e3de280cf257a9db93fccd..d478155f282d3f306cb5eec3850dab422e7bedd7 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 c7922d5200beba7fb8471bf6af1d6fa04717d970..86455bb873062fa9ad616d52a5f1fa98283d2faa 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."