VirtualBox

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

Last change on this file since 2836 was 2836, checked in by bird, 9 years ago

kWorker: More hacking to prevent the temporary _CL_xxxxxxyy files from C1.dll from hitting the disk. Storing them in memory.

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