VirtualBox

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

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

kWorker: cmdline quoting fix.

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