VirtualBox

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

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

updates

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