VirtualBox

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

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

updates

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