VirtualBox

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

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

x86 exception dispatching.

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