VirtualBox

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

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

fixes

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