VirtualBox

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

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

fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 297.2 KB
Line 
1/* $Id: kWorker.c 2905 2016-09-09 17:46:33Z 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 <[email protected]>
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 PKWEXITCALLACK pCallback;
2641 KW_LOG(("_onexit(%p)\n", pfnFunc));
2642 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
2643
2644 pCallback = kHlpAlloc(sizeof(*pCallback));
2645 if (pCallback)
2646 {
2647 pCallback->pfnCallback = pfnFunc;
2648 pCallback->fAtExit = K_FALSE;
2649 pCallback->pNext = g_Sandbox.pExitCallbackHead;
2650 g_Sandbox.pExitCallbackHead = pCallback;
2651 return pfnFunc;
2652 }
2653
2654 return NULL;
2655}
2656
2657
2658/** CRT - atexit */
2659static int __cdecl kwSandbox_msvcrt_atexit(int (__cdecl *pfnFunc)(void))
2660{
2661 PKWEXITCALLACK pCallback;
2662 KW_LOG(("_onexit(%p)\n", pfnFunc));
2663 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
2664
2665 pCallback = kHlpAlloc(sizeof(*pCallback));
2666 if (pCallback)
2667 {
2668 pCallback->pfnCallback = (_onexit_t)pfnFunc;
2669 pCallback->fAtExit = K_TRUE;
2670 pCallback->pNext = g_Sandbox.pExitCallbackHead;
2671 g_Sandbox.pExitCallbackHead = pCallback;
2672 return 0;
2673 }
2674
2675 return -1;
2676}
2677
2678
2679/** Kernel32 - SetConsoleCtrlHandler(). */
2680static BOOL WINAPI kwSandbox_Kernel32_SetConsoleCtrlHandler(PHANDLER_ROUTINE pfnHandler, BOOL fAdd)
2681{
2682 KW_LOG(("SetConsoleCtrlHandler(%p, %d) - ignoring\n"));
2683 return TRUE;
2684}
2685
2686
2687/** The CRT internal __getmainargs() API. */
2688static int __cdecl kwSandbox_msvcrt___getmainargs(int *pargc, char ***pargv, char ***penvp,
2689 int dowildcard, int const *piNewMode)
2690{
2691 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
2692 *pargc = g_Sandbox.cArgs;
2693 *pargv = g_Sandbox.papszArgs;
2694 *penvp = g_Sandbox.environ;
2695
2696 /** @todo startinfo points at a newmode (setmode) value. */
2697 return 0;
2698}
2699
2700
2701/** The CRT internal __wgetmainargs() API. */
2702static int __cdecl kwSandbox_msvcrt___wgetmainargs(int *pargc, wchar_t ***pargv, wchar_t ***penvp,
2703 int dowildcard, int const *piNewMode)
2704{
2705 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
2706 *pargc = g_Sandbox.cArgs;
2707 *pargv = g_Sandbox.papwszArgs;
2708 *penvp = g_Sandbox.wenviron;
2709
2710 /** @todo startinfo points at a newmode (setmode) value. */
2711 return 0;
2712}
2713
2714
2715
2716/** Kernel32 - GetCommandLineA() */
2717static LPCSTR /*LPSTR*/ WINAPI kwSandbox_Kernel32_GetCommandLineA(VOID)
2718{
2719 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
2720 return g_Sandbox.pszCmdLine;
2721}
2722
2723
2724/** Kernel32 - GetCommandLineW() */
2725static LPCWSTR /*LPWSTR*/ WINAPI kwSandbox_Kernel32_GetCommandLineW(VOID)
2726{
2727 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
2728 return g_Sandbox.pwszCmdLine;
2729}
2730
2731
2732/** Kernel32 - GetStartupInfoA() */
2733static VOID WINAPI kwSandbox_Kernel32_GetStartupInfoA(LPSTARTUPINFOA pStartupInfo)
2734{
2735 KW_LOG(("GetStartupInfoA\n"));
2736 GetStartupInfoA(pStartupInfo);
2737 pStartupInfo->lpReserved = NULL;
2738 pStartupInfo->lpTitle = NULL;
2739 pStartupInfo->lpReserved2 = NULL;
2740 pStartupInfo->cbReserved2 = 0;
2741}
2742
2743
2744/** Kernel32 - GetStartupInfoW() */
2745static VOID WINAPI kwSandbox_Kernel32_GetStartupInfoW(LPSTARTUPINFOW pStartupInfo)
2746{
2747 KW_LOG(("GetStartupInfoW\n"));
2748 GetStartupInfoW(pStartupInfo);
2749 pStartupInfo->lpReserved = NULL;
2750 pStartupInfo->lpTitle = NULL;
2751 pStartupInfo->lpReserved2 = NULL;
2752 pStartupInfo->cbReserved2 = 0;
2753}
2754
2755
2756/** CRT - __p___argc(). */
2757static int * __cdecl kwSandbox_msvcrt___p___argc(void)
2758{
2759 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
2760 return &g_Sandbox.cArgs;
2761}
2762
2763
2764/** CRT - __p___argv(). */
2765static char *** __cdecl kwSandbox_msvcrt___p___argv(void)
2766{
2767 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
2768 return &g_Sandbox.papszArgs;
2769}
2770
2771
2772/** CRT - __p___sargv(). */
2773static wchar_t *** __cdecl kwSandbox_msvcrt___p___wargv(void)
2774{
2775 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
2776 return &g_Sandbox.papwszArgs;
2777}
2778
2779
2780/** CRT - __p__acmdln(). */
2781static char ** __cdecl kwSandbox_msvcrt___p__acmdln(void)
2782{
2783 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
2784 return (char **)&g_Sandbox.pszCmdLine;
2785}
2786
2787
2788/** CRT - __p__acmdln(). */
2789static wchar_t ** __cdecl kwSandbox_msvcrt___p__wcmdln(void)
2790{
2791 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
2792 return &g_Sandbox.pwszCmdLine;
2793}
2794
2795
2796/** CRT - __p__pgmptr(). */
2797static char ** __cdecl kwSandbox_msvcrt___p__pgmptr(void)
2798{
2799 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
2800 return &g_Sandbox.pgmptr;
2801}
2802
2803
2804/** CRT - __p__wpgmptr(). */
2805static wchar_t ** __cdecl kwSandbox_msvcrt___p__wpgmptr(void)
2806{
2807 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
2808 return &g_Sandbox.wpgmptr;
2809}
2810
2811
2812/** CRT - _get_pgmptr(). */
2813static errno_t __cdecl kwSandbox_msvcrt__get_pgmptr(char **ppszValue)
2814{
2815 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
2816 *ppszValue = g_Sandbox.pgmptr;
2817 return 0;
2818}
2819
2820
2821/** CRT - _get_wpgmptr(). */
2822static errno_t __cdecl kwSandbox_msvcrt__get_wpgmptr(wchar_t **ppwszValue)
2823{
2824 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
2825 *ppwszValue = g_Sandbox.wpgmptr;
2826 return 0;
2827}
2828
2829/** Just in case. */
2830static void kwSandbox_msvcrt__wincmdln(void)
2831{
2832 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
2833 KWFS_TODO();
2834}
2835
2836
2837/** Just in case. */
2838static void kwSandbox_msvcrt__wwincmdln(void)
2839{
2840 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
2841 KWFS_TODO();
2842}
2843
2844/** CreateThread interceptor. */
2845static HANDLE WINAPI kwSandbox_Kernel32_CreateThread(LPSECURITY_ATTRIBUTES pSecAttr, SIZE_T cbStack,
2846 PTHREAD_START_ROUTINE pfnThreadProc, PVOID pvUser,
2847 DWORD fFlags, PDWORD pidThread)
2848{
2849 HANDLE hThread = NULL;
2850 KW_LOG(("CreateThread: pSecAttr=%p (inh=%d) cbStack=%#x pfnThreadProc=%p pvUser=%p fFlags=%#x pidThread=%p\n",
2851 pSecAttr, pSecAttr ? pSecAttr->bInheritHandle : 0, cbStack, pfnThreadProc, pvUser, fFlags, pidThread));
2852 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
2853 if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK)
2854 {
2855 /* Allow link::DbgThread. */
2856 hThread = CreateThread(pSecAttr, cbStack, pfnThreadProc, pvUser, fFlags, pidThread);
2857 KW_LOG(("CreateThread -> %p, *pidThread=%#x\n", hThread, pidThread ? *pidThread : 0));
2858 }
2859 else
2860 KWFS_TODO();
2861 return hThread;
2862}
2863
2864
2865/** _beginthread - create a new thread. */
2866static uintptr_t __cdecl kwSandbox_msvcrt__beginthread(void (__cdecl *pfnThreadProc)(void *), unsigned cbStack, void *pvUser)
2867{
2868 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
2869 KWFS_TODO();
2870 return 0;
2871}
2872
2873
2874/** _beginthreadex - create a new thread. */
2875static uintptr_t __cdecl kwSandbox_msvcrt__beginthreadex(void *pvSecAttr, unsigned cbStack,
2876 unsigned (__stdcall *pfnThreadProc)(void *), void *pvUser,
2877 unsigned fCreate, unsigned *pidThread)
2878{
2879 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
2880 KWFS_TODO();
2881 return 0;
2882}
2883
2884
2885/*
2886 *
2887 * Environment related APIs.
2888 * Environment related APIs.
2889 * Environment related APIs.
2890 *
2891 */
2892
2893/** Kernel32 - GetEnvironmentStringsA (Watcom uses this one). */
2894static LPCH WINAPI kwSandbox_Kernel32_GetEnvironmentStringsA(void)
2895{
2896 char *pszzEnv;
2897 char *pszCur;
2898 KSIZE cbNeeded = 1;
2899 KSIZE iVar = 0;
2900
2901 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
2902
2903 /* Figure how space much we need first. */
2904 while ((pszCur = g_Sandbox.papszEnvVars[iVar++]) != NULL)
2905 cbNeeded += kHlpStrLen(pszCur) + 1;
2906
2907 /* Allocate it. */
2908 pszzEnv = kHlpAlloc(cbNeeded);
2909 if (pszzEnv)
2910 {
2911 char *psz = pszzEnv;
2912 iVar = 0;
2913 while ((pszCur = g_Sandbox.papszEnvVars[iVar++]) != NULL)
2914 {
2915 KSIZE cbCur = kHlpStrLen(pszCur) + 1;
2916 kHlpAssert((KUPTR)(&psz[cbCur] - pszzEnv) < cbNeeded);
2917 psz = (char *)kHlpMemPCopy(psz, pszCur, cbCur);
2918 }
2919 *psz++ = '\0';
2920 kHlpAssert(psz - pszzEnv == cbNeeded);
2921 }
2922
2923 KW_LOG(("GetEnvironmentStringsA -> %p [%u]\n", pszzEnv, cbNeeded));
2924#if 0
2925 fprintf(stderr, "GetEnvironmentStringsA: %p LB %#x\n", pszzEnv, cbNeeded);
2926 pszCur = pszzEnv;
2927 iVar = 0;
2928 while (*pszCur)
2929 {
2930 fprintf(stderr, " %u:%p=%s<eos>\n\n", iVar, pszCur, pszCur);
2931 iVar++;
2932 pszCur += kHlpStrLen(pszCur) + 1;
2933 }
2934 fprintf(stderr, " %u:%p=<eos>\n\n", iVar, pszCur);
2935 pszCur++;
2936 fprintf(stderr, "ended at %p, after %u bytes (exepcted %u)\n", pszCur, pszCur - pszzEnv, cbNeeded);
2937#endif
2938 return pszzEnv;
2939}
2940
2941
2942/** Kernel32 - GetEnvironmentStrings */
2943static LPCH WINAPI kwSandbox_Kernel32_GetEnvironmentStrings(void)
2944{
2945 KW_LOG(("GetEnvironmentStrings!\n"));
2946 return kwSandbox_Kernel32_GetEnvironmentStringsA();
2947}
2948
2949
2950/** Kernel32 - GetEnvironmentStringsW */
2951static LPWCH WINAPI kwSandbox_Kernel32_GetEnvironmentStringsW(void)
2952{
2953 wchar_t *pwszzEnv;
2954 wchar_t *pwszCur;
2955 KSIZE cwcNeeded = 1;
2956 KSIZE iVar = 0;
2957
2958 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
2959
2960 /* Figure how space much we need first. */
2961 while ((pwszCur = g_Sandbox.papwszEnvVars[iVar++]) != NULL)
2962 cwcNeeded += kwUtf16Len(pwszCur) + 1;
2963
2964 /* Allocate it. */
2965 pwszzEnv = kHlpAlloc(cwcNeeded * sizeof(wchar_t));
2966 if (pwszzEnv)
2967 {
2968 wchar_t *pwsz = pwszzEnv;
2969 iVar = 0;
2970 while ((pwszCur = g_Sandbox.papwszEnvVars[iVar++]) != NULL)
2971 {
2972 KSIZE cwcCur = kwUtf16Len(pwszCur) + 1;
2973 kHlpAssert((KUPTR)(&pwsz[cwcCur] - pwszzEnv) < cwcNeeded);
2974 pwsz = (wchar_t *)kHlpMemPCopy(pwsz, pwszCur, cwcCur * sizeof(wchar_t));
2975 }
2976 *pwsz++ = '\0';
2977 kHlpAssert(pwsz - pwszzEnv == cwcNeeded);
2978 }
2979
2980 KW_LOG(("GetEnvironmentStringsW -> %p [%u]\n", pwszzEnv, cwcNeeded));
2981 return pwszzEnv;
2982}
2983
2984
2985/** Kernel32 - FreeEnvironmentStringsA */
2986static BOOL WINAPI kwSandbox_Kernel32_FreeEnvironmentStringsA(LPCH pszzEnv)
2987{
2988 KW_LOG(("FreeEnvironmentStringsA: %p -> TRUE\n", pszzEnv));
2989 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
2990 kHlpFree(pszzEnv);
2991 return TRUE;
2992}
2993
2994
2995/** Kernel32 - FreeEnvironmentStringsW */
2996static BOOL WINAPI kwSandbox_Kernel32_FreeEnvironmentStringsW(LPWCH pwszzEnv)
2997{
2998 KW_LOG(("FreeEnvironmentStringsW: %p -> TRUE\n", pwszzEnv));
2999 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
3000 kHlpFree(pwszzEnv);
3001 return TRUE;
3002}
3003
3004
3005/**
3006 * Grows the environment vectors (KWSANDBOX::environ, KWSANDBOX::papszEnvVars,
3007 * KWSANDBOX::wenviron, and KWSANDBOX::papwszEnvVars).
3008 *
3009 * @returns 0 on success, non-zero on failure.
3010 * @param pSandbox The sandbox.
3011 * @param cMin Minimum size, including terminator.
3012 */
3013static int kwSandboxGrowEnv(PKWSANDBOX pSandbox, KSIZE cMin)
3014{
3015 void *pvNew;
3016 KSIZE const cOld = pSandbox->cEnvVarsAllocated;
3017 KSIZE cNew = cOld + 256;
3018 while (cNew < cMin)
3019 cNew += 256;
3020
3021
3022 pvNew = kHlpRealloc(pSandbox->environ, cNew * sizeof(pSandbox->environ[0]));
3023 if (pvNew)
3024 {
3025 pSandbox->environ = (char **)pvNew;
3026 pSandbox->environ[cOld] = NULL;
3027
3028 pvNew = kHlpRealloc(pSandbox->papszEnvVars, cNew * sizeof(pSandbox->papszEnvVars[0]));
3029 if (pvNew)
3030 {
3031 pSandbox->papszEnvVars = (char **)pvNew;
3032 pSandbox->papszEnvVars[cOld] = NULL;
3033
3034 pvNew = kHlpRealloc(pSandbox->wenviron, cNew * sizeof(pSandbox->wenviron[0]));
3035 if (pvNew)
3036 {
3037 pSandbox->wenviron = (wchar_t **)pvNew;
3038 pSandbox->wenviron[cOld] = NULL;
3039
3040 pvNew = kHlpRealloc(pSandbox->papwszEnvVars, cNew * sizeof(pSandbox->papwszEnvVars[0]));
3041 if (pvNew)
3042 {
3043 pSandbox->papwszEnvVars = (wchar_t **)pvNew;
3044 pSandbox->papwszEnvVars[cOld] = NULL;
3045
3046 pSandbox->cEnvVarsAllocated = cNew;
3047 KW_LOG(("kwSandboxGrowEnv: cNew=%d - crt: %p / %p; shadow: %p, %p\n",
3048 cNew, pSandbox->environ, pSandbox->wenviron, pSandbox->papszEnvVars, pSandbox->papwszEnvVars));
3049 return 0;
3050 }
3051 }
3052 }
3053 }
3054 kwErrPrintf("kwSandboxGrowEnv ran out of memory! cNew=%u\n", cNew);
3055 return KERR_NO_MEMORY;
3056}
3057
3058
3059/**
3060 * Sets an environment variable, ANSI style.
3061 *
3062 * @returns 0 on success, non-zero on failure.
3063 * @param pSandbox The sandbox.
3064 * @param pchVar The variable name.
3065 * @param cchVar The length of the name.
3066 * @param pszValue The value.
3067 */
3068static int kwSandboxDoSetEnvA(PKWSANDBOX pSandbox, const char *pchVar, KSIZE cchVar, const char *pszValue)
3069{
3070 /* Allocate and construct the new strings. */
3071 KSIZE cchTmp = kHlpStrLen(pszValue);
3072 char *pszNew = (char *)kHlpAlloc(cchVar + 1 + cchTmp + 1);
3073 if (pszNew)
3074 {
3075 wchar_t *pwszNew;
3076 kHlpMemCopy(pszNew, pchVar, cchVar);
3077 pszNew[cchVar] = '=';
3078 kHlpMemCopy(&pszNew[cchVar + 1], pszValue, cchTmp);
3079 cchTmp += cchVar + 1;
3080 pszNew[cchTmp] = '\0';
3081
3082 pwszNew = kwStrToUtf16AllocN(pszNew, cchTmp);
3083 if (pwszNew)
3084 {
3085 /* Look it up. */
3086 KSIZE iVar = 0;
3087 char *pszEnv;
3088 while ((pszEnv = pSandbox->papszEnvVars[iVar]) != NULL)
3089 {
3090 if ( _strnicmp(pszEnv, pchVar, cchVar) == 0
3091 && pszEnv[cchVar] == '=')
3092 {
3093 KW_LOG(("kwSandboxDoSetEnvA: Replacing iVar=%d: %p='%s' and %p='%ls'\n"
3094 " iVar=%d: %p='%s' and %p='%ls'\n",
3095 iVar, pSandbox->papszEnvVars[iVar], pSandbox->papszEnvVars[iVar],
3096 pSandbox->papwszEnvVars[iVar], pSandbox->papwszEnvVars[iVar],
3097 iVar, pszNew, pszNew, pwszNew, pwszNew));
3098
3099 kHlpFree(pSandbox->papszEnvVars[iVar]);
3100 pSandbox->papszEnvVars[iVar] = pszNew;
3101 pSandbox->environ[iVar] = pszNew;
3102
3103 kHlpFree(pSandbox->papwszEnvVars[iVar]);
3104 pSandbox->papwszEnvVars[iVar] = pwszNew;
3105 pSandbox->wenviron[iVar] = pwszNew;
3106 return 0;
3107 }
3108 iVar++;
3109 }
3110
3111 /* Not found, do we need to grow the table first? */
3112 if (iVar + 1 >= pSandbox->cEnvVarsAllocated)
3113 kwSandboxGrowEnv(pSandbox, iVar + 2);
3114 if (iVar + 1 < pSandbox->cEnvVarsAllocated)
3115 {
3116 KW_LOG(("kwSandboxDoSetEnvA: Adding iVar=%d: %p='%s' and %p='%ls'\n", iVar, pszNew, pszNew, pwszNew, pwszNew));
3117
3118 pSandbox->papszEnvVars[iVar + 1] = NULL;
3119 pSandbox->papszEnvVars[iVar] = pszNew;
3120 pSandbox->environ[iVar + 1] = NULL;
3121 pSandbox->environ[iVar] = pszNew;
3122
3123 pSandbox->papwszEnvVars[iVar + 1] = NULL;
3124 pSandbox->papwszEnvVars[iVar] = pwszNew;
3125 pSandbox->wenviron[iVar + 1] = NULL;
3126 pSandbox->wenviron[iVar] = pwszNew;
3127 return 0;
3128 }
3129
3130 kHlpFree(pwszNew);
3131 }
3132 kHlpFree(pszNew);
3133 }
3134 KW_LOG(("Out of memory!\n"));
3135 return 0;
3136}
3137
3138
3139/**
3140 * Sets an environment variable, UTF-16 style.
3141 *
3142 * @returns 0 on success, non-zero on failure.
3143 * @param pSandbox The sandbox.
3144 * @param pwcVar The variable name.
3145 * @param cwcVar The length of the name.
3146 * @param pwszValue The value.
3147 */
3148static int kwSandboxDoSetEnvW(PKWSANDBOX pSandbox, const wchar_t *pwchVar, KSIZE cwcVar, const wchar_t *pwszValue)
3149{
3150 /* Allocate and construct the new strings. */
3151 KSIZE cwcTmp = kwUtf16Len(pwszValue);
3152 wchar_t *pwszNew = (wchar_t *)kHlpAlloc((cwcVar + 1 + cwcTmp + 1) * sizeof(wchar_t));
3153 if (pwszNew)
3154 {
3155 char *pszNew;
3156 kHlpMemCopy(pwszNew, pwchVar, cwcVar * sizeof(wchar_t));
3157 pwszNew[cwcVar] = '=';
3158 kHlpMemCopy(&pwszNew[cwcVar + 1], pwszValue, cwcTmp * sizeof(wchar_t));
3159 cwcTmp += cwcVar + 1;
3160 pwszNew[cwcVar] = '\0';
3161
3162 pszNew = kwUtf16ToStrAllocN(pwszNew, cwcVar);
3163 if (pszNew)
3164 {
3165 /* Look it up. */
3166 KSIZE iVar = 0;
3167 wchar_t *pwszEnv;
3168 while ((pwszEnv = pSandbox->papwszEnvVars[iVar]) != NULL)
3169 {
3170 if ( _wcsnicmp(pwszEnv, pwchVar, cwcVar) == 0
3171 && pwszEnv[cwcVar] == '=')
3172 {
3173 KW_LOG(("kwSandboxDoSetEnvW: Replacing iVar=%d: %p='%s' and %p='%ls'\n"
3174 " iVar=%d: %p='%s' and %p='%ls'\n",
3175 iVar, pSandbox->papszEnvVars[iVar], pSandbox->papszEnvVars[iVar],
3176 pSandbox->papwszEnvVars[iVar], pSandbox->papwszEnvVars[iVar],
3177 iVar, pszNew, pszNew, pwszNew, pwszNew));
3178
3179 kHlpFree(pSandbox->papszEnvVars[iVar]);
3180 pSandbox->papszEnvVars[iVar] = pszNew;
3181 pSandbox->environ[iVar] = pszNew;
3182
3183 kHlpFree(pSandbox->papwszEnvVars[iVar]);
3184 pSandbox->papwszEnvVars[iVar] = pwszNew;
3185 pSandbox->wenviron[iVar] = pwszNew;
3186 return 0;
3187 }
3188 iVar++;
3189 }
3190
3191 /* Not found, do we need to grow the table first? */
3192 if (iVar + 1 >= pSandbox->cEnvVarsAllocated)
3193 kwSandboxGrowEnv(pSandbox, iVar + 2);
3194 if (iVar + 1 < pSandbox->cEnvVarsAllocated)
3195 {
3196 KW_LOG(("kwSandboxDoSetEnvW: Adding iVar=%d: %p='%s' and %p='%ls'\n", iVar, pszNew, pszNew, pwszNew, pwszNew));
3197
3198 pSandbox->papszEnvVars[iVar + 1] = NULL;
3199 pSandbox->papszEnvVars[iVar] = pszNew;
3200 pSandbox->environ[iVar + 1] = NULL;
3201 pSandbox->environ[iVar] = pszNew;
3202
3203 pSandbox->papwszEnvVars[iVar + 1] = NULL;
3204 pSandbox->papwszEnvVars[iVar] = pwszNew;
3205 pSandbox->wenviron[iVar + 1] = NULL;
3206 pSandbox->wenviron[iVar] = pwszNew;
3207 return 0;
3208 }
3209
3210 kHlpFree(pwszNew);
3211 }
3212 kHlpFree(pszNew);
3213 }
3214 KW_LOG(("Out of memory!\n"));
3215 return 0;
3216}
3217
3218
3219/** ANSI unsetenv worker. */
3220static int kwSandboxDoUnsetEnvA(PKWSANDBOX pSandbox, const char *pchVar, KSIZE cchVar)
3221{
3222 KSIZE iVar = 0;
3223 char *pszEnv;
3224 while ((pszEnv = pSandbox->papszEnvVars[iVar]) != NULL)
3225 {
3226 if ( _strnicmp(pszEnv, pchVar, cchVar) == 0
3227 && pszEnv[cchVar] == '=')
3228 {
3229 KSIZE cVars = iVar;
3230 while (pSandbox->papszEnvVars[cVars])
3231 cVars++;
3232 kHlpAssert(pSandbox->papwszEnvVars[iVar] != NULL);
3233 kHlpAssert(pSandbox->papwszEnvVars[cVars] == NULL);
3234
3235 KW_LOG(("kwSandboxDoUnsetEnvA: Removing iVar=%d: %p='%s' and %p='%ls'; new cVars=%d\n", iVar,
3236 pSandbox->papszEnvVars[iVar], pSandbox->papszEnvVars[iVar],
3237 pSandbox->papwszEnvVars[iVar], pSandbox->papwszEnvVars[iVar], cVars - 1));
3238
3239 kHlpFree(pSandbox->papszEnvVars[iVar]);
3240 pSandbox->papszEnvVars[iVar] = pSandbox->papszEnvVars[cVars];
3241 pSandbox->environ[iVar] = pSandbox->papszEnvVars[cVars];
3242 pSandbox->papszEnvVars[cVars] = NULL;
3243 pSandbox->environ[cVars] = NULL;
3244
3245 kHlpFree(pSandbox->papwszEnvVars[iVar]);
3246 pSandbox->papwszEnvVars[iVar] = pSandbox->papwszEnvVars[cVars];
3247 pSandbox->wenviron[iVar] = pSandbox->papwszEnvVars[cVars];
3248 pSandbox->papwszEnvVars[cVars] = NULL;
3249 pSandbox->wenviron[cVars] = NULL;
3250 return 0;
3251 }
3252 iVar++;
3253 }
3254 return KERR_ENVVAR_NOT_FOUND;
3255}
3256
3257
3258/** UTF-16 unsetenv worker. */
3259static int kwSandboxDoUnsetEnvW(PKWSANDBOX pSandbox, const wchar_t *pwcVar, KSIZE cwcVar)
3260{
3261 KSIZE iVar = 0;
3262 wchar_t *pwszEnv;
3263 while ((pwszEnv = pSandbox->papwszEnvVars[iVar]) != NULL)
3264 {
3265 if ( _wcsnicmp(pwszEnv, pwcVar, cwcVar) == 0
3266 && pwszEnv[cwcVar] == '=')
3267 {
3268 KSIZE cVars = iVar;
3269 while (pSandbox->papwszEnvVars[cVars])
3270 cVars++;
3271 kHlpAssert(pSandbox->papszEnvVars[iVar] != NULL);
3272 kHlpAssert(pSandbox->papszEnvVars[cVars] == NULL);
3273
3274 KW_LOG(("kwSandboxDoUnsetEnvA: Removing iVar=%d: %p='%s' and %p='%ls'; new cVars=%d\n", iVar,
3275 pSandbox->papszEnvVars[iVar], pSandbox->papszEnvVars[iVar],
3276 pSandbox->papwszEnvVars[iVar], pSandbox->papwszEnvVars[iVar], cVars - 1));
3277
3278 kHlpFree(pSandbox->papszEnvVars[iVar]);
3279 pSandbox->papszEnvVars[iVar] = pSandbox->papszEnvVars[cVars];
3280 pSandbox->environ[iVar] = pSandbox->papszEnvVars[cVars];
3281 pSandbox->papszEnvVars[cVars] = NULL;
3282 pSandbox->environ[cVars] = NULL;
3283
3284 kHlpFree(pSandbox->papwszEnvVars[iVar]);
3285 pSandbox->papwszEnvVars[iVar] = pSandbox->papwszEnvVars[cVars];
3286 pSandbox->wenviron[iVar] = pSandbox->papwszEnvVars[cVars];
3287 pSandbox->papwszEnvVars[cVars] = NULL;
3288 pSandbox->wenviron[cVars] = NULL;
3289 return 0;
3290 }
3291 iVar++;
3292 }
3293 return KERR_ENVVAR_NOT_FOUND;
3294}
3295
3296
3297
3298/** ANSI getenv worker. */
3299static char *kwSandboxDoGetEnvA(PKWSANDBOX pSandbox, const char *pchVar, KSIZE cchVar)
3300{
3301 KSIZE iVar = 0;
3302 char *pszEnv;
3303 while ((pszEnv = pSandbox->papszEnvVars[iVar++]) != NULL)
3304 if ( _strnicmp(pszEnv, pchVar, cchVar) == 0
3305 && pszEnv[cchVar] == '=')
3306 return &pszEnv[cchVar + 1];
3307 return NULL;
3308}
3309
3310
3311/** UTF-16 getenv worker. */
3312static wchar_t *kwSandboxDoGetEnvW(PKWSANDBOX pSandbox, const wchar_t *pwcVar, KSIZE cwcVar)
3313{
3314 KSIZE iVar = 0;
3315 wchar_t *pwszEnv;
3316 while ((pwszEnv = pSandbox->papwszEnvVars[iVar++]) != NULL)
3317 if ( _wcsnicmp(pwszEnv, pwcVar, cwcVar) == 0
3318 && pwszEnv[cwcVar] == '=')
3319 return &pwszEnv[cwcVar + 1];
3320 return NULL;
3321}
3322
3323
3324/** Kernel32 - GetEnvironmentVariableA() */
3325static DWORD WINAPI kwSandbox_Kernel32_GetEnvironmentVariableA(LPCSTR pszVar, LPSTR pszValue, DWORD cbValue)
3326{
3327 char *pszFoundValue;
3328 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
3329
3330 pszFoundValue = kwSandboxDoGetEnvA(&g_Sandbox, pszVar, kHlpStrLen(pszVar));
3331 if (pszFoundValue)
3332 {
3333 DWORD cchRet = kwStrCopyStyle1(pszFoundValue, pszValue, cbValue);
3334 KW_LOG(("GetEnvironmentVariableA: '%s' -> %u (%s)\n", pszVar, cchRet, pszFoundValue));
3335 return cchRet;
3336 }
3337 KW_LOG(("GetEnvironmentVariableA: '%s' -> 0\n", pszVar));
3338 SetLastError(ERROR_ENVVAR_NOT_FOUND);
3339 return 0;
3340}
3341
3342
3343/** Kernel32 - GetEnvironmentVariableW() */
3344static DWORD WINAPI kwSandbox_Kernel32_GetEnvironmentVariableW(LPCWSTR pwszVar, LPWSTR pwszValue, DWORD cwcValue)
3345{
3346 wchar_t *pwszFoundValue;
3347 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
3348
3349 pwszFoundValue = kwSandboxDoGetEnvW(&g_Sandbox, pwszVar, kwUtf16Len(pwszVar));
3350 if (pwszFoundValue)
3351 {
3352 DWORD cchRet = kwUtf16CopyStyle1(pwszFoundValue, pwszValue, cwcValue);
3353 KW_LOG(("GetEnvironmentVariableW: '%ls' -> %u (%ls)\n", pwszVar, cchRet, pwszFoundValue));
3354 return cchRet;
3355 }
3356 KW_LOG(("GetEnvironmentVariableW: '%ls' -> 0\n", pwszVar));
3357 SetLastError(ERROR_ENVVAR_NOT_FOUND);
3358 return 0;
3359}
3360
3361
3362/** Kernel32 - SetEnvironmentVariableA() */
3363static BOOL WINAPI kwSandbox_Kernel32_SetEnvironmentVariableA(LPCSTR pszVar, LPCSTR pszValue)
3364{
3365 int rc;
3366 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
3367
3368 if (pszValue)
3369 rc = kwSandboxDoSetEnvA(&g_Sandbox, pszVar, kHlpStrLen(pszVar), pszValue);
3370 else
3371 {
3372 kwSandboxDoUnsetEnvA(&g_Sandbox, pszVar, kHlpStrLen(pszVar));
3373 rc = 0; //??
3374 }
3375 if (rc == 0)
3376 {
3377 KW_LOG(("SetEnvironmentVariableA(%s,%s) -> TRUE\n", pszVar, pszValue));
3378 return TRUE;
3379 }
3380 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3381 KW_LOG(("SetEnvironmentVariableA(%s,%s) -> FALSE!\n", pszVar, pszValue));
3382 return FALSE;
3383}
3384
3385
3386/** Kernel32 - SetEnvironmentVariableW() */
3387static BOOL WINAPI kwSandbox_Kernel32_SetEnvironmentVariableW(LPCWSTR pwszVar, LPCWSTR pwszValue)
3388{
3389 int rc;
3390 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
3391
3392 if (pwszValue)
3393 rc = kwSandboxDoSetEnvW(&g_Sandbox, pwszVar, kwUtf16Len(pwszVar), pwszValue);
3394 else
3395 {
3396 kwSandboxDoUnsetEnvW(&g_Sandbox, pwszVar, kwUtf16Len(pwszVar));
3397 rc = 0; //??
3398 }
3399 if (rc == 0)
3400 {
3401 KW_LOG(("SetEnvironmentVariableA(%ls,%ls) -> TRUE\n", pwszVar, pwszValue));
3402 return TRUE;
3403 }
3404 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3405 KW_LOG(("SetEnvironmentVariableA(%ls,%ls) -> FALSE!\n", pwszVar, pwszValue));
3406 return FALSE;
3407}
3408
3409
3410/** Kernel32 - ExpandEnvironmentStringsA() */
3411static DWORD WINAPI kwSandbox_Kernel32_ExpandEnvironmentStringsA(LPCSTR pszSrc, LPSTR pwszDst, DWORD cbDst)
3412{
3413 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
3414 KWFS_TODO();
3415 return 0;
3416}
3417
3418
3419/** Kernel32 - ExpandEnvironmentStringsW() */
3420static DWORD WINAPI kwSandbox_Kernel32_ExpandEnvironmentStringsW(LPCWSTR pwszSrc, LPWSTR pwszDst, DWORD cbDst)
3421{
3422 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
3423 KWFS_TODO();
3424 return 0;
3425}
3426
3427
3428/** CRT - _putenv(). */
3429static int __cdecl kwSandbox_msvcrt__putenv(const char *pszVarEqualValue)
3430{
3431 int rc;
3432 char const *pszEqual;
3433 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
3434
3435 pszEqual = kHlpStrChr(pszVarEqualValue, '=');
3436 if (pszEqual)
3437 {
3438 rc = kwSandboxDoSetEnvA(&g_Sandbox, pszVarEqualValue, pszEqual - pszVarEqualValue, pszEqual + 1);
3439 if (rc == 0)
3440 { }
3441 else
3442 rc = -1;
3443 }
3444 else
3445 {
3446 kwSandboxDoUnsetEnvA(&g_Sandbox, pszVarEqualValue, kHlpStrLen(pszVarEqualValue));
3447 rc = 0;
3448 }
3449 KW_LOG(("_putenv(%s) -> %d\n", pszVarEqualValue, rc));
3450 return rc;
3451}
3452
3453
3454/** CRT - _wputenv(). */
3455static int __cdecl kwSandbox_msvcrt__wputenv(const wchar_t *pwszVarEqualValue)
3456{
3457 int rc;
3458 wchar_t const *pwszEqual;
3459 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
3460
3461 pwszEqual = wcschr(pwszVarEqualValue, '=');
3462 if (pwszEqual)
3463 {
3464 rc = kwSandboxDoSetEnvW(&g_Sandbox, pwszVarEqualValue, pwszEqual - pwszVarEqualValue, pwszEqual + 1);
3465 if (rc == 0)
3466 { }
3467 else
3468 rc = -1;
3469 }
3470 else
3471 {
3472 kwSandboxDoUnsetEnvW(&g_Sandbox, pwszVarEqualValue, kwUtf16Len(pwszVarEqualValue));
3473 rc = 0;
3474 }
3475 KW_LOG(("_wputenv(%ls) -> %d\n", pwszVarEqualValue, rc));
3476 return rc;
3477}
3478
3479
3480/** CRT - _putenv_s(). */
3481static errno_t __cdecl kwSandbox_msvcrt__putenv_s(const char *pszVar, const char *pszValue)
3482{
3483 char const *pszEqual;
3484 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
3485
3486 pszEqual = kHlpStrChr(pszVar, '=');
3487 if (pszEqual == NULL)
3488 {
3489 if (pszValue)
3490 {
3491 int rc = kwSandboxDoSetEnvA(&g_Sandbox, pszVar, kHlpStrLen(pszVar), pszValue);
3492 if (rc == 0)
3493 {
3494 KW_LOG(("_putenv_s(%s,%s) -> 0\n", pszVar, pszValue));
3495 return 0;
3496 }
3497 }
3498 else
3499 {
3500 kwSandboxDoUnsetEnvA(&g_Sandbox, pszVar, kHlpStrLen(pszVar));
3501 KW_LOG(("_putenv_s(%ls,NULL) -> 0\n", pszVar));
3502 return 0;
3503 }
3504 KW_LOG(("_putenv_s(%s,%s) -> ENOMEM\n", pszVar, pszValue));
3505 return ENOMEM;
3506 }
3507 KW_LOG(("_putenv_s(%s,%s) -> EINVAL\n", pszVar, pszValue));
3508 return EINVAL;
3509}
3510
3511
3512/** CRT - _wputenv_s(). */
3513static errno_t __cdecl kwSandbox_msvcrt__wputenv_s(const wchar_t *pwszVar, const wchar_t *pwszValue)
3514{
3515 wchar_t const *pwszEqual;
3516 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
3517
3518 pwszEqual = wcschr(pwszVar, '=');
3519 if (pwszEqual == NULL)
3520 {
3521 if (pwszValue)
3522 {
3523 int rc = kwSandboxDoSetEnvW(&g_Sandbox, pwszVar, kwUtf16Len(pwszVar), pwszValue);
3524 if (rc == 0)
3525 {
3526 KW_LOG(("_wputenv_s(%ls,%ls) -> 0\n", pwszVar, pwszValue));
3527 return 0;
3528 }
3529 }
3530 else
3531 {
3532 kwSandboxDoUnsetEnvW(&g_Sandbox, pwszVar, kwUtf16Len(pwszVar));
3533 KW_LOG(("_wputenv_s(%ls,NULL) -> 0\n", pwszVar));
3534 return 0;
3535 }
3536 KW_LOG(("_wputenv_s(%ls,%ls) -> ENOMEM\n", pwszVar, pwszValue));
3537 return ENOMEM;
3538 }
3539 KW_LOG(("_wputenv_s(%ls,%ls) -> EINVAL\n", pwszVar, pwszValue));
3540 return EINVAL;
3541}
3542
3543
3544/** CRT - get pointer to the __initenv variable (initial environment). */
3545static char *** __cdecl kwSandbox_msvcrt___p___initenv(void)
3546{
3547 KW_LOG(("__p___initenv\n"));
3548 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
3549 KWFS_TODO();
3550 return &g_Sandbox.initenv;
3551}
3552
3553
3554/** CRT - get pointer to the __winitenv variable (initial environment). */
3555static wchar_t *** __cdecl kwSandbox_msvcrt___p___winitenv(void)
3556{
3557 KW_LOG(("__p___winitenv\n"));
3558 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
3559 KWFS_TODO();
3560 return &g_Sandbox.winitenv;
3561}
3562
3563
3564/** CRT - get pointer to the _environ variable (current environment). */
3565static char *** __cdecl kwSandbox_msvcrt___p__environ(void)
3566{
3567 KW_LOG(("__p__environ\n"));
3568 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
3569 return &g_Sandbox.environ;
3570}
3571
3572
3573/** CRT - get pointer to the _wenviron variable (current environment). */
3574static wchar_t *** __cdecl kwSandbox_msvcrt___p__wenviron(void)
3575{
3576 KW_LOG(("__p__wenviron\n"));
3577 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
3578 return &g_Sandbox.wenviron;
3579}
3580
3581
3582/** CRT - get the _environ variable (current environment).
3583 * @remarks Not documented or prototyped? */
3584static KUPTR /*void*/ __cdecl kwSandbox_msvcrt__get_environ(char ***ppapszEnviron)
3585{
3586 KWFS_TODO(); /** @todo check the callers expectations! */
3587 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
3588 *ppapszEnviron = g_Sandbox.environ;
3589 return 0;
3590}
3591
3592
3593/** CRT - get the _wenviron variable (current environment).
3594 * @remarks Not documented or prototyped? */
3595static KUPTR /*void*/ __cdecl kwSandbox_msvcrt__get_wenviron(wchar_t ***ppapwszEnviron)
3596{
3597 KWFS_TODO(); /** @todo check the callers expectations! */
3598 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
3599 *ppapwszEnviron = g_Sandbox.wenviron;
3600 return 0;
3601}
3602
3603
3604
3605/*
3606 *
3607 * Loader related APIs
3608 * Loader related APIs
3609 * Loader related APIs
3610 *
3611 */
3612
3613/**
3614 * Kernel32 - LoadLibraryExA() worker that loads resource files and such.
3615 */
3616static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryExA_Resource(PKWDYNLOAD pDynLoad, DWORD fFlags)
3617{
3618 /* Load it first. */
3619 HMODULE hmod = LoadLibraryExA(pDynLoad->szRequest, NULL /*hFile*/, fFlags);
3620 if (hmod)
3621 {
3622 pDynLoad->hmod = hmod;
3623 pDynLoad->pMod = NULL; /* indicates special */
3624
3625 pDynLoad->pNext = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead;
3626 g_Sandbox.pTool->u.Sandboxed.pDynLoadHead = pDynLoad;
3627 KW_LOG(("LoadLibraryExA(%s,,[resource]) -> %p\n", pDynLoad->szRequest, pDynLoad->hmod));
3628 }
3629 else
3630 kHlpFree(pDynLoad);
3631 return hmod;
3632}
3633
3634
3635/**
3636 * Kernel32 - LoadLibraryExA() worker that deals with the api-ms-xxx modules.
3637 */
3638static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryExA_VirtualApiModule(PKWDYNLOAD pDynLoad, DWORD fFlags)
3639{
3640 HMODULE hmod;
3641 PKWMODULE pMod;
3642 KU32 uHashPath;
3643 KSIZE idxHash;
3644 char szNormPath[256];
3645 KSIZE cbFilename = kHlpStrLen(pDynLoad->szRequest) + 1;
3646
3647 /*
3648 * Lower case it.
3649 */
3650 if (cbFilename <= sizeof(szNormPath))
3651 {
3652 kHlpMemCopy(szNormPath, pDynLoad->szRequest, cbFilename);
3653 _strlwr(szNormPath);
3654 }
3655 else
3656 {
3657 SetLastError(ERROR_FILENAME_EXCED_RANGE);
3658 return NULL;
3659 }
3660
3661 /*
3662 * Check if it has already been loaded so we don't create an unnecessary
3663 * loader module for it.
3664 */
3665 uHashPath = kwStrHash(szNormPath);
3666 idxHash = uHashPath % K_ELEMENTS(g_apModules);
3667 pMod = g_apModules[idxHash];
3668 if (pMod)
3669 {
3670 do
3671 {
3672 if ( pMod->uHashPath == uHashPath
3673 && kHlpStrComp(pMod->pszPath, szNormPath) == 0)
3674 {
3675 pDynLoad->pMod = kwLdrModuleRetain(pMod);
3676 pDynLoad->hmod = pMod->hOurMod;
3677
3678 pDynLoad->pNext = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead;
3679 g_Sandbox.pTool->u.Sandboxed.pDynLoadHead = pDynLoad;
3680 KW_LOG(("LoadLibraryExA(%s,,) -> %p [already loaded]\n", pDynLoad->szRequest, pDynLoad->hmod));
3681 return pDynLoad->hmod;
3682 }
3683 pMod = pMod->pNext;
3684 } while (pMod);
3685 }
3686
3687
3688 /*
3689 * Try load it and make a kLdr module for it.
3690 */
3691 hmod = LoadLibraryExA(szNormPath, NULL /*hFile*/, fFlags);
3692 if (hmod)
3693 {
3694 PKLDRMOD pLdrMod;
3695 int rc = kLdrModOpenNativeByHandle((KUPTR)hmod, &pLdrMod);
3696 if (rc == 0)
3697 {
3698 PKWMODULE pMod = kwLdrModuleCreateForNativekLdrModule(pLdrMod, szNormPath, cbFilename, uHashPath,
3699 K_FALSE /*fDoReplacements*/);
3700 if (pMod)
3701 {
3702 kwToolAddModuleAndImports(g_Sandbox.pTool, pMod);
3703
3704 pDynLoad = (PKWDYNLOAD)kHlpAlloc(sizeof(*pDynLoad) + cbFilename + cbFilename * sizeof(wchar_t));
3705 if (pDynLoad)
3706 {
3707 pDynLoad->pMod = pMod;
3708 pDynLoad->hmod = hmod;
3709
3710 pDynLoad->pNext = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead;
3711 g_Sandbox.pTool->u.Sandboxed.pDynLoadHead = pDynLoad;
3712 KW_LOG(("LoadLibraryExA(%s,,) -> %p\n", pDynLoad->szRequest, pDynLoad->hmod));
3713 return hmod;
3714 }
3715
3716 KWFS_TODO();
3717 }
3718 else
3719 KWFS_TODO();
3720 }
3721 else
3722 KWFS_TODO();
3723 }
3724 kHlpFree(pDynLoad);
3725 return hmod;
3726}
3727
3728
3729/** Kernel32 - LoadLibraryExA() */
3730static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryExA(LPCSTR pszFilename, HANDLE hFile, DWORD fFlags)
3731{
3732 KSIZE cchFilename = kHlpStrLen(pszFilename);
3733 PKWDYNLOAD pDynLoad;
3734 PKWMODULE pMod;
3735 int rc;
3736 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
3737
3738 /*
3739 * Deal with a couple of extremely unlikely special cases right away.
3740 */
3741 if ( !(fFlags & LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE)
3742 && (hFile == NULL || hFile == INVALID_HANDLE_VALUE) )
3743 { /* likely */ }
3744 else
3745 {
3746 KWFS_TODO();
3747 return LoadLibraryExA(pszFilename, hFile, fFlags);
3748 }
3749
3750 /*
3751 * Check if we've already got a dynload entry for this one.
3752 */
3753 for (pDynLoad = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead; pDynLoad; pDynLoad = pDynLoad->pNext)
3754 if ( pDynLoad->cchRequest == cchFilename
3755 && kHlpMemComp(pDynLoad->szRequest, pszFilename, cchFilename) == 0)
3756 {
3757 if (pDynLoad->pMod)
3758 rc = kwLdrModuleInitTree(pDynLoad->pMod);
3759 else
3760 rc = 0;
3761 if (rc == 0)
3762 {
3763 KW_LOG(("LoadLibraryExA(%s,,) -> %p [cached]\n", pszFilename, pDynLoad->hmod));
3764 return pDynLoad->hmod;
3765 }
3766 SetLastError(ERROR_DLL_INIT_FAILED);
3767 return NULL;
3768 }
3769
3770 /*
3771 * Allocate a dynload entry for the request.
3772 */
3773 pDynLoad = (PKWDYNLOAD)kHlpAlloc(sizeof(*pDynLoad) + cchFilename + 1);
3774 if (pDynLoad)
3775 {
3776 pDynLoad->cchRequest = cchFilename;
3777 kHlpMemCopy(pDynLoad->szRequest, pszFilename, cchFilename + 1);
3778 }
3779 else
3780 {
3781 KW_LOG(("LoadLibraryExA: Out of memory!\n"));
3782 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3783 return NULL;
3784 }
3785
3786 /*
3787 * Deal with resource / data DLLs.
3788 */
3789 if (fFlags & ( DONT_RESOLVE_DLL_REFERENCES
3790 | LOAD_LIBRARY_AS_DATAFILE
3791 | LOAD_LIBRARY_AS_IMAGE_RESOURCE) )
3792 return kwSandbox_Kernel32_LoadLibraryExA_Resource(pDynLoad, fFlags);
3793
3794 /*
3795 * Special case: api-ms-win-core-synch-l1-2-0 and friends (32-bit yasm, built with VS2015).
3796 */
3797 if ( strnicmp(pszFilename, TUPLE("api-ms-")) == 0
3798 && kHlpIsFilenameOnly(pszFilename))
3799 return kwSandbox_Kernel32_LoadLibraryExA_VirtualApiModule(pDynLoad, fFlags);
3800
3801 /*
3802 * Normal library loading.
3803 * We start by being very lazy and reusing the code for resolving imports.
3804 */
3805 if (!kHlpIsFilenameOnly(pszFilename))
3806 pMod = kwLdrModuleTryLoadDll(pszFilename, KWLOCATION_UNKNOWN, g_Sandbox.pTool->u.Sandboxed.pExe);
3807 else
3808 {
3809 rc = kwLdrModuleResolveAndLookup(pszFilename, g_Sandbox.pTool->u.Sandboxed.pExe, NULL /*pImporter*/, &pMod);
3810 if (rc != 0)
3811 pMod = NULL;
3812 }
3813 if (pMod)
3814 {
3815 /* Enter it into the tool module table and dynamic link request cache. */
3816 kwToolAddModuleAndImports(g_Sandbox.pTool, pMod);
3817
3818 pDynLoad->pMod = pMod;
3819 pDynLoad->hmod = pMod->hOurMod;
3820
3821 pDynLoad->pNext = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead;
3822 g_Sandbox.pTool->u.Sandboxed.pDynLoadHead = pDynLoad;
3823
3824 /*
3825 * Make sure it's initialized (need to link it first since DllMain may
3826 * use loader APIs).
3827 */
3828 rc = kwLdrModuleInitTree(pMod);
3829 if (rc == 0)
3830 {
3831 KW_LOG(("LoadLibraryExA(%s,,) -> %p\n", pszFilename, pDynLoad->hmod));
3832 return pDynLoad->hmod;
3833 }
3834
3835 SetLastError(ERROR_DLL_INIT_FAILED);
3836 }
3837 else
3838 {
3839 KWFS_TODO();
3840 kHlpFree(pDynLoad);
3841 SetLastError(ERROR_MOD_NOT_FOUND);
3842 }
3843 return NULL;
3844}
3845
3846
3847/** Kernel32 - LoadLibraryExW() */
3848static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryExW(LPCWSTR pwszFilename, HANDLE hFile, DWORD fFlags)
3849{
3850 char szTmp[4096];
3851 KSIZE cchTmp = kwUtf16ToStr(pwszFilename, szTmp, sizeof(szTmp));
3852 if (cchTmp < sizeof(szTmp))
3853 return kwSandbox_Kernel32_LoadLibraryExA(szTmp, hFile, fFlags);
3854
3855 KWFS_TODO();
3856 SetLastError(ERROR_FILENAME_EXCED_RANGE);
3857 return NULL;
3858}
3859
3860/** Kernel32 - LoadLibraryA() */
3861static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryA(LPCSTR pszFilename)
3862{
3863 return kwSandbox_Kernel32_LoadLibraryExA(pszFilename, NULL /*hFile*/, 0 /*fFlags*/);
3864}
3865
3866
3867/** Kernel32 - LoadLibraryW() */
3868static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryW(LPCWSTR pwszFilename)
3869{
3870 char szTmp[4096];
3871 KSIZE cchTmp = kwUtf16ToStr(pwszFilename, szTmp, sizeof(szTmp));
3872 if (cchTmp < sizeof(szTmp))
3873 return kwSandbox_Kernel32_LoadLibraryExA(szTmp, NULL /*hFile*/, 0 /*fFlags*/);
3874 KWFS_TODO();
3875 SetLastError(ERROR_FILENAME_EXCED_RANGE);
3876 return NULL;
3877}
3878
3879
3880/** Kernel32 - FreeLibrary() */
3881static BOOL WINAPI kwSandbox_Kernel32_FreeLibrary(HMODULE hmod)
3882{
3883 /* Ignored, we like to keep everything loaded. */
3884 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
3885 return TRUE;
3886}
3887
3888
3889/** Kernel32 - GetModuleHandleA() */
3890static HMODULE WINAPI kwSandbox_Kernel32_GetModuleHandleA(LPCSTR pszModule)
3891{
3892 KSIZE i;
3893 KSIZE cchModule;
3894 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
3895
3896 /*
3897 * The executable.
3898 */
3899 if (pszModule == NULL)
3900 return (HMODULE)g_Sandbox.pTool->u.Sandboxed.pExe->hOurMod;
3901
3902 /*
3903 * Cache of system modules we've seen queried.
3904 */
3905 cchModule = kHlpStrLen(pszModule);
3906 for (i = 0; i < K_ELEMENTS(g_aGetModuleHandleCache); i++)
3907 if ( g_aGetModuleHandleCache[i].cchName == cchModule
3908 && stricmp(pszModule, g_aGetModuleHandleCache[i].pszName) == 0)
3909 {
3910 if (g_aGetModuleHandleCache[i].hmod != NULL)
3911 return g_aGetModuleHandleCache[i].hmod;
3912 return g_aGetModuleHandleCache[i].hmod = GetModuleHandleA(pszModule);
3913 }
3914
3915 KWFS_TODO();
3916 return NULL;
3917}
3918
3919
3920/** Kernel32 - GetModuleHandleW() */
3921static HMODULE WINAPI kwSandbox_Kernel32_GetModuleHandleW(LPCWSTR pwszModule)
3922{
3923 KSIZE i;
3924 KSIZE cwcModule;
3925 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
3926
3927 /*
3928 * The executable.
3929 */
3930 if (pwszModule == NULL)
3931 return (HMODULE)g_Sandbox.pTool->u.Sandboxed.pExe->hOurMod;
3932
3933 /*
3934 * Cache of system modules we've seen queried.
3935 */
3936 cwcModule = kwUtf16Len(pwszModule);
3937 for (i = 0; i < K_ELEMENTS(g_aGetModuleHandleCache); i++)
3938 if ( g_aGetModuleHandleCache[i].cwcName == cwcModule
3939 && _wcsicmp(pwszModule, g_aGetModuleHandleCache[i].pwszName) == 0)
3940 {
3941 if (g_aGetModuleHandleCache[i].hmod != NULL)
3942 return g_aGetModuleHandleCache[i].hmod;
3943 return g_aGetModuleHandleCache[i].hmod = GetModuleHandleW(pwszModule);
3944 }
3945
3946 KWFS_TODO();
3947 return NULL;
3948}
3949
3950
3951/** Used to debug dynamically resolved procedures. */
3952static UINT WINAPI kwSandbox_BreakIntoDebugger(void *pv1, void *pv2, void *pv3, void *pv4)
3953{
3954#ifdef _MSC_VER
3955 __debugbreak();
3956#else
3957 KWFS_TODO();
3958#endif
3959 return -1;
3960}
3961
3962
3963/** Kernel32 - GetProcAddress() */
3964static FARPROC WINAPI kwSandbox_Kernel32_GetProcAddress(HMODULE hmod, LPCSTR pszProc)
3965{
3966 KSIZE i;
3967 PKWMODULE pMod;
3968 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
3969
3970 /*
3971 * Try locate the module.
3972 */
3973 pMod = kwToolLocateModuleByHandle(g_Sandbox.pTool, hmod);
3974 if (pMod)
3975 {
3976 KLDRADDR uValue;
3977 int rc = kLdrModQuerySymbol(pMod->pLdrMod,
3978 pMod->fNative ? NULL : pMod->u.Manual.pvBits,
3979 pMod->fNative ? KLDRMOD_BASEADDRESS_MAP : (KUPTR)pMod->u.Manual.pvLoad,
3980 KU32_MAX /*iSymbol*/,
3981 pszProc,
3982 kHlpStrLen(pszProc),
3983 NULL /*pszVersion*/,
3984 NULL /*pfnGetForwarder*/, NULL /*pvUser*/,
3985 &uValue,
3986 NULL /*pfKind*/);
3987 if (rc == 0)
3988 {
3989 static int s_cDbgGets = 0;
3990 s_cDbgGets++;
3991 KW_LOG(("GetProcAddress(%s, %s) -> %p [%d]\n", pMod->pszPath, pszProc, (KUPTR)uValue, s_cDbgGets));
3992 kwLdrModuleRelease(pMod);
3993 //if (s_cGets >= 3)
3994 // return (FARPROC)kwSandbox_BreakIntoDebugger;
3995 return (FARPROC)(KUPTR)uValue;
3996 }
3997
3998 KWFS_TODO();
3999 SetLastError(ERROR_PROC_NOT_FOUND);
4000 kwLdrModuleRelease(pMod);
4001 return NULL;
4002 }
4003
4004 /*
4005 * Hmm... could be a cached module-by-name.
4006 */
4007 for (i = 0; i < K_ELEMENTS(g_aGetModuleHandleCache); i++)
4008 if (g_aGetModuleHandleCache[i].hmod == hmod)
4009 return GetProcAddress(hmod, pszProc);
4010
4011 KWFS_TODO();
4012 return GetProcAddress(hmod, pszProc);
4013}
4014
4015
4016/** Kernel32 - GetModuleFileNameA() */
4017static DWORD WINAPI kwSandbox_Kernel32_GetModuleFileNameA(HMODULE hmod, LPSTR pszFilename, DWORD cbFilename)
4018{
4019 PKWMODULE pMod;
4020 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
4021
4022 pMod = kwToolLocateModuleByHandle(g_Sandbox.pTool, hmod);
4023 if (pMod != NULL)
4024 {
4025 DWORD cbRet = kwStrCopyStyle1(pMod->pszPath, pszFilename, cbFilename);
4026 kwLdrModuleRelease(pMod);
4027 return cbRet;
4028 }
4029 KWFS_TODO();
4030 return 0;
4031}
4032
4033
4034/** Kernel32 - GetModuleFileNameW() */
4035static DWORD WINAPI kwSandbox_Kernel32_GetModuleFileNameW(HMODULE hmod, LPWSTR pwszFilename, DWORD cbFilename)
4036{
4037 PKWMODULE pMod;
4038 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
4039
4040 pMod = kwToolLocateModuleByHandle(g_Sandbox.pTool, hmod);
4041 if (pMod)
4042 {
4043 DWORD cwcRet = kwUtf16CopyStyle1(pMod->pwszPath, pwszFilename, cbFilename);
4044 kwLdrModuleRelease(pMod);
4045 return cwcRet;
4046 }
4047
4048 KWFS_TODO();
4049 return 0;
4050}
4051
4052
4053/** NtDll - RtlPcToFileHeader
4054 * This is necessary for msvcr100.dll!CxxThrowException. */
4055static PVOID WINAPI kwSandbox_ntdll_RtlPcToFileHeader(PVOID pvPC, PVOID *ppvImageBase)
4056{
4057 PVOID pvRet;
4058
4059 /*
4060 * Do a binary lookup of the module table for the current tool.
4061 * This will give us a
4062 */
4063 if (g_Sandbox.fRunning)
4064 {
4065 KUPTR const uPC = (KUPTR)pvPC;
4066 PKWMODULE *papMods = g_Sandbox.pTool->u.Sandboxed.papModules;
4067 KU32 iEnd = g_Sandbox.pTool->u.Sandboxed.cModules;
4068 KU32 i;
4069 if (iEnd)
4070 {
4071 KU32 iStart = 0;
4072 i = iEnd / 2;
4073 for (;;)
4074 {
4075 KUPTR const uHModThis = (KUPTR)papMods[i]->hOurMod;
4076 if (uPC < uHModThis)
4077 {
4078 iEnd = i;
4079 if (iStart < i)
4080 { }
4081 else
4082 break;
4083 }
4084 else if (uPC != uHModThis)
4085 {
4086 iStart = ++i;
4087 if (i < iEnd)
4088 { }
4089 else
4090 break;
4091 }
4092 else
4093 {
4094 /* This isn't supposed to happen. */
4095 break;
4096 }
4097
4098 i = iStart + (iEnd - iStart) / 2;
4099 }
4100
4101 /* For reasons of simplicity (= copy & paste), we end up with the
4102 module after the one we're interested in here. */
4103 i--;
4104 if (i < g_Sandbox.pTool->u.Sandboxed.cModules
4105 && papMods[i]->pLdrMod)
4106 {
4107 KSIZE uRvaPC = uPC - (KUPTR)papMods[i]->hOurMod;
4108 if (uRvaPC < papMods[i]->cbImage)
4109 {
4110 *ppvImageBase = papMods[i]->hOurMod;
4111 pvRet = papMods[i]->hOurMod;
4112 KW_LOG(("RtlPcToFileHeader(PC=%p) -> %p, *ppvImageBase=%p [our]\n", pvPC, pvRet, *ppvImageBase));
4113 return pvRet;
4114 }
4115 }
4116 }
4117 else
4118 i = 0;
4119 }
4120
4121 /*
4122 * Call the regular API.
4123 */
4124 pvRet = RtlPcToFileHeader(pvPC, ppvImageBase);
4125 KW_LOG(("RtlPcToFileHeader(PC=%p) -> %p, *ppvImageBase=%p \n", pvPC, pvRet, *ppvImageBase));
4126 return pvRet;
4127}
4128
4129
4130/*
4131 *
4132 * File access APIs (for speeding them up).
4133 * File access APIs (for speeding them up).
4134 * File access APIs (for speeding them up).
4135 *
4136 */
4137
4138
4139/**
4140 * Converts a lookup error to a windows error code.
4141 *
4142 * @returns The windows error code.
4143 * @param enmError The lookup error.
4144 */
4145static DWORD kwFsLookupErrorToWindowsError(KFSLOOKUPERROR enmError)
4146{
4147 switch (enmError)
4148 {
4149 case KFSLOOKUPERROR_NOT_FOUND:
4150 case KFSLOOKUPERROR_NOT_DIR:
4151 return ERROR_FILE_NOT_FOUND;
4152
4153 case KFSLOOKUPERROR_PATH_COMP_NOT_FOUND:
4154 case KFSLOOKUPERROR_PATH_COMP_NOT_DIR:
4155 return ERROR_PATH_NOT_FOUND;
4156
4157 case KFSLOOKUPERROR_PATH_TOO_LONG:
4158 return ERROR_FILENAME_EXCED_RANGE;
4159
4160 case KFSLOOKUPERROR_OUT_OF_MEMORY:
4161 return ERROR_NOT_ENOUGH_MEMORY;
4162
4163 default:
4164 return ERROR_PATH_NOT_FOUND;
4165 }
4166}
4167
4168#ifdef WITH_TEMP_MEMORY_FILES
4169
4170/**
4171 * Checks for a cl.exe temporary file.
4172 *
4173 * There are quite a bunch of these. They seems to be passing data between the
4174 * first and second compiler pass. Since they're on disk, they get subjected to
4175 * AV software screening and normal file consistency rules. So, not necessarily
4176 * a very efficient way of handling reasonably small amounts of data.
4177 *
4178 * We make the files live in virtual memory by intercepting their opening,
4179 * writing, reading, closing , mapping, unmapping, and maybe some more stuff.
4180 *
4181 * @returns K_TRUE / K_FALSE
4182 * @param pwszFilename The file name being accessed.
4183 */
4184static KBOOL kwFsIsClTempFileW(const wchar_t *pwszFilename)
4185{
4186 wchar_t const *pwszName = kwPathGetFilenameW(pwszFilename);
4187 if (pwszName)
4188 {
4189 /* The name starts with _CL_... */
4190 if ( pwszName[0] == '_'
4191 && pwszName[1] == 'C'
4192 && pwszName[2] == 'L'
4193 && pwszName[3] == '_' )
4194 {
4195 /* ... followed by 8 xdigits and ends with a two letter file type. Simplify
4196 this check by just checking that it's alpha numerical ascii from here on. */
4197 wchar_t wc;
4198 pwszName += 4;
4199 while ((wc = *pwszName++) != '\0')
4200 {
4201 if (wc < 127 && iswalnum(wc))
4202 { /* likely */ }
4203 else
4204 return K_FALSE;
4205 }
4206 return K_TRUE;
4207 }
4208 }
4209 return K_FALSE;
4210}
4211
4212
4213/**
4214 * Creates a handle to a temporary file.
4215 *
4216 * @returns The handle on success.
4217 * INVALID_HANDLE_VALUE and SetLastError on failure.
4218 * @param pTempFile The temporary file.
4219 * @param dwDesiredAccess The desired access to the handle.
4220 * @param fMapping Whether this is a mapping (K_TRUE) or file
4221 * (K_FALSE) handle type.
4222 */
4223static HANDLE kwFsTempFileCreateHandle(PKWFSTEMPFILE pTempFile, DWORD dwDesiredAccess, KBOOL fMapping)
4224{
4225 /*
4226 * Create a handle to the temporary file.
4227 */
4228 HANDLE hFile = INVALID_HANDLE_VALUE;
4229 HANDLE hProcSelf = GetCurrentProcess();
4230 if (DuplicateHandle(hProcSelf, hProcSelf,
4231 hProcSelf, &hFile,
4232 SYNCHRONIZE, FALSE,
4233 0 /*dwOptions*/))
4234 {
4235 PKWHANDLE pHandle = (PKWHANDLE)kHlpAlloc(sizeof(*pHandle));
4236 if (pHandle)
4237 {
4238 pHandle->enmType = !fMapping ? KWHANDLETYPE_TEMP_FILE : KWHANDLETYPE_TEMP_FILE_MAPPING;
4239 pHandle->offFile = 0;
4240 pHandle->hHandle = hFile;
4241 pHandle->dwDesiredAccess = dwDesiredAccess;
4242 pHandle->u.pTempFile = pTempFile;
4243 if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle))
4244 {
4245 pTempFile->cActiveHandles++;
4246 kHlpAssert(pTempFile->cActiveHandles >= 1);
4247 kHlpAssert(pTempFile->cActiveHandles <= 2);
4248 KWFS_LOG(("kwFsTempFileCreateHandle: Temporary file '%ls' -> %p\n", pTempFile->pwszPath, hFile));
4249 return hFile;
4250 }
4251
4252 kHlpFree(pHandle);
4253 }
4254 else
4255 KWFS_LOG(("kwFsTempFileCreateHandle: Out of memory!\n"));
4256 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4257 }
4258 else
4259 KWFS_LOG(("kwFsTempFileCreateHandle: DuplicateHandle failed: err=%u\n", GetLastError()));
4260 return INVALID_HANDLE_VALUE;
4261}
4262
4263
4264static HANDLE kwFsTempFileCreateW(const wchar_t *pwszFilename, DWORD dwDesiredAccess, DWORD dwCreationDisposition)
4265{
4266 HANDLE hFile;
4267 DWORD dwErr;
4268
4269 /*
4270 * Check if we've got an existing temp file.
4271 * ASSUME exact same path for now.
4272 */
4273 KSIZE const cwcFilename = kwUtf16Len(pwszFilename);
4274 PKWFSTEMPFILE pTempFile;
4275 for (pTempFile = g_Sandbox.pTempFileHead; pTempFile != NULL; pTempFile = pTempFile->pNext)
4276 {
4277 /* Since the last two chars are usually the only difference, we check them manually before calling memcmp. */
4278 if ( pTempFile->cwcPath == cwcFilename
4279 && pTempFile->pwszPath[cwcFilename - 1] == pwszFilename[cwcFilename - 1]
4280 && pTempFile->pwszPath[cwcFilename - 2] == pwszFilename[cwcFilename - 2]
4281 && kHlpMemComp(pTempFile->pwszPath, pwszFilename, cwcFilename) == 0)
4282 break;
4283 }
4284
4285 /*
4286 * Create a new temporary file instance if not found.
4287 */
4288 if (pTempFile == NULL)
4289 {
4290 KSIZE cbFilename;
4291
4292 switch (dwCreationDisposition)
4293 {
4294 case CREATE_ALWAYS:
4295 case OPEN_ALWAYS:
4296 dwErr = NO_ERROR;
4297 break;
4298
4299 case CREATE_NEW:
4300 kHlpAssertFailed();
4301 SetLastError(ERROR_ALREADY_EXISTS);
4302 return INVALID_HANDLE_VALUE;
4303
4304 case OPEN_EXISTING:
4305 case TRUNCATE_EXISTING:
4306 kHlpAssertFailed();
4307 SetLastError(ERROR_FILE_NOT_FOUND);
4308 return INVALID_HANDLE_VALUE;
4309
4310 default:
4311 kHlpAssertFailed();
4312 SetLastError(ERROR_INVALID_PARAMETER);
4313 return INVALID_HANDLE_VALUE;
4314 }
4315
4316 cbFilename = (cwcFilename + 1) * sizeof(wchar_t);
4317 pTempFile = (PKWFSTEMPFILE)kHlpAlloc(sizeof(*pTempFile) + cbFilename);
4318 if (pTempFile)
4319 {
4320 pTempFile->cwcPath = (KU16)cwcFilename;
4321 pTempFile->cbFile = 0;
4322 pTempFile->cbFileAllocated = 0;
4323 pTempFile->cActiveHandles = 0;
4324 pTempFile->cMappings = 0;
4325 pTempFile->cSegs = 0;
4326 pTempFile->paSegs = NULL;
4327 pTempFile->pwszPath = (wchar_t const *)kHlpMemCopy(pTempFile + 1, pwszFilename, cbFilename);
4328
4329 pTempFile->pNext = g_Sandbox.pTempFileHead;
4330 g_Sandbox.pTempFileHead = pTempFile;
4331 KWFS_LOG(("kwFsTempFileCreateW: Created new temporary file '%ls'\n", pwszFilename));
4332 }
4333 else
4334 {
4335 KWFS_LOG(("kwFsTempFileCreateW: Out of memory!\n"));
4336 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4337 return INVALID_HANDLE_VALUE;
4338 }
4339 }
4340 else
4341 {
4342 switch (dwCreationDisposition)
4343 {
4344 case OPEN_EXISTING:
4345 dwErr = NO_ERROR;
4346 break;
4347 case OPEN_ALWAYS:
4348 dwErr = ERROR_ALREADY_EXISTS ;
4349 break;
4350
4351 case TRUNCATE_EXISTING:
4352 case CREATE_ALWAYS:
4353 kHlpAssertFailed();
4354 pTempFile->cbFile = 0;
4355 dwErr = ERROR_ALREADY_EXISTS;
4356 break;
4357
4358 case CREATE_NEW:
4359 kHlpAssertFailed();
4360 SetLastError(ERROR_FILE_EXISTS);
4361 return INVALID_HANDLE_VALUE;
4362
4363 default:
4364 kHlpAssertFailed();
4365 SetLastError(ERROR_INVALID_PARAMETER);
4366 return INVALID_HANDLE_VALUE;
4367 }
4368 }
4369
4370 /*
4371 * Create a handle to the temporary file.
4372 */
4373 hFile = kwFsTempFileCreateHandle(pTempFile, dwDesiredAccess, K_FALSE /*fMapping*/);
4374 if (hFile != INVALID_HANDLE_VALUE)
4375 SetLastError(dwErr);
4376 return hFile;
4377}
4378
4379#endif /* WITH_TEMP_MEMORY_FILES */
4380
4381
4382/**
4383 * Checks if the file extension indicates that the file/dir is something we
4384 * ought to cache.
4385 *
4386 * @returns K_TRUE if cachable, K_FALSE if not.
4387 * @param pszExt The kHlpGetExt result.
4388 * @param fAttrQuery Set if it's for an attribute query, clear if for
4389 * file creation.
4390 */
4391static KBOOL kwFsIsCachableExtensionA(const char *pszExt, KBOOL fAttrQuery)
4392{
4393 char const chFirst = *pszExt;
4394
4395 /* C++ header without an extension or a directory. */
4396 if (chFirst == '\0')
4397 {
4398 /** @todo exclude temporary files... */
4399 return K_TRUE;
4400 }
4401
4402 /* C Header: .h */
4403 if (chFirst == 'h' || chFirst == 'H')
4404 {
4405 char chThird;
4406 char const chSecond = pszExt[1];
4407 if (chSecond == '\0')
4408 return K_TRUE;
4409 chThird = pszExt[2];
4410
4411 /* C++ Header: .hpp, .hxx */
4412 if ( (chSecond == 'p' || chSecond == 'P')
4413 && (chThird == 'p' || chThird == 'P')
4414 && pszExt[3] == '\0')
4415 return K_TRUE;
4416 if ( (chSecond == 'x' || chSecond == 'X')
4417 && (chThird == 'x' || chThird == 'X')
4418 && pszExt[3] == '\0')
4419 return K_TRUE;
4420 }
4421 /* Misc starting with i. */
4422 else if (chFirst == 'i' || chFirst == 'I')
4423 {
4424 char const chSecond = pszExt[1];
4425 if (chSecond != '\0')
4426 {
4427 if (chSecond == 'n' || chSecond == 'N')
4428 {
4429 char const chThird = pszExt[2];
4430
4431 /* C++ inline header: .inl */
4432 if ( (chThird == 'l' || chThird == 'L')
4433 && pszExt[3] == '\0')
4434 return K_TRUE;
4435
4436 /* Assembly include file: .inc */
4437 if ( (chThird == 'c' || chThird == 'C')
4438 && pszExt[3] == '\0')
4439 return K_TRUE;
4440 }
4441 }
4442 }
4443 /* Assembly header: .mac */
4444 else if (chFirst == 'm' || chFirst == 'M')
4445 {
4446 char const chSecond = pszExt[1];
4447 if (chSecond == 'a' || chSecond == 'A')
4448 {
4449 char const chThird = pszExt[2];
4450 if ( (chThird == 'c' || chThird == 'C')
4451 && pszExt[3] == '\0')
4452 return K_TRUE;
4453 }
4454 }
4455 else if (fAttrQuery)
4456 {
4457 /* Dynamic link library: .dll */
4458 if (chFirst == 'd' || chFirst == 'D')
4459 {
4460 char const chSecond = pszExt[1];
4461 if (chSecond == 'l' || chSecond == 'L')
4462 {
4463 char const chThird = pszExt[2];
4464 if (chThird == 'l' || chThird == 'L')
4465 return K_TRUE;
4466 }
4467 }
4468 /* Executable file: .exe */
4469 else if (chFirst == 'e' || chFirst == 'E')
4470 {
4471 char const chSecond = pszExt[1];
4472 if (chSecond == 'x' || chSecond == 'X')
4473 {
4474 char const chThird = pszExt[2];
4475 if (chThird == 'e' || chThird == 'e')
4476 return K_TRUE;
4477 }
4478 }
4479 }
4480
4481 return K_FALSE;
4482}
4483
4484
4485/**
4486 * Checks if the extension of the given UTF-16 path indicates that the file/dir
4487 * should be cached.
4488 *
4489 * @returns K_TRUE if cachable, K_FALSE if not.
4490 * @param pwszPath The UTF-16 path to examine.
4491 * @param fAttrQuery Set if it's for an attribute query, clear if for
4492 * file creation.
4493 */
4494static KBOOL kwFsIsCachablePathExtensionW(const wchar_t *pwszPath, KBOOL fAttrQuery)
4495{
4496 /*
4497 * Extract the extension, check that it's in the applicable range, roughly
4498 * convert it to ASCII/ANSI, and feed it to kwFsIsCachableExtensionA for
4499 * the actual check. This avoids a lot of code duplication.
4500 */
4501 wchar_t wc;
4502 char szExt[4];
4503 KSIZE cwcExt;
4504 wchar_t const *pwszExt = kwFsPathGetExtW(pwszPath, &cwcExt);
4505 switch (cwcExt)
4506 {
4507 case 3: if ((wchar_t)(szExt[2] = (char)(wc = pwszExt[2])) == wc) { /*likely*/ } else break;
4508 case 2: if ((wchar_t)(szExt[1] = (char)(wc = pwszExt[1])) == wc) { /*likely*/ } else break;
4509 case 1: if ((wchar_t)(szExt[0] = (char)(wc = pwszExt[0])) == wc) { /*likely*/ } else break;
4510 case 0:
4511 szExt[cwcExt] = '\0';
4512 return kwFsIsCachableExtensionA(szExt, fAttrQuery);
4513 }
4514 return K_FALSE;
4515}
4516
4517
4518
4519/**
4520 * Creates a new
4521 *
4522 * @returns
4523 * @param pFsObj .
4524 * @param pwszFilename .
4525 */
4526static PKFSWCACHEDFILE kwFsObjCacheNewFile(PKFSOBJ pFsObj)
4527{
4528 HANDLE hFile;
4529 MY_IO_STATUS_BLOCK Ios;
4530 MY_OBJECT_ATTRIBUTES ObjAttr;
4531 MY_UNICODE_STRING UniStr;
4532 MY_NTSTATUS rcNt;
4533 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
4534
4535 /*
4536 * Open the file relative to the parent directory.
4537 */
4538 kHlpAssert(pFsObj->bObjType == KFSOBJ_TYPE_FILE);
4539 kHlpAssert(pFsObj->pParent);
4540 kHlpAssertReturn(pFsObj->pParent->hDir != INVALID_HANDLE_VALUE, NULL);
4541
4542 Ios.Information = -1;
4543 Ios.u.Status = -1;
4544
4545 UniStr.Buffer = (wchar_t *)pFsObj->pwszName;
4546 UniStr.Length = (USHORT)(pFsObj->cwcName * sizeof(wchar_t));
4547 UniStr.MaximumLength = UniStr.Length + sizeof(wchar_t);
4548
4549 MyInitializeObjectAttributes(&ObjAttr, &UniStr, OBJ_CASE_INSENSITIVE, pFsObj->pParent->hDir, NULL /*pSecAttr*/);
4550
4551 rcNt = g_pfnNtCreateFile(&hFile,
4552 GENERIC_READ | SYNCHRONIZE,
4553 &ObjAttr,
4554 &Ios,
4555 NULL, /*cbFileInitialAlloc */
4556 FILE_ATTRIBUTE_NORMAL,
4557 FILE_SHARE_READ,
4558 FILE_OPEN,
4559 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
4560 NULL, /*pEaBuffer*/
4561 0); /*cbEaBuffer*/
4562 if (MY_NT_SUCCESS(rcNt))
4563 {
4564 /*
4565 * Read the whole file into memory.
4566 */
4567 LARGE_INTEGER cbFile;
4568 if (GetFileSizeEx(hFile, &cbFile))
4569 {
4570 if ( cbFile.QuadPart >= 0
4571 && cbFile.QuadPart < 16*1024*1024)
4572 {
4573 KU32 cbCache = (KU32)cbFile.QuadPart;
4574 KU8 *pbCache = (KU8 *)kHlpAlloc(cbCache);
4575 if (pbCache)
4576 {
4577 DWORD cbActually = 0;
4578 if ( ReadFile(hFile, pbCache, cbCache, &cbActually, NULL)
4579 && cbActually == cbCache)
4580 {
4581 LARGE_INTEGER offZero;
4582 offZero.QuadPart = 0;
4583 if (SetFilePointerEx(hFile, offZero, NULL /*poffNew*/, FILE_BEGIN))
4584 {
4585 /*
4586 * Create the cached file object.
4587 */
4588 PKFSWCACHEDFILE pCachedFile;
4589 KU32 cbPath = pFsObj->cchParent + pFsObj->cchName + 2;
4590 pCachedFile = (PKFSWCACHEDFILE)kFsCacheObjAddUserData(g_pFsCache, pFsObj, KW_DATA_KEY_CACHED_FILE,
4591 sizeof(*pCachedFile) + cbPath);
4592 if (pCachedFile)
4593 {
4594 pCachedFile->hCached = hFile;
4595 pCachedFile->cbCached = cbCache;
4596 pCachedFile->pbCached = pbCache;
4597 pCachedFile->pFsObj = pFsObj;
4598 kFsCacheObjGetFullPathA(pFsObj, pCachedFile->szPath, cbPath, '/');
4599 kFsCacheObjRetain(pFsObj);
4600 return pCachedFile;
4601 }
4602
4603 KWFS_LOG(("Failed to allocate KFSWCACHEDFILE structure!\n"));
4604 }
4605 else
4606 KWFS_LOG(("Failed to seek to start of cached file! err=%u\n", GetLastError()));
4607 }
4608 else
4609 KWFS_LOG(("Failed to read %#x bytes into cache! err=%u cbActually=%#x\n",
4610 cbCache, GetLastError(), cbActually));
4611 kHlpFree(pbCache);
4612 }
4613 else
4614 KWFS_LOG(("Failed to allocate %#x bytes for cache!\n", cbCache));
4615 }
4616 else
4617 KWFS_LOG(("File to big to cache! %#llx\n", cbFile.QuadPart));
4618 }
4619 else
4620 KWFS_LOG(("File to get file size! err=%u\n", GetLastError()));
4621 g_pfnNtClose(hFile);
4622 }
4623 else
4624 KWFS_LOG(("Error opening '%ls' for caching: %#x\n", pFsObj->pwszName, rcNt));
4625 return NULL;
4626}
4627
4628
4629/**
4630 * Kernel32 - Common code for CreateFileW and CreateFileA.
4631 */
4632static KBOOL kwFsObjCacheCreateFile(PKFSOBJ pFsObj, DWORD dwDesiredAccess, BOOL fInheritHandle, HANDLE *phFile)
4633{
4634 *phFile = INVALID_HANDLE_VALUE;
4635 kHlpAssert(pFsObj->fHaveStats);
4636
4637 /*
4638 * At the moment we only handle existing files.
4639 */
4640 if (pFsObj->bObjType == KFSOBJ_TYPE_FILE)
4641 {
4642 PKFSWCACHEDFILE pCachedFile = (PKFSWCACHEDFILE)kFsCacheObjGetUserData(g_pFsCache, pFsObj, KW_DATA_KEY_CACHED_FILE);
4643 if ( pCachedFile != NULL
4644 || (pCachedFile = kwFsObjCacheNewFile(pFsObj)) != NULL)
4645 {
4646 HANDLE hProcSelf = GetCurrentProcess();
4647 if (DuplicateHandle(hProcSelf, pCachedFile->hCached,
4648 hProcSelf, phFile,
4649 dwDesiredAccess, fInheritHandle,
4650 0 /*dwOptions*/))
4651 {
4652 /*
4653 * Create handle table entry for the duplicate handle.
4654 */
4655 PKWHANDLE pHandle = (PKWHANDLE)kHlpAlloc(sizeof(*pHandle));
4656 if (pHandle)
4657 {
4658 pHandle->enmType = KWHANDLETYPE_FSOBJ_READ_CACHE;
4659 pHandle->offFile = 0;
4660 pHandle->hHandle = *phFile;
4661 pHandle->dwDesiredAccess = dwDesiredAccess;
4662 pHandle->u.pCachedFile = pCachedFile;
4663 if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle))
4664 return K_TRUE;
4665
4666 kHlpFree(pHandle);
4667 }
4668 else
4669 KWFS_LOG(("Out of memory for handle!\n"));
4670
4671 CloseHandle(*phFile);
4672 *phFile = INVALID_HANDLE_VALUE;
4673 }
4674 else
4675 KWFS_LOG(("DuplicateHandle failed! err=%u\n", GetLastError()));
4676 }
4677 }
4678 /** @todo Deal with non-existing files if it becomes necessary (it's not for VS2010). */
4679
4680 /* Do fallback, please. */
4681 return K_FALSE;
4682}
4683
4684
4685/** Kernel32 - CreateFileA */
4686static HANDLE WINAPI kwSandbox_Kernel32_CreateFileA(LPCSTR pszFilename, DWORD dwDesiredAccess, DWORD dwShareMode,
4687 LPSECURITY_ATTRIBUTES pSecAttrs, DWORD dwCreationDisposition,
4688 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
4689{
4690 HANDLE hFile;
4691 if (dwCreationDisposition == FILE_OPEN_IF)
4692 {
4693 if ( dwDesiredAccess == GENERIC_READ
4694 || dwDesiredAccess == FILE_GENERIC_READ)
4695 {
4696 if (dwShareMode & FILE_SHARE_READ)
4697 {
4698 if ( !pSecAttrs
4699 || ( pSecAttrs->nLength == sizeof(*pSecAttrs)
4700 && pSecAttrs->lpSecurityDescriptor == NULL ) )
4701 {
4702 const char *pszExt = kHlpGetExt(pszFilename);
4703 if (kwFsIsCachableExtensionA(pszExt, K_FALSE /*fAttrQuery*/))
4704 {
4705 KFSLOOKUPERROR enmError;
4706 PKFSOBJ pFsObj;
4707 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
4708
4709 pFsObj = kFsCacheLookupNoMissingA(g_pFsCache, pszFilename, &enmError);
4710 if (pFsObj)
4711 {
4712 KBOOL fRc = kwFsObjCacheCreateFile(pFsObj, dwDesiredAccess, pSecAttrs && pSecAttrs->bInheritHandle,
4713 &hFile);
4714 kFsCacheObjRelease(g_pFsCache, pFsObj);
4715 if (fRc)
4716 {
4717 KWFS_LOG(("CreateFileA(%s) -> %p [cached]\n", pszFilename, hFile));
4718 return hFile;
4719 }
4720 }
4721 /* These are for nasm and yasm header searching. Cache will already
4722 have checked the directories for the file, no need to call
4723 CreateFile to do it again. */
4724 else if (enmError == KFSLOOKUPERROR_NOT_FOUND)
4725 {
4726 KWFS_LOG(("CreateFileA(%s) -> INVALID_HANDLE_VALUE, ERROR_FILE_NOT_FOUND\n", pszFilename));
4727 return INVALID_HANDLE_VALUE;
4728 }
4729 else if ( enmError == KFSLOOKUPERROR_PATH_COMP_NOT_FOUND
4730 || enmError == KFSLOOKUPERROR_PATH_COMP_NOT_DIR)
4731 {
4732 KWFS_LOG(("CreateFileA(%s) -> INVALID_HANDLE_VALUE, ERROR_PATH_NOT_FOUND\n", pszFilename));
4733 return INVALID_HANDLE_VALUE;
4734 }
4735
4736 /* fallback */
4737 hFile = CreateFileA(pszFilename, dwDesiredAccess, dwShareMode, pSecAttrs,
4738 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
4739 KWFS_LOG(("CreateFileA(%s) -> %p (err=%u) [fallback]\n", pszFilename, hFile, GetLastError()));
4740 return hFile;
4741 }
4742 }
4743 }
4744 }
4745 }
4746
4747 hFile = CreateFileA(pszFilename, dwDesiredAccess, dwShareMode, pSecAttrs,
4748 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
4749 KWFS_LOG(("CreateFileA(%s) -> %p\n", pszFilename, hFile));
4750 return hFile;
4751}
4752
4753
4754/** Kernel32 - CreateFileW */
4755static HANDLE WINAPI kwSandbox_Kernel32_CreateFileW(LPCWSTR pwszFilename, DWORD dwDesiredAccess, DWORD dwShareMode,
4756 LPSECURITY_ATTRIBUTES pSecAttrs, DWORD dwCreationDisposition,
4757 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
4758{
4759 HANDLE hFile;
4760
4761#ifdef WITH_TEMP_MEMORY_FILES
4762 /* First check for temporary files (cl.exe only). */
4763 if ( g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL
4764 && !(dwFlagsAndAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE | FILE_FLAG_BACKUP_SEMANTICS))
4765 && !(dwDesiredAccess & (GENERIC_EXECUTE | FILE_EXECUTE))
4766 && kwFsIsClTempFileW(pwszFilename))
4767 {
4768 hFile = kwFsTempFileCreateW(pwszFilename, dwDesiredAccess, dwCreationDisposition);
4769 KWFS_LOG(("CreateFileW(%ls) -> %p [temp]\n", pwszFilename, hFile));
4770 return hFile;
4771 }
4772#endif
4773
4774 /* Then check for include files and similar. */
4775 if (dwCreationDisposition == FILE_OPEN_IF)
4776 {
4777 if ( dwDesiredAccess == GENERIC_READ
4778 || dwDesiredAccess == FILE_GENERIC_READ)
4779 {
4780 if (dwShareMode & FILE_SHARE_READ)
4781 {
4782 if ( !pSecAttrs
4783 || ( pSecAttrs->nLength == sizeof(*pSecAttrs)
4784 && pSecAttrs->lpSecurityDescriptor == NULL ) )
4785 {
4786 if (kwFsIsCachablePathExtensionW(pwszFilename, K_FALSE /*fAttrQuery*/))
4787 {
4788 /** @todo rewrite in pure UTF-16. */
4789 char szTmp[2048];
4790 KSIZE cch = kwUtf16ToStr(pwszFilename, szTmp, sizeof(szTmp));
4791 if (cch < sizeof(szTmp))
4792 return kwSandbox_Kernel32_CreateFileA(szTmp, dwDesiredAccess, dwShareMode, pSecAttrs,
4793 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
4794 }
4795 }
4796 else
4797 KWFS_LOG(("CreateFileW: incompatible security attributes (nLength=%#x pDesc=%p)\n",
4798 pSecAttrs->nLength, pSecAttrs->lpSecurityDescriptor));
4799 }
4800 else
4801 KWFS_LOG(("CreateFileW: incompatible sharing mode %#x\n", dwShareMode));
4802 }
4803 else
4804 KWFS_LOG(("CreateFileW: incompatible desired access %#x\n", dwDesiredAccess));
4805 }
4806 else
4807 KWFS_LOG(("CreateFileW: incompatible disposition %u\n", dwCreationDisposition));
4808 hFile = CreateFileW(pwszFilename, dwDesiredAccess, dwShareMode, pSecAttrs,
4809 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
4810 KWFS_LOG(("CreateFileW(%ls) -> %p\n", pwszFilename, hFile));
4811 return hFile;
4812}
4813
4814
4815/** Kernel32 - SetFilePointer */
4816static DWORD WINAPI kwSandbox_Kernel32_SetFilePointer(HANDLE hFile, LONG cbMove, PLONG pcbMoveHi, DWORD dwMoveMethod)
4817{
4818 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
4819 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
4820 if (idxHandle < g_Sandbox.cHandles)
4821 {
4822 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
4823 if (pHandle != NULL)
4824 {
4825 KU32 cbFile;
4826 KI64 offMove = pcbMoveHi ? ((KI64)*pcbMoveHi << 32) | cbMove : cbMove;
4827 switch (pHandle->enmType)
4828 {
4829 case KWHANDLETYPE_FSOBJ_READ_CACHE:
4830 cbFile = pHandle->u.pCachedFile->cbCached;
4831 break;
4832#ifdef WITH_TEMP_MEMORY_FILES
4833 case KWHANDLETYPE_TEMP_FILE:
4834 cbFile = pHandle->u.pTempFile->cbFile;
4835 break;
4836 case KWHANDLETYPE_TEMP_FILE_MAPPING:
4837#endif
4838 default:
4839 kHlpAssertFailed();
4840 SetLastError(ERROR_INVALID_FUNCTION);
4841 return INVALID_SET_FILE_POINTER;
4842 }
4843
4844 switch (dwMoveMethod)
4845 {
4846 case FILE_BEGIN:
4847 break;
4848 case FILE_CURRENT:
4849 offMove += pHandle->offFile;
4850 break;
4851 case FILE_END:
4852 offMove += cbFile;
4853 break;
4854 default:
4855 KWFS_LOG(("SetFilePointer(%p) - invalid seek method %u! [cached]\n", hFile));
4856 SetLastError(ERROR_INVALID_PARAMETER);
4857 return INVALID_SET_FILE_POINTER;
4858 }
4859 if (offMove >= 0)
4860 {
4861 if (offMove >= (KSSIZE)cbFile)
4862 {
4863 /* For read-only files, seeking beyond the end isn't useful to us, so clamp it. */
4864 if (pHandle->enmType != KWHANDLETYPE_TEMP_FILE)
4865 offMove = (KSSIZE)cbFile;
4866 /* For writable files, seeking beyond the end is fine, but check that we've got
4867 the type range for the request. */
4868 else if (((KU64)offMove & KU32_MAX) != (KU64)offMove)
4869 {
4870 kHlpAssertMsgFailed(("%#llx\n", offMove));
4871 SetLastError(ERROR_SEEK);
4872 return INVALID_SET_FILE_POINTER;
4873 }
4874 }
4875 pHandle->offFile = (KU32)offMove;
4876 }
4877 else
4878 {
4879 KWFS_LOG(("SetFilePointer(%p) - negative seek! [cached]\n", hFile));
4880 SetLastError(ERROR_NEGATIVE_SEEK);
4881 return INVALID_SET_FILE_POINTER;
4882 }
4883 if (pcbMoveHi)
4884 *pcbMoveHi = (KU64)offMove >> 32;
4885 KWFS_LOG(("SetFilePointer(%p) -> %#llx [cached]\n", hFile, offMove));
4886 SetLastError(NO_ERROR);
4887 return (KU32)offMove;
4888 }
4889 }
4890 KWFS_LOG(("SetFilePointer(%p)\n", hFile));
4891 return SetFilePointer(hFile, cbMove, pcbMoveHi, dwMoveMethod);
4892}
4893
4894
4895/** Kernel32 - SetFilePointerEx */
4896static BOOL WINAPI kwSandbox_Kernel32_SetFilePointerEx(HANDLE hFile, LARGE_INTEGER offMove, PLARGE_INTEGER poffNew,
4897 DWORD dwMoveMethod)
4898{
4899 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
4900 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
4901 if (idxHandle < g_Sandbox.cHandles)
4902 {
4903 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
4904 if (pHandle != NULL)
4905 {
4906 KI64 offMyMove = offMove.QuadPart;
4907 KU32 cbFile;
4908 switch (pHandle->enmType)
4909 {
4910 case KWHANDLETYPE_FSOBJ_READ_CACHE:
4911 cbFile = pHandle->u.pCachedFile->cbCached;
4912 break;
4913#ifdef WITH_TEMP_MEMORY_FILES
4914 case KWHANDLETYPE_TEMP_FILE:
4915 cbFile = pHandle->u.pTempFile->cbFile;
4916 break;
4917 case KWHANDLETYPE_TEMP_FILE_MAPPING:
4918#endif
4919 default:
4920 kHlpAssertFailed();
4921 SetLastError(ERROR_INVALID_FUNCTION);
4922 return INVALID_SET_FILE_POINTER;
4923 }
4924
4925 switch (dwMoveMethod)
4926 {
4927 case FILE_BEGIN:
4928 break;
4929 case FILE_CURRENT:
4930 offMyMove += pHandle->offFile;
4931 break;
4932 case FILE_END:
4933 offMyMove += cbFile;
4934 break;
4935 default:
4936 KWFS_LOG(("SetFilePointer(%p) - invalid seek method %u! [cached]\n", hFile));
4937 SetLastError(ERROR_INVALID_PARAMETER);
4938 return INVALID_SET_FILE_POINTER;
4939 }
4940 if (offMyMove >= 0)
4941 {
4942 if (offMyMove >= (KSSIZE)cbFile)
4943 {
4944 /* For read-only files, seeking beyond the end isn't useful to us, so clamp it. */
4945 if (pHandle->enmType != KWHANDLETYPE_TEMP_FILE)
4946 offMyMove = (KSSIZE)cbFile;
4947 /* For writable files, seeking beyond the end is fine, but check that we've got
4948 the type range for the request. */
4949 else if (((KU64)offMyMove & KU32_MAX) != (KU64)offMyMove)
4950 {
4951 kHlpAssertMsgFailed(("%#llx\n", offMyMove));
4952 SetLastError(ERROR_SEEK);
4953 return INVALID_SET_FILE_POINTER;
4954 }
4955 }
4956 pHandle->offFile = (KU32)offMyMove;
4957 }
4958 else
4959 {
4960 KWFS_LOG(("SetFilePointerEx(%p) - negative seek! [cached]\n", hFile));
4961 SetLastError(ERROR_NEGATIVE_SEEK);
4962 return INVALID_SET_FILE_POINTER;
4963 }
4964 if (poffNew)
4965 poffNew->QuadPart = offMyMove;
4966 KWFS_LOG(("SetFilePointerEx(%p) -> TRUE, %#llx [cached]\n", hFile, offMyMove));
4967 return TRUE;
4968 }
4969 }
4970 KWFS_LOG(("SetFilePointerEx(%p)\n", hFile));
4971 return SetFilePointerEx(hFile, offMove, poffNew, dwMoveMethod);
4972}
4973
4974
4975/** Kernel32 - ReadFile */
4976static BOOL WINAPI kwSandbox_Kernel32_ReadFile(HANDLE hFile, LPVOID pvBuffer, DWORD cbToRead, LPDWORD pcbActuallyRead,
4977 LPOVERLAPPED pOverlapped)
4978{
4979 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
4980 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
4981 if (idxHandle < g_Sandbox.cHandles)
4982 {
4983 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
4984 if (pHandle != NULL)
4985 {
4986 switch (pHandle->enmType)
4987 {
4988 case KWHANDLETYPE_FSOBJ_READ_CACHE:
4989 {
4990 PKFSWCACHEDFILE pCachedFile = pHandle->u.pCachedFile;
4991 KU32 cbActually = pCachedFile->cbCached - pHandle->offFile;
4992 if (cbActually > cbToRead)
4993 cbActually = cbToRead;
4994 else if (cbActually < cbToRead) // debug debug debug
4995 kHlpMemSet((KU8 *)pvBuffer + cbActually, '\0', cbToRead - cbActually); // debug debug debug
4996
4997#ifdef WITH_HASH_MD5_CACHE
4998 if (g_Sandbox.pHashHead)
4999 {
5000 g_Sandbox.LastHashRead.pCachedFile = pCachedFile;
5001 g_Sandbox.LastHashRead.offRead = pHandle->offFile;
5002 g_Sandbox.LastHashRead.cbRead = cbActually;
5003 g_Sandbox.LastHashRead.pvRead = pvBuffer;
5004 }
5005#endif
5006
5007 kHlpMemCopy(pvBuffer, &pCachedFile->pbCached[pHandle->offFile], cbActually);
5008 pHandle->offFile += cbActually;
5009
5010 kHlpAssert(!pOverlapped); kHlpAssert(pcbActuallyRead);
5011 *pcbActuallyRead = cbActually;
5012
5013 KWFS_LOG(("ReadFile(%p,,%#x) -> TRUE, %#x bytes [cached]\n", hFile, cbToRead, cbActually));
5014 return TRUE;
5015 }
5016
5017#ifdef WITH_TEMP_MEMORY_FILES
5018 case KWHANDLETYPE_TEMP_FILE:
5019 {
5020 PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile;
5021 KU32 cbActually;
5022 if (pHandle->offFile < pTempFile->cbFile)
5023 {
5024 cbActually = pTempFile->cbFile - pHandle->offFile;
5025 if (cbActually > cbToRead)
5026 cbActually = cbToRead;
5027
5028 /* Copy the data. */
5029 if (cbActually > 0)
5030 {
5031 KU32 cbLeft;
5032 KU32 offSeg;
5033 KWFSTEMPFILESEG const *paSegs = pTempFile->paSegs;
5034
5035 /* Locate the segment containing the byte at offFile. */
5036 KU32 iSeg = pTempFile->cSegs - 1;
5037 kHlpAssert(pTempFile->cSegs > 0);
5038 while (paSegs[iSeg].offData > pHandle->offFile)
5039 iSeg--;
5040
5041 /* Copy out the data. */
5042 cbLeft = cbActually;
5043 offSeg = (pHandle->offFile - paSegs[iSeg].offData);
5044 for (;;)
5045 {
5046 KU32 cbAvail = paSegs[iSeg].cbDataAlloc - offSeg;
5047 if (cbAvail >= cbLeft)
5048 {
5049 kHlpMemCopy(pvBuffer, &paSegs[iSeg].pbData[offSeg], cbLeft);
5050 break;
5051 }
5052
5053 pvBuffer = kHlpMemPCopy(pvBuffer, &paSegs[iSeg].pbData[offSeg], cbAvail);
5054 cbLeft -= cbAvail;
5055 offSeg = 0;
5056 iSeg++;
5057 kHlpAssert(iSeg < pTempFile->cSegs);
5058 }
5059
5060 /* Update the file offset. */
5061 pHandle->offFile += cbActually;
5062 }
5063 }
5064 /* Read does not commit file space, so return zero bytes. */
5065 else
5066 cbActually = 0;
5067
5068 kHlpAssert(!pOverlapped); kHlpAssert(pcbActuallyRead);
5069 *pcbActuallyRead = cbActually;
5070
5071 KWFS_LOG(("ReadFile(%p,,%#x) -> TRUE, %#x bytes [temp]\n", hFile, cbToRead, (KU32)cbActually));
5072 return TRUE;
5073 }
5074
5075 case KWHANDLETYPE_TEMP_FILE_MAPPING:
5076#endif /* WITH_TEMP_MEMORY_FILES */
5077 default:
5078 kHlpAssertFailed();
5079 SetLastError(ERROR_INVALID_FUNCTION);
5080 *pcbActuallyRead = 0;
5081 return FALSE;
5082 }
5083 }
5084 }
5085
5086 KWFS_LOG(("ReadFile(%p)\n", hFile));
5087 return ReadFile(hFile, pvBuffer, cbToRead, pcbActuallyRead, pOverlapped);
5088}
5089
5090
5091/** Kernel32 - ReadFileEx */
5092static BOOL WINAPI kwSandbox_Kernel32_ReadFileEx(HANDLE hFile, LPVOID pvBuffer, DWORD cbToRead, LPOVERLAPPED pOverlapped,
5093 LPOVERLAPPED_COMPLETION_ROUTINE pfnCompletionRoutine)
5094{
5095 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
5096 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
5097 if (idxHandle < g_Sandbox.cHandles)
5098 {
5099 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
5100 if (pHandle != NULL)
5101 {
5102 kHlpAssertFailed();
5103 }
5104 }
5105
5106 KWFS_LOG(("ReadFile(%p)\n", hFile));
5107 return ReadFileEx(hFile, pvBuffer, cbToRead, pOverlapped, pfnCompletionRoutine);
5108}
5109
5110#ifdef WITH_TEMP_MEMORY_FILES
5111
5112static KBOOL kwFsTempFileEnsureSpace(PKWFSTEMPFILE pTempFile, KU32 offFile, KU32 cbNeeded)
5113{
5114 KU32 cbMinFile = offFile + cbNeeded;
5115 if (cbMinFile >= offFile)
5116 {
5117 /* Calc how much space we've already allocated and */
5118 if (cbMinFile <= pTempFile->cbFileAllocated)
5119 return K_TRUE;
5120
5121 /* Grow the file. */
5122 if (cbMinFile <= KWFS_TEMP_FILE_MAX)
5123 {
5124 int rc;
5125 KU32 cSegs = pTempFile->cSegs;
5126 KU32 cbNewSeg = cbMinFile > 4*1024*1024 ? 256*1024 : 4*1024*1024;
5127 do
5128 {
5129 /* grow the segment array? */
5130 if ((cSegs % 16) == 0)
5131 {
5132 void *pvNew = kHlpRealloc(pTempFile->paSegs, (cSegs + 16) * sizeof(pTempFile->paSegs[0]));
5133 if (!pvNew)
5134 return K_FALSE;
5135 pTempFile->paSegs = (PKWFSTEMPFILESEG)pvNew;
5136 }
5137
5138 /* Use page alloc here to simplify mapping later. */
5139 rc = kHlpPageAlloc((void **)&pTempFile->paSegs[cSegs].pbData, cbNewSeg, KPROT_READWRITE, K_FALSE);
5140 if (rc == 0)
5141 { /* likely */ }
5142 else
5143 {
5144 cbNewSeg = 64*1024;
5145 rc = kHlpPageAlloc((void **)&pTempFile->paSegs[cSegs].pbData, cbNewSeg, KPROT_READWRITE, K_FALSE);
5146 if (rc != 0)
5147 {
5148 kHlpAssertFailed();
5149 return K_FALSE;
5150 }
5151 }
5152 pTempFile->paSegs[cSegs].offData = pTempFile->cbFileAllocated;
5153 pTempFile->paSegs[cSegs].cbDataAlloc = cbNewSeg;
5154 pTempFile->cbFileAllocated += cbNewSeg;
5155 pTempFile->cSegs = ++cSegs;
5156
5157 } while (pTempFile->cbFileAllocated < cbMinFile);
5158
5159 return K_TRUE;
5160 }
5161 }
5162
5163 kHlpAssertMsgFailed(("Out of bounds offFile=%#x + cbNeeded=%#x = %#x\n", offFile, cbNeeded, offFile + cbNeeded));
5164 return K_FALSE;
5165}
5166
5167
5168/** Kernel32 - WriteFile */
5169static BOOL WINAPI kwSandbox_Kernel32_WriteFile(HANDLE hFile, LPCVOID pvBuffer, DWORD cbToWrite, LPDWORD pcbActuallyWritten,
5170 LPOVERLAPPED pOverlapped)
5171{
5172 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
5173 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
5174 if (idxHandle < g_Sandbox.cHandles)
5175 {
5176 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
5177 if (pHandle != NULL)
5178 {
5179 switch (pHandle->enmType)
5180 {
5181 case KWHANDLETYPE_TEMP_FILE:
5182 {
5183 PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile;
5184
5185 kHlpAssert(!pOverlapped);
5186 kHlpAssert(pcbActuallyWritten);
5187
5188 if (kwFsTempFileEnsureSpace(pTempFile, pHandle->offFile, cbToWrite))
5189 {
5190 KU32 cbLeft;
5191 KU32 offSeg;
5192
5193 /* Locate the segment containing the byte at offFile. */
5194 KWFSTEMPFILESEG const *paSegs = pTempFile->paSegs;
5195 KU32 iSeg = pTempFile->cSegs - 1;
5196 kHlpAssert(pTempFile->cSegs > 0);
5197 while (paSegs[iSeg].offData > pHandle->offFile)
5198 iSeg--;
5199
5200 /* Copy in the data. */
5201 cbLeft = cbToWrite;
5202 offSeg = (pHandle->offFile - paSegs[iSeg].offData);
5203 for (;;)
5204 {
5205 KU32 cbAvail = paSegs[iSeg].cbDataAlloc - offSeg;
5206 if (cbAvail >= cbLeft)
5207 {
5208 kHlpMemCopy(&paSegs[iSeg].pbData[offSeg], pvBuffer, cbLeft);
5209 break;
5210 }
5211
5212 kHlpMemCopy(&paSegs[iSeg].pbData[offSeg], pvBuffer, cbAvail);
5213 pvBuffer = (KU8 const *)pvBuffer + cbAvail;
5214 cbLeft -= cbAvail;
5215 offSeg = 0;
5216 iSeg++;
5217 kHlpAssert(iSeg < pTempFile->cSegs);
5218 }
5219
5220 /* Update the file offset. */
5221 pHandle->offFile += cbToWrite;
5222 if (pHandle->offFile > pTempFile->cbFile)
5223 pTempFile->cbFile = pHandle->offFile;
5224
5225 *pcbActuallyWritten = cbToWrite;
5226 KWFS_LOG(("WriteFile(%p,,%#x) -> TRUE [temp]\n", hFile, cbToWrite));
5227 return TRUE;
5228 }
5229
5230 kHlpAssertFailed();
5231 *pcbActuallyWritten = 0;
5232 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5233 return FALSE;
5234 }
5235
5236 case KWHANDLETYPE_FSOBJ_READ_CACHE:
5237 kHlpAssertFailed();
5238 SetLastError(ERROR_ACCESS_DENIED);
5239 *pcbActuallyWritten = 0;
5240 return FALSE;
5241
5242 default:
5243 case KWHANDLETYPE_TEMP_FILE_MAPPING:
5244 kHlpAssertFailed();
5245 SetLastError(ERROR_INVALID_FUNCTION);
5246 *pcbActuallyWritten = 0;
5247 return FALSE;
5248 }
5249 }
5250 }
5251
5252#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
5253 /*
5254 * Check for stdout and stderr.
5255 */
5256 if ( g_Sandbox.StdErr.hOutput == hFile
5257 || g_Sandbox.StdOut.hOutput == hFile)
5258 {
5259 PKWCONSOLEOUTPUTLINE pLineBuf = g_Sandbox.StdErr.hOutput == hFile ? &g_Sandbox.StdErr : &g_Sandbox.StdOut;
5260 if (pLineBuf->fIsConsole)
5261 {
5262 kwSandboxConsoleWriteA(&g_Sandbox, pLineBuf, (const char *)pvBuffer, cbToWrite);
5263 KWFS_LOG(("WriteFile(console) -> TRUE\n", hFile));
5264 return TRUE;
5265 }
5266 }
5267#endif
5268
5269 KWFS_LOG(("WriteFile(%p)\n", hFile));
5270 return WriteFile(hFile, pvBuffer, cbToWrite, pcbActuallyWritten, pOverlapped);
5271}
5272
5273
5274/** Kernel32 - WriteFileEx */
5275static BOOL WINAPI kwSandbox_Kernel32_WriteFileEx(HANDLE hFile, LPCVOID pvBuffer, DWORD cbToWrite, LPOVERLAPPED pOverlapped,
5276 LPOVERLAPPED_COMPLETION_ROUTINE pfnCompletionRoutine)
5277{
5278 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
5279 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
5280 if (idxHandle < g_Sandbox.cHandles)
5281 {
5282 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
5283 if (pHandle != NULL)
5284 {
5285 kHlpAssertFailed();
5286 }
5287 }
5288
5289 KWFS_LOG(("WriteFileEx(%p)\n", hFile));
5290 return WriteFileEx(hFile, pvBuffer, cbToWrite, pOverlapped, pfnCompletionRoutine);
5291}
5292
5293
5294/** Kernel32 - SetEndOfFile; */
5295static BOOL WINAPI kwSandbox_Kernel32_SetEndOfFile(HANDLE hFile)
5296{
5297 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
5298 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
5299 if (idxHandle < g_Sandbox.cHandles)
5300 {
5301 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
5302 if (pHandle != NULL)
5303 {
5304 switch (pHandle->enmType)
5305 {
5306 case KWHANDLETYPE_TEMP_FILE:
5307 {
5308 PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile;
5309 if ( pHandle->offFile > pTempFile->cbFile
5310 && !kwFsTempFileEnsureSpace(pTempFile, pHandle->offFile, 0))
5311 {
5312 kHlpAssertFailed();
5313 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5314 return FALSE;
5315 }
5316
5317 pTempFile->cbFile = pHandle->offFile;
5318 KWFS_LOG(("SetEndOfFile(%p) -> TRUE (cbFile=%#x)\n", hFile, pTempFile->cbFile));
5319 return TRUE;
5320 }
5321
5322 case KWHANDLETYPE_FSOBJ_READ_CACHE:
5323 kHlpAssertFailed();
5324 SetLastError(ERROR_ACCESS_DENIED);
5325 return FALSE;
5326
5327 default:
5328 case KWHANDLETYPE_TEMP_FILE_MAPPING:
5329 kHlpAssertFailed();
5330 SetLastError(ERROR_INVALID_FUNCTION);
5331 return FALSE;
5332 }
5333 }
5334 }
5335
5336 KWFS_LOG(("SetEndOfFile(%p)\n", hFile));
5337 return SetEndOfFile(hFile);
5338}
5339
5340
5341/** Kernel32 - GetFileType */
5342static BOOL WINAPI kwSandbox_Kernel32_GetFileType(HANDLE hFile)
5343{
5344 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
5345 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
5346 if (idxHandle < g_Sandbox.cHandles)
5347 {
5348 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
5349 if (pHandle != NULL)
5350 {
5351 switch (pHandle->enmType)
5352 {
5353 case KWHANDLETYPE_FSOBJ_READ_CACHE:
5354 KWFS_LOG(("GetFileType(%p) -> FILE_TYPE_DISK [cached]\n", hFile));
5355 return FILE_TYPE_DISK;
5356
5357 case KWHANDLETYPE_TEMP_FILE:
5358 KWFS_LOG(("GetFileType(%p) -> FILE_TYPE_DISK [temp]\n", hFile));
5359 return FILE_TYPE_DISK;
5360 }
5361 }
5362 }
5363
5364 KWFS_LOG(("GetFileType(%p)\n", hFile));
5365 return GetFileType(hFile);
5366}
5367
5368
5369/** Kernel32 - GetFileSize */
5370static DWORD WINAPI kwSandbox_Kernel32_GetFileSize(HANDLE hFile, LPDWORD pcbHighDword)
5371{
5372 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
5373 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
5374 if (idxHandle < g_Sandbox.cHandles)
5375 {
5376 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
5377 if (pHandle != NULL)
5378 {
5379 if (pcbHighDword)
5380 *pcbHighDword = 0;
5381 SetLastError(NO_ERROR);
5382 switch (pHandle->enmType)
5383 {
5384 case KWHANDLETYPE_FSOBJ_READ_CACHE:
5385 KWFS_LOG(("GetFileSize(%p) -> %#x [cached]\n", hFile, pHandle->u.pCachedFile->cbCached));
5386 return pHandle->u.pCachedFile->cbCached;
5387
5388 case KWHANDLETYPE_TEMP_FILE:
5389 KWFS_LOG(("GetFileSize(%p) -> %#x [temp]\n", hFile, pHandle->u.pTempFile->cbFile));
5390 return pHandle->u.pTempFile->cbFile;
5391
5392 default:
5393 kHlpAssertFailed();
5394 SetLastError(ERROR_INVALID_FUNCTION);
5395 return INVALID_FILE_SIZE;
5396 }
5397 }
5398 }
5399
5400 KWFS_LOG(("GetFileSize(%p,)\n", hFile));
5401 return GetFileSize(hFile, pcbHighDword);
5402}
5403
5404
5405/** Kernel32 - GetFileSizeEx */
5406static BOOL WINAPI kwSandbox_Kernel32_GetFileSizeEx(HANDLE hFile, PLARGE_INTEGER pcbFile)
5407{
5408 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
5409 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
5410 if (idxHandle < g_Sandbox.cHandles)
5411 {
5412 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
5413 if (pHandle != NULL)
5414 {
5415 switch (pHandle->enmType)
5416 {
5417 case KWHANDLETYPE_FSOBJ_READ_CACHE:
5418 KWFS_LOG(("GetFileSizeEx(%p) -> TRUE, %#x [cached]\n", hFile, pHandle->u.pCachedFile->cbCached));
5419 pcbFile->QuadPart = pHandle->u.pCachedFile->cbCached;
5420 return TRUE;
5421
5422 case KWHANDLETYPE_TEMP_FILE:
5423 KWFS_LOG(("GetFileSizeEx(%p) -> TRUE, %#x [temp]\n", hFile, pHandle->u.pTempFile->cbFile));
5424 pcbFile->QuadPart = pHandle->u.pTempFile->cbFile;
5425 return TRUE;
5426
5427 default:
5428 kHlpAssertFailed();
5429 SetLastError(ERROR_INVALID_FUNCTION);
5430 return INVALID_FILE_SIZE;
5431 }
5432 }
5433 }
5434
5435 KWFS_LOG(("GetFileSizeEx(%p,)\n", hFile));
5436 return GetFileSizeEx(hFile, pcbFile);
5437}
5438
5439
5440/** Kernel32 - CreateFileMapping */
5441static HANDLE WINAPI kwSandbox_Kernel32_CreateFileMappingW(HANDLE hFile, LPSECURITY_ATTRIBUTES pSecAttrs,
5442 DWORD fProtect, DWORD dwMaximumSizeHigh,
5443 DWORD dwMaximumSizeLow, LPCWSTR pwszName)
5444{
5445 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
5446 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
5447 if (idxHandle < g_Sandbox.cHandles)
5448 {
5449 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
5450 if (pHandle != NULL)
5451 {
5452 switch (pHandle->enmType)
5453 {
5454 case KWHANDLETYPE_TEMP_FILE:
5455 {
5456 PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile;
5457 if ( ( fProtect == PAGE_READONLY
5458 || fProtect == PAGE_EXECUTE_READ)
5459 && dwMaximumSizeHigh == 0
5460 && ( dwMaximumSizeLow == 0
5461 || dwMaximumSizeLow == pTempFile->cbFile)
5462 && pwszName == NULL)
5463 {
5464 HANDLE hMapping = kwFsTempFileCreateHandle(pHandle->u.pTempFile, GENERIC_READ, K_TRUE /*fMapping*/);
5465 KWFS_LOG(("CreateFileMappingW(%p, %u) -> %p [temp]\n", hFile, fProtect, hMapping));
5466 return hMapping;
5467 }
5468 kHlpAssertMsgFailed(("fProtect=%#x cb=%#x'%08x name=%p\n",
5469 fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName));
5470 SetLastError(ERROR_ACCESS_DENIED);
5471 return INVALID_HANDLE_VALUE;
5472 }
5473 }
5474 }
5475 }
5476
5477 KWFS_LOG(("CreateFileMappingW(%p)\n", hFile));
5478 return CreateFileMappingW(hFile, pSecAttrs, fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName);
5479}
5480
5481/** Kernel32 - MapViewOfFile */
5482static HANDLE WINAPI kwSandbox_Kernel32_MapViewOfFile(HANDLE hSection, DWORD dwDesiredAccess,
5483 DWORD offFileHigh, DWORD offFileLow, SIZE_T cbToMap)
5484{
5485 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hSection);
5486 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
5487 if (idxHandle < g_Sandbox.cHandles)
5488 {
5489 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
5490 if (pHandle != NULL)
5491 {
5492 switch (pHandle->enmType)
5493 {
5494 case KWHANDLETYPE_FSOBJ_READ_CACHE:
5495 case KWHANDLETYPE_TEMP_FILE:
5496 kHlpAssertFailed();
5497 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5498 return NULL;
5499
5500 case KWHANDLETYPE_TEMP_FILE_MAPPING:
5501 {
5502 PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile;
5503 if ( dwDesiredAccess == FILE_MAP_READ
5504 && offFileHigh == 0
5505 && offFileLow == 0
5506 && (cbToMap == 0 || cbToMap == pTempFile->cbFile) )
5507 {
5508 kHlpAssert(pTempFile->cMappings == 0 || pTempFile->cSegs == 1);
5509 if (pTempFile->cSegs != 1)
5510 {
5511 KU32 iSeg;
5512 KU32 cbLeft;
5513 KU32 cbAll = pTempFile->cbFile ? (KU32)K_ALIGN_Z(pTempFile->cbFile, 0x2000) : 0x1000;
5514 KU8 *pbAll = NULL;
5515 int rc = kHlpPageAlloc((void **)&pbAll, cbAll, KPROT_READWRITE, K_FALSE);
5516 if (rc != 0)
5517 {
5518 kHlpAssertFailed();
5519 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5520 return NULL;
5521 }
5522
5523 cbLeft = pTempFile->cbFile;
5524 for (iSeg = 0; iSeg < pTempFile->cSegs && cbLeft > 0; iSeg++)
5525 {
5526 KU32 cbToCopy = K_MIN(cbLeft, pTempFile->paSegs[iSeg].cbDataAlloc);
5527 kHlpMemCopy(&pbAll[pTempFile->paSegs[iSeg].offData], pTempFile->paSegs[iSeg].pbData, cbToCopy);
5528 cbLeft -= cbToCopy;
5529 }
5530
5531 for (iSeg = 0; iSeg < pTempFile->cSegs; iSeg++)
5532 {
5533 kHlpPageFree(pTempFile->paSegs[iSeg].pbData, pTempFile->paSegs[iSeg].cbDataAlloc);
5534 pTempFile->paSegs[iSeg].pbData = NULL;
5535 pTempFile->paSegs[iSeg].cbDataAlloc = 0;
5536 }
5537
5538 pTempFile->cSegs = 1;
5539 pTempFile->cbFileAllocated = cbAll;
5540 pTempFile->paSegs[0].cbDataAlloc = cbAll;
5541 pTempFile->paSegs[0].pbData = pbAll;
5542 pTempFile->paSegs[0].offData = 0;
5543 }
5544
5545 pTempFile->cMappings++;
5546 kHlpAssert(pTempFile->cMappings == 1);
5547
5548 KWFS_LOG(("CreateFileMappingW(%p) -> %p [temp]\n", hSection, pTempFile->paSegs[0].pbData));
5549 return pTempFile->paSegs[0].pbData;
5550 }
5551
5552 kHlpAssertMsgFailed(("dwDesiredAccess=%#x offFile=%#x'%08x cbToMap=%#x (cbFile=%#x)\n",
5553 dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pTempFile->cbFile));
5554 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5555 return NULL;
5556 }
5557 }
5558 }
5559 }
5560
5561 KWFS_LOG(("MapViewOfFile(%p)\n", hSection));
5562 return MapViewOfFile(hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap);
5563}
5564/** @todo MapViewOfFileEx */
5565
5566
5567/** Kernel32 - UnmapViewOfFile */
5568static BOOL WINAPI kwSandbox_Kernel32_UnmapViewOfFile(LPCVOID pvBase)
5569{
5570 /* Is this one of our temporary mappings? */
5571 PKWFSTEMPFILE pCur = g_Sandbox.pTempFileHead;
5572 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
5573 while (pCur)
5574 {
5575 if ( pCur->cMappings > 0
5576 && pCur->paSegs[0].pbData == (KU8 *)pvBase)
5577 {
5578 pCur->cMappings--;
5579 KWFS_LOG(("UnmapViewOfFile(%p) -> TRUE [temp]\n", pvBase));
5580 return TRUE;
5581 }
5582 pCur = pCur->pNext;
5583 }
5584
5585 KWFS_LOG(("UnmapViewOfFile(%p)\n", pvBase));
5586 return UnmapViewOfFile(pvBase);
5587}
5588
5589/** @todo UnmapViewOfFileEx */
5590
5591
5592#endif /* WITH_TEMP_MEMORY_FILES */
5593
5594/** Kernel32 - CloseHandle */
5595static BOOL WINAPI kwSandbox_Kernel32_CloseHandle(HANDLE hObject)
5596{
5597 BOOL fRet;
5598 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hObject);
5599 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
5600 if ( idxHandle < g_Sandbox.cHandles
5601 && g_Sandbox.papHandles[idxHandle] != NULL)
5602 {
5603 fRet = CloseHandle(hObject);
5604 if (fRet)
5605 {
5606 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
5607 g_Sandbox.papHandles[idxHandle] = NULL;
5608 g_Sandbox.cActiveHandles--;
5609#ifdef WITH_TEMP_MEMORY_FILES
5610 if (pHandle->enmType == KWHANDLETYPE_TEMP_FILE)
5611 {
5612 kHlpAssert(pHandle->u.pTempFile->cActiveHandles > 0);
5613 pHandle->u.pTempFile->cActiveHandles--;
5614 }
5615#endif
5616 kHlpFree(pHandle);
5617 KWFS_LOG(("CloseHandle(%p) -> TRUE [intercepted handle]\n", hObject));
5618 }
5619 else
5620 KWFS_LOG(("CloseHandle(%p) -> FALSE [intercepted handle] err=%u!\n", hObject, GetLastError()));
5621 }
5622 else
5623 {
5624 KWFS_LOG(("CloseHandle(%p)\n", hObject));
5625 fRet = CloseHandle(hObject);
5626 }
5627 return fRet;
5628}
5629
5630
5631/** Kernel32 - GetFileAttributesA. */
5632static DWORD WINAPI kwSandbox_Kernel32_GetFileAttributesA(LPCSTR pszFilename)
5633{
5634 DWORD fRet;
5635 const char *pszExt = kHlpGetExt(pszFilename);
5636 if (kwFsIsCachableExtensionA(pszExt, K_TRUE /*fAttrQuery*/))
5637 {
5638 KFSLOOKUPERROR enmError;
5639 PKFSOBJ pFsObj;
5640 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
5641
5642 pFsObj = kFsCacheLookupNoMissingA(g_pFsCache, pszFilename, &enmError);
5643 if (pFsObj)
5644 {
5645 kHlpAssert(pFsObj->fHaveStats);
5646 fRet = pFsObj->Stats.st_attribs;
5647 kFsCacheObjRelease(g_pFsCache, pFsObj);
5648 }
5649 else
5650 {
5651 SetLastError(kwFsLookupErrorToWindowsError(enmError));
5652 fRet = INVALID_FILE_ATTRIBUTES;
5653 }
5654
5655 KWFS_LOG(("GetFileAttributesA(%s) -> %#x [cached]\n", pszFilename, fRet));
5656 return fRet;
5657 }
5658
5659 fRet = GetFileAttributesA(pszFilename);
5660 KWFS_LOG(("GetFileAttributesA(%s) -> %#x\n", pszFilename, fRet));
5661 return fRet;
5662}
5663
5664
5665/** Kernel32 - GetFileAttributesW. */
5666static DWORD WINAPI kwSandbox_Kernel32_GetFileAttributesW(LPCWSTR pwszFilename)
5667{
5668 DWORD fRet;
5669 if (kwFsIsCachablePathExtensionW(pwszFilename, K_TRUE /*fAttrQuery*/))
5670 {
5671 KFSLOOKUPERROR enmError;
5672 PKFSOBJ pFsObj;
5673 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
5674
5675 pFsObj = kFsCacheLookupNoMissingW(g_pFsCache, pwszFilename, &enmError);
5676 if (pFsObj)
5677 {
5678 kHlpAssert(pFsObj->fHaveStats);
5679 fRet = pFsObj->Stats.st_attribs;
5680 kFsCacheObjRelease(g_pFsCache, pFsObj);
5681 }
5682 else
5683 {
5684 SetLastError(kwFsLookupErrorToWindowsError(enmError));
5685 fRet = INVALID_FILE_ATTRIBUTES;
5686 }
5687
5688 KWFS_LOG(("GetFileAttributesW(%ls) -> %#x [cached]\n", pwszFilename, fRet));
5689 return fRet;
5690 }
5691
5692 fRet = GetFileAttributesW(pwszFilename);
5693 KWFS_LOG(("GetFileAttributesW(%ls) -> %#x\n", pwszFilename, fRet));
5694 return fRet;
5695}
5696
5697
5698/** Kernel32 - GetShortPathNameW - c1[xx].dll of VS2010 does this to the
5699 * directory containing each include file. We cache the result to speed
5700 * things up a little. */
5701static DWORD WINAPI kwSandbox_Kernel32_GetShortPathNameW(LPCWSTR pwszLongPath, LPWSTR pwszShortPath, DWORD cwcShortPath)
5702{
5703 DWORD cwcRet;
5704 if (kwFsIsCachablePathExtensionW(pwszLongPath, K_TRUE /*fAttrQuery*/))
5705 {
5706 KFSLOOKUPERROR enmError;
5707 PKFSOBJ pObj;
5708 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
5709
5710 pObj = kFsCacheLookupW(g_pFsCache, pwszLongPath, &enmError);
5711 if (pObj)
5712 {
5713 if (pObj->bObjType != KFSOBJ_TYPE_MISSING)
5714 {
5715 if (kFsCacheObjGetFullShortPathW(pObj, pwszShortPath, cwcShortPath, '\\'))
5716 {
5717 cwcRet = (DWORD)kwUtf16Len(pwszShortPath);
5718
5719 /* Should preserve trailing slash on directory paths. */
5720 if (pObj->bObjType == KFSOBJ_TYPE_DIR)
5721 {
5722 if ( cwcRet + 1 < cwcShortPath
5723 && pwszShortPath[cwcRet - 1] != '\\')
5724 {
5725 KSIZE cwcIn = kwUtf16Len(pwszLongPath);
5726 if ( cwcIn > 0
5727 && (pwszLongPath[cwcIn - 1] == '\\' || pwszLongPath[cwcIn - 1] == '/') )
5728 {
5729 pwszShortPath[cwcRet++] = '\\';
5730 pwszShortPath[cwcRet] = '\0';
5731 }
5732 }
5733 }
5734
5735 KWFS_LOG(("GetShortPathNameW(%ls) -> '%*.*ls' & %#x [cached]\n",
5736 pwszLongPath, K_MIN(cwcShortPath, cwcRet), K_MIN(cwcShortPath, cwcRet), pwszShortPath, cwcRet));
5737 kFsCacheObjRelease(g_pFsCache, pObj);
5738 return cwcRet;
5739 }
5740
5741 /* fall back for complicated cases. */
5742 }
5743 kFsCacheObjRelease(g_pFsCache, pObj);
5744 }
5745 }
5746 cwcRet = GetShortPathNameW(pwszLongPath, pwszShortPath, cwcShortPath);
5747 KWFS_LOG(("GetShortPathNameW(%ls) -> '%*.*ls' & %#x\n",
5748 pwszLongPath, K_MIN(cwcShortPath, cwcRet), K_MIN(cwcShortPath, cwcRet), pwszShortPath, cwcRet));
5749 return cwcRet;
5750}
5751
5752
5753#ifdef WITH_TEMP_MEMORY_FILES
5754/** Kernel32 - DeleteFileW
5755 * Skip deleting the in-memory files. */
5756static BOOL WINAPI kwSandbox_Kernel32_DeleteFileW(LPCWSTR pwszFilename)
5757{
5758 BOOL fRc;
5759 if ( g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL
5760 && kwFsIsClTempFileW(pwszFilename))
5761 {
5762 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
5763 KWFS_LOG(("DeleteFileW(%s) -> TRUE [temp]\n", pwszFilename));
5764 fRc = TRUE;
5765 }
5766 else
5767 {
5768 fRc = DeleteFileW(pwszFilename);
5769 KWFS_LOG(("DeleteFileW(%s) -> %d (%d)\n", pwszFilename, fRc, GetLastError()));
5770 }
5771 return fRc;
5772}
5773#endif /* WITH_TEMP_MEMORY_FILES */
5774
5775
5776
5777#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
5778
5779/*
5780 *
5781 * Console output buffering.
5782 * Console output buffering.
5783 * Console output buffering.
5784 *
5785 */
5786
5787
5788/**
5789 * Write a wide char string to the console.
5790 *
5791 * @param pSandbox The sandbox which output buffer to flush.
5792 */
5793static void kwSandboxConsoleWriteIt(PKWSANDBOX pSandbox, wchar_t const *pwcBuf, KU32 cwcToWrite)
5794{
5795 if (cwcToWrite > 0)
5796 {
5797 DWORD cwcWritten = 0;
5798 if (WriteConsoleW(pSandbox->Combined.hOutput, pwcBuf, cwcToWrite, &cwcWritten, NULL))
5799 {
5800 if (cwcWritten == cwcToWrite)
5801 { /* likely */ }
5802 else
5803 {
5804 DWORD off = 0;
5805 do
5806 {
5807 off += cwcWritten;
5808 cwcWritten = 0;
5809 }
5810 while ( off < cwcToWrite
5811 && WriteConsoleW(pSandbox->Combined.hOutput, &pwcBuf[off], cwcToWrite - off, &cwcWritten, NULL));
5812 kHlpAssert(off == cwcWritten);
5813 }
5814 }
5815 else
5816 kHlpAssertFailed();
5817 pSandbox->Combined.cFlushes++;
5818 }
5819}
5820
5821
5822/**
5823 * Flushes the combined console output buffer.
5824 *
5825 * @param pSandbox The sandbox which output buffer to flush.
5826 */
5827static void kwSandboxConsoleFlushCombined(PKWSANDBOX pSandbox)
5828{
5829 if (pSandbox->Combined.cwcBuf > 0)
5830 {
5831 kwSandboxConsoleWriteIt(pSandbox, pSandbox->Combined.wszBuf, pSandbox->Combined.cwcBuf);
5832 pSandbox->Combined.cwcBuf = 0;
5833 }
5834}
5835
5836
5837/**
5838 * For handling combined buffer overflow cases line by line.
5839 *
5840 * @param pSandbox The sandbox.
5841 * @param pwcBuf What to add to the combined buffer. Usually a
5842 * line, unless we're really low on buffer space.
5843 * @param cwcBuf The length of what to add.
5844 * @param fBrokenLine Whether this is a broken line.
5845 */
5846static void kwSandboxConsoleAddToCombined(PKWSANDBOX pSandbox, wchar_t const *pwcBuf, KU32 cwcBuf, KBOOL fBrokenLine)
5847{
5848 if (fBrokenLine)
5849 kwSandboxConsoleFlushCombined(pSandbox);
5850 if (pSandbox->Combined.cwcBuf + cwcBuf > K_ELEMENTS(pSandbox->Combined.wszBuf))
5851 {
5852 kwSandboxConsoleFlushCombined(pSandbox);
5853 kwSandboxConsoleWriteIt(pSandbox, pwcBuf, cwcBuf);
5854 }
5855 else
5856 {
5857 memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf], pwcBuf, cwcBuf * sizeof(wchar_t));
5858 pSandbox->Combined.cwcBuf += cwcBuf;
5859 }
5860}
5861
5862
5863/**
5864 * Called to final flush a line buffer via the combined buffer (if applicable).
5865 *
5866 * @param pSandbox The sandbox.
5867 * @param pLineBuf The line buffer.
5868 */
5869static void kwSandboxConsoleFinalFlushLineBuf(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLineBuf)
5870{
5871 if (pLineBuf->cwcBuf > 0)
5872 {
5873 if (pLineBuf->fIsConsole)
5874 {
5875 if (pLineBuf->cwcBuf < pLineBuf->cwcBufAlloc)
5876 {
5877 pLineBuf->pwcBuf[pLineBuf->cwcBuf++] = '\n';
5878 kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_FALSE /*fBrokenLine*/);
5879 }
5880 else
5881 {
5882 kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_TRUE /*fBrokenLine*/);
5883 kwSandboxConsoleAddToCombined(pSandbox, L"\n", 1, K_TRUE /*fBrokenLine*/);
5884 }
5885 pLineBuf->cwcBuf = 0;
5886 }
5887 else
5888 {
5889 kHlpAssertFailed();
5890 }
5891 }
5892}
5893
5894
5895/**
5896 * Called at the end of sandboxed execution to flush both stream buffers.
5897 *
5898 * @param pSandbox The sandbox.
5899 */
5900static void kwSandboxConsoleFlushAll(PKWSANDBOX pSandbox)
5901{
5902 /*
5903 * First do the cl.exe source file supression trick, if applicable.
5904 */
5905 if ( pSandbox->Combined.cwcBuf >= 3
5906 && pSandbox->StdOut.cwcBuf == 0
5907 && pSandbox->StdErr.cwcBuf == 0
5908 && pSandbox->Combined.cFlushes == 0
5909 && pSandbox->pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL)
5910 {
5911 KI32 off = pSandbox->Combined.cwcBuf - 1;
5912 if (pSandbox->Combined.wszBuf[off] == '\n')
5913 {
5914 KBOOL fOk = K_TRUE;
5915 while (off-- > 0)
5916 {
5917 wchar_t const wc = pSandbox->Combined.wszBuf[off];
5918 if (iswalnum(wc) || wc == '.' || wc == ' ' || wc == '_' || wc == '-')
5919 { /* likely */ }
5920 else
5921 {
5922 fOk = K_FALSE;
5923 break;
5924 }
5925 }
5926 if (fOk)
5927 {
5928 pSandbox->Combined.cwcBuf = 0;
5929 return;
5930 }
5931 }
5932 }
5933
5934 /*
5935 * Flush the two line buffer, the the combined buffer.
5936 */
5937 kwSandboxConsoleFinalFlushLineBuf(pSandbox, &pSandbox->StdErr);
5938 kwSandboxConsoleFinalFlushLineBuf(pSandbox, &pSandbox->StdOut);
5939 kwSandboxConsoleFlushCombined(pSandbox);
5940}
5941
5942
5943/**
5944 * Writes a string to the given output stream.
5945 *
5946 * @param pSandbox The sandbox.
5947 * @param pLineBuf The line buffer for the output stream.
5948 * @param pwcBuffer The buffer to write.
5949 * @param cwcToWrite The number of wchar_t's in the buffer.
5950 */
5951static void kwSandboxConsoleWriteW(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLineBuf, wchar_t const *pwcBuffer, KU32 cwcToWrite)
5952{
5953 if (cwcToWrite > 0)
5954 {
5955 /*
5956 * First, find the start of the last incomplete line so we can figure
5957 * out how much line buffering we need to do.
5958 */
5959 KU32 cchLastIncompleteLine;
5960 KU32 offLastIncompleteLine = cwcToWrite;
5961 while ( offLastIncompleteLine > 0
5962 && pwcBuffer[offLastIncompleteLine - 1] != '\n')
5963 offLastIncompleteLine--;
5964 cchLastIncompleteLine = cwcToWrite - offLastIncompleteLine;
5965
5966 /* Was there anything to line buffer? */
5967 if (offLastIncompleteLine < cwcToWrite)
5968 {
5969 /* Need to grow the line buffer? */
5970 KU32 cwcNeeded = offLastIncompleteLine != 0 ? offLastIncompleteLine : cchLastIncompleteLine + pLineBuf->cwcBuf;
5971 if (cwcNeeded > pLineBuf->cwcBufAlloc)
5972 {
5973 void *pvNew;
5974 KU32 cwcNew = !pLineBuf->cwcBufAlloc ? 1024 : pLineBuf->cwcBufAlloc * 2;
5975 while (cwcNew < cwcNeeded)
5976 cwcNew *= 2;
5977 pvNew = kHlpRealloc(pLineBuf->pwcBuf, cwcNew * sizeof(wchar_t));
5978 if (pvNew)
5979 {
5980 pLineBuf->pwcBuf = (wchar_t *)pvNew;
5981 pLineBuf->cwcBufAlloc = cwcNew;
5982 }
5983 else
5984 {
5985 pvNew = kHlpRealloc(pLineBuf->pwcBuf, cwcNeeded * sizeof(wchar_t));
5986 if (pvNew)
5987 {
5988 pLineBuf->pwcBuf = (wchar_t *)pvNew;
5989 pLineBuf->cwcBufAlloc = cwcNeeded;
5990 }
5991 else
5992 {
5993 /* This isn't perfect, but it will have to do for now. */
5994 if (pLineBuf->cwcBuf > 0)
5995 {
5996 kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_TRUE /*fBrokenLine*/);
5997 pLineBuf->cwcBuf = 0;
5998 }
5999 kwSandboxConsoleAddToCombined(pSandbox, pwcBuffer, cwcToWrite, K_TRUE /*fBrokenLine*/);
6000 return;
6001 }
6002 }
6003 }
6004
6005 /*
6006 * Handle the case where we only add to the line buffer.
6007 */
6008 if (offLastIncompleteLine == 0)
6009 {
6010 memcpy(&pLineBuf->pwcBuf[pLineBuf->cwcBuf], pwcBuffer, cwcToWrite * sizeof(wchar_t));
6011 pLineBuf->cwcBuf += cwcToWrite;
6012 return;
6013 }
6014 }
6015
6016 /*
6017 * If there is sufficient combined buffer to handle this request, this are rather simple.
6018 */
6019 if (pLineBuf->cwcBuf + cchLastIncompleteLine <= K_ELEMENTS(pSandbox->Combined.wszBuf))
6020 {
6021 if (pLineBuf->cwcBuf > 0)
6022 {
6023 memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf],
6024 pLineBuf->pwcBuf, pLineBuf->cwcBuf * sizeof(wchar_t));
6025 pSandbox->Combined.cwcBuf += pLineBuf->cwcBuf;
6026 pLineBuf->cwcBuf = 0;
6027 }
6028
6029 memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf],
6030 pwcBuffer, offLastIncompleteLine * sizeof(wchar_t));
6031 pSandbox->Combined.cwcBuf += offLastIncompleteLine;
6032 }
6033 else
6034 {
6035 /*
6036 * Do line-by-line processing of the input, flusing the combined buffer
6037 * when it becomes necessary. We may have to write lines
6038 */
6039 KU32 off = 0;
6040 KU32 offNextLine = 0;
6041
6042 /* If there is buffered chars, we handle the first line outside the
6043 main loop. We must try our best outputting it as a complete line. */
6044 if (pLineBuf->cwcBuf > 0)
6045 {
6046 while (offNextLine < cwcToWrite && pwcBuffer[offNextLine] != '\n')
6047 offNextLine++;
6048 offNextLine++;
6049 kHlpAssert(offNextLine <= offLastIncompleteLine);
6050
6051 if (pLineBuf->cwcBuf + offNextLine + pSandbox->Combined.cwcBuf <= K_ELEMENTS(pSandbox->Combined.wszBuf))
6052 {
6053 memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf],
6054 pLineBuf->pwcBuf, pLineBuf->cwcBuf * sizeof(wchar_t));
6055 pSandbox->Combined.cwcBuf += pLineBuf->cwcBuf;
6056 pLineBuf->cwcBuf = 0;
6057
6058 memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf], pwcBuffer, offNextLine * sizeof(wchar_t));
6059 pSandbox->Combined.cwcBuf += offNextLine;
6060 }
6061 else
6062 {
6063 KU32 cwcLeft = pLineBuf->cwcBufAlloc - pLineBuf->cwcBuf;
6064 if (cwcLeft > 0)
6065 {
6066 KU32 cwcCopy = K_MIN(cwcLeft, offNextLine);
6067 memcpy(&pLineBuf->pwcBuf[pLineBuf->cwcBuf], pwcBuffer, cwcCopy * sizeof(wchar_t));
6068 pLineBuf->cwcBuf += cwcCopy;
6069 off += cwcCopy;
6070 }
6071 if (pLineBuf->cwcBuf > 0)
6072 {
6073 kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_TRUE /*fBrokenLine*/);
6074 pLineBuf->cwcBuf = 0;
6075 }
6076 if (off < offNextLine)
6077 kwSandboxConsoleAddToCombined(pSandbox, &pwcBuffer[off], offNextLine - off, K_TRUE /*fBrokenLine*/);
6078 }
6079 off = offNextLine;
6080 }
6081
6082 /* Deal with the remaining lines */
6083 while (off < offLastIncompleteLine)
6084 {
6085 while (offNextLine < offLastIncompleteLine && pwcBuffer[offNextLine] != '\n')
6086 offNextLine++;
6087 offNextLine++;
6088 kHlpAssert(offNextLine <= offLastIncompleteLine);
6089 kwSandboxConsoleAddToCombined(pSandbox, &pwcBuffer[off], offNextLine - off, K_FALSE /*fBrokenLine*/);
6090 off = offNextLine;
6091 }
6092 }
6093
6094 /*
6095 * Buffer any remaining incomplete line chars.
6096 */
6097 if (offLastIncompleteLine < cwcToWrite)
6098 {
6099 memcpy(&pLineBuf->pwcBuf[0], &pwcBuffer[offLastIncompleteLine], cchLastIncompleteLine * sizeof(wchar_t));
6100 pLineBuf->cwcBuf = cchLastIncompleteLine;
6101 }
6102 }
6103}
6104
6105
6106/**
6107 * Worker for WriteConsoleA and WriteFile.
6108 *
6109 * @param pSandbox The sandbox.
6110 * @param pLineBuf The line buffer.
6111 * @param pchBuffer What to write.
6112 * @param cchToWrite How much to write.
6113 */
6114static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLineBuf, const char *pchBuffer, KU32 cchToWrite)
6115{
6116 /*
6117 * Convert it to wide char and use the 'W' to do the work.
6118 */
6119 int cwcRet;
6120 KU32 cwcBuf = cchToWrite * 2 + 1;
6121 wchar_t *pwcBufFree = NULL;
6122 wchar_t *pwcBuf;
6123
6124 if (cwcBuf <= 4096)
6125 pwcBuf = alloca(cwcBuf * sizeof(wchar_t));
6126 else
6127 pwcBuf = pwcBufFree = kHlpAlloc(cwcBuf * sizeof(wchar_t));
6128
6129 cwcRet = MultiByteToWideChar(pSandbox->Combined.uCodepage, 0/*dwFlags*/, pchBuffer, cchToWrite, pwcBuf, cwcBuf);
6130 if (cwcRet > 0)
6131 kwSandboxConsoleWriteW(pSandbox, pLineBuf, pwcBuf, cwcRet);
6132 else
6133 {
6134 DWORD cchWritten;
6135 kHlpAssertFailed();
6136
6137 /* Flush the line buffer and combined buffer before calling WriteConsoleA. */
6138 if (pLineBuf->cwcBuf > 0)
6139 {
6140 kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_TRUE /*fBroken*/);
6141 pLineBuf->cwcBuf = 0;
6142 }
6143 kwSandboxConsoleFlushCombined(pSandbox);
6144
6145 if (WriteConsoleA(pLineBuf->hBackup, pchBuffer, cchToWrite, &cchWritten, NULL /*pvReserved*/))
6146 {
6147 if (cchWritten >= cchToWrite)
6148 { /* likely */ }
6149 else
6150 {
6151 KU32 off = 0;
6152 do
6153 {
6154 off += cchWritten;
6155 cchWritten = 0;
6156 } while ( off < cchToWrite
6157 && WriteConsoleA(pLineBuf->hBackup, &pchBuffer[off], cchToWrite - off, &cchWritten, NULL));
6158 }
6159 }
6160 }
6161
6162 if (pwcBufFree)
6163 kHlpFree(pwcBufFree);
6164}
6165
6166
6167/** Kernel32 - WriteConsoleA */
6168BOOL WINAPI kwSandbox_Kernel32_WriteConsoleA(HANDLE hConOutput, CONST VOID *pvBuffer, DWORD cbToWrite, PDWORD pcbWritten,
6169 PVOID pvReserved)
6170{
6171 BOOL fRc;
6172 PKWCONSOLEOUTPUTLINE pLineBuf;
6173 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
6174
6175 if (hConOutput == g_Sandbox.StdErr.hOutput)
6176 pLineBuf = &g_Sandbox.StdErr;
6177 else
6178 pLineBuf = &g_Sandbox.StdOut;
6179 if (pLineBuf->fIsConsole)
6180 {
6181 kwSandboxConsoleWriteA(&g_Sandbox, pLineBuf, (char const *)pvBuffer, cbToWrite);
6182
6183 KWFS_LOG(("WriteConsoleA: %p, %p LB %#x (%*.*s), %p, %p -> TRUE [cached]\n",
6184 hConOutput, pvBuffer, cbToWrite, cbToWrite, cbToWrite, pvBuffer, pcbWritten, pvReserved));
6185 if (pcbWritten)
6186 *pcbWritten = cbToWrite;
6187 fRc = TRUE;
6188 }
6189 else
6190 {
6191 fRc = WriteConsoleA(hConOutput, pvBuffer, cbToWrite, pcbWritten, pvReserved);
6192 KWFS_LOG(("WriteConsoleA: %p, %p LB %#x (%*.*s), %p, %p -> %d !fallback!\n",
6193 hConOutput, pvBuffer, cbToWrite, cbToWrite, cbToWrite, pvBuffer, pcbWritten, pvReserved, fRc));
6194 }
6195 return fRc;
6196}
6197
6198
6199/** Kernel32 - WriteConsoleW */
6200BOOL WINAPI kwSandbox_Kernel32_WriteConsoleW(HANDLE hConOutput, CONST VOID *pvBuffer, DWORD cwcToWrite, PDWORD pcwcWritten,
6201 PVOID pvReserved)
6202{
6203 BOOL fRc;
6204 PKWCONSOLEOUTPUTLINE pLineBuf;
6205 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
6206
6207 if (hConOutput == g_Sandbox.StdErr.hOutput)
6208 pLineBuf = &g_Sandbox.StdErr;
6209 else
6210 pLineBuf = &g_Sandbox.StdOut;
6211 if (pLineBuf->fIsConsole)
6212 {
6213 kwSandboxConsoleWriteW(&g_Sandbox, pLineBuf, (wchar_t const *)pvBuffer, cwcToWrite);
6214
6215 KWFS_LOG(("WriteConsoleW: %p, %p LB %#x (%*.*ls), %p, %p -> TRUE [cached]\n",
6216 hConOutput, pvBuffer, cwcToWrite, cwcToWrite, cwcToWrite, pvBuffer, pcwcWritten, pvReserved));
6217 if (pcwcWritten)
6218 *pcwcWritten = cwcToWrite;
6219 fRc = TRUE;
6220 }
6221 else
6222 {
6223 fRc = WriteConsoleW(hConOutput, pvBuffer, cwcToWrite, pcwcWritten, pvReserved);
6224 KWFS_LOG(("WriteConsoleW: %p, %p LB %#x (%*.*ls), %p, %p -> %d !fallback!\n",
6225 hConOutput, pvBuffer, cwcToWrite, cwcToWrite, cwcToWrite, pvBuffer, pcwcWritten, pvReserved, fRc));
6226 }
6227 return fRc;
6228}
6229
6230#endif /* WITH_CONSOLE_OUTPUT_BUFFERING */
6231
6232
6233
6234/*
6235 *
6236 * Virtual memory leak prevension.
6237 * Virtual memory leak prevension.
6238 * Virtual memory leak prevension.
6239 *
6240 */
6241
6242/** Kernel32 - VirtualAlloc - for c1[xx].dll 78GB leaks. */
6243static PVOID WINAPI kwSandbox_Kernel32_VirtualAlloc(PVOID pvAddr, SIZE_T cb, DWORD fAllocType, DWORD fProt)
6244{
6245 PVOID pvMem = VirtualAlloc(pvAddr, cb, fAllocType, fProt);
6246 KW_LOG(("VirtualAlloc: pvAddr=%p cb=%p type=%#x prot=%#x -> %p (last=%d)\n",
6247 pvAddr, cb, fAllocType, fProt, pvMem, GetLastError()));
6248 if ( g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL
6249 && pvMem)
6250 {
6251 PKWVIRTALLOC pTracker;
6252 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
6253
6254 pTracker = g_Sandbox.pVirtualAllocHead;
6255 while ( pTracker
6256 && (KUPTR)pvMem - (KUPTR)pTracker->pvAlloc >= pTracker->cbAlloc)
6257 pTracker = pTracker->pNext;
6258 if (!pTracker)
6259 {
6260 DWORD dwErr = GetLastError();
6261 PKWVIRTALLOC pTracker = (PKWVIRTALLOC)kHlpAlloc(sizeof(*pTracker));
6262 if (pTracker)
6263 {
6264 pTracker->pvAlloc = pvMem;
6265 pTracker->cbAlloc = cb;
6266 pTracker->pNext = g_Sandbox.pVirtualAllocHead;
6267 g_Sandbox.pVirtualAllocHead = pTracker;
6268 }
6269 SetLastError(dwErr);
6270 }
6271 }
6272 return pvMem;
6273}
6274
6275
6276/** Kernel32 - VirtualFree. */
6277static BOOL WINAPI kwSandbox_Kernel32_VirtualFree(PVOID pvAddr, SIZE_T cb, DWORD dwFreeType)
6278{
6279 BOOL fRc = VirtualFree(pvAddr, cb, dwFreeType);
6280 KW_LOG(("VirtualFree: pvAddr=%p cb=%p type=%#x -> %d\n", pvAddr, cb, dwFreeType, fRc));
6281 if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL)
6282 {
6283 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
6284 if (dwFreeType & MEM_RELEASE)
6285 {
6286 PKWVIRTALLOC pTracker = g_Sandbox.pVirtualAllocHead;
6287 if (pTracker)
6288 {
6289 if (pTracker->pvAlloc == pvAddr)
6290 g_Sandbox.pVirtualAllocHead = pTracker->pNext;
6291 else
6292 {
6293 PKWVIRTALLOC pPrev;
6294 do
6295 {
6296 pPrev = pTracker;
6297 pTracker = pTracker->pNext;
6298 } while (pTracker && pTracker->pvAlloc != pvAddr);
6299 if (pTracker)
6300 pPrev->pNext = pTracker->pNext;
6301 }
6302 if (pTracker)
6303 kHlpFree(pTracker);
6304 else
6305 KW_LOG(("VirtualFree: pvAddr=%p not found!\n", pvAddr));
6306 }
6307 }
6308 }
6309 return fRc;
6310}
6311
6312
6313/** Kernel32 - HeapCreate / NtDll - RTlCreateHeap */
6314HANDLE WINAPI kwSandbox_Kernel32_HeapCreate(DWORD fOptions, SIZE_T cbInitial, SIZE_T cbMax)
6315{
6316 HANDLE hHeap;
6317 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
6318
6319 hHeap = HeapCreate(fOptions, cbInitial, cbMax);
6320 if (hHeap != NULL)
6321 {
6322 DWORD dwErr = GetLastError();
6323 PKWHEAP pTracker = (PKWHEAP)kHlpAlloc(sizeof(*pTracker));
6324 if (pTracker)
6325 {
6326 pTracker->hHeap = hHeap;
6327 pTracker->pNext = g_Sandbox.pHeapHead;
6328 g_Sandbox.pHeapHead = pTracker;
6329 }
6330
6331 SetLastError(dwErr);
6332 }
6333 return hHeap;
6334
6335}
6336
6337
6338/** Kernel32 - HeapDestroy / NtDll - RTlDestroyHeap */
6339BOOL WINAPI kwSandbox_Kernel32_HeapDestroy(HANDLE hHeap)
6340{
6341 BOOL fRc = HeapDestroy(hHeap);
6342 KW_LOG(("HeapDestroy: hHeap=%p -> %d\n", hHeap, fRc));
6343 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
6344 if (fRc)
6345 {
6346 PKWHEAP pTracker = g_Sandbox.pHeapHead;
6347 if (pTracker)
6348 {
6349 if (pTracker->hHeap == hHeap)
6350 g_Sandbox.pHeapHead = pTracker->pNext;
6351 else
6352 {
6353 PKWHEAP pPrev;
6354 do
6355 {
6356 pPrev = pTracker;
6357 pTracker = pTracker->pNext;
6358 } while (pTracker && pTracker->hHeap == hHeap);
6359 if (pTracker)
6360 pPrev->pNext = pTracker->pNext;
6361 }
6362 if (pTracker)
6363 kHlpFree(pTracker);
6364 else
6365 KW_LOG(("HeapDestroy: pvAddr=%p not found!\n", hHeap));
6366 }
6367 }
6368
6369 return fRc;
6370}
6371
6372
6373
6374/*
6375 *
6376 * Thread/Fiber local storage leak prevention.
6377 * Thread/Fiber local storage leak prevention.
6378 * Thread/Fiber local storage leak prevention.
6379 *
6380 * Note! The FlsAlloc/Free causes problems for statically linked VS2010
6381 * code like VBoxBs3ObjConverter.exe. One thing is that we're
6382 * leaking these indexes, but more importantely we crash during
6383 * worker exit since the callback is triggered multiple times.
6384 */
6385
6386
6387/** Kernel32 - FlsAlloc */
6388DWORD WINAPI kwSandbox_Kernel32_FlsAlloc(PFLS_CALLBACK_FUNCTION pfnCallback)
6389{
6390 DWORD idxFls = FlsAlloc(pfnCallback);
6391 KW_LOG(("FlsAlloc(%p) -> %#x\n", pfnCallback, idxFls));
6392 if (idxFls != FLS_OUT_OF_INDEXES)
6393 {
6394 PKWLOCALSTORAGE pTracker = (PKWLOCALSTORAGE)kHlpAlloc(sizeof(*pTracker));
6395 if (pTracker)
6396 {
6397 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
6398 pTracker->idx = idxFls;
6399 pTracker->pNext = g_Sandbox.pFlsAllocHead;
6400 g_Sandbox.pFlsAllocHead = pTracker;
6401 }
6402 }
6403
6404 return idxFls;
6405}
6406
6407/** Kernel32 - FlsFree */
6408BOOL WINAPI kwSandbox_Kernel32_FlsFree(DWORD idxFls)
6409{
6410 BOOL fRc = FlsFree(idxFls);
6411 KW_LOG(("FlsFree(%#x) -> %d\n", idxFls, fRc));
6412 if (fRc)
6413 {
6414 PKWLOCALSTORAGE pTracker;
6415 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
6416
6417 pTracker = g_Sandbox.pFlsAllocHead;
6418 if (pTracker)
6419 {
6420 if (pTracker->idx == idxFls)
6421 g_Sandbox.pFlsAllocHead = pTracker->pNext;
6422 else
6423 {
6424 PKWLOCALSTORAGE pPrev;
6425 do
6426 {
6427 pPrev = pTracker;
6428 pTracker = pTracker->pNext;
6429 } while (pTracker && pTracker->idx != idxFls);
6430 if (pTracker)
6431 pPrev->pNext = pTracker->pNext;
6432 }
6433 if (pTracker)
6434 {
6435 pTracker->idx = FLS_OUT_OF_INDEXES;
6436 pTracker->pNext = NULL;
6437 kHlpFree(pTracker);
6438 }
6439 }
6440 }
6441 return fRc;
6442}
6443
6444
6445
6446/*
6447 *
6448 * Header file hashing.
6449 * Header file hashing.
6450 * Header file hashing.
6451 *
6452 * c1.dll / c1XX.dll hashes the input files. The Visual C++ 2010 profiler
6453 * indicated that ~12% of the time was spent doing MD5 caluclation when
6454 * rebuiling openssl. The hashing it done right after reading the source
6455 * via ReadFile, same buffers and sizes.
6456 */
6457
6458#ifdef WITH_HASH_MD5_CACHE
6459
6460/** Advapi32 - CryptCreateHash */
6461static BOOL WINAPI kwSandbox_Advapi32_CryptCreateHash(HCRYPTPROV hProv, ALG_ID idAlg, HCRYPTKEY hKey, DWORD dwFlags,
6462 HCRYPTHASH *phHash)
6463{
6464 BOOL fRc;
6465
6466 /*
6467 * Only do this for cl.exe when it request normal MD5.
6468 */
6469 if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL)
6470 {
6471 if (idAlg == CALG_MD5)
6472 {
6473 if (hKey == 0)
6474 {
6475 if (dwFlags == 0)
6476 {
6477 PKWHASHMD5 pHash = (PKWHASHMD5)kHlpAllocZ(sizeof(*pHash));
6478 if (pHash)
6479 {
6480 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
6481 pHash->uMagic = KWHASHMD5_MAGIC;
6482 pHash->cbHashed = 0;
6483 pHash->fGoneBad = K_FALSE;
6484 pHash->fFallbackMode = K_FALSE;
6485 pHash->fFinal = K_FALSE;
6486
6487 /* link it. */
6488 pHash->pNext = g_Sandbox.pHashHead;
6489 g_Sandbox.pHashHead = pHash;
6490
6491 *phHash = (KUPTR)pHash;
6492 KWCRYPT_LOG(("CryptCreateHash(hProv=%p, idAlg=CALG_MD5, 0, 0, *phHash=%p) -> %d [cached]\n",
6493 hProv, *phHash, TRUE));
6494 return TRUE;
6495 }
6496
6497 kwErrPrintf("CryptCreateHash: out of memory!\n");
6498 }
6499 else
6500 kwErrPrintf("CryptCreateHash: dwFlags=%p is not supported with CALG_MD5\n", hKey);
6501 }
6502 else
6503 kwErrPrintf("CryptCreateHash: hKey=%p is not supported with CALG_MD5\n", hKey);
6504 }
6505 else
6506 kwErrPrintf("CryptCreateHash: idAlg=%#x is not supported\n", idAlg);
6507 }
6508
6509 /*
6510 * Fallback.
6511 */
6512 fRc = CryptCreateHash(hProv, idAlg, hKey, dwFlags, phHash);
6513 KWCRYPT_LOG(("CryptCreateHash(hProv=%p, idAlg=%#x (%d), hKey=%p, dwFlags=%#x, *phHash=%p) -> %d\n",
6514 hProv, idAlg, idAlg, hKey, dwFlags, *phHash, fRc));
6515 return fRc;
6516}
6517
6518
6519/** Advapi32 - CryptHashData */
6520static BOOL WINAPI kwSandbox_Advapi32_CryptHashData(HCRYPTHASH hHash, CONST BYTE *pbData, DWORD cbData, DWORD dwFlags)
6521{
6522 BOOL fRc;
6523 PKWHASHMD5 pHash = g_Sandbox.pHashHead;
6524 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
6525 while (pHash && (KUPTR)pHash != hHash)
6526 pHash = pHash->pNext;
6527 KWCRYPT_LOG(("CryptHashData(hHash=%p/%p, pbData=%p, cbData=%#x, dwFlags=%#x)\n",
6528 hHash, pHash, pbData, cbData, dwFlags));
6529 if (pHash)
6530 {
6531 /*
6532 * Validate the state.
6533 */
6534 if ( pHash->uMagic == KWHASHMD5_MAGIC
6535 && !pHash->fFinal)
6536 {
6537 if (!pHash->fFallbackMode)
6538 {
6539 /*
6540 * Does this match the previous ReadFile call to a cached file?
6541 * If it doesn't, try falling back.
6542 */
6543 if ( g_Sandbox.LastHashRead.cbRead == cbData
6544 && g_Sandbox.LastHashRead.pvRead == (void *)pbData)
6545 {
6546 PKFSWCACHEDFILE pCachedFile = g_Sandbox.LastHashRead.pCachedFile;
6547 if ( pCachedFile
6548 && kHlpMemComp(pbData, &pCachedFile->pbCached[g_Sandbox.LastHashRead.offRead], K_MIN(cbData, 64)) == 0)
6549 {
6550
6551 if (g_Sandbox.LastHashRead.offRead == pHash->cbHashed)
6552 {
6553 if ( pHash->pCachedFile == NULL
6554 && pHash->cbHashed == 0)
6555 pHash->pCachedFile = pCachedFile;
6556 if (pHash->pCachedFile == pCachedFile)
6557 {
6558 pHash->cbHashed += cbData;
6559 g_Sandbox.LastHashRead.pCachedFile = NULL;
6560 g_Sandbox.LastHashRead.pvRead = NULL;
6561 g_Sandbox.LastHashRead.cbRead = 0;
6562 g_Sandbox.LastHashRead.offRead = 0;
6563 KWCRYPT_LOG(("CryptHashData(hHash=%p/%p/%s, pbData=%p, cbData=%#x, dwFlags=%#x) -> 1 [cached]\n",
6564 hHash, pCachedFile, pCachedFile->szPath, pbData, cbData, dwFlags));
6565 return TRUE;
6566 }
6567
6568 /* Note! it's possible to fall back here too, if necessary. */
6569 kwErrPrintf("CryptHashData: Expected pCachedFile=%p, last read was made to %p!!\n",
6570 pHash->pCachedFile, g_Sandbox.LastHashRead.pCachedFile);
6571 }
6572 else
6573 kwErrPrintf("CryptHashData: Expected last read at %#x, instead it was made at %#x\n",
6574 pHash->cbHashed, g_Sandbox.LastHashRead.offRead);
6575 }
6576 else if (!pCachedFile)
6577 kwErrPrintf("CryptHashData: Last pCachedFile is NULL when buffer address and size matches!\n");
6578 else
6579 kwErrPrintf("CryptHashData: First 64 bytes of the buffer doesn't match the cache.\n");
6580 }
6581 else if (g_Sandbox.LastHashRead.cbRead != 0 && pHash->cbHashed != 0)
6582 kwErrPrintf("CryptHashData: Expected cbRead=%#x and pbData=%p, got %#x and %p instead\n",
6583 g_Sandbox.LastHashRead.cbRead, g_Sandbox.LastHashRead.pvRead, cbData, pbData);
6584 if (pHash->cbHashed == 0)
6585 pHash->fFallbackMode = K_TRUE;
6586 if (pHash->fFallbackMode)
6587 {
6588 /* Initiate fallback mode (file that we don't normally cache, like .c/.cpp). */
6589 pHash->fFallbackMode = K_TRUE;
6590 MD5Init(&pHash->Md5Ctx);
6591 MD5Update(&pHash->Md5Ctx, pbData, cbData);
6592 pHash->cbHashed = cbData;
6593 KWCRYPT_LOG(("CryptHashData(hHash=%p/fallback, pbData=%p, cbData=%#x, dwFlags=%#x) -> 1 [fallback!]\n",
6594 hHash, pbData, cbData, dwFlags));
6595 return TRUE;
6596 }
6597 pHash->fGoneBad = K_TRUE;
6598 SetLastError(ERROR_INVALID_PARAMETER);
6599 fRc = FALSE;
6600 }
6601 else
6602 {
6603 /* fallback. */
6604 MD5Update(&pHash->Md5Ctx, pbData, cbData);
6605 pHash->cbHashed += cbData;
6606 fRc = TRUE;
6607 KWCRYPT_LOG(("CryptHashData(hHash=%p/fallback, pbData=%p, cbData=%#x, dwFlags=%#x) -> 1 [fallback]\n",
6608 hHash, pbData, cbData, dwFlags));
6609 }
6610 }
6611 /*
6612 * Bad handle state.
6613 */
6614 else
6615 {
6616 if (pHash->uMagic != KWHASHMD5_MAGIC)
6617 kwErrPrintf("CryptHashData: Invalid cached hash handle!!\n");
6618 else
6619 kwErrPrintf("CryptHashData: Hash is already finalized!!\n");
6620 SetLastError(NTE_BAD_HASH);
6621 fRc = FALSE;
6622 }
6623 }
6624 else
6625 {
6626
6627 fRc = CryptHashData(hHash, pbData, cbData, dwFlags);
6628 KWCRYPT_LOG(("CryptHashData(hHash=%p, pbData=%p, cbData=%#x, dwFlags=%#x) -> %d\n", hHash, pbData, cbData, dwFlags, fRc));
6629 }
6630 return fRc;
6631}
6632
6633
6634/** Advapi32 - CryptGetHashParam */
6635static BOOL WINAPI kwSandbox_Advapi32_CryptGetHashParam(HCRYPTHASH hHash, DWORD dwParam,
6636 BYTE *pbData, DWORD *pcbData, DWORD dwFlags)
6637{
6638 BOOL fRc;
6639 PKWHASHMD5 pHash = g_Sandbox.pHashHead;
6640 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
6641 while (pHash && (KUPTR)pHash != hHash)
6642 pHash = pHash->pNext;
6643 if (pHash)
6644 {
6645 if (pHash->uMagic == KWHASHMD5_MAGIC)
6646 {
6647 if (dwFlags == 0)
6648 {
6649 DWORD cbRet;
6650 void *pvRet;
6651 union
6652 {
6653 DWORD dw;
6654 } uBuf;
6655
6656 switch (dwParam)
6657 {
6658 case HP_HASHVAL:
6659 {
6660 /* Check the hash progress. */
6661 PKFSWCACHEDFILE pCachedFile = pHash->pCachedFile;
6662 if (pCachedFile)
6663 {
6664 if ( pCachedFile->cbCached == pHash->cbHashed
6665 && !pHash->fGoneBad)
6666 {
6667 if (pCachedFile->fValidMd5)
6668 KWCRYPT_LOG(("Already calculated hash for %p/%s! [hit]\n", pCachedFile, pCachedFile->szPath));
6669 else
6670 {
6671 MD5Init(&pHash->Md5Ctx);
6672 MD5Update(&pHash->Md5Ctx, pCachedFile->pbCached, pCachedFile->cbCached);
6673 MD5Final(pCachedFile->abMd5Digest, &pHash->Md5Ctx);
6674 pCachedFile->fValidMd5 = K_TRUE;
6675 KWCRYPT_LOG(("Calculated hash for %p/%s.\n", pCachedFile, pCachedFile->szPath));
6676 }
6677 pvRet = pCachedFile->abMd5Digest;
6678 }
6679 else
6680 {
6681 /* This actually happens (iprt/string.h + common/alloc/alloc.cpp), at least
6682 from what I can tell, so just deal with it. */
6683 KWCRYPT_LOG(("CryptGetHashParam/HP_HASHVAL: Not at end of cached file! cbCached=%#x cbHashed=%#x fGoneBad=%d (%p/%p/%s)\n",
6684 pHash->pCachedFile->cbCached, pHash->cbHashed, pHash->fGoneBad,
6685 pHash, pCachedFile, pCachedFile->szPath));
6686 pHash->fFallbackMode = K_TRUE;
6687 pHash->pCachedFile = NULL;
6688 MD5Init(&pHash->Md5Ctx);
6689 MD5Update(&pHash->Md5Ctx, pCachedFile->pbCached, pHash->cbHashed);
6690 MD5Final(pHash->abDigest, &pHash->Md5Ctx);
6691 pvRet = pHash->abDigest;
6692 }
6693 pHash->fFinal = K_TRUE;
6694 cbRet = 16;
6695 break;
6696 }
6697 else if (pHash->fFallbackMode)
6698 {
6699 if (!pHash->fFinal)
6700 {
6701 pHash->fFinal = K_TRUE;
6702 MD5Final(pHash->abDigest, &pHash->Md5Ctx);
6703 }
6704 pvRet = pHash->abDigest;
6705 cbRet = 16;
6706 break;
6707 }
6708 else
6709 {
6710 kwErrPrintf("CryptGetHashParam/HP_HASHVAL: pCachedFile is NULL!!\n");
6711 SetLastError(ERROR_INVALID_SERVER_STATE);
6712 }
6713 return FALSE;
6714 }
6715
6716 case HP_HASHSIZE:
6717 uBuf.dw = 16;
6718 pvRet = &uBuf;
6719 cbRet = sizeof(DWORD);
6720 break;
6721
6722 case HP_ALGID:
6723 uBuf.dw = CALG_MD5;
6724 pvRet = &uBuf;
6725 cbRet = sizeof(DWORD);
6726 break;
6727
6728 default:
6729 kwErrPrintf("CryptGetHashParam: Unknown dwParam=%#x\n", dwParam);
6730 SetLastError(NTE_BAD_TYPE);
6731 return FALSE;
6732 }
6733
6734 /*
6735 * Copy out cbRet from pvRet.
6736 */
6737 if (pbData)
6738 {
6739 if (*pcbData >= cbRet)
6740 {
6741 *pcbData = cbRet;
6742 kHlpMemCopy(pbData, pvRet, cbRet);
6743 if (cbRet == 4)
6744 KWCRYPT_LOG(("CryptGetHashParam/%#x/%p/%p: TRUE, cbRet=%#x data=%#x [cached]\n",
6745 dwParam, pHash, pHash->pCachedFile, cbRet, (DWORD *)pbData));
6746 else if (cbRet == 16)
6747 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",
6748 dwParam, pHash, pHash->pCachedFile, cbRet,
6749 pbData[0], pbData[1], pbData[2], pbData[3],
6750 pbData[4], pbData[5], pbData[6], pbData[7],
6751 pbData[8], pbData[9], pbData[10], pbData[11],
6752 pbData[12], pbData[13], pbData[14], pbData[15]));
6753 else
6754 KWCRYPT_LOG(("CryptGetHashParam/%#x%/p%/%p: TRUE, cbRet=%#x [cached]\n",
6755 dwParam, pHash, pHash->pCachedFile, cbRet));
6756 return TRUE;
6757 }
6758
6759 kHlpMemCopy(pbData, pvRet, *pcbData);
6760 }
6761 SetLastError(ERROR_MORE_DATA);
6762 *pcbData = cbRet;
6763 KWCRYPT_LOG(("CryptGetHashParam/%#x: ERROR_MORE_DATA\n"));
6764 }
6765 else
6766 {
6767 kwErrPrintf("CryptGetHashParam: dwFlags is not zero: %#x!\n", dwFlags);
6768 SetLastError(NTE_BAD_FLAGS);
6769 }
6770 }
6771 else
6772 {
6773 kwErrPrintf("CryptGetHashParam: Invalid cached hash handle!!\n");
6774 SetLastError(NTE_BAD_HASH);
6775 }
6776 fRc = FALSE;
6777 }
6778 /*
6779 * Regular handle.
6780 */
6781 else
6782 {
6783 fRc = CryptGetHashParam(hHash, dwParam, pbData, pcbData, dwFlags);
6784 KWCRYPT_LOG(("CryptGetHashParam(hHash=%p, dwParam=%#x (%d), pbData=%p, *pcbData=%#x, dwFlags=%#x) -> %d\n",
6785 hHash, dwParam, pbData, *pcbData, dwFlags, fRc));
6786 }
6787
6788 return fRc;
6789}
6790
6791
6792/** Advapi32 - CryptDestroyHash */
6793static BOOL WINAPI kwSandbox_Advapi32_CryptDestroyHash(HCRYPTHASH hHash)
6794{
6795 BOOL fRc;
6796 PKWHASHMD5 pPrev = NULL;
6797 PKWHASHMD5 pHash = g_Sandbox.pHashHead;
6798 kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
6799 while (pHash && (KUPTR)pHash != hHash)
6800 {
6801 pPrev = pHash;
6802 pHash = pHash->pNext;
6803 }
6804 if (pHash)
6805 {
6806 if (pHash->uMagic == KWHASHMD5_MAGIC)
6807 {
6808 pHash->uMagic = 0;
6809 if (!pPrev)
6810 g_Sandbox.pHashHead = pHash->pNext;
6811 else
6812 pPrev->pNext = pHash->pNext;
6813 kHlpFree(pHash);
6814 KWCRYPT_LOG(("CryptDestroyHash(hHash=%p) -> 1 [cached]\n", hHash));
6815 fRc = TRUE;
6816 }
6817 else
6818 {
6819 kwErrPrintf("CryptDestroyHash: Invalid cached hash handle!!\n");
6820 KWCRYPT_LOG(("CryptDestroyHash(hHash=%p) -> FALSE! [cached]\n", hHash));
6821 SetLastError(ERROR_INVALID_HANDLE);
6822 fRc = FALSE;
6823 }
6824 }
6825 /*
6826 * Regular handle.
6827 */
6828 else
6829 {
6830 fRc = CryptDestroyHash(hHash);
6831 KWCRYPT_LOG(("CryptDestroyHash(hHash=%p) -> %d\n", hHash, fRc));
6832 }
6833 return fRc;
6834}
6835
6836#endif /* WITH_HASH_MD5_CACHE */
6837
6838
6839/*
6840 *
6841 * Misc function only intercepted while debugging.
6842 * Misc function only intercepted while debugging.
6843 * Misc function only intercepted while debugging.
6844 *
6845 */
6846
6847#ifndef NDEBUG
6848
6849/** CRT - memcpy */
6850static void * __cdecl kwSandbox_msvcrt_memcpy(void *pvDst, void const *pvSrc, size_t cb)
6851{
6852 KU8 const *pbSrc = (KU8 const *)pvSrc;
6853 KU8 *pbDst = (KU8 *)pvDst;
6854 KSIZE cbLeft = cb;
6855 while (cbLeft-- > 0)
6856 *pbDst++ = *pbSrc++;
6857 return pvDst;
6858}
6859
6860#endif /* NDEBUG */
6861
6862
6863
6864/**
6865 * Functions that needs replacing for sandboxed execution.
6866 */
6867KWREPLACEMENTFUNCTION const g_aSandboxReplacements[] =
6868{
6869 /*
6870 * Kernel32.dll and friends.
6871 */
6872 { TUPLE("ExitProcess"), NULL, (KUPTR)kwSandbox_Kernel32_ExitProcess },
6873 { TUPLE("TerminateProcess"), NULL, (KUPTR)kwSandbox_Kernel32_TerminateProcess },
6874
6875 { TUPLE("LoadLibraryA"), NULL, (KUPTR)kwSandbox_Kernel32_LoadLibraryA },
6876 { TUPLE("LoadLibraryW"), NULL, (KUPTR)kwSandbox_Kernel32_LoadLibraryW },
6877 { TUPLE("LoadLibraryExA"), NULL, (KUPTR)kwSandbox_Kernel32_LoadLibraryExA },
6878 { TUPLE("LoadLibraryExW"), NULL, (KUPTR)kwSandbox_Kernel32_LoadLibraryExW },
6879 { TUPLE("FreeLibrary"), NULL, (KUPTR)kwSandbox_Kernel32_FreeLibrary },
6880 { TUPLE("GetModuleHandleA"), NULL, (KUPTR)kwSandbox_Kernel32_GetModuleHandleA },
6881 { TUPLE("GetModuleHandleW"), NULL, (KUPTR)kwSandbox_Kernel32_GetModuleHandleW },
6882 { TUPLE("GetProcAddress"), NULL, (KUPTR)kwSandbox_Kernel32_GetProcAddress },
6883 { TUPLE("GetModuleFileNameA"), NULL, (KUPTR)kwSandbox_Kernel32_GetModuleFileNameA },
6884 { TUPLE("GetModuleFileNameW"), NULL, (KUPTR)kwSandbox_Kernel32_GetModuleFileNameW },
6885 { TUPLE("RtlPcToFileHeader"), NULL, (KUPTR)kwSandbox_ntdll_RtlPcToFileHeader },
6886
6887 { TUPLE("GetCommandLineA"), NULL, (KUPTR)kwSandbox_Kernel32_GetCommandLineA },
6888 { TUPLE("GetCommandLineW"), NULL, (KUPTR)kwSandbox_Kernel32_GetCommandLineW },
6889 { TUPLE("GetStartupInfoA"), NULL, (KUPTR)kwSandbox_Kernel32_GetStartupInfoA },
6890 { TUPLE("GetStartupInfoW"), NULL, (KUPTR)kwSandbox_Kernel32_GetStartupInfoW },
6891
6892 { TUPLE("CreateThread"), NULL, (KUPTR)kwSandbox_Kernel32_CreateThread },
6893
6894 { TUPLE("GetEnvironmentStrings"), NULL, (KUPTR)kwSandbox_Kernel32_GetEnvironmentStrings },
6895 { TUPLE("GetEnvironmentStringsA"), NULL, (KUPTR)kwSandbox_Kernel32_GetEnvironmentStringsA },
6896 { TUPLE("GetEnvironmentStringsW"), NULL, (KUPTR)kwSandbox_Kernel32_GetEnvironmentStringsW },
6897 { TUPLE("FreeEnvironmentStringsA"), NULL, (KUPTR)kwSandbox_Kernel32_FreeEnvironmentStringsA },
6898 { TUPLE("FreeEnvironmentStringsW"), NULL, (KUPTR)kwSandbox_Kernel32_FreeEnvironmentStringsW },
6899 { TUPLE("GetEnvironmentVariableA"), NULL, (KUPTR)kwSandbox_Kernel32_GetEnvironmentVariableA },
6900 { TUPLE("GetEnvironmentVariableW"), NULL, (KUPTR)kwSandbox_Kernel32_GetEnvironmentVariableW },
6901 { TUPLE("SetEnvironmentVariableA"), NULL, (KUPTR)kwSandbox_Kernel32_SetEnvironmentVariableA },
6902 { TUPLE("SetEnvironmentVariableW"), NULL, (KUPTR)kwSandbox_Kernel32_SetEnvironmentVariableW },
6903 { TUPLE("ExpandEnvironmentStringsA"), NULL, (KUPTR)kwSandbox_Kernel32_ExpandEnvironmentStringsA },
6904 { TUPLE("ExpandEnvironmentStringsW"), NULL, (KUPTR)kwSandbox_Kernel32_ExpandEnvironmentStringsW },
6905
6906 { TUPLE("CreateFileA"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileA },
6907 { TUPLE("CreateFileW"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileW },
6908 { TUPLE("ReadFile"), NULL, (KUPTR)kwSandbox_Kernel32_ReadFile },
6909 { TUPLE("ReadFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_ReadFileEx },
6910#ifdef WITH_TEMP_MEMORY_FILES
6911 { TUPLE("WriteFile"), NULL, (KUPTR)kwSandbox_Kernel32_WriteFile },
6912 { TUPLE("WriteFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_WriteFileEx },
6913 { TUPLE("SetEndOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_SetEndOfFile },
6914 { TUPLE("GetFileType"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileType },
6915 { TUPLE("GetFileSize"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileSize },
6916 { TUPLE("GetFileSizeEx"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileSizeEx },
6917 { TUPLE("CreateFileMappingW"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileMappingW },
6918 { TUPLE("MapViewOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_MapViewOfFile },
6919 { TUPLE("UnmapViewOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_UnmapViewOfFile },
6920#endif
6921 { TUPLE("SetFilePointer"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointer },
6922 { TUPLE("SetFilePointerEx"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointerEx },
6923 { TUPLE("CloseHandle"), NULL, (KUPTR)kwSandbox_Kernel32_CloseHandle },
6924 { TUPLE("GetFileAttributesA"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesA },
6925 { TUPLE("GetFileAttributesW"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesW },
6926 { TUPLE("GetShortPathNameW"), NULL, (KUPTR)kwSandbox_Kernel32_GetShortPathNameW },
6927#ifdef WITH_TEMP_MEMORY_FILES
6928 { TUPLE("DeleteFileW"), NULL, (KUPTR)kwSandbox_Kernel32_DeleteFileW },
6929#endif
6930
6931 { TUPLE("WriteConsoleA"), NULL, (KUPTR)kwSandbox_Kernel32_WriteConsoleA },
6932 { TUPLE("WriteConsoleW"), NULL, (KUPTR)kwSandbox_Kernel32_WriteConsoleW },
6933
6934 { TUPLE("VirtualAlloc"), NULL, (KUPTR)kwSandbox_Kernel32_VirtualAlloc },
6935 { TUPLE("VirtualFree"), NULL, (KUPTR)kwSandbox_Kernel32_VirtualFree },
6936
6937 { TUPLE("HeapCreate"), NULL, (KUPTR)kwSandbox_Kernel32_HeapCreate, K_TRUE /*fOnlyExe*/ },
6938 { TUPLE("HeapDestroy"), NULL, (KUPTR)kwSandbox_Kernel32_HeapDestroy, K_TRUE /*fOnlyExe*/ },
6939
6940 { TUPLE("FlsAlloc"), NULL, (KUPTR)kwSandbox_Kernel32_FlsAlloc },
6941 { TUPLE("FlsFree"), NULL, (KUPTR)kwSandbox_Kernel32_FlsFree },
6942
6943 { TUPLE("SetConsoleCtrlHandler"), NULL, (KUPTR)kwSandbox_Kernel32_SetConsoleCtrlHandler },
6944
6945#ifdef WITH_HASH_MD5_CACHE
6946 { TUPLE("CryptCreateHash"), NULL, (KUPTR)kwSandbox_Advapi32_CryptCreateHash },
6947 { TUPLE("CryptHashData"), NULL, (KUPTR)kwSandbox_Advapi32_CryptHashData },
6948 { TUPLE("CryptGetHashParam"), NULL, (KUPTR)kwSandbox_Advapi32_CryptGetHashParam },
6949 { TUPLE("CryptDestroyHash"), NULL, (KUPTR)kwSandbox_Advapi32_CryptDestroyHash },
6950#endif
6951
6952 /*
6953 * MS Visual C++ CRTs.
6954 */
6955 { TUPLE("exit"), NULL, (KUPTR)kwSandbox_msvcrt_exit },
6956 { TUPLE("_exit"), NULL, (KUPTR)kwSandbox_msvcrt__exit },
6957 { TUPLE("_cexit"), NULL, (KUPTR)kwSandbox_msvcrt__cexit },
6958 { TUPLE("_c_exit"), NULL, (KUPTR)kwSandbox_msvcrt__c_exit },
6959 { TUPLE("_amsg_exit"), NULL, (KUPTR)kwSandbox_msvcrt__amsg_exit },
6960 { TUPLE("terminate"), NULL, (KUPTR)kwSandbox_msvcrt_terminate },
6961
6962 { TUPLE("onexit"), NULL, (KUPTR)kwSandbox_msvcrt__onexit, K_TRUE /*fOnlyExe*/ },
6963 { TUPLE("_onexit"), NULL, (KUPTR)kwSandbox_msvcrt__onexit, K_TRUE /*fOnlyExe*/ },
6964 { TUPLE("atexit"), NULL, (KUPTR)kwSandbox_msvcrt_atexit, K_TRUE /*fOnlyExe*/ },
6965
6966 { TUPLE("_beginthread"), NULL, (KUPTR)kwSandbox_msvcrt__beginthread },
6967 { TUPLE("_beginthreadex"), NULL, (KUPTR)kwSandbox_msvcrt__beginthreadex },
6968
6969 { TUPLE("__argc"), NULL, (KUPTR)&g_Sandbox.cArgs },
6970 { TUPLE("__argv"), NULL, (KUPTR)&g_Sandbox.papszArgs },
6971 { TUPLE("__wargv"), NULL, (KUPTR)&g_Sandbox.papwszArgs },
6972 { TUPLE("__p___argc"), NULL, (KUPTR)kwSandbox_msvcrt___p___argc },
6973 { TUPLE("__p___argv"), NULL, (KUPTR)kwSandbox_msvcrt___p___argv },
6974 { TUPLE("__p___wargv"), NULL, (KUPTR)kwSandbox_msvcrt___p___wargv },
6975 { TUPLE("_acmdln"), NULL, (KUPTR)&g_Sandbox.pszCmdLine },
6976 { TUPLE("_wcmdln"), NULL, (KUPTR)&g_Sandbox.pwszCmdLine },
6977 { TUPLE("__p__acmdln"), NULL, (KUPTR)kwSandbox_msvcrt___p__acmdln },
6978 { TUPLE("__p__wcmdln"), NULL, (KUPTR)kwSandbox_msvcrt___p__wcmdln },
6979 { TUPLE("_pgmptr"), NULL, (KUPTR)&g_Sandbox.pgmptr },
6980 { TUPLE("_wpgmptr"), NULL, (KUPTR)&g_Sandbox.wpgmptr },
6981 { TUPLE("_get_pgmptr"), NULL, (KUPTR)kwSandbox_msvcrt__get_pgmptr },
6982 { TUPLE("_get_wpgmptr"), NULL, (KUPTR)kwSandbox_msvcrt__get_wpgmptr },
6983 { TUPLE("__p__pgmptr"), NULL, (KUPTR)kwSandbox_msvcrt___p__pgmptr },
6984 { TUPLE("__p__wpgmptr"), NULL, (KUPTR)kwSandbox_msvcrt___p__wpgmptr },
6985 { TUPLE("_wincmdln"), NULL, (KUPTR)kwSandbox_msvcrt__wincmdln },
6986 { TUPLE("_wwincmdln"), NULL, (KUPTR)kwSandbox_msvcrt__wwincmdln },
6987 { TUPLE("__getmainargs"), NULL, (KUPTR)kwSandbox_msvcrt___getmainargs},
6988 { TUPLE("__wgetmainargs"), NULL, (KUPTR)kwSandbox_msvcrt___wgetmainargs},
6989
6990 { TUPLE("_putenv"), NULL, (KUPTR)kwSandbox_msvcrt__putenv},
6991 { TUPLE("_wputenv"), NULL, (KUPTR)kwSandbox_msvcrt__wputenv},
6992 { TUPLE("_putenv_s"), NULL, (KUPTR)kwSandbox_msvcrt__putenv_s},
6993 { TUPLE("_wputenv_s"), NULL, (KUPTR)kwSandbox_msvcrt__wputenv_s},
6994 { TUPLE("__initenv"), NULL, (KUPTR)&g_Sandbox.initenv },
6995 { TUPLE("__winitenv"), NULL, (KUPTR)&g_Sandbox.winitenv },
6996 { TUPLE("__p___initenv"), NULL, (KUPTR)kwSandbox_msvcrt___p___initenv},
6997 { TUPLE("__p___winitenv"), NULL, (KUPTR)kwSandbox_msvcrt___p___winitenv},
6998 { TUPLE("_environ"), NULL, (KUPTR)&g_Sandbox.environ },
6999 { TUPLE("_wenviron"), NULL, (KUPTR)&g_Sandbox.wenviron },
7000 { TUPLE("_get_environ"), NULL, (KUPTR)kwSandbox_msvcrt__get_environ },
7001 { TUPLE("_get_wenviron"), NULL, (KUPTR)kwSandbox_msvcrt__get_wenviron },
7002 { TUPLE("__p__environ"), NULL, (KUPTR)kwSandbox_msvcrt___p__environ },
7003 { TUPLE("__p__wenviron"), NULL, (KUPTR)kwSandbox_msvcrt___p__wenviron },
7004
7005#ifndef NDEBUG
7006 { TUPLE("memcpy"), NULL, (KUPTR)kwSandbox_msvcrt_memcpy },
7007#endif
7008};
7009/** Number of entries in g_aReplacements. */
7010KU32 const g_cSandboxReplacements = K_ELEMENTS(g_aSandboxReplacements);
7011
7012
7013/**
7014 * Functions that needs replacing in natively loaded DLLs when doing sandboxed
7015 * execution.
7016 */
7017KWREPLACEMENTFUNCTION const g_aSandboxNativeReplacements[] =
7018{
7019 /*
7020 * Kernel32.dll and friends.
7021 */
7022 { TUPLE("ExitProcess"), NULL, (KUPTR)kwSandbox_Kernel32_ExitProcess },
7023 { TUPLE("TerminateProcess"), NULL, (KUPTR)kwSandbox_Kernel32_TerminateProcess },
7024
7025#if 0
7026 { TUPLE("CreateThread"), NULL, (KUPTR)kwSandbox_Kernel32_CreateThread },
7027#endif
7028
7029 { TUPLE("CreateFileA"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileA },
7030 { TUPLE("CreateFileW"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileW },
7031 { TUPLE("ReadFile"), NULL, (KUPTR)kwSandbox_Kernel32_ReadFile },
7032 { TUPLE("ReadFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_ReadFileEx },
7033#ifdef WITH_TEMP_MEMORY_FILES
7034 { TUPLE("WriteFile"), NULL, (KUPTR)kwSandbox_Kernel32_WriteFile },
7035 { TUPLE("WriteFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_WriteFileEx },
7036 { TUPLE("SetEndOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_SetEndOfFile },
7037 { TUPLE("GetFileType"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileType },
7038 { TUPLE("GetFileSize"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileSize },
7039 { TUPLE("GetFileSizeEx"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileSizeEx },
7040 { TUPLE("CreateFileMappingW"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileMappingW },
7041 { TUPLE("MapViewOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_MapViewOfFile },
7042 { TUPLE("UnmapViewOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_UnmapViewOfFile },
7043#endif
7044 { TUPLE("SetFilePointer"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointer },
7045 { TUPLE("SetFilePointerEx"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointerEx },
7046 { TUPLE("CloseHandle"), NULL, (KUPTR)kwSandbox_Kernel32_CloseHandle },
7047 { TUPLE("GetFileAttributesA"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesA },
7048 { TUPLE("GetFileAttributesW"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesW },
7049 { TUPLE("GetShortPathNameW"), NULL, (KUPTR)kwSandbox_Kernel32_GetShortPathNameW },
7050#ifdef WITH_TEMP_MEMORY_FILES
7051 { TUPLE("DeleteFileW"), NULL, (KUPTR)kwSandbox_Kernel32_DeleteFileW },
7052#endif
7053 { TUPLE("SetConsoleCtrlHandler"), NULL, (KUPTR)kwSandbox_Kernel32_SetConsoleCtrlHandler },
7054
7055 { TUPLE("WriteConsoleA"), NULL, (KUPTR)kwSandbox_Kernel32_WriteConsoleA },
7056 { TUPLE("WriteConsoleW"), NULL, (KUPTR)kwSandbox_Kernel32_WriteConsoleW },
7057
7058#ifdef WITH_HASH_MD5_CACHE
7059 { TUPLE("CryptCreateHash"), NULL, (KUPTR)kwSandbox_Advapi32_CryptCreateHash },
7060 { TUPLE("CryptHashData"), NULL, (KUPTR)kwSandbox_Advapi32_CryptHashData },
7061 { TUPLE("CryptGetHashParam"), NULL, (KUPTR)kwSandbox_Advapi32_CryptGetHashParam },
7062 { TUPLE("CryptDestroyHash"), NULL, (KUPTR)kwSandbox_Advapi32_CryptDestroyHash },
7063#endif
7064
7065 { TUPLE("RtlPcToFileHeader"), NULL, (KUPTR)kwSandbox_ntdll_RtlPcToFileHeader },
7066
7067
7068 /*
7069 * MS Visual C++ CRTs.
7070 */
7071 { TUPLE("exit"), NULL, (KUPTR)kwSandbox_msvcrt_exit },
7072 { TUPLE("_exit"), NULL, (KUPTR)kwSandbox_msvcrt__exit },
7073 { TUPLE("_cexit"), NULL, (KUPTR)kwSandbox_msvcrt__cexit },
7074 { TUPLE("_c_exit"), NULL, (KUPTR)kwSandbox_msvcrt__c_exit },
7075 { TUPLE("_amsg_exit"), NULL, (KUPTR)kwSandbox_msvcrt__amsg_exit },
7076 { TUPLE("terminate"), NULL, (KUPTR)kwSandbox_msvcrt_terminate },
7077
7078#if 0 /* used by mspdbXXX.dll */
7079 { TUPLE("_beginthread"), NULL, (KUPTR)kwSandbox_msvcrt__beginthread },
7080 { TUPLE("_beginthreadex"), NULL, (KUPTR)kwSandbox_msvcrt__beginthreadex },
7081#endif
7082};
7083/** Number of entries in g_aSandboxNativeReplacements. */
7084KU32 const g_cSandboxNativeReplacements = K_ELEMENTS(g_aSandboxNativeReplacements);
7085
7086
7087/**
7088 * Control handler.
7089 *
7090 * @returns TRUE if handled, FALSE if not.
7091 * @param dwCtrlType The signal.
7092 */
7093static BOOL WINAPI kwSandboxCtrlHandler(DWORD dwCtrlType)
7094{
7095 switch (dwCtrlType)
7096 {
7097 case CTRL_C_EVENT:
7098 fprintf(stderr, "kWorker: Ctrl-C\n");
7099 exit(9);
7100 break;
7101
7102 case CTRL_BREAK_EVENT:
7103 fprintf(stderr, "kWorker: Ctrl-Break\n");
7104 exit(10);
7105 break;
7106
7107 case CTRL_CLOSE_EVENT:
7108 fprintf(stderr, "kWorker: console closed\n");
7109 exit(11);
7110 break;
7111
7112 case CTRL_LOGOFF_EVENT:
7113 fprintf(stderr, "kWorker: logoff event\n");
7114 exit(11);
7115 break;
7116
7117 case CTRL_SHUTDOWN_EVENT:
7118 fprintf(stderr, "kWorker: shutdown event\n");
7119 exit(11);
7120 break;
7121
7122 default:
7123 fprintf(stderr, "kwSandboxCtrlHandler: %#x\n", dwCtrlType);
7124 break;
7125 }
7126 return TRUE;
7127}
7128
7129
7130/**
7131 * Used by kwSandboxExec to reset the state of the module tree.
7132 *
7133 * This is done recursively.
7134 *
7135 * @param pMod The root of the tree to consider.
7136 */
7137static void kwSandboxResetModuleState(PKWMODULE pMod)
7138{
7139 if ( !pMod->fNative
7140 && pMod->u.Manual.enmState != KWMODSTATE_NEEDS_BITS)
7141 {
7142 KSIZE iImp;
7143 pMod->u.Manual.enmState = KWMODSTATE_NEEDS_BITS;
7144 iImp = pMod->u.Manual.cImpMods;
7145 while (iImp-- > 0)
7146 kwSandboxResetModuleState(pMod->u.Manual.apImpMods[iImp]);
7147 }
7148}
7149
7150static PPEB kwSandboxGetProcessEnvironmentBlock(void)
7151{
7152#if K_ARCH == K_ARCH_X86_32
7153 return (PPEB)__readfsdword(0x030 /* offset of ProcessEnvironmentBlock in TEB */);
7154#elif K_ARCH == K_ARCH_AMD64
7155 return (PPEB)__readgsqword(0x060 /* offset of ProcessEnvironmentBlock in TEB */);
7156#else
7157# error "Port me!"
7158#endif
7159}
7160
7161
7162#if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_X86)
7163typedef struct _EXCEPTION_REGISTRATION_RECORD
7164{
7165 struct _EXCEPTION_REGISTRATION_RECORD * volatile PrevStructure;
7166 KU32 (__cdecl * volatile ExceptionHandler)(PEXCEPTION_RECORD, struct _EXCEPTION_REGISTRATION_RECORD*, PCONTEXT,
7167 struct _EXCEPTION_REGISTRATION_RECORD * volatile *);
7168};
7169
7170/**
7171 * Vectored exception handler that emulates x86 chained exception handler.
7172 *
7173 * This is necessary because the RtlIsValidHandler check fails for self loaded
7174 * code and prevents cl.exe from working. (On AMD64 we can register function
7175 * tables, but on X86 cooking your own handling seems to be the only viabke
7176 * alternative.)
7177 *
7178 * @returns EXCEPTION_CONTINUE_SEARCH or EXCEPTION_CONTINUE_EXECUTION.
7179 * @param pXcptPtrs The exception details.
7180 */
7181static LONG CALLBACK kwSandboxVecXcptEmulateChained(PEXCEPTION_POINTERS pXcptPtrs)
7182{
7183 PNT_TIB pTib = (PNT_TIB)NtCurrentTeb();
7184 KW_LOG(("kwSandboxVecXcptEmulateChained: %#x\n", pXcptPtrs->ExceptionRecord->ExceptionCode));
7185 if (g_Sandbox.fRunning)
7186 {
7187 PEXCEPTION_RECORD pXcptRec = pXcptPtrs->ExceptionRecord;
7188 PCONTEXT pXcptCtx = pXcptPtrs->ContextRecord;
7189 struct _EXCEPTION_REGISTRATION_RECORD * volatile *ppRegRec = &pTib->ExceptionList;
7190 struct _EXCEPTION_REGISTRATION_RECORD * pRegRec = *ppRegRec;
7191 while (((KUPTR)pRegRec & (sizeof(void *) - 3)) == 0 && pRegRec != NULL)
7192 {
7193#if 1
7194 /* This is a more robust version that isn't subject to calling
7195 convension cleanup disputes and such. */
7196 KU32 uSavedEdi;
7197 KU32 uSavedEsi;
7198 KU32 uSavedEbx;
7199 KU32 rcHandler;
7200 __asm
7201 {
7202 mov [uSavedEdi], edi
7203 mov [uSavedEsi], esi
7204 mov [uSavedEbx], ebx
7205 mov esi, esp
7206 mov edi, esp
7207 mov ecx, [pXcptRec]
7208 mov edx, [pRegRec]
7209 mov eax, [pXcptCtx]
7210 mov ebx, [ppRegRec]
7211 sub esp, 16
7212 and esp, 0fffffff0h
7213 mov [esp ], ecx
7214 mov [esp + 4], edx
7215 mov [esp + 8], eax
7216 mov [esp + 12], ebx
7217 call dword ptr [edx + 4]
7218 mov esp, esi
7219 cmp esp, edi
7220 je stack_ok
7221 int 3
7222 stack_ok:
7223 mov edi, [uSavedEdi]
7224 mov esi, [uSavedEsi]
7225 mov ebx, [uSavedEbx]
7226 mov [rcHandler], eax
7227 }
7228#else
7229 KU32 rcHandler = pRegRec->ExceptionHandler(pXcptPtrs->ExceptionRecord, pRegRec, pXcptPtrs->ContextRecord, ppRegRec);
7230#endif
7231 if (rcHandler == ExceptionContinueExecution)
7232 {
7233 kHlpAssert(!(pXcptPtrs->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE));
7234 return EXCEPTION_CONTINUE_EXECUTION;
7235 }
7236 if (rcHandler == ExceptionContinueSearch)
7237 kHlpAssert(!(pXcptPtrs->ExceptionRecord->ExceptionFlags & 8 /*EXCEPTION_STACK_INVALID*/));
7238 else if (rcHandler == ExceptionNestedException)
7239 kHlpAssertMsgFailed(("Nested exceptions.\n"));
7240 else
7241 kHlpAssertMsgFailed(("Invalid return %#x (%d).\n", rcHandler, rcHandler));
7242
7243 /*
7244 * Next.
7245 */
7246 ppRegRec = &pRegRec->PrevStructure;
7247 pRegRec = pRegRec->PrevStructure;
7248 }
7249 }
7250 return EXCEPTION_CONTINUE_SEARCH;
7251}
7252#endif /* WINDOWS + X86 */
7253
7254
7255/**
7256 * Enters the given handle into the handle table.
7257 *
7258 * @returns K_TRUE on success, K_FALSE on failure.
7259 * @param pSandbox The sandbox.
7260 * @param pHandle The handle.
7261 */
7262static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle)
7263{
7264 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(pHandle->hHandle);
7265 kHlpAssertReturn(idxHandle < KW_HANDLE_MAX, K_FALSE);
7266
7267 /*
7268 * Grow handle table.
7269 */
7270 if (idxHandle >= pSandbox->cHandles)
7271 {
7272 void *pvNew;
7273 KU32 cHandles = pSandbox->cHandles ? pSandbox->cHandles * 2 : 32;
7274 while (cHandles <= idxHandle)
7275 cHandles *= 2;
7276 pvNew = kHlpRealloc(pSandbox->papHandles, cHandles * sizeof(pSandbox->papHandles[0]));
7277 if (!pvNew)
7278 {
7279 KW_LOG(("Out of memory growing handle table to %u handles\n", cHandles));
7280 return K_FALSE;
7281 }
7282 pSandbox->papHandles = (PKWHANDLE *)pvNew;
7283 kHlpMemSet(&pSandbox->papHandles[pSandbox->cHandles], 0,
7284 (cHandles - pSandbox->cHandles) * sizeof(pSandbox->papHandles[0]));
7285 pSandbox->cHandles = cHandles;
7286 }
7287
7288 /*
7289 * Check that the entry is unused then insert it.
7290 */
7291 kHlpAssertReturn(pSandbox->papHandles[idxHandle] == NULL, K_FALSE);
7292 pSandbox->papHandles[idxHandle] = pHandle;
7293 pSandbox->cActiveHandles++;
7294 return K_TRUE;
7295}
7296
7297
7298/**
7299 * Creates a correctly quoted ANSI command line string from the given argv.
7300 *
7301 * @returns Pointer to the command line.
7302 * @param cArgs Number of arguments.
7303 * @param papszArgs The argument vector.
7304 * @param fWatcomBrainDamange Whether to apply watcom rules while quoting.
7305 * @param pcbCmdLine Where to return the command line length,
7306 * including one terminator.
7307 */
7308static char *kwSandboxInitCmdLineFromArgv(KU32 cArgs, const char **papszArgs, KBOOL fWatcomBrainDamange, KSIZE *pcbCmdLine)
7309{
7310 KU32 i;
7311 KSIZE cbCmdLine;
7312 char *pszCmdLine;
7313
7314 /* Make a copy of the argument vector that we'll be quoting. */
7315 char **papszQuotedArgs = alloca(sizeof(papszArgs[0]) * (cArgs + 1));
7316 kHlpMemCopy(papszQuotedArgs, papszArgs, sizeof(papszArgs[0]) * (cArgs + 1));
7317
7318 /* Quote the arguments that need it. */
7319 quote_argv(cArgs, papszQuotedArgs, fWatcomBrainDamange, 0 /*leak*/);
7320
7321 /* figure out cmd line length. */
7322 cbCmdLine = 0;
7323 for (i = 0; i < cArgs; i++)
7324 cbCmdLine += kHlpStrLen(papszQuotedArgs[i]) + 1;
7325 *pcbCmdLine = cbCmdLine;
7326
7327 pszCmdLine = (char *)kHlpAlloc(cbCmdLine + 1);
7328 if (pszCmdLine)
7329 {
7330 char *psz = kHlpStrPCopy(pszCmdLine, papszQuotedArgs[0]);
7331 if (papszQuotedArgs[0] != papszArgs[0])
7332 free(papszQuotedArgs[0]);
7333
7334 for (i = 1; i < cArgs; i++)
7335 {
7336 *psz++ = ' ';
7337 psz = kHlpStrPCopy(psz, papszQuotedArgs[i]);
7338 if (papszQuotedArgs[i] != papszArgs[i])
7339 free(papszQuotedArgs[i]);
7340 }
7341 kHlpAssert((KSIZE)(&psz[1] - pszCmdLine) == cbCmdLine);
7342
7343 *psz++ = '\0';
7344 *psz++ = '\0';
7345 }
7346
7347 return pszCmdLine;
7348}
7349
7350
7351
7352static int kwSandboxInit(PKWSANDBOX pSandbox, PKWTOOL pTool,
7353 KU32 cArgs, const char **papszArgs, KBOOL fWatcomBrainDamange,
7354 KU32 cEnvVars, const char **papszEnvVars)
7355{
7356 PPEB pPeb = kwSandboxGetProcessEnvironmentBlock();
7357 wchar_t *pwcPool;
7358 KSIZE cbStrings;
7359 KSIZE cwc;
7360 KSIZE cbCmdLine;
7361 KU32 i;
7362 int rc;
7363
7364 /* Simple stuff. */
7365 pSandbox->rcExitCode = 256;
7366 pSandbox->pTool = pTool;
7367 pSandbox->idMainThread = GetCurrentThreadId();
7368 pSandbox->pgmptr = (char *)pTool->pszPath;
7369 pSandbox->wpgmptr = (wchar_t *)pTool->pwszPath;
7370#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
7371 pSandbox->StdOut.cwcBuf = 0;
7372 pSandbox->StdErr.cwcBuf = 0;
7373 pSandbox->Combined.cwcBuf = 0;
7374 pSandbox->Combined.cFlushes = 0;
7375#endif
7376 pSandbox->cArgs = cArgs;
7377 pSandbox->papszArgs = (char **)papszArgs;
7378 pSandbox->pszCmdLine = kwSandboxInitCmdLineFromArgv(cArgs, papszArgs, fWatcomBrainDamange, &cbCmdLine);
7379 if (!pSandbox->pszCmdLine)
7380 return KERR_NO_MEMORY;
7381
7382 /*
7383 * Convert command line and argv to UTF-16.
7384 * We assume each ANSI char requires a surrogate pair in the UTF-16 variant.
7385 */
7386 pSandbox->papwszArgs = (wchar_t **)kHlpAlloc(sizeof(wchar_t *) * (pSandbox->cArgs + 2) + cbCmdLine * 2 * sizeof(wchar_t));
7387 if (!pSandbox->papwszArgs)
7388 return KERR_NO_MEMORY;
7389 pwcPool = (wchar_t *)&pSandbox->papwszArgs[pSandbox->cArgs + 2];
7390 for (i = 0; i < cArgs; i++)
7391 {
7392 *pwcPool++ = pSandbox->papszArgs[i][-1]; /* flags */
7393 pSandbox->papwszArgs[i] = pwcPool;
7394 pwcPool += kwStrToUtf16(pSandbox->papszArgs[i], pwcPool, (kHlpStrLen(pSandbox->papszArgs[i]) + 1) * 2);
7395 pwcPool++;
7396 }
7397 pSandbox->papwszArgs[pSandbox->cArgs + 0] = NULL;
7398 pSandbox->papwszArgs[pSandbox->cArgs + 1] = NULL;
7399
7400 /*
7401 * Convert the commandline string to UTF-16, same pessimistic approach as above.
7402 */
7403 cbStrings = (cbCmdLine + 1) * 2 * sizeof(wchar_t);
7404 pSandbox->pwszCmdLine = kHlpAlloc(cbStrings);
7405 if (!pSandbox->pwszCmdLine)
7406 return KERR_NO_MEMORY;
7407 cwc = kwStrToUtf16(pSandbox->pszCmdLine, pSandbox->pwszCmdLine, cbStrings / sizeof(wchar_t));
7408
7409 pSandbox->SavedCommandLine = pPeb->ProcessParameters->CommandLine;
7410 pPeb->ProcessParameters->CommandLine.Buffer = pSandbox->pwszCmdLine;
7411 pPeb->ProcessParameters->CommandLine.Length = (USHORT)cwc * sizeof(wchar_t);
7412
7413 /*
7414 * Setup the enviornment.
7415 */
7416 rc = kwSandboxGrowEnv(pSandbox, cEnvVars + 2);
7417 if (rc == 0)
7418 {
7419 KU32 iDst = 0;
7420 for (i = 0; i < cEnvVars; i++)
7421 {
7422 const char *pszVar = papszEnvVars[i];
7423 KSIZE cchVar = kHlpStrLen(pszVar);
7424 if ( cchVar > 0
7425 && kHlpMemChr(pszVar, '=', cchVar) != NULL)
7426 {
7427 char *pszCopy = kHlpDup(pszVar, cchVar + 1);
7428 wchar_t *pwszCopy = kwStrToUtf16AllocN(pszVar, cchVar + 1);
7429 if (pszCopy && pwszCopy)
7430 {
7431 pSandbox->papszEnvVars[iDst] = pszCopy;
7432 pSandbox->environ[iDst] = pszCopy;
7433 pSandbox->papwszEnvVars[iDst] = pwszCopy;
7434 pSandbox->wenviron[iDst] = pwszCopy;
7435 iDst++;
7436 }
7437 else
7438 {
7439 kHlpFree(pszCopy);
7440 kHlpFree(pwszCopy);
7441 return kwErrPrintfRc(KERR_NO_MEMORY, "Out of memory setting up env vars!\n");
7442 }
7443 }
7444 else
7445 kwErrPrintf("kwSandboxInit: Skipping bad env var '%s'\n", pszVar);
7446 }
7447 pSandbox->papszEnvVars[iDst] = NULL;
7448 pSandbox->environ[iDst] = NULL;
7449 pSandbox->papwszEnvVars[iDst] = NULL;
7450 pSandbox->wenviron[iDst] = NULL;
7451 }
7452 else
7453 return kwErrPrintfRc(KERR_NO_MEMORY, "Error setting up environment variables: %d\n", rc);
7454
7455 /*
7456 * Invalidate the volatile parts of cache (kBuild output directory,
7457 * temporary directory, whatever).
7458 */
7459 kFsCacheInvalidateCustomBoth(g_pFsCache);
7460 return 0;
7461}
7462
7463
7464/**
7465 * Does sandbox cleanup between jobs.
7466 *
7467 * We postpone whatever isn't externally visible (i.e. files) and doesn't
7468 * influence the result, so that kmk can get on with things ASAP.
7469 *
7470 * @param pSandbox The sandbox.
7471 */
7472static void kwSandboxCleanupLate(PKWSANDBOX pSandbox)
7473{
7474 PROCESS_MEMORY_COUNTERS MemInfo;
7475 PKWVIRTALLOC pTracker;
7476 PKWHEAP pHeap;
7477 PKWLOCALSTORAGE pLocalStorage;
7478#ifdef WITH_HASH_MD5_CACHE
7479 PKWHASHMD5 pHash;
7480#endif
7481#ifdef WITH_TEMP_MEMORY_FILES
7482 PKWFSTEMPFILE pTempFile;
7483#endif
7484 PKWEXITCALLACK pExitCallback;
7485
7486 /* Do exit callback first. */
7487 pExitCallback = g_Sandbox.pExitCallbackHead;
7488 g_Sandbox.pExitCallbackHead = NULL;
7489 while (pExitCallback)
7490 {
7491 PKWEXITCALLACK pNext = pExitCallback->pNext;
7492 KW_LOG(("kwSandboxCleanupLate: calling %p %sexit handler\n",
7493 pExitCallback->pfnCallback, pExitCallback->fAtExit ? "at" : "_on"));
7494 __try
7495 {
7496 pExitCallback->pfnCallback();
7497 }
7498 __except (EXCEPTION_EXECUTE_HANDLER)
7499 {
7500 KW_LOG(("kwSandboxCleanupLate: %sexit handler %p threw an exception!\n",
7501 pExitCallback->fAtExit ? "at" : "_on", pExitCallback->pfnCallback));
7502 kHlpAssertFailed();
7503 }
7504 kHlpFree(pExitCallback);
7505 pExitCallback = pNext;
7506 }
7507
7508
7509#ifdef WITH_TEMP_MEMORY_FILES
7510 /* The temporary files aren't externally visible, they're all in memory. */
7511 pTempFile = pSandbox->pTempFileHead;
7512 pSandbox->pTempFileHead = NULL;
7513 while (pTempFile)
7514 {
7515 PKWFSTEMPFILE pNext = pTempFile->pNext;
7516 KU32 iSeg = pTempFile->cSegs;
7517 while (iSeg-- > 0)
7518 kHlpPageFree(pTempFile->paSegs[iSeg].pbData, pTempFile->paSegs[iSeg].cbDataAlloc);
7519 kHlpFree(pTempFile->paSegs);
7520 pTempFile->pNext = NULL;
7521 kHlpFree(pTempFile);
7522
7523 pTempFile = pNext;
7524 }
7525#endif
7526
7527 /* Free left behind VirtualAlloc leaks. */
7528 pTracker = g_Sandbox.pVirtualAllocHead;
7529 g_Sandbox.pVirtualAllocHead = NULL;
7530 while (pTracker)
7531 {
7532 PKWVIRTALLOC pNext = pTracker->pNext;
7533 KW_LOG(("Freeing VirtualFree leak %p LB %#x\n", pTracker->pvAlloc, pTracker->cbAlloc));
7534 VirtualFree(pTracker->pvAlloc, 0, MEM_RELEASE);
7535 kHlpFree(pTracker);
7536 pTracker = pNext;
7537 }
7538
7539 /* Free left behind HeapCreate leaks. */
7540 pHeap = g_Sandbox.pHeapHead;
7541 g_Sandbox.pHeapHead = NULL;
7542 while (pHeap != NULL)
7543 {
7544 PKWHEAP pNext = pHeap->pNext;
7545 KW_LOG(("Freeing HeapCreate leak %p\n", pHeap->hHeap));
7546 HeapDestroy(pHeap->hHeap);
7547 pHeap = pNext;
7548 }
7549
7550 /* Free left behind FlsAlloc leaks. */
7551 pLocalStorage = g_Sandbox.pFlsAllocHead;
7552 g_Sandbox.pFlsAllocHead = NULL;
7553 while (pLocalStorage)
7554 {
7555 PKWLOCALSTORAGE pNext = pLocalStorage->pNext;
7556 KW_LOG(("Freeing leaked FlsAlloc index %#x\n", pLocalStorage->idx));
7557 FlsFree(pLocalStorage->idx);
7558 kHlpFree(pLocalStorage);
7559 pLocalStorage = pNext;
7560 }
7561
7562 /* Free left behind TlsAlloc leaks. */
7563 pLocalStorage = g_Sandbox.pTlsAllocHead;
7564 g_Sandbox.pTlsAllocHead = NULL;
7565 while (pLocalStorage)
7566 {
7567 PKWLOCALSTORAGE pNext = pLocalStorage->pNext;
7568 KW_LOG(("Freeing leaked TlsAlloc index %#x\n", pLocalStorage->idx));
7569 TlsFree(pLocalStorage->idx);
7570 kHlpFree(pLocalStorage);
7571 pLocalStorage = pNext;
7572 }
7573
7574
7575 /* Free the environment. */
7576 if (pSandbox->papszEnvVars)
7577 {
7578 KU32 i;
7579 for (i = 0; pSandbox->papszEnvVars[i]; i++)
7580 kHlpFree(pSandbox->papszEnvVars[i]);
7581 pSandbox->environ[0] = NULL;
7582 pSandbox->papszEnvVars[0] = NULL;
7583
7584 for (i = 0; pSandbox->papwszEnvVars[i]; i++)
7585 kHlpFree(pSandbox->papwszEnvVars[i]);
7586 pSandbox->wenviron[0] = NULL;
7587 pSandbox->papwszEnvVars[0] = NULL;
7588 }
7589
7590#ifdef WITH_HASH_MD5_CACHE
7591 /*
7592 * Hash handles.
7593 */
7594 pHash = pSandbox->pHashHead;
7595 pSandbox->pHashHead = NULL;
7596 while (pHash)
7597 {
7598 PKWHASHMD5 pNext = pHash->pNext;
7599 KWCRYPT_LOG(("Freeing leaked hash instance %#p\n", pHash));
7600 kHlpFree(pHash);
7601 pHash = pNext;
7602 }
7603#endif
7604
7605 /*
7606 * Check the memory usage. If it's getting high, trigger a respawn
7607 * after the next job.
7608 */
7609 MemInfo.WorkingSetSize = 0;
7610 if (GetProcessMemoryInfo(GetCurrentProcess(), &MemInfo, sizeof(MemInfo)))
7611 {
7612#if K_ARCH_BITS >= 64
7613 if (MemInfo.WorkingSetSize >= 512*1024*1024)
7614#else
7615 if (MemInfo.WorkingSetSize >= 384*1024*1024)
7616#endif
7617 {
7618 KW_LOG(("WorkingSetSize = %#x - > restart next time.\n", MemInfo.WorkingSetSize));
7619 //fprintf(stderr, "WorkingSetSize = %#x - > restart next time.\n", MemInfo.WorkingSetSize);
7620 g_fRestart = K_TRUE;
7621 }
7622 }
7623}
7624
7625
7626static void kwSandboxCleanup(PKWSANDBOX pSandbox)
7627{
7628 /*
7629 * Restore the parent command line string.
7630 */
7631 PPEB pPeb = kwSandboxGetProcessEnvironmentBlock();
7632 pPeb->ProcessParameters->CommandLine = pSandbox->SavedCommandLine;
7633
7634 /*
7635 * Kill all open handles.
7636 */
7637 if (pSandbox->cActiveHandles > 0)
7638 {
7639 KU32 i = pSandbox->cHandles;
7640 while (i-- > 0)
7641 if (pSandbox->papHandles[i] == NULL)
7642 { /* likely */ }
7643 else
7644 {
7645 PKWHANDLE pHandle = pSandbox->papHandles[i];
7646 pSandbox->papHandles[i] = NULL;
7647 switch (pHandle->enmType)
7648 {
7649 case KWHANDLETYPE_FSOBJ_READ_CACHE:
7650 break;
7651 case KWHANDLETYPE_TEMP_FILE:
7652 case KWHANDLETYPE_TEMP_FILE_MAPPING:
7653 pHandle->u.pTempFile->cActiveHandles--;
7654 break;
7655 default:
7656 kHlpAssertFailed();
7657 }
7658 kHlpFree(pHandle);
7659 if (--pSandbox->cActiveHandles == 0)
7660 break;
7661 }
7662 }
7663}
7664
7665
7666static int kwSandboxExec(PKWSANDBOX pSandbox, PKWTOOL pTool, KU32 cArgs, const char **papszArgs, KBOOL fWatcomBrainDamange,
7667 KU32 cEnvVars, const char **papszEnvVars)
7668{
7669 int rcExit = 42;
7670 int rc;
7671
7672 /*
7673 * Initialize the sandbox environment.
7674 */
7675 rc = kwSandboxInit(&g_Sandbox, pTool, cArgs, papszArgs, fWatcomBrainDamange, cEnvVars, papszEnvVars);
7676 if (rc == 0)
7677 {
7678 /*
7679 * Do module initialization.
7680 */
7681 kwSandboxResetModuleState(pTool->u.Sandboxed.pExe);
7682 rc = kwLdrModuleInitTree(pTool->u.Sandboxed.pExe);
7683 if (rc == 0)
7684 {
7685 /*
7686 * Call the main function.
7687 */
7688#if K_ARCH == K_ARCH_AMD64
7689 int (*pfnWin64Entrypoint)(void *pvPeb, void *, void *, void *);
7690#elif K_ARCH == K_ARCH_X86_32
7691 int (__cdecl *pfnWin32Entrypoint)(void *pvPeb);
7692#else
7693# error "Port me!"
7694#endif
7695
7696 /* Save the NT TIB first (should do that here, not in some other function). */
7697 PNT_TIB pTib = (PNT_TIB)NtCurrentTeb();
7698 pSandbox->TibMainThread = *pTib;
7699
7700 /* Make the call in a guarded fashion. */
7701#if K_ARCH == K_ARCH_AMD64
7702 /* AMD64 */
7703 *(KUPTR *)&pfnWin64Entrypoint = pTool->u.Sandboxed.uMainAddr;
7704 __try
7705 {
7706 pSandbox->pOutXcptListHead = pTib->ExceptionList;
7707 if (setjmp(pSandbox->JmpBuf) == 0)
7708 {
7709 *(KU64*)(pSandbox->JmpBuf) = 0; /** @todo find other way to prevent longjmp from doing unwind! */
7710 pSandbox->fRunning = K_TRUE;
7711 rcExit = pfnWin64Entrypoint(kwSandboxGetProcessEnvironmentBlock(), NULL, NULL, NULL);
7712 pSandbox->fRunning = K_FALSE;
7713 }
7714 else
7715 rcExit = pSandbox->rcExitCode;
7716 }
7717#elif K_ARCH == K_ARCH_X86_32
7718 /* x86 (see _tmainCRTStartup) */
7719 *(KUPTR *)&pfnWin32Entrypoint = 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 = pfnWin32Entrypoint(kwSandboxGetProcessEnvironmentBlock());
7728 pSandbox->fRunning = K_FALSE;
7729 }
7730 else
7731 rcExit = pSandbox->rcExitCode;
7732 }
7733#endif
7734 __except (EXCEPTION_EXECUTE_HANDLER)
7735 {
7736 rcExit = 512;
7737 }
7738 pSandbox->fRunning = K_FALSE;
7739
7740 /* Now, restore the NT TIB. */
7741 *pTib = pSandbox->TibMainThread;
7742 }
7743 else
7744 rcExit = 42 + 4;
7745
7746 /*
7747 * Flush and clean up the essential bits only, postpone whatever we
7748 * can till after we've replied to kmk.
7749 */
7750#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
7751 kwSandboxConsoleFlushAll(&g_Sandbox);
7752#endif
7753 kwSandboxCleanup(&g_Sandbox);
7754 }
7755 else
7756 rcExit = 42 + 3;
7757
7758 return rcExit;
7759}
7760
7761
7762/**
7763 * Does the post command part of a job (optional).
7764 *
7765 * @returns The exit code of the job.
7766 * @param cPostCmdArgs Number of post command arguments (includes cmd).
7767 * @param papszPostCmdArgs The post command and its argument.
7768 */
7769static int kSubmitHandleJobPostCmd(KU32 cPostCmdArgs, const char **papszPostCmdArgs)
7770{
7771 const char *pszCmd = papszPostCmdArgs[0];
7772
7773 /* Allow the kmk builtin prefix. */
7774 static const char s_szKmkBuiltinPrefix[] = "kmk_builtin_";
7775 if (kHlpStrNComp(pszCmd, s_szKmkBuiltinPrefix, sizeof(s_szKmkBuiltinPrefix) - 1) == 0)
7776 pszCmd += sizeof(s_szKmkBuiltinPrefix) - 1;
7777
7778 /* Command switch. */
7779 if (kHlpStrComp(pszCmd, "kDepObj") == 0)
7780 return kmk_builtin_kDepObj(cPostCmdArgs, (char **)papszPostCmdArgs, NULL);
7781
7782 return kwErrPrintfRc(42 + 5 , "Unknown post command: '%s'\n", pszCmd);
7783}
7784
7785
7786/**
7787 * Part 2 of the "JOB" command handler.
7788 *
7789 * @returns The exit code of the job.
7790 * @param pszExecutable The executable to execute.
7791 * @param pszCwd The current working directory of the job.
7792 * @param cArgs The number of arguments.
7793 * @param papszArgs The argument vector.
7794 * @param fWatcomBrainDamange Whether to apply watcom rules while quoting.
7795 * @param cEnvVars The number of environment variables.
7796 * @param papszEnvVars The enviornment vector.
7797 * @param cPostCmdArgs Number of post command arguments (includes cmd).
7798 * @param papszPostCmdArgs The post command and its argument.
7799 */
7800static int kSubmitHandleJobUnpacked(const char *pszExecutable, const char *pszCwd,
7801 KU32 cArgs, const char **papszArgs, KBOOL fWatcomBrainDamange,
7802 KU32 cEnvVars, const char **papszEnvVars,
7803 KU32 cPostCmdArgs, const char **papszPostCmdArgs)
7804{
7805 int rcExit;
7806 PKWTOOL pTool;
7807
7808 /*
7809 * Lookup the tool.
7810 */
7811 pTool = kwToolLookup(pszExecutable);
7812 if (pTool)
7813 {
7814 /*
7815 * Change the directory if we're going to execute the job inside
7816 * this process. Then invoke the tool type specific handler.
7817 */
7818 switch (pTool->enmType)
7819 {
7820 case KWTOOLTYPE_SANDBOXED:
7821 case KWTOOLTYPE_WATCOM:
7822 {
7823 /* Change dir. */
7824 KFSLOOKUPERROR enmError;
7825 PKFSOBJ pNewCurDir = kFsCacheLookupA(g_pFsCache, pszCwd, &enmError);
7826 if ( pNewCurDir == g_pCurDirObj
7827 && pNewCurDir->bObjType == KFSOBJ_TYPE_DIR)
7828 kFsCacheObjRelease(g_pFsCache, pNewCurDir);
7829 else if (SetCurrentDirectoryA(pszCwd))
7830 {
7831 kFsCacheObjRelease(g_pFsCache, g_pCurDirObj);
7832 g_pCurDirObj = pNewCurDir;
7833 }
7834 else
7835 {
7836 kwErrPrintf("SetCurrentDirectory failed with %u on '%s'\n", GetLastError(), pszCwd);
7837 kFsCacheObjRelease(g_pFsCache, pNewCurDir);
7838 rcExit = 42 + 1;
7839 break;
7840 }
7841
7842 /* Call specific handler. */
7843 if (pTool->enmType == KWTOOLTYPE_SANDBOXED)
7844 {
7845 KW_LOG(("Sandboxing tool %s\n", pTool->pszPath));
7846 rcExit = kwSandboxExec(&g_Sandbox, pTool, cArgs, papszArgs, fWatcomBrainDamange, cEnvVars, papszEnvVars);
7847 }
7848 else
7849 {
7850 kwErrPrintf("TODO: Watcom style tool %s\n", pTool->pszPath);
7851 rcExit = 42 + 2;
7852 }
7853 break;
7854 }
7855
7856 case KWTOOLTYPE_EXEC:
7857 kwErrPrintf("TODO: Direct exec tool %s\n", pTool->pszPath);
7858 rcExit = 42 + 2;
7859 break;
7860
7861 default:
7862 kHlpAssertFailed();
7863 kwErrPrintf("Internal tool type corruption!!\n");
7864 rcExit = 42 + 2;
7865 g_fRestart = K_TRUE;
7866 break;
7867 }
7868
7869 /*
7870 * Do the post command, if present.
7871 */
7872 if (cPostCmdArgs && rcExit == 0)
7873 rcExit = kSubmitHandleJobPostCmd(cPostCmdArgs, papszPostCmdArgs);
7874 }
7875 else
7876 rcExit = 42 + 1;
7877 return rcExit;
7878}
7879
7880
7881/**
7882 * Handles a "JOB" command.
7883 *
7884 * @returns The exit code of the job.
7885 * @param pszMsg Points to the "JOB" command part of the message.
7886 * @param cbMsg Number of message bytes at @a pszMsg. There are
7887 * 4 more zero bytes after the message body to
7888 * simplify parsing.
7889 */
7890static int kSubmitHandleJob(const char *pszMsg, KSIZE cbMsg)
7891{
7892 int rcExit = 42;
7893
7894 /*
7895 * Unpack the message.
7896 */
7897 const char *pszExecutable;
7898 KSIZE cbTmp;
7899
7900 pszMsg += sizeof("JOB");
7901 cbMsg -= sizeof("JOB");
7902
7903 /* Executable name. */
7904 pszExecutable = pszMsg;
7905 cbTmp = kHlpStrLen(pszMsg) + 1;
7906 pszMsg += cbTmp;
7907 if ( cbTmp < cbMsg
7908 && cbTmp > 2)
7909 {
7910 const char *pszCwd;
7911 cbMsg -= cbTmp;
7912
7913 /* Current working directory. */
7914 pszCwd = pszMsg;
7915 cbTmp = kHlpStrLen(pszMsg) + 1;
7916 pszMsg += cbTmp;
7917 if ( cbTmp + sizeof(KU32) < cbMsg
7918 && cbTmp >= 2)
7919 {
7920 KU32 cArgs;
7921 cbMsg -= cbTmp;
7922
7923 /* Argument count. */
7924 kHlpMemCopy(&cArgs, pszMsg, sizeof(cArgs));
7925 pszMsg += sizeof(cArgs);
7926 cbMsg -= sizeof(cArgs);
7927
7928 if (cArgs > 0 && cArgs < 4096)
7929 {
7930 /* The argument vector. */
7931 char const **papszArgs = kHlpAlloc((cArgs + 1) * sizeof(papszArgs[0]));
7932 if (papszArgs)
7933 {
7934 KU32 i;
7935 for (i = 0; i < cArgs; i++)
7936 {
7937 papszArgs[i] = pszMsg + 1; /* First byte is expansion flags for MSC & EMX. */
7938 cbTmp = 1 + kHlpStrLen(pszMsg + 1) + 1;
7939 pszMsg += cbTmp;
7940 if (cbTmp < cbMsg)
7941 cbMsg -= cbTmp;
7942 else
7943 {
7944 cbMsg = 0;
7945 break;
7946 }
7947
7948 }
7949 papszArgs[cArgs] = 0;
7950
7951 /* Environment variable count. */
7952 if (cbMsg > sizeof(KU32))
7953 {
7954 KU32 cEnvVars;
7955 kHlpMemCopy(&cEnvVars, pszMsg, sizeof(cEnvVars));
7956 pszMsg += sizeof(cEnvVars);
7957 cbMsg -= sizeof(cEnvVars);
7958
7959 if (cEnvVars >= 0 && cEnvVars < 4096)
7960 {
7961 /* The argument vector. */
7962 char const **papszEnvVars = kHlpAlloc((cEnvVars + 1) * sizeof(papszEnvVars[0]));
7963 if (papszEnvVars)
7964 {
7965 for (i = 0; i < cEnvVars; i++)
7966 {
7967 papszEnvVars[i] = pszMsg;
7968 cbTmp = kHlpStrLen(pszMsg) + 1;
7969 pszMsg += cbTmp;
7970 if (cbTmp < cbMsg)
7971 cbMsg -= cbTmp;
7972 else
7973 {
7974 cbMsg = 0;
7975 break;
7976 }
7977 }
7978 papszEnvVars[cEnvVars] = 0;
7979
7980 /* Flags (currently just watcom argument brain damanage). */
7981 if (cbMsg >= sizeof(KU8))
7982 {
7983 KBOOL fWatcomBrainDamange = *pszMsg++;
7984 cbMsg--;
7985
7986 /* Post command argument count (can be zero). */
7987 if (cbMsg >= sizeof(KU32))
7988 {
7989 KU32 cPostCmdArgs;
7990 kHlpMemCopy(&cPostCmdArgs, pszMsg, sizeof(cPostCmdArgs));
7991 pszMsg += sizeof(cPostCmdArgs);
7992 cbMsg -= sizeof(cPostCmdArgs);
7993
7994 if (cPostCmdArgs >= 0 && cPostCmdArgs < 32)
7995 {
7996 char const *apszPostCmdArgs[32+1];
7997 for (i = 0; i < cPostCmdArgs; i++)
7998 {
7999 apszPostCmdArgs[i] = pszMsg;
8000 cbTmp = kHlpStrLen(pszMsg) + 1;
8001 pszMsg += cbTmp;
8002 if ( cbTmp < cbMsg
8003 || (cbTmp == cbMsg && i + 1 == cPostCmdArgs))
8004 cbMsg -= cbTmp;
8005 else
8006 {
8007 cbMsg = KSIZE_MAX;
8008 break;
8009 }
8010 }
8011 if (cbMsg == 0)
8012 {
8013 apszPostCmdArgs[cPostCmdArgs] = NULL;
8014
8015 /*
8016 * The next step.
8017 */
8018 rcExit = kSubmitHandleJobUnpacked(pszExecutable, pszCwd,
8019 cArgs, papszArgs, fWatcomBrainDamange,
8020 cEnvVars, papszEnvVars,
8021 cPostCmdArgs, apszPostCmdArgs);
8022 }
8023 else if (cbMsg == KSIZE_MAX)
8024 kwErrPrintf("Detected bogus message unpacking post command and its arguments!\n");
8025 else
8026 kwErrPrintf("Message has %u bytes unknown trailing bytes\n", cbMsg);
8027 }
8028 else
8029 kwErrPrintf("Bogus post command argument count: %u %#x\n", cPostCmdArgs, cPostCmdArgs);
8030 }
8031 else
8032 kwErrPrintf("Detected bogus message looking for the post command argument count!\n");
8033 }
8034 else
8035 kwErrPrintf("Detected bogus message unpacking environment variables!\n");
8036 kHlpFree((void *)papszEnvVars);
8037 }
8038 else
8039 kwErrPrintf("Error allocating papszEnvVars for %u variables\n", cEnvVars);
8040 }
8041 else
8042 kwErrPrintf("Bogus environment variable count: %u (%#x)\n", cEnvVars, cEnvVars);
8043 }
8044 else
8045 kwErrPrintf("Detected bogus message unpacking arguments and environment variable count!\n");
8046 kHlpFree((void *)papszArgs);
8047 }
8048 else
8049 kwErrPrintf("Error allocating argv for %u arguments\n", cArgs);
8050 }
8051 else
8052 kwErrPrintf("Bogus argument count: %u (%#x)\n", cArgs, cArgs);
8053 }
8054 else
8055 kwErrPrintf("Detected bogus message unpacking CWD path and argument count!\n");
8056 }
8057 else
8058 kwErrPrintf("Detected bogus message unpacking executable path!\n");
8059 return rcExit;
8060}
8061
8062
8063/**
8064 * Wrapper around WriteFile / write that writes the whole @a cbToWrite.
8065 *
8066 * @retval 0 on success.
8067 * @retval -1 on error (fully bitched).
8068 *
8069 * @param hPipe The pipe handle.
8070 * @param pvBuf The buffer to write out out.
8071 * @param cbToWrite The number of bytes to write.
8072 */
8073static int kSubmitWriteIt(HANDLE hPipe, const void *pvBuf, KU32 cbToWrite)
8074{
8075 KU8 const *pbBuf = (KU8 const *)pvBuf;
8076 KU32 cbLeft = cbToWrite;
8077 for (;;)
8078 {
8079 DWORD cbActuallyWritten = 0;
8080 if (WriteFile(hPipe, pbBuf, cbLeft, &cbActuallyWritten, NULL /*pOverlapped*/))
8081 {
8082 cbLeft -= cbActuallyWritten;
8083 if (!cbLeft)
8084 return 0;
8085 pbBuf += cbActuallyWritten;
8086 }
8087 else
8088 {
8089 DWORD dwErr = GetLastError();
8090 if (cbLeft == cbToWrite)
8091 kwErrPrintf("WriteFile failed: %u\n", dwErr);
8092 else
8093 kwErrPrintf("WriteFile failed %u byte(s) in: %u\n", cbToWrite - cbLeft, dwErr);
8094 return -1;
8095 }
8096 }
8097}
8098
8099
8100/**
8101 * Wrapper around ReadFile / read that reads the whole @a cbToRead.
8102 *
8103 * @retval 0 on success.
8104 * @retval 1 on shut down (fShutdownOkay must be K_TRUE).
8105 * @retval -1 on error (fully bitched).
8106 * @param hPipe The pipe handle.
8107 * @param pvBuf The buffer to read into.
8108 * @param cbToRead The number of bytes to read.
8109 * @param fShutdownOkay Whether connection shutdown while reading the
8110 * first byte is okay or not.
8111 */
8112static int kSubmitReadIt(HANDLE hPipe, void *pvBuf, KU32 cbToRead, KBOOL fMayShutdown)
8113{
8114 KU8 *pbBuf = (KU8 *)pvBuf;
8115 KU32 cbLeft = cbToRead;
8116 for (;;)
8117 {
8118 DWORD cbActuallyRead = 0;
8119 if (ReadFile(hPipe, pbBuf, cbLeft, &cbActuallyRead, NULL /*pOverlapped*/))
8120 {
8121 cbLeft -= cbActuallyRead;
8122 if (!cbLeft)
8123 return 0;
8124 pbBuf += cbActuallyRead;
8125 }
8126 else
8127 {
8128 DWORD dwErr = GetLastError();
8129 if (cbLeft == cbToRead)
8130 {
8131 if ( fMayShutdown
8132 && dwErr == ERROR_BROKEN_PIPE)
8133 return 1;
8134 kwErrPrintf("ReadFile failed: %u\n", dwErr);
8135 }
8136 else
8137 kwErrPrintf("ReadFile failed %u byte(s) in: %u\n", cbToRead - cbLeft, dwErr);
8138 return -1;
8139 }
8140 }
8141}
8142
8143
8144/**
8145 * Handles what comes after --test.
8146 *
8147 * @returns Exit code.
8148 * @param argc Number of arguments after --test.
8149 * @param argv Arguments after --test.
8150 */
8151static int kwTestRun(int argc, char **argv)
8152{
8153 int i;
8154 int j;
8155 int rcExit;
8156 int cRepeats;
8157 char szCwd[MAX_PATH];
8158 const char *pszCwd = getcwd(szCwd, sizeof(szCwd));
8159 KU32 cEnvVars;
8160 KBOOL fWatcomBrainDamange = K_FALSE;
8161
8162 /*
8163 * Parse arguments.
8164 */
8165 /* Repeat count. */
8166 i = 0;
8167 if (i >= argc)
8168 return kwErrPrintfRc(2, "--test takes an repeat count argument or '--'!\n");
8169 if (strcmp(argv[i], "--") != 0)
8170 {
8171 cRepeats = atoi(argv[i]);
8172 if (cRepeats <= 0)
8173 return kwErrPrintfRc(2, "The repeat count '%s' is zero, negative or invalid!\n", argv[i]);
8174 i++;
8175
8176 /* Optional directory change. */
8177 if ( i < argc
8178 && strcmp(argv[i], "--chdir") == 0)
8179 {
8180 i++;
8181 if (i >= argc)
8182 return kwErrPrintfRc(2, "--chdir takes an argument!\n");
8183 pszCwd = argv[i++];
8184 }
8185
8186 /* Optional watcom flag directory change. */
8187 if ( i < argc
8188 && ( strcmp(argv[i], "--wcc-brain-damage") == 0
8189 || strcmp(argv[i], "--watcom-brain-damage") == 0) )
8190 {
8191 fWatcomBrainDamange = K_TRUE;
8192 i++;
8193 }
8194
8195 /* Check for '--'. */
8196 if (i >= argc)
8197 return kwErrPrintfRc(2, "Missing '--'\n");
8198 if (strcmp(argv[i], "--") != 0)
8199 return kwErrPrintfRc(2, "Expected '--' found '%s'\n", argv[i]);
8200 i++;
8201 }
8202 else
8203 {
8204 cRepeats = 1;
8205 i++;
8206 }
8207 if (i >= argc)
8208 return kwErrPrintfRc(2, "Nothing to execute after '--'!\n");
8209
8210 /*
8211 * Do the job.
8212 */
8213 cEnvVars = 0;
8214 while (environ[cEnvVars] != NULL)
8215 cEnvVars++;
8216
8217 for (j = 0; j < cRepeats; j++)
8218 {
8219 rcExit = kSubmitHandleJobUnpacked(argv[i], pszCwd,
8220 argc - i, &argv[i], fWatcomBrainDamange,
8221 cEnvVars, environ,
8222 0, NULL);
8223 KW_LOG(("rcExit=%d\n", rcExit));
8224 kwSandboxCleanupLate(&g_Sandbox);
8225 }
8226
8227 return rcExit;
8228}
8229
8230#if 1
8231
8232int main(int argc, char **argv)
8233{
8234 KSIZE cbMsgBuf = 0;
8235 KU8 *pbMsgBuf = NULL;
8236 int i;
8237 HANDLE hPipe = INVALID_HANDLE_VALUE;
8238 const char *pszTmp;
8239 KFSLOOKUPERROR enmIgnored;
8240#if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_X86)
8241 PVOID pvVecXcptHandler = AddVectoredExceptionHandler(0 /*called last*/, kwSandboxVecXcptEmulateChained);
8242#endif
8243#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
8244 HANDLE hCurProc = GetCurrentProcess();
8245 PPEB pPeb = kwSandboxGetProcessEnvironmentBlock();
8246 PMY_RTL_USER_PROCESS_PARAMETERS pProcessParams = (PMY_RTL_USER_PROCESS_PARAMETERS)pPeb->ProcessParameters;
8247#endif
8248
8249 /*
8250 * Register our Control-C and Control-Break handlers.
8251 */
8252 if (!SetConsoleCtrlHandler(kwSandboxCtrlHandler, TRUE /*fAdd*/))
8253 return kwErrPrintfRc(3, "SetConsoleCtrlHandler failed: %u\n", GetLastError());
8254
8255 /*
8256 * Create the cache and mark the temporary directory as using the custom revision.
8257 */
8258 g_pFsCache = kFsCacheCreate(KFSCACHE_F_MISSING_OBJECTS | KFSCACHE_F_MISSING_PATHS);
8259 if (!g_pFsCache)
8260 return kwErrPrintfRc(3, "kFsCacheCreate failed!\n");
8261
8262 pszTmp = getenv("TEMP");
8263 if (pszTmp && *pszTmp != '\0')
8264 kFsCacheSetupCustomRevisionForTree(g_pFsCache, kFsCacheLookupA(g_pFsCache, pszTmp, &enmIgnored));
8265 pszTmp = getenv("TMP");
8266 if (pszTmp && *pszTmp != '\0')
8267 kFsCacheSetupCustomRevisionForTree(g_pFsCache, kFsCacheLookupA(g_pFsCache, pszTmp, &enmIgnored));
8268 pszTmp = getenv("TMPDIR");
8269 if (pszTmp && *pszTmp != '\0')
8270 kFsCacheSetupCustomRevisionForTree(g_pFsCache, kFsCacheLookupA(g_pFsCache, pszTmp, &enmIgnored));
8271
8272#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
8273 /*
8274 * Get and duplicate the console handles.
8275 */
8276 g_Sandbox.StdOut.hOutput = pProcessParams->StandardOutput;
8277 if (!DuplicateHandle(hCurProc, pProcessParams->StandardOutput, hCurProc, &g_Sandbox.StdOut.hBackup,
8278 GENERIC_WRITE, FALSE /*fInherit*/, DUPLICATE_SAME_ACCESS))
8279 kHlpAssertFailedStmt(g_Sandbox.StdOut.hBackup = pProcessParams->StandardOutput);
8280 g_Sandbox.StdOut.fIsConsole = GetFileType(g_Sandbox.StdOut.hOutput) == FILE_TYPE_CHAR;
8281
8282 g_Sandbox.StdErr.hOutput = pProcessParams->StandardError;
8283 if (!DuplicateHandle(hCurProc, pProcessParams->StandardError, hCurProc, &g_Sandbox.StdErr.hBackup,
8284 GENERIC_WRITE, FALSE /*fInherit*/, DUPLICATE_SAME_ACCESS))
8285 kHlpAssertFailedStmt(g_Sandbox.StdErr.hBackup = pProcessParams->StandardError);
8286 g_Sandbox.StdErr.fIsConsole = GetFileType(g_Sandbox.StdErr.hOutput) == FILE_TYPE_CHAR;
8287
8288 if (g_Sandbox.StdErr.fIsConsole)
8289 {
8290 g_Sandbox.Combined.hOutput = g_Sandbox.StdErr.hBackup;
8291 g_Sandbox.Combined.uCodepage = GetConsoleCP();
8292 }
8293 else if (g_Sandbox.StdOut.fIsConsole)
8294 {
8295 g_Sandbox.Combined.hOutput = g_Sandbox.StdOut.hBackup;
8296 g_Sandbox.Combined.uCodepage = GetConsoleCP();
8297 }
8298 else
8299 {
8300 g_Sandbox.Combined.hOutput = INVALID_HANDLE_VALUE;
8301 g_Sandbox.Combined.uCodepage = CP_ACP;
8302 }
8303#endif
8304
8305
8306 /*
8307 * Parse arguments.
8308 */
8309 for (i = 1; i < argc; i++)
8310 {
8311 if (strcmp(argv[i], "--pipe") == 0)
8312 {
8313 i++;
8314 if (i < argc)
8315 {
8316 char *pszEnd = NULL;
8317 unsigned __int64 u64Value = _strtoui64(argv[i], &pszEnd, 16);
8318 if ( *argv[i]
8319 && pszEnd != NULL
8320 && *pszEnd == '\0'
8321 && u64Value != 0
8322 && u64Value != (uintptr_t)INVALID_HANDLE_VALUE
8323 && (uintptr_t)u64Value == u64Value)
8324 hPipe = (HANDLE)(uintptr_t)u64Value;
8325 else
8326 return kwErrPrintfRc(2, "Invalid --pipe argument: %s\n", argv[i]);
8327 }
8328 else
8329 return kwErrPrintfRc(2, "--pipe takes an argument!\n");
8330 }
8331 else if (strcmp(argv[i], "--volatile") == 0)
8332 {
8333 i++;
8334 if (i < argc)
8335 kFsCacheSetupCustomRevisionForTree(g_pFsCache, kFsCacheLookupA(g_pFsCache, argv[i], &enmIgnored));
8336 else
8337 return kwErrPrintfRc(2, "--volatile takes an argument!\n");
8338 }
8339 else if (strcmp(argv[i], "--test") == 0)
8340 return kwTestRun(argc - i - 1, &argv[i + 1]);
8341 else if ( strcmp(argv[i], "--help") == 0
8342 || strcmp(argv[i], "-h") == 0
8343 || strcmp(argv[i], "-?") == 0)
8344 {
8345 printf("usage: kWorker [--volatile dir] --pipe <pipe-handle>\n"
8346 "usage: kWorker <--help|-h>\n"
8347 "usage: kWorker <--version|-V>\n"
8348 "usage: kWorker [--volatile dir] --test [<times> [--chdir <dir>]] -- args\n"
8349 "\n"
8350 "This is an internal kmk program that is used via the builtin_kSubmit.\n");
8351 return 0;
8352 }
8353 else if ( strcmp(argv[i], "--version") == 0
8354 || strcmp(argv[i], "-V") == 0)
8355 return kbuild_version(argv[0]);
8356 else
8357 return kwErrPrintfRc(2, "Unknown argument '%s'\n", argv[i]);
8358 }
8359
8360 if (hPipe == INVALID_HANDLE_VALUE)
8361 return kwErrPrintfRc(2, "Missing --pipe <pipe-handle> argument!\n");
8362
8363 /*
8364 * Serve the pipe.
8365 */
8366 for (;;)
8367 {
8368 KU32 cbMsg = 0;
8369 int rc = kSubmitReadIt(hPipe, &cbMsg, sizeof(cbMsg), K_TRUE /*fShutdownOkay*/);
8370 if (rc == 0)
8371 {
8372 /* Make sure the message length is within sane bounds. */
8373 if ( cbMsg > 4
8374 && cbMsg <= 256*1024*1024)
8375 {
8376 /* Reallocate the message buffer if necessary. We add 4 zero bytes. */
8377 if (cbMsg + 4 <= cbMsgBuf)
8378 { /* likely */ }
8379 else
8380 {
8381 cbMsgBuf = K_ALIGN_Z(cbMsg + 4, 2048);
8382 pbMsgBuf = kHlpRealloc(pbMsgBuf, cbMsgBuf);
8383 if (!pbMsgBuf)
8384 return kwErrPrintfRc(1, "Failed to allocate %u bytes for a message buffer!\n", cbMsgBuf);
8385 }
8386
8387 /* Read the whole message into the buffer, making sure there is are a 4 zero bytes following it. */
8388 *(KU32 *)pbMsgBuf = cbMsg;
8389 rc = kSubmitReadIt(hPipe, &pbMsgBuf[sizeof(cbMsg)], cbMsg - sizeof(cbMsg), K_FALSE /*fShutdownOkay*/);
8390 if (rc == 0)
8391 {
8392 const char *psz;
8393
8394 pbMsgBuf[cbMsg] = '\0';
8395 pbMsgBuf[cbMsg + 1] = '\0';
8396 pbMsgBuf[cbMsg + 2] = '\0';
8397 pbMsgBuf[cbMsg + 3] = '\0';
8398
8399 /* The first string after the header is the command. */
8400 psz = (const char *)&pbMsgBuf[sizeof(cbMsg)];
8401 if (strcmp(psz, "JOB") == 0)
8402 {
8403 struct
8404 {
8405 KI32 rcExitCode;
8406 KU8 bExiting;
8407 KU8 abZero[3];
8408 } Reply;
8409 Reply.rcExitCode = kSubmitHandleJob(psz, cbMsg - sizeof(cbMsg));
8410 Reply.bExiting = g_fRestart;
8411 Reply.abZero[0] = 0;
8412 Reply.abZero[1] = 0;
8413 Reply.abZero[2] = 0;
8414 rc = kSubmitWriteIt(hPipe, &Reply, sizeof(Reply));
8415 if ( rc == 0
8416 && !g_fRestart)
8417 {
8418 kwSandboxCleanupLate(&g_Sandbox);
8419 continue;
8420 }
8421 }
8422 else
8423 rc = kwErrPrintfRc(-1, "Unknown command: '%s'\n", psz);
8424 }
8425 }
8426 else
8427 rc = kwErrPrintfRc(-1, "Bogus message length: %u (%#x)\n", cbMsg, cbMsg);
8428 }
8429
8430 /*
8431 * If we're exitting because we're restarting, we need to delay till
8432 * kmk/kSubmit has read the result. Windows documentation says it
8433 * immediately discards pipe buffers once the pipe is broken by the
8434 * server (us). So, We flush the buffer and queues a 1 byte read
8435 * waiting for kSubmit to close the pipe when it receives the
8436 * bExiting = K_TRUE result.
8437 */
8438 if (g_fRestart)
8439 {
8440 KU8 b;
8441 FlushFileBuffers(hPipe);
8442 ReadFile(hPipe, &b, 1, &cbMsg, NULL);
8443 }
8444
8445 CloseHandle(hPipe);
8446 return rc > 0 ? 0 : 1;
8447 }
8448}
8449
8450#else
8451
8452static int kwExecCmdLine(const char *pszExe, const char *pszCmdLine)
8453{
8454 int rc;
8455 PKWTOOL pTool = kwToolLookup(pszExe);
8456 if (pTool)
8457 {
8458 int rcExitCode;
8459 switch (pTool->enmType)
8460 {
8461 case KWTOOLTYPE_SANDBOXED:
8462 KW_LOG(("Sandboxing tool %s\n", pTool->pszPath));
8463 rc = kwSandboxExec(&g_Sandbox, pTool, pszCmdLine, &rcExitCode);
8464 break;
8465 default:
8466 kHlpAssertFailed();
8467 KW_LOG(("TODO: Direct exec tool %s\n", pTool->pszPath));
8468 rc = rcExitCode = 2;
8469 break;
8470 }
8471 KW_LOG(("rcExitCode=%d (rc=%d)\n", rcExitCode, rc));
8472 }
8473 else
8474 rc = 1;
8475 return rc;
8476}
8477
8478int main(int argc, char **argv)
8479{
8480 int rc = 0;
8481 int i;
8482 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";
8483# if 0
8484 rc = kwExecCmdLine(argv[1], argv[2]);
8485 rc = kwExecCmdLine(argv[1], argv[2]);
8486 K_NOREF(i);
8487# else
8488// Skylake (W10/amd64, only stdandard MS defender):
8489// cmd 1: 48 /1024 = 0x0 (0.046875) [for /l %i in (1,1,1024) do ...]
8490// kmk 1: 44 /1024 = 0x0 (0.04296875) [all: ; 1024 x cl.exe]
8491// run 1: 37 /1024 = 0x0 (0.0361328125) [just process creation gain]
8492// run 2: 34 /1024 = 0x0 (0.033203125) [get file attribs]
8493// run 3: 32.77 /1024 = 0x0 (0.032001953125) [read caching of headers]
8494// run 4: 32.67 /1024 = 0x0 (0.031904296875) [loader tweaking]
8495// run 5: 29.144/1024 = 0x0 (0.0284609375) [with temp files in memory]
8496// r2881 building src/VBox/Runtime:
8497// without: 2m01.016388s = 120.016388 s
8498// with: 1m15.165069s = 75.165069 s => 120.016388s - 75.165069s = 44.851319s => 44.85/120.02 = 37% speed up.
8499// r2884 building vbox/debug (r110512):
8500// without: 11m14.446609s = 674.446609 s
8501// with: 9m01.017344s = 541.017344 s => 674.446609s - 541.017344s = 133.429265 => 133.43/674.45 = 19% speed up
8502// r2896 building vbox/debug (r110577):
8503// with: 8m31.182384s = 511.182384 s => 674.446609s - 511.182384s = 163.264225 = 163.26/674.45 = 24% speed up
8504//
8505// Dell (W7/amd64, infected by mcafee):
8506// kmk 1: 285.278/1024 = 0x0 (0.278591796875)
8507// run 1: 134.503/1024 = 0x0 (0.1313505859375) [w/o temp files in memory]
8508// run 2: 78.161/1024 = 0x0 (0.0763291015625) [with temp files in memory]
8509 g_cVerbose = 0;
8510 for (i = 0; i < 1024 && rc == 0; i++)
8511 rc = kwExecCmdLine(argv[1], argv[2]);
8512# endif
8513 return rc;
8514}
8515
8516#endif
8517
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