VirtualBox

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

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

fixed exception in c1xx.dll/msvcrt/memcpy.

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