summaryrefslogtreecommitdiff
path: root/tizen/src/util/osutil-win32.c
blob: f733aedc6793d0f5aee0394337cb1149d0f62b6a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
/*
 * osutil
 *
 * Copyright (C) 2012 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
 *
 * Contact:
 * SeokYeon Hwang <syeon.hwang@samsung.com>
 * MunKyu Im <munkyu.im@samsung.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * Contributors:
 * - S-Core Co., Ltd
 *
 */

/**
  @file     osutil-win32.c
  @brief    Collection of utilities for win32
 */

#include <windows.h>

#include "png.h"

#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu/error-report.h"
#include "osutil.h"
#include "emulator.h"
#include "emul_state.h"

#ifndef CONFIG_WIN32
#error
#endif

#include "new_debug_ch.h"
DECLARE_DEBUG_CHANNEL(osutil);

static char *lock_filename = NULL;
static HANDLE lock_file = INVALID_HANDLE_VALUE;

static sdcard_info info = {
    .handle = INVALID_HANDLE_VALUE,
    .lock_file = NULL,
};

static void remove_vm_lock_os(void)
{
    g_free(lock_filename);
    lock_filename = NULL;

    if (lock_file == INVALID_HANDLE_VALUE) {
        return;
    }

    CloseHandle(lock_file);
    lock_file = INVALID_HANDLE_VALUE;
}

static void notify_remove_lock(Notifier *notifier, void *data)
{
    remove_vm_lock_os();
}

static Notifier remove_lock = { .notify = notify_remove_lock };

/*
On Windows, emulator will stop before checking lock because platform
image file and kernel log file are aleady opened with exclusive write
lock by pre-executed emulator. But it is still useful for
emulator-manager.
*/
void make_vm_lock_os(gchar *vms_path)
{

    g_assert(lock_file == INVALID_HANDLE_VALUE);
    g_assert(lock_filename == NULL);

    lock_filename = g_strdup_printf("%s\\%s", vms_path, VMLOCK_FILE);

    if (g_mkdir_with_parents(g_path_get_dirname(lock_filename), 0777)) {
        LOG_WARNING("Can not create directory for lock file: %ld\n",
                    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);
    if (lock_file == INVALID_HANDLE_VALUE) {
        DWORD error = GetLastError();
        // On Windows, the file opened by CreateFile has exclusive lock
        // naturally unless FILE_SHARE_* attribute is set.
        if (error == ERROR_SHARING_VIOLATION) {
            error_report("Can not execute this VM. "
                    "The same VM may be running now.");
            exit(1);
        }

        LOG_WARNING("Failed to create lock file: %0xlx\n", error);
    }

    emulator_add_exit_notifier(&remove_lock);
}

void set_bin_path_os(char const *const exec_argv)
{
    char link_path[PATH_MAX] = { 0, };
    char bin_path_os[PATH_MAX] = { 0, };
    char *file_name = NULL;

    if (!GetModuleFileName(NULL, link_path, PATH_MAX)) {
        return;
    }

    file_name = g_strrstr(link_path, "\\");
    g_strlcpy(bin_path_os, link_path, strlen(link_path) - strlen(file_name) + 1);
    g_strlcat(bin_path_os, "\\", PATH_MAX);

    bin_path = g_strdup(bin_path_os);
}

int get_number_of_processors(void)
{
    SYSTEM_INFO sysi;
    int num_processors = 0;

    GetSystemInfo(&sysi);
    LOG_TRACE("Processor type: %d, Core number: %d\n",
        sysi.dwProcessorType, sysi.dwNumberOfProcessors);

    num_processors = sysi.dwNumberOfProcessors;
    if (num_processors < 1) {
        num_processors = 1;
    }

    return num_processors;
}

// FIXME
OSVERSIONINFO osvi;

void print_system_info_os(void)
{
    LOG_INFO("* Windows\n");
    LOG_INFO("* LibPNG Version : %s\n", PNG_LIBPNG_VER_STRING);

    /* Retrieves information about the current os */
    ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

    if (GetVersionEx(&osvi)) {
        LOG_INFO("* MajorVersion : %d, MinorVersion : %d, BuildNumber : %d, "
            "PlatformId : %d, CSDVersion : %s\n", osvi.dwMajorVersion,
            osvi.dwMinorVersion, osvi.dwBuildNumber,
            osvi.dwPlatformId, osvi.szCSDVersion);
    }

    /* Retrieves information about the current system */
    SYSTEM_INFO sysi;
    ZeroMemory(&sysi, sizeof(SYSTEM_INFO));

#if 0
    GetSystemInfo(&sysi);
    LOG_INFO("* Processor type : %d, Number of processors : %d\n",
            sysi.dwProcessorType, sysi.dwNumberOfProcessors);
#endif
    get_number_of_processors();

    MEMORYSTATUSEX memInfo;
    memInfo.dwLength = sizeof(MEMORYSTATUSEX);
    GlobalMemoryStatusEx(&memInfo);
    LOG_INFO("* Total Ram : %llu kB, Free: %lld kB\n",
            memInfo.ullTotalPhys / 1024, memInfo.ullAvailPhys / 1024);
}

bool make_sdcard_lock_os(char *sdcard)
{
    HANDLE  h;
    char    *fname;

    if (info.handle != INVALID_HANDLE_VALUE) {
        g_assert(info.lock_file != NULL);
        LOG_INFO("sdcard(%s) is already attached\n", info.lock_file);
        return false;
    }

    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);

    if (h == INVALID_HANDLE_VALUE) {
        LOG_WARNING("Failed to CreateFile a sdcard lock file: %d\n",
                 (DWORD)GetLastError());
        g_free(fname);
        return false;
    }

    /* If the lock file exists and CreateFile() succeeded, just go on.
     * If other emulator locks the sdcard, CreateFile failed owing to
     * ERROR_SHARING_VIOLATION. Therefore, no emulator opened the lock file
     * and just go on attaching sdcard.
     */
    if (GetLastError() != ERROR_ALREADY_EXISTS) {
        LOG_WARNING("The lock file exists but CreateFile succeeded. Just go on\n");
    }

    info.handle = h;
    info.lock_file = fname;
    LOG_INFO("Locked sdcard: %s\n", fname);
    return true;

}

