VirtualBox

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

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

output optimizations

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