VirtualBox

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

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

updates

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