VirtualBox

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

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

restart when we've leaked a lot of memory (this won't ever be perfect).

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