VirtualBox

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

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

rewrote kmk_redirect to skip the separate process. Added chache invalidation after directory deletion for addressing kmk rebuild and fetching.

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