VirtualBox

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

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

kWorker: Next step, speed up header file opening by handle duplication.

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