VirtualBox

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

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

Made 32-bit kWorker work.

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