VirtualBox

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

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

kSubmit/kWorker: updates

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 184.8 KB
Line 
1/* $Id: kWorker.c 2844 2016-08-29 16:31: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
3818 kHlpMemCopy(pvBuffer, &pFsObj->pbCached[pHandle->offFile], cbActually);
3819 pHandle->offFile += cbActually;
3820
3821 kHlpAssert(!pOverlapped); kHlpAssert(pcbActuallyRead);
3822 *pcbActuallyRead = cbActually;
3823
3824 KWFS_LOG(("ReadFile(%p,,%#x) -> TRUE, %#x bytes [cached]\n", hFile, cbToRead, cbActually));
3825 return TRUE;
3826 }
3827
3828#ifdef WITH_TEMP_MEMORY_FILES
3829 case KWHANDLETYPE_TEMP_FILE:
3830 {
3831 PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile;
3832 KU32 cbActually;
3833 if (pHandle->offFile < pTempFile->cbFile)
3834 {
3835 cbActually = pTempFile->cbFile - pHandle->offFile;
3836 if (cbActually > cbToRead)
3837 cbActually = cbToRead;
3838
3839 /* Copy the data. */
3840 if (cbActually > 0)
3841 {
3842 KU32 cbLeft;
3843 KU32 offSeg;
3844 KWFSTEMPFILESEG const *paSegs = pTempFile->paSegs;
3845
3846 /* Locate the segment containing the byte at offFile. */
3847 KU32 iSeg = pTempFile->cSegs - 1;
3848 kHlpAssert(pTempFile->cSegs > 0);
3849 while (paSegs[iSeg].offData > pHandle->offFile)
3850 iSeg--;
3851
3852 /* Copy out the data. */
3853 cbLeft = cbActually;
3854 offSeg = (pHandle->offFile - paSegs[iSeg].offData);
3855 for (;;)
3856 {
3857 KU32 cbAvail = paSegs[iSeg].cbDataAlloc - offSeg;
3858 if (cbAvail >= cbLeft)
3859 {
3860 kHlpMemCopy(pvBuffer, &paSegs[iSeg].pbData[offSeg], cbLeft);
3861 break;
3862 }
3863
3864 pvBuffer = kHlpMemPCopy(pvBuffer, &paSegs[iSeg].pbData[offSeg], cbAvail);
3865 cbLeft -= cbAvail;
3866 offSeg = 0;
3867 iSeg++;
3868 kHlpAssert(iSeg < pTempFile->cSegs);
3869 }
3870
3871 /* Update the file offset. */
3872 pHandle->offFile += cbActually;
3873 }
3874 }
3875 /* Read does not commit file space, so return zero bytes. */
3876 else
3877 cbActually = 0;
3878
3879 kHlpAssert(!pOverlapped); kHlpAssert(pcbActuallyRead);
3880 *pcbActuallyRead = cbActually;
3881
3882 KWFS_LOG(("ReadFile(%p,,%#x) -> TRUE, %#x bytes [temp]\n", hFile, cbToRead, (KU32)cbActually));
3883 return TRUE;
3884 }
3885
3886 case KWHANDLETYPE_TEMP_FILE_MAPPING:
3887#endif /* WITH_TEMP_MEMORY_FILES */
3888 default:
3889 kHlpAssertFailed();
3890 SetLastError(ERROR_INVALID_FUNCTION);
3891 *pcbActuallyRead = 0;
3892 return FALSE;
3893 }
3894 }
3895 }
3896
3897 KWFS_LOG(("ReadFile(%p)\n", hFile));
3898 return ReadFile(hFile, pvBuffer, cbToRead, pcbActuallyRead, pOverlapped);
3899}
3900
3901
3902/** Kernel32 - ReadFileEx */
3903static BOOL WINAPI kwSandbox_Kernel32_ReadFileEx(HANDLE hFile, LPVOID pvBuffer, DWORD cbToRead, LPOVERLAPPED pOverlapped,
3904 LPOVERLAPPED_COMPLETION_ROUTINE pfnCompletionRoutine)
3905{
3906 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
3907 if (idxHandle < g_Sandbox.cHandles)
3908 {
3909 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
3910 if (pHandle != NULL)
3911 {
3912 kHlpAssertFailed();
3913 }
3914 }
3915
3916 KWFS_LOG(("ReadFile(%p)\n", hFile));
3917 return ReadFileEx(hFile, pvBuffer, cbToRead, pOverlapped, pfnCompletionRoutine);
3918}
3919
3920#ifdef WITH_TEMP_MEMORY_FILES
3921
3922static KBOOL kwFsTempFileEnsureSpace(PKWFSTEMPFILE pTempFile, KU32 offFile, KU32 cbNeeded)
3923{
3924 KU32 cbMinFile = offFile + cbNeeded;
3925 if (cbMinFile >= offFile)
3926 {
3927 /* Calc how much space we've already allocated and */
3928 if (cbMinFile <= pTempFile->cbFileAllocated)
3929 return K_TRUE;
3930
3931 /* Grow the file. */
3932 if (cbMinFile <= KWFS_TEMP_FILE_MAX)
3933 {
3934 int rc;
3935 KU32 cSegs = pTempFile->cSegs;
3936 KU32 cbNewSeg = cbMinFile > 4*1024*1024 ? 256*1024 : 4*1024*1024;
3937 do
3938 {
3939 /* grow the segment array? */
3940 if ((cSegs % 16) == 0)
3941 {
3942 void *pvNew = kHlpRealloc(pTempFile->paSegs, (cSegs + 16) * sizeof(pTempFile->paSegs[0]));
3943 if (!pvNew)
3944 return K_FALSE;
3945 pTempFile->paSegs = (PKWFSTEMPFILESEG)pvNew;
3946 }
3947
3948 /* Use page alloc here to simplify mapping later. */
3949 rc = kHlpPageAlloc((void **)&pTempFile->paSegs[cSegs].pbData, cbNewSeg, KPROT_READWRITE, K_FALSE);
3950 if (rc == 0)
3951 { /* likely */ }
3952 else
3953 {
3954 cbNewSeg = 64*1024*1024;
3955 rc = kHlpPageAlloc((void **)&pTempFile->paSegs[cSegs].pbData, cbNewSeg, KPROT_READWRITE, K_FALSE);
3956 if (rc != 0)
3957 return K_FALSE;
3958 }
3959 pTempFile->paSegs[cSegs].offData = pTempFile->cbFileAllocated;
3960 pTempFile->paSegs[cSegs].cbDataAlloc = cbNewSeg;
3961 pTempFile->cbFileAllocated += cbNewSeg;
3962 pTempFile->cSegs = ++cSegs;
3963
3964 } while (pTempFile->cbFileAllocated < cbMinFile);
3965
3966 return K_TRUE;
3967 }
3968 }
3969
3970 kHlpAssertMsgFailed(("Out of bounds offFile=%#x + cbNeeded=%#x = %#x\n", offFile, cbNeeded, offFile + cbNeeded));
3971 return K_FALSE;
3972}
3973
3974
3975/** Kernel32 - WriteFile */
3976static BOOL WINAPI kwSandbox_Kernel32_WriteFile(HANDLE hFile, LPCVOID pvBuffer, DWORD cbToWrite, LPDWORD pcbActuallyWritten,
3977 LPOVERLAPPED pOverlapped)
3978{
3979 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
3980 if (idxHandle < g_Sandbox.cHandles)
3981 {
3982 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
3983 if (pHandle != NULL)
3984 {
3985 switch (pHandle->enmType)
3986 {
3987 case KWHANDLETYPE_TEMP_FILE:
3988 {
3989 PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile;
3990
3991 kHlpAssert(!pOverlapped);
3992 kHlpAssert(pcbActuallyWritten);
3993
3994 if (kwFsTempFileEnsureSpace(pTempFile, pHandle->offFile, cbToWrite))
3995 {
3996 KU32 cbLeft;
3997 KU32 offSeg;
3998
3999 /* Locate the segment containing the byte at offFile. */
4000 KWFSTEMPFILESEG const *paSegs = pTempFile->paSegs;
4001 KU32 iSeg = pTempFile->cSegs - 1;
4002 kHlpAssert(pTempFile->cSegs > 0);
4003 while (paSegs[iSeg].offData > pHandle->offFile)
4004 iSeg--;
4005
4006 /* Copy in the data. */
4007 cbLeft = cbToWrite;
4008 offSeg = (pHandle->offFile - paSegs[iSeg].offData);
4009 for (;;)
4010 {
4011 KU32 cbAvail = paSegs[iSeg].cbDataAlloc - offSeg;
4012 if (cbAvail >= cbLeft)
4013 {
4014 kHlpMemCopy(&paSegs[iSeg].pbData[offSeg], pvBuffer, cbLeft);
4015 break;
4016 }
4017
4018 kHlpMemCopy(&paSegs[iSeg].pbData[offSeg], pvBuffer, cbAvail);
4019 pvBuffer = (KU8 const *)pvBuffer + cbAvail;
4020 cbLeft -= cbAvail;
4021 offSeg = 0;
4022 iSeg++;
4023 kHlpAssert(iSeg < pTempFile->cSegs);
4024 }
4025
4026 /* Update the file offset. */
4027 pHandle->offFile += cbToWrite;
4028 if (pHandle->offFile > pTempFile->cbFile)
4029 pTempFile->cbFile = pHandle->offFile;
4030
4031 *pcbActuallyWritten = cbToWrite;
4032 KWFS_LOG(("WriteFile(%p,,%#x) -> TRUE [temp]\n", hFile, cbToWrite));
4033 return TRUE;
4034 }
4035
4036 *pcbActuallyWritten = 0;
4037 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4038 return FALSE;
4039 }
4040
4041 case KWHANDLETYPE_FSOBJ_READ_CACHE:
4042 kHlpAssertFailed();
4043 SetLastError(ERROR_ACCESS_DENIED);
4044 *pcbActuallyWritten = 0;
4045 return FALSE;
4046
4047 default:
4048 case KWHANDLETYPE_TEMP_FILE_MAPPING:
4049 kHlpAssertFailed();
4050 SetLastError(ERROR_INVALID_FUNCTION);
4051 *pcbActuallyWritten = 0;
4052 return FALSE;
4053 }
4054 }
4055 }
4056
4057 KWFS_LOG(("WriteFile(%p)\n", hFile));
4058 return WriteFile(hFile, pvBuffer, cbToWrite, pcbActuallyWritten, pOverlapped);
4059}
4060
4061
4062/** Kernel32 - WriteFileEx */
4063static BOOL WINAPI kwSandbox_Kernel32_WriteFileEx(HANDLE hFile, LPCVOID pvBuffer, DWORD cbToWrite, LPOVERLAPPED pOverlapped,
4064 LPOVERLAPPED_COMPLETION_ROUTINE pfnCompletionRoutine)
4065{
4066 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
4067 if (idxHandle < g_Sandbox.cHandles)
4068 {
4069 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
4070 if (pHandle != NULL)
4071 {
4072 kHlpAssertFailed();
4073 }
4074 }
4075
4076 KWFS_LOG(("WriteFileEx(%p)\n", hFile));
4077 return WriteFileEx(hFile, pvBuffer, cbToWrite, pOverlapped, pfnCompletionRoutine);
4078}
4079
4080
4081/** Kernel32 - SetEndOfFile; */
4082static BOOL WINAPI kwSandbox_Kernel32_SetEndOfFile(HANDLE hFile)
4083{
4084 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
4085 if (idxHandle < g_Sandbox.cHandles)
4086 {
4087 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
4088 if (pHandle != NULL)
4089 {
4090 switch (pHandle->enmType)
4091 {
4092 case KWHANDLETYPE_TEMP_FILE:
4093 {
4094 PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile;
4095 if ( pHandle->offFile > pTempFile->cbFile
4096 && !kwFsTempFileEnsureSpace(pTempFile, pHandle->offFile, 0))
4097 {
4098 kHlpAssertFailed();
4099 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4100 return FALSE;
4101 }
4102
4103 pTempFile->cbFile = pHandle->offFile;
4104 KWFS_LOG(("SetEndOfFile(%p) -> TRUE (cbFile=%#x)\n", hFile, pTempFile->cbFile));
4105 return TRUE;
4106 }
4107
4108 case KWHANDLETYPE_FSOBJ_READ_CACHE:
4109 kHlpAssertFailed();
4110 SetLastError(ERROR_ACCESS_DENIED);
4111 return FALSE;
4112
4113 default:
4114 case KWHANDLETYPE_TEMP_FILE_MAPPING:
4115 kHlpAssertFailed();
4116 SetLastError(ERROR_INVALID_FUNCTION);
4117 return FALSE;
4118 }
4119 }
4120 }
4121
4122 KWFS_LOG(("SetEndOfFile(%p)\n", hFile));
4123 return SetEndOfFile(hFile);
4124}
4125
4126
4127/** Kernel32 - GetFileType */
4128static BOOL WINAPI kwSandbox_Kernel32_GetFileType(HANDLE hFile)
4129{
4130 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
4131 if (idxHandle < g_Sandbox.cHandles)
4132 {
4133 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
4134 if (pHandle != NULL)
4135 {
4136 switch (pHandle->enmType)
4137 {
4138 case KWHANDLETYPE_FSOBJ_READ_CACHE:
4139 KWFS_LOG(("GetFileType(%p) -> FILE_TYPE_DISK [cached]\n", hFile));
4140 return FILE_TYPE_DISK;
4141
4142 case KWHANDLETYPE_TEMP_FILE:
4143 KWFS_LOG(("GetFileType(%p) -> FILE_TYPE_DISK [temp]\n", hFile));
4144 return FILE_TYPE_DISK;
4145 }
4146 }
4147 }
4148
4149 KWFS_LOG(("GetFileType(%p)\n", hFile));
4150 return GetFileType(hFile);
4151}
4152
4153
4154/** Kernel32 - GetFileSize */
4155static DWORD WINAPI kwSandbox_Kernel32_GetFileSize(HANDLE hFile, LPDWORD pcbHighDword)
4156{
4157 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
4158 if (idxHandle < g_Sandbox.cHandles)
4159 {
4160 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
4161 if (pHandle != NULL)
4162 {
4163 if (pcbHighDword)
4164 *pcbHighDword = 0;
4165 SetLastError(NO_ERROR);
4166 switch (pHandle->enmType)
4167 {
4168 case KWHANDLETYPE_FSOBJ_READ_CACHE:
4169 KWFS_LOG(("GetFileSize(%p) -> %#x [cached]\n", hFile, pHandle->u.pFsObj->cbCached));
4170 return pHandle->u.pFsObj->cbCached;
4171
4172 case KWHANDLETYPE_TEMP_FILE:
4173 KWFS_LOG(("GetFileSize(%p) -> %#x [temp]\n", hFile, pHandle->u.pTempFile->cbFile));
4174 return pHandle->u.pTempFile->cbFile;
4175
4176 default:
4177 kHlpAssertFailed();
4178 SetLastError(ERROR_INVALID_FUNCTION);
4179 return INVALID_FILE_SIZE;
4180 }
4181 }
4182 }
4183
4184 KWFS_LOG(("GetFileSize(%p,)\n", hFile));
4185 return GetFileSize(hFile, pcbHighDword);
4186}
4187
4188
4189/** Kernel32 - GetFileSizeEx */
4190static BOOL WINAPI kwSandbox_Kernel32_GetFileSizeEx(HANDLE hFile, PLARGE_INTEGER pcbFile)
4191{
4192 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
4193 if (idxHandle < g_Sandbox.cHandles)
4194 {
4195 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
4196 if (pHandle != NULL)
4197 {
4198 switch (pHandle->enmType)
4199 {
4200 case KWHANDLETYPE_FSOBJ_READ_CACHE:
4201 KWFS_LOG(("GetFileSizeEx(%p) -> TRUE, %#x [cached]\n", hFile, pHandle->u.pFsObj->cbCached));
4202 pcbFile->QuadPart = pHandle->u.pFsObj->cbCached;
4203 return TRUE;
4204
4205 case KWHANDLETYPE_TEMP_FILE:
4206 KWFS_LOG(("GetFileSizeEx(%p) -> TRUE, %#x [temp]\n", hFile, pHandle->u.pTempFile->cbFile));
4207 pcbFile->QuadPart = pHandle->u.pTempFile->cbFile;
4208 return TRUE;
4209
4210 default:
4211 kHlpAssertFailed();
4212 SetLastError(ERROR_INVALID_FUNCTION);
4213 return INVALID_FILE_SIZE;
4214 }
4215 }
4216 }
4217
4218 KWFS_LOG(("GetFileSizeEx(%p,)\n", hFile));
4219 return GetFileSizeEx(hFile, pcbFile);
4220}
4221
4222
4223/** Kernel32 - CreateFileMapping */
4224static HANDLE WINAPI kwSandbox_Kernel32_CreateFileMappingW(HANDLE hFile, LPSECURITY_ATTRIBUTES pSecAttrs,
4225 DWORD fProtect, DWORD dwMaximumSizeHigh,
4226 DWORD dwMaximumSizeLow, LPCWSTR pwszName)
4227{
4228 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
4229 if (idxHandle < g_Sandbox.cHandles)
4230 {
4231 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
4232 if (pHandle != NULL)
4233 {
4234 switch (pHandle->enmType)
4235 {
4236 case KWHANDLETYPE_TEMP_FILE:
4237 {
4238 PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile;
4239 if ( ( fProtect == PAGE_READONLY
4240 || fProtect == PAGE_EXECUTE_READ)
4241 && dwMaximumSizeHigh == 0
4242 && ( dwMaximumSizeLow == 0
4243 || dwMaximumSizeLow == pTempFile->cbFile)
4244 && pwszName == NULL)
4245 {
4246 HANDLE hMapping = kwFsTempFileCreateHandle(pHandle->u.pTempFile, GENERIC_READ, K_TRUE /*fMapping*/);
4247 KWFS_LOG(("CreateFileMappingW(%p, %u) -> %p [temp]\n", hFile, fProtect, hMapping));
4248 return hMapping;
4249 }
4250 kHlpAssertMsgFailed(("fProtect=%#x cb=%#x'%08x name=%p\n",
4251 fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName));
4252 SetLastError(ERROR_ACCESS_DENIED);
4253 return INVALID_HANDLE_VALUE;
4254 }
4255 }
4256 }
4257 }
4258
4259 KWFS_LOG(("CreateFileMappingW(%p)\n", hFile));
4260 return CreateFileMappingW(hFile, pSecAttrs, fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName);
4261}
4262
4263/** Kernel32 - MapViewOfFile */
4264static HANDLE WINAPI kwSandbox_Kernel32_MapViewOfFile(HANDLE hSection, DWORD dwDesiredAccess,
4265 DWORD offFileHigh, DWORD offFileLow, SIZE_T cbToMap)
4266{
4267 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hSection);
4268 if (idxHandle < g_Sandbox.cHandles)
4269 {
4270 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
4271 if (pHandle != NULL)
4272 {
4273 switch (pHandle->enmType)
4274 {
4275 case KWHANDLETYPE_FSOBJ_READ_CACHE:
4276 case KWHANDLETYPE_TEMP_FILE:
4277 kHlpAssertFailed();
4278 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4279 return NULL;
4280
4281 case KWHANDLETYPE_TEMP_FILE_MAPPING:
4282 {
4283 PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile;
4284 if ( dwDesiredAccess == FILE_MAP_READ
4285 && offFileHigh == 0
4286 && offFileLow == 0
4287 && (cbToMap == 0 || cbToMap == pTempFile->cbFile) )
4288 {
4289 kHlpAssert(pTempFile->cMappings == 0 || pTempFile->cSegs == 1);
4290 if (pTempFile->cSegs != 1)
4291 {
4292 KU32 iSeg;
4293 KU32 cbLeft;
4294 KU32 cbAll = pTempFile->cbFile ? (KU32)K_ALIGN_Z(pTempFile->cbFile, 0x2000) : 0x1000;
4295 KU8 *pbAll = NULL;
4296 int rc = kHlpPageAlloc((void **)&pbAll, cbAll, KPROT_READWRITE, K_FALSE);
4297 if (rc != 0)
4298 {
4299 kHlpAssertFailed();
4300 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4301 return NULL;
4302 }
4303
4304 cbLeft = pTempFile->cbFile;
4305 for (iSeg = 0; iSeg < pTempFile->cSegs && cbLeft > 0; iSeg++)
4306 {
4307 KU32 cbToCopy = K_MIN(cbLeft, pTempFile->paSegs[iSeg].cbDataAlloc);
4308 kHlpMemCopy(&pbAll[pTempFile->paSegs[iSeg].offData], pTempFile->paSegs[iSeg].pbData, cbToCopy);
4309 cbLeft -= cbToCopy;
4310 }
4311
4312 for (iSeg = 0; iSeg < pTempFile->cSegs; iSeg++)
4313 {
4314 kHlpPageFree(pTempFile->paSegs[iSeg].pbData, pTempFile->paSegs[iSeg].cbDataAlloc);
4315 pTempFile->paSegs[iSeg].pbData = NULL;
4316 pTempFile->paSegs[iSeg].cbDataAlloc = 0;
4317 }
4318
4319 pTempFile->cSegs = 1;
4320 pTempFile->cbFileAllocated = cbAll;
4321 pTempFile->paSegs[0].cbDataAlloc = cbAll;
4322 pTempFile->paSegs[0].pbData = pbAll;
4323 pTempFile->paSegs[0].offData = 0;
4324 }
4325
4326 pTempFile->cMappings++;
4327 kHlpAssert(pTempFile->cMappings == 1);
4328
4329 KWFS_LOG(("CreateFileMappingW(%p) -> %p [temp]\n", hSection, pTempFile->paSegs[0].pbData));
4330 return pTempFile->paSegs[0].pbData;
4331 }
4332
4333 kHlpAssertMsgFailed(("dwDesiredAccess=%#x offFile=%#x'%08x cbToMap=%#x (cbFile=%#x)\n",
4334 dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pTempFile->cbFile));
4335 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4336 return NULL;
4337 }
4338 }
4339 }
4340 }
4341
4342 KWFS_LOG(("MapViewOfFile(%p)\n", hSection));
4343 return MapViewOfFile(hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap);
4344}
4345/** @todo MapViewOfFileEx */
4346
4347
4348/** Kernel32 - UnmapViewOfFile */
4349static BOOL WINAPI kwSandbox_Kernel32_UnmapViewOfFile(LPCVOID pvBase)
4350{
4351 /* Is this one of our temporary mappings? */
4352 PKWFSTEMPFILE pCur = g_Sandbox.pTempFileHead;
4353 while (pCur)
4354 {
4355 if ( pCur->cMappings > 0
4356 && pCur->paSegs[0].pbData == (KU8 *)pvBase)
4357 {
4358 pCur->cMappings--;
4359 KWFS_LOG(("UnmapViewOfFile(%p) -> TRUE [temp]\n", pvBase));
4360 return TRUE;
4361 }
4362 pCur = pCur->pNext;
4363 }
4364
4365 KWFS_LOG(("UnmapViewOfFile(%p)\n", pvBase));
4366 return UnmapViewOfFile(pvBase);
4367}
4368
4369/** @todo UnmapViewOfFileEx */
4370
4371
4372#endif /* WITH_TEMP_MEMORY_FILES */
4373
4374/** Kernel32 - CloseHandle */
4375static BOOL WINAPI kwSandbox_Kernel32_CloseHandle(HANDLE hObject)
4376{
4377 BOOL fRet;
4378 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hObject);
4379 if ( idxHandle < g_Sandbox.cHandles
4380 && g_Sandbox.papHandles[idxHandle] != NULL)
4381 {
4382 fRet = CloseHandle(hObject);
4383 if (fRet)
4384 {
4385 PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
4386 g_Sandbox.papHandles[idxHandle] = NULL;
4387 g_Sandbox.cActiveHandles--;
4388#ifdef WITH_TEMP_MEMORY_FILES
4389 if (pHandle->enmType == KWHANDLETYPE_TEMP_FILE)
4390 {
4391 kHlpAssert(pHandle->u.pTempFile->cActiveHandles > 0);
4392 pHandle->u.pTempFile->cActiveHandles--;
4393 }
4394#endif
4395 kHlpFree(pHandle);
4396 KWFS_LOG(("CloseHandle(%p) -> TRUE [intercepted handle]\n", hObject));
4397 }
4398 else
4399 KWFS_LOG(("CloseHandle(%p) -> FALSE [intercepted handle] err=%u!\n", hObject, GetLastError()));
4400 }
4401 else
4402 {
4403 KWFS_LOG(("CloseHandle(%p)\n", hObject));
4404 fRet = CloseHandle(hObject);
4405 }
4406 return fRet;
4407}
4408
4409
4410/** Kernel32 - GetFileAttributesA. */
4411static DWORD WINAPI kwSandbox_Kernel32_GetFileAttributesA(LPCSTR pszFilename)
4412{
4413 DWORD fRet;
4414 const char *pszExt = kHlpGetExt(pszFilename);
4415 if (kwFsIsCachableExtensionA(pszExt, K_TRUE /*fAttrQuery*/))
4416 {
4417 PKWFSOBJ pFsObj = kwFsLookupA(pszFilename);
4418 if (pFsObj)
4419 {
4420 if (pFsObj->fAttribs == INVALID_FILE_ATTRIBUTES)
4421 SetLastError(pFsObj->uLastError);
4422 KWFS_LOG(("GetFileAttributesA(%s) -> %#x [cached]\n", pszFilename, pFsObj->fAttribs));
4423 return pFsObj->fAttribs;
4424 }
4425 }
4426
4427 fRet = GetFileAttributesA(pszFilename);
4428 KWFS_LOG(("GetFileAttributesA(%s) -> %#x\n", pszFilename, fRet));
4429 return fRet;
4430}
4431
4432
4433/** Kernel32 - GetFileAttributesW. */
4434static DWORD WINAPI kwSandbox_Kernel32_GetFileAttributesW(LPCWSTR pwszFilename)
4435{
4436 DWORD fRet;
4437 if (kwFsIsCachablePathExtensionW(pwszFilename, K_TRUE /*fAttrQuery*/))
4438 {
4439 /** @todo rewrite to pure UTF-16. */
4440 char szTmp[2048];
4441 KSIZE cch = kwUtf16ToStr(pwszFilename, szTmp, sizeof(szTmp));
4442 if (cch < sizeof(szTmp))
4443 return kwSandbox_Kernel32_GetFileAttributesA(szTmp);
4444 }
4445
4446 fRet = GetFileAttributesW(pwszFilename);
4447 KWFS_LOG(("GetFileAttributesW(%ls) -> %#x\n", pwszFilename, fRet));
4448 return fRet;
4449}
4450
4451
4452/** Kernel32 - GetShortPathNameW - cl1[xx].dll of VS2010 does this to the
4453 * directory containing each include file. We cache the result to speed
4454 * things up a little. */
4455static DWORD WINAPI kwSandbox_Kernel32_GetShortPathNameW(LPCWSTR pwszLongPath, LPWSTR pwszShortPath, DWORD cwcShortPath)
4456{
4457 DWORD cwcRet;
4458 if (kwFsIsCachablePathExtensionW(pwszLongPath, K_TRUE /*fAttrQuery*/))
4459 {
4460 /** @todo proper implementation later, for now just copy it over as it. */
4461 KSIZE cwcLongPath = kwUtf16Len(pwszLongPath);
4462 cwcRet = kwUtf16CopyStyle1(pwszLongPath, pwszShortPath, cwcShortPath);
4463 KWFS_LOG(("GetShortPathNameW(%ls) -> '%*.*ls' & %#x [cached]\n",
4464 pwszLongPath, K_MIN(cwcShortPath, cwcRet), K_MIN(cwcShortPath, cwcRet), pwszShortPath, cwcRet));
4465 }
4466 else
4467 {
4468 cwcRet = GetShortPathNameW(pwszLongPath, pwszShortPath, cwcShortPath);
4469 KWFS_LOG(("GetShortPathNameW(%ls) -> '%*.*ls' & %#x\n",
4470 pwszLongPath, K_MIN(cwcShortPath, cwcRet), K_MIN(cwcShortPath, cwcRet), pwszShortPath, cwcRet));
4471 }
4472 return cwcRet;
4473}
4474
4475
4476
4477/**
4478 * Functions that needs replacing for sandboxed execution.
4479 */
4480KWREPLACEMENTFUNCTION const g_aSandboxReplacements[] =
4481{
4482 /*
4483 * Kernel32.dll and friends.
4484 */
4485 { TUPLE("ExitProcess"), NULL, (KUPTR)kwSandbox_Kernel32_ExitProcess },
4486 { TUPLE("TerminateProcess"), NULL, (KUPTR)kwSandbox_Kernel32_TerminateProcess },
4487
4488 { TUPLE("LoadLibraryA"), NULL, (KUPTR)kwSandbox_Kernel32_LoadLibraryA },
4489 { TUPLE("LoadLibraryW"), NULL, (KUPTR)kwSandbox_Kernel32_LoadLibraryW },
4490 { TUPLE("LoadLibraryExA"), NULL, (KUPTR)kwSandbox_Kernel32_LoadLibraryExA },
4491 { TUPLE("LoadLibraryExW"), NULL, (KUPTR)kwSandbox_Kernel32_LoadLibraryExW },
4492 { TUPLE("FreeLibrary"), NULL, (KUPTR)kwSandbox_Kernel32_FreeLibrary },
4493 { TUPLE("GetModuleHandleA"), NULL, (KUPTR)kwSandbox_Kernel32_GetModuleHandleA },
4494 { TUPLE("GetModuleHandleW"), NULL, (KUPTR)kwSandbox_Kernel32_GetModuleHandleW },
4495 { TUPLE("GetProcAddress"), NULL, (KUPTR)kwSandbox_Kernel32_GetProcAddress },
4496 { TUPLE("GetModuleFileNameA"), NULL, (KUPTR)kwSandbox_Kernel32_GetModuleFileNameA },
4497 { TUPLE("GetModuleFileNameW"), NULL, (KUPTR)kwSandbox_Kernel32_GetModuleFileNameW },
4498
4499 { TUPLE("GetCommandLineA"), NULL, (KUPTR)kwSandbox_Kernel32_GetCommandLineA },
4500 { TUPLE("GetCommandLineW"), NULL, (KUPTR)kwSandbox_Kernel32_GetCommandLineW },
4501 { TUPLE("GetStartupInfoA"), NULL, (KUPTR)kwSandbox_Kernel32_GetStartupInfoA },
4502 { TUPLE("GetStartupInfoW"), NULL, (KUPTR)kwSandbox_Kernel32_GetStartupInfoW },
4503
4504 { TUPLE("CreateThread"), NULL, (KUPTR)kwSandbox_Kernel32_CreateThread },
4505
4506 { TUPLE("GetEnvironmentVariableA"), NULL, (KUPTR)kwSandbox_Kernel32_GetEnvironmentVariableA },
4507 { TUPLE("GetEnvironmentVariableW"), NULL, (KUPTR)kwSandbox_Kernel32_GetEnvironmentVariableW },
4508 { TUPLE("SetEnvironmentVariableA"), NULL, (KUPTR)kwSandbox_Kernel32_SetEnvironmentVariableA },
4509 { TUPLE("SetEnvironmentVariableW"), NULL, (KUPTR)kwSandbox_Kernel32_SetEnvironmentVariableW },
4510 { TUPLE("ExpandEnvironmentStringsA"), NULL, (KUPTR)kwSandbox_Kernel32_ExpandEnvironmentStringsA },
4511 { TUPLE("ExpandEnvironmentStringsW"), NULL, (KUPTR)kwSandbox_Kernel32_ExpandEnvironmentStringsW },
4512
4513 { TUPLE("CreateFileA"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileA },
4514 { TUPLE("CreateFileW"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileW },
4515 { TUPLE("ReadFile"), NULL, (KUPTR)kwSandbox_Kernel32_ReadFile },
4516 { TUPLE("ReadFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_ReadFileEx },
4517#ifdef WITH_TEMP_MEMORY_FILES
4518 { TUPLE("WriteFile"), NULL, (KUPTR)kwSandbox_Kernel32_WriteFile },
4519 { TUPLE("WriteFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_WriteFileEx },
4520 { TUPLE("SetEndOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_SetEndOfFile },
4521 { TUPLE("GetFileType"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileType },
4522 { TUPLE("GetFileSize"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileSize },
4523 { TUPLE("GetFileSizeEx"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileSizeEx },
4524 { TUPLE("CreateFileMappingW"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileMappingW },
4525 { TUPLE("MapViewOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_MapViewOfFile },
4526 { TUPLE("UnmapViewOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_UnmapViewOfFile },
4527#endif
4528 { TUPLE("SetFilePointer"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointer },
4529 { TUPLE("SetFilePointerEx"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointerEx },
4530 { TUPLE("CloseHandle"), NULL, (KUPTR)kwSandbox_Kernel32_CloseHandle },
4531 { TUPLE("GetFileAttributesA"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesA },
4532 { TUPLE("GetFileAttributesW"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesW },
4533 { TUPLE("GetShortPathNameW"), NULL, (KUPTR)kwSandbox_Kernel32_GetShortPathNameW },
4534
4535 /*
4536 * MS Visual C++ CRTs.
4537 */
4538 { TUPLE("exit"), NULL, (KUPTR)kwSandbox_msvcrt_exit },
4539 { TUPLE("_exit"), NULL, (KUPTR)kwSandbox_msvcrt__exit },
4540 { TUPLE("_cexit"), NULL, (KUPTR)kwSandbox_msvcrt__cexit },
4541 { TUPLE("_c_exit"), NULL, (KUPTR)kwSandbox_msvcrt__c_exit },
4542 { TUPLE("_amsg_exit"), NULL, (KUPTR)kwSandbox_msvcrt__amsg_exit },
4543 { TUPLE("terminate"), NULL, (KUPTR)kwSandbox_msvcrt_terminate },
4544
4545 { TUPLE("_beginthread"), NULL, (KUPTR)kwSandbox_msvcrt__beginthread },
4546 { TUPLE("_beginthreadex"), NULL, (KUPTR)kwSandbox_msvcrt__beginthreadex },
4547
4548 { TUPLE("__argc"), NULL, (KUPTR)&g_Sandbox.cArgs },
4549 { TUPLE("__argv"), NULL, (KUPTR)&g_Sandbox.papszArgs },
4550 { TUPLE("__wargv"), NULL, (KUPTR)&g_Sandbox.papwszArgs },
4551 { TUPLE("__p___argc"), NULL, (KUPTR)kwSandbox_msvcrt___p___argc },
4552 { TUPLE("__p___argv"), NULL, (KUPTR)kwSandbox_msvcrt___p___argv },
4553 { TUPLE("__p___wargv"), NULL, (KUPTR)kwSandbox_msvcrt___p___wargv },
4554 { TUPLE("_acmdln"), NULL, (KUPTR)&g_Sandbox.pszCmdLine },
4555 { TUPLE("_wcmdln"), NULL, (KUPTR)&g_Sandbox.pwszCmdLine },
4556 { TUPLE("__p__acmdln"), NULL, (KUPTR)kwSandbox_msvcrt___p__acmdln },
4557 { TUPLE("__p__wcmdln"), NULL, (KUPTR)kwSandbox_msvcrt___p__wcmdln },
4558 { TUPLE("_pgmptr"), NULL, (KUPTR)&g_Sandbox.pgmptr },
4559 { TUPLE("_wpgmptr"), NULL, (KUPTR)&g_Sandbox.wpgmptr },
4560 { TUPLE("_get_pgmptr"), NULL, (KUPTR)kwSandbox_msvcrt__get_pgmptr },
4561 { TUPLE("_get_wpgmptr"), NULL, (KUPTR)kwSandbox_msvcrt__get_wpgmptr },
4562 { TUPLE("__p__pgmptr"), NULL, (KUPTR)kwSandbox_msvcrt___p__pgmptr },
4563 { TUPLE("__p__wpgmptr"), NULL, (KUPTR)kwSandbox_msvcrt___p__wpgmptr },
4564 { TUPLE("_wincmdln"), NULL, (KUPTR)kwSandbox_msvcrt__wincmdln },
4565 { TUPLE("_wwincmdln"), NULL, (KUPTR)kwSandbox_msvcrt__wwincmdln },
4566 { TUPLE("__getmainargs"), NULL, (KUPTR)kwSandbox_msvcrt___getmainargs},
4567 { TUPLE("__wgetmainargs"), NULL, (KUPTR)kwSandbox_msvcrt___wgetmainargs},
4568
4569 { TUPLE("_putenv"), NULL, (KUPTR)kwSandbox_msvcrt__putenv},
4570 { TUPLE("_wputenv"), NULL, (KUPTR)kwSandbox_msvcrt__wputenv},
4571 { TUPLE("_putenv_s"), NULL, (KUPTR)kwSandbox_msvcrt__putenv_s},
4572 { TUPLE("_wputenv_s"), NULL, (KUPTR)kwSandbox_msvcrt__wputenv_s},
4573 { TUPLE("__initenv"), NULL, (KUPTR)&g_Sandbox.initenv },
4574 { TUPLE("__winitenv"), NULL, (KUPTR)&g_Sandbox.winitenv },
4575 { TUPLE("__p___initenv"), NULL, (KUPTR)kwSandbox_msvcrt___p___initenv},
4576 { TUPLE("__p___winitenv"), NULL, (KUPTR)kwSandbox_msvcrt___p___winitenv},
4577 { TUPLE("_environ"), NULL, (KUPTR)&g_Sandbox.environ },
4578 { TUPLE("_wenviron"), NULL, (KUPTR)&g_Sandbox.wenviron },
4579 { TUPLE("_get_environ"), NULL, (KUPTR)kwSandbox_msvcrt__get_environ },
4580 { TUPLE("_get_wenviron"), NULL, (KUPTR)kwSandbox_msvcrt__get_wenviron },
4581 { TUPLE("__p__environ"), NULL, (KUPTR)kwSandbox_msvcrt___p__environ },
4582 { TUPLE("__p__wenviron"), NULL, (KUPTR)kwSandbox_msvcrt___p__wenviron },
4583};
4584/** Number of entries in g_aReplacements. */
4585KU32 const g_cSandboxReplacements = K_ELEMENTS(g_aSandboxReplacements);
4586
4587
4588/**
4589 * Functions that needs replacing in natively loaded DLLs when doing sandboxed
4590 * execution.
4591 */
4592KWREPLACEMENTFUNCTION const g_aSandboxNativeReplacements[] =
4593{
4594 /*
4595 * Kernel32.dll and friends.
4596 */
4597 { TUPLE("ExitProcess"), NULL, (KUPTR)kwSandbox_Kernel32_ExitProcess },
4598 { TUPLE("TerminateProcess"), NULL, (KUPTR)kwSandbox_Kernel32_TerminateProcess },
4599
4600#if 0
4601 { TUPLE("CreateThread"), NULL, (KUPTR)kwSandbox_Kernel32_CreateThread },
4602#endif
4603
4604 { TUPLE("CreateFileA"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileA },
4605 { TUPLE("CreateFileW"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileW },
4606 { TUPLE("ReadFile"), NULL, (KUPTR)kwSandbox_Kernel32_ReadFile },
4607 { TUPLE("ReadFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_ReadFileEx },
4608#ifdef WITH_TEMP_MEMORY_FILES
4609 { TUPLE("WriteFile"), NULL, (KUPTR)kwSandbox_Kernel32_WriteFile },
4610 { TUPLE("WriteFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_WriteFileEx },
4611 { TUPLE("SetEndOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_SetEndOfFile },
4612 { TUPLE("GetFileType"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileType },
4613 { TUPLE("GetFileSize"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileSize },
4614 { TUPLE("GetFileSizeEx"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileSizeEx },
4615 { TUPLE("CreateFileMappingW"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileMappingW },
4616 { TUPLE("MapViewOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_MapViewOfFile },
4617 { TUPLE("UnmapViewOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_UnmapViewOfFile },
4618#endif
4619 { TUPLE("SetFilePointer"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointer },
4620 { TUPLE("SetFilePointerEx"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointerEx },
4621 { TUPLE("CloseHandle"), NULL, (KUPTR)kwSandbox_Kernel32_CloseHandle },
4622 { TUPLE("GetFileAttributesA"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesA },
4623 { TUPLE("GetFileAttributesW"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesW },
4624 { TUPLE("GetShortPathNameW"), NULL, (KUPTR)kwSandbox_Kernel32_GetShortPathNameW },
4625
4626 /*
4627 * MS Visual C++ CRTs.
4628 */
4629 { TUPLE("exit"), NULL, (KUPTR)kwSandbox_msvcrt_exit },
4630 { TUPLE("_exit"), NULL, (KUPTR)kwSandbox_msvcrt__exit },
4631 { TUPLE("_cexit"), NULL, (KUPTR)kwSandbox_msvcrt__cexit },
4632 { TUPLE("_c_exit"), NULL, (KUPTR)kwSandbox_msvcrt__c_exit },
4633 { TUPLE("_amsg_exit"), NULL, (KUPTR)kwSandbox_msvcrt__amsg_exit },
4634 { TUPLE("terminate"), NULL, (KUPTR)kwSandbox_msvcrt_terminate },
4635
4636#if 0 /* used by mspdbXXX.dll */
4637 { TUPLE("_beginthread"), NULL, (KUPTR)kwSandbox_msvcrt__beginthread },
4638 { TUPLE("_beginthreadex"), NULL, (KUPTR)kwSandbox_msvcrt__beginthreadex },
4639#endif
4640};
4641/** Number of entries in g_aSandboxNativeReplacements. */
4642KU32 const g_cSandboxNativeReplacements = K_ELEMENTS(g_aSandboxNativeReplacements);
4643
4644
4645/**
4646 * Used by kwSandboxExec to reset the state of the module tree.
4647 *
4648 * This is done recursively.
4649 *
4650 * @param pMod The root of the tree to consider.
4651 */
4652static void kwSandboxResetModuleState(PKWMODULE pMod)
4653{
4654 if ( !pMod->fNative
4655 && pMod->u.Manual.enmState != KWMODSTATE_NEEDS_BITS)
4656 {
4657 KSIZE iImp;
4658 pMod->u.Manual.enmState = KWMODSTATE_NEEDS_BITS;
4659 iImp = pMod->u.Manual.cImpMods;
4660 while (iImp-- > 0)
4661 kwSandboxResetModuleState(pMod->u.Manual.apImpMods[iImp]);
4662 }
4663}
4664
4665static PPEB kwSandboxGetProcessEnvironmentBlock(void)
4666{
4667#if K_ARCH == K_ARCH_X86_32
4668 return (PPEB)__readfsdword(0x030 /* offset of ProcessEnvironmentBlock in TEB */);
4669#elif K_ARCH == K_ARCH_AMD64
4670 return (PPEB)__readgsqword(0x060 /* offset of ProcessEnvironmentBlock in TEB */);
4671#else
4672# error "Port me!"
4673#endif
4674}
4675
4676
4677/**
4678 * Enters the given handle into the handle table.
4679 *
4680 * @returns K_TRUE on success, K_FALSE on failure.
4681 * @param pSandbox The sandbox.
4682 * @param pHandle The handle.
4683 */
4684static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle)
4685{
4686 KUPTR const idxHandle = KW_HANDLE_TO_INDEX(pHandle->hHandle);
4687 kHlpAssertReturn(idxHandle < KW_HANDLE_MAX, K_FALSE);
4688
4689 /*
4690 * Grow handle table.
4691 */
4692 if (idxHandle >= pSandbox->cHandles)
4693 {
4694 void *pvNew;
4695 KU32 cHandles = pSandbox->cHandles ? pSandbox->cHandles * 2 : 32;
4696 while (cHandles <= idxHandle)
4697 cHandles *= 2;
4698 pvNew = kHlpRealloc(pSandbox->papHandles, cHandles * sizeof(pSandbox->papHandles[0]));
4699 if (!pvNew)
4700 {
4701 KW_LOG(("Out of memory growing handle table to %u handles\n", cHandles));
4702 return K_FALSE;
4703 }
4704 pSandbox->papHandles = (PKWHANDLE *)pvNew;
4705 kHlpMemSet(&pSandbox->papHandles[pSandbox->cHandles], 0,
4706 (cHandles - pSandbox->cHandles) * sizeof(pSandbox->papHandles[0]));
4707 pSandbox->cHandles = cHandles;
4708 }
4709
4710 /*
4711 * Check that the entry is unused then insert it.
4712 */
4713 kHlpAssertReturn(pSandbox->papHandles[idxHandle] == NULL, K_FALSE);
4714 pSandbox->papHandles[idxHandle] = pHandle;
4715 pSandbox->cActiveHandles++;
4716 return K_TRUE;
4717}
4718
4719
4720
4721static int kwSandboxInit(PKWSANDBOX pSandbox, PKWTOOL pTool,
4722 KU32 cArgs, const char **papszArgs, KU32 cbArgs,
4723 KU32 cEnvVars, const char **papszEnvVars)
4724{
4725 PPEB pPeb = kwSandboxGetProcessEnvironmentBlock();
4726 char *psz;
4727 wchar_t *pwcPool;
4728 KSIZE cbStrings;
4729 KSIZE cwc;
4730 KU32 i;
4731
4732 /* Simple stuff. */
4733 g_Sandbox.rcExitCode = 256;
4734 g_Sandbox.pTool = pTool;
4735 g_Sandbox.idMainThread = GetCurrentThreadId();
4736 g_Sandbox.TibMainThread = *(PNT_TIB)NtCurrentTeb();
4737 g_Sandbox.pgmptr = (char *)pTool->pszPath;
4738 g_Sandbox.wpgmptr = (wchar_t *)pTool->pwszPath;
4739 g_Sandbox.cArgs = cArgs;
4740 g_Sandbox.papszArgs = (char **)papszArgs;
4741
4742 /*
4743 * Create a command line from the given argv.
4744 * ASSUME that it's correctly quoted by quote_argv.c already.
4745 */
4746 pSandbox->pszCmdLine = psz = (char *)kHlpAlloc(cbArgs + 1);
4747 if (!psz)
4748 return KERR_NO_MEMORY;
4749 psz = kHlpStrPCopy(psz, papszArgs[0]);
4750 for (i = 1; i < cArgs; i++)
4751 {
4752 *psz++ = ' ';
4753 psz = kHlpStrPCopy(psz, papszArgs[i]);
4754 }
4755 kHlpAssert((KSIZE)(&psz[1] - pSandbox->pszCmdLine) == cbArgs);
4756 psz[0] = '\0';
4757 psz[1] = '\0';
4758
4759 /*
4760 * Convert command line and argv to UTF-16.
4761 * We assume each ANSI char requires a surrogate pair in the UTF-16 variant.
4762 */
4763 pSandbox->papwszArgs = (wchar_t **)kHlpAlloc(sizeof(wchar_t *) * (pSandbox->cArgs + 2) + cbArgs * 2 * sizeof(wchar_t));
4764 if (!pSandbox->papwszArgs)
4765 return KERR_NO_MEMORY;
4766 pwcPool = (wchar_t *)&pSandbox->papwszArgs[pSandbox->cArgs + 2];
4767 for (i = 0; i < cArgs; i++)
4768 {
4769 *pwcPool++ = pSandbox->papszArgs[i][-1]; /* flags */
4770 pSandbox->papwszArgs[i] = pwcPool;
4771 pwcPool += kwStrToUtf16(pSandbox->papszArgs[i], pwcPool, (strlen(pSandbox->papszArgs[i]) + 1) * 2);
4772 pwcPool++;
4773 }
4774 pSandbox->papwszArgs[pSandbox->cArgs + 0] = NULL;
4775 pSandbox->papwszArgs[pSandbox->cArgs + 1] = NULL;
4776
4777 /*
4778 * Convert the commandline string to UTF-16, same pessimistic approach as above.
4779 */
4780 cbStrings = (cbArgs + 1) * 2 * sizeof(wchar_t);
4781 pSandbox->pwszCmdLine = kHlpAlloc(cbStrings);
4782 if (!pSandbox->pwszCmdLine)
4783 return KERR_NO_MEMORY;
4784 cwc = kwStrToUtf16(pSandbox->pszCmdLine, pSandbox->pwszCmdLine, cbStrings / sizeof(wchar_t));
4785
4786 pSandbox->SavedCommandLine = pPeb->ProcessParameters->CommandLine;
4787 pPeb->ProcessParameters->CommandLine.Buffer = pSandbox->pwszCmdLine;
4788 pPeb->ProcessParameters->CommandLine.Length = (USHORT)cwc * sizeof(wchar_t);
4789
4790
4791 g_uFsCacheGeneration++;
4792 if (g_uFsCacheGeneration == KFSWOBJ_CACHE_GEN_IGNORE)
4793 g_uFsCacheGeneration++;
4794 return 0;
4795}
4796
4797
4798static void kwSandboxCleanup(PKWSANDBOX pSandbox)
4799{
4800#ifdef WITH_TEMP_MEMORY_FILES
4801 PKWFSTEMPFILE pTempFile;
4802#endif
4803 PPEB pPeb = kwSandboxGetProcessEnvironmentBlock();
4804 pPeb->ProcessParameters->CommandLine = pSandbox->SavedCommandLine;
4805 /** @todo lots more to do here! */
4806
4807#ifdef WITH_TEMP_MEMORY_FILES
4808 pTempFile = pSandbox->pTempFileHead;
4809 pSandbox->pTempFileHead = NULL;
4810 while (pTempFile)
4811 {
4812 PKWFSTEMPFILE pNext = pTempFile->pNext;
4813 KU32 iSeg = pTempFile->cSegs;
4814 while (iSeg-- > 0)
4815 kHlpPageFree(pTempFile->paSegs[iSeg].pbData, pTempFile->paSegs[iSeg].cbDataAlloc);
4816 kHlpFree(pTempFile->paSegs);
4817 pTempFile->pNext = NULL;
4818 kHlpFree(pTempFile);
4819
4820 pTempFile = pNext;
4821 }
4822#endif
4823
4824}
4825
4826
4827static int kwSandboxExec(PKWTOOL pTool, KU32 cArgs, const char **papszArgs, KU32 cbArgs,
4828 KU32 cEnvVars, const char **papszEnvVars)
4829{
4830 int rcExit = 42;
4831 int rc;
4832
4833 /*
4834 * Initialize the sandbox environment.
4835 */
4836 rc = kwSandboxInit(&g_Sandbox, pTool, cArgs, papszArgs, cbArgs, cEnvVars, papszEnvVars);
4837 if (rc == 0)
4838 {
4839 /*
4840 * Do module initialization.
4841 */
4842 kwSandboxResetModuleState(pTool->u.Sandboxed.pExe);
4843 rc = kwLdrModuleInitTree(pTool->u.Sandboxed.pExe);
4844 if (rc == 0)
4845 {
4846 /*
4847 * Call the main function.
4848 */
4849 KUPTR uAddrMain;
4850 rc = kwLdrModuleQueryMainEntrypoint(pTool->u.Sandboxed.pExe, &uAddrMain);
4851 if (rc == 0)
4852 {
4853 int (*pfnWin64Entrypoint)(void *pvPeb, void *, void *, void *);
4854 *(KUPTR *)&pfnWin64Entrypoint = uAddrMain;
4855
4856 __try
4857 {
4858 if (setjmp(g_Sandbox.JmpBuf) == 0)
4859 {
4860#if K_ARCH == K_ARCH_AMD64
4861 *(KU64*)(g_Sandbox.JmpBuf) = 0; /** @todo find other way to prevent longjmp from doing unwind! */
4862#else
4863# error "Port me!"
4864#endif
4865 rcExit = pfnWin64Entrypoint(kwSandboxGetProcessEnvironmentBlock(), NULL, NULL, NULL);
4866 }
4867 else
4868 rcExit = g_Sandbox.rcExitCode;
4869 }
4870 __except (EXCEPTION_EXECUTE_HANDLER)
4871 {
4872 rcExit = 512;
4873 }
4874
4875 /*
4876 * Restore the TIB and later some other stuff.
4877 */
4878 *(PNT_TIB)NtCurrentTeb() = g_Sandbox.TibMainThread;
4879 }
4880 else
4881 rcExit = 42 + 5;
4882 }
4883 else
4884 rcExit = 42 + 4;
4885
4886 kwSandboxCleanup(&g_Sandbox);
4887 }
4888 else
4889 rcExit = 42 + 3;
4890
4891 return rcExit;
4892}
4893
4894
4895#if 0
4896static int kwExecCmdLine(const char *pszExe, const char *pszCmdLine)
4897{
4898 int rc;
4899 PKWTOOL pTool = kwToolLookup(pszExe);
4900 if (pTool)
4901 {
4902 int rc;
4903 int rcExitCode;
4904 switch (pTool->enmType)
4905 {
4906 case KWTOOLTYPE_SANDBOXED:
4907 KW_LOG(("Sandboxing tool %s\n", pTool->pszPath));
4908 rc = kwSandboxExec(pTool, pszCmdLine, &rcExitCode);
4909 break;
4910
4911 case KWTOOLTYPE_WATCOM:
4912 KW_LOG(("TODO: Watcom style tool %s\n", pTool->pszPath));
4913 rc = rcExitCode = 2;
4914 break;
4915
4916 case KWTOOLTYPE_EXEC:
4917 KW_LOG(("TODO: Direct exec tool %s\n", pTool->pszPath));
4918 rc = rcExitCode = 2;
4919 break;
4920
4921 default:
4922 kHlpAssertFailed();
4923 rc = rcExitCode = 2;
4924 break;
4925 }
4926 KW_LOG(("rcExitCode=%d (rc=%d)\n", rcExitCode, rc));
4927 }
4928 else
4929 rc = 1;
4930 return rc;
4931}
4932#endif
4933
4934
4935/**
4936 * Part 2 of the "JOB" command handler.
4937 *
4938 * @returns The exit code of the job.
4939 * @param pszExecutable The executable to execute.
4940 * @param pszCwd The current working directory of the job.
4941 * @param cArgs The number of arguments.
4942 * @param papszArgs The argument vector.
4943 * @param cbArgs The size of the argument strings and terminators.
4944 * @param cEnvVars The number of environment variables.
4945 * @param papszEnvVars The enviornment vector.
4946 */
4947static int kSubmitHandleJobUnpacked(const char *pszExecutable, const char *pszCwd,
4948 KU32 cArgs, const char **papszArgs, KU32 cbArgs,
4949 KU32 cEnvVars, const char **papszEnvVars)
4950{
4951 int rcExit;
4952 PKWTOOL pTool;
4953
4954 /*
4955 * Lookup the tool.
4956 */
4957 pTool = kwToolLookup(pszExecutable);
4958 if (pTool)
4959 {
4960 /*
4961 * Change the directory if we're going to execute the job inside
4962 * this process. Then invoke the tool type specific handler.
4963 */
4964 switch (pTool->enmType)
4965 {
4966 case KWTOOLTYPE_SANDBOXED:
4967 case KWTOOLTYPE_WATCOM:
4968 /** @todo cache this */
4969 if (SetCurrentDirectoryA(pszCwd))
4970 {
4971 if (pTool->enmType == KWTOOLTYPE_SANDBOXED)
4972 {
4973 KW_LOG(("Sandboxing tool %s\n", pTool->pszPath));
4974 rcExit = kwSandboxExec(pTool, cArgs, papszArgs, cbArgs, cEnvVars, papszEnvVars);
4975 }
4976 else
4977 {
4978 kwErrPrintf("TODO: Watcom style tool %s\n", pTool->pszPath);
4979 rcExit = 42 + 2;
4980 }
4981 }
4982 else
4983 {
4984 kwErrPrintf("SetCurrentDirectory failed with %u on '%s'\n", GetLastError(), pszCwd);
4985 rcExit = 42 + 1;
4986 }
4987 break;
4988
4989 case KWTOOLTYPE_EXEC:
4990 kwErrPrintf("TODO: Direct exec tool %s\n", pTool->pszPath);
4991 rcExit = 42 + 2;
4992 break;
4993
4994 default:
4995 kHlpAssertFailed();
4996 kwErrPrintf("Internal tool type corruption!!\n");
4997 rcExit = 42 + 2;
4998 g_fRestart = K_TRUE;
4999 break;
5000 }
5001 }
5002 else
5003 rcExit = 42 + 1;
5004 return rcExit;
5005}
5006
5007
5008/**
5009 * Handles a "JOB" command.
5010 *
5011 * @returns The exit code of the job.
5012 * @param pszMsg Points to the "JOB" command part of the message.
5013 * @param cbMsg Number of message bytes at @a pszMsg. There are
5014 * 4 more zero bytes after the message body to
5015 * simplify parsing.
5016 */
5017static int kSubmitHandleJob(const char *pszMsg, KSIZE cbMsg)
5018{
5019 int rcExit = 42;
5020
5021 /*
5022 * Unpack the message.
5023 */
5024 const char *pszExecutable;
5025 size_t cbTmp;
5026
5027 pszMsg += sizeof("JOB");
5028 cbMsg -= sizeof("JOB");
5029
5030 /* Executable name. */
5031 pszExecutable = pszMsg;
5032 cbTmp = strlen(pszMsg) + 1;
5033 pszMsg += cbTmp;
5034 if ( cbTmp < cbMsg
5035 && cbTmp > 2)
5036 {
5037 const char *pszCwd;
5038 cbMsg -= cbTmp;
5039
5040 /* Current working directory. */
5041 pszCwd = pszMsg;
5042 cbTmp = strlen(pszMsg) + 1;
5043 pszMsg += cbTmp;
5044 if ( cbTmp + sizeof(KU32) < cbMsg
5045 && cbTmp >= 2)
5046 {
5047 KU32 cArgs;
5048 cbMsg -= cbTmp;
5049
5050 /* Argument count. */
5051 kHlpMemCopy(&cArgs, pszMsg, sizeof(cArgs));
5052 pszMsg += sizeof(cArgs);
5053 cbMsg -= sizeof(cArgs);
5054
5055 if (cArgs > 0 && cArgs < 4096)
5056 {
5057 /* The argument vector. */
5058 char const **papszArgs = kHlpAlloc((cArgs + 1) * sizeof(papszArgs[0]));
5059 if (papszArgs)
5060 {
5061 KU32 cbArgs;
5062 KU32 i;
5063 for (i = 0; i < cArgs; i++)
5064 {
5065 papszArgs[i] = pszMsg + 1; /* First byte is expansion flags for MSC & EMX. */
5066 cbTmp = 1 + strlen(pszMsg + 1) + 1;
5067 pszMsg += cbTmp;
5068 if (cbTmp < cbMsg)
5069 cbMsg -= cbTmp;
5070 else
5071 {
5072 cbMsg = 0;
5073 break;
5074 }
5075
5076 }
5077 papszArgs[cArgs] = 0;
5078 cbArgs = (KU32)(pszMsg - papszArgs[0]) - cArgs + 1;
5079
5080 /* Environment variable count. */
5081 if (sizeof(KU32) < cbMsg)
5082 {
5083 KU32 cEnvVars;
5084 kHlpMemCopy(&cEnvVars, pszMsg, sizeof(cEnvVars));
5085 pszMsg += sizeof(cEnvVars);
5086 cbMsg -= sizeof(cEnvVars);
5087
5088 if (cEnvVars >= 0 && cEnvVars < 4096)
5089 {
5090 /* The argument vector. */
5091 char const **papszEnvVars = kHlpAlloc((cEnvVars + 1) * sizeof(papszEnvVars[0]));
5092 if (papszEnvVars)
5093 {
5094 KU32 i;
5095 for (i = 0; i < cEnvVars; i++)
5096 {
5097 papszEnvVars[i] = pszMsg;
5098 cbTmp = strlen(pszMsg) + 1;
5099 pszMsg += cbTmp;
5100 if (cbTmp < cbMsg)
5101 cbMsg -= cbTmp;
5102 else
5103 {
5104 if ( cbTmp == cbMsg
5105 && i + 1 == cEnvVars)
5106 cbMsg = 0;
5107 else
5108 cbMsg = KSIZE_MAX;
5109 break;
5110 }
5111 }
5112 papszEnvVars[cEnvVars] = 0;
5113 if (cbMsg != KSIZE_MAX)
5114 {
5115 if (cbMsg == 0)
5116 {
5117 /*
5118 * The next step.
5119 */
5120 rcExit = kSubmitHandleJobUnpacked(pszExecutable, pszCwd,
5121 cArgs, papszArgs, cbArgs,
5122 cEnvVars, papszEnvVars);
5123 }
5124 else
5125 kwErrPrintf("Message has %u bytes unknown trailing bytes\n", cbMsg);
5126 }
5127 else
5128 kwErrPrintf("Detected bogus message unpacking environment variables!\n");
5129 kHlpFree((void *)papszEnvVars);
5130 }
5131 else
5132 kwErrPrintf("Error allocating papszEnvVars for %u variables\n", cEnvVars);
5133 }
5134 else
5135 kwErrPrintf("Bogus environment variable count: %u (%#x)\n", cEnvVars, cEnvVars);
5136 }
5137 else
5138 kwErrPrintf("Detected bogus message unpacking arguments and environment variable count!\n");
5139 kHlpFree((void *)papszArgs);
5140 }
5141 else
5142 kwErrPrintf("Error allocating argv for %u arguments\n", cArgs);
5143 }
5144 else
5145 kwErrPrintf("Bogus argument count: %u (%#x)\n", cArgs, cArgs);
5146 }
5147 else
5148 kwErrPrintf("Detected bogus message unpacking CWD path and argument count!\n");
5149 }
5150 else
5151 kwErrPrintf("Detected bogus message unpacking executable path!\n");
5152 return rcExit;
5153}
5154
5155
5156/**
5157 * Wrapper around WriteFile / write that writes the whole @a cbToWrite.
5158 *
5159 * @retval 0 on success.
5160 * @retval -1 on error (fully bitched).
5161 *
5162 * @param hPipe The pipe handle.
5163 * @param pvBuf The buffer to write out out.
5164 * @param cbToWrite The number of bytes to write.
5165 */
5166static int kSubmitWriteIt(HANDLE hPipe, const void *pvBuf, KU32 cbToWrite)
5167{
5168 KU8 const *pbBuf = (KU8 const *)pvBuf;
5169 KU32 cbLeft = cbToWrite;
5170 for (;;)
5171 {
5172 DWORD cbActuallyWritten = 0;
5173 if (WriteFile(hPipe, pbBuf, cbLeft, &cbActuallyWritten, NULL /*pOverlapped*/))
5174 {
5175 cbLeft -= cbActuallyWritten;
5176 if (!cbLeft)
5177 return 0;
5178 pbBuf += cbActuallyWritten;
5179 }
5180 else
5181 {
5182 DWORD dwErr = GetLastError();
5183 if (cbLeft == cbToWrite)
5184 kwErrPrintf("WriteFile failed: %u\n", dwErr);
5185 else
5186 kwErrPrintf("WriteFile failed %u byte(s) in: %u\n", cbToWrite - cbLeft, dwErr);
5187 return -1;
5188 }
5189 }
5190}
5191
5192
5193/**
5194 * Wrapper around ReadFile / read that reads the whole @a cbToRead.
5195 *
5196 * @retval 0 on success.
5197 * @retval 1 on shut down (fShutdownOkay must be K_TRUE).
5198 * @retval -1 on error (fully bitched).
5199 * @param hPipe The pipe handle.
5200 * @param pvBuf The buffer to read into.
5201 * @param cbToRead The number of bytes to read.
5202 * @param fShutdownOkay Whether connection shutdown while reading the
5203 * first byte is okay or not.
5204 */
5205static int kSubmitReadIt(HANDLE hPipe, void *pvBuf, KU32 cbToRead, KBOOL fMayShutdown)
5206{
5207 KU8 *pbBuf = (KU8 *)pvBuf;
5208 KU32 cbLeft = cbToRead;
5209 for (;;)
5210 {
5211 DWORD cbActuallyRead = 0;
5212 if (ReadFile(hPipe, pbBuf, cbLeft, &cbActuallyRead, NULL /*pOverlapped*/))
5213 {
5214 cbLeft -= cbActuallyRead;
5215 if (!cbLeft)
5216 return 0;
5217 pbBuf += cbActuallyRead;
5218 }
5219 else
5220 {
5221 DWORD dwErr = GetLastError();
5222 if (cbLeft == cbToRead)
5223 {
5224 if ( fMayShutdown
5225 && dwErr == ERROR_BROKEN_PIPE)
5226 return 1;
5227 kwErrPrintf("ReadFile failed: %u\n", dwErr);
5228 }
5229 else
5230 kwErrPrintf("ReadFile failed %u byte(s) in: %u\n", cbToRead - cbLeft, dwErr);
5231 return -1;
5232 }
5233 }
5234}
5235
5236
5237int main(int argc, char **argv)
5238{
5239#if 1
5240 KSIZE cbMsgBuf = 0;
5241 KU8 *pbMsgBuf = NULL;
5242 int i;
5243 HANDLE hPipe = INVALID_HANDLE_VALUE;
5244
5245 /*
5246 * Parse arguments.
5247 */
5248 for (i = 1; i < argc; i++)
5249 {
5250 if (strcmp(argv[i], "--pipe") == 0)
5251 {
5252 i++;
5253 if (i < argc)
5254 {
5255 char *pszEnd = NULL;
5256 unsigned __int64 u64Value = _strtoui64(argv[i], &pszEnd, 16);
5257 if ( *argv[i]
5258 && pszEnd != NULL
5259 && *pszEnd == '\0'
5260 && u64Value != 0
5261 && u64Value != (uintptr_t)INVALID_HANDLE_VALUE
5262 && (uintptr_t)u64Value == u64Value)
5263 hPipe = (HANDLE)(uintptr_t)u64Value;
5264 else
5265 {
5266 kwErrPrintf("Invalid --pipe argument: %s\n", argv[i]);
5267 return 2;
5268 }
5269 }
5270 else
5271 {
5272 kwErrPrintf("--pipe takes an argument!\n");
5273 return 2;
5274 }
5275 }
5276 else if ( strcmp(argv[i], "--help") == 0
5277 || strcmp(argv[i], "-h") == 0
5278 || strcmp(argv[i], "-?") == 0)
5279 {
5280 printf("usage: kWorker --pipe <pipe-handle>\n"
5281 "usage: kWorker <--help|-h>\n"
5282 "usage: kWorker <--version|-V>\n"
5283 "\n"
5284 "This is an internal kmk program that is used via the builtin_kSubmit.\n");
5285 return 0;
5286 }
5287 else if ( strcmp(argv[i], "--version") == 0
5288 || strcmp(argv[i], "-V") == 0)
5289 return kbuild_version(argv[0]);
5290 else
5291 {
5292 kwErrPrintf("Unknown argument '%s'\n", argv[i]);
5293 return 2;
5294 }
5295 }
5296
5297 if (hPipe == INVALID_HANDLE_VALUE)
5298 {
5299 kwErrPrintf("Missing --pipe <pipe-handle> argument!\n");
5300 return 2;
5301 }
5302
5303 /*
5304 * Serve the pipe.
5305 */
5306 for (;;)
5307 {
5308 KU32 cbMsg = 0;
5309 int rc = kSubmitReadIt(hPipe, &cbMsg, sizeof(cbMsg), K_TRUE /*fShutdownOkay*/);
5310 if (rc == 0)
5311 {
5312 /* Make sure the message length is within sane bounds. */
5313 if ( cbMsg > 4
5314 && cbMsg <= 256*1024*1024)
5315 {
5316 /* Reallocate the message buffer if necessary. We add 4 zero bytes. */
5317 if (cbMsg + 4 <= cbMsgBuf)
5318 { /* likely */ }
5319 else
5320 {
5321 cbMsgBuf = K_ALIGN_Z(cbMsg + 4, 2048);
5322 pbMsgBuf = kHlpRealloc(pbMsgBuf, cbMsgBuf);
5323 if (!pbMsgBuf)
5324 {
5325 kwErrPrintf("Failed to allocate %u bytes for a message buffer!\n", cbMsgBuf);
5326 return 1;
5327 }
5328 }
5329
5330 /* Read the whole message into the buffer, making sure there is are a 4 zero bytes following it. */
5331 *(KU32 *)pbMsgBuf = cbMsg;
5332 rc = kSubmitReadIt(hPipe, &pbMsgBuf[sizeof(cbMsg)], cbMsg - sizeof(cbMsg), K_FALSE /*fShutdownOkay*/);
5333 if (rc == 0)
5334 {
5335 const char *psz;
5336
5337 pbMsgBuf[cbMsg] = '\0';
5338 pbMsgBuf[cbMsg + 1] = '\0';
5339 pbMsgBuf[cbMsg + 2] = '\0';
5340 pbMsgBuf[cbMsg + 3] = '\0';
5341
5342 /* The first string after the header is the command. */
5343 psz = (const char *)&pbMsgBuf[sizeof(cbMsg)];
5344 if (strcmp(psz, "JOB") == 0)
5345 {
5346 struct
5347 {
5348 KI32 rcExitCode;
5349 KU8 bExiting;
5350 KU8 abZero[3];
5351 } Reply;
5352 Reply.rcExitCode = kSubmitHandleJob(psz, cbMsg - sizeof(cbMsg));
5353 Reply.bExiting = g_fRestart;
5354 Reply.abZero[0] = 0;
5355 Reply.abZero[1] = 0;
5356 Reply.abZero[2] = 0;
5357 rc = kSubmitWriteIt(hPipe, &Reply, sizeof(Reply));
5358 if ( rc == 0
5359 && !g_fRestart)
5360 continue;
5361 }
5362 else
5363 {
5364 kwErrPrintf("Unknown command: '%s'\n", psz);
5365 rc = -1;
5366 }
5367 }
5368 }
5369 else
5370 {
5371 kwErrPrintf("Bogus message length: %u (%#x)\n", cbMsg, cbMsg);
5372 rc = -1;
5373 }
5374 }
5375 return rc > 0 ? 0 : 1;
5376 }
5377
5378#else
5379 int rc = 0;
5380 int i;
5381 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";
5382# if 0
5383 rc = kwExecCmdLine(argv[1], argv[2]);
5384 rc = kwExecCmdLine(argv[1], argv[2]);
5385 K_NOREF(i);
5386# else
5387// Skylake (W10/amd64, only stdandard MS defender):
5388// cmd 1: 48 /1024 = 0x0 (0.046875) [for /l %i in (1,1,1024) do ...]
5389// kmk 1: 44 /1024 = 0x0 (0.04296875) [all: ; 1024 x cl.exe]
5390// run 1: 37 /1024 = 0x0 (0.0361328125) [just process creation gain]
5391// run 2: 34 /1024 = 0x0 (0.033203125) [get file attribs]
5392// run 3: 32.77 /1024 = 0x0 (0.032001953125) [read caching of headers]
5393// run 4: 32.67 /1024 = 0x0 (0.031904296875) [loader tweaking]
5394// run 5: 29.144/1024 = 0x0 (0.0284609375) [with temp files in memory]
5395// Dell (W7/amd64, infected by mcafee):
5396// kmk 1: 285.278/1024 = 0x0 (0.278591796875)
5397// run 1: 134.503/1024 = 0x0 (0.1313505859375) [w/o temp files in memory]
5398// run 2: 78.161/1024 = 0x0 (0.0763291015625) [with temp files in memory]
5399 g_cVerbose = 0;
5400 for (i = 0; i < 1024 && rc == 0; i++)
5401 rc = kwExecCmdLine(argv[1], argv[2]);
5402# endif
5403 return rc;
5404
5405#endif
5406}
5407
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