VirtualBox

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

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

kWorker: More hacking. Read cache, ldr optimizations.

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