VirtualBox

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

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

kWorker: More hacking.

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