int remove_sdcard_lock_os(char *sdcard)
{
    /* check whether the sdcard is attached or not */
    if (info.handle == INVALID_HANDLE_VALUE) {
        LOG_INFO("No attached sdcard\n");
        return ERR_NODEV;
    }

    if (memcmp(sdcard, info.lock_file, strlen(sdcard)) != 0) {
        LOG_INFO("%s is already attached\n", info.lock_file);
        return ERR_NOENT;
    }

    /* CloseHandle(info.handle) will remove the lock file */
    LOG_INFO("Unlocked sdcard\n");
    CloseHandle(info.handle);
    info.handle = INVALID_HANDLE_VALUE;
    g_free(info.lock_file);
    info.lock_file = NULL;
    return ERR_SUCCESS;
}

/* Gets the JavaHome path from the windows registry.
   Must call the RegOpenKeyEx by using the following flag.
   For details, "http://stackoverflow.com/questions/10533421/
   accessing-64-bit-registry-from-32-bit-application" */
#define MY_KEY_WOW64_64KEY 0x0100
void get_java_path_win32(const char **java_path)
{
    LONG res;
    HKEY hKey;
    char strKey[PATH_MAX] = {0};
    char strVersion[PATH_MAX] = {0};
    char strJavaHome[PATH_MAX] = {0};
    DWORD dwBufLen = PATH_MAX;
    static char current_java_path[PATH_MAX];

    if (current_java_path[0] != '\0') {
        *java_path = current_java_path;
        return;
    }

    g_strlcpy(strKey, "SOFTWARE\\JavaSoft\\Java Runtime Environment", PATH_MAX);

    /* Opens above key to query the current version */
    res = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
            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;
    }

    /* Queries for the current version */
    res = RegQueryValueEx(hKey,
            "CurrentVersion",
            NULL,
            NULL,
            (LPBYTE)strVersion,
            &dwBufLen);
    RegCloseKey(hKey);
    if (res != ERROR_SUCCESS) {
        LOG_WARNING("JRE CurrentVersion not found\n");
        goto javahome_not_found;
    }

    /* Adds the current version to the key */
    g_strlcat(strKey, "\\", PATH_MAX);
    g_strlcat(strKey, strVersion, PATH_MAX);

    /* Opens above key to query the JavaHome */
    res = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
            strKey,
            0,
            KEY_QUERY_VALUE |
            MY_KEY_WOW64_64KEY,
            &hKey);
    if (res == ERROR_SUCCESS) {
        /* Queries for the JavaHome */
        dwBufLen = PATH_MAX;
        RegQueryValueEx(hKey, "JavaHome", NULL,
                        NULL, (LPBYTE)strJavaHome, &dwBufLen);
    }
    RegCloseKey(hKey);

javahome_not_found:
    if (strJavaHome[0] == '\0') {
        dwBufLen = GetEnvironmentVariable("JAVA_HOME",
                                          strJavaHome,
                                          PATH_MAX);
        if (dwBufLen == 0) {
            LOG_WARNING("There is no JavaHome\n");
            /* try it with "javaw.exe" */
            *java_path = "javaw.exe";
            return;
        }
    }
    g_sprintf(current_java_path, "\"%s\\bin\\javaw.exe\"", strJavaHome);
    LOG_INFO("CurrentVersion JavaHome path: %s\n", current_java_path);

    *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;
}