VirtualBox

source: kBuild/trunk/src/kWorker/kWorker.c@ 2874

Last change on this file since 2874 was 2874, checked in by bird, 8 years ago

Deal with FlSAlloc leak.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 200.0 KB
Line 
1/* $Id: kWorker.c 2874 2016-09-04 19:45:29Z bird $ */
2/** @file
3 * kWorker - experimental process reuse worker for Windows.
4 *
5 * Note! This module must be linked statically in order to avoid
6 * accidentally intercepting our own CRT calls.
7 */
8
9/*
10 * Copyright (c) 2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
11 *
12 * This file is part of kBuild.
13 *
14 * kBuild is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
18 *
19 * kBuild is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with kBuild. If not, see <http://www.gnu.org/licenses/>
26 *
27 */
28
29
30/*********************************************************************************************************************************
31* Header Files *
32*********************************************************************************************************************************/
33#include <k/kHlp.h>
34#include <k/kLdr.h>
35
36#include <stdio.h>
37#include <intrin.h>
38#include <setjmp.h>
39#include <ctype.h>
40
41#include "nt/ntstat.h"
42#include "kbuild_version.h"
43/* lib/nt_fullpath.c */
44extern void nt_fullpath(const char *pszPath, char *pszFull, size_t cchFull);
45
46#include "nt/ntstuff.h"
47
48#include "nt/kFsCache.h"
49#include "quote_argv.h"
50
51
52/*********************************************************************************************************************************
53* Defined Constants And Macros *
54*********************************************************************************************************************************/
55/** String constant comma length. */
56#define TUPLE(a_sz) a_sz, sizeof(a_sz) - 1
57
58/** @def KW_LOG
59 * Generic logging.
60 * @param a Argument list for kwDbgPrintf */
61#ifndef NDEBUG
62# define KW_LOG(a) kwDbgPrintf a
63#else
64# define KW_LOG(a) do { } while (0)
65#endif
66
67
68/** @def KWFS_LOG
69 * FS cache logging.
70 * @param a Argument list for kwDbgPrintf */
71#ifndef NDEBUG
72# define KWFS_LOG(a) kwDbgPrintf a
73#else
74# define KWFS_LOG(a) do { } while (0)
75#endif
76
77/** Converts a windows handle to a handle table index.
78 * @note We currently just mask off the 31th bit, and do no shifting or anything
79 * else to create an index of the handle.
80 * @todo consider shifting by 2 or 3. */
81#define KW_HANDLE_TO_INDEX(a_hHandle) ((KUPTR)(a_hHandle) & ~(KUPTR)KU32_C(0x8000000))
82/** Maximum handle value we can deal with. */
83#define KW_HANDLE_MAX 0x20000
84
85/** @def WITH_TEMP_MEMORY_FILES
86 * Enables temporary memory files for cl.exe. */
87#define WITH_TEMP_MEMORY_FILES
88
89/** Max temporary file size (memory backed). */
90#if K_ARCH_BITS >= 64
91# define KWFS_TEMP_FILE_MAX (256*1024*1024)
92#else
93# define KWFS_TEMP_FILE_MAX (64*1024*1024)
94#endif
95
96/** Marks unfinished code. */
97#if 1
98# define KWFS_TODO() do { kwErrPrintf("\nHit TODO on line %u in %s!\n", __LINE__, __FUNCTION__); __debugbreak(); } while (0)
99#else
100# define KWFS_TODO() do { kwErrPrintf("\nHit TODO on line %u in %s!\n", __LINE__, __FUNCTION__); } while (0)
101#endif
102
103/** User data key for tools. */
104#define KW_DATA_KEY_TOOL (~(KUPTR)16381)
105/** User data key for a cached file. */
106#define KW_DATA_KEY_CACHED_FILE (~(KUPTR)65521)
107
108
109/*********************************************************************************************************************************
110* Structures and Typedefs *
111*********************************************************************************************************************************/
112typedef enum KWLOCATION
113{
114 KWLOCATION_INVALID = 0,
115 KWLOCATION_EXE_DIR,
116 KWLOCATION_IMPORTER_DIR,
117 KWLOCATION_SYSTEM32,
118 KWLOCATION_UNKNOWN_NATIVE,
119 KWLOCATION_UNKNOWN,
120} KWLOCATION;
121
122typedef enum KWMODSTATE
123{
124 KWMODSTATE_INVALID = 0,
125 KWMODSTATE_NEEDS_BITS,
126 KWMODSTATE_NEEDS_INIT,
127 KWMODSTATE_BEING_INITED,
128 KWMODSTATE_INIT_FAILED,
129 KWMODSTATE_READY,
130} KWMODSTATE;
131
132typedef struct KWMODULE *PKWMODULE;
133typedef struct KWMODULE
134{
135 /** Pointer to the next image. */
136 PKWMODULE pNext;
137 /** The normalized path to the image. */
138 const char *pszPath;
139 /** The hash of the program path. */
140 KU32 uHashPath;
141 /** Number of references. */
142 KU32 cRefs;
143 /** UTF-16 version of pszPath. */
144 const wchar_t *pwszPath;
145 /** The offset of the filename in pszPath. */
146 KU16 offFilename;
147 /** Set if executable. */
148 KBOOL fExe;
149 /** Set if native module entry. */
150 KBOOL fNative;
151 /** Loader module handle. */
152 PKLDRMOD pLdrMod;
153 /** The windows module handle. */
154 HMODULE hOurMod;
155
156 union
157 {
158 /** Data for a manually loaded image. */
159 struct
160 {
161 /** The of the loaded image bits. */
162 KSIZE cbImage;
163 /** Where we load the image. */
164 void *pvLoad;
165 /** Virgin copy of the image. */
166 void *pvCopy;
167 /** Ldr pvBits argument. This is NULL till we've successfully resolved
168 * the imports. */
169 void *pvBits;
170 /** The state. */
171 KWMODSTATE enmState;
172#if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_AMD64)
173 /** The number of entries in the table. */
174 KU32 cFunctions;
175 /** The function table address (in the copy). */
176 PRUNTIME_FUNCTION paFunctions;
177 /** Set if we've already registered a function table already. */
178 KBOOL fRegisteredFunctionTable;
179#endif
180 /** Set if we share memory with other executables. */
181 KBOOL fUseLdBuf;
182 /** Number of imported modules. */
183 KSIZE cImpMods;
184 /** Import array (variable size). */
185 PKWMODULE apImpMods[1];
186 } Manual;
187 } u;
188} KWMODULE;
189
190
191typedef struct KWDYNLOAD *PKWDYNLOAD;
192typedef struct KWDYNLOAD
193{
194 /** Pointer to the next in the list. */
195 PKWDYNLOAD pNext;
196
197 /** The normalized path to the image. */
198 const char *pszPath;
199 /** The module name (within pszPath). */
200 const char *pszModName;
201 /** UTF-16 version of pszPath. */
202 const wchar_t *pwszPath;
203 /** The hash of the path. */
204 KU32 uHashPath;
205
206 /** The module handle we present to the application.
207 * This is the LoadLibraryEx return value for special modules and the
208 * KWMODULE.hOurMod value for the others. */
209 HMODULE hmod;
210
211 /** The module for non-special resource stuff, NULL if special. */
212 PKWMODULE pMod;
213} KWDYNLOAD;
214
215
216/**
217 * GetModuleHandle cache for system modules frequently queried.
218 */
219typedef struct KWGETMODULEHANDLECACHE
220{
221 const char *pszName;
222 KU8 cchName;
223 KU8 cwcName;
224 const wchar_t *pwszName;
225 HANDLE hmod;
226} KWGETMODULEHANDLECACHE;
227typedef KWGETMODULEHANDLECACHE *PKWGETMODULEHANDLECACHE;
228
229
230/**
231 * A cached file.
232 */
233typedef struct KFSWCACHEDFILE
234{
235 /** The user data core. */
236 KFSUSERDATA Core;
237
238 /** Cached file handle. */
239 HANDLE hCached;
240 /** The file size. */
241 KU32 cbCached;
242 /** Cached file content. */
243 KU8 *pbCached;
244
245 /** Circular self reference. Prevents the object from ever going away and
246 * keeps it handy for debugging. */
247 PKFSOBJ pFsObj;
248} KFSWCACHEDFILE;
249/** Pointe to a cached filed. */
250typedef KFSWCACHEDFILE *PKFSWCACHEDFILE;
251
252
253typedef struct KWFSTEMPFILESEG *PKWFSTEMPFILESEG;
254typedef struct KWFSTEMPFILESEG
255{
256 /** File offset of data. */
257 KU32 offData;
258 /** The size of the buffer pbData points to. */
259 KU32 cbDataAlloc;
260 /** The segment data. */
261 KU8 *pbData;
262} KWFSTEMPFILESEG;
263
264typedef struct KWFSTEMPFILE *PKWFSTEMPFILE;
265typedef struct KWFSTEMPFILE
266{
267 /** Pointer to the next temporary file for this run. */
268 PKWFSTEMPFILE pNext;
269 /** The UTF-16 path. (Allocated after this structure.) */
270 const wchar_t *pwszPath;
271 /** The path length. */
272 KU16 cwcPath;
273 /** Number of active handles using this file/mapping (<= 2). */
274 KU8 cActiveHandles;
275 /** Number of active mappings (mapped views) (0 or 1). */
276 KU8 cMappings;
277 /** The amount of space allocated in the segments. */
278 KU32 cbFileAllocated;
279 /** The current file size. */
280 KU32 cbFile;
281 /** The number of segments. */
282 KU32 cSegs;
283 /** Segments making up the file. */
284 PKWFSTEMPFILESEG paSegs;
285} KWFSTEMPFILE;
286
287
288/** Handle type. */
289typedef enum KWHANDLETYPE
290{
291 KWHANDLETYPE_INVALID = 0,
292 KWHANDLETYPE_FSOBJ_READ_CACHE,
293 KWHANDLETYPE_TEMP_FILE,
294 KWHANDLETYPE_TEMP_FILE_MAPPING
295 //KWHANDLETYPE_CONSOLE_CACHE
296} KWHANDLETYPE;
297
298/** Handle data. */
299typedef struct KWHANDLE
300{
301 KWHANDLETYPE enmType;
302 /** The current file offset. */
303 KU32 offFile;
304 /** Handle access. */
305 KU32 dwDesiredAccess;
306 /** The handle. */
307 HANDLE hHandle;
308
309 /** Type specific data. */
310 union
311 {
312 /** The file system object. */
313 PKFSWCACHEDFILE pCachedFile;
314 /** Temporary file handle or mapping handle. */
315 PKWFSTEMPFILE pTempFile;
316 } u;
317} KWHANDLE;
318typedef KWHANDLE *PKWHANDLE;
319
320
321/** Pointer to a VirtualAlloc tracker entry. */
322typedef struct KWVIRTALLOC *PKWVIRTALLOC;
323/**
324 * Tracking an VirtualAlloc allocation.
325 */
326typedef struct KWVIRTALLOC
327{
328 PKWVIRTALLOC pNext;
329 void *pvAlloc;
330 KSIZE cbAlloc;
331} KWVIRTALLOC;
332
333
334/** Pointer to a FlsAlloc/TlsAlloc tracker entry. */
335typedef struct KWLOCALSTORAGE *PKWLOCALSTORAGE;
336/**
337 * Tracking an FlsAlloc/TlsAlloc index.
338 */
339typedef struct KWLOCALSTORAGE
340{
341 PKWLOCALSTORAGE pNext;
342 KU32 idx;
343} KWLOCALSTORAGE;
344
345
346typedef enum KWTOOLTYPE
347{
348 KWTOOLTYPE_INVALID = 0,
349 KWTOOLTYPE_SANDBOXED,
350 KWTOOLTYPE_WATCOM,
351 KWTOOLTYPE_EXEC,
352 KWTOOLTYPE_END
353} KWTOOLTYPE;
354
355typedef enum KWTOOLHINT
356{
357 KWTOOLHINT_INVALID = 0,
358 KWTOOLHINT_NONE,
359 KWTOOLHINT_VISUAL_CPP_CL,
360 KWTOOLHINT_END
361} KWTOOLHINT;
362
363
364/**
365 * A kWorker tool.
366 */
367typedef struct KWTOOL
368{
369 /** The user data core structure. */
370 KFSUSERDATA Core;
371
372 /** The normalized path to the program. */
373 const char *pszPath;
374 /** UTF-16 version of pszPath. */
375 wchar_t const *pwszPath;
376 /** The kind of tool. */
377 KWTOOLTYPE enmType;
378
379 union
380 {
381 struct
382 {
383 /** The executable. */
384 PKWMODULE pExe;
385 /** List of dynamically loaded modules.
386 * These will be kept loaded till the tool is destroyed (if we ever do that). */
387 PKWDYNLOAD pDynLoadHead;
388 /** Tool hint (for hacks and such). */
389 KWTOOLHINT enmHint;
390 } Sandboxed;
391 } u;
392} KWTOOL;
393/** Pointer to a tool. */
394typedef struct KWTOOL *PKWTOOL;
395
396
397typedef struct KWSANDBOX *PKWSANDBOX;
398typedef struct KWSANDBOX
399{
400 /** The tool currently running in the sandbox. */
401 PKWTOOL pTool;
402 /** Jump buffer. */
403 jmp_buf JmpBuf;
404 /** The thread ID of the main thread (owner of JmpBuf). */
405 DWORD idMainThread;
406 /** Copy of the NT TIB of the main thread. */
407 NT_TIB TibMainThread;
408 /** The NT_TIB::ExceptionList value inside the try case.
409 * We restore this prior to the longjmp. */
410 void *pOutXcptListHead;
411 /** The exit code in case of longjmp. */
412 int rcExitCode;
413 /** Set if we're running. */
414 KBOOL fRunning;
415
416 /** The command line. */
417 char *pszCmdLine;
418 /** The UTF-16 command line. */
419 wchar_t *pwszCmdLine;
420 /** Number of arguments in papszArgs. */
421 int cArgs;
422 /** The argument vector. */
423 char **papszArgs;
424 /** The argument vector. */
425 wchar_t **papwszArgs;
426
427 /** The _pgmptr msvcrt variable. */
428 char *pgmptr;
429 /** The _wpgmptr msvcrt variable. */
430 wchar_t *wpgmptr;
431
432 /** The _initenv msvcrt variable. */
433 char **initenv;
434 /** The _winitenv msvcrt variable. */
435 wchar_t **winitenv;
436
437 /** The _environ msvcrt variable. */
438 char **environ;
439 /** The _wenviron msvcrt variable. */
440 wchar_t **wenviron;
441
442
443 /** Handle table. */
444 PKWHANDLE *papHandles;
445 /** Size of the handle table. */
446 KU32 cHandles;
447 /** Number of active handles in the table. */
448 KU32 cActiveHandles;
449
450 /** Head of the list of temporary file. */
451 PKWFSTEMPFILE pTempFileHead;
452
453 /** Head of the virtual alloc allocations. */
454 PKWVIRTALLOC pVirtualAllocHead;
455 /** Head of the FlsAlloc indexes. */
456 PKWLOCALSTORAGE pFlsAllocHead;
457 /** Head of the TlsAlloc indexes. */
458 PKWLOCALSTORAGE pTlsAllocHead;
459
460 UNICODE_STRING SavedCommandLine;
461} KWSANDBOX;
462
463/** Replacement function entry. */
464typedef struct KWREPLACEMENTFUNCTION
465{
466 /** The function name. */
467 const char *pszFunction;
468 /** The length of the function name. */
469 KSIZE cchFunction;
470 /** The module name (optional). */
471 const char *pszModule;
472 /** The replacement function or data address. */
473 KUPTR pfnReplacement;
474} KWREPLACEMENTFUNCTION;
475typedef KWREPLACEMENTFUNCTION const *PCKWREPLACEMENTFUNCTION;
476
477#if 0
478/** Replacement function entry. */
479typedef struct KWREPLACEMENTDATA
480{
481 /** The function name. */
482 const char *pszFunction;
483 /** The length of the function name. */
484 KSIZE cchFunction;
485 /** The module name (optional). */
486 const char *pszModule;
487 /** Function providing the replacement. */
488 KUPTR (*pfnMakeReplacement)(PKWMODULE pMod, const char *pchSymbol, KSIZE cchSymbol);
489} KWREPLACEMENTDATA;
490typedef KWREPLACEMENTDATA const *PCKWREPLACEMENTDATA;
491#endif
492
493
494/*********************************************************************************************************************************
495* Global Variables *
496*********************************************************************************************************************************/
497/** The sandbox data. */
498static KWSANDBOX g_Sandbox;
499
500/** The module currently occupying g_abDefLdBuf. */
501static PKWMODULE g_pModInLdBuf = NULL;
502
503/** Module hash table. */
504static PKWMODULE g_apModules[127];
505
506/** GetModuleHandle cache. */
507static KWGETMODULEHANDLECACHE g_aGetModuleHandleCache[] =
508{
509#define MOD_CACHE_STRINGS(str) str, sizeof(str) - 1, (sizeof(L##str) / sizeof(wchar_t)) - 1, L##str
510 { MOD_CACHE_STRINGS("KERNEL32.DLL"), NULL },
511 { MOD_CACHE_STRINGS("mscoree.dll"), NULL },
512};
513
514
515/** The file system cache. */
516static PKFSCACHE g_pFsCache;
517/** The current directory (referenced). */
518static PKFSOBJ g_pCurDirObj = NULL;
519
520/** Verbosity level. */
521static int g_cVerbose = 2;
522
523/** Whether we should restart the worker. */
524static KBOOL g_fRestart = K_FALSE;
525
526/* Further down. */
527extern KWREPLACEMENTFUNCTION const g_aSandboxReplacements[];
528extern KU32 const g_cSandboxReplacements;
529
530extern KWREPLACEMENTFUNCTION const g_aSandboxNativeReplacements[];
531extern KU32 const g_cSandboxNativeReplacements;
532
533/** Create a larget BSS blob that with help of /IMAGEBASE:0x10000 should
534 * cover the default executable link address of 0x400000. */
535#pragma section("DefLdBuf", write, execute, read)
536__declspec(allocate("DefLdBuf"))
537static KU8 g_abDefLdBuf[16*1024*1024];
538
539
540
541/*********************************************************************************************************************************
542* Internal Functions *
543*********************************************************************************************************************************/
544static FNKLDRMODGETIMPORT kwLdrModuleGetImportCallback;
545static int kwLdrModuleResolveAndLookup(const char *pszName, PKWMODULE pExe, PKWMODULE pImporter, PKWMODULE *ppMod);
546static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle);
547
548
549
550/**
551 * Debug printing.
552 * @param pszFormat Debug format string.
553 * @param ... Format argument.
554 */
555static void kwDbgPrintfV(const char *pszFormat, va_list va)
556{
557 if (g_cVerbose >= 2)
558 {
559 DWORD const dwSavedErr = GetLastError();
560
561 fprintf(stderr, "debug: ");
562 vfprintf(stderr, pszFormat, va);
563
564 SetLastError(dwSavedErr);
565 }
566}
567
568
569/**
570 * Debug printing.
571 * @param pszFormat Debug format string.
572 * @param ... Format argument.
573 */
574static void kwDbgPrintf(const char *pszFormat, ...)
575{
576 if (g_cVerbose >= 2)
577 {
578 va_list va;
579 va_start(va, pszFormat);
580 kwDbgPrintfV(pszFormat, va);
581 va_end(va);
582 }
583}
584
585
586/**
587 * Debugger printing.
588 * @param pszFormat Debug format string.
589 * @param ... Format argument.
590 */
591static void kwDebuggerPrintfV(const char *pszFormat, va_list va)
592{
593 if (IsDebuggerPresent())
594 {
595 DWORD const dwSavedErr = GetLastError();
596 char szTmp[2048];
597
598 _vsnprintf(szTmp, sizeof(szTmp), pszFormat, va);
599 OutputDebugStringA(szTmp);
600
601 SetLastError(dwSavedErr);
602 }
603}
604
605
606/**
607 * Debugger printing.
608 * @param pszFormat Debug format string.
609 * @param ... Format argument.
610 */
611static void kwDebuggerPrintf(const char *pszFormat, ...)
612{
613 va_list va;
614 va_start(va, pszFormat);
615 kwDebuggerPrintfV(pszFormat, va);
616 va_end(va);
617}
618
619
620
621/**
622 * Error printing.
623 * @param pszFormat Message format string.
624 * @param ... Format argument.
625 */
626static void kwErrPrintfV(const char *pszFormat, va_list va)
627{
628 DWORD const dwSavedErr = GetLastError();
629
630 fprintf(stderr, "kWorker: error: ");
631 vfprintf(stderr, pszFormat, va);
632
633 SetLastError(dwSavedErr);
634}
635
636
637/**
638 * Error printing.
639 * @param pszFormat Message format string.
640 * @param ... Format argument.
641 */
642static void kwErrPrintf(const char *pszFormat, ...)
643{
644 va_list va;
645 va_start(va, pszFormat);
646 kwErrPrintfV(pszFormat, va);
647 va_end(va);
648}
649
650
651/**
652 * Error printing.
653 * @return rc;
654 * @param rc Return value
655 * @param pszFormat Message format string.
656 * @param ... Format argument.
657 */
658static int kwErrPrintfRc(int rc, const char *pszFormat, ...)
659{
660 va_list va;
661 va_start(va, pszFormat);
662 kwErrPrintfV(pszFormat, va);
663 va_end(va);
664 return rc;
665}
666
667
668#ifdef K_STRICT
669
670KHLP_DECL(void) kHlpAssertMsg1(const char *pszExpr, const char *pszFile, unsigned iLine, const char *pszFunction)
671{
672 DWORD const dwSavedErr = GetLastError();
673
674 fprintf(stderr,
675 "\n"
676 "!!Assertion failed!!\n"
677 "Expression: %s\n"
678 "Function : %s\n"
679 "File: %s\n"
680 "Line: %d\n"
681 , pszExpr, pszFunction, pszFile, iLine);
682
683 SetLastError(dwSavedErr);
684}
685
686
687KHLP_DECL(void) kHlpAssertMsg2(const char *pszFormat, ...)
688{
689 DWORD const dwSavedErr = GetLastError();
690 va_list va;
691
692 va_start(va, pszFormat);
693 fprintf(stderr, pszFormat, va);
694 va_end(va);
695
696 SetLastError(dwSavedErr);
697}
698
699#endif /* K_STRICT */
700
701
702/**
703 * Hashes a string.
704 *
705 * @returns 32-bit string hash.
706 * @param pszString String to hash.
707 */
708static KU32 kwStrHash(const char *pszString)
709{
710 /* This algorithm was created for sdbm (a public-domain reimplementation of
711 ndbm) database library. it was found to do well in scrambling bits,
712 causing better distribution of the keys and fewer splits. it also happens
713 to be a good general hashing function with good distribution. the actual
714 function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
715 is the faster version used in gawk. [there is even a faster, duff-device
716 version] the magic constant 65599 was picked out of thin air while
717 experimenting with different constants, and turns out to be a prime.
718 this is one of the algorithms used in berkeley db (see sleepycat) and
719 elsewhere. */
720 KU32 uHash = 0;
721 KU32 uChar;
722 while ((uChar = (unsigned char)*pszString++) != 0)
723 uHash = uChar + (uHash << 6) + (uHash << 16) - uHash;
724 return uHash;
725}
726
727
728/**
729 * Hashes a string.
730 *
731 * @returns The string length.
732 * @param pszString String to hash.
733 * @param puHash Where to return the 32-bit string hash.
734 */
735static KSIZE kwStrHashEx(const char *pszString, KU32 *puHash)
736{
737 const char * const pszStart = pszString;
738 KU32 uHash = 0;
739 KU32 uChar;
740 while ((uChar = (unsigned char)*pszString) != 0)
741 {
742 uHash = uChar + (uHash << 6) + (uHash << 16) - uHash;
743 pszString++;
744 }
745 *puHash = uHash;
746 return pszString - pszStart;
747}
748
749
750/**
751 * Hashes a string.
752 *
753 * @returns The string length in wchar_t units.
754 * @param pwszString String to hash.
755 * @param puHash Where to return the 32-bit string hash.
756 */
757static KSIZE kwUtf16HashEx(const wchar_t *pwszString, KU32 *puHash)
758{
759 const wchar_t * const pwszStart = pwszString;
760 KU32 uHash = 0;
761 KU32 uChar;
762 while ((uChar = *pwszString) != 0)
763 {
764 uHash = uChar + (uHash << 6) + (uHash << 16) - uHash;
765 pwszString++;
766 }
767 *puHash = uHash;
768 return pwszString - pwszStart;
769}
770
771
772/**
773 * Converts the given string to unicode.
774 *
775 * @returns Length of the resulting string in wchar_t's.
776 * @param pszSrc The source string.
777 * @param pwszDst The destination buffer.
778 * @param cwcDst The size of the destination buffer in wchar_t's.
779 */
780static KSIZE kwStrToUtf16(const char *pszSrc, wchar_t *pwszDst, KSIZE cwcDst)
781{
782 /* Just to the quick ASCII stuff for now. correct ansi code page stuff later some time. */
783 KSIZE offDst = 0;
784 while (offDst < cwcDst)
785 {
786 char ch = *pszSrc++;
787 pwszDst[offDst++] = ch;
788 if (!ch)
789 return offDst - 1;
790 kHlpAssert((unsigned)ch < 127);
791 }
792
793 pwszDst[offDst - 1] = '\0';
794 return offDst;
795}
796
797
798/**
799 * Converts the given UTF-16 to a normal string.
800 *
801 * @returns Length of the resulting string.
802 * @param pwszSrc The source UTF-16 string.
803 * @param pszDst The destination buffer.
804 * @param cbDst The size of the destination buffer in bytes.
805 */
806static KSIZE kwUtf16ToStr(const wchar_t *pwszSrc, char *pszDst, KSIZE cbDst)
807{
808 /* Just to the quick ASCII stuff for now. correct ansi code page stuff later some time. */
809 KSIZE offDst = 0;
810 while (offDst < cbDst)
811 {
812 wchar_t wc = *pwszSrc++;
813 pszDst[offDst++] = (char)wc;
814 if (!wc)
815 return offDst - 1;
816 kHlpAssert((unsigned)wc < 127);
817 }
818
819 pszDst[offDst - 1] = '\0';
820 return offDst;
821}
822
823
824
825/** UTF-16 string length. */
826static KSIZE kwUtf16Len(wchar_t const *pwsz)
827{
828 KSIZE cwc = 0;
829 while (*pwsz != '\0')
830 cwc++, pwsz++;
831 return cwc;
832}
833
834/**
835 * Copy out the UTF-16 string following the convension of GetModuleFileName
836 */
837static DWORD kwUtf16CopyStyle1(wchar_t const *pwszSrc, wchar_t *pwszDst, KSIZE cwcDst)
838{
839 KSIZE cwcSrc = kwUtf16Len(pwszSrc);
840 if (cwcSrc + 1 <= cwcDst)
841 {
842 kHlpMemCopy(pwszDst, pwszSrc, (cwcSrc + 1) * sizeof(wchar_t));
843 return (DWORD)cwcSrc;
844 }
845 if (cwcDst > 0)
846 {
847 KSIZE cwcDstTmp = cwcDst - 1;
848 pwszDst[cwcDstTmp] = '\0';
849 if (cwcDstTmp > 0)
850 kHlpMemCopy(pwszDst, pwszSrc, cwcDstTmp);
851 }
852 SetLastError(ERROR_INSUFFICIENT_BUFFER);
853 return (DWORD)cwcDst;
854}
855
856
857/**
858 * Copy out the ANSI string following the convension of GetModuleFileName
859 */
860static DWORD kwStrCopyStyle1(char const *pszSrc, char *pszDst, KSIZE cbDst)
861{
862 KSIZE cchSrc = kHlpStrLen(pszSrc);
863 if (cchSrc + 1 <= cbDst)
864 {
865 kHlpMemCopy(pszDst, pszSrc, cchSrc + 1);
866 return (DWORD)cchSrc;
867 }
868 if (cbDst > 0)
869 {
870 KSIZE cbDstTmp = cbDst - 1;
871 pszDst[cbDstTmp] = '\0';
872 if (cbDstTmp > 0)
873 kHlpMemCopy(pszDst, pszSrc, cbDstTmp);
874 }
875 SetLastError(ERROR_INSUFFICIENT_BUFFER);
876 return (DWORD)cbDst;
877}
878
879
880/**
881 * Normalizes the path so we get a consistent hash.
882 *
883 * @returns status code.
884 * @param pszPath The path.
885 * @param pszNormPath The output buffer.
886 * @param cbNormPath The size of the output buffer.
887 */
888static int kwPathNormalize(const char *pszPath, char *pszNormPath, KSIZE cbNormPath)
889{
890 KFSLOOKUPERROR enmError;
891 PKFSOBJ pFsObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError);
892 if (pFsObj)
893 {
894 KBOOL fRc;
895 fRc = kFsCacheObjGetFullPathA(pFsObj, pszNormPath, cbNormPath, '\\');
896 kFsCacheObjRelease(g_pFsCache, pFsObj);
897 if (fRc)
898 return 0;
899 return KERR_BUFFER_OVERFLOW;
900 }
901 return KERR_FILE_NOT_FOUND;
902}
903
904
905/**
906 * Get the pointer to the filename part of the path.
907 *
908 * @returns Pointer to where the filename starts within the string pointed to by pszFilename.
909 * @returns Pointer to the terminator char if no filename.
910 * @param pszPath The path to parse.
911 */
912static wchar_t *kwPathGetFilenameW(const wchar_t *pwszPath)
913{
914 const wchar_t *pwszLast = NULL;
915 for (;;)
916 {
917 wchar_t wc = *pwszPath;
918#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS
919 if (wc == '/' || wc == '\\' || wc == ':')
920 {
921 while ((wc = *++pwszPath) == '/' || wc == '\\' || wc == ':')
922 /* nothing */;
923 pwszLast = pwszPath;
924 }
925#else
926 if (wc == '/')
927 {
928 while ((wc = *++pszFilename) == '/')
929 /* betsuni */;
930 pwszLast = pwszPath;
931 }
932#endif
933 if (!wc)
934 return (wchar_t *)(pwszLast ? pwszLast : pwszPath);
935 pwszPath++;
936 }
937}
938
939
940
941/**
942 * Retains a new reference to the given module
943 * @returns pMod
944 * @param pMod The module to retain.
945 */
946static PKWMODULE kwLdrModuleRetain(PKWMODULE pMod)
947{
948 kHlpAssert(pMod->cRefs > 0);
949 kHlpAssert(pMod->cRefs < 64);
950 pMod->cRefs++;
951 return pMod;
952}
953
954
955/**
956 * Releases a module reference.
957 *
958 * @param pMod The module to release.
959 */
960static void kwLdrModuleRelease(PKWMODULE pMod)
961{
962 if (--pMod->cRefs == 0)
963 {
964 /* Unlink it. */
965 if (!pMod->fExe)
966 {
967 PKWMODULE pPrev = NULL;
968 unsigned idx = pMod->uHashPath % K_ELEMENTS(g_apModules);
969 if (g_apModules[idx] == pMod)
970 g_apModules[idx] = pMod->pNext;
971 else
972 {
973 PKWMODULE pPrev = g_apModules[idx];
974 kHlpAssert(pPrev != NULL);
975 while (pPrev->pNext != pMod)
976 {
977 pPrev = pPrev->pNext;
978 kHlpAssert(pPrev != NULL);
979 }
980 pPrev->pNext = pMod->pNext;
981 }
982 }
983
984 /* Release import modules. */
985 if (!pMod->fNative)
986 {
987 KSIZE idx = pMod->u.Manual.cImpMods;
988 while (idx-- > 0)
989 if (pMod->u.Manual.apImpMods[idx])
990 {
991 kwLdrModuleRelease(pMod->u.Manual.apImpMods[idx]);
992 pMod->u.Manual.apImpMods[idx] = NULL;
993 }
994 }
995
996 /* Free our resources. */
997 kLdrModClose(pMod->pLdrMod);
998 pMod->pLdrMod = NULL;
999
1000 if (!pMod->fNative)
1001 {
1002 kHlpPageFree(pMod->u.Manual.pvCopy, pMod->u.Manual.cbImage);
1003 kHlpPageFree(pMod->u.Manual.pvLoad, pMod->u.Manual.cbImage);
1004 }
1005
1006 kHlpFree(pMod);
1007 }
1008 else
1009 kHlpAssert(pMod->cRefs < 64);
1010}
1011
1012
1013/**
1014 * Links the module into the module hash table.
1015 *
1016 * @returns pMod
1017 * @param pMod The module to link.
1018 */
1019static PKWMODULE kwLdrModuleLink(PKWMODULE pMod)
1020{
1021 unsigned idx = pMod->uHashPath % K_ELEMENTS(g_apModules);
1022 pMod->pNext = g_apModules[idx];
1023 g_apModules[idx] = pMod;
1024 return pMod;
1025}
1026
1027
1028/**
1029 * Replaces imports for this module according to g_aSandboxNativeReplacements.
1030 *
1031 * @param pMod The natively loaded module to process.
1032 */
1033static void kwLdrModuleDoNativeImportReplacements(PKWMODULE pMod)
1034{
1035 KSIZE const cbImage = (KSIZE)kLdrModSize(pMod->pLdrMod);
1036 KU8 const * const pbImage = (KU8 const *)pMod->hOurMod;
1037 IMAGE_DOS_HEADER const *pMzHdr = (IMAGE_DOS_HEADER const *)pbImage;
1038 IMAGE_NT_HEADERS const *pNtHdrs;
1039 IMAGE_DATA_DIRECTORY const *pDirEnt;
1040
1041 kHlpAssert(pMod->fNative);
1042
1043 /*
1044 * Locate the export descriptors.
1045 */
1046 /* MZ header. */
1047 if (pMzHdr->e_magic == IMAGE_DOS_SIGNATURE)
1048 {
1049 kHlpAssertReturnVoid((KU32)pMzHdr->e_lfanew <= cbImage - sizeof(*pNtHdrs));
1050 pNtHdrs = (IMAGE_NT_HEADERS const *)&pbImage[pMzHdr->e_lfanew];
1051 }
1052 else
1053 pNtHdrs = (IMAGE_NT_HEADERS const *)pbImage;
1054
1055 /* Check PE header. */
1056 kHlpAssertReturnVoid(pNtHdrs->Signature == IMAGE_NT_SIGNATURE);
1057 kHlpAssertReturnVoid(pNtHdrs->FileHeader.SizeOfOptionalHeader == sizeof(pNtHdrs->OptionalHeader));
1058
1059 /* Locate the import descriptor array. */
1060 pDirEnt = (IMAGE_DATA_DIRECTORY const *)&pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
1061 if ( pDirEnt->Size > 0
1062 && pDirEnt->VirtualAddress != 0)
1063 {
1064 const IMAGE_IMPORT_DESCRIPTOR *pImpDesc = (const IMAGE_IMPORT_DESCRIPTOR *)&pbImage[pDirEnt->VirtualAddress];
1065 KU32 cLeft = pDirEnt->Size / sizeof(*pImpDesc);
1066 MEMORY_BASIC_INFORMATION ProtInfo = { NULL, NULL, 0, 0, 0, 0, 0 };
1067 KU8 *pbProtRange = NULL;
1068 SIZE_T cbProtRange = 0;
1069 DWORD fOldProt = 0;
1070 KU32 const cbPage = 0x1000;
1071 BOOL fRc;
1072
1073
1074 kHlpAssertReturnVoid(pDirEnt->VirtualAddress < cbImage);
1075 kHlpAssertReturnVoid(pDirEnt->Size < cbImage);
1076 kHlpAssertReturnVoid(pDirEnt->VirtualAddress + pDirEnt->Size <= cbImage);
1077
1078 /*
1079 * Walk the import descriptor array.
1080 * Note! This only works if there's a backup thunk array, otherwise we cannot get at the name.
1081 */
1082 while ( cLeft-- > 0
1083 && pImpDesc->Name > 0
1084 && pImpDesc->FirstThunk > 0)
1085 {
1086 KU32 iThunk;
1087 const char * const pszImport = (const char *)&pbImage[pImpDesc->Name];
1088 PIMAGE_THUNK_DATA paThunks = (PIMAGE_THUNK_DATA)&pbImage[pImpDesc->FirstThunk];
1089 PIMAGE_THUNK_DATA paOrgThunks = (PIMAGE_THUNK_DATA)&pbImage[pImpDesc->OriginalFirstThunk];
1090 kHlpAssertReturnVoid(pImpDesc->Name < cbImage);
1091 kHlpAssertReturnVoid(pImpDesc->FirstThunk < cbImage);
1092 kHlpAssertReturnVoid(pImpDesc->OriginalFirstThunk < cbImage);
1093 kHlpAssertReturnVoid(pImpDesc->OriginalFirstThunk != pImpDesc->FirstThunk);
1094 kHlpAssertReturnVoid(pImpDesc->OriginalFirstThunk);
1095
1096 /* Iterate the thunks. */
1097 for (iThunk = 0; paOrgThunks[iThunk].u1.Ordinal != 0; iThunk++)
1098 {
1099 KUPTR const off = paOrgThunks[iThunk].u1.Function;
1100 kHlpAssertReturnVoid(off < cbImage);
1101 if (!IMAGE_SNAP_BY_ORDINAL(off))
1102 {
1103 IMAGE_IMPORT_BY_NAME const *pName = (IMAGE_IMPORT_BY_NAME const *)&pbImage[off];
1104 KSIZE const cchSymbol = kHlpStrLen(pName->Name);
1105 KU32 i = g_cSandboxNativeReplacements;
1106 while (i-- > 0)
1107 if ( g_aSandboxNativeReplacements[i].cchFunction == cchSymbol
1108 && kHlpMemComp(g_aSandboxNativeReplacements[i].pszFunction, pName->Name, cchSymbol) == 0)
1109 {
1110 if ( !g_aSandboxNativeReplacements[i].pszModule
1111 || kHlpStrICompAscii(g_aSandboxNativeReplacements[i].pszModule, pszImport) == 0)
1112 {
1113 KW_LOG(("%s: replacing %s!%s\n", pMod->pLdrMod->pszName, pszImport, pName->Name));
1114
1115 /* The .rdata section is normally read-only, so we need to make it writable first. */
1116 if ((KUPTR)&paThunks[iThunk] - (KUPTR)pbProtRange >= cbPage)
1117 {
1118 /* Restore previous .rdata page. */
1119 if (fOldProt)
1120 {
1121 fRc = VirtualProtect(pbProtRange, cbProtRange, fOldProt, NULL /*pfOldProt*/);
1122 kHlpAssert(fRc);
1123 fOldProt = 0;
1124 }
1125
1126 /* Query attributes for the current .rdata page. */
1127 pbProtRange = (KU8 *)((KUPTR)&paThunks[iThunk] & ~(KUPTR)(cbPage - 1));
1128 cbProtRange = VirtualQuery(pbProtRange, &ProtInfo, sizeof(ProtInfo));
1129 kHlpAssert(cbProtRange);
1130 if (cbProtRange)
1131 {
1132 switch (ProtInfo.Protect)
1133 {
1134 case PAGE_READWRITE:
1135 case PAGE_WRITECOPY:
1136 case PAGE_EXECUTE_READWRITE:
1137 case PAGE_EXECUTE_WRITECOPY:
1138 /* Already writable, nothing to do. */
1139 break;
1140
1141 default:
1142 kHlpAssertMsgFailed(("%#x\n", ProtInfo.Protect));
1143 case PAGE_READONLY:
1144 cbProtRange = cbPage;
1145 fRc = VirtualProtect(pbProtRange, cbProtRange, PAGE_READWRITE, &fOldProt);
1146 break;
1147
1148 case PAGE_EXECUTE:
1149 case PAGE_EXECUTE_READ:
1150 cbProtRange = cbPage;
1151 fRc = VirtualProtect(pbProtRange, cbProtRange, PAGE_EXECUTE_READWRITE, &fOldProt);
1152 break;
1153 }
1154 kHlpAssertStmt(fRc, fOldProt = 0);
1155 }
1156 }
1157
1158 paThunks[iThunk].u1.AddressOfData = g_aSandboxNativeReplacements[i].pfnReplacement;
1159 break;
1160 }
1161 }
1162 }
1163 }
1164
1165
1166 /* Next import descriptor. */
1167 pImpDesc++;
1168 }
1169
1170
1171 if (fOldProt)
1172 {
1173 DWORD fIgnore = 0;
1174 fRc = VirtualProtect(pbProtRange, cbProtRange, fOldProt, &fIgnore);
1175 kHlpAssertMsg(fRc, ("%u\n", GetLastError())); K_NOREF(fRc);
1176 }
1177 }
1178
1179}
1180
1181
1182/**
1183 * Creates a module from a native kLdr module handle.
1184 *
1185 * @returns Module w/ 1 reference on success, NULL on failure.
1186 * @param pLdrMod The native kLdr module.
1187 * @param pszPath The normalized path to the module.
1188 * @param cbPath The module path length with terminator.
1189 * @param uHashPath The module path hash.
1190 * @param fDoReplacements Whether to do import replacements on this
1191 * module.
1192 */
1193static PKWMODULE kwLdrModuleCreateForNativekLdrModule(PKLDRMOD pLdrMod, const char *pszPath, KSIZE cbPath, KU32 uHashPath,
1194 KBOOL fDoReplacements)
1195{
1196 /*
1197 * Create the entry.
1198 */
1199 PKWMODULE pMod = (PKWMODULE)kHlpAllocZ(sizeof(*pMod) + cbPath + cbPath * 2 * sizeof(wchar_t));
1200 if (pMod)
1201 {
1202 pMod->pwszPath = (wchar_t *)(pMod + 1);
1203 kwStrToUtf16(pszPath, (wchar_t *)pMod->pwszPath, cbPath * 2);
1204 pMod->pszPath = (char *)kHlpMemCopy((char *)&pMod->pwszPath[cbPath * 2], pszPath, cbPath);
1205 pMod->uHashPath = uHashPath;
1206 pMod->cRefs = 1;
1207 pMod->offFilename = (KU16)(kHlpGetFilename(pszPath) - pszPath);
1208 pMod->fExe = K_FALSE;
1209 pMod->fNative = K_TRUE;
1210 pMod->pLdrMod = pLdrMod;
1211 pMod->hOurMod = (HMODULE)(KUPTR)pLdrMod->aSegments[0].MapAddress;
1212
1213 if (fDoReplacements)
1214 {
1215 DWORD const dwSavedErr = GetLastError();
1216 kwLdrModuleDoNativeImportReplacements(pMod);
1217 SetLastError(dwSavedErr);
1218 }
1219
1220 KW_LOG(("New module: %p LB %#010x %s (native)\n",
1221 (KUPTR)pMod->pLdrMod->aSegments[0].MapAddress, kLdrModSize(pMod->pLdrMod), pMod->pszPath));
1222 return kwLdrModuleLink(pMod);
1223 }
1224 return NULL;
1225}
1226
1227
1228
1229/**
1230 * Creates a module using the native loader.
1231 *
1232 * @returns Module w/ 1 reference on success, NULL on failure.
1233 * @param pszPath The normalized path to the module.
1234 * @param uHashPath The module path hash.
1235 * @param fDoReplacements Whether to do import replacements on this
1236 * module.
1237 */
1238static PKWMODULE kwLdrModuleCreateNative(const char *pszPath, KU32 uHashPath, KBOOL fDoReplacements)
1239{
1240 /*
1241 * Open the module and check the type.
1242 */
1243 PKLDRMOD pLdrMod;
1244 int rc = kLdrModOpenNative(pszPath, &pLdrMod);
1245 if (rc == 0)
1246 {
1247 PKWMODULE pMod = kwLdrModuleCreateForNativekLdrModule(pLdrMod, pszPath, kHlpStrLen(pszPath) + 1,
1248 uHashPath, fDoReplacements);
1249 if (pMod)
1250 return pMod;
1251 kLdrModClose(pLdrMod);
1252 }
1253 return NULL;
1254}
1255
1256
1257/**
1258 * Creates a module using the our own loader.
1259 *
1260 * @returns Module w/ 1 reference on success, NULL on failure.
1261 * @param pszPath The normalized path to the module.
1262 * @param uHashPath The module path hash.
1263 * @param fExe K_TRUE if this is an executable image, K_FALSE
1264 * if not. Executable images does not get entered
1265 * into the global module table.
1266 * @param pExeMod The executable module of the process (for
1267 * resolving imports). NULL if fExe is set.
1268 */
1269static PKWMODULE kwLdrModuleCreateNonNative(const char *pszPath, KU32 uHashPath, KBOOL fExe, PKWMODULE pExeMod)
1270{
1271 /*
1272 * Open the module and check the type.
1273 */
1274 PKLDRMOD pLdrMod;
1275 int rc = kLdrModOpen(pszPath, 0 /*fFlags*/, (KCPUARCH)K_ARCH, &pLdrMod);
1276 if (rc == 0)
1277 {
1278 switch (pLdrMod->enmType)
1279 {
1280 case KLDRTYPE_EXECUTABLE_FIXED:
1281 case KLDRTYPE_EXECUTABLE_RELOCATABLE:
1282 case KLDRTYPE_EXECUTABLE_PIC:
1283 if (!fExe)
1284 rc = KERR_GENERAL_FAILURE;
1285 break;
1286
1287 case KLDRTYPE_SHARED_LIBRARY_RELOCATABLE:
1288 case KLDRTYPE_SHARED_LIBRARY_PIC:
1289 case KLDRTYPE_SHARED_LIBRARY_FIXED:
1290 if (fExe)
1291 rc = KERR_GENERAL_FAILURE;
1292 break;
1293
1294 default:
1295 rc = KERR_GENERAL_FAILURE;
1296 break;
1297 }
1298 if (rc == 0)
1299 {
1300 KI32 cImports = kLdrModNumberOfImports(pLdrMod, NULL /*pvBits*/);
1301 if (cImports >= 0)
1302 {
1303 /*
1304 * Create the entry.
1305 */
1306 KSIZE cbPath = kHlpStrLen(pszPath) + 1;
1307 PKWMODULE pMod = (PKWMODULE)kHlpAllocZ(sizeof(*pMod)
1308 + sizeof(pMod) * cImports
1309 + cbPath
1310 + cbPath * 2 * sizeof(wchar_t));
1311 if (pMod)
1312 {
1313 KBOOL fFixed;
1314
1315 pMod->cRefs = 1;
1316 pMod->offFilename = (KU16)(kHlpGetFilename(pszPath) - pszPath);
1317 pMod->uHashPath = uHashPath;
1318 pMod->fExe = fExe;
1319 pMod->fNative = K_FALSE;
1320 pMod->pLdrMod = pLdrMod;
1321 pMod->u.Manual.cImpMods = (KU32)cImports;
1322 pMod->u.Manual.fUseLdBuf = K_FALSE;
1323#if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_AMD64)
1324 pMod->u.Manual.fRegisteredFunctionTable = K_FALSE;
1325#endif
1326 pMod->pszPath = (char *)kHlpMemCopy(&pMod->u.Manual.apImpMods[cImports + 1], pszPath, cbPath);
1327 pMod->pwszPath = (wchar_t *)(pMod->pszPath + cbPath + (cbPath & 1));
1328 kwStrToUtf16(pMod->pszPath, (wchar_t *)pMod->pwszPath, cbPath * 2);
1329
1330 /*
1331 * Figure out where to load it and get memory there.
1332 */
1333 fFixed = pLdrMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
1334 || pLdrMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED;
1335 pMod->u.Manual.pvLoad = fFixed ? (void *)(KUPTR)pLdrMod->aSegments[0].LinkAddress : NULL;
1336 pMod->u.Manual.cbImage = (KSIZE)kLdrModSize(pLdrMod);
1337 if ( !fFixed
1338 || pLdrMod->enmType != KLDRTYPE_EXECUTABLE_FIXED /* only allow fixed executables */
1339 || (KUPTR)pMod->u.Manual.pvLoad - (KUPTR)g_abDefLdBuf >= sizeof(g_abDefLdBuf)
1340 || sizeof(g_abDefLdBuf) - (KUPTR)pMod->u.Manual.pvLoad - (KUPTR)g_abDefLdBuf < pMod->u.Manual.cbImage)
1341 rc = kHlpPageAlloc(&pMod->u.Manual.pvLoad, pMod->u.Manual.cbImage, KPROT_EXECUTE_READWRITE, fFixed);
1342 else
1343 pMod->u.Manual.fUseLdBuf = K_TRUE;
1344 if (rc == 0)
1345 {
1346 rc = kHlpPageAlloc(&pMod->u.Manual.pvCopy, pMod->u.Manual.cbImage, KPROT_READWRITE, K_FALSE);
1347 if (rc == 0)
1348 {
1349
1350 KI32 iImp;
1351
1352 /*
1353 * Link the module (unless it's an executable image) and process the imports.
1354 */
1355 pMod->hOurMod = (HMODULE)pMod->u.Manual.pvLoad;
1356 if (!fExe)
1357 kwLdrModuleLink(pMod);
1358 KW_LOG(("New module: %p LB %#010x %s (kLdr)\n",
1359 pMod->u.Manual.pvLoad, pMod->u.Manual.cbImage, pMod->pszPath));
1360 kwDebuggerPrintf("TODO: .reload /f %s=%p\n", pMod->pszPath, pMod->u.Manual.pvLoad);
1361
1362 for (iImp = 0; iImp < cImports; iImp++)
1363 {
1364 char szName[1024];
1365 rc = kLdrModGetImport(pMod->pLdrMod, NULL /*pvBits*/, iImp, szName, sizeof(szName));
1366 if (rc == 0)
1367 {
1368 rc = kwLdrModuleResolveAndLookup(szName, pExeMod, pMod, &pMod->u.Manual.apImpMods[iImp]);
1369 if (rc == 0)
1370 continue;
1371 }
1372 break;
1373 }
1374
1375 if (rc == 0)
1376 {
1377 rc = kLdrModGetBits(pLdrMod, pMod->u.Manual.pvCopy, (KUPTR)pMod->u.Manual.pvLoad,
1378 kwLdrModuleGetImportCallback, pMod);
1379 if (rc == 0)
1380 {
1381#if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_AMD64)
1382 /*
1383 * Find the function table. No validation here because the
1384 * loader did that already, right...
1385 */
1386 KU8 *pbImg = (KU8 *)pMod->u.Manual.pvCopy;
1387 IMAGE_NT_HEADERS const *pNtHdrs;
1388 IMAGE_DATA_DIRECTORY const *pXcptDir;
1389 if (((PIMAGE_DOS_HEADER)pbImg)->e_magic == IMAGE_DOS_SIGNATURE)
1390 pNtHdrs = (PIMAGE_NT_HEADERS)&pbImg[((PIMAGE_DOS_HEADER)pbImg)->e_lfanew];
1391 else
1392 pNtHdrs = (PIMAGE_NT_HEADERS)pbImg;
1393 pXcptDir = &pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION];
1394 kHlpAssert(pNtHdrs->Signature == IMAGE_NT_SIGNATURE);
1395 if (pXcptDir->Size > 0)
1396 {
1397 pMod->u.Manual.cFunctions = pXcptDir->Size / sizeof(pMod->u.Manual.paFunctions[0]);
1398 kHlpAssert( pMod->u.Manual.cFunctions * sizeof(pMod->u.Manual.paFunctions[0])
1399 == pXcptDir->Size);
1400 pMod->u.Manual.paFunctions = (PRUNTIME_FUNCTION)&pbImg[pXcptDir->VirtualAddress];
1401 }
1402 else
1403 {
1404 pMod->u.Manual.cFunctions = 0;
1405 pMod->u.Manual.paFunctions = NULL;
1406 }
1407#endif
1408
1409 /*
1410 * Final finish.
1411 */
1412 pMod->u.Manual.pvBits = pMod->u.Manual.pvCopy;
1413 pMod->u.Manual.enmState = KWMODSTATE_NEEDS_BITS;
1414 return pMod;
1415 }
1416 }
1417
1418 kwLdrModuleRelease(pMod);
1419 return NULL;
1420 }
1421
1422 kHlpPageFree(pMod->u.Manual.pvLoad, pMod->u.Manual.cbImage);
1423 kwErrPrintf("Failed to allocate %#x bytes\n", pMod->u.Manual.cbImage);
1424 }
1425 else if (fFixed)
1426 kwErrPrintf("Failed to allocate %#x bytes at %p\n",
1427 pMod->u.Manual.cbImage, (void *)(KUPTR)pLdrMod->aSegments[0].LinkAddress);
1428 else
1429 kwErrPrintf("Failed to allocate %#x bytes\n", pMod->u.Manual.cbImage);
1430 }
1431 }
1432 }
1433 kLdrModClose(pLdrMod);
1434 }
1435 else
1436 kwErrPrintf("kLdrOpen failed with %#x (%d) for %s\n", rc, rc, pszPath);
1437 return NULL;
1438}
1439
1440
1441/** Implements FNKLDRMODGETIMPORT, used by kwLdrModuleCreate. */
1442static int kwLdrModuleGetImportCallback(PKLDRMOD pMod, KU32 iImport, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol,
1443 const char *pszVersion, PKLDRADDR puValue, KU32 *pfKind, void *pvUser)
1444{
1445 PKWMODULE pCurMod = (PKWMODULE)pvUser;
1446 PKWMODULE pImpMod = pCurMod->u.Manual.apImpMods[iImport];
1447 int rc;
1448 K_NOREF(pMod);
1449
1450 if (pImpMod->fNative)
1451 rc = kLdrModQuerySymbol(pImpMod->pLdrMod, NULL /*pvBits*/, KLDRMOD_BASEADDRESS_MAP,
1452 iSymbol, pchSymbol, cchSymbol, pszVersion,
1453 NULL /*pfnGetForwarder*/, NULL /*pvUSer*/,
1454 puValue, pfKind);
1455 else
1456 rc = kLdrModQuerySymbol(pImpMod->pLdrMod, pImpMod->u.Manual.pvBits, (KUPTR)pImpMod->u.Manual.pvLoad,
1457 iSymbol, pchSymbol, cchSymbol, pszVersion,
1458 NULL /*pfnGetForwarder*/, NULL /*pvUSer*/,
1459 puValue, pfKind);
1460 if (rc == 0)
1461 {
1462 KU32 i = g_cSandboxReplacements;
1463 while (i-- > 0)
1464 if ( g_aSandboxReplacements[i].cchFunction == cchSymbol
1465 && kHlpMemComp(g_aSandboxReplacements[i].pszFunction, pchSymbol, cchSymbol) == 0)
1466 {
1467 if ( !g_aSandboxReplacements[i].pszModule
1468 || kHlpStrICompAscii(g_aSandboxReplacements[i].pszModule, &pImpMod->pszPath[pImpMod->offFilename]) == 0)
1469 {
1470 KW_LOG(("replacing %s!%s\n", &pImpMod->pszPath[pImpMod->offFilename], g_aSandboxReplacements[i].pszFunction));
1471 *puValue = g_aSandboxReplacements[i].pfnReplacement;
1472 break;
1473 }
1474 }
1475 }
1476
1477 //printf("iImport=%u (%s) %*.*s rc=%d\n", iImport, &pImpMod->pszPath[pImpMod->offFilename], cchSymbol, cchSymbol, pchSymbol, rc);
1478 return rc;
1479
1480}
1481
1482
1483/**
1484 * Gets the main entrypoint for a module.
1485 *
1486 * @returns 0 on success, KERR on failure
1487 * @param pMod The module.
1488 * @param puAddrMain Where to return the address.
1489 */
1490static int kwLdrModuleQueryMainEntrypoint(PKWMODULE pMod, KUPTR *puAddrMain)
1491{
1492 KLDRADDR uLdrAddrMain;
1493 int rc = kLdrModQueryMainEntrypoint(pMod->pLdrMod, pMod->u.Manual.pvBits, (KUPTR)pMod->u.Manual.pvLoad, &uLdrAddrMain);
1494 if (rc == 0)
1495 {
1496 *puAddrMain = (KUPTR)uLdrAddrMain;
1497 return 0;
1498 }
1499 return rc;
1500}
1501
1502
1503/**
1504 * Whether to apply g_aSandboxNativeReplacements to the imports of this module.
1505 *
1506 * @returns K_TRUE/K_FALSE.
1507 * @param pszFilename The filename (no path).
1508 * @param enmLocation The location.
1509 */
1510static KBOOL kwLdrModuleShouldDoNativeReplacements(const char *pszFilename, KWLOCATION enmLocation)
1511{
1512 if (enmLocation != KWLOCATION_SYSTEM32)
1513 return K_TRUE;
1514 return kHlpStrNICompAscii(pszFilename, TUPLE("msvc")) == 0
1515 || kHlpStrNICompAscii(pszFilename, TUPLE("msdis")) == 0
1516 || kHlpStrNICompAscii(pszFilename, TUPLE("mspdb")) == 0;
1517}
1518
1519
1520/**
1521 * Whether we can load this DLL natively or not.
1522 *
1523 * @returns K_TRUE/K_FALSE.
1524 * @param pszFilename The filename (no path).
1525 * @param enmLocation The location.
1526 */
1527static KBOOL kwLdrModuleCanLoadNatively(const char *pszFilename, KWLOCATION enmLocation)
1528{
1529 if (enmLocation == KWLOCATION_SYSTEM32)
1530 return K_TRUE;
1531 if (enmLocation == KWLOCATION_UNKNOWN_NATIVE)
1532 return K_TRUE;
1533 return kHlpStrNICompAscii(pszFilename, TUPLE("msvc")) == 0
1534 || kHlpStrNICompAscii(pszFilename, TUPLE("msdis")) == 0
1535 || kHlpStrNICompAscii(pszFilename, TUPLE("mspdb")) == 0;
1536}
1537
1538
1539/**
1540 * Check if the path leads to a regular file (that exists).
1541 *
1542 * @returns K_TRUE / K_FALSE
1543 * @param pszPath Path to the file to check out.
1544 */
1545static KBOOL kwLdrModuleIsRegularFile(const char *pszPath)
1546{
1547 /* For stuff with .DLL extensions, we can use the GetFileAttribute cache to speed this up! */
1548 KSIZE cchPath = kHlpStrLen(pszPath);
1549 if ( cchPath > 3
1550 && pszPath[cchPath - 4] == '.'
1551 && (pszPath[cchPath - 3] == 'd' || pszPath[cchPath - 3] == 'D')
1552 && (pszPath[cchPath - 2] == 'l' || pszPath[cchPath - 2] == 'L')
1553 && (pszPath[cchPath - 1] == 'l' || pszPath[cchPath - 1] == 'L') )
1554 {
1555 KFSLOOKUPERROR enmError;
1556 PKFSOBJ pFsObj = kFsCacheLookupNoMissingA(g_pFsCache, pszPath, &enmError);
1557 if (pFsObj)
1558 {
1559 KBOOL fRc = pFsObj->bObjType == KFSOBJ_TYPE_FILE;
1560 kFsCacheObjRelease(g_pFsCache, pFsObj);
1561 return fRc;
1562 }
1563 }
1564 else
1565 {
1566 BirdStat_T Stat;
1567 int rc = birdStatFollowLink(pszPath, &Stat);
1568 if (rc == 0)
1569 {
1570 if (S_ISREG(Stat.st_mode))
1571 return K_TRUE;
1572 }
1573 }
1574 return K_FALSE;
1575}
1576
1577
1578/**
1579 * Worker for kwLdrModuleResolveAndLookup that checks out one possibility.
1580 *
1581 * If the file exists, we consult the module hash table before trying to load it
1582 * off the disk.
1583 *
1584 * @returns Pointer to module on success, NULL if not found, ~(KUPTR)0 on
1585 * failure.
1586 * @param pszPath The name of the import module.
1587 * @param enmLocation The location we're searching. This is used in
1588 * the heuristics for determining if we can use the
1589 * native loader or need to sandbox the DLL.
1590 * @param pExe The executable (optional).
1591 */
1592static PKWMODULE kwLdrModuleTryLoadDll(const char *pszPath, KWLOCATION enmLocation, PKWMODULE pExeMod)
1593{
1594 /*
1595 * Does the file exists and is it a regular file?
1596 */
1597 if (kwLdrModuleIsRegularFile(pszPath))
1598 {
1599 /*
1600 * Yes! Normalize it and look it up in the hash table.
1601 */
1602 char szNormPath[1024];
1603 int rc = kwPathNormalize(pszPath, szNormPath, sizeof(szNormPath));
1604 if (rc == 0)
1605 {
1606 const char *pszName;
1607 KU32 const uHashPath = kwStrHash(szNormPath);
1608 unsigned idxHash = uHashPath % K_ELEMENTS(g_apModules);
1609 PKWMODULE pMod = g_apModules[idxHash];
1610 if (pMod)
1611 {
1612 do
1613 {
1614 if ( pMod->uHashPath == uHashPath
1615 && kHlpStrComp(pMod->pszPath, szNormPath) == 0)
1616 return kwLdrModuleRetain(pMod);
1617 pMod = pMod->pNext;
1618 } while (pMod);
1619 }
1620
1621 /*
1622 * Not in the hash table, so we have to load it from scratch.
1623 */
1624 pszName = kHlpGetFilename(szNormPath);
1625 if (kwLdrModuleCanLoadNatively(pszName, enmLocation))
1626 pMod = kwLdrModuleCreateNative(szNormPath, uHashPath,
1627 kwLdrModuleShouldDoNativeReplacements(pszName, enmLocation));
1628 else
1629 pMod = kwLdrModuleCreateNonNative(szNormPath, uHashPath, K_FALSE /*fExe*/, pExeMod);
1630 if (pMod)
1631 return pMod;
1632 return (PKWMODULE)~(KUPTR)0;
1633 }
1634 }
1635 return NULL;
1636}
1637
1638
1639/**
1640 * Gets a reference to the module by the given name.
1641 *
1642 * We must do the search path thing, as our hash table may multiple DLLs with
1643 * the same base name due to different tools version and similar. We'll use a
1644 * modified search sequence, though. No point in searching the current
1645 * directory for instance.
1646 *
1647 * @returns 0 on success, KERR on failure.
1648 * @param pszName The name of the import module.
1649 * @param pExe The executable (optional).
1650 * @param pImporter The module doing the importing (optional).
1651 * @param ppMod Where to return the module pointer w/ reference.
1652 */
1653static int kwLdrModuleResolveAndLookup(const char *pszName, PKWMODULE pExe, PKWMODULE pImporter, PKWMODULE *ppMod)
1654{
1655 KSIZE const cchName = kHlpStrLen(pszName);
1656 char szPath[1024];
1657 PKWMODULE pMod = NULL;
1658
1659
1660 /* The import path. */
1661 if (pMod == NULL && pImporter != NULL)
1662 {
1663 if (pImporter->offFilename + cchName >= sizeof(szPath))
1664 return KERR_BUFFER_OVERFLOW;
1665 kHlpMemCopy(kHlpMemPCopy(szPath, pImporter->pszPath, pImporter->offFilename), pszName, cchName + 1);
1666 pMod = kwLdrModuleTryLoadDll(szPath, KWLOCATION_IMPORTER_DIR, pExe);
1667 }
1668
1669 /* Application directory first. */
1670 if (pMod == NULL && pExe != NULL && pExe != pImporter)
1671 {
1672 if (pExe->offFilename + cchName >= sizeof(szPath))
1673 return KERR_BUFFER_OVERFLOW;
1674 kHlpMemCopy(kHlpMemPCopy(szPath, pExe->pszPath, pExe->offFilename), pszName, cchName + 1);
1675 pMod = kwLdrModuleTryLoadDll(szPath, KWLOCATION_EXE_DIR, pExe);
1676 }
1677
1678 /* The windows directory. */
1679 if (pMod == NULL)
1680 {
1681 UINT cchDir = GetSystemDirectoryA(szPath, sizeof(szPath));
1682 if ( cchDir <= 2
1683 || cchDir + 1 + cchName >= sizeof(szPath))
1684 return KERR_BUFFER_OVERFLOW;
1685 szPath[cchDir++] = '\\';
1686 kHlpMemCopy(&szPath[cchDir], pszName, cchName + 1);
1687 pMod = kwLdrModuleTryLoadDll(szPath, KWLOCATION_SYSTEM32, pExe);
1688 }
1689
1690 /* Return. */
1691 if (pMod != NULL && pMod != (PKWMODULE)~(KUPTR)0)
1692 {
1693 *ppMod = pMod;
1694 return 0;
1695 }
1696 *ppMod = NULL;
1697 return KERR_GENERAL_FAILURE;
1698}
1699
1700
1701/**
1702 * Does module initialization starting at @a pMod.
1703 *
1704 * This is initially used on the executable. Later it is used by the
1705 * LoadLibrary interceptor.
1706 *
1707 * @returns 0 on success, error on failure.
1708 * @param pMod The module to initialize.
1709 */
1710static int kwLdrModuleInitTree(PKWMODULE pMod)
1711{
1712 int rc = 0;
1713 if (!pMod->fNative)
1714 {
1715 /* Need to copy bits? */
1716 if (pMod->u.Manual.enmState == KWMODSTATE_NEEDS_BITS)
1717 {
1718 if (pMod->u.Manual.fUseLdBuf)
1719 {
1720#if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_AMD64)
1721 if (g_pModInLdBuf != NULL && g_pModInLdBuf != pMod && pMod->u.Manual.fRegisteredFunctionTable)
1722 {
1723 BOOLEAN fRc = RtlDeleteFunctionTable(pMod->u.Manual.paFunctions);
1724 kHlpAssert(fRc); K_NOREF(fRc);
1725 }
1726#endif
1727 g_pModInLdBuf = pMod;
1728 }
1729
1730 kHlpMemCopy(pMod->u.Manual.pvLoad, pMod->u.Manual.pvCopy, pMod->u.Manual.cbImage);
1731 pMod->u.Manual.enmState = KWMODSTATE_NEEDS_INIT;
1732 }
1733
1734#if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_AMD64)
1735 /* Need to register function table? */
1736 if ( !pMod->u.Manual.fRegisteredFunctionTable
1737 && pMod->u.Manual.cFunctions > 0)
1738 {
1739 pMod->u.Manual.fRegisteredFunctionTable = RtlAddFunctionTable(pMod->u.Manual.paFunctions,
1740 pMod->u.Manual.cFunctions,
1741 (KUPTR)pMod->u.Manual.pvLoad) != FALSE;
1742 kHlpAssert(pMod->u.Manual.fRegisteredFunctionTable);
1743 }
1744#endif
1745
1746 if (pMod->u.Manual.enmState == KWMODSTATE_NEEDS_INIT)
1747 {
1748 /* Must do imports first, but mark our module as being initialized to avoid
1749 endless recursion should there be a dependency loop. */
1750 KSIZE iImp;
1751 pMod->u.Manual.enmState = KWMODSTATE_BEING_INITED;
1752
1753 for (iImp = 0; iImp < pMod->u.Manual.cImpMods; iImp++)
1754 {
1755 rc = kwLdrModuleInitTree(pMod->u.Manual.apImpMods[iImp]);
1756 if (rc != 0)
1757 return rc;
1758 }
1759
1760 rc = kLdrModCallInit(pMod->pLdrMod, pMod->u.Manual.pvLoad, (KUPTR)pMod->u.Manual.pvLoad);
1761 if (rc == 0)
1762 pMod->u.Manual.enmState = KWMODSTATE_READY;
1763 else
1764 pMod->u.Manual.enmState = KWMODSTATE_INIT_FAILED;
1765 }
1766 }
1767 return rc;
1768}
1769
1770
1771
1772
1773/**
1774 * Creates a tool entry and inserts it.
1775 *
1776 * @returns Pointer to the tool entry. NULL on failure.
1777 * @param pToolFsObj The file object of the tool. The created tool
1778 * will be associated with it.
1779 *
1780 * A reference is donated by the caller and must be
1781 * released.
1782 */
1783static PKWTOOL kwToolEntryCreate(PKFSOBJ pToolFsObj)
1784{
1785 KSIZE cwcPath = pToolFsObj->cwcParent + pToolFsObj->cwcName + 1;
1786 KSIZE cbPath = pToolFsObj->cchParent + pToolFsObj->cchName + 1;
1787 PKWTOOL pTool = (PKWTOOL)kFsCacheObjAddUserData(g_pFsCache, pToolFsObj, KW_DATA_KEY_TOOL,
1788 sizeof(*pTool) + cwcPath * sizeof(wchar_t) + cbPath);
1789 if (pTool)
1790 {
1791 KBOOL fRc;
1792 pTool->pwszPath = (wchar_t const *)(pTool + 1);
1793 fRc = kFsCacheObjGetFullPathW(pToolFsObj, (wchar_t *)pTool->pwszPath, cwcPath, '\\');
1794 kHlpAssert(fRc); K_NOREF(fRc);
1795
1796 pTool->pszPath = (char const *)&pTool->pwszPath[cwcPath];
1797 fRc = kFsCacheObjGetFullPathA(pToolFsObj, (char *)pTool->pszPath, cbPath, '\\');
1798 kHlpAssert(fRc);
1799
1800 pTool->enmType = KWTOOLTYPE_SANDBOXED;
1801 pTool->u.Sandboxed.pExe = kwLdrModuleCreateNonNative(pTool->pszPath, kwStrHash(pTool->pszPath), K_TRUE /*fExe*/, NULL);
1802 if (!pTool->u.Sandboxed.pExe)
1803 pTool->enmType = KWTOOLTYPE_EXEC;
1804 else if (kHlpStrICompAscii(pToolFsObj->pszName, "cl.exe") == 0)
1805 pTool->u.Sandboxed.enmHint = KWTOOLHINT_VISUAL_CPP_CL;
1806 else
1807 pTool->u.Sandboxed.enmHint = KWTOOLHINT_NONE;
1808
1809 kFsCacheObjRelease(g_pFsCache, pToolFsObj);
1810 return pTool;
1811 }
1812 kFsCacheObjRelease(g_pFsCache, pToolFsObj);
1813 return NULL;
1814}
1815
1816
1817/**
1818 * Looks up the given tool, creating a new tool table entry if necessary.
1819 *
1820 * @returns Pointer to the tool entry. NULL on failure.
1821 * @param pszExe The executable for the tool (not normalized).
1822 */
1823static PKWTOOL kwToolLookup(const char *pszExe)
1824{
1825 /*
1826 * We associate the tools instances with the file system objects.
1827 */
1828 KFSLOOKUPERROR enmError;
1829 PKFSOBJ pToolFsObj = kFsCacheLookupA(g_pFsCache, pszExe, &enmError);
1830 if (pToolFsObj)
1831 {
1832 if (pToolFsObj->bObjType == KFSOBJ_TYPE_FILE)
1833 {
1834 PKWTOOL pTool = (PKWTOOL)kFsCacheObjGetUserData(g_pFsCache, pToolFsObj, KW_DATA_KEY_TOOL);
1835 if (pTool)
1836 {
1837 kFsCacheObjRelease(g_pFsCache, pToolFsObj);
1838 return pTool;
1839 }
1840
1841 /*
1842 * Need to create a new tool.
1843 */
1844 return kwToolEntryCreate(pToolFsObj);
1845 }
1846 kFsCacheObjRelease(g_pFsCache, pToolFsObj);
1847 }
1848 return NULL;
1849}
1850
1851
1852
1853/*
1854 *
1855 * File system cache.
1856 * File system cache.
1857 * File system cache.
1858 *
1859 */
1860
1861
1862
1863/**
1864 * Helper for getting the extension of a UTF-16 path.
1865 *
1866 * @returns Pointer to the extension or the terminator.
1867 * @param pwszPath The path.
1868 * @param pcwcExt Where to return the length of the extension.
1869 */
1870static wchar_t const *kwFsPathGetExtW(wchar_t const *pwszPath, KSIZE *pcwcExt)
1871{
1872 wchar_t const *pwszName = pwszPath;
1873 wchar_t const *pwszExt = NULL;
1874 for (;;)
1875 {
1876 wchar_t const wc = *pwszPath++;
1877 if (wc == '.')
1878 pwszExt = pwszPath;
1879 else if (wc == '/' || wc == '\\' || wc == ':')
1880 {
1881 pwszName = pwszPath;
1882 pwszExt = NULL;
1883 }
1884 else if (wc == '\0')
1885 {
1886 if (pwszExt)
1887 {
1888 *pcwcExt = pwszPath - pwszExt - 1;
1889 return pwszExt;
1890 }
1891 *pcwcExt = 0;
1892 return pwszPath - 1;
1893 }
1894 }
1895}
1896
1897
1898
1899/**
1900 * Parses the argument string passed in as pszSrc.
1901 *
1902 * @returns size of the processed arguments.
1903 * @param pszSrc Pointer to the commandline that's to be parsed.
1904 * @param pcArgs Where to return the number of arguments.
1905 * @param argv Pointer to argument vector to put argument pointers in. NULL allowed.
1906 * @param pchPool Pointer to memory pchPool to put the arguments into. NULL allowed.
1907 *
1908 * @remarks Lifted from startuphacks-win.c
1909 */
1910static int parse_args(const char *pszSrc, int *pcArgs, char **argv, char *pchPool)
1911{
1912 int bs;
1913 char chQuote;
1914 char *pfFlags;
1915 int cbArgs;
1916 int cArgs;
1917
1918#define PUTC(c) do { ++cbArgs; if (pchPool != NULL) *pchPool++ = (c); } while (0)
1919#define PUTV do { ++cArgs; if (argv != NULL) *argv++ = pchPool; } while (0)
1920#define WHITE(c) ((c) == ' ' || (c) == '\t')
1921
1922#define _ARG_DQUOTE 0x01 /* Argument quoted (") */
1923#define _ARG_RESPONSE 0x02 /* Argument read from response file */
1924#define _ARG_WILDCARD 0x04 /* Argument expanded from wildcard */
1925#define _ARG_ENV 0x08 /* Argument from environment */
1926#define _ARG_NONZERO 0x80 /* Always set, to avoid end of string */
1927
1928 cArgs = 0;
1929 cbArgs = 0;
1930
1931#if 0
1932 /* argv[0] */
1933 PUTC((char)_ARG_NONZERO);
1934 PUTV;
1935 for (;;)
1936 {
1937 PUTC(*pszSrc);
1938 if (*pszSrc == 0)
1939 break;
1940 ++pszSrc;
1941 }
1942 ++pszSrc;
1943#endif
1944
1945 for (;;)
1946 {
1947 while (WHITE(*pszSrc))
1948 ++pszSrc;
1949 if (*pszSrc == 0)
1950 break;
1951 pfFlags = pchPool;
1952 PUTC((char)_ARG_NONZERO);
1953 PUTV;
1954 bs = 0; chQuote = 0;
1955 for (;;)
1956 {
1957 if (!chQuote ? (*pszSrc == '"' /*|| *pszSrc == '\''*/) : *pszSrc == chQuote)
1958 {
1959 while (bs >= 2)
1960 {
1961 PUTC('\\');
1962 bs -= 2;
1963 }
1964 if (bs & 1)
1965 PUTC(*pszSrc);
1966 else
1967 {
1968 chQuote = chQuote ? 0 : *pszSrc;
1969 if (pfFlags != NULL)
1970 *pfFlags |= _ARG_DQUOTE;
1971 }
1972 bs = 0;
1973 }
1974 else if (*pszSrc == '\\')
1975 ++bs;
1976 else
1977 {
1978 while (bs != 0)
1979 {
1980 PUTC('\\');
1981 --bs;
1982 }
1983 if (*pszSrc == 0 || (WHITE(*pszSrc) && !chQuote))
1984 break;
1985 PUTC(*pszSrc);
1986 }
1987 ++pszSrc;
1988 }
1989 PUTC(0);
1990 }
1991
1992 *pcArgs = cArgs;
1993 return cbArgs;
1994}
1995
1996
1997
1998
1999/*
2000 *
2001 * Process and thread related APIs.
2002 * Process and thread related APIs.
2003 * Process and thread related APIs.
2004 *
2005 */
2006
2007/** ExitProcess replacement. */
2008static void WINAPI kwSandbox_Kernel32_ExitProcess(UINT uExitCode)
2009{
2010 if (g_Sandbox.idMainThread == GetCurrentThreadId())
2011 {
2012 PNT_TIB pTib = (PNT_TIB)NtCurrentTeb();
2013
2014 g_Sandbox.rcExitCode = (int)uExitCode;
2015
2016 /* Before we jump, restore the TIB as we're not interested in any
2017 exception chain stuff installed by the sandboxed executable. */
2018 *pTib = g_Sandbox.TibMainThread;
2019 pTib->ExceptionList = g_Sandbox.pOutXcptListHead;
2020
2021 longjmp(g_Sandbox.JmpBuf, 1);
2022 }
2023 KWFS_TODO();
2024}
2025
2026
2027/** ExitProcess replacement. */
2028static BOOL WINAPI kwSandbox_Kernel32_TerminateProcess(HANDLE hProcess, UINT uExitCode)
2029{
2030 if (hProcess == GetCurrentProcess())
2031 kwSandbox_Kernel32_ExitProcess(uExitCode);
2032 KWFS_TODO();
2033 return TerminateProcess(hProcess, uExitCode);
2034}
2035
2036
2037/** Normal CRT exit(). */
2038static void __cdecl kwSandbox_msvcrt_exit(int rcExitCode)
2039{
2040 KW_LOG(("kwSandbox_msvcrt_exit: %d\n", rcExitCode));
2041 kwSandbox_Kernel32_ExitProcess(rcExitCode);
2042}
2043
2044
2045/** Quick CRT _exit(). */
2046static void __cdecl kwSandbox_msvcrt__exit(int rcExitCode)
2047{
2048 /* Quick. */
2049 KW_LOG(("kwSandbox_msvcrt__exit %d\n", rcExitCode));
2050 kwSandbox_Kernel32_ExitProcess(rcExitCode);
2051}
2052
2053
2054/** Return to caller CRT _cexit(). */
2055static void __cdecl kwSandbox_msvcrt__cexit(int rcExitCode)
2056{
2057 KW_LOG(("kwSandbox_msvcrt__cexit: %d\n", rcExitCode));
2058 kwSandbox_Kernel32_ExitProcess(rcExitCode);
2059}
2060
2061
2062/** Quick return to caller CRT _c_exit(). */
2063static void __cdecl kwSandbox_msvcrt__c_exit(int rcExitCode)
2064{
2065 KW_LOG(("kwSandbox_msvcrt__c_exit: %d\n", rcExitCode));
2066 kwSandbox_Kernel32_ExitProcess(rcExitCode);
2067}
2068
2069
2070/** Runtime error and exit _amsg_exit(). */
2071static void __cdecl kwSandbox_msvcrt__amsg_exit(int iMsgNo)
2072{
2073 KW_LOG(("\nRuntime error #%u!\n", iMsgNo));
2074 kwSandbox_Kernel32_ExitProcess(255);
2075}
2076
2077
2078/** CRT - terminate(). */
2079static void __cdecl kwSandbox_msvcrt_terminate(void)
2080{
2081 KW_LOG(("\nRuntime - terminate!\n"));
2082 kwSandbox_Kernel32_ExitProcess(254);
2083}
2084
2085
2086/** The CRT internal __getmainargs() API. */
2087static int __cdecl kwSandbox_msvcrt___getmainargs(int *pargc, char ***pargv, char ***penvp,
2088 int dowildcard, int const *piNewMode)
2089{
2090 *pargc = g_Sandbox.cArgs;
2091 *pargv = g_Sandbox.papszArgs;
2092 *penvp = g_Sandbox.environ;
2093
2094 /** @todo startinfo points at a newmode (setmode) value. */
2095 return 0;
2096}
2097
2098
2099/** The CRT internal __wgetmainargs() API. */
2100static int __cdecl kwSandbox_msvcrt___wgetmainargs(int *pargc, wchar_t ***pargv, wchar_t ***penvp,
2101 int dowildcard, int const *piNewMode)
2102{
2103 *pargc = g_Sandbox.cArgs;
2104 *pargv = g_Sandbox.papwszArgs;
2105 *penvp = g_Sandbox.wenviron;
2106
2107 /** @todo startinfo points at a newmode (setmode) value. */
2108 return 0;
2109}
2110
2111
2112
2113/** Kernel32 - GetCommandLineA() */
2114static LPCSTR /*LPSTR*/ WINAPI kwSandbox_Kernel32_GetCommandLineA(VOID)
2115{
2116 return g_Sandbox.pszCmdLine;
2117}
2118
2119
2120/** Kernel32 - GetCommandLineW() */
2121static LPCWSTR /*LPWSTR*/ WINAPI kwSandbox_Kernel32_GetCommandLineW(VOID)
2122{
2123 return g_Sandbox.pwszCmdLine;
2124}
2125
2126
2127/** Kernel32 - GetStartupInfoA() */
2128static VOID WINAPI kwSandbox_Kernel32_GetStartupInfoA(LPSTARTUPINFOA pStartupInfo)
2129{
2130 KW_LOG(("GetStartupInfoA\n"));
2131 GetStartupInfoA(pStartupInfo);
2132 pStartupInfo->lpReserved = NULL;
2133 pStartupInfo->lpTitle = NULL;
2134 pStartupInfo->lpReserved2 = NULL;
2135 pStartupInfo->cbReserved2 = 0;
2136}
2137
2138
2139/** Kernel32 - GetStartupInfoW() */
2140static VOID WINAPI kwSandbox_Kernel32_GetStartupInfoW(LPSTARTUPINFOW pStartupInfo)
2141{
2142 KW_LOG(("GetStartupInfoW\n"));
2143 GetStartupInfoW(pStartupInfo);
2144 pStartupInfo->lpReserved = NULL;
2145 pStartupInfo->lpTitle = NULL;
2146 pStartupInfo->lpReserved2 = NULL;
2147 pStartupInfo->cbReserved2 = 0;
2148}
2149
2150
2151/** CRT - __p___argc(). */
2152static int * __cdecl kwSandbox_msvcrt___p___argc(void)
2153{
2154 return &g_Sandbox.cArgs;
2155}
2156
2157
2158/** CRT - __p___argv(). */
2159static char *** __cdecl kwSandbox_msvcrt___p___argv(void)
2160{
2161 return &g_Sandbox.papszArgs;
2162}
2163
2164
2165/** CRT - __p___sargv(). */
2166static wchar_t *** __cdecl kwSandbox_msvcrt___p___wargv(void)
2167{
2168 return &g_Sandbox.papwszArgs;
2169}
2170
2171
2172/** CRT - __p__acmdln(). */
2173static char ** __cdecl kwSandbox_msvcrt___p__acmdln(void)
2174{
2175 return (char **)&g_Sandbox.pszCmdLine;
2176}
2177
2178
2179/** CRT - __p__acmdln(). */
2180static wchar_t ** __cdecl kwSandbox_msvcrt___p__wcmdln(void)
2181{
2182 return &g_Sandbox.pwszCmdLine;
2183}
2184
2185
2186/** CRT - __p__pgmptr(). */
2187static char ** __cdecl kwSandbox_msvcrt___p__pgmptr(void)
2188{
2189 return &g_Sandbox.pgmptr;
2190}
2191
2192
2193/** CRT - __p__wpgmptr(). */
2194static wchar_t ** __cdecl kwSandbox_msvcrt___p__wpgmptr(void)
2195{
2196 return &g_Sandbox.wpgmptr;
2197}
2198
2199
2200/** CRT - _get_pgmptr(). */
2201static errno_t __cdecl kwSandbox_msvcrt__get_pgmptr(char **ppszValue)
2202{
2203 *ppszValue = g_Sandbox.pgmptr;
2204 return 0;
2205}
2206
2207
2208/** CRT - _get_wpgmptr(). */
2209static errno_t __cdecl kwSandbox_msvcrt__get_wpgmptr(wchar_t **ppwszValue)
2210{
2211 *ppwszValue = g_Sandbox.wpgmptr;
2212 return 0;
2213}
2214
2215/** Just in case. */
2216static void kwSandbox_msvcrt__wincmdln(void)
2217{
2218 KWFS_TODO();
2219}
2220
2221
2222/** Just in case. */
2223static void kwSandbox_msvcrt__wwincmdln(void)
2224{
2225 KWFS_TODO();
2226}
2227
2228/** CreateThread interceptor. */
2229static HANDLE WINAPI kwSandbox_Kernel32_CreateThread(LPSECURITY_ATTRIBUTES pSecAttr, SIZE_T cbStack,
2230 PTHREAD_START_ROUTINE pfnThreadProc, PVOID pvUser,
2231 DWORD fFlags, PDWORD pidThread)
2232{
2233 KWFS_TODO();
2234 return NULL;
2235}
2236
2237
2238/** _beginthread - create a new thread. */
2239static uintptr_t __cdecl kwSandbox_msvcrt__beginthread(void (__cdecl *pfnThreadProc)(void *), unsigned cbStack, void *pvUser)
2240{
2241 KWFS_TODO();
2242 return 0;
2243}
2244
2245
2246/** _beginthreadex - create a new thread. */
2247static uintptr_t __cdecl kwSandbox_msvcrt__beginthreadex(void *pvSecAttr, unsigned cbStack,
2248 unsigned (__stdcall *pfnThreadProc)(void *), void *pvUser,
2249 unsigned fCreate, unsigned *pidThread)
2250{
2251 KWFS_TODO();
2252 return 0;
2253}
2254
2255
2256/*
2257 *
2258 * Environment related APIs.
2259 * Environment related APIs.
2260 * Environment related APIs.
2261 *
2262 */
2263
2264/** Kernel32 - GetEnvironmentVariableA() */
2265static DWORD WINAPI kwSandbox_Kernel32_GetEnvironmentVariableA(LPCSTR pwszVar, LPSTR pszValue, DWORD cbValue)
2266{
2267 KWFS_TODO();
2268 return 0;
2269}
2270
2271
2272/** Kernel32 - GetEnvironmentVariableW() */
2273static DWORD WINAPI kwSandbox_Kernel32_GetEnvironmentVariableW(LPCWSTR pwszVar, LPWSTR pwszValue, DWORD cbValue)
2274{
2275 KW_LOG(("GetEnvironmentVariableW: '%ls'\n", pwszVar));
2276 //KWFS_TODO();
2277 //SetLastError(ERROR_ENVVAR_NOT_FOUND);
2278 //return 0;
2279 return GetEnvironmentVariableW(pwszVar, pwszValue, cbValue);
2280}
2281
2282
2283/** Kernel32 - SetEnvironmentVariableA() */
2284static BOOL WINAPI kwSandbox_Kernel32_SetEnvironmentVariableA(LPCSTR pszVar, LPCSTR pszValue)
2285{
2286 KWFS_TODO();
2287 return FALSE;
2288}
2289
2290
2291/** Kernel32 - SetEnvironmentVariableW() */
2292static BOOL WINAPI kwSandbox_Kernel32_SetEnvironmentVariableW(LPCWSTR pwszVar, LPCWSTR pwszValue)
2293{
2294 KW_LOG(("SetEnvironmentVariableW: '%ls' = '%ls'\n", pwszVar, pwszValue));
2295 return SetEnvironmentVariableW(pwszVar, pwszValue);
2296 //KWFS_TODO();
2297 //return FALSE;
2298}
2299
2300
2301/** Kernel32 - ExpandEnvironmentStringsA() */
2302static DWORD WINAPI kwSandbox_Kernel32_ExpandEnvironmentStringsA(LPCSTR pszSrc, LPSTR pwszDst, DWORD cbDst)
2303{
2304 KWFS_TODO();
2305 return 0;
2306}
2307
2308
2309/** Kernel32 - ExpandEnvironmentStringsW() */
2310static DWORD WINAPI kwSandbox_Kernel32_ExpandEnvironmentStringsW(LPCWSTR pwszSrc, LPWSTR pwszDst, DWORD cbDst)
2311{
2312 KWFS_TODO();
2313 return 0;
2314}
2315
2316
2317/** CRT - _putenv(). */
2318static int __cdecl kwSandbox_msvcrt__putenv(const char *pszVarEqualValue)
2319{
2320 KWFS_TODO();
2321 return 0;
2322}
2323
2324
2325/** CRT - _wputenv(). */
2326static int __cdecl kwSandbox_msvcrt__wputenv(const wchar_t *pwszVarEqualValue)
2327{
2328 KWFS_TODO();
2329 return 0;
2330}
2331
2332
2333/** CRT - _putenv_s(). */
2334static errno_t __cdecl kwSandbox_msvcrt__putenv_s(const char *pszVar, const char *pszValue)
2335{
2336 KWFS_TODO();
2337 return 0;
2338}
2339
2340
2341/** CRT - _wputenv_s(). */
2342static errno_t __cdecl kwSandbox_msvcrt__wputenv_s(const wchar_t *pwszVar, const wchar_t *pwszValue)
2343{
2344 KW_LOG(("_wputenv_s: '%ls' = '%ls'\n", pwszVar, pwszValue));
2345 //KWFS_TODO();
2346 return SetEnvironmentVariableW(pwszVar, pwszValue) ? 0 : -1;
2347}
2348
2349
2350/** CRT - get pointer to the __initenv variable (initial environment). */
2351static char *** __cdecl kwSandbox_msvcrt___p___initenv(void)
2352{
2353 return &g_Sandbox.initenv;
2354}
2355
2356
2357/** CRT - get pointer to the __winitenv variable (initial environment). */
2358static wchar_t *** __cdecl kwSandbox_msvcrt___p___winitenv(void)
2359{
2360 return &g_Sandbox.winitenv;
2361}
2362
2363
2364/** CRT - get pointer to the _environ variable (current environment). */
2365static char *** __cdecl kwSandbox_msvcrt___p__environ(void)
2366{
2367 return &g_Sandbox.environ;
2368}
2369
2370
2371/** CRT - get pointer to the _wenviron variable (current environment). */
2372static wchar_t *** __cdecl kwSandbox_msvcrt___p__wenviron(void)
2373{
2374 return &g_Sandbox.wenviron;
2375}
2376
2377
2378/** CRT - get the _environ variable (current environment).
2379 * @remarks Not documented or prototyped? */
2380static KUPTR /*void*/ __cdecl kwSandbox_msvcrt__get_environ(char ***ppapszEnviron)
2381{
2382 KWFS_TODO(); /** @todo check the callers expecations! */
2383 *ppapszEnviron = g_Sandbox.environ;
2384 return 0;
2385}
2386
2387
2388/** CRT - get the _wenviron variable (current environment).
2389 * @remarks Not documented or prototyped? */
2390static KUPTR /*void*/ __cdecl kwSandbox_msvcrt__get_wenviron(wchar_t ***ppapwszEnviron)
2391{
2392 KWFS_TODO(); /** @todo check the callers expecations! */
2393 *ppapwszEnviron = g_Sandbox.wenviron;
2394 return 0;
2395}
2396
2397
2398
2399/*
2400 *
2401 * Loader related APIs
2402 * Loader related APIs
2403 * Loader related APIs
2404 *
2405 */
2406
2407/**
2408 * Kernel32 - LoadLibraryExA() worker that loads resource files and such.
2409 */
2410static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryExA_Resource(LPCSTR pszFilename, HANDLE hFile, DWORD fFlags)
2411{
2412 HMODULE hmod;
2413 PKWDYNLOAD pDynLoad;
2414 KU32 uHashPath;
2415 char szNormPath[4096];
2416
2417 /* Normalize the path. */
2418 int rc = kwPathNormalize(pszFilename, szNormPath, sizeof(szNormPath));
2419 if (rc != 0)
2420 {
2421 KWFS_TODO();
2422 return LoadLibraryExA(pszFilename, hFile, fFlags);
2423 }
2424
2425 /* Try look it up. */
2426 uHashPath = kwStrHash(szNormPath);
2427 for (pDynLoad = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead; pDynLoad != NULL; pDynLoad = pDynLoad->pNext)
2428 if ( pDynLoad->uHashPath == uHashPath
2429 && kHlpStrComp(pDynLoad->pszPath, szNormPath) == 0)
2430 {
2431 if (pDynLoad->pMod == NULL)
2432 return pDynLoad->hmod;
2433 KWFS_TODO();
2434 }
2435
2436 /* Then try load it. */
2437 hmod = LoadLibraryExA(szNormPath, hFile, fFlags);
2438 if (hmod)
2439 {
2440 KSIZE cbNormPath = kHlpStrLen(szNormPath) + 1;
2441 pDynLoad = (PKWDYNLOAD)kHlpAlloc(sizeof(*pDynLoad) + cbNormPath + cbNormPath * 2 * sizeof(wchar_t));
2442 if (pDynLoad)
2443 {
2444 pDynLoad->pszPath = (char *)kHlpMemCopy(pDynLoad + 1, szNormPath, cbNormPath);
2445 pDynLoad->pwszPath = (wchar_t *)(pDynLoad->pszPath + cbNormPath + (cbNormPath & 1));
2446 kwStrToUtf16(pDynLoad->pszPath, (wchar_t *)pDynLoad->pwszPath, cbNormPath * 2);
2447 pDynLoad->pszModName = kHlpGetFilename(pDynLoad->pszPath);
2448 pDynLoad->uHashPath = uHashPath;
2449 pDynLoad->pMod = NULL; /* indicates special */
2450 pDynLoad->hmod = hmod;
2451
2452 pDynLoad->pNext = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead;
2453 g_Sandbox.pTool->u.Sandboxed.pDynLoadHead = pDynLoad;
2454 }
2455 else
2456 KWFS_TODO();
2457 }
2458 return hmod;
2459}
2460
2461
2462/**
2463 * Kernel32 - LoadLibraryExA() worker that deals with the api-ms-xxx modules.
2464 */
2465static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryExA_VirtualApiModule(LPCSTR pszFilename, HANDLE hFile, DWORD fFlags)
2466{
2467 HMODULE hmod;
2468 PKWDYNLOAD pDynLoad;
2469 KU32 uHashPath;
2470 char szNormPath[256];
2471 KSIZE cbFilename = kHlpStrLen(pszFilename) + 1;
2472
2473 /* Lower case it. */
2474 if (cbFilename <= sizeof(szNormPath))
2475 {
2476 kHlpMemCopy(szNormPath, pszFilename, cbFilename);
2477 _strlwr(szNormPath);
2478 }
2479 else
2480 {
2481 SetLastError(ERROR_FILENAME_EXCED_RANGE);
2482 return NULL;
2483 }
2484
2485 /* Try look it up. */
2486 uHashPath = kwStrHash(szNormPath);
2487 for (pDynLoad = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead; pDynLoad != NULL; pDynLoad = pDynLoad->pNext)
2488 if ( pDynLoad->uHashPath == uHashPath
2489 && kHlpStrComp(pDynLoad->pszPath, szNormPath) == 0)
2490 {
2491 if (pDynLoad->pMod != NULL)
2492 return pDynLoad->hmod;
2493 KWFS_TODO();
2494 }
2495
2496 /* Then try load it and make a kLdr module for it. */
2497 hmod = LoadLibraryExA(szNormPath, hFile, fFlags);
2498 if (hmod)
2499 {
2500 PKLDRMOD pLdrMod;
2501 int rc = kLdrModOpenNativeByHandle((KUPTR)hmod, &pLdrMod);
2502 if (rc == 0)
2503 {
2504 PKWMODULE pMod = kwLdrModuleCreateForNativekLdrModule(pLdrMod, szNormPath, cbFilename, uHashPath,
2505 K_FALSE /*fDoReplacements*/);
2506 if (pMod)
2507 {
2508 pDynLoad = (PKWDYNLOAD)kHlpAlloc(sizeof(*pDynLoad) + cbFilename + cbFilename * sizeof(wchar_t));
2509 if (pDynLoad)
2510 {
2511 pDynLoad->pwszPath = (wchar_t *)(pDynLoad + 1);
2512 kwStrToUtf16(szNormPath, (wchar_t *)pDynLoad->pwszPath, cbFilename);
2513 pDynLoad->pszPath = (char *)kHlpMemCopy((char *)&pDynLoad->pwszPath[cbFilename], szNormPath, cbFilename);
2514 pDynLoad->pszModName = pDynLoad->pszPath;
2515 pDynLoad->uHashPath = uHashPath;
2516 pDynLoad->pMod = pMod;
2517 pDynLoad->hmod = hmod;
2518
2519 pDynLoad->pNext = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead;
2520 g_Sandbox.pTool->u.Sandboxed.pDynLoadHead = pDynLoad;
2521 return hmod;
2522 }
2523
2524 KWFS_TODO();
2525 }
2526 else
2527 KWFS_TODO();
2528 }
2529 else
2530 KWFS_TODO();
2531 }
2532 return hmod;
2533}
2534
2535
2536/** Kernel32 - LoadLibraryExA() */
2537static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryExA(LPCSTR pszFilename, HANDLE hFile, DWORD fFlags)
2538{
2539 PKWDYNLOAD pDynLoad;
2540 PKWMODULE pMod;
2541 int rc;
2542
2543 if ( (fFlags & LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE)
2544 || (hFile != NULL && hFile != INVALID_HANDLE_VALUE) )
2545 {
2546 KWFS_TODO();
2547 return LoadLibraryExA(pszFilename, hFile, fFlags);
2548 }
2549
2550 /*
2551 * Deal with resource / data DLLs.
2552 */
2553 if (fFlags & ( DONT_RESOLVE_DLL_REFERENCES
2554 | LOAD_LIBRARY_AS_DATAFILE
2555 | LOAD_LIBRARY_AS_IMAGE_RESOURCE) )
2556 {
2557 /* currently, only deal with those that has a path. */
2558 if (kHlpIsFilenameOnly(pszFilename))
2559 {
2560 KWFS_TODO();
2561 return LoadLibraryExA(pszFilename, hFile, fFlags);
2562 }
2563
2564 return kwSandbox_Kernel32_LoadLibraryExA_Resource(pszFilename, hFile, fFlags);
2565 }
2566
2567 /*
2568 * Normal library loading.
2569 * We start by being very lazy and reusing the code for resolving imports.
2570 */
2571 if (!kHlpIsFilenameOnly(pszFilename))
2572 pMod = kwLdrModuleTryLoadDll(pszFilename, KWLOCATION_UNKNOWN, g_Sandbox.pTool->u.Sandboxed.pExe);
2573 /* Special case: api-ms-win-core-synch-l1-2-0 and friends (32-bit yasm, built with VS2015). */
2574 else if (strnicmp(pszFilename, TUPLE("api-ms-")) == 0)
2575 return kwSandbox_Kernel32_LoadLibraryExA_VirtualApiModule(pszFilename, hFile, fFlags);
2576 else
2577 {
2578 KWFS_TODO();
2579 rc = kwLdrModuleResolveAndLookup(pszFilename, g_Sandbox.pTool->u.Sandboxed.pExe, NULL /*pImporter*/, &pMod);
2580 if (rc != 0)
2581 pMod = NULL;
2582 }
2583 if (!pMod)
2584 {
2585 KWFS_TODO();
2586 SetLastError(ERROR_MOD_NOT_FOUND);
2587 return NULL;
2588 }
2589
2590 /*
2591 * Make sure it's initialized.
2592 */
2593 rc = kwLdrModuleInitTree(pMod);
2594 if (rc == 0)
2595 {
2596 /*
2597 * Create an dynamic loading entry for it.
2598 */
2599 pDynLoad = (PKWDYNLOAD)kHlpAlloc(sizeof(*pDynLoad));
2600 if (pDynLoad)
2601 {
2602 pDynLoad->pszPath = pMod->pszPath;
2603 pDynLoad->pwszPath = pMod->pwszPath;
2604 pDynLoad->pszModName = kHlpGetFilename(pDynLoad->pszPath);
2605 pDynLoad->uHashPath = pMod->uHashPath;
2606 pDynLoad->pMod = pMod;
2607 pDynLoad->hmod = pMod->hOurMod;
2608
2609 pDynLoad->pNext = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead;
2610 g_Sandbox.pTool->u.Sandboxed.pDynLoadHead = pDynLoad;
2611
2612 return pDynLoad->hmod;
2613 }
2614 }
2615
2616 KWFS_TODO();
2617 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2618 kwLdrModuleRelease(pMod);
2619 return NULL;
2620}
2621
2622
2623/** Kernel32 - LoadLibraryExW() */
2624static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryExW(LPCWSTR pwszFilename, HANDLE hFile, DWORD fFlags)
2625{
2626 char szTmp[4096];
2627 KSIZE cchTmp = kwUtf16ToStr(pwszFilename, szTmp, sizeof(szTmp));
2628 if (cchTmp < sizeof(szTmp))
2629 return kwSandbox_Kernel32_LoadLibraryExA(szTmp, hFile, fFlags);
2630
2631 KWFS_TODO();
2632 SetLastError(ERROR_FILENAME_EXCED_RANGE);
2633 return NULL;
2634}
2635
2636/** Kernel32 - LoadLibraryA() */
2637static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryA(LPCSTR pszFilename)
2638{
2639 return kwSandbox_Kernel32_LoadLibraryExA(pszFilename, NULL /*hFile*/, 0 /*fFlags*/);
2640}
2641
2642
2643/** Kernel32 - LoadLibraryW() */
2644static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryW(LPCWSTR pwszFilename)
2645{
2646 char szTmp[4096];
2647 KSIZE cchTmp = kwUtf16ToStr(pwszFilename, szTmp, sizeof(szTmp));
2648 if (cchTmp < sizeof(szTmp))
2649 return kwSandbox_Kernel32_LoadLibraryExA(szTmp, NULL /*hFile*/, 0 /*fFlags*/);
2650 KWFS_TODO();
2651 SetLastError(ERROR_FILENAME_EXCED_RANGE);
2652 return NULL;
2653}
2654
2655
2656/** Kernel32 - FreeLibrary() */
2657static BOOL WINAPI kwSandbox_Kernel32_FreeLibrary(HMODULE hmod)
2658{
2659 /* Ignored, we like to keep everything loaded. */
2660 return TRUE;
2661}
2662
2663
2664/** Kernel32 - GetModuleHandleA() */
2665static HMODULE WINAPI kwSandbox_Kernel32_GetModuleHandleA(LPCSTR pszModule)
2666{
2667 KSIZE i;
2668 KSIZE cchModule;
2669
2670 /*
2671 * The executable.
2672 */
2673 if (pszModule == NULL)
2674 return (HMODULE)g_Sandbox.pTool->u.Sandboxed.pExe->hOurMod;
2675
2676 /*
2677 * Cache of system modules we've seen queried.
2678 */
2679 cchModule = kHlpStrLen(pszModule);
2680 for (i = 0; i < K_ELEMENTS(g_aGetModuleHandleCache); i++)
2681 if ( g_aGetModuleHandleCache[i].cchName == cchModule
2682 && stricmp(pszModule, g_aGetModuleHandleCache[i].pszName) == 0)
2683 {
2684 if (g_aGetModuleHandleCache[i].hmod != NULL)
2685 return g_aGetModuleHandleCache[i].hmod;
2686 return g_aGetModuleHandleCache[i].hmod = GetModuleHandleA(pszModule);
2687 }
2688
2689 KWFS_TODO();
2690 return NULL;
2691}
2692
2693
2694/** Kernel32 - GetModuleHandleW() */
2695static HMODULE WINAPI kwSandbox_Kernel32_GetModuleHandleW(LPCWSTR pwszModule)
2696{
2697 KSIZE i;
2698 KSIZE cwcModule;
2699
2700 /*
2701 * The executable.
2702 */
2703 if (pwszModule == NULL)
2704 return (HMODULE)g_Sandbox.pTool->u.Sandboxed.pExe->hOurMod;
2705
2706 /*
2707 * Cache of system modules we've seen queried.
2708 */
2709 cwcModule = kwUtf16Len(pwszModule);
2710 for (i = 0; i < K_ELEMENTS(g_aGetModuleHandleCache); i++)
2711 if ( g_aGetModuleHandleCache[i].cwcName == cwcModule
2712 && _wcsicmp(pwszModule, g_aGetModuleHandleCache[i].pwszName) == 0)
2713 {
2714 if (g_aGetModuleHandleCache[i].hmod != NULL)
2715 return g_aGetModuleHandleCache[i].hmod;
2716 return g_aGetModuleHandleCache[i].hmod = GetModuleHandleW(pwszModule);
2717 }
2718
2719 KWFS_TODO();
2720 return NULL;
2721}
2722
2723
2724static PKWMODULE kwSandboxLocateModuleByHandle(PKWSANDBOX pSandbox, HMODULE hmod)
2725{
2726 PKWDYNLOAD pDynLoad;
2727
2728 /* The executable. */
2729 if ( hmod == NULL
2730 || pSandbox->pTool->u.Sandboxed.pExe->hOurMod == hmod)
2731 return kwLdrModuleRetain(pSandbox->pTool->u.Sandboxed.pExe);
2732
2733 /* Dynamically loaded images. */
2734 for (pDynLoad = pSandbox->pTool->u.Sandboxed.pDynLoadHead; pDynLoad != NULL; pDynLoad = pDynLoad->pNext)
2735 if (pDynLoad->hmod == hmod)
2736 {
2737 if (pDynLoad->pMod)
2738 return kwLdrModuleRetain(pDynLoad->pMod);
2739 KWFS_TODO();
2740 return NULL;
2741 }
2742
2743 return NULL;
2744}
2745
2746
2747/** Used to debug dynamically resolved procedures. */
2748static UINT WINAPI kwSandbox_BreakIntoDebugger(void *pv1, void *pv2, void *pv3, void *pv4)
2749{
2750 KWFS_TODO();
2751 return -1;
2752}
2753
2754
2755/** Kernel32 - GetProcAddress() */
2756static FARPROC WINAPI kwSandbox_Kernel32_GetProcAddress(HMODULE hmod, LPCSTR pszProc)
2757{
2758 KSIZE i;
2759
2760 /*
2761 * Try locate the module.
2762 */
2763 PKWMODULE pMod = kwSandboxLocateModuleByHandle(&g_Sandbox, hmod);
2764 if (pMod)
2765 {
2766 KLDRADDR uValue;
2767 int rc = kLdrModQuerySymbol(pMod->pLdrMod,
2768 pMod->fNative ? NULL : pMod->u.Manual.pvBits,
2769 pMod->fNative ? KLDRMOD_BASEADDRESS_MAP : (KUPTR)pMod->u.Manual.pvLoad,
2770 KU32_MAX /*iSymbol*/,
2771 pszProc,
2772 strlen(pszProc),
2773 NULL /*pszVersion*/,
2774 NULL /*pfnGetForwarder*/, NULL /*pvUser*/,
2775 &uValue,
2776 NULL /*pfKind*/);
2777 if (rc == 0)
2778 {
2779 static int s_cDbgGets = 0;
2780 s_cDbgGets++;
2781 KW_LOG(("GetProcAddress(%s, %s) -> %p [%d]\n", pMod->pszPath, pszProc, (KUPTR)uValue, s_cDbgGets));
2782 kwLdrModuleRelease(pMod);
2783 //if (s_cGets >= 3)
2784 // return (FARPROC)kwSandbox_BreakIntoDebugger;
2785 return (FARPROC)(KUPTR)uValue;
2786 }
2787
2788 KWFS_TODO();
2789 SetLastError(ERROR_PROC_NOT_FOUND);
2790 kwLdrModuleRelease(pMod);
2791 return NULL;
2792 }
2793
2794 /*
2795 * Hmm... could be a cached module-by-name.
2796 */
2797 for (i = 0; i < K_ELEMENTS(g_aGetModuleHandleCache); i++)
2798 if (g_aGetModuleHandleCache[i].hmod == hmod)
2799 return GetProcAddress(hmod, pszProc);
2800
2801 KWFS_TODO();
2802 return GetProcAddress(hmod, pszProc);
2803}
2804
2805
2806/** Kernel32 - GetModuleFileNameA() */
2807static DWORD WINAPI kwSandbox_Kernel32_GetModuleFileNameA(HMODULE hmod, LPSTR pszFilename, DWORD cbFilename)
2808{
2809 PKWMODULE pMod = kwSandboxLocateModuleByHandle(&g_Sandbox, hmod);
2810 if (pMod != NULL)
2811 {
2812 DWORD cbRet = kwStrCopyStyle1(pMod->pszPath, pszFilename, cbFilename);
2813 kwLdrModuleRelease(pMod);
2814 return cbRet;
2815 }
2816 KWFS_TODO();
2817 return 0;
2818}
2819
2820
2821/** Kernel32 - GetModuleFileNameW() */
2822static DWORD WINAPI kwSandbox_Kernel32_GetModuleFileNameW(HMODULE hmod, LPWSTR pwszFilename, DWORD cbFilename)
2823{
2824 PKWMODULE pMod = kwSandboxLocateModuleByHandle(&g_Sandbox, hmod);
2825 if (pMod)
2826 {
2827 DWORD cwcRet = kwUtf16CopyStyle1(pMod->pwszPath, pwszFilename, cbFilename);
2828 kwLdrModuleRelease(pMod);
2829 return cwcRet;
2830 }
2831
2832 KWFS_TODO();
2833 return 0;
2834}
2835
2836
2837
2838/*
2839 *
2840 * File access APIs (for speeding them up).
2841 * File access APIs (for speeding them up).
2842 * File access APIs (for speeding them up).
2843 *
2844 */
2845
2846
2847/**
2848 * Converts a lookup error to a windows error code.
2849 *
2850 * @returns The windows error code.
2851 * @param enmError The lookup error.
2852 */
2853static DWORD kwFsLookupErrorToWindowsError(KFSLOOKUPERROR enmError)
2854{
2855 switch (enmError)
2856 {
2857 case KFSLOOKUPERROR_NOT_FOUND:
2858 case KFSLOOKUPERROR_NOT_DIR:
2859 return ERROR_FILE_NOT_FOUND;
2860
2861 case KFSLOOKUPERROR_PATH_COMP_NOT_FOUND:
2862 case KFSLOOKUPERROR_PATH_COMP_NOT_DIR:
2863 return ERROR_PATH_NOT_FOUND;
2864
2865 case KFSLOOKUPERROR_PATH_TOO_LONG:
2866 return ERROR_FILENAME_EXCED_RANGE;
2867
2868 case KFSLOOKUPERROR_OUT_OF_MEMORY:
2869 return ERROR_NOT_ENOUGH_MEMORY;
2870
2871 default:
2872 return ERROR_PATH_NOT_FOUND;
2873 }
2874}
2875
2876#ifdef WITH_TEMP_MEMORY_FILES
2877
2878/**
2879 * Checks for a cl.exe temporary file.
2880 *
2881 * There are quite a bunch of these. They seems to be passing data between the
2882 * first and second compiler pass. Since they're on disk, they get subjected to
2883 * AV software screening and normal file consistency rules. So, not necessarily
2884 * a very efficient way of handling reasonably small amounts of data.
2885 *
2886 * We make the files live in virtual memory by intercepting their opening,
2887 * writing, reading, closing , mapping, unmapping, and maybe some more stuff.
2888 *
2889 * @returns K_TRUE / K_FALSE
2890 * @param pwszFilename The file name being accessed.
2891 */
2892static KBOOL kwFsIsClTempFileW(const wchar_t *pwszFilename)
2893{
2894 wchar_t const *pwszName = kwPathGetFilenameW(pwszFilename);
2895 if (pwszName)
2896 {
2897 /* The name starts with _CL_... */
2898 if ( pwszName[0] == '_'
2899 && pwszName[1] == 'C'
2900 && pwszName[2] == 'L'
2901 && pwszName[3] == '_' )
2902 {
2903 /* ... followed by 8 xdigits and ends with a two letter file type. Simplify
2904 this check by just checking that it's alpha numerical ascii from here on. */
2905 wchar_t wc;
2906 pwszName += 4;
2907 while ((wc = *pwszName++) != '\0')
2908 {
2909 if (wc < 127 && iswalnum(wc))
2910 { /* likely */ }
2911 else
2912 return K_FALSE;
2913 }
2914 return K_TRUE;
2915 }
2916 }
2917 return K_FALSE;
2918}
2919
2920
2921/**
2922 * Creates a handle to a temporary file.
2923 *
2924 * @returns The handle on success.
2925 * INVALID_HANDLE_VALUE and SetLastError on failure.
2926 * @param pTempFile The temporary file.
2927 * @param dwDesiredAccess The desired access to the handle.
2928 * @param fMapping Whether this is a mapping (K_TRUE) or file
2929 * (K_FALSE) handle type.
2930 */
2931static HANDLE kwFsTempFileCreateHandle(PKWFSTEMPFILE pTempFile, DWORD dwDesiredAccess, KBOOL fMapping)
2932{
2933 /*
2934 * Create a handle to the temporary file.
2935 */
2936 HANDLE hFile = INVALID_HANDLE_VALUE;
2937 HANDLE hProcSelf = GetCurrentProcess();
2938 if (DuplicateHandle(hProcSelf, hProcSelf,
2939 hProcSelf, &hFile,
2940 SYNCHRONIZE, FALSE,
2941 0 /*dwOptions*/))
2942 {
2943 PKWHANDLE pHandle = (PKWHANDLE)kHlpAlloc(sizeof(*pHandle));
2944 if (pHandle)
2945 {
2946 pHandle->enmType = !fMapping ? KWHANDLETYPE_TEMP_FILE : KWHANDLETYPE_TEMP_FILE_MAPPING;
2947 pHandle->offFile = 0;
2948 pHandle->hHandle = hFile;
2949 pHandle->dwDesiredAccess = dwDesiredAccess;
2950 pHandle->u.pTempFile = pTempFile;
2951 if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle))
2952 {
2953 pTempFile->cActiveHandles++;
2954 kHlpAssert(pTempFile->cActiveHandles >= 1);
2955 kHlpAssert(pTempFile->cActiveHandles <= 2);
2956 KWFS_LOG(("kwFsTempFileCreateHandle: Temporary file '%ls' -> %p\n", pTempFile->pwszPath, hFile));
2957 return hFile;
2958 }
2959
2960 kHlpFree(pHandle);
2961 }
2962 else
2963 KWFS_LOG(("kwFsTempFileCreateHandle: Out of memory!\n"));
2964 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2965 }
2966 else
2967 KWFS_LOG(("kwFsTempFileCreateHandle: DuplicateHandle failed: err=%u\n", GetLastError()));
2968 return INVALID_HANDLE_VALUE;
2969}
2970
2971
2972static HANDLE kwFsTempFileCreateW(const wchar_t *pwszFilename, DWORD dwDesiredAccess, DWORD dwCreationDisposition)
2973{
2974 HANDLE hFile;
2975 DWORD dwErr;
2976
2977 /*
2978 * Check if we've got an existing temp file.
2979 * ASSUME exact same path for now.
2980 */
2981 KSIZE const cwcFilename = kwUtf16Len(pwszFilename);
2982 PKWFSTEMPFILE pTempFile;
2983 for (pTempFile = g_Sandbox.pTempFileHead; pTempFile != NULL; pTempFile = pTempFile->pNext)
2984 {
2985 /* Since the last two chars are usually the only difference, we check them manually before calling memcmp. */
2986 if ( pTempFile->cwcPath == cwcFilename
2987 && pTempFile->pwszPath[cwcFilename - 1] == pwszFilename[cwcFilename - 1]
2988 && pTempFile->pwszPath[cwcFilename - 2] == pwszFilename[cwcFilename - 2]
2989 && kHlpMemComp(pTempFile->pwszPath, pwszFilename, cwcFilename) == 0)
2990 break;
2991 }
2992
2993 /*
2994 * Create a new temporary file instance if not found.
2995 */
2996 if (pTempFile == NULL)
2997 {
2998 KSIZE cbFilename;
2999
3000 switch (dwCreationDisposition)
3001 {
3002 case CREATE_ALWAYS:
3003 case OPEN_ALWAYS:
3004 dwErr = NO_ERROR;
3005 break;
3006
3007 case CREATE_NEW:
3008 kHlpAssertFailed();
3009 SetLastError(ERROR_ALREADY_EXISTS);
3010 return INVALID_HANDLE_VALUE;
3011
3012 case OPEN_EXISTING:
3013 case TRUNCATE_EXISTING:
3014 kHlpAssertFailed();
3015 SetLastError(ERROR_FILE_NOT_FOUND);
3016 return INVALID_HANDLE_VALUE;
3017
3018 default:
3019 kHlpAssertFailed();
3020 SetLastError(ERROR_INVALID_PARAMETER);
3021 return INVALID_HANDLE_VALUE;
3022 }
3023
3024 cbFilename = (cwcFilename + 1) * sizeof(wchar_t);
3025 pTempFile = (PKWFSTEMPFILE)kHlpAlloc(sizeof(*pTempFile) + cbFilename);
3026 if (pTempFile)
3027 {
3028 pTempFile->cwcPath = (KU16)cwcFilename;
3029 pTempFile->cbFile = 0;
3030 pTempFile->cbFileAllocated = 0;
3031 pTempFile->cActiveHandles = 0;
3032 pTempFile->cMappings = 0;
3033 pTempFile->cSegs = 0;
3034 pTempFile->paSegs = NULL;
3035 pTempFile->pwszPath = (wchar_t const *)kHlpMemCopy(pTempFile + 1, pwszFilename, cbFilename);
3036
3037 pTempFile->pNext = g_Sandbox.pTempFileHead;
3038 g_Sandbox.pTempFileHead = pTempFile;
3039 KWFS_LOG(("kwFsTempFileCreateW: Created new temporary file '%ls'\n", pwszFilename));
3040 }
3041 else
3042 {
3043 KWFS_LOG(("kwFsTempFileCreateW: Out of memory!\n"));
3044 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3045 return INVALID_HANDLE_VALUE;
3046 }
3047 }
3048 else
3049 {
3050 switch (dwCreationDisposition)
3051 {
3052 case OPEN_EXISTING:
3053 dwErr = NO_ERROR;
3054 break;
3055 case OPEN_ALWAYS:
3056 dwErr = ERROR_ALREADY_EXISTS ;
3057 break;
3058
3059 case TRUNCATE_EXISTING:
3060 case CREATE_ALWAYS:
3061 kHlpAssertFailed();
3062 pTempFile->cbFile = 0;
3063 dwErr = ERROR_ALREADY_EXISTS;
3064 break;
3065
3066 case CREATE_NEW:
3067 kHlpAssertFailed();
3068 SetLastError(ERROR_FILE_EXISTS);
3069 return INVALID_HANDLE_VALUE;
3070
3071 default:
3072 kHlpAssertFailed();
3073 SetLastError(ERROR_INVALID_PARAMETER);
3074 return INVALID_HANDLE_VALUE;
3075 }
3076 }
3077
3078 /*
3079 * Create a handle to the temporary file.
3080 */
3081 hFile = kwFsTempFileCreateHandle(pTempFile, dwDesiredAccess, K_FALSE /*fMapping*/);
3082 if (hFile != INVALID_HANDLE_VALUE)
3083 SetLastError(dwErr);
3084 return hFile;
3085}
3086
3087#endif /* WITH_TEMP_MEMORY_FILES */
3088
3089
3090/**
3091 * Checks if the file extension indicates that the file/dir is something we
3092 * ought to cache.
3093 *
3094 * @returns K_TRUE if cachable, K_FALSE if not.
3095 * @param pszExt The kHlpGetExt result.
3096 * @param fAttrQuery Set if it's for an attribute query, clear if for
3097 * file creation.
3098 */
3099static KBOOL kwFsIsCachableExtensionA(const char *pszExt, KBOOL fAttrQuery)
3100{
3101 char const chFirst = *pszExt;
3102
3103 /* C++ header without an extension or a directory. */
3104 if (chFirst == '\0')
3105 {
3106 /** @todo exclude temporary files... */
3107 return K_TRUE;
3108 }
3109
3110 /* C Header: .h */
3111 if (chFirst == 'h' || chFirst == 'H')
3112 {
3113 char chThird;
3114 char const chSecond = pszExt[1];
3115 if (chSecond == '\0')
3116 return K_TRUE;
3117 chThird = pszExt[2];
3118
3119 /* C++ Header: .hpp, .hxx */
3120 if ( (chSecond == 'p' || chSecond == 'P')
3121 && (chThird == 'p' || chThird == 'P')
3122 && pszExt[3] == '\0')
3123 return K_TRUE;
3124 if ( (chSecond == 'x' || chSecond == 'X')
3125 && (chThird == 'x' || chThird == 'X')
3126 && pszExt[3] == '\0')
3127 return K_TRUE;
3128
3129 }
3130 /* Misc starting with i. */
3131 else if (chFirst == 'i' || chFirst == 'I')
3132 {
3133 char const chSecond = pszExt[1];
3134 if (chSecond != '\0')
3135 {
3136 if (chSecond == 'n' || chSecond == 'N')
3137 {
3138 char const chThird = pszExt[2];
3139
3140 /* C++ inline header: .inl */
3141 if ( (chThird == 'l' || chThird == 'L')
3142 && pszExt[3] == '\0')
3143 return K_TRUE;
3144
3145 /* Assembly include file: .inc */
3146 if ( (chThird == 'c' || chThird == 'C')
3147 && pszExt[3] == '\0')
3148 return K_TRUE;
3149 }
3150 }
3151 }
3152 else if (fAttrQuery)
3153 {
3154 /* Dynamic link library: .dll */
3155 if (chFirst == 'd' || chFirst == 'D')
3156 {
3157 char const chSecond = pszExt[1];
3158 if (chSecond == 'l' || chSecond == 'L')
3159 {
3160 char const chThird = pszExt[2];
3161 if (chThird == 'l' || chThird == 'L')
3162 return K_TRUE;
3163 }
3164 }
3165 /* Executable file: .exe */
3166 else if (chFirst == 'e' || chFirst == 'E')
3167 {
3168 char const chSecond = pszExt[1];
3169 if (chSecond == 'x' || chSecond == 'X')
3170 {
3171 char const chThird = pszExt[2];
3172 if (chThird == 'e' || chThird == 'e')
3173 return K_TRUE;
3174 }
3175 }
3176 }
3177
3178 return K_FALSE;
3179}
3180
3181
3182/**
3183 * Checks if the extension of the given UTF-16 path indicates that the file/dir
3184 * should be cached.
3185 *
3186 * @returns K_TRUE if cachable, K_FALSE if not.
3187 * @param pwszPath The UTF-16 path to examine.
3188 * @param fAttrQuery Set if it's for an attribute query, clear if for
3189 * file creation.
3190 */
3191static KBOOL kwFsIsCachablePathExtensionW(const wchar_t *pwszPath, KBOOL fAttrQuery)
3192{
3193 /*
3194 * Extract the extension, check that it's in the applicable range, roughly
3195 * convert it to ASCII/ANSI, and feed it to kwFsIsCachableExtensionA for
3196 * the actual check. This avoids a lot of code duplication.
3197 */
3198 wchar_t wc;
3199 char szExt[4];
3200 KSIZE cwcExt;
3201 wchar_t const *pwszExt = kwFsPathGetExtW(pwszPath, &cwcExt);
3202 switch (cwcExt)
3203 {
3204 case 3: if ((wchar_t)(szExt[2] = (char)(wc = pwszExt[2])) == wc) { /*likely*/ } else break;
3205 case 2: if ((wchar_t)(szExt[1] = (char)(wc = pwszExt[1])) == wc) { /*likely*/ } else break;
3206 case 1: if ((wchar_t)(szExt[0] = (char)(wc = pwszExt[0])) == wc) { /*likely*/ } else break;
3207 case 0:
3208 szExt[cwcExt] = '\0';
3209 return kwFsIsCachableExtensionA(szExt, fAttrQuery);
3210 }
3211 return K_FALSE;
3212}
3213
3214
3215
3216/**
3217 * Creates a new
3218 *
3219 * @returns
3220 * @param pFsObj .
3221 * @param pwszFilename .
3222 */
3223static PKFSWCACHEDFILE kwFsObjCacheNewFile(PKFSOBJ pFsObj)
3224{
3225 HANDLE hFile;
3226 MY_IO_STATUS_BLOCK Ios;
3227 MY_OBJECT_ATTRIBUTES ObjAttr;
3228 MY_UNICODE_STRING UniStr;
3229 MY_NTSTATUS rcNt;
3230
3231 /*
3232 * Open the file relative to the parent directory.
3233 */
3234 kHlpAssert(pFsObj->bObjType == KFSOBJ_TYPE_FILE);
3235 kHlpAssert(pFsObj->pParent);
3236 kHlpAssertReturn(pFsObj->pParent->hDir != INVALID_HANDLE_VALUE, NULL);
3237
3238 Ios.Information = -1;
3239 Ios.u.Status = -1;
3240
3241 UniStr.Buffer = (wchar_t *)pFsObj->pwszName;
3242 UniStr.Length = (USHORT)(pFsObj->cwcName * sizeof(wchar_t));
3243 UniStr.MaximumLength = UniStr.Length + sizeof(wchar_t);
3244
3245 MyInitializeObjectAttributes(&ObjAttr, &UniStr, OBJ_CASE_INSENSITIVE, pFsObj->pParent->hDir, NULL /*pSecAttr*/);
3246
3247 rcNt = g_pfnNtCreateFile(&hFile,
3248 GENERIC_READ | SYNCHRONIZE,
3249 &ObjAttr,
3250 &Ios,
3251 NULL, /*cbFileInitialAlloc */
3252 FILE_ATTRIBUTE_NORMAL,
3253 FILE_SHARE_READ,
3254 FILE_OPEN,
3255 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
3256 NULL, /*pEaBuffer*/
3257 0); /*cbEaBuffer*/
3258 if (MY_NT_SUCCESS(rcNt))
3259 {
3260 /*
3261 * Read the whole file into memory.
3262 */
3263 LARGE_INTEGER cbFile;
3264 if (GetFileSizeEx(hFile, &cbFile))
3265 {
3266 if ( cbFile.QuadPart >= 0
3267 && cbFile.QuadPart < 16*1024*1024)
3268 {
3269 KU32 cbCache = (KU32)cbFile.QuadPart;
3270 KU8 *pbCache = (KU8 *)kHlpAlloc(cbCache);
3271 if (pbCache)
3272 {
3273 DWORD cbActually = 0;
3274 if ( ReadFile(hFile, pbCache, cbCache, &cbActually, NULL)
3275 && cbActually == cbCache)
3276 {
3277 LARGE_INTEGER offZero;
3278 offZero.QuadPart = 0;
3279 if (SetFilePointerEx(hFile, offZero, NULL /*poffNew*/, FILE_BEGIN))
3280 {
3281 /*
3282 * Create the cached file object.
3283 */
3284 PKFSWCACHEDFILE pCachedFile;
3285 pCachedFile = (PKFSWCACHEDFILE)kFsCacheObjAddUserData(g_pFsCache, pFsObj, KW_DATA_KEY_CACHED_FILE,
3286 sizeof(*pCachedFile));
3287 if (pCachedFile)
3288 {
3289 pCachedFile->hCached = hFile;
3290 pCachedFile->cbCached = cbCache;
3291 pCachedFile->pbCached = pbCache;
3292 pCachedFile->pFsObj = pFsObj;
3293 kFsCacheObjRetain(pFsObj);
3294 return pCachedFile;
3295 }
3296
3297 KWFS_LOG(("Failed to allocate KFSWCACHEDFILE structure!\n"));
3298 }
3299 else
3300 KWFS_LOG(("Failed to seek to start of cached file! err=%u\n", GetLastError()));
3301 }
3302 else
3303 KWFS_LOG(("Failed to read %#x bytes into cache! err=%u cbActually=%#x\n",
3304 cbCache, GetLastError(), cbActually));
3305 kHlpFree(pbCache);
3306 }
3307 else
3308 KWFS_LOG(("Failed to allocate %#x bytes for cache!\n", cbCache));
3309 }
3310 else
3311 KWFS_LOG(("File to big to cache! %#llx\n", cbFile.QuadPart));
3312 }
3313 else
3314 KWFS_LOG(("File to get file size! err=%u\n", GetLastError()));
3315 g_pfnNtClose(hFile);
3316 }
3317 else
3318 KWFS_LOG(("Error opening '%ls' for caching: %#x\n", pFsObj->pwszName, rcNt));
3319 return NULL;
3320}
3321
3322
3323/**
3324 * Kernel32 - Common code for CreateFileW and CreateFileA.
3325 */
3326static KBOOL kwFsObjCacheCreateFile(PKFSOBJ pFsObj, DWORD dwDesiredAccess, BOOL fInheritHandle, HANDLE *phFile)
3327{
3328 *phFile = INVALID_HANDLE_VALUE;
3329 kHlpAssert(pFsObj->fHaveStats);
3330
3331 /*
3332 * At the moment we only handle existing files.
3333 */
3334 if (pFsObj->bObjType == KFSOBJ_TYPE_FILE)
3335 {
3336 PKFSWCACHEDFILE pCachedFile = (PKFSWCACHEDFILE)kFsCacheObjGetUserData(g_pFsCache, pFsObj, KW_DATA_KEY_CACHED_FILE);
3337 if ( pCachedFile != NULL
3338 || (pCachedFile = kwFsObjCacheNewFile(pFsObj)) != NULL)
3339 {
3340 HANDLE hProcSelf = GetCurrentProcess();
3341 if (DuplicateHandle(hProcSelf, pCachedFile->hCached,
3342 hProcSelf, phFile,
3343 dwDesiredAccess, fInheritHandle,
3344 0 /*dwOptions*/))
3345 {
3346 /*
3347 * Create handle table entry for the duplicate handle.
3348 */
3349 PKWHANDLE pHandle = (PKWHANDLE)kHlpAlloc(sizeof(*pHandle));
3350 if (pHandle)
3351 {
3352 pHandle->enmType = KWHANDLETYPE_FSOBJ_READ_CACHE;
3353 pHandle->offFile = 0;
3354 pHandle->hHandle = *phFile;
3355 pHandle->dwDesiredAccess = dwDesiredAccess;
3356 pHandle->u.pCachedFile = pCachedFile;
3357 if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle))
3358 return K_TRUE;
3359
3360 kHlpFree(pHandle);
3361 }
3362 else
3363 KWFS_LOG(("Out of memory for handle!\n"));
3364
3365 CloseHandle(*phFile);
3366 *phFile = INVALID_HANDLE_VALUE;
3367 }
3368 else
3369 KWFS_LOG(("DuplicateHandle failed! err=%u\n", GetLastError()));
3370 }
3371 }
3372 /** @todo Deal with non-existing files if it becomes necessary (it's not for VS2010). */
3373
3374 /* Do fallback, please. */
3375 return K_FALSE;
3376}
3377
3378
3379/** Kernel32 - CreateFileA */
3380static HANDLE WINAPI kwSandbox_Kernel32_CreateFileA(LPCSTR pszFilename, DWORD dwDesiredAccess, DWORD dwShareMode,
3381 LPSECURITY_ATTRIBUTES pSecAttrs, DWORD dwCreationDisposition,
3382 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
3383{
3384 HANDLE hFile;
3385 if (dwCreationDisposition == FILE_OPEN_IF)
3386 {
3387 if ( dwDesiredAccess == GENERIC_READ
3388 || dwDesiredAccess == FILE_GENERIC_READ)
3389 {
3390 if (dwShareMode & FILE_SHARE_READ)
3391 {
3392 if ( !pSecAttrs
3393 || ( pSecAttrs->nLength == sizeof(*pSecAttrs)
3394 && pSecAttrs->lpSecurityDescriptor == NULL ) )
3395 {
3396 const char *pszExt = kHlpGetExt(pszFilename);
3397 if (kwFsIsCachableExtensionA(pszExt, K_FALSE /*fAttrQuery*/))
3398 {
3399 KFSLOOKUPERROR enmError;
3400 PKFSOBJ pFsObj = kFsCacheLookupNoMissingA(g_pFsCache, pszFilename, &enmError);
3401 if (pFsObj)
3402 {
3403 KBOOL fRc = kwFsObjCacheCreateFile(pFsObj, dwDesiredAccess, pSecAttrs && pSecAttrs->bInheritHandle,
3404 &hFile);
3405 kFsCacheObjRelease(g_pFsCache, pFsObj);
3406 if (fRc)
3407 {
3408 KWFS_LOG(("CreateFileA(%s) -> %p [cached]\n", pszFilename, hFile));
3409 return hFile;
3410 }
3411 }
3412
3413 /* fallback */
3414 hFile = CreateFileA(pszFilename, dwDesiredAccess, dwShareMode, pSecAttrs,
3415 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
3416 KWFS_LOG(("CreateFileA(%s) -> %p (err=%u) [fallback]\n", pszFilename, hFile, GetLastError()));
3417 return hFile;
3418 }
3419 }
3420 }
3421 }
3422 }
3423
3424 hFile = CreateFileA(pszFilename, dwDesiredAccess, dwShareMode, pSecAttrs,
3425 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
3426 KWFS_LOG(("CreateFileA(%s) -> %p\n", pszFilename, hFile));
3427 return hFile;
3428}
3429
3430
3431/** Kernel32 - CreateFileW */
3432static HANDLE WINAPI kwSandbox_Kernel32_CreateFileW(LPCWSTR pwszFilename, DWORD dwDesiredAccess, DWORD dwShareMode,
3433 LPSECURITY_ATTRIBUTES pSecAttrs, DWORD dwCreationDisposition,
3434 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
3435{
3436 HANDLE hFile;
3437
3438#ifdef WITH_TEMP_MEMORY_FILES
3439 /* First check for temporary files (cl.exe only). */
3440 if ( g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL
3441 && !(dwFlagsAndAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE | FILE_FLAG_BACKUP_SEMANTICS))
3442 && !(dwDesiredAccess & (GENERIC_EXECUTE | FILE_EXECUTE))
3443 && kwFsIsClTempFileW(pwszFilename))
3444 {
3445 hFile = kwFsTempFileCreateW(pwszFilename, dwDesiredAccess, dwCreationDisposition);
3446 KWFS_LOG(("CreateFileW(%ls) -> %p [temp]\n", pwszFilename, hFile));
3447 return hFile;
3448 }
3449#endif
3450
3451 /* Then check for include files and similar. */
3452 if (dwCreationDisposition == FILE_OPEN_IF)
3453 {
3454 if ( dwDesiredAccess == GENERIC_READ
3455 || dwDesiredAccess == FILE_GENERIC_READ)
3456 {
3457 if (dwShareMode & FILE_SHARE_READ)
3458 {
3459 if ( !pSecAttrs
3460 || ( pSecAttrs->nLength == sizeof(*pSecAttrs)
3461 && pSecAttrs->lpSecurityDescriptor == NULL ) )
3462 {
3463 if (kwFsIsCachablePathExtensionW(pwszFilename, K_FALSE /*fAttrQuery*/))
3464 {
3465 /** @todo rewrite to pure UTF-16. */
3466 char szTmp[2048];
3467 KSIZE cch = kwUtf16ToStr(pwszFilename, szTmp, sizeof(szTmp));
3468 if (cch < sizeof(szTmp))
3469 return kwSandbox_Kernel32_CreateFileA(szTmp, dwDesiredAccess, dwShareMode, pSecAttrs,
3470 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
3471 }
3472 }
3473 else
3474 KWFS_LOG(("CreateFileW: incompatible security attributes (nLength=%#x pDesc=%p)\n",
3475 pSecAttrs->nLength, pSecAttrs->lpSecurityDescriptor));
3476 }
3477 else
3478 KWFS_LOG(("CreateFileW: incompatible sharing mode %#x\n", dwShareMode));
3479 }
3480 else
3481 KWFS_LOG(("CreateFileW: incompatible desired access %#x\n", dwDesiredAccess));
3482 }
3483 else
3484 KWFS_LOG(("CreateFileW: incompatible disposition %u\n", dwCreationDisposition));
3485 hFile = CreateFileW(pwszFilename, dwDesiredAccess, dwShareMode, pSecAttrs,
3486 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
3487 KWFS_LOG(("CreateFileW(%ls) -> %p\n", pwszFilename, hFile));
3488 return hFile;
3489}
3490
3491
3492/** Kernel32 - SetFilePointer */
3493static DWORD WINAPI kwSandbox_Kernel32_SetFilePointer(HANDLE hFile, LONG cbMove, PLONG pcbMoveHi, DWORD dwMoveMethod)
3494{
3495 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
3496 if (idxHandle < g_Sandbox.cHandles)
3497 {
3498 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
3499 if (pHandle != NULL)
3500 {
3501 KU32 cbFile;
3502 KI64 offMove = pcbMoveHi ? ((KI64)*pcbMoveHi << 32) | cbMove : cbMove;
3503 switch (pHandle->enmType)
3504 {
3505 case KWHANDLETYPE_FSOBJ_READ_CACHE:
3506 cbFile = pHandle->u.pCachedFile->cbCached;
3507 break;
3508#ifdef WITH_TEMP_MEMORY_FILES
3509 case KWHANDLETYPE_TEMP_FILE:
3510 cbFile = pHandle->u.pTempFile->cbFile;
3511 break;
3512 case KWHANDLETYPE_TEMP_FILE_MAPPING:
3513#endif
3514 default:
3515 kHlpAssertFailed();
3516 SetLastError(ERROR_INVALID_FUNCTION);
3517 return INVALID_SET_FILE_POINTER;
3518 }
3519
3520 switch (dwMoveMethod)
3521 {
3522 case FILE_BEGIN:
3523 break;
3524 case FILE_CURRENT:
3525 offMove += pHandle->offFile;
3526 break;
3527 case FILE_END:
3528 offMove += cbFile;
3529 break;
3530 default:
3531 KWFS_LOG(("SetFilePointer(%p) - invalid seek method %u! [cached]\n", hFile));
3532 SetLastError(ERROR_INVALID_PARAMETER);
3533 return INVALID_SET_FILE_POINTER;
3534 }
3535 if (offMove >= 0)
3536 {
3537 if (offMove >= (KSSIZE)cbFile)
3538 {
3539 /* For read-only files, seeking beyond the end isn't useful to us, so clamp it. */
3540 if (pHandle->enmType != KWHANDLETYPE_TEMP_FILE)
3541 offMove = (KSSIZE)cbFile;
3542 /* For writable files, seeking beyond the end is fine, but check that we've got
3543 the type range for the request. */
3544 else if (((KU64)offMove & KU32_MAX) != (KU64)offMove)
3545 {
3546 kHlpAssertMsgFailed(("%#llx\n", offMove));
3547 SetLastError(ERROR_SEEK);
3548 return INVALID_SET_FILE_POINTER;
3549 }
3550 }
3551 pHandle->offFile = (KU32)offMove;
3552 }
3553 else
3554 {
3555 KWFS_LOG(("SetFilePointer(%p) - negative seek! [cached]\n", hFile));
3556 SetLastError(ERROR_NEGATIVE_SEEK);
3557 return INVALID_SET_FILE_POINTER;
3558 }
3559 if (pcbMoveHi)
3560 *pcbMoveHi = (KU64)offMove >> 32;
3561 KWFS_LOG(("SetFilePointer(%p) -> %#llx [cached]\n", hFile, offMove));
3562 SetLastError(NO_ERROR);
3563 return (KU32)offMove;
3564 }
3565 }
3566 KWFS_LOG(("SetFilePointer(%p)\n", hFile));
3567 return SetFilePointer(hFile, cbMove, pcbMoveHi, dwMoveMethod);
3568}
3569
3570
3571/** Kernel32 - SetFilePointerEx */
3572static BOOL WINAPI kwSandbox_Kernel32_SetFilePointerEx(HANDLE hFile, LARGE_INTEGER offMove, PLARGE_INTEGER poffNew,
3573 DWORD dwMoveMethod)
3574{
3575 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
3576 if (idxHandle < g_Sandbox.cHandles)
3577 {
3578 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
3579 if (pHandle != NULL)
3580 {
3581 KI64 offMyMove = offMove.QuadPart;
3582 KU32 cbFile;
3583 switch (pHandle->enmType)
3584 {
3585 case KWHANDLETYPE_FSOBJ_READ_CACHE:
3586 cbFile = pHandle->u.pCachedFile->cbCached;
3587 break;
3588#ifdef WITH_TEMP_MEMORY_FILES
3589 case KWHANDLETYPE_TEMP_FILE:
3590 cbFile = pHandle->u.pTempFile->cbFile;
3591 break;
3592 case KWHANDLETYPE_TEMP_FILE_MAPPING:
3593#endif
3594 default:
3595 kHlpAssertFailed();
3596 SetLastError(ERROR_INVALID_FUNCTION);
3597 return INVALID_SET_FILE_POINTER;
3598 }
3599
3600 switch (dwMoveMethod)
3601 {
3602 case FILE_BEGIN:
3603 break;
3604 case FILE_CURRENT:
3605 offMyMove += pHandle->offFile;
3606 break;
3607 case FILE_END:
3608 offMyMove += cbFile;
3609 break;
3610 default:
3611 KWFS_LOG(("SetFilePointer(%p) - invalid seek method %u! [cached]\n", hFile));
3612 SetLastError(ERROR_INVALID_PARAMETER);
3613 return INVALID_SET_FILE_POINTER;
3614 }
3615 if (offMyMove >= 0)
3616 {
3617 if (offMyMove >= (KSSIZE)cbFile)
3618 {
3619 /* For read-only files, seeking beyond the end isn't useful to us, so clamp it. */
3620 if (pHandle->enmType != KWHANDLETYPE_TEMP_FILE)
3621 offMyMove = (KSSIZE)cbFile;
3622 /* For writable files, seeking beyond the end is fine, but check that we've got
3623 the type range for the request. */
3624 else if (((KU64)offMyMove & KU32_MAX) != (KU64)offMyMove)
3625 {
3626 kHlpAssertMsgFailed(("%#llx\n", offMyMove));
3627 SetLastError(ERROR_SEEK);
3628 return INVALID_SET_FILE_POINTER;
3629 }
3630 }
3631 pHandle->offFile = (KU32)offMyMove;
3632 }
3633 else
3634 {
3635 KWFS_LOG(("SetFilePointerEx(%p) - negative seek! [cached]\n", hFile));
3636 SetLastError(ERROR_NEGATIVE_SEEK);
3637 return INVALID_SET_FILE_POINTER;
3638 }
3639 if (poffNew)
3640 poffNew->QuadPart = offMyMove;
3641 KWFS_LOG(("SetFilePointerEx(%p) -> TRUE, %#llx [cached]\n", hFile, offMyMove));
3642 return TRUE;
3643 }
3644 }
3645 KWFS_LOG(("SetFilePointerEx(%p)\n", hFile));
3646 return SetFilePointerEx(hFile, offMove, poffNew, dwMoveMethod);
3647}
3648
3649
3650/** Kernel32 - ReadFile */
3651static BOOL WINAPI kwSandbox_Kernel32_ReadFile(HANDLE hFile, LPVOID pvBuffer, DWORD cbToRead, LPDWORD pcbActuallyRead,
3652 LPOVERLAPPED pOverlapped)
3653{
3654 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
3655 if (idxHandle < g_Sandbox.cHandles)
3656 {
3657 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
3658 if (pHandle != NULL)
3659 {
3660 switch (pHandle->enmType)
3661 {
3662 case KWHANDLETYPE_FSOBJ_READ_CACHE:
3663 {
3664 PKFSWCACHEDFILE pCachedFile = pHandle->u.pCachedFile;
3665 KU32 cbActually = pCachedFile->cbCached - pHandle->offFile;
3666 if (cbActually > cbToRead)
3667 cbActually = cbToRead;
3668 else if (cbActually < cbToRead)
3669 ((KU8 *)pvBuffer)[cbActually] = '\0'; // hack hack hack
3670
3671 kHlpMemCopy(pvBuffer, &pCachedFile->pbCached[pHandle->offFile], cbActually);
3672 pHandle->offFile += cbActually;
3673
3674 kHlpAssert(!pOverlapped); kHlpAssert(pcbActuallyRead);
3675 *pcbActuallyRead = cbActually;
3676
3677 KWFS_LOG(("ReadFile(%p,,%#x) -> TRUE, %#x bytes [cached]\n", hFile, cbToRead, cbActually));
3678 return TRUE;
3679 }
3680
3681#ifdef WITH_TEMP_MEMORY_FILES
3682 case KWHANDLETYPE_TEMP_FILE:
3683 {
3684 PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile;
3685 KU32 cbActually;
3686 if (pHandle->offFile < pTempFile->cbFile)
3687 {
3688 cbActually = pTempFile->cbFile - pHandle->offFile;
3689 if (cbActually > cbToRead)
3690 cbActually = cbToRead;
3691
3692 /* Copy the data. */
3693 if (cbActually > 0)
3694 {
3695 KU32 cbLeft;
3696 KU32 offSeg;
3697 KWFSTEMPFILESEG const *paSegs = pTempFile->paSegs;
3698
3699 /* Locate the segment containing the byte at offFile. */
3700 KU32 iSeg = pTempFile->cSegs - 1;
3701 kHlpAssert(pTempFile->cSegs > 0);
3702 while (paSegs[iSeg].offData > pHandle->offFile)
3703 iSeg--;
3704
3705 /* Copy out the data. */
3706 cbLeft = cbActually;
3707 offSeg = (pHandle->offFile - paSegs[iSeg].offData);
3708 for (;;)
3709 {
3710 KU32 cbAvail = paSegs[iSeg].cbDataAlloc - offSeg;
3711 if (cbAvail >= cbLeft)
3712 {
3713 kHlpMemCopy(pvBuffer, &paSegs[iSeg].pbData[offSeg], cbLeft);
3714 break;
3715 }
3716
3717 pvBuffer = kHlpMemPCopy(pvBuffer, &paSegs[iSeg].pbData[offSeg], cbAvail);
3718 cbLeft -= cbAvail;
3719 offSeg = 0;
3720 iSeg++;
3721 kHlpAssert(iSeg < pTempFile->cSegs);
3722 }
3723
3724 /* Update the file offset. */
3725 pHandle->offFile += cbActually;
3726 }
3727 }
3728 /* Read does not commit file space, so return zero bytes. */
3729 else
3730 cbActually = 0;
3731
3732 kHlpAssert(!pOverlapped); kHlpAssert(pcbActuallyRead);
3733 *pcbActuallyRead = cbActually;
3734
3735 KWFS_LOG(("ReadFile(%p,,%#x) -> TRUE, %#x bytes [temp]\n", hFile, cbToRead, (KU32)cbActually));
3736 return TRUE;
3737 }
3738
3739 case KWHANDLETYPE_TEMP_FILE_MAPPING:
3740#endif /* WITH_TEMP_MEMORY_FILES */
3741 default:
3742 kHlpAssertFailed();
3743 SetLastError(ERROR_INVALID_FUNCTION);
3744 *pcbActuallyRead = 0;
3745 return FALSE;
3746 }
3747 }
3748 }
3749
3750 KWFS_LOG(("ReadFile(%p)\n", hFile));
3751 return ReadFile(hFile, pvBuffer, cbToRead, pcbActuallyRead, pOverlapped);
3752}
3753
3754
3755/** Kernel32 - ReadFileEx */
3756static BOOL WINAPI kwSandbox_Kernel32_ReadFileEx(HANDLE hFile, LPVOID pvBuffer, DWORD cbToRead, LPOVERLAPPED pOverlapped,
3757 LPOVERLAPPED_COMPLETION_ROUTINE pfnCompletionRoutine)
3758{
3759 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
3760 if (idxHandle < g_Sandbox.cHandles)
3761 {
3762 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
3763 if (pHandle != NULL)
3764 {
3765 kHlpAssertFailed();
3766 }
3767 }
3768
3769 KWFS_LOG(("ReadFile(%p)\n", hFile));
3770 return ReadFileEx(hFile, pvBuffer, cbToRead, pOverlapped, pfnCompletionRoutine);
3771}
3772
3773#ifdef WITH_TEMP_MEMORY_FILES
3774
3775static KBOOL kwFsTempFileEnsureSpace(PKWFSTEMPFILE pTempFile, KU32 offFile, KU32 cbNeeded)
3776{
3777 KU32 cbMinFile = offFile + cbNeeded;
3778 if (cbMinFile >= offFile)
3779 {
3780 /* Calc how much space we've already allocated and */
3781 if (cbMinFile <= pTempFile->cbFileAllocated)
3782 return K_TRUE;
3783
3784 /* Grow the file. */
3785 if (cbMinFile <= KWFS_TEMP_FILE_MAX)
3786 {
3787 int rc;
3788 KU32 cSegs = pTempFile->cSegs;
3789 KU32 cbNewSeg = cbMinFile > 4*1024*1024 ? 256*1024 : 4*1024*1024;
3790 do
3791 {
3792 /* grow the segment array? */
3793 if ((cSegs % 16) == 0)
3794 {
3795 void *pvNew = kHlpRealloc(pTempFile->paSegs, (cSegs + 16) * sizeof(pTempFile->paSegs[0]));
3796 if (!pvNew)
3797 return K_FALSE;
3798 pTempFile->paSegs = (PKWFSTEMPFILESEG)pvNew;
3799 }
3800
3801 /* Use page alloc here to simplify mapping later. */
3802 rc = kHlpPageAlloc((void **)&pTempFile->paSegs[cSegs].pbData, cbNewSeg, KPROT_READWRITE, K_FALSE);
3803 if (rc == 0)
3804 { /* likely */ }
3805 else
3806 {
3807 cbNewSeg = 64*1024;
3808 rc = kHlpPageAlloc((void **)&pTempFile->paSegs[cSegs].pbData, cbNewSeg, KPROT_READWRITE, K_FALSE);
3809 if (rc != 0)
3810 {
3811 kHlpAssertFailed();
3812 return K_FALSE;
3813 }
3814 }
3815 pTempFile->paSegs[cSegs].offData = pTempFile->cbFileAllocated;
3816 pTempFile->paSegs[cSegs].cbDataAlloc = cbNewSeg;
3817 pTempFile->cbFileAllocated += cbNewSeg;
3818 pTempFile->cSegs = ++cSegs;
3819
3820 } while (pTempFile->cbFileAllocated < cbMinFile);
3821
3822 return K_TRUE;
3823 }
3824 }
3825
3826 kHlpAssertMsgFailed(("Out of bounds offFile=%#x + cbNeeded=%#x = %#x\n", offFile, cbNeeded, offFile + cbNeeded));
3827 return K_FALSE;
3828}
3829
3830
3831/** Kernel32 - WriteFile */
3832static BOOL WINAPI kwSandbox_Kernel32_WriteFile(HANDLE hFile, LPCVOID pvBuffer, DWORD cbToWrite, LPDWORD pcbActuallyWritten,
3833 LPOVERLAPPED pOverlapped)
3834{
3835 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
3836 if (idxHandle < g_Sandbox.cHandles)
3837 {
3838 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
3839 if (pHandle != NULL)
3840 {
3841 switch (pHandle->enmType)
3842 {
3843 case KWHANDLETYPE_TEMP_FILE:
3844 {
3845 PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile;
3846
3847 kHlpAssert(!pOverlapped);
3848 kHlpAssert(pcbActuallyWritten);
3849
3850 if (kwFsTempFileEnsureSpace(pTempFile, pHandle->offFile, cbToWrite))
3851 {
3852 KU32 cbLeft;
3853 KU32 offSeg;
3854
3855 /* Locate the segment containing the byte at offFile. */
3856 KWFSTEMPFILESEG const *paSegs = pTempFile->paSegs;
3857 KU32 iSeg = pTempFile->cSegs - 1;
3858 kHlpAssert(pTempFile->cSegs > 0);
3859 while (paSegs[iSeg].offData > pHandle->offFile)
3860 iSeg--;
3861
3862 /* Copy in the data. */
3863 cbLeft = cbToWrite;
3864 offSeg = (pHandle->offFile - paSegs[iSeg].offData);
3865 for (;;)
3866 {
3867 KU32 cbAvail = paSegs[iSeg].cbDataAlloc - offSeg;
3868 if (cbAvail >= cbLeft)
3869 {
3870 kHlpMemCopy(&paSegs[iSeg].pbData[offSeg], pvBuffer, cbLeft);
3871 break;
3872 }
3873
3874 kHlpMemCopy(&paSegs[iSeg].pbData[offSeg], pvBuffer, cbAvail);
3875 pvBuffer = (KU8 const *)pvBuffer + cbAvail;
3876 cbLeft -= cbAvail;
3877 offSeg = 0;
3878 iSeg++;
3879 kHlpAssert(iSeg < pTempFile->cSegs);
3880 }
3881
3882 /* Update the file offset. */
3883 pHandle->offFile += cbToWrite;
3884 if (pHandle->offFile > pTempFile->cbFile)
3885 pTempFile->cbFile = pHandle->offFile;
3886
3887 *pcbActuallyWritten = cbToWrite;
3888 KWFS_LOG(("WriteFile(%p,,%#x) -> TRUE [temp]\n", hFile, cbToWrite));
3889 return TRUE;
3890 }
3891
3892 kHlpAssertFailed();
3893 *pcbActuallyWritten = 0;
3894 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3895 return FALSE;
3896 }
3897
3898 case KWHANDLETYPE_FSOBJ_READ_CACHE:
3899 kHlpAssertFailed();
3900 SetLastError(ERROR_ACCESS_DENIED);
3901 *pcbActuallyWritten = 0;
3902 return FALSE;
3903
3904 default:
3905 case KWHANDLETYPE_TEMP_FILE_MAPPING:
3906 kHlpAssertFailed();
3907 SetLastError(ERROR_INVALID_FUNCTION);
3908 *pcbActuallyWritten = 0;
3909 return FALSE;
3910 }
3911 }
3912 }
3913
3914 KWFS_LOG(("WriteFile(%p)\n", hFile));
3915 return WriteFile(hFile, pvBuffer, cbToWrite, pcbActuallyWritten, pOverlapped);
3916}
3917
3918
3919/** Kernel32 - WriteFileEx */
3920static BOOL WINAPI kwSandbox_Kernel32_WriteFileEx(HANDLE hFile, LPCVOID pvBuffer, DWORD cbToWrite, LPOVERLAPPED pOverlapped,
3921 LPOVERLAPPED_COMPLETION_ROUTINE pfnCompletionRoutine)
3922{
3923 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
3924 if (idxHandle < g_Sandbox.cHandles)
3925 {
3926 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
3927 if (pHandle != NULL)
3928 {
3929 kHlpAssertFailed();
3930 }
3931 }
3932
3933 KWFS_LOG(("WriteFileEx(%p)\n", hFile));
3934 return WriteFileEx(hFile, pvBuffer, cbToWrite, pOverlapped, pfnCompletionRoutine);
3935}
3936
3937
3938/** Kernel32 - SetEndOfFile; */
3939static BOOL WINAPI kwSandbox_Kernel32_SetEndOfFile(HANDLE hFile)
3940{
3941 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
3942 if (idxHandle < g_Sandbox.cHandles)
3943 {
3944 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
3945 if (pHandle != NULL)
3946 {
3947 switch (pHandle->enmType)
3948 {
3949 case KWHANDLETYPE_TEMP_FILE:
3950 {
3951 PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile;
3952 if ( pHandle->offFile > pTempFile->cbFile
3953 && !kwFsTempFileEnsureSpace(pTempFile, pHandle->offFile, 0))
3954 {
3955 kHlpAssertFailed();
3956 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3957 return FALSE;
3958 }
3959
3960 pTempFile->cbFile = pHandle->offFile;
3961 KWFS_LOG(("SetEndOfFile(%p) -> TRUE (cbFile=%#x)\n", hFile, pTempFile->cbFile));
3962 return TRUE;
3963 }
3964
3965 case KWHANDLETYPE_FSOBJ_READ_CACHE:
3966 kHlpAssertFailed();
3967 SetLastError(ERROR_ACCESS_DENIED);
3968 return FALSE;
3969
3970 default:
3971 case KWHANDLETYPE_TEMP_FILE_MAPPING:
3972 kHlpAssertFailed();
3973 SetLastError(ERROR_INVALID_FUNCTION);
3974 return FALSE;
3975 }
3976 }
3977 }
3978
3979 KWFS_LOG(("SetEndOfFile(%p)\n", hFile));
3980 return SetEndOfFile(hFile);
3981}
3982
3983
3984/** Kernel32 - GetFileType */
3985static BOOL WINAPI kwSandbox_Kernel32_GetFileType(HANDLE hFile)
3986{
3987 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
3988 if (idxHandle < g_Sandbox.cHandles)
3989 {
3990 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
3991 if (pHandle != NULL)
3992 {
3993 switch (pHandle->enmType)
3994 {
3995 case KWHANDLETYPE_FSOBJ_READ_CACHE:
3996 KWFS_LOG(("GetFileType(%p) -> FILE_TYPE_DISK [cached]\n", hFile));
3997 return FILE_TYPE_DISK;
3998
3999 case KWHANDLETYPE_TEMP_FILE:
4000 KWFS_LOG(("GetFileType(%p) -> FILE_TYPE_DISK [temp]\n", hFile));
4001 return FILE_TYPE_DISK;
4002 }
4003 }
4004 }
4005
4006 KWFS_LOG(("GetFileType(%p)\n", hFile));
4007 return GetFileType(hFile);
4008}
4009
4010
4011/** Kernel32 - GetFileSize */
4012static DWORD WINAPI kwSandbox_Kernel32_GetFileSize(HANDLE hFile, LPDWORD pcbHighDword)
4013{
4014 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
4015 if (idxHandle < g_Sandbox.cHandles)
4016 {
4017 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
4018 if (pHandle != NULL)
4019 {
4020 if (pcbHighDword)
4021 *pcbHighDword = 0;
4022 SetLastError(NO_ERROR);
4023 switch (pHandle->enmType)
4024 {
4025 case KWHANDLETYPE_FSOBJ_READ_CACHE:
4026 KWFS_LOG(("GetFileSize(%p) -> %#x [cached]\n", hFile, pHandle->u.pCachedFile->cbCached));
4027 return pHandle->u.pCachedFile->cbCached;
4028
4029 case KWHANDLETYPE_TEMP_FILE:
4030 KWFS_LOG(("GetFileSize(%p) -> %#x [temp]\n", hFile, pHandle->u.pTempFile->cbFile));
4031 return pHandle->u.pTempFile->cbFile;
4032
4033 default:
4034 kHlpAssertFailed();
4035 SetLastError(ERROR_INVALID_FUNCTION);
4036 return INVALID_FILE_SIZE;
4037 }
4038 }
4039 }
4040
4041 KWFS_LOG(("GetFileSize(%p,)\n", hFile));
4042 return GetFileSize(hFile, pcbHighDword);
4043}
4044
4045
4046/** Kernel32 - GetFileSizeEx */
4047static BOOL WINAPI kwSandbox_Kernel32_GetFileSizeEx(HANDLE hFile, PLARGE_INTEGER pcbFile)
4048{
4049 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
4050 if (idxHandle < g_Sandbox.cHandles)
4051 {
4052 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
4053 if (pHandle != NULL)
4054 {
4055 switch (pHandle->enmType)
4056 {
4057 case KWHANDLETYPE_FSOBJ_READ_CACHE:
4058 KWFS_LOG(("GetFileSizeEx(%p) -> TRUE, %#x [cached]\n", hFile, pHandle->u.pCachedFile->cbCached));
4059 pcbFile->QuadPart = pHandle->u.pCachedFile->cbCached;
4060 return TRUE;
4061
4062 case KWHANDLETYPE_TEMP_FILE:
4063 KWFS_LOG(("GetFileSizeEx(%p) -> TRUE, %#x [temp]\n", hFile, pHandle->u.pTempFile->cbFile));
4064 pcbFile->QuadPart = pHandle->u.pTempFile->cbFile;
4065 return TRUE;
4066
4067 default:
4068 kHlpAssertFailed();
4069 SetLastError(ERROR_INVALID_FUNCTION);
4070 return INVALID_FILE_SIZE;
4071 }
4072 }
4073 }
4074
4075 KWFS_LOG(("GetFileSizeEx(%p,)\n", hFile));
4076 return GetFileSizeEx(hFile, pcbFile);
4077}
4078
4079
4080/** Kernel32 - CreateFileMapping */
4081static HANDLE WINAPI kwSandbox_Kernel32_CreateFileMappingW(HANDLE hFile, LPSECURITY_ATTRIBUTES pSecAttrs,
4082 DWORD fProtect, DWORD dwMaximumSizeHigh,
4083 DWORD dwMaximumSizeLow, LPCWSTR pwszName)
4084{
4085 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
4086 if (idxHandle < g_Sandbox.cHandles)
4087 {
4088 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
4089 if (pHandle != NULL)
4090 {
4091 switch (pHandle->enmType)
4092 {
4093 case KWHANDLETYPE_TEMP_FILE:
4094 {
4095 PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile;
4096 if ( ( fProtect == PAGE_READONLY
4097 || fProtect == PAGE_EXECUTE_READ)
4098 && dwMaximumSizeHigh == 0
4099 && ( dwMaximumSizeLow == 0
4100 || dwMaximumSizeLow == pTempFile->cbFile)
4101 && pwszName == NULL)
4102 {
4103 HANDLE hMapping = kwFsTempFileCreateHandle(pHandle->u.pTempFile, GENERIC_READ, K_TRUE /*fMapping*/);
4104 KWFS_LOG(("CreateFileMappingW(%p, %u) -> %p [temp]\n", hFile, fProtect, hMapping));
4105 return hMapping;
4106 }
4107 kHlpAssertMsgFailed(("fProtect=%#x cb=%#x'%08x name=%p\n",
4108 fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName));
4109 SetLastError(ERROR_ACCESS_DENIED);
4110 return INVALID_HANDLE_VALUE;
4111 }
4112 }
4113 }
4114 }
4115
4116 KWFS_LOG(("CreateFileMappingW(%p)\n", hFile));
4117 return CreateFileMappingW(hFile, pSecAttrs, fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName);
4118}
4119
4120/** Kernel32 - MapViewOfFile */
4121static HANDLE WINAPI kwSandbox_Kernel32_MapViewOfFile(HANDLE hSection, DWORD dwDesiredAccess,
4122 DWORD offFileHigh, DWORD offFileLow, SIZE_T cbToMap)
4123{
4124 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hSection);
4125 if (idxHandle < g_Sandbox.cHandles)
4126 {
4127 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
4128 if (pHandle != NULL)
4129 {
4130 switch (pHandle->enmType)
4131 {
4132 case KWHANDLETYPE_FSOBJ_READ_CACHE:
4133 case KWHANDLETYPE_TEMP_FILE:
4134 kHlpAssertFailed();
4135 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4136 return NULL;
4137
4138 case KWHANDLETYPE_TEMP_FILE_MAPPING:
4139 {
4140 PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile;
4141 if ( dwDesiredAccess == FILE_MAP_READ
4142 && offFileHigh == 0
4143 && offFileLow == 0
4144 && (cbToMap == 0 || cbToMap == pTempFile->cbFile) )
4145 {
4146 kHlpAssert(pTempFile->cMappings == 0 || pTempFile->cSegs == 1);
4147 if (pTempFile->cSegs != 1)
4148 {
4149 KU32 iSeg;
4150 KU32 cbLeft;
4151 KU32 cbAll = pTempFile->cbFile ? (KU32)K_ALIGN_Z(pTempFile->cbFile, 0x2000) : 0x1000;
4152 KU8 *pbAll = NULL;
4153 int rc = kHlpPageAlloc((void **)&pbAll, cbAll, KPROT_READWRITE, K_FALSE);
4154 if (rc != 0)
4155 {
4156 kHlpAssertFailed();
4157 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4158 return NULL;
4159 }
4160
4161 cbLeft = pTempFile->cbFile;
4162 for (iSeg = 0; iSeg < pTempFile->cSegs && cbLeft > 0; iSeg++)
4163 {
4164 KU32 cbToCopy = K_MIN(cbLeft, pTempFile->paSegs[iSeg].cbDataAlloc);
4165 kHlpMemCopy(&pbAll[pTempFile->paSegs[iSeg].offData], pTempFile->paSegs[iSeg].pbData, cbToCopy);
4166 cbLeft -= cbToCopy;
4167 }
4168
4169 for (iSeg = 0; iSeg < pTempFile->cSegs; iSeg++)
4170 {
4171 kHlpPageFree(pTempFile->paSegs[iSeg].pbData, pTempFile->paSegs[iSeg].cbDataAlloc);
4172 pTempFile->paSegs[iSeg].pbData = NULL;
4173 pTempFile->paSegs[iSeg].cbDataAlloc = 0;
4174 }
4175
4176 pTempFile->cSegs = 1;
4177 pTempFile->cbFileAllocated = cbAll;
4178 pTempFile->paSegs[0].cbDataAlloc = cbAll;
4179 pTempFile->paSegs[0].pbData = pbAll;
4180 pTempFile->paSegs[0].offData = 0;
4181 }
4182
4183 pTempFile->cMappings++;
4184 kHlpAssert(pTempFile->cMappings == 1);
4185
4186 KWFS_LOG(("CreateFileMappingW(%p) -> %p [temp]\n", hSection, pTempFile->paSegs[0].pbData));
4187 return pTempFile->paSegs[0].pbData;
4188 }
4189
4190 kHlpAssertMsgFailed(("dwDesiredAccess=%#x offFile=%#x'%08x cbToMap=%#x (cbFile=%#x)\n",
4191 dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pTempFile->cbFile));
4192 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4193 return NULL;
4194 }
4195 }
4196 }
4197 }
4198
4199 KWFS_LOG(("MapViewOfFile(%p)\n", hSection));
4200 return MapViewOfFile(hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap);
4201}
4202/** @todo MapViewOfFileEx */
4203
4204
4205/** Kernel32 - UnmapViewOfFile */
4206static BOOL WINAPI kwSandbox_Kernel32_UnmapViewOfFile(LPCVOID pvBase)
4207{
4208 /* Is this one of our temporary mappings? */
4209 PKWFSTEMPFILE pCur = g_Sandbox.pTempFileHead;
4210 while (pCur)
4211 {
4212 if ( pCur->cMappings > 0
4213 && pCur->paSegs[0].pbData == (KU8 *)pvBase)
4214 {
4215 pCur->cMappings--;
4216 KWFS_LOG(("UnmapViewOfFile(%p) -> TRUE [temp]\n", pvBase));
4217 return TRUE;
4218 }
4219 pCur = pCur->pNext;
4220 }
4221
4222 KWFS_LOG(("UnmapViewOfFile(%p)\n", pvBase));
4223 return UnmapViewOfFile(pvBase);
4224}
4225
4226/** @todo UnmapViewOfFileEx */
4227
4228
4229#endif /* WITH_TEMP_MEMORY_FILES */
4230
4231/** Kernel32 - CloseHandle */
4232static BOOL WINAPI kwSandbox_Kernel32_CloseHandle(HANDLE hObject)
4233{
4234 BOOL fRet;
4235 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hObject);
4236 if ( idxHandle < g_Sandbox.cHandles
4237 && g_Sandbox.papHandles[idxHandle] != NULL)
4238 {
4239 fRet = CloseHandle(hObject);
4240 if (fRet)
4241 {
4242 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
4243 g_Sandbox.papHandles[idxHandle] = NULL;
4244 g_Sandbox.cActiveHandles--;
4245#ifdef WITH_TEMP_MEMORY_FILES
4246 if (pHandle->enmType == KWHANDLETYPE_TEMP_FILE)
4247 {
4248 kHlpAssert(pHandle->u.pTempFile->cActiveHandles > 0);
4249 pHandle->u.pTempFile->cActiveHandles--;
4250 }
4251#endif
4252 kHlpFree(pHandle);
4253 KWFS_LOG(("CloseHandle(%p) -> TRUE [intercepted handle]\n", hObject));
4254 }
4255 else
4256 KWFS_LOG(("CloseHandle(%p) -> FALSE [intercepted handle] err=%u!\n", hObject, GetLastError()));
4257 }
4258 else
4259 {
4260 KWFS_LOG(("CloseHandle(%p)\n", hObject));
4261 fRet = CloseHandle(hObject);
4262 }
4263 return fRet;
4264}
4265
4266
4267/** Kernel32 - GetFileAttributesA. */
4268static DWORD WINAPI kwSandbox_Kernel32_GetFileAttributesA(LPCSTR pszFilename)
4269{
4270 DWORD fRet;
4271 const char *pszExt = kHlpGetExt(pszFilename);
4272 if (kwFsIsCachableExtensionA(pszExt, K_TRUE /*fAttrQuery*/))
4273 {
4274 KFSLOOKUPERROR enmError;
4275 PKFSOBJ pFsObj = kFsCacheLookupNoMissingA(g_pFsCache, pszFilename, &enmError);
4276 if (pFsObj)
4277 {
4278 kHlpAssert(pFsObj->fHaveStats);
4279 fRet = pFsObj->Stats.st_attribs;
4280 kFsCacheObjRelease(g_pFsCache, pFsObj);
4281 }
4282 else
4283 {
4284 SetLastError(kwFsLookupErrorToWindowsError(enmError));
4285 fRet = INVALID_FILE_ATTRIBUTES;
4286 }
4287
4288 KWFS_LOG(("GetFileAttributesA(%s) -> %#x [cached]\n", pszFilename, fRet));
4289 return fRet;
4290 }
4291
4292 fRet = GetFileAttributesA(pszFilename);
4293 KWFS_LOG(("GetFileAttributesA(%s) -> %#x\n", pszFilename, fRet));
4294 return fRet;
4295}
4296
4297
4298/** Kernel32 - GetFileAttributesW. */
4299static DWORD WINAPI kwSandbox_Kernel32_GetFileAttributesW(LPCWSTR pwszFilename)
4300{
4301 DWORD fRet;
4302 if (kwFsIsCachablePathExtensionW(pwszFilename, K_TRUE /*fAttrQuery*/))
4303 {
4304 KFSLOOKUPERROR enmError;
4305 PKFSOBJ pFsObj = kFsCacheLookupNoMissingW(g_pFsCache, pwszFilename, &enmError);
4306 if (pFsObj)
4307 {
4308 kHlpAssert(pFsObj->fHaveStats);
4309 fRet = pFsObj->Stats.st_attribs;
4310 kFsCacheObjRelease(g_pFsCache, pFsObj);
4311 }
4312 else
4313 {
4314 SetLastError(kwFsLookupErrorToWindowsError(enmError));
4315 fRet = INVALID_FILE_ATTRIBUTES;
4316 }
4317
4318 KWFS_LOG(("GetFileAttributesW(%ls) -> %#x [cached]\n", pwszFilename, fRet));
4319 return fRet;
4320 }
4321
4322 fRet = GetFileAttributesW(pwszFilename);
4323 KWFS_LOG(("GetFileAttributesW(%ls) -> %#x\n", pwszFilename, fRet));
4324 return fRet;
4325}
4326
4327
4328/** Kernel32 - GetShortPathNameW - c1[xx].dll of VS2010 does this to the
4329 * directory containing each include file. We cache the result to speed
4330 * things up a little. */
4331static DWORD WINAPI kwSandbox_Kernel32_GetShortPathNameW(LPCWSTR pwszLongPath, LPWSTR pwszShortPath, DWORD cwcShortPath)
4332{
4333 DWORD cwcRet;
4334 if (kwFsIsCachablePathExtensionW(pwszLongPath, K_TRUE /*fAttrQuery*/))
4335 {
4336 KFSLOOKUPERROR enmError;
4337 PKFSOBJ pObj = kFsCacheLookupW(g_pFsCache, pwszLongPath, &enmError);
4338 if (pObj)
4339 {
4340 if (pObj->bObjType != KFSOBJ_TYPE_MISSING)
4341 {
4342 if (kFsCacheObjGetFullShortPathW(pObj, pwszShortPath, cwcShortPath, '\\'))
4343 {
4344 cwcRet = (DWORD)kwUtf16Len(pwszShortPath);
4345
4346 /* Should preserve trailing slash on directory paths. */
4347 if (pObj->bObjType == KFSOBJ_TYPE_DIR)
4348 {
4349 if ( cwcRet + 1 < cwcShortPath
4350 && pwszShortPath[cwcRet - 1] != '\\')
4351 {
4352 KSIZE cwcIn = kwUtf16Len(pwszLongPath);
4353 if ( cwcIn > 0
4354 && (pwszLongPath[cwcIn - 1] == '\\' || pwszLongPath[cwcIn - 1] == '/') )
4355 {
4356 pwszShortPath[cwcRet++] = '\\';
4357 pwszShortPath[cwcRet] = '\0';
4358 }
4359 }
4360 }
4361
4362 KWFS_LOG(("GetShortPathNameW(%ls) -> '%*.*ls' & %#x [cached]\n",
4363 pwszLongPath, K_MIN(cwcShortPath, cwcRet), K_MIN(cwcShortPath, cwcRet), pwszShortPath, cwcRet));
4364 kFsCacheObjRelease(g_pFsCache, pObj);
4365 return cwcRet;
4366 }
4367
4368 /* fall back for complicated cases. */
4369 }
4370 kFsCacheObjRelease(g_pFsCache, pObj);
4371 }
4372 }
4373 cwcRet = GetShortPathNameW(pwszLongPath, pwszShortPath, cwcShortPath);
4374 KWFS_LOG(("GetShortPathNameW(%ls) -> '%*.*ls' & %#x\n",
4375 pwszLongPath, K_MIN(cwcShortPath, cwcRet), K_MIN(cwcShortPath, cwcRet), pwszShortPath, cwcRet));
4376 return cwcRet;
4377}
4378
4379
4380
4381/*
4382 *
4383 * Virtual memory leak prevension.
4384 * Virtual memory leak prevension.
4385 * Virtual memory leak prevension.
4386 *
4387 */
4388
4389/** Kernel32 - VirtualAlloc - for c1[xx].dll 78GB leaks. */
4390static PVOID WINAPI kwSandbox_Kernel32_VirtualAlloc(PVOID pvAddr, SIZE_T cb, DWORD fAllocType, DWORD fProt)
4391{
4392 PVOID pvMem = VirtualAlloc(pvAddr, cb, fAllocType, fProt);
4393 KW_LOG(("VirtualAlloc: pvAddr=%p cb=%p type=%#x prot=%#x -> %p (last=%d)\n",
4394 pvAddr, cb, fAllocType, fProt, pvMem, GetLastError()));
4395 if ( g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL
4396 && pvMem)
4397 {
4398 PKWVIRTALLOC pTracker = g_Sandbox.pVirtualAllocHead;
4399 while ( pTracker
4400 && (KUPTR)pvMem - (KUPTR)pTracker->pvAlloc >= pTracker->cbAlloc)
4401 pTracker = pTracker->pNext;
4402 if (!pTracker)
4403 {
4404 DWORD dwErr = GetLastError();
4405 PKWVIRTALLOC pTracker = (PKWVIRTALLOC)kHlpAlloc(sizeof(*pTracker));
4406 if (pTracker)
4407 {
4408 pTracker->pvAlloc = pvMem;
4409 pTracker->cbAlloc = cb;
4410 pTracker->pNext = g_Sandbox.pVirtualAllocHead;
4411 g_Sandbox.pVirtualAllocHead = pTracker;
4412 }
4413 SetLastError(dwErr);
4414 }
4415 }
4416 return pvMem;
4417}
4418
4419
4420/** Kernel32 - VirtualFree. */
4421static BOOL WINAPI kwSandbox_Kernel32_VirtualFree(PVOID pvAddr, SIZE_T cb, DWORD dwFreeType)
4422{
4423 BOOL fRc = VirtualFree(pvAddr, cb, dwFreeType);
4424 KW_LOG(("VirtualFree: pvAddr=%p cb=%p type=%#x -> %d\n", pvAddr, cb, dwFreeType, fRc));
4425 if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL)
4426 {
4427 if (dwFreeType & MEM_RELEASE)
4428 {
4429 PKWVIRTALLOC pTracker = g_Sandbox.pVirtualAllocHead;
4430 if (pTracker)
4431 {
4432 if (pTracker->pvAlloc == pvAddr)
4433 g_Sandbox.pVirtualAllocHead = pTracker->pNext;
4434 else
4435 {
4436 PKWVIRTALLOC pPrev;
4437 do
4438 {
4439 pPrev = pTracker;
4440 pTracker = pTracker->pNext;
4441 } while (pTracker && pTracker->pvAlloc != pvAddr);
4442 if (pTracker)
4443 pPrev->pNext = pTracker->pNext;
4444 }
4445 if (pTracker)
4446 kHlpFree(pTracker);
4447 else
4448 KW_LOG(("VirtualFree: pvAddr=%p not found!\n", pvAddr));
4449 }
4450 }
4451 }
4452 return fRc;
4453}
4454
4455
4456
4457/*
4458 *
4459 * Thread/Fiber local storage leak prevention.
4460 * Thread/Fiber local storage leak prevention.
4461 * Thread/Fiber local storage leak prevention.
4462 *
4463 * Note! The FlsAlloc/Free causes problems for statically linked VS2010
4464 * code like VBoxBs3ObjConverter.exe. One thing is that we're
4465 * leaking these indexes, but more importantely we crash during
4466 * worker exit since the callback is triggered multiple times.
4467 */
4468
4469
4470/** Kernel32 - FlsAlloc */
4471DWORD WINAPI kwSandbox_Kernel32_FlsAlloc(PFLS_CALLBACK_FUNCTION pfnCallback)
4472{
4473 DWORD idxFls = FlsAlloc(pfnCallback);
4474 KW_LOG(("FlsAlloc(%p) -> %#x\n", pfnCallback, idxFls));
4475 if (idxFls != FLS_OUT_OF_INDEXES)
4476 {
4477 PKWLOCALSTORAGE pTracker = (PKWLOCALSTORAGE)kHlpAlloc(sizeof(*pTracker));
4478 if (pTracker)
4479 {
4480 pTracker->idx = idxFls;
4481 pTracker->pNext = g_Sandbox.pFlsAllocHead;
4482 g_Sandbox.pFlsAllocHead = pTracker;
4483 }
4484 }
4485
4486 return idxFls;
4487}
4488
4489/** Kernel32 - FlsFree */
4490BOOL WINAPI kwSandbox_Kernel32_FlsFree(DWORD idxFls)
4491{
4492 BOOL fRc = FlsFree(idxFls);
4493 KW_LOG(("FlsFree(%#x) -> %d\n", idxFls, fRc));
4494 if (fRc)
4495 {
4496 PKWLOCALSTORAGE pTracker = g_Sandbox.pFlsAllocHead;
4497 if (pTracker)
4498 {
4499 if (pTracker->idx == idxFls)
4500 g_Sandbox.pFlsAllocHead = pTracker->pNext;
4501 else
4502 {
4503 PKWLOCALSTORAGE pPrev;
4504 do
4505 {
4506 pPrev = pTracker;
4507 pTracker = pTracker->pNext;
4508 } while (pTracker && pTracker->idx != idxFls);
4509 if (pTracker)
4510 pPrev->pNext = pTracker->pNext;
4511 }
4512 if (pTracker)
4513 {
4514 pTracker->idx = FLS_OUT_OF_INDEXES;
4515 pTracker->pNext = NULL;
4516 kHlpFree(pTracker);
4517 }
4518 }
4519 }
4520 return fRc;
4521}
4522
4523
4524
4525/*
4526 *
4527 * Misc function only intercepted while debugging.
4528 * Misc function only intercepted while debugging.
4529 * Misc function only intercepted while debugging.
4530 *
4531 */
4532
4533#ifndef NDEBUG
4534
4535/** CRT - memcpy */
4536static void * __cdecl kwSandbox_msvcrt_memcpy(void *pvDst, void const *pvSrc, size_t cb)
4537{
4538 KU8 const *pbSrc = (KU8 const *)pvSrc;
4539 KU8 *pbDst = (KU8 *)pvDst;
4540 KSIZE cbLeft = cb;
4541 while (cbLeft-- > 0)
4542 *pbDst++ = *pbSrc++;
4543 return pvDst;
4544}
4545
4546#endif /* NDEBUG */
4547
4548
4549
4550/**
4551 * Functions that needs replacing for sandboxed execution.
4552 */
4553KWREPLACEMENTFUNCTION const g_aSandboxReplacements[] =
4554{
4555 /*
4556 * Kernel32.dll and friends.
4557 */
4558 { TUPLE("ExitProcess"), NULL, (KUPTR)kwSandbox_Kernel32_ExitProcess },
4559 { TUPLE("TerminateProcess"), NULL, (KUPTR)kwSandbox_Kernel32_TerminateProcess },
4560
4561 { TUPLE("LoadLibraryA"), NULL, (KUPTR)kwSandbox_Kernel32_LoadLibraryA },
4562 { TUPLE("LoadLibraryW"), NULL, (KUPTR)kwSandbox_Kernel32_LoadLibraryW },
4563 { TUPLE("LoadLibraryExA"), NULL, (KUPTR)kwSandbox_Kernel32_LoadLibraryExA },
4564 { TUPLE("LoadLibraryExW"), NULL, (KUPTR)kwSandbox_Kernel32_LoadLibraryExW },
4565 { TUPLE("FreeLibrary"), NULL, (KUPTR)kwSandbox_Kernel32_FreeLibrary },
4566 { TUPLE("GetModuleHandleA"), NULL, (KUPTR)kwSandbox_Kernel32_GetModuleHandleA },
4567 { TUPLE("GetModuleHandleW"), NULL, (KUPTR)kwSandbox_Kernel32_GetModuleHandleW },
4568 { TUPLE("GetProcAddress"), NULL, (KUPTR)kwSandbox_Kernel32_GetProcAddress },
4569 { TUPLE("GetModuleFileNameA"), NULL, (KUPTR)kwSandbox_Kernel32_GetModuleFileNameA },
4570 { TUPLE("GetModuleFileNameW"), NULL, (KUPTR)kwSandbox_Kernel32_GetModuleFileNameW },
4571
4572 { TUPLE("GetCommandLineA"), NULL, (KUPTR)kwSandbox_Kernel32_GetCommandLineA },
4573 { TUPLE("GetCommandLineW"), NULL, (KUPTR)kwSandbox_Kernel32_GetCommandLineW },
4574 { TUPLE("GetStartupInfoA"), NULL, (KUPTR)kwSandbox_Kernel32_GetStartupInfoA },
4575 { TUPLE("GetStartupInfoW"), NULL, (KUPTR)kwSandbox_Kernel32_GetStartupInfoW },
4576
4577 { TUPLE("CreateThread"), NULL, (KUPTR)kwSandbox_Kernel32_CreateThread },
4578
4579 { TUPLE("GetEnvironmentVariableA"), NULL, (KUPTR)kwSandbox_Kernel32_GetEnvironmentVariableA },
4580 { TUPLE("GetEnvironmentVariableW"), NULL, (KUPTR)kwSandbox_Kernel32_GetEnvironmentVariableW },
4581 { TUPLE("SetEnvironmentVariableA"), NULL, (KUPTR)kwSandbox_Kernel32_SetEnvironmentVariableA },
4582 { TUPLE("SetEnvironmentVariableW"), NULL, (KUPTR)kwSandbox_Kernel32_SetEnvironmentVariableW },
4583 { TUPLE("ExpandEnvironmentStringsA"), NULL, (KUPTR)kwSandbox_Kernel32_ExpandEnvironmentStringsA },
4584 { TUPLE("ExpandEnvironmentStringsW"), NULL, (KUPTR)kwSandbox_Kernel32_ExpandEnvironmentStringsW },
4585
4586 { TUPLE("CreateFileA"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileA },
4587 { TUPLE("CreateFileW"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileW },
4588 { TUPLE("ReadFile"), NULL, (KUPTR)kwSandbox_Kernel32_ReadFile },
4589 { TUPLE("ReadFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_ReadFileEx },
4590#ifdef WITH_TEMP_MEMORY_FILES
4591 { TUPLE("WriteFile"), NULL, (KUPTR)kwSandbox_Kernel32_WriteFile },
4592 { TUPLE("WriteFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_WriteFileEx },
4593 { TUPLE("SetEndOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_SetEndOfFile },
4594 { TUPLE("GetFileType"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileType },
4595 { TUPLE("GetFileSize"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileSize },
4596 { TUPLE("GetFileSizeEx"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileSizeEx },
4597 { TUPLE("CreateFileMappingW"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileMappingW },
4598 { TUPLE("MapViewOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_MapViewOfFile },
4599 { TUPLE("UnmapViewOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_UnmapViewOfFile },
4600#endif
4601 { TUPLE("SetFilePointer"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointer },
4602 { TUPLE("SetFilePointerEx"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointerEx },
4603 { TUPLE("CloseHandle"), NULL, (KUPTR)kwSandbox_Kernel32_CloseHandle },
4604 { TUPLE("GetFileAttributesA"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesA },
4605 { TUPLE("GetFileAttributesW"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesW },
4606 { TUPLE("GetShortPathNameW"), NULL, (KUPTR)kwSandbox_Kernel32_GetShortPathNameW },
4607
4608 { TUPLE("VirtualAlloc"), NULL, (KUPTR)kwSandbox_Kernel32_VirtualAlloc },
4609 { TUPLE("VirtualFree"), NULL, (KUPTR)kwSandbox_Kernel32_VirtualFree },
4610
4611 { TUPLE("FlsAlloc"), NULL, (KUPTR)kwSandbox_Kernel32_FlsAlloc },
4612 { TUPLE("FlsFree"), NULL, (KUPTR)kwSandbox_Kernel32_FlsFree },
4613
4614 /*
4615 * MS Visual C++ CRTs.
4616 */
4617 { TUPLE("exit"), NULL, (KUPTR)kwSandbox_msvcrt_exit },
4618 { TUPLE("_exit"), NULL, (KUPTR)kwSandbox_msvcrt__exit },
4619 { TUPLE("_cexit"), NULL, (KUPTR)kwSandbox_msvcrt__cexit },
4620 { TUPLE("_c_exit"), NULL, (KUPTR)kwSandbox_msvcrt__c_exit },
4621 { TUPLE("_amsg_exit"), NULL, (KUPTR)kwSandbox_msvcrt__amsg_exit },
4622 { TUPLE("terminate"), NULL, (KUPTR)kwSandbox_msvcrt_terminate },
4623
4624 { TUPLE("_beginthread"), NULL, (KUPTR)kwSandbox_msvcrt__beginthread },
4625 { TUPLE("_beginthreadex"), NULL, (KUPTR)kwSandbox_msvcrt__beginthreadex },
4626
4627 { TUPLE("__argc"), NULL, (KUPTR)&g_Sandbox.cArgs },
4628 { TUPLE("__argv"), NULL, (KUPTR)&g_Sandbox.papszArgs },
4629 { TUPLE("__wargv"), NULL, (KUPTR)&g_Sandbox.papwszArgs },
4630 { TUPLE("__p___argc"), NULL, (KUPTR)kwSandbox_msvcrt___p___argc },
4631 { TUPLE("__p___argv"), NULL, (KUPTR)kwSandbox_msvcrt___p___argv },
4632 { TUPLE("__p___wargv"), NULL, (KUPTR)kwSandbox_msvcrt___p___wargv },
4633 { TUPLE("_acmdln"), NULL, (KUPTR)&g_Sandbox.pszCmdLine },
4634 { TUPLE("_wcmdln"), NULL, (KUPTR)&g_Sandbox.pwszCmdLine },
4635 { TUPLE("__p__acmdln"), NULL, (KUPTR)kwSandbox_msvcrt___p__acmdln },
4636 { TUPLE("__p__wcmdln"), NULL, (KUPTR)kwSandbox_msvcrt___p__wcmdln },
4637 { TUPLE("_pgmptr"), NULL, (KUPTR)&g_Sandbox.pgmptr },
4638 { TUPLE("_wpgmptr"), NULL, (KUPTR)&g_Sandbox.wpgmptr },
4639 { TUPLE("_get_pgmptr"), NULL, (KUPTR)kwSandbox_msvcrt__get_pgmptr },
4640 { TUPLE("_get_wpgmptr"), NULL, (KUPTR)kwSandbox_msvcrt__get_wpgmptr },
4641 { TUPLE("__p__pgmptr"), NULL, (KUPTR)kwSandbox_msvcrt___p__pgmptr },
4642 { TUPLE("__p__wpgmptr"), NULL, (KUPTR)kwSandbox_msvcrt___p__wpgmptr },
4643 { TUPLE("_wincmdln"), NULL, (KUPTR)kwSandbox_msvcrt__wincmdln },
4644 { TUPLE("_wwincmdln"), NULL, (KUPTR)kwSandbox_msvcrt__wwincmdln },
4645 { TUPLE("__getmainargs"), NULL, (KUPTR)kwSandbox_msvcrt___getmainargs},
4646 { TUPLE("__wgetmainargs"), NULL, (KUPTR)kwSandbox_msvcrt___wgetmainargs},
4647
4648 { TUPLE("_putenv"), NULL, (KUPTR)kwSandbox_msvcrt__putenv},
4649 { TUPLE("_wputenv"), NULL, (KUPTR)kwSandbox_msvcrt__wputenv},
4650 { TUPLE("_putenv_s"), NULL, (KUPTR)kwSandbox_msvcrt__putenv_s},
4651 { TUPLE("_wputenv_s"), NULL, (KUPTR)kwSandbox_msvcrt__wputenv_s},
4652 { TUPLE("__initenv"), NULL, (KUPTR)&g_Sandbox.initenv },
4653 { TUPLE("__winitenv"), NULL, (KUPTR)&g_Sandbox.winitenv },
4654 { TUPLE("__p___initenv"), NULL, (KUPTR)kwSandbox_msvcrt___p___initenv},
4655 { TUPLE("__p___winitenv"), NULL, (KUPTR)kwSandbox_msvcrt___p___winitenv},
4656 { TUPLE("_environ"), NULL, (KUPTR)&g_Sandbox.environ },
4657 { TUPLE("_wenviron"), NULL, (KUPTR)&g_Sandbox.wenviron },
4658 { TUPLE("_get_environ"), NULL, (KUPTR)kwSandbox_msvcrt__get_environ },
4659 { TUPLE("_get_wenviron"), NULL, (KUPTR)kwSandbox_msvcrt__get_wenviron },
4660 { TUPLE("__p__environ"), NULL, (KUPTR)kwSandbox_msvcrt___p__environ },
4661 { TUPLE("__p__wenviron"), NULL, (KUPTR)kwSandbox_msvcrt___p__wenviron },
4662
4663#ifndef NDEBUG
4664 { TUPLE("memcpy"), NULL, (KUPTR)kwSandbox_msvcrt_memcpy },
4665#endif
4666};
4667/** Number of entries in g_aReplacements. */
4668KU32 const g_cSandboxReplacements = K_ELEMENTS(g_aSandboxReplacements);
4669
4670
4671/**
4672 * Functions that needs replacing in natively loaded DLLs when doing sandboxed
4673 * execution.
4674 */
4675KWREPLACEMENTFUNCTION const g_aSandboxNativeReplacements[] =
4676{
4677 /*
4678 * Kernel32.dll and friends.
4679 */
4680 { TUPLE("ExitProcess"), NULL, (KUPTR)kwSandbox_Kernel32_ExitProcess },
4681 { TUPLE("TerminateProcess"), NULL, (KUPTR)kwSandbox_Kernel32_TerminateProcess },
4682
4683#if 0
4684 { TUPLE("CreateThread"), NULL, (KUPTR)kwSandbox_Kernel32_CreateThread },
4685#endif
4686
4687 { TUPLE("CreateFileA"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileA },
4688 { TUPLE("CreateFileW"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileW },
4689 { TUPLE("ReadFile"), NULL, (KUPTR)kwSandbox_Kernel32_ReadFile },
4690 { TUPLE("ReadFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_ReadFileEx },
4691#ifdef WITH_TEMP_MEMORY_FILES
4692 { TUPLE("WriteFile"), NULL, (KUPTR)kwSandbox_Kernel32_WriteFile },
4693 { TUPLE("WriteFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_WriteFileEx },
4694 { TUPLE("SetEndOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_SetEndOfFile },
4695 { TUPLE("GetFileType"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileType },
4696 { TUPLE("GetFileSize"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileSize },
4697 { TUPLE("GetFileSizeEx"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileSizeEx },
4698 { TUPLE("CreateFileMappingW"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileMappingW },
4699 { TUPLE("MapViewOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_MapViewOfFile },
4700 { TUPLE("UnmapViewOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_UnmapViewOfFile },
4701#endif
4702 { TUPLE("SetFilePointer"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointer },
4703 { TUPLE("SetFilePointerEx"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointerEx },
4704 { TUPLE("CloseHandle"), NULL, (KUPTR)kwSandbox_Kernel32_CloseHandle },
4705 { TUPLE("GetFileAttributesA"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesA },
4706 { TUPLE("GetFileAttributesW"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesW },
4707 { TUPLE("GetShortPathNameW"), NULL, (KUPTR)kwSandbox_Kernel32_GetShortPathNameW },
4708
4709 /*
4710 * MS Visual C++ CRTs.
4711 */
4712 { TUPLE("exit"), NULL, (KUPTR)kwSandbox_msvcrt_exit },
4713 { TUPLE("_exit"), NULL, (KUPTR)kwSandbox_msvcrt__exit },
4714 { TUPLE("_cexit"), NULL, (KUPTR)kwSandbox_msvcrt__cexit },
4715 { TUPLE("_c_exit"), NULL, (KUPTR)kwSandbox_msvcrt__c_exit },
4716 { TUPLE("_amsg_exit"), NULL, (KUPTR)kwSandbox_msvcrt__amsg_exit },
4717 { TUPLE("terminate"), NULL, (KUPTR)kwSandbox_msvcrt_terminate },
4718
4719#if 0 /* used by mspdbXXX.dll */
4720 { TUPLE("_beginthread"), NULL, (KUPTR)kwSandbox_msvcrt__beginthread },
4721 { TUPLE("_beginthreadex"), NULL, (KUPTR)kwSandbox_msvcrt__beginthreadex },
4722#endif
4723};
4724/** Number of entries in g_aSandboxNativeReplacements. */
4725KU32 const g_cSandboxNativeReplacements = K_ELEMENTS(g_aSandboxNativeReplacements);
4726
4727
4728/**
4729 * Used by kwSandboxExec to reset the state of the module tree.
4730 *
4731 * This is done recursively.
4732 *
4733 * @param pMod The root of the tree to consider.
4734 */
4735static void kwSandboxResetModuleState(PKWMODULE pMod)
4736{
4737 if ( !pMod->fNative
4738 && pMod->u.Manual.enmState != KWMODSTATE_NEEDS_BITS)
4739 {
4740 KSIZE iImp;
4741 pMod->u.Manual.enmState = KWMODSTATE_NEEDS_BITS;
4742 iImp = pMod->u.Manual.cImpMods;
4743 while (iImp-- > 0)
4744 kwSandboxResetModuleState(pMod->u.Manual.apImpMods[iImp]);
4745 }
4746}
4747
4748static PPEB kwSandboxGetProcessEnvironmentBlock(void)
4749{
4750#if K_ARCH == K_ARCH_X86_32
4751 return (PPEB)__readfsdword(0x030 /* offset of ProcessEnvironmentBlock in TEB */);
4752#elif K_ARCH == K_ARCH_AMD64
4753 return (PPEB)__readgsqword(0x060 /* offset of ProcessEnvironmentBlock in TEB */);
4754#else
4755# error "Port me!"
4756#endif
4757}
4758
4759
4760#if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_X86)
4761typedef struct _EXCEPTION_REGISTRATION_RECORD
4762{
4763 struct _EXCEPTION_REGISTRATION_RECORD * volatile PrevStructure;
4764 KU32 (__cdecl * volatile ExceptionHandler)(PEXCEPTION_RECORD, struct _EXCEPTION_REGISTRATION_RECORD*, PCONTEXT,
4765 struct _EXCEPTION_REGISTRATION_RECORD * volatile *);
4766};
4767
4768/**
4769 * Vectored exception handler that emulates x86 chained exception handler.
4770 *
4771 * This is necessary because the RtlIsValidHandler check fails for self loaded
4772 * code and prevents cl.exe from working. (On AMD64 we can register function
4773 * tables, but on X86 cooking your own handling seems to be the only viabke
4774 * alternative.)
4775 *
4776 * @returns EXCEPTION_CONTINUE_SEARCH or EXCEPTION_CONTINUE_EXECUTION.
4777 * @param pXcptPtrs The exception details.
4778 */
4779static LONG CALLBACK kwSandboxVecXcptEmulateChained(PEXCEPTION_POINTERS pXcptPtrs)
4780{
4781 PNT_TIB pTib = (PNT_TIB)NtCurrentTeb();
4782 KW_LOG(("kwSandboxVecXcptEmulateChained: %#x\n", pXcptPtrs->ExceptionRecord->ExceptionCode));
4783 if (g_Sandbox.fRunning)
4784 {
4785 PEXCEPTION_RECORD pXcptRec = pXcptPtrs->ExceptionRecord;
4786 PCONTEXT pXcptCtx = pXcptPtrs->ContextRecord;
4787 struct _EXCEPTION_REGISTRATION_RECORD * volatile *ppRegRec = &pTib->ExceptionList;
4788 struct _EXCEPTION_REGISTRATION_RECORD * pRegRec = *ppRegRec;
4789 while (((KUPTR)pRegRec & (sizeof(void *) - 3)) == 0 && pRegRec != NULL)
4790 {
4791#if 1
4792 /* This is a more robust version that isn't subject to calling
4793 convension cleanup disputes and such. */
4794 KU32 uSavedEdi;
4795 KU32 uSavedEsi;
4796 KU32 uSavedEbx;
4797 KU32 rcHandler;
4798 __asm
4799 {
4800 mov [uSavedEdi], edi
4801 mov [uSavedEsi], esi
4802 mov [uSavedEbx], ebx
4803 mov esi, esp
4804 mov edi, esp
4805 mov ecx, [pXcptRec]
4806 mov edx, [pRegRec]
4807 mov eax, [pXcptCtx]
4808 mov ebx, [ppRegRec]
4809 sub esp, 16
4810 and esp, 0fffffff0h
4811 mov [esp ], ecx
4812 mov [esp + 4], edx
4813 mov [esp + 8], eax
4814 mov [esp + 12], ebx
4815 call dword ptr [edx + 4]
4816 mov esp, esi
4817 cmp esp, edi
4818 je stack_ok
4819 int 3
4820 stack_ok:
4821 mov edi, [uSavedEdi]
4822 mov esi, [uSavedEsi]
4823 mov ebx, [uSavedEbx]
4824 mov [rcHandler], eax
4825 }
4826#else
4827 KU32 rcHandler = pRegRec->ExceptionHandler(pXcptPtrs->ExceptionRecord, pRegRec, pXcptPtrs->ContextRecord, ppRegRec);
4828#endif
4829 if (rcHandler == ExceptionContinueExecution)
4830 {
4831 kHlpAssert(!(pXcptPtrs->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE));
4832 return EXCEPTION_CONTINUE_EXECUTION;
4833 }
4834 if (rcHandler == ExceptionContinueSearch)
4835 kHlpAssert(!(pXcptPtrs->ExceptionRecord->ExceptionFlags & 8 /*EXCEPTION_STACK_INVALID*/));
4836 else if (rcHandler == ExceptionNestedException)
4837 kHlpAssertMsgFailed(("Nested exceptions.\n"));
4838 else
4839 kHlpAssertMsgFailed(("Invalid return %#x (%d).\n", rcHandler, rcHandler));
4840
4841 /*
4842 * Next.
4843 */
4844 ppRegRec = &pRegRec->PrevStructure;
4845 pRegRec = pRegRec->PrevStructure;
4846 }
4847 }
4848 return EXCEPTION_CONTINUE_SEARCH;
4849}
4850#endif /* WINDOWS + X86 */
4851
4852
4853/**
4854 * Enters the given handle into the handle table.
4855 *
4856 * @returns K_TRUE on success, K_FALSE on failure.
4857 * @param pSandbox The sandbox.
4858 * @param pHandle The handle.
4859 */
4860static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle)
4861{
4862 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(pHandle->hHandle);
4863 kHlpAssertReturn(idxHandle < KW_HANDLE_MAX, K_FALSE);
4864
4865 /*
4866 * Grow handle table.
4867 */
4868 if (idxHandle >= pSandbox->cHandles)
4869 {
4870 void *pvNew;
4871 KU32 cHandles = pSandbox->cHandles ? pSandbox->cHandles * 2 : 32;
4872 while (cHandles <= idxHandle)
4873 cHandles *= 2;
4874 pvNew = kHlpRealloc(pSandbox->papHandles, cHandles * sizeof(pSandbox->papHandles[0]));
4875 if (!pvNew)
4876 {
4877 KW_LOG(("Out of memory growing handle table to %u handles\n", cHandles));
4878 return K_FALSE;
4879 }
4880 pSandbox->papHandles = (PKWHANDLE *)pvNew;
4881 kHlpMemSet(&pSandbox->papHandles[pSandbox->cHandles], 0,
4882 (cHandles - pSandbox->cHandles) * sizeof(pSandbox->papHandles[0]));
4883 pSandbox->cHandles = cHandles;
4884 }
4885
4886 /*
4887 * Check that the entry is unused then insert it.
4888 */
4889 kHlpAssertReturn(pSandbox->papHandles[idxHandle] == NULL, K_FALSE);
4890 pSandbox->papHandles[idxHandle] = pHandle;
4891 pSandbox->cActiveHandles++;
4892 return K_TRUE;
4893}
4894
4895
4896/**
4897 * Creates a correctly quoted ANSI command line string from the given argv.
4898 *
4899 * @returns Pointer to the command line.
4900 * @param cArgs Number of arguments.
4901 * @param papszArgs The argument vector.
4902 * @param fWatcomBrainDamange Whether to apply watcom rules while quoting.
4903 * @param pcbCmdLine Where to return the command line length,
4904 * including one terminator.
4905 */
4906static char *kwSandboxInitCmdLineFromArgv(KU32 cArgs, const char **papszArgs, KBOOL fWatcomBrainDamange, KSIZE *pcbCmdLine)
4907{
4908 KU32 i;
4909 KSIZE cbCmdLine;
4910 char *pszCmdLine;
4911
4912 /* Make a copy of the argument vector that we'll be quoting. */
4913 char **papszQuotedArgs = alloca(sizeof(papszArgs[0]) * (cArgs + 1));
4914 kHlpMemCopy(papszQuotedArgs, papszArgs, sizeof(papszArgs[0]) * (cArgs + 1));
4915
4916 /* Quote the arguments that need it. */
4917 quote_argv(cArgs, papszQuotedArgs, fWatcomBrainDamange, 0 /*leak*/);
4918
4919 /* figure out cmd line length. */
4920 cbCmdLine = 0;
4921 for (i = 0; i < cArgs; i++)
4922 cbCmdLine += strlen(papszQuotedArgs[i]) + 1;
4923 *pcbCmdLine = cbCmdLine;
4924
4925 pszCmdLine = (char *)kHlpAlloc(cbCmdLine + 1);
4926 if (pszCmdLine)
4927 {
4928 char *psz = kHlpStrPCopy(pszCmdLine, papszQuotedArgs[0]);
4929 if (papszQuotedArgs[0] != papszArgs[0])
4930 free(papszQuotedArgs[0]);
4931
4932 for (i = 1; i < cArgs; i++)
4933 {
4934 *psz++ = ' ';
4935 psz = kHlpStrPCopy(psz, papszQuotedArgs[i]);
4936 if (papszQuotedArgs[i] != papszArgs[i])
4937 free(papszQuotedArgs[i]);
4938 }
4939 kHlpAssert((KSIZE)(&psz[1] - pszCmdLine) == cbCmdLine);
4940
4941 *psz++ = '\0';
4942 *psz++ = '\0';
4943 }
4944
4945 return pszCmdLine;
4946}
4947
4948
4949
4950static int kwSandboxInit(PKWSANDBOX pSandbox, PKWTOOL pTool,
4951 KU32 cArgs, const char **papszArgs, KBOOL fWatcomBrainDamange,
4952 KU32 cEnvVars, const char **papszEnvVars)
4953{
4954 PPEB pPeb = kwSandboxGetProcessEnvironmentBlock();
4955 wchar_t *pwcPool;
4956 KSIZE cbStrings;
4957 KSIZE cwc;
4958 KSIZE cbCmdLine;
4959 KU32 i;
4960
4961 /* Simple stuff. */
4962 pSandbox->rcExitCode = 256;
4963 pSandbox->pTool = pTool;
4964 pSandbox->idMainThread = GetCurrentThreadId();
4965 pSandbox->pgmptr = (char *)pTool->pszPath;
4966 pSandbox->wpgmptr = (wchar_t *)pTool->pwszPath;
4967 pSandbox->cArgs = cArgs;
4968 pSandbox->papszArgs = (char **)papszArgs;
4969 pSandbox->pszCmdLine = kwSandboxInitCmdLineFromArgv(cArgs, papszArgs, fWatcomBrainDamange, &cbCmdLine);
4970 if (!pSandbox->pszCmdLine)
4971 return KERR_NO_MEMORY;
4972
4973 /*
4974 * Convert command line and argv to UTF-16.
4975 * We assume each ANSI char requires a surrogate pair in the UTF-16 variant.
4976 */
4977 pSandbox->papwszArgs = (wchar_t **)kHlpAlloc(sizeof(wchar_t *) * (pSandbox->cArgs + 2) + cbCmdLine * 2 * sizeof(wchar_t));
4978 if (!pSandbox->papwszArgs)
4979 return KERR_NO_MEMORY;
4980 pwcPool = (wchar_t *)&pSandbox->papwszArgs[pSandbox->cArgs + 2];
4981 for (i = 0; i < cArgs; i++)
4982 {
4983 *pwcPool++ = pSandbox->papszArgs[i][-1]; /* flags */
4984 pSandbox->papwszArgs[i] = pwcPool;
4985 pwcPool += kwStrToUtf16(pSandbox->papszArgs[i], pwcPool, (strlen(pSandbox->papszArgs[i]) + 1) * 2);
4986 pwcPool++;
4987 }
4988 pSandbox->papwszArgs[pSandbox->cArgs + 0] = NULL;
4989 pSandbox->papwszArgs[pSandbox->cArgs + 1] = NULL;
4990
4991 /*
4992 * Convert the commandline string to UTF-16, same pessimistic approach as above.
4993 */
4994 cbStrings = (cbCmdLine + 1) * 2 * sizeof(wchar_t);
4995 pSandbox->pwszCmdLine = kHlpAlloc(cbStrings);
4996 if (!pSandbox->pwszCmdLine)
4997 return KERR_NO_MEMORY;
4998 cwc = kwStrToUtf16(pSandbox->pszCmdLine, pSandbox->pwszCmdLine, cbStrings / sizeof(wchar_t));
4999
5000 pSandbox->SavedCommandLine = pPeb->ProcessParameters->CommandLine;
5001 pPeb->ProcessParameters->CommandLine.Buffer = pSandbox->pwszCmdLine;
5002 pPeb->ProcessParameters->CommandLine.Length = (USHORT)cwc * sizeof(wchar_t);
5003
5004 /*
5005 * Invalidate the volatile parts of cache (kBuild output directory,
5006 * temporary directory, whatever).
5007 */
5008 kFsCacheInvalidateCustomBoth(g_pFsCache);
5009 return 0;
5010}
5011
5012
5013static void kwSandboxCleanup(PKWSANDBOX pSandbox)
5014{
5015 PKWVIRTALLOC pTracker;
5016 PKWLOCALSTORAGE pLocalStorage;
5017#ifdef WITH_TEMP_MEMORY_FILES
5018 PKWFSTEMPFILE pTempFile;
5019#endif
5020 PPEB pPeb = kwSandboxGetProcessEnvironmentBlock();
5021 pPeb->ProcessParameters->CommandLine = pSandbox->SavedCommandLine;
5022 /** @todo lots more to do here! */
5023
5024#ifdef WITH_TEMP_MEMORY_FILES
5025 pTempFile = pSandbox->pTempFileHead;
5026 pSandbox->pTempFileHead = NULL;
5027 while (pTempFile)
5028 {
5029 PKWFSTEMPFILE pNext = pTempFile->pNext;
5030 KU32 iSeg = pTempFile->cSegs;
5031 while (iSeg-- > 0)
5032 kHlpPageFree(pTempFile->paSegs[iSeg].pbData, pTempFile->paSegs[iSeg].cbDataAlloc);
5033 kHlpFree(pTempFile->paSegs);
5034 pTempFile->pNext = NULL;
5035 kHlpFree(pTempFile);
5036
5037 pTempFile = pNext;
5038 }
5039#endif
5040
5041 /* Free left behind VirtualAlloc leaks. */
5042 pTracker = g_Sandbox.pVirtualAllocHead;
5043 g_Sandbox.pVirtualAllocHead = NULL;
5044 while (pTracker)
5045 {
5046 PKWVIRTALLOC pNext = pTracker->pNext;
5047 KW_LOG(("Freeing VirtualFree leak %p LB %#x\n", pTracker->pvAlloc, pTracker->cbAlloc));
5048 VirtualFree(pTracker->pvAlloc, 0, MEM_RELEASE);
5049 kHlpFree(pTracker);
5050 pTracker = pNext;
5051 }
5052
5053 /* Free left behind FlsAlloc leaks. */
5054 pLocalStorage = g_Sandbox.pFlsAllocHead;
5055 g_Sandbox.pFlsAllocHead = NULL;
5056 while (pLocalStorage)
5057 {
5058 PKWLOCALSTORAGE pNext = pLocalStorage->pNext;
5059 KW_LOG(("Freeing leaded FlsAlloc index %#x\n", pLocalStorage->idx));
5060 FlsFree(pLocalStorage->idx);
5061 kHlpFree(pLocalStorage);
5062 pLocalStorage = pNext;
5063 }
5064
5065 /* Free left behind TlsAlloc leaks. */
5066 pLocalStorage = g_Sandbox.pTlsAllocHead;
5067 g_Sandbox.pTlsAllocHead = NULL;
5068 while (pLocalStorage)
5069 {
5070 PKWLOCALSTORAGE pNext = pLocalStorage->pNext;
5071 KW_LOG(("Freeing leaded TlsAlloc index %#x\n", pLocalStorage->idx));
5072 TlsFree(pLocalStorage->idx);
5073 kHlpFree(pLocalStorage);
5074 pLocalStorage = pNext;
5075 }
5076
5077}
5078
5079
5080static int kwSandboxExec(PKWSANDBOX pSandbox, PKWTOOL pTool, KU32 cArgs, const char **papszArgs, KBOOL fWatcomBrainDamange,
5081 KU32 cEnvVars, const char **papszEnvVars)
5082{
5083 int rcExit = 42;
5084 int rc;
5085
5086 /*
5087 * Initialize the sandbox environment.
5088 */
5089 rc = kwSandboxInit(&g_Sandbox, pTool, cArgs, papszArgs, fWatcomBrainDamange, cEnvVars, papszEnvVars);
5090 if (rc == 0)
5091 {
5092 /*
5093 * Do module initialization.
5094 */
5095 kwSandboxResetModuleState(pTool->u.Sandboxed.pExe);
5096 rc = kwLdrModuleInitTree(pTool->u.Sandboxed.pExe);
5097 if (rc == 0)
5098 {
5099 /*
5100 * Call the main function.
5101 */
5102 KUPTR uAddrMain;
5103 rc = kwLdrModuleQueryMainEntrypoint(pTool->u.Sandboxed.pExe, &uAddrMain);
5104 if (rc == 0)
5105 {
5106#if K_ARCH == K_ARCH_AMD64
5107 int (*pfnWin64Entrypoint)(void *pvPeb, void *, void *, void *);
5108#elif K_ARCH == K_ARCH_X86_32
5109 int (__cdecl *pfnWin32Entrypoint)(void *pvPeb);
5110#else
5111# error "Port me!"
5112#endif
5113
5114 /* Save the NT TIB first (should do that here, not in some other function). */
5115 PNT_TIB pTib = (PNT_TIB)NtCurrentTeb();
5116 pSandbox->TibMainThread = *pTib;
5117
5118 /* Make the call in a guarded fashion. */
5119#if K_ARCH == K_ARCH_AMD64
5120 /* AMD64 */
5121 *(KUPTR *)&pfnWin64Entrypoint = uAddrMain;
5122 __try
5123 {
5124 pSandbox->pOutXcptListHead = pTib->ExceptionList;
5125 if (setjmp(pSandbox->JmpBuf) == 0)
5126 {
5127 *(KU64*)(pSandbox->JmpBuf) = 0; /** @todo find other way to prevent longjmp from doing unwind! */
5128 pSandbox->fRunning = K_TRUE;
5129 rcExit = pfnWin64Entrypoint(kwSandboxGetProcessEnvironmentBlock(), NULL, NULL, NULL);
5130 pSandbox->fRunning = K_FALSE;
5131 }
5132 else
5133 rcExit = pSandbox->rcExitCode;
5134 }
5135#elif K_ARCH == K_ARCH_X86_32
5136 /* x86 (see _tmainCRTStartup) */
5137 *(KUPTR *)&pfnWin32Entrypoint = uAddrMain;
5138 __try
5139 {
5140 pSandbox->pOutXcptListHead = pTib->ExceptionList;
5141 if (setjmp(pSandbox->JmpBuf) == 0)
5142 {
5143 //*(KU64*)(pSandbox->JmpBuf) = 0; /** @todo find other way to prevent longjmp from doing unwind! */
5144 pSandbox->fRunning = K_TRUE;
5145 rcExit = pfnWin32Entrypoint(kwSandboxGetProcessEnvironmentBlock());
5146 pSandbox->fRunning = K_FALSE;
5147 }
5148 else
5149 rcExit = pSandbox->rcExitCode;
5150 }
5151#endif
5152 __except (EXCEPTION_EXECUTE_HANDLER)
5153 {
5154 rcExit = 512;
5155 }
5156 pSandbox->fRunning = K_FALSE;
5157
5158 /* Now, restore the NT TIB. */
5159 *pTib = pSandbox->TibMainThread;
5160 }
5161 else
5162 rcExit = 42 + 5;
5163 }
5164 else
5165 rcExit = 42 + 4;
5166
5167 kwSandboxCleanup(&g_Sandbox);
5168 }
5169 else
5170 rcExit = 42 + 3;
5171
5172 return rcExit;
5173}
5174
5175
5176/**
5177 * Part 2 of the "JOB" command handler.
5178 *
5179 * @returns The exit code of the job.
5180 * @param pszExecutable The executable to execute.
5181 * @param pszCwd The current working directory of the job.
5182 * @param cArgs The number of arguments.
5183 * @param papszArgs The argument vector.
5184 * @param fWatcomBrainDamange Whether to apply watcom rules while quoting.
5185 * @param cEnvVars The number of environment variables.
5186 * @param papszEnvVars The enviornment vector.
5187 */
5188static int kSubmitHandleJobUnpacked(const char *pszExecutable, const char *pszCwd,
5189 KU32 cArgs, const char **papszArgs, KBOOL fWatcomBrainDamange,
5190 KU32 cEnvVars, const char **papszEnvVars)
5191{
5192 int rcExit;
5193 PKWTOOL pTool;
5194
5195 /*
5196 * Lookup the tool.
5197 */
5198 pTool = kwToolLookup(pszExecutable);
5199 if (pTool)
5200 {
5201 /*
5202 * Change the directory if we're going to execute the job inside
5203 * this process. Then invoke the tool type specific handler.
5204 */
5205 switch (pTool->enmType)
5206 {
5207 case KWTOOLTYPE_SANDBOXED:
5208 case KWTOOLTYPE_WATCOM:
5209 {
5210 /* Change dir. */
5211 KFSLOOKUPERROR enmError;
5212 PKFSOBJ pNewCurDir = kFsCacheLookupA(g_pFsCache, pszCwd, &enmError);
5213 if ( pNewCurDir == g_pCurDirObj
5214 && pNewCurDir->bObjType == KFSOBJ_TYPE_DIR)
5215 kFsCacheObjRelease(g_pFsCache, pNewCurDir);
5216 else if (SetCurrentDirectoryA(pszCwd))
5217 {
5218 kFsCacheObjRelease(g_pFsCache, g_pCurDirObj);
5219 g_pCurDirObj = pNewCurDir;
5220 }
5221 else
5222 {
5223 kwErrPrintf("SetCurrentDirectory failed with %u on '%s'\n", GetLastError(), pszCwd);
5224 kFsCacheObjRelease(g_pFsCache, pNewCurDir);
5225 rcExit = 42 + 1;
5226 break;
5227 }
5228
5229 /* Call specific handler. */
5230 if (pTool->enmType == KWTOOLTYPE_SANDBOXED)
5231 {
5232 KW_LOG(("Sandboxing tool %s\n", pTool->pszPath));
5233 rcExit = kwSandboxExec(&g_Sandbox, pTool, cArgs, papszArgs, fWatcomBrainDamange, cEnvVars, papszEnvVars);
5234 }
5235 else
5236 {
5237 kwErrPrintf("TODO: Watcom style tool %s\n", pTool->pszPath);
5238 rcExit = 42 + 2;
5239 }
5240 break;
5241 }
5242
5243 case KWTOOLTYPE_EXEC:
5244 kwErrPrintf("TODO: Direct exec tool %s\n", pTool->pszPath);
5245 rcExit = 42 + 2;
5246 break;
5247
5248 default:
5249 kHlpAssertFailed();
5250 kwErrPrintf("Internal tool type corruption!!\n");
5251 rcExit = 42 + 2;
5252 g_fRestart = K_TRUE;
5253 break;
5254 }
5255 }
5256 else
5257 rcExit = 42 + 1;
5258 return rcExit;
5259}
5260
5261
5262/**
5263 * Handles a "JOB" command.
5264 *
5265 * @returns The exit code of the job.
5266 * @param pszMsg Points to the "JOB" command part of the message.
5267 * @param cbMsg Number of message bytes at @a pszMsg. There are
5268 * 4 more zero bytes after the message body to
5269 * simplify parsing.
5270 */
5271static int kSubmitHandleJob(const char *pszMsg, KSIZE cbMsg)
5272{
5273 int rcExit = 42;
5274
5275 /*
5276 * Unpack the message.
5277 */
5278 const char *pszExecutable;
5279 size_t cbTmp;
5280
5281 pszMsg += sizeof("JOB");
5282 cbMsg -= sizeof("JOB");
5283
5284 /* Executable name. */
5285 pszExecutable = pszMsg;
5286 cbTmp = strlen(pszMsg) + 1;
5287 pszMsg += cbTmp;
5288 if ( cbTmp < cbMsg
5289 && cbTmp > 2)
5290 {
5291 const char *pszCwd;
5292 cbMsg -= cbTmp;
5293
5294 /* Current working directory. */
5295 pszCwd = pszMsg;
5296 cbTmp = strlen(pszMsg) + 1;
5297 pszMsg += cbTmp;
5298 if ( cbTmp + sizeof(KU32) < cbMsg
5299 && cbTmp >= 2)
5300 {
5301 KU32 cArgs;
5302 cbMsg -= cbTmp;
5303
5304 /* Argument count. */
5305 kHlpMemCopy(&cArgs, pszMsg, sizeof(cArgs));
5306 pszMsg += sizeof(cArgs);
5307 cbMsg -= sizeof(cArgs);
5308
5309 if (cArgs > 0 && cArgs < 4096)
5310 {
5311 /* The argument vector. */
5312 char const **papszArgs = kHlpAlloc((cArgs + 1) * sizeof(papszArgs[0]));
5313 if (papszArgs)
5314 {
5315 KU32 i;
5316 for (i = 0; i < cArgs; i++)
5317 {
5318 papszArgs[i] = pszMsg + 1; /* First byte is expansion flags for MSC & EMX. */
5319 cbTmp = 1 + strlen(pszMsg + 1) + 1;
5320 pszMsg += cbTmp;
5321 if (cbTmp < cbMsg)
5322 cbMsg -= cbTmp;
5323 else
5324 {
5325 cbMsg = 0;
5326 break;
5327 }
5328
5329 }
5330 papszArgs[cArgs] = 0;
5331
5332 /* Environment variable count. */
5333 if (sizeof(KU32) < cbMsg)
5334 {
5335 KU32 cEnvVars;
5336 kHlpMemCopy(&cEnvVars, pszMsg, sizeof(cEnvVars));
5337 pszMsg += sizeof(cEnvVars);
5338 cbMsg -= sizeof(cEnvVars);
5339
5340 if (cEnvVars >= 0 && cEnvVars < 4096)
5341 {
5342 /* The argument vector. */
5343 char const **papszEnvVars = kHlpAlloc((cEnvVars + 1) * sizeof(papszEnvVars[0]));
5344 if (papszEnvVars)
5345 {
5346 KU32 i;
5347 for (i = 0; i < cEnvVars; i++)
5348 {
5349 papszEnvVars[i] = pszMsg;
5350 cbTmp = strlen(pszMsg) + 1;
5351 pszMsg += cbTmp;
5352 if (cbTmp < cbMsg)
5353 cbMsg -= cbTmp;
5354 else
5355 {
5356 if ( cbTmp == cbMsg
5357 && i + 1 == cEnvVars)
5358 cbMsg = 0;
5359 else
5360 cbMsg = KSIZE_MAX;
5361 break;
5362 }
5363 }
5364 papszEnvVars[cEnvVars] = 0;
5365 if (cbMsg != KSIZE_MAX)
5366 {
5367 if (cbMsg == 0)
5368 {
5369 KBOOL fWatcomBrainDamange = K_FALSE; /** @todo fix fWatcomBrainDamange */
5370 /*
5371 * The next step.
5372 */
5373 rcExit = kSubmitHandleJobUnpacked(pszExecutable, pszCwd,
5374 cArgs, papszArgs, fWatcomBrainDamange,
5375 cEnvVars, papszEnvVars);
5376 }
5377 else
5378 kwErrPrintf("Message has %u bytes unknown trailing bytes\n", cbMsg);
5379 }
5380 else
5381 kwErrPrintf("Detected bogus message unpacking environment variables!\n");
5382 kHlpFree((void *)papszEnvVars);
5383 }
5384 else
5385 kwErrPrintf("Error allocating papszEnvVars for %u variables\n", cEnvVars);
5386 }
5387 else
5388 kwErrPrintf("Bogus environment variable count: %u (%#x)\n", cEnvVars, cEnvVars);
5389 }
5390 else
5391 kwErrPrintf("Detected bogus message unpacking arguments and environment variable count!\n");
5392 kHlpFree((void *)papszArgs);
5393 }
5394 else
5395 kwErrPrintf("Error allocating argv for %u arguments\n", cArgs);
5396 }
5397 else
5398 kwErrPrintf("Bogus argument count: %u (%#x)\n", cArgs, cArgs);
5399 }
5400 else
5401 kwErrPrintf("Detected bogus message unpacking CWD path and argument count!\n");
5402 }
5403 else
5404 kwErrPrintf("Detected bogus message unpacking executable path!\n");
5405 return rcExit;
5406}
5407
5408
5409/**
5410 * Wrapper around WriteFile / write that writes the whole @a cbToWrite.
5411 *
5412 * @retval 0 on success.
5413 * @retval -1 on error (fully bitched).
5414 *
5415 * @param hPipe The pipe handle.
5416 * @param pvBuf The buffer to write out out.
5417 * @param cbToWrite The number of bytes to write.
5418 */
5419static int kSubmitWriteIt(HANDLE hPipe, const void *pvBuf, KU32 cbToWrite)
5420{
5421 KU8 const *pbBuf = (KU8 const *)pvBuf;
5422 KU32 cbLeft = cbToWrite;
5423 for (;;)
5424 {
5425 DWORD cbActuallyWritten = 0;
5426 if (WriteFile(hPipe, pbBuf, cbLeft, &cbActuallyWritten, NULL /*pOverlapped*/))
5427 {
5428 cbLeft -= cbActuallyWritten;
5429 if (!cbLeft)
5430 return 0;
5431 pbBuf += cbActuallyWritten;
5432 }
5433 else
5434 {
5435 DWORD dwErr = GetLastError();
5436 if (cbLeft == cbToWrite)
5437 kwErrPrintf("WriteFile failed: %u\n", dwErr);
5438 else
5439 kwErrPrintf("WriteFile failed %u byte(s) in: %u\n", cbToWrite - cbLeft, dwErr);
5440 return -1;
5441 }
5442 }
5443}
5444
5445
5446/**
5447 * Wrapper around ReadFile / read that reads the whole @a cbToRead.
5448 *
5449 * @retval 0 on success.
5450 * @retval 1 on shut down (fShutdownOkay must be K_TRUE).
5451 * @retval -1 on error (fully bitched).
5452 * @param hPipe The pipe handle.
5453 * @param pvBuf The buffer to read into.
5454 * @param cbToRead The number of bytes to read.
5455 * @param fShutdownOkay Whether connection shutdown while reading the
5456 * first byte is okay or not.
5457 */
5458static int kSubmitReadIt(HANDLE hPipe, void *pvBuf, KU32 cbToRead, KBOOL fMayShutdown)
5459{
5460 KU8 *pbBuf = (KU8 *)pvBuf;
5461 KU32 cbLeft = cbToRead;
5462 for (;;)
5463 {
5464 DWORD cbActuallyRead = 0;
5465 if (ReadFile(hPipe, pbBuf, cbLeft, &cbActuallyRead, NULL /*pOverlapped*/))
5466 {
5467 cbLeft -= cbActuallyRead;
5468 if (!cbLeft)
5469 return 0;
5470 pbBuf += cbActuallyRead;
5471 }
5472 else
5473 {
5474 DWORD dwErr = GetLastError();
5475 if (cbLeft == cbToRead)
5476 {
5477 if ( fMayShutdown
5478 && dwErr == ERROR_BROKEN_PIPE)
5479 return 1;
5480 kwErrPrintf("ReadFile failed: %u\n", dwErr);
5481 }
5482 else
5483 kwErrPrintf("ReadFile failed %u byte(s) in: %u\n", cbToRead - cbLeft, dwErr);
5484 return -1;
5485 }
5486 }
5487}
5488
5489
5490/**
5491 * Handles what comes after --test.
5492 *
5493 * @returns Exit code.
5494 * @param argc Number of arguments after --test.
5495 * @param argv Arguments after --test.
5496 */
5497static int kwTestRun(int argc, char **argv)
5498{
5499 int i;
5500 int j;
5501 int rcExit;
5502 int cRepeats;
5503 char szCwd[MAX_PATH];
5504 const char *pszCwd = getcwd(szCwd, sizeof(szCwd));
5505 KU32 cEnvVars;
5506
5507 /*
5508 * Parse arguments.
5509 */
5510 /* Repeat count. */
5511 i = 0;
5512 if (i >= argc)
5513 return kwErrPrintfRc(2, "--test takes an repeat count argument or '--'!\n");
5514 if (strcmp(argv[i], "--") != 0)
5515 {
5516 cRepeats = atoi(argv[i]);
5517 if (cRepeats <= 0)
5518 return kwErrPrintfRc(2, "The repeat count '%s' is zero, negative or invalid!\n", argv[i]);
5519 i++;
5520
5521 /* Optional directory change. */
5522 if ( i < argc
5523 && strcmp(argv[i], "--chdir") == 0)
5524 {
5525 i++;
5526 if (i >= argc)
5527 return kwErrPrintfRc(2, "--chdir takes an argument!\n");
5528 pszCwd = argv[i++];
5529 }
5530
5531 /* Check for '--'. */
5532 if (i >= argc)
5533 return kwErrPrintfRc(2, "Missing '--'\n");
5534 if (strcmp(argv[i], "--") != 0)
5535 return kwErrPrintfRc(2, "Expected '--' found '%s'\n", argv[i]);
5536 i++;
5537 }
5538 else
5539 {
5540 cRepeats = 1;
5541 i++;
5542 }
5543 if (i >= argc)
5544 return kwErrPrintfRc(2, "Nothing to execute after '--'!\n");
5545
5546 /*
5547 * Do the job.
5548 */
5549 cEnvVars = 0;
5550 while (environ[cEnvVars] != NULL)
5551 cEnvVars++;
5552
5553 for (j = 0; j < cRepeats; j++)
5554 {
5555 rcExit = kSubmitHandleJobUnpacked(argv[i], pszCwd,
5556 argc - i, &argv[i], K_FALSE /* fWatcomBrainDamange*/,
5557 cEnvVars, environ);
5558 }
5559
5560 return rcExit;
5561}
5562
5563#if 1
5564
5565int main(int argc, char **argv)
5566{
5567 KSIZE cbMsgBuf = 0;
5568 KU8 *pbMsgBuf = NULL;
5569 int i;
5570 HANDLE hPipe = INVALID_HANDLE_VALUE;
5571 const char *pszTmp;
5572 KFSLOOKUPERROR enmIgnored;
5573#if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_X86)
5574 PVOID pvVecXcptHandler = AddVectoredExceptionHandler(0 /*called last*/, kwSandboxVecXcptEmulateChained);
5575#endif
5576
5577 /*
5578 * Create the cache and mark the temporary directory as using the custom revision.
5579 */
5580 g_pFsCache = kFsCacheCreate(KFSCACHE_F_MISSING_OBJECTS | KFSCACHE_F_MISSING_PATHS);
5581 if (!g_pFsCache)
5582 return kwErrPrintfRc(3, "kFsCacheCreate failed!\n");
5583
5584 pszTmp = getenv("TEMP");
5585 if (pszTmp && *pszTmp != '\0')
5586 kFsCacheSetupCustomRevisionForTree(g_pFsCache, kFsCacheLookupA(g_pFsCache, pszTmp, &enmIgnored));
5587 pszTmp = getenv("TMP");
5588 if (pszTmp && *pszTmp != '\0')
5589 kFsCacheSetupCustomRevisionForTree(g_pFsCache, kFsCacheLookupA(g_pFsCache, pszTmp, &enmIgnored));
5590 pszTmp = getenv("TMPDIR");
5591 if (pszTmp && *pszTmp != '\0')
5592 kFsCacheSetupCustomRevisionForTree(g_pFsCache, kFsCacheLookupA(g_pFsCache, pszTmp, &enmIgnored));
5593
5594 /*
5595 * Parse arguments.
5596 */
5597 for (i = 1; i < argc; i++)
5598 {
5599 if (strcmp(argv[i], "--pipe") == 0)
5600 {
5601 i++;
5602 if (i < argc)
5603 {
5604 char *pszEnd = NULL;
5605 unsigned __int64 u64Value = _strtoui64(argv[i], &pszEnd, 16);
5606 if ( *argv[i]
5607 && pszEnd != NULL
5608 && *pszEnd == '\0'
5609 && u64Value != 0
5610 && u64Value != (uintptr_t)INVALID_HANDLE_VALUE
5611 && (uintptr_t)u64Value == u64Value)
5612 hPipe = (HANDLE)(uintptr_t)u64Value;
5613 else
5614 return kwErrPrintfRc(2, "Invalid --pipe argument: %s\n", argv[i]);
5615 }
5616 else
5617 return kwErrPrintfRc(2, "--pipe takes an argument!\n");
5618 }
5619 else if (strcmp(argv[i], "--volatile") == 0)
5620 {
5621 i++;
5622 if (i < argc)
5623 kFsCacheSetupCustomRevisionForTree(g_pFsCache, kFsCacheLookupA(g_pFsCache, argv[i], &enmIgnored));
5624 else
5625 return kwErrPrintfRc(2, "--volatile takes an argument!\n");
5626 }
5627 else if (strcmp(argv[i], "--test") == 0)
5628 return kwTestRun(argc - i - 1, &argv[i + 1]);
5629 else if ( strcmp(argv[i], "--help") == 0
5630 || strcmp(argv[i], "-h") == 0
5631 || strcmp(argv[i], "-?") == 0)
5632 {
5633 printf("usage: kWorker [--volatile dir] --pipe <pipe-handle>\n"
5634 "usage: kWorker <--help|-h>\n"
5635 "usage: kWorker <--version|-V>\n"
5636 "usage: kWorker [--volatile dir] --test [<times> [--chdir <dir>]] -- args\n"
5637 "\n"
5638 "This is an internal kmk program that is used via the builtin_kSubmit.\n");
5639 return 0;
5640 }
5641 else if ( strcmp(argv[i], "--version") == 0
5642 || strcmp(argv[i], "-V") == 0)
5643 return kbuild_version(argv[0]);
5644 else
5645 return kwErrPrintfRc(2, "Unknown argument '%s'\n", argv[i]);
5646 }
5647
5648 if (hPipe == INVALID_HANDLE_VALUE)
5649 return kwErrPrintfRc(2, "Missing --pipe <pipe-handle> argument!\n");
5650
5651 /*
5652 * Serve the pipe.
5653 */
5654 for (;;)
5655 {
5656 KU32 cbMsg = 0;
5657 int rc = kSubmitReadIt(hPipe, &cbMsg, sizeof(cbMsg), K_TRUE /*fShutdownOkay*/);
5658 if (rc == 0)
5659 {
5660 /* Make sure the message length is within sane bounds. */
5661 if ( cbMsg > 4
5662 && cbMsg <= 256*1024*1024)
5663 {
5664 /* Reallocate the message buffer if necessary. We add 4 zero bytes. */
5665 if (cbMsg + 4 <= cbMsgBuf)
5666 { /* likely */ }
5667 else
5668 {
5669 cbMsgBuf = K_ALIGN_Z(cbMsg + 4, 2048);
5670 pbMsgBuf = kHlpRealloc(pbMsgBuf, cbMsgBuf);
5671 if (!pbMsgBuf)
5672 return kwErrPrintfRc(1, "Failed to allocate %u bytes for a message buffer!\n", cbMsgBuf);
5673 }
5674
5675 /* Read the whole message into the buffer, making sure there is are a 4 zero bytes following it. */
5676 *(KU32 *)pbMsgBuf = cbMsg;
5677 rc = kSubmitReadIt(hPipe, &pbMsgBuf[sizeof(cbMsg)], cbMsg - sizeof(cbMsg), K_FALSE /*fShutdownOkay*/);
5678 if (rc == 0)
5679 {
5680 const char *psz;
5681
5682 pbMsgBuf[cbMsg] = '\0';
5683 pbMsgBuf[cbMsg + 1] = '\0';
5684 pbMsgBuf[cbMsg + 2] = '\0';
5685 pbMsgBuf[cbMsg + 3] = '\0';
5686
5687 /* The first string after the header is the command. */
5688 psz = (const char *)&pbMsgBuf[sizeof(cbMsg)];
5689 if (strcmp(psz, "JOB") == 0)
5690 {
5691 struct
5692 {
5693 KI32 rcExitCode;
5694 KU8 bExiting;
5695 KU8 abZero[3];
5696 } Reply;
5697 Reply.rcExitCode = kSubmitHandleJob(psz, cbMsg - sizeof(cbMsg));
5698 Reply.bExiting = g_fRestart;
5699 Reply.abZero[0] = 0;
5700 Reply.abZero[1] = 0;
5701 Reply.abZero[2] = 0;
5702 rc = kSubmitWriteIt(hPipe, &Reply, sizeof(Reply));
5703 if ( rc == 0
5704 && !g_fRestart)
5705 continue;
5706 }
5707 else
5708 rc = kwErrPrintfRc(-1, "Unknown command: '%s'\n", psz);
5709 }
5710 }
5711 else
5712 rc = kwErrPrintfRc(-1, "Bogus message length: %u (%#x)\n", cbMsg, cbMsg);
5713 }
5714 return rc > 0 ? 0 : 1;
5715 }
5716}
5717
5718#else
5719
5720static int kwExecCmdLine(const char *pszExe, const char *pszCmdLine)
5721{
5722 int rc;
5723 PKWTOOL pTool = kwToolLookup(pszExe);
5724 if (pTool)
5725 {
5726 int rcExitCode;
5727 switch (pTool->enmType)
5728 {
5729 case KWTOOLTYPE_SANDBOXED:
5730 KW_LOG(("Sandboxing tool %s\n", pTool->pszPath));
5731 rc = kwSandboxExec(&g_Sandbox, pTool, pszCmdLine, &rcExitCode);
5732 break;
5733 default:
5734 kHlpAssertFailed();
5735 KW_LOG(("TODO: Direct exec tool %s\n", pTool->pszPath));
5736 rc = rcExitCode = 2;
5737 break;
5738 }
5739 KW_LOG(("rcExitCode=%d (rc=%d)\n", rcExitCode, rc));
5740 }
5741 else
5742 rc = 1;
5743 return rc;
5744}
5745
5746int main(int argc, char **argv)
5747{
5748 int rc = 0;
5749 int i;
5750 argv[2] = "\"E:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/bin/amd64/cl.exe\" -c -c -TP -nologo -Zi -Zi -Zl -GR- -EHsc -GF -Zc:wchar_t- -Oy- -MT -W4 -Wall -wd4065 -wd4996 -wd4127 -wd4706 -wd4201 -wd4214 -wd4510 -wd4512 -wd4610 -wd4514 -wd4820 -wd4365 -wd4987 -wd4710 -wd4061 -wd4986 -wd4191 -wd4574 -wd4917 -wd4711 -wd4611 -wd4571 -wd4324 -wd4505 -wd4263 -wd4264 -wd4738 -wd4242 -wd4244 -WX -RTCsu -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/include -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/atlmfc/include -IE:/vbox/svn/trunk/tools/win.x86/sdk/v7.1/Include -IE:/vbox/svn/trunk/include -IE:/vbox/svn/trunk/out/win.amd64/debug -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/include -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/atlmfc/include -DVBOX -DVBOX_WITH_64_BITS_GUESTS -DVBOX_WITH_REM -DVBOX_WITH_RAW_MODE -DDEBUG -DDEBUG_bird -DDEBUG_USERNAME=bird -DRT_OS_WINDOWS -D__WIN__ -DRT_ARCH_AMD64 -D__AMD64__ -D__WIN64__ -DVBOX_WITH_DEBUGGER -DRT_LOCK_STRICT -DRT_LOCK_STRICT_ORDER -DIN_RING3 -DLOG_DISABLED -DIN_BLD_PROG -D_CRT_SECURE_NO_DEPRECATE -FdE:/vbox/svn/trunk/out/win.amd64/debug/obj/VBoxBs2Linker/VBoxBs2Linker-obj.pdb -FD -FoE:/vbox/svn/trunk/out/win.amd64/debug/obj/VBoxBs2Linker/VBoxBs2Linker.obj E:\\vbox\\svn\\trunk\\src\\VBox\\ValidationKit\\bootsectors\\VBoxBs2Linker.cpp";
5751# if 0
5752 rc = kwExecCmdLine(argv[1], argv[2]);
5753 rc = kwExecCmdLine(argv[1], argv[2]);
5754 K_NOREF(i);
5755# else
5756// Skylake (W10/amd64, only stdandard MS defender):
5757// cmd 1: 48 /1024 = 0x0 (0.046875) [for /l %i in (1,1,1024) do ...]
5758// kmk 1: 44 /1024 = 0x0 (0.04296875) [all: ; 1024 x cl.exe]
5759// run 1: 37 /1024 = 0x0 (0.0361328125) [just process creation gain]
5760// run 2: 34 /1024 = 0x0 (0.033203125) [get file attribs]
5761// run 3: 32.77 /1024 = 0x0 (0.032001953125) [read caching of headers]
5762// run 4: 32.67 /1024 = 0x0 (0.031904296875) [loader tweaking]
5763// run 5: 29.144/1024 = 0x0 (0.0284609375) [with temp files in memory]
5764// Dell (W7/amd64, infected by mcafee):
5765// kmk 1: 285.278/1024 = 0x0 (0.278591796875)
5766// run 1: 134.503/1024 = 0x0 (0.1313505859375) [w/o temp files in memory]
5767// run 2: 78.161/1024 = 0x0 (0.0763291015625) [with temp files in memory]
5768 g_cVerbose = 0;
5769 for (i = 0; i < 1024 && rc == 0; i++)
5770 rc = kwExecCmdLine(argv[1], argv[2]);
5771# endif
5772 return rc;
5773}
5774
5775#endif
5776
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette