VirtualBox

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

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

ctrl-c + assembly headers

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