VirtualBox

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

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

updates

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