VirtualBox

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

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

kWorker: hacked up MD5 hash caching on header files we keep in memory already.

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