VirtualBox

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

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

numbers

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