Changeset 2833 for trunk/src/kWorker/kWorker.c
- Timestamp:
- Aug 22, 2016, 11:00:38 PM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kWorker/kWorker.c
r2832 r2833 2 2 /** @file 3 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. 4 7 */ 5 8 … … 40 43 #include <Windows.h> 41 44 #include <winternl.h> 45 46 47 /********************************************************************************************************************************* 48 * Defined Constants And Macros * 49 *********************************************************************************************************************************/ 50 /** Special KWFSOBJ::uCacheGen number indicating that it does not apply. */ 51 #define KFSWOBJ_CACHE_GEN_IGNORE KU32_MAX 52 53 /** String constant comma length. */ 54 #define TUPLE(a_sz) a_sz, sizeof(a_sz) - 1 55 56 /** @def KW_LOG 57 * Generic logging. 58 * @param a Argument list for kwDbgPrintf */ 59 #ifndef NDEBUG 60 # define KW_LOG(a) kwDbgPrintf a 61 #else 62 # define KW_LOG(a) do { } while (0) 63 #endif 64 65 66 /** @def KWFS_LOG 67 * FS cache logging. 68 * @param a Argument list for kwDbgPrintf */ 69 #ifndef NDEBUG 70 # define KWFS_LOG(a) kwDbgPrintf a 71 #else 72 # define KWFS_LOG(a) do { } while (0) 73 #endif 42 74 43 75 … … 95 127 { 96 128 /** The of the loaded image bits. */ 97 size_tcbImage;129 KSIZE cbImage; 98 130 /** Where we load the image. */ 99 131 void *pvLoad; … … 106 138 KWMODSTATE enmState; 107 139 /** Number of imported modules. */ 108 size_tcImpMods;140 KSIZE cImpMods; 109 141 /** Import array (variable size). */ 110 142 PKWMODULE apImpMods[1]; … … 137 169 PKWMODULE pMod; 138 170 } KWDYNLOAD; 171 172 173 typedef struct KWFSOBJ *PKWFSOBJ; 174 typedef struct KWFSOBJ 175 { 176 /** The object name. (Allocated after the structure.) */ 177 const char *pszName; 178 /** The UTF-16 object name. (Allocated after the structure.) */ 179 const wchar_t *pwszName; 180 /** The length of pszName. */ 181 KU16 cchName; 182 /** The length of UTF-16 (in wchar_t's). */ 183 KU16 cwcName; 184 185 /** The number of child objects. */ 186 KU32 cChildren; 187 /** Child objects. */ 188 PKWFSOBJ *papChildren; 189 /** Pointer to the parent. */ 190 PKWFSOBJ pParent; 191 192 /** The cache generation, KFSWOBJ_CACHE_GEN_IGNORE. */ 193 KU32 uCacheGen; 194 /** The GetFileAttributes result for the file. 195 * FILE_ATTRIBUTE_XXX or INVALID_FILE_ATTRIBUTES. */ 196 KU32 fAttribs; 197 /** The GetLastError() for INVALI_FILE_ATTRIBUTES. */ 198 KU32 uLastError; 199 200 /** Cached file handle. */ 201 HANDLE hCached; 202 /** The file size. */ 203 KSIZE cbCached; 204 /** Cached file content. */ 205 KU8 *pbCached; 206 } KWFSOBJ; 207 208 209 /** Pointer to an ANSI path hash table entry. */ 210 typedef struct KWFSHASHA *PKWFSHASHA; 211 /** 212 * ANSI file system path hash table entry. 213 * The path hash table allows us to skip parsing and walking a path. 214 */ 215 typedef struct KWFSHASHA 216 { 217 /** Next entry with the same hash. */ 218 PKWFSHASHA pNext; 219 /** Path hash value. */ 220 KU32 uHashPath; 221 /** The path length. */ 222 KU32 cchPath; 223 /** The path. (Allocated after the structure.) */ 224 const char *pszPath; 225 /** Pointer to the matching FS object. */ 226 PKWFSOBJ pFsObj; 227 } KWFSHASHA; 228 229 230 /** Pointer to an UTF-16 path hash table entry. */ 231 typedef struct KWFSHASHW *PKWFSHASHW; 232 /** 233 * UTF-16 file system path hash table entry. The path hash table allows us 234 * to skip parsing and walking a path. 235 */ 236 typedef struct KWFSHASHW 237 { 238 /** Next entry with the same hash. */ 239 PKWFSHASHW pNext; 240 /** Path hash value. */ 241 KU32 uHashPath; 242 /** The path length (in wchar_t units). */ 243 KU32 cwcPath; 244 /** The path. (Allocated after the structure.) */ 245 const wchar_t *pwszPath; 246 /** Pointer to the matching FS object. */ 247 PKWFSOBJ pFsObj; 248 } KWFSHASHW; 139 249 140 250 … … 263 373 static PKWTOOL g_apTools[63]; 264 374 375 /** Special file system root (parent to the drive letters). */ 376 static KWFSOBJ g_FsRoot = 377 { 378 /* .pszName = */ "", 379 /* .pwszName = */ L"", 380 /* .cchName = */ 0, 381 /* .cwcName = */ 0, 382 /* .cChildren = */ 0, 383 /* .papChildren = */ NULL, 384 /* .pParent = */ NULL, 385 /* .uCacheGen = */ KFSWOBJ_CACHE_GEN_IGNORE, 386 /* .fAttribs = */ FILE_ATTRIBUTE_DIRECTORY, 387 /* .uLastError = */ ERROR_PATH_NOT_FOUND, 388 /* .hCached = */ INVALID_HANDLE_VALUE, 389 /* .cbCached = */ 0, 390 /* .pbCached = */ NULL, 391 }; 392 /** File system hash table for ANSI filename strings. */ 393 static PKWFSHASHA g_apFsAnsiPaths[1021]; 394 /** File system hash table for UTF-16 filename strings. */ 395 static PKWFSHASHW g_apFsUtf16Paths[1021]; 396 /** Special file system object returned if the path is invalid. */ 397 static KWFSOBJ g_FsPathNotFound = 398 { 399 /* .pszName = */ "", 400 /* .pwszName = */ L"", 401 /* .cchName = */ 0, 402 /* .cwcName = */ 0, 403 /* .cChildren = */ 0, 404 /* .papChildren = */ NULL, 405 /* .pParent = */ NULL, 406 /* .uCacheGen = */ KFSWOBJ_CACHE_GEN_IGNORE, 407 /* .fAttribs = */ FILE_ATTRIBUTE_DIRECTORY, 408 /* .uLastError = */ ERROR_PATH_NOT_FOUND, 409 /* .hCached = */ INVALID_HANDLE_VALUE, 410 /* .cbCached = */ 0, 411 /* .pbCached = */ NULL, 412 }; 413 /** The cache generation number, incremented for each sandboxed execution. 414 * This is used to invalid negative results from parts of the file system. */ 415 static KU32 g_uFsCacheGeneration = 0; 416 417 /** Verbosity level. */ 265 418 static int g_cVerbose = 2; 266 419 … … 268 421 extern KWREPLACEMENTFUNCTION const g_aSandboxReplacements[]; 269 422 extern KU32 const g_cSandboxReplacements; 423 424 extern KWREPLACEMENTFUNCTION const g_aSandboxNativeReplacements[]; 425 extern KU32 const g_cSandboxNativeReplacements; 270 426 271 427 /** Create a larget BSS blob that with help of /IMAGEBASE:0x10000 should … … 282 438 static FNKLDRMODGETIMPORT kwLdrModuleGetImportCallback; 283 439 static int kwLdrModuleResolveAndLookup(const char *pszName, PKWMODULE pExe, PKWMODULE pImporter, PKWMODULE *ppMod); 440 static PKWFSOBJ kwFsLookupA(const char *pszPath); 284 441 285 442 … … 294 451 if (g_cVerbose >= 2) 295 452 { 453 DWORD const dwSavedErr = GetLastError(); 454 296 455 fprintf(stderr, "debug: "); 297 456 vfprintf(stderr, pszFormat, va); 457 458 SetLastError(dwSavedErr); 298 459 } 299 460 } … … 326 487 if (IsDebuggerPresent()) 327 488 { 489 DWORD const dwSavedErr = GetLastError(); 328 490 char szTmp[2048]; 491 329 492 _vsnprintf(szTmp, sizeof(szTmp), pszFormat, va); 330 493 OutputDebugStringA(szTmp); 494 495 SetLastError(dwSavedErr); 331 496 } 332 497 } … … 355 520 static void kwErrPrintfV(const char *pszFormat, va_list va) 356 521 { 522 DWORD const dwSavedErr = GetLastError(); 523 357 524 fprintf(stderr, "error: "); 358 525 vfprintf(stderr, pszFormat, va); 526 527 SetLastError(dwSavedErr); 359 528 } 360 529 … … 374 543 375 544 545 #ifdef K_STRICT 546 547 KHLP_DECL(void) kHlpAssertMsg1(const char *pszExpr, const char *pszFile, unsigned iLine, const char *pszFunction) 548 { 549 DWORD const dwSavedErr = GetLastError(); 550 551 fprintf(stderr, 552 "\n" 553 "!!Assertion failed!!\n" 554 "Expression: %s\n" 555 "Function : %s\n" 556 "File: %s\n" 557 "Line: %d\n" 558 , pszExpr, pszFunction, pszFile, iLine); 559 560 SetLastError(dwSavedErr); 561 } 562 563 564 KHLP_DECL(void) kHlpAssertMsg2(const char *pszFormat, ...) 565 { 566 DWORD const dwSavedErr = GetLastError(); 567 va_list va; 568 569 va_start(va, pszFormat); 570 fprintf(stderr, pszFormat, va); 571 va_end(va); 572 573 SetLastError(dwSavedErr); 574 } 575 576 #endif /* K_STRICT */ 577 578 376 579 /** 377 580 * Normalizes the path so we get a consistent hash. … … 382 585 * @param cbNormPath The size of the output buffer. 383 586 */ 384 static int kwPathNormalize(const char *pszPath, char *pszNormPath, size_tcbNormPath)587 static int kwPathNormalize(const char *pszPath, char *pszNormPath, KSIZE cbNormPath) 385 588 { 386 589 char *pchSlash; … … 424 627 425 628 629 /** 630 * Hashes a string. 631 * 632 * @returns The string length. 633 * @param pszString String to hash. 634 * @param puHash Where to return the 32-bit string hash. 635 */ 636 static KSIZE kwStrHashEx(const char *pszString, KU32 *puHash) 637 { 638 const char * const pszStart = pszString; 639 KU32 uHash = 0; 640 KU32 uChar; 641 while ((uChar = (unsigned char)*pszString) != 0) 642 { 643 uHash = uChar + (uHash << 6) + (uHash << 16) - uHash; 644 pszString++; 645 } 646 *puHash = uHash; 647 return pszString - pszStart; 648 } 649 650 651 /** 652 * Hashes a string. 653 * 654 * @returns The string length in wchar_t units. 655 * @param pwszString String to hash. 656 * @param puHash Where to return the 32-bit string hash. 657 */ 658 static KSIZE kwUtf16HashEx(const wchar_t *pwszString, KU32 *puHash) 659 { 660 const wchar_t * const pwszStart = pwszString; 661 KU32 uHash = 0; 662 KU32 uChar; 663 while ((uChar = *pwszString) != 0) 664 { 665 uHash = uChar + (uHash << 6) + (uHash << 16) - uHash; 666 pwszString++; 667 } 668 *puHash = uHash; 669 return pwszString - pwszStart; 670 } 671 426 672 427 673 /** … … 433 679 * @param cwcDst The size of the destination buffer in wchar_t's. 434 680 */ 435 static size_t kwStrToUtf16(const char *pszSrc, wchar_t *pwszDst, size_tcwcDst)681 static KSIZE kwStrToUtf16(const char *pszSrc, wchar_t *pwszDst, KSIZE cwcDst) 436 682 { 437 683 /* Just to the quick ASCII stuff for now. correct ansi code page stuff later some time. */ 438 size_toffDst = 0;684 KSIZE offDst = 0; 439 685 while (offDst < cwcDst) 440 686 { … … 459 705 * @param cbDst The size of the destination buffer in bytes. 460 706 */ 461 static size_t kwUtf16ToStr(const wchar_t *pwszSrc, char *pszDst, size_tcbDst)707 static KSIZE kwUtf16ToStr(const wchar_t *pwszSrc, char *pszDst, KSIZE cbDst) 462 708 { 463 709 /* Just to the quick ASCII stuff for now. correct ansi code page stuff later some time. */ 464 size_toffDst = 0;710 KSIZE offDst = 0; 465 711 while (offDst < cbDst) 466 712 { … … 500 746 if (cwcDst > 0) 501 747 { 502 size_tcwcDstTmp = cwcDst - 1;748 KSIZE cwcDstTmp = cwcDst - 1; 503 749 pwszDst[cwcDstTmp] = '\0'; 504 750 if (cwcDstTmp > 0) … … 523 769 if (cbDst > 0) 524 770 { 525 size_tcbDstTmp = cbDst - 1;771 KSIZE cbDstTmp = cbDst - 1; 526 772 pszDst[cbDstTmp] = '\0'; 527 773 if (cbDstTmp > 0) … … 621 867 622 868 /** 869 * Replaces imports for this module according to g_aSandboxNativeReplacements. 870 * 871 * @param pMod The natively loaded module to process. 872 */ 873 static void kwLdrModuleDoNativeImportReplacements(PKWMODULE pMod) 874 { 875 KSIZE const cbImage = kLdrModSize(pMod->pLdrMod); 876 KU8 const * const pbImage = (KU8 const *)pMod->hOurMod; 877 IMAGE_DOS_HEADER const *pMzHdr = (IMAGE_DOS_HEADER const *)pbImage; 878 IMAGE_NT_HEADERS const *pNtHdrs; 879 IMAGE_DATA_DIRECTORY const *pDirEnt; 880 881 kHlpAssert(pMod->fNative); 882 883 /* 884 * Locate the export descriptors. 885 */ 886 /* MZ header. */ 887 if (pMzHdr->e_magic == IMAGE_DOS_SIGNATURE) 888 { 889 kHlpAssertReturnVoid(pMzHdr->e_lfanew <= cbImage - sizeof(*pNtHdrs)); 890 pNtHdrs = (IMAGE_NT_HEADERS const *)&pbImage[pMzHdr->e_lfanew]; 891 } 892 else 893 pNtHdrs = (IMAGE_NT_HEADERS const *)pbImage; 894 895 /* Check PE header. */ 896 kHlpAssertReturnVoid(pNtHdrs->Signature == IMAGE_NT_SIGNATURE); 897 kHlpAssertReturnVoid(pNtHdrs->FileHeader.SizeOfOptionalHeader == sizeof(pNtHdrs->OptionalHeader)); 898 899 /* Locate the import descriptor array. */ 900 pDirEnt = (IMAGE_DATA_DIRECTORY const *)&pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; 901 if ( pDirEnt->Size > 0 902 && pDirEnt->VirtualAddress != 0) 903 { 904 const IMAGE_IMPORT_DESCRIPTOR *pImpDesc = (const IMAGE_IMPORT_DESCRIPTOR *)&pbImage[pDirEnt->VirtualAddress]; 905 KU32 cLeft = pDirEnt->Size / sizeof(*pImpDesc); 906 MEMORY_BASIC_INFORMATION ProtInfo = { NULL, NULL, 0, 0, 0, 0, 0 }; 907 KU8 *pbProtRange = NULL; 908 SIZE_T cbProtRange = 0; 909 DWORD fOldProt = 0; 910 KU32 const cbPage = 0x1000; 911 BOOL fRc; 912 913 914 kHlpAssertReturnVoid(pDirEnt->VirtualAddress < cbImage); 915 kHlpAssertReturnVoid(pDirEnt->Size < cbImage); 916 kHlpAssertReturnVoid(pDirEnt->VirtualAddress + pDirEnt->Size <= cbImage); 917 918 /* 919 * Walk the import descriptor array. 920 * Note! This only works if there's a backup thunk array, otherwise we cannot get at the name. 921 */ 922 while ( cLeft-- > 0 923 && pImpDesc->Name > 0 924 && pImpDesc->FirstThunk > 0) 925 { 926 KU32 iThunk; 927 const char * const pszImport = (const char *)&pbImage[pImpDesc->Name]; 928 PIMAGE_THUNK_DATA paThunks = (PIMAGE_THUNK_DATA)&pbImage[pImpDesc->FirstThunk]; 929 PIMAGE_THUNK_DATA paOrgThunks = (PIMAGE_THUNK_DATA)&pbImage[pImpDesc->OriginalFirstThunk]; 930 kHlpAssertReturnVoid(pImpDesc->Name < cbImage); 931 kHlpAssertReturnVoid(pImpDesc->FirstThunk < cbImage); 932 kHlpAssertReturnVoid(pImpDesc->OriginalFirstThunk < cbImage); 933 kHlpAssertReturnVoid(pImpDesc->OriginalFirstThunk != pImpDesc->FirstThunk); 934 kHlpAssertReturnVoid(pImpDesc->OriginalFirstThunk); 935 936 /* Iterate the thunks. */ 937 for (iThunk = 0; paOrgThunks[iThunk].u1.Ordinal != 0; iThunk++) 938 { 939 KUPTR const off = paOrgThunks[iThunk].u1.Function; 940 kHlpAssertReturnVoid(off < cbImage); 941 if (!IMAGE_SNAP_BY_ORDINAL(off)) 942 { 943 IMAGE_IMPORT_BY_NAME const *pName = (IMAGE_IMPORT_BY_NAME const *)&pbImage[off]; 944 KSIZE const cchSymbol = kHlpStrLen(pName->Name); 945 KU32 i = g_cSandboxNativeReplacements; 946 while (i-- > 0) 947 if ( g_aSandboxNativeReplacements[i].cchFunction == cchSymbol 948 && kHlpMemComp(g_aSandboxNativeReplacements[i].pszFunction, pName->Name, cchSymbol) == 0) 949 { 950 if ( !g_aSandboxNativeReplacements[i].pszModule 951 || kHlpStrICompAscii(g_aSandboxNativeReplacements[i].pszModule, pszImport) == 0) 952 { 953 KW_LOG(("%s: replacing %s!%s\n", pMod->pLdrMod->pszName, pszImport, pName->Name)); 954 955 /* The .rdata section is normally read-only, so we need to make it writable first. */ 956 if ((KUPTR)&paThunks[iThunk] - (KUPTR)pbProtRange >= cbPage) 957 { 958 /* Restore previous .rdata page. */ 959 if (fOldProt) 960 { 961 fRc = VirtualProtect(pbProtRange, cbProtRange, fOldProt, NULL /*pfOldProt*/); 962 kHlpAssert(fRc); 963 fOldProt = 0; 964 } 965 966 /* Query attributes for the current .rdata page. */ 967 pbProtRange = (KU8 *)((KUPTR)&paThunks[iThunk] & ~(KUPTR)(cbPage - 1)); 968 cbProtRange = VirtualQuery(pbProtRange, &ProtInfo, sizeof(ProtInfo)); 969 kHlpAssert(cbProtRange); 970 if (cbProtRange) 971 { 972 switch (ProtInfo.Protect) 973 { 974 case PAGE_READWRITE: 975 case PAGE_WRITECOPY: 976 case PAGE_EXECUTE_READWRITE: 977 case PAGE_EXECUTE_WRITECOPY: 978 /* Already writable, nothing to do. */ 979 break; 980 981 default: 982 kHlpAssertMsgFailed(("%#x\n", ProtInfo.Protect)); 983 case PAGE_READONLY: 984 cbProtRange = cbPage; 985 fRc = VirtualProtect(pbProtRange, cbProtRange, PAGE_READWRITE, &fOldProt); 986 break; 987 988 case PAGE_EXECUTE: 989 case PAGE_EXECUTE_READ: 990 cbProtRange = cbPage; 991 fRc = VirtualProtect(pbProtRange, cbProtRange, PAGE_EXECUTE_READWRITE, &fOldProt); 992 break; 993 } 994 kHlpAssertStmt(fRc, fOldProt = 0); 995 } 996 } 997 998 paThunks[iThunk].u1.AddressOfData = g_aSandboxNativeReplacements[i].pfnReplacement; 999 break; 1000 } 1001 } 1002 } 1003 } 1004 1005 1006 /* Next import descriptor. */ 1007 pImpDesc++; 1008 } 1009 1010 1011 if (fOldProt) 1012 { 1013 DWORD fIgnore = 0; 1014 fRc = VirtualProtect(pbProtRange, cbProtRange, fOldProt, &fIgnore); 1015 kHlpAssertMsg(fRc, ("%u\n", GetLastError())); K_NOREF(fRc); 1016 } 1017 } 1018 1019 } 1020 1021 1022 /** 623 1023 * Creates a module using the native loader. 624 1024 * … … 626 1026 * @param pszPath The normalized path to the module. 627 1027 * @param uHashPath The module path hash. 628 */ 629 static PKWMODULE kwLdrModuleCreateNative(const char *pszPath, KU32 uHashPath) 1028 * @param fDoReplacements Whether to do import replacements on this 1029 * module. 1030 */ 1031 static PKWMODULE kwLdrModuleCreateNative(const char *pszPath, KU32 uHashPath, KBOOL fDoReplacements) 630 1032 { 631 1033 /* … … 653 1055 pMod->pLdrMod = pLdrMod; 654 1056 pMod->hOurMod = (HMODULE)(KUPTR)pLdrMod->aSegments[0].MapAddress; 655 kwDbgPrintf("New module: %p LB %#010x %s (native)\n", 656 (KUPTR)pMod->pLdrMod->aSegments[0].MapAddress, kLdrModSize(pMod->pLdrMod), pMod->pszPath); 1057 1058 if (fDoReplacements) 1059 { 1060 DWORD const dwSavedErr = GetLastError(); 1061 kwLdrModuleDoNativeImportReplacements(pMod); 1062 SetLastError(dwSavedErr); 1063 } 1064 1065 KW_LOG(("New module: %p LB %#010x %s (native)\n", 1066 (KUPTR)pMod->pLdrMod->aSegments[0].MapAddress, kLdrModSize(pMod->pLdrMod), pMod->pszPath)); 657 1067 return kwLdrModuleLink(pMod); 658 1068 } … … 757 1167 if (!fExe) 758 1168 kwLdrModuleLink(pMod); 759 kwDbgPrintf("New module: %p LB %#010x %s (kLdr)\n",760 pMod->u.Manual.pvLoad, pMod->u.Manual.cbImage, pMod->pszPath);1169 KW_LOG(("New module: %p LB %#010x %s (kLdr)\n", 1170 pMod->u.Manual.pvLoad, pMod->u.Manual.cbImage, pMod->pszPath)); 761 1171 kwDebuggerPrintf("TODO: .reload /f %s=%p\n", pMod->pszPath, pMod->u.Manual.pvLoad); 762 1172 … … 838 1248 || kHlpStrICompAscii(g_aSandboxReplacements[i].pszModule, &pImpMod->pszPath[pImpMod->offFilename]) == 0) 839 1249 { 840 kwDbgPrintf("replacing %s!%s\n", &pImpMod->pszPath[pImpMod->offFilename], g_aSandboxReplacements[i].pszFunction);1250 KW_LOG(("replacing %s!%s\n", &pImpMod->pszPath[pImpMod->offFilename], g_aSandboxReplacements[i].pszFunction)); 841 1251 *puValue = g_aSandboxReplacements[i].pfnReplacement; 1252 break; 842 1253 } 843 1254 } … … 870 1281 871 1282 1283 /** 1284 * Whether to apply g_aSandboxNativeReplacements to the imports of this module. 1285 * 1286 * @returns K_TRUE/K_FALSE. 1287 * @param pszFilename The filename (no path). 1288 * @param enmLocation The location. 1289 */ 1290 static KBOOL kwLdrModuleShouldDoNativeReplacements(const char *pszFilename, KWLOCATION enmLocation) 1291 { 1292 if (enmLocation != KWLOCATION_SYSTEM32) 1293 return K_TRUE; 1294 return kHlpStrNICompAscii(pszFilename, TUPLE("msvc")) == 0 1295 || kHlpStrNICompAscii(pszFilename, TUPLE("msdis")) == 0 1296 || kHlpStrNICompAscii(pszFilename, TUPLE("mspdb")) == 0; 1297 } 1298 1299 1300 /** 1301 * Whether we can load this DLL natively or not. 1302 * 1303 * @returns K_TRUE/K_FALSE. 1304 * @param pszFilename The filename (no path). 1305 * @param enmLocation The location. 1306 */ 872 1307 static KBOOL kwLdrModuleCanLoadNatively(const char *pszFilename, KWLOCATION enmLocation) 873 1308 { … … 876 1311 if (enmLocation == KWLOCATION_UNKNOWN_NATIVE) 877 1312 return K_TRUE; 878 return kHlpStrICompAscii(pszFilename, "msvcrt.dll") == 0 879 || kHlpStrNICompAscii(pszFilename, "msvc", 4) == 0 880 || kHlpStrNICompAscii(pszFilename, "msdis", 5) == 0 881 || kHlpStrNICompAscii(pszFilename, "mspdb", 5) == 0; 1313 return kHlpStrNICompAscii(pszFilename, TUPLE("msvc")) == 0 1314 || kHlpStrNICompAscii(pszFilename, TUPLE("msdis")) == 0 1315 || kHlpStrNICompAscii(pszFilename, TUPLE("mspdb")) == 0; 882 1316 } 883 1317 … … 915 1349 if (rc == 0) 916 1350 { 917 KU32 const uHashPath = kwStrHash(szNormPath); 918 unsigned idxHash = uHashPath % K_ELEMENTS(g_apModules); 919 PKWMODULE pMod = g_apModules[idxHash]; 1351 const char *pszName; 1352 KU32 const uHashPath = kwStrHash(szNormPath); 1353 unsigned idxHash = uHashPath % K_ELEMENTS(g_apModules); 1354 PKWMODULE pMod = g_apModules[idxHash]; 920 1355 if (pMod) 921 1356 { … … 932 1367 * Not in the hash table, so we have to load it from scratch. 933 1368 */ 934 if (kwLdrModuleCanLoadNatively(kHlpGetFilename(szNormPath), enmLocation)) 935 pMod = kwLdrModuleCreateNative(szNormPath, uHashPath); 1369 pszName = kHlpGetFilename(szNormPath); 1370 if (kwLdrModuleCanLoadNatively(pszName, enmLocation)) 1371 pMod = kwLdrModuleCreateNative(szNormPath, uHashPath, 1372 kwLdrModuleShouldDoNativeReplacements(pszName, enmLocation)); 936 1373 else 937 1374 pMod = kwLdrModuleCreateNonNative(szNormPath, uHashPath, K_FALSE /*fExe*/, pExeMod); … … 1125 1562 return NULL; 1126 1563 } 1564 1565 1566 1567 /* 1568 * 1569 * File system cache. 1570 * File system cache. 1571 * File system cache. 1572 * 1573 */ 1574 1575 1576 #define IS_ALPHA(ch) ( ((ch) >= 'A' && (ch) <= 'Z') || ((ch) >= 'a' && (ch) <= 'z') ) 1577 #define IS_SLASH(ch) ((ch) == '\\' || (ch) == '/') 1578 1579 1580 /** 1581 * Helper for getting the extension of a UTF-16 path. 1582 * 1583 * @returns Pointer to the extension or the terminator. 1584 * @param pwszPath The path. 1585 * @param pcwcExt Where to return the length of the extension. 1586 */ 1587 static wchar_t const *kwFsPathGetExtW(wchar_t const *pwszPath, KSIZE *pcwcExt) 1588 { 1589 wchar_t const *pwszName = pwszPath; 1590 wchar_t const *pwszExt = NULL; 1591 for (;;) 1592 { 1593 wchar_t const wc = *pwszPath++; 1594 if (wc == '.') 1595 pwszExt = pwszPath; 1596 else if (wc == '/' || wc == '\\' || wc == ':') 1597 { 1598 pwszName = pwszPath; 1599 pwszExt = NULL; 1600 } 1601 else if (wc == '\0') 1602 { 1603 if (pwszExt) 1604 { 1605 *pcwcExt = pwszPath - pwszExt - 1; 1606 return pwszExt; 1607 } 1608 *pcwcExt = 0; 1609 return pwszPath - 1; 1610 } 1611 } 1612 } 1613 1614 1615 /** 1616 * Looks for '..' in the path. 1617 * 1618 * @returns K_TRUE if '..' component found, K_FALSE if not. 1619 * @param pszPath The path. 1620 * @param cchPath The length of the path. 1621 */ 1622 static KBOOL kwFsHasDotDot(const char *pszPath, KSIZE cchPath) 1623 { 1624 const char *pchDot = (const char *)kHlpMemChr(pszPath, '.', cchPath); 1625 while (pchDot) 1626 { 1627 if (pchDot[1] != '.') 1628 pchDot = (const char *)kHlpMemChr(pchDot + 1, '.', &pszPath[cchPath] - pchDot - 1); 1629 else 1630 { 1631 char ch; 1632 if ( (ch = pchDot[2]) == '\0' 1633 && IS_SLASH(ch)) 1634 { 1635 if (pchDot == pszPath) 1636 return K_TRUE; 1637 ch = pchDot[-1]; 1638 if ( IS_SLASH(ch) 1639 || ch == ':') 1640 return K_TRUE; 1641 } 1642 pchDot = (const char *)kHlpMemChr(pchDot + 2, '.', &pszPath[cchPath] - pchDot - 2); 1643 } 1644 } 1645 1646 return K_FALSE; 1647 } 1648 1649 1650 static void kwFsCreateHashTabEntryA(PKWFSOBJ pFsObj, const char *pszPath, KU32 cchPath, KU32 uHashPath, KU32 idxHashTab) 1651 { 1652 PKWFSHASHA pHashEntry = (PKWFSHASHA)kHlpAlloc(sizeof(*pHashEntry) + cchPath + 1); 1653 if (pHashEntry) 1654 { 1655 pHashEntry->uHashPath = uHashPath; 1656 pHashEntry->cchPath = cchPath; 1657 pHashEntry->pszPath = (const char *)kHlpMemCopy(pHashEntry + 1, pszPath, cchPath + 1); 1658 pHashEntry->pFsObj = pFsObj; 1659 1660 pHashEntry->pNext = g_apFsAnsiPaths[idxHashTab]; 1661 g_apFsAnsiPaths[idxHashTab] = pHashEntry; 1662 } 1663 } 1664 1665 1666 /** 1667 * Refreshes a node that hash expired. 1668 * 1669 * This is for files and directories in the output directory tree. The plan is 1670 * to invalid negative results for each tool execution, in case a include file 1671 * or directory has been created since the last time we were active. Assuming 1672 * that we'll be stopped together with kmk, there is no need to invalidate 1673 * positive results. 1674 * 1675 * @param pNode The FS node. 1676 */ 1677 static void kwFsRefreshNode(PKWFSOBJ pNode) 1678 { 1679 /** @todo implement once we've start inserting uCacheGen nodes. */ 1680 __debugbreak(); 1681 } 1682 1683 1684 /** 1685 * Links the child in under the parent. 1686 * 1687 * @returns K_TRUE on success, K_FALSE if out of memory. 1688 * @param pParent The parent node. 1689 * @param pChild The child node. 1690 */ 1691 static KBOOL kwFsLinkChild(PKWFSOBJ pParent, PKWFSOBJ pChild) 1692 { 1693 if ((pParent->cChildren % 16) == 0) 1694 { 1695 void *pvNew = kHlpRealloc(pParent->papChildren, (pParent->cChildren + 16) * sizeof(pParent->papChildren[0])); 1696 if (!pvNew) 1697 return K_FALSE; 1698 pParent->papChildren = (PKWFSOBJ *)pvNew; 1699 } 1700 pParent->papChildren[pParent->cChildren++] = pChild; 1701 return K_TRUE; 1702 } 1703 1704 1705 /** 1706 * Creates a child node for an ANSI path. 1707 * 1708 * @returns Pointer to the child tree node on success. 1709 * NULL on failure (out of memory). 1710 * @param pParent The parent node. 1711 * @param pchPath The path. 1712 * @param offName The offset of the child name into pchPath. 1713 * @param cchName The length of the child name. 1714 */ 1715 static PKWFSOBJ kwFsCreateChildA(PKWFSOBJ pParent, const char *pchPath, KU32 offName, KU32 cchName) 1716 { 1717 char szTmp[2048]; 1718 DWORD const dwSavedErr = GetLastError(); 1719 DWORD dwAttr; 1720 DWORD dwErr; 1721 PKWFSOBJ pChild; 1722 1723 /* 1724 * Get attributes. 1725 */ 1726 if (pchPath[offName + cchName]) 1727 { 1728 if (cchName + offName >= sizeof(szTmp)) 1729 return NULL; 1730 memcpy(szTmp, pchPath, offName + cchName); 1731 if (offName != 0 || cchName != 2 || pchPath[1] != ':') 1732 szTmp[offName + cchName] = '\0'; 1733 else 1734 { 1735 /* Change 'E:' to 'E:\\.' so that it's actually absolute. */ 1736 szTmp[2] = '\\'; 1737 szTmp[3] = '.'; 1738 szTmp[4] = '\0'; 1739 } 1740 pchPath = szTmp; 1741 } 1742 1743 SetLastError(NO_ERROR); 1744 dwAttr = GetFileAttributesA(pchPath); 1745 dwErr = GetLastError(); 1746 1747 /* 1748 * Create the entry. 1749 */ 1750 pChild = (PKWFSOBJ)kHlpAlloc(sizeof(*pChild) + cchName + 1 + (cchName + 1) * sizeof(wchar_t) * 2); 1751 SetLastError(dwSavedErr); 1752 if (pChild) 1753 { 1754 pChild->pwszName = (const wchar_t *)(pChild + 1); 1755 pChild->pszName = (const char *)kHlpMemCopy((void *)&pChild->pwszName[(cchName + 1) * 2], 1756 &pchPath[offName], cchName); 1757 ((char *)pChild->pszName)[cchName] = '\0'; 1758 pChild->cwcName = (KU16)kwStrToUtf16(pChild->pszName, (wchar_t *)pChild->pwszName, (cchName + 1) * 2); 1759 1760 pChild->cchName = cchName; 1761 pChild->cChildren = 0; 1762 pChild->papChildren = NULL; 1763 pChild->pParent = pParent; 1764 1765 pChild->uCacheGen = pParent->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE ? KFSWOBJ_CACHE_GEN_IGNORE : g_uFsCacheGeneration; 1766 pChild->fAttribs = dwAttr; 1767 pChild->uLastError = dwErr; 1768 1769 pChild->hCached = INVALID_HANDLE_VALUE; 1770 pChild->cbCached = 0; 1771 pChild->pbCached = NULL; 1772 1773 if (kwFsLinkChild(pParent, pChild)) 1774 return pChild; 1775 1776 kHlpFree(pChild); 1777 } 1778 return NULL; 1779 } 1780 1781 1782 /** 1783 * Look up a child node, ANSI version. 1784 * 1785 * @returns Pointer to the child if found, NULL if not. 1786 * @param pParent The parent to search the children of. 1787 * @param pchName The child name to search for (not terminated). 1788 * @param cchName The length of the child name. 1789 */ 1790 static PKWFSOBJ kwFsFindChildA(PKWFSOBJ pParent, const char *pchName, KU32 cchName) 1791 { 1792 /* Check for '.' first. */ 1793 if (cchName != 1 || *pchName != '.') 1794 { 1795 KU32 cLeft = pParent->cChildren; 1796 PKWFSOBJ *ppCur = pParent->papChildren; 1797 while (cLeft-- > 0) 1798 { 1799 PKWFSOBJ pCur = *ppCur++; 1800 if ( pCur->cchName == cchName 1801 && _memicmp(pCur->pszName, pchName, cchName) == 0) 1802 { 1803 if ( pCur->uCacheGen != KFSWOBJ_CACHE_GEN_IGNORE 1804 && pCur->uCacheGen != g_uFsCacheGeneration) 1805 kwFsRefreshNode(pCur); 1806 return pCur; 1807 } 1808 } 1809 return NULL; 1810 } 1811 return pParent; 1812 } 1813 1814 1815 /** 1816 * Walk the file system tree for the given absolute path, entering it into the 1817 * hash table. 1818 * 1819 * This will create any missing nodes while walking. 1820 * 1821 * @returns Pointer to the tree node corresponding to @a pszPath. 1822 * NULL if we ran out of memory. 1823 * @param pszPath The path to walk. 1824 * @param cchPath The length of the path. 1825 * @param uHashPath The hash of the path. 1826 * @param idxHashTab Index into the hash table. 1827 */ 1828 static PKWFSOBJ kwFsLookupAbsoluteA(const char *pszPath, KU32 cchPath, KU32 uHashPath, KU32 idxHashTab) 1829 { 1830 PKWFSOBJ pParent = &g_FsRoot; 1831 KU32 off; 1832 KWFS_LOG(("kwFsLookupAbsoluteA(%s)\n", pszPath)); 1833 1834 kHlpAssert(IS_ALPHA(pszPath[0])); 1835 kHlpAssert(pszPath[1] == ':'); 1836 kHlpAssert(IS_SLASH(pszPath[2])); 1837 1838 off = 0; 1839 for (;;) 1840 { 1841 PKWFSOBJ pChild; 1842 1843 /* Find the end of the component. */ 1844 char ch; 1845 KU32 cchSlashes = 0; 1846 KU32 offEnd = off + 1; 1847 while ((ch = pszPath[offEnd]) != '\0') 1848 { 1849 if (!IS_SLASH(ch)) 1850 offEnd++; 1851 else 1852 { 1853 do 1854 cchSlashes++; 1855 while (IS_SLASH(pszPath[offEnd + cchSlashes])); 1856 break; 1857 } 1858 } 1859 1860 /* Search the current node for the name. */ 1861 pChild = kwFsFindChildA(pParent, &pszPath[off], offEnd - off); 1862 if (!pChild) 1863 { 1864 pChild = kwFsCreateChildA(pParent, pszPath, off, offEnd - off); 1865 if (!pChild) 1866 break; 1867 } 1868 off = offEnd + cchSlashes; 1869 if ( cchSlashes == 0 1870 || off >= cchPath) 1871 { 1872 kwFsCreateHashTabEntryA(pChild, pszPath, cchPath, uHashPath, idxHashTab); 1873 return pChild; 1874 } 1875 1876 /* Check that it's a directory (won't match INVALID_FILE_ATTRIBUTES). */ 1877 if (!(pChild->fAttribs & FILE_ATTRIBUTE_DIRECTORY)) 1878 return &g_FsPathNotFound; 1879 1880 pParent = pChild; 1881 } 1882 1883 return NULL; 1884 } 1885 1886 1887 /** 1888 * This deals with paths that are relative and paths that contains '..' 1889 * elements. 1890 * 1891 * @returns Pointer to object corresponding to @a pszPath on success. 1892 * NULL if this isn't a path we care to cache. 1893 * @param pszPath The path. 1894 * @param cchPath The length of the path. 1895 * @param uHashPath The hash of the path. 1896 * @param idxHashTab The path table index. 1897 */ 1898 static PKWFSOBJ kwFsLookupSlowA(const char *pszPath, KU32 cchPath, KU32 uHashPath, KU32 idxHashTab) 1899 { 1900 /* Turns out getcwd/_getdcwd uses GetFullPathName internall, so just call it directly here. */ 1901 char szFull[2048]; 1902 UINT cchFull = GetFullPathNameA(pszPath, sizeof(szFull), szFull, NULL); 1903 if ( cchFull >= 3 1904 && cchFull < sizeof(szFull)) 1905 { 1906 KWFS_LOG(("kwFsLookupSlowA(%s)\n", pszPath)); 1907 if ( szFull[1] == ':' 1908 && IS_SLASH(szFull[2]) 1909 && IS_ALPHA(szFull[0]) ) 1910 { 1911 KU32 uHashPath2 = kwStrHash(szFull); 1912 PKWFSOBJ pFsObj = kwFsLookupAbsoluteA(szFull, cchFull, uHashPath2, uHashPath2 % K_ELEMENTS(g_apFsAnsiPaths)); 1913 if (pFsObj) 1914 { 1915 kwFsCreateHashTabEntryA(pFsObj, pszPath, cchPath, uHashPath, idxHashTab); 1916 return pFsObj; 1917 } 1918 } 1919 1920 /* It's worth remembering uncacheable paths in the hash table. */ 1921 kwFsCreateHashTabEntryA(NULL /*pFsObj*/, pszPath, cchPath, uHashPath, idxHashTab); 1922 } 1923 return NULL; 1924 } 1925 1926 1927 /** 1928 * Looks up a KWFSOBJ for the given ANSI path. 1929 * 1930 * This will first try the hash table. If not in the hash table, the file 1931 * system cache tree is walked, missing bits filled in and finally a hash table 1932 * entry is created. 1933 * 1934 * Only drive letter paths are cachable. We don't do any UNC paths at this 1935 * point. 1936 * 1937 * 1938 * @returns Pointer to object corresponding to @a pszPath on success. 1939 * NULL if not a path we care to cache. 1940 * @param pszPath The path to lookup. 1941 */ 1942 static PKWFSOBJ kwFsLookupA(const char *pszPath) 1943 { 1944 /* 1945 * Do hash table lookup of the path. 1946 */ 1947 KU32 uHashPath; 1948 KU32 cchPath = (KU32)kwStrHashEx(pszPath, &uHashPath); 1949 KU32 idxHashTab = uHashPath % K_ELEMENTS(g_apFsAnsiPaths); 1950 PKWFSHASHA pHashEntry = g_apFsAnsiPaths[idxHashTab]; 1951 if (pHashEntry) 1952 { 1953 do 1954 { 1955 if ( pHashEntry->uHashPath == uHashPath 1956 && pHashEntry->cchPath == cchPath 1957 && kHlpMemComp(pHashEntry->pszPath, pszPath, cchPath) == 0) 1958 { 1959 KWFS_LOG(("kwFsLookupA(%s) - hit %p\n", pszPath, pHashEntry->pFsObj)); 1960 return pHashEntry->pFsObj; 1961 } 1962 pHashEntry = pHashEntry->pNext; 1963 } while (pHashEntry); 1964 } 1965 1966 /* 1967 * Create an entry for it by walking the file system cache and filling in the blanks. 1968 */ 1969 if ( cchPath > 0 1970 && cchPath < 1024) 1971 { 1972 /* Is absolute without any '..' bits? */ 1973 if ( cchPath >= 3 1974 && pszPath[1] == ':' 1975 && IS_SLASH(pszPath[2]) 1976 && IS_ALPHA(pszPath[0]) 1977 && !kwFsHasDotDot(pszPath, cchPath) ) 1978 return kwFsLookupAbsoluteA(pszPath, cchPath, uHashPath, idxHashTab); 1979 1980 /* Not UNC? */ 1981 if ( cchPath < 2 1982 || !IS_SLASH(pszPath[0]) 1983 || !IS_SLASH(pszPath[1]) ) 1984 return kwFsLookupSlowA(pszPath, cchPath, uHashPath, idxHashTab); 1985 1986 1987 /* It's worth remembering uncacheable paths in the hash table. */ 1988 kwFsCreateHashTabEntryA(NULL /*pFsObj*/, pszPath, cchPath, uHashPath, idxHashTab); 1989 } 1990 return NULL; 1991 } 1992 1127 1993 1128 1994 … … 1268 2134 static void __cdecl kwSandbox_msvcrt_exit(int rcExitCode) 1269 2135 { 1270 kwDbgPrintf("kwSandbox_msvcrt_exit: %d\n", rcExitCode);2136 KW_LOG(("kwSandbox_msvcrt_exit: %d\n", rcExitCode)); 1271 2137 kwSandbox_Kernel32_ExitProcess(rcExitCode); 1272 2138 } … … 1277 2143 { 1278 2144 /* Quick. */ 1279 kwDbgPrintf("kwSandbox_msvcrt__exit %d\n", rcExitCode);2145 KW_LOG(("kwSandbox_msvcrt__exit %d\n", rcExitCode)); 1280 2146 kwSandbox_Kernel32_ExitProcess(rcExitCode); 1281 2147 } … … 1285 2151 static void __cdecl kwSandbox_msvcrt__cexit(int rcExitCode) 1286 2152 { 1287 kwDbgPrintf("kwSandbox_msvcrt__cexit: %d\n", rcExitCode);2153 KW_LOG(("kwSandbox_msvcrt__cexit: %d\n", rcExitCode)); 1288 2154 kwSandbox_Kernel32_ExitProcess(rcExitCode); 1289 2155 } … … 1293 2159 static void __cdecl kwSandbox_msvcrt__c_exit(int rcExitCode) 1294 2160 { 1295 kwDbgPrintf("kwSandbox_msvcrt__c_exit: %d\n", rcExitCode);2161 KW_LOG(("kwSandbox_msvcrt__c_exit: %d\n", rcExitCode)); 1296 2162 kwSandbox_Kernel32_ExitProcess(rcExitCode); 1297 2163 } … … 1301 2167 static void __cdecl kwSandbox_msvcrt__amsg_exit(int iMsgNo) 1302 2168 { 1303 kwDbgPrintf("\nRuntime error #%u!\n", iMsgNo);2169 KW_LOG(("\nRuntime error #%u!\n", iMsgNo)); 1304 2170 kwSandbox_Kernel32_ExitProcess(255); 2171 } 2172 2173 2174 /** CRT - terminate(). */ 2175 static void __cdecl kwSandbox_msvcrt_terminate(void) 2176 { 2177 KW_LOG(("\nRuntime - terminate!\n")); 2178 kwSandbox_Kernel32_ExitProcess(254); 1305 2179 } 1306 2180 … … 1485 2359 static DWORD WINAPI kwSandbox_Kernel32_GetEnvironmentVariableW(LPCWSTR pwszVar, LPWSTR pwszValue, DWORD cbValue) 1486 2360 { 1487 kwDbgPrintf("GetEnvironmentVariableW: '%ls'\n", pwszVar);2361 KW_LOG(("GetEnvironmentVariableW: '%ls'\n", pwszVar)); 1488 2362 //__debugbreak(); 1489 2363 //SetLastError(ERROR_ENVVAR_NOT_FOUND); … … 1504 2378 static BOOL WINAPI kwSandbox_Kernel32_SetEnvironmentVariableW(LPCWSTR pwszVar, LPCWSTR pwszValue) 1505 2379 { 1506 kwDbgPrintf("SetEnvironmentVariableW: '%ls' = '%ls'\n", pwszVar, pwszValue);2380 KW_LOG(("SetEnvironmentVariableW: '%ls' = '%ls'\n", pwszVar, pwszValue)); 1507 2381 return SetEnvironmentVariableW(pwszVar, pwszValue); 1508 2382 //__debugbreak(); … … 1554 2428 static errno_t __cdecl kwSandbox_msvcrt__wputenv_s(const wchar_t *pwszVar, const wchar_t *pwszValue) 1555 2429 { 1556 kwDbgPrintf("_wputenv_s: '%ls' = '%ls'\n", pwszVar, pwszValue);2430 KW_LOG(("_wputenv_s: '%ls' = '%ls'\n", pwszVar, pwszValue)); 1557 2431 //__debugbreak(); 1558 2432 return SetEnvironmentVariableW(pwszVar, pwszValue) ? 0 : -1; … … 1863 2737 static int s_cDbgGets = 0; 1864 2738 s_cDbgGets++; 1865 kwDbgPrintf("GetProcAddress(%s, %s) -> %p [%d]\n", pMod->pszPath, pszProc, (KUPTR)uValue, s_cDbgGets);2739 KW_LOG(("GetProcAddress(%s, %s) -> %p [%d]\n", pMod->pszPath, pszProc, (KUPTR)uValue, s_cDbgGets)); 1866 2740 kwLdrModuleRelease(pMod); 1867 2741 //if (s_cGets >= 3) … … 1913 2787 1914 2788 2789 /* 2790 * 2791 * File access APIs (for speeding them up). 2792 * File access APIs (for speeding them up). 2793 * File access APIs (for speeding them up). 2794 * 2795 */ 2796 2797 /** 2798 * Checks if the file extension indicates that the file/dir is something we 2799 * ought to cache. 2800 * 2801 * @returns K_TRUE if cachable, K_FALSE if not. 2802 * @param pszExt The kHlpGetExt result. 2803 * @param fAttrQuery Set if it's for an attribute query, clear if for 2804 * file creation. 2805 */ 2806 static KBOOL kwFsIsCachableExtensionA(const char *pszExt, KBOOL fAttrQuery) 2807 { 2808 char const chFirst = *pszExt; 2809 2810 /* C++ header without an extension or a directory. */ 2811 if (chFirst == '\0') 2812 return K_TRUE; 2813 2814 /* C Header: .h */ 2815 if (chFirst == 'h' || chFirst == 'H') 2816 { 2817 char chThird; 2818 char const chSecond = pszExt[1]; 2819 if (chSecond == '\0') 2820 return K_TRUE; 2821 chThird = pszExt[2]; 2822 2823 /* C++ Header: .hpp, .hxx */ 2824 if ( (chSecond == 'p' || chSecond == 'P') 2825 && (chThird == 'p' || chThird == 'P') 2826 && pszExt[3] == '\0') 2827 return K_TRUE; 2828 if ( (chSecond == 'x' || chSecond == 'X') 2829 && (chThird == 'x' || chThird == 'X') 2830 && pszExt[3] == '\0') 2831 return K_TRUE; 2832 2833 } 2834 /* Misc starting with i. */ 2835 else if (chFirst == 'i' || chFirst == 'I') 2836 { 2837 char const chSecond = pszExt[1]; 2838 if (chSecond != '\0') 2839 { 2840 if (chSecond == 'n' || chSecond == 'N') 2841 { 2842 char const chThird = pszExt[2]; 2843 2844 /* C++ inline header: .inl */ 2845 if ( (chThird == 'l' || chThird == 'L') 2846 && pszExt[3] == '\0') 2847 return K_TRUE; 2848 2849 /* Assembly include file: .inc */ 2850 if ( (chThird == 'c' || chThird == 'C') 2851 && pszExt[3] == '\0') 2852 return K_TRUE; 2853 } 2854 } 2855 } 2856 else if (fAttrQuery) 2857 { 2858 /* Dynamic link library: .dll */ 2859 if (chFirst == 'd' || chFirst == 'D') 2860 { 2861 char const chSecond = pszExt[1]; 2862 if (chSecond == 'l' || chSecond == 'L') 2863 { 2864 char const chThird = pszExt[2]; 2865 if (chThird == 'l' || chThird == 'L') 2866 return K_TRUE; 2867 } 2868 } 2869 /* Executable file: .exe */ 2870 else if (chFirst == 'e' || chFirst == 'E') 2871 { 2872 char const chSecond = pszExt[1]; 2873 if (chSecond == 'x' || chSecond == 'X') 2874 { 2875 char const chThird = pszExt[2]; 2876 if (chThird == 'e' || chThird == 'e') 2877 return K_TRUE; 2878 } 2879 } 2880 } 2881 2882 return K_FALSE; 2883 } 2884 2885 2886 /** 2887 * Checks if the extension of the given UTF-16 path indicates that the file/dir 2888 * should be cached. 2889 * 2890 * @returns K_TRUE if cachable, K_FALSE if not. 2891 * @param pwszPath The UTF-16 path to examine. 2892 * @param fAttrQuery Set if it's for an attribute query, clear if for 2893 * file creation. 2894 */ 2895 static KBOOL kwFsIsCachablePathExtensionW(const wchar_t *pwszPath, KBOOL fAttrQuery) 2896 { 2897 /* 2898 * Extract the extension, check that it's in the applicable range, roughly 2899 * convert it to ASCII/ANSI, and feed it to kwFsIsCachableExtensionA for 2900 * the actual check. This avoids a lot of code duplication. 2901 */ 2902 wchar_t wc; 2903 char szExt[4]; 2904 KSIZE cwcExt; 2905 wchar_t const *pwszExt = kwFsPathGetExtW(pwszPath, &cwcExt); 2906 switch (cwcExt) 2907 { 2908 case 3: if ((wchar_t)(szExt[2] = (char)(wc = pwszExt[2])) == wc) { /*likely*/ } else break; 2909 case 2: if ((wchar_t)(szExt[1] = (char)(wc = pwszExt[1])) == wc) { /*likely*/ } else break; 2910 case 1: if ((wchar_t)(szExt[0] = (char)(wc = pwszExt[0])) == wc) { /*likely*/ } else break; 2911 case 0: 2912 szExt[cwcExt] = '\0'; 2913 return kwFsIsCachableExtensionA(szExt, fAttrQuery); 2914 } 2915 return K_FALSE; 2916 } 2917 2918 2919 /** Kernel32 - CreateFileA */ 2920 static HANDLE WINAPI kwSandbox_Kernel32_CreateFileA(LPCSTR pszFilename, DWORD dwDesiredAccess, DWORD dwShareMode, 2921 LPSECURITY_ATTRIBUTES pSecAttrs, DWORD dwCreationDisposition, 2922 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) 2923 { 2924 HANDLE hFile; 2925 if (dwCreationDisposition == FILE_OPEN) 2926 { 2927 if ( dwDesiredAccess == GENERIC_READ 2928 || dwDesiredAccess == FILE_GENERIC_READ) 2929 { 2930 if (dwShareMode & FILE_SHARE_READ) 2931 { 2932 if ( !pSecAttrs 2933 || ( pSecAttrs->bInheritHandle == FALSE 2934 && pSecAttrs->nLength == 0) ) /** @todo This one might not make a lot of sense... */ 2935 { 2936 const char *pszExt = kHlpGetExt(pszFilename); 2937 if (kwFsIsCachableExtensionA(pszExt, K_FALSE /*fAttrQuery*/)) 2938 { 2939 /** @todo later. */ 2940 hFile = CreateFileA(pszFilename, dwDesiredAccess, dwShareMode, pSecAttrs, 2941 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); 2942 KWFS_LOG(("CreateFileA(%s) - cachable -> %p\n", pszFilename, hFile)); 2943 return hFile; 2944 } 2945 } 2946 } 2947 } 2948 } 2949 2950 hFile = CreateFileA(pszFilename, dwDesiredAccess, dwShareMode, pSecAttrs, 2951 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); 2952 KWFS_LOG(("CreateFileA(%s) -> %p\n", pszFilename, hFile)); 2953 return hFile; 2954 } 2955 2956 2957 /** Kernel32 - CreateFileW */ 2958 static HANDLE WINAPI kwSandbox_Kernel32_CreateFileW(LPCWSTR pwszFilename, DWORD dwDesiredAccess, DWORD dwShareMode, 2959 LPSECURITY_ATTRIBUTES pSecAttrs, DWORD dwCreationDisposition, 2960 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) 2961 { 2962 HANDLE hFile; 2963 if (dwCreationDisposition == FILE_OPEN) 2964 { 2965 if ( dwDesiredAccess == GENERIC_READ 2966 || dwDesiredAccess == FILE_GENERIC_READ) 2967 { 2968 if (dwShareMode & FILE_SHARE_READ) 2969 { 2970 if ( !pSecAttrs 2971 || ( pSecAttrs->bInheritHandle == FALSE 2972 && pSecAttrs->nLength == 0) ) /** @todo This one might not make a lot of sense... */ 2973 { 2974 if (kwFsIsCachablePathExtensionW(pwszFilename, K_FALSE /*fAttrQuery*/)) 2975 { 2976 /** @todo later. */ 2977 2978 hFile = CreateFileW(pwszFilename, dwDesiredAccess, dwShareMode, pSecAttrs, 2979 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); 2980 2981 KWFS_LOG(("CreateFileW(%ls) - cachable -> %p\n", pwszFilename, hFile)); 2982 return hFile; 2983 } 2984 } 2985 } 2986 } 2987 } 2988 hFile = CreateFileW(pwszFilename, dwDesiredAccess, dwShareMode, pSecAttrs, 2989 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); 2990 KWFS_LOG(("CreateFileW(%ls) -> %p\n", pwszFilename, hFile)); 2991 return hFile; 2992 } 2993 2994 2995 /** Kernel32 - SetFilePointer */ 2996 static DWORD WINAPI kwSandbox_Kernel32_SetFilePointer(HANDLE hFile, LONG cbMove, PLONG pcbMoveHi, DWORD dwMoveMethod) 2997 { 2998 KWFS_LOG(("SetFilePointer(%p)\n", hFile)); 2999 return SetFilePointer(hFile, cbMove, pcbMoveHi, dwMoveMethod); 3000 } 3001 3002 3003 /** Kernel32 - SetFilePointerEx */ 3004 static BOOL WINAPI kwSandbox_Kernel32_SetFilePointerEx(HANDLE hFile, LARGE_INTEGER pcbMove, PLARGE_INTEGER poffNew, 3005 DWORD dwMoveMethod) 3006 { 3007 KWFS_LOG(("SetFilePointerEx(%p)\n", hFile)); 3008 return SetFilePointerEx(hFile, pcbMove, poffNew, dwMoveMethod); 3009 } 3010 3011 3012 /** Kernel32 - ReadFile */ 3013 static BOOL WINAPI kwSandbox_Kernel32_ReadFile(HANDLE hFile, LPVOID pvBuffer, DWORD cbToWrite, LPDWORD pcbActuallyWritten, 3014 LPOVERLAPPED pOverlapped) 3015 { 3016 KWFS_LOG(("ReadFile(%p)\n", hFile)); 3017 return ReadFile(hFile, pvBuffer, cbToWrite, pcbActuallyWritten, pOverlapped); 3018 } 3019 3020 3021 /** Kernel32 - CloseHandle */ 3022 static BOOL WINAPI kwSandbox_Kernel32_CloseHandle(HANDLE hObject) 3023 { 3024 KWFS_LOG(("CloseHandle(%p)\n", hObject)); 3025 return CloseHandle(hObject); 3026 } 3027 3028 3029 /** Kernel32 - GetFileAttributesA. */ 3030 static DWORD WINAPI kwSandbox_Kernel32_GetFileAttributesA(LPCSTR pszFilename) 3031 { 3032 DWORD fRet; 3033 const char *pszExt = kHlpGetExt(pszFilename); 3034 if (kwFsIsCachableExtensionA(pszExt, K_TRUE /*fAttrQuery*/)) 3035 { 3036 PKWFSOBJ pFsObj = kwFsLookupA(pszFilename); 3037 if (pFsObj) 3038 { 3039 if (pFsObj->fAttribs == INVALID_FILE_ATTRIBUTES) 3040 SetLastError(pFsObj->uLastError); 3041 KWFS_LOG(("GetFileAttributesA(%s) -> %#x [cached]\n", pszFilename, pFsObj->fAttribs)); 3042 return pFsObj->fAttribs; 3043 } 3044 } 3045 3046 fRet = GetFileAttributesA(pszFilename); 3047 KWFS_LOG(("GetFileAttributesA(%s) -> %#x\n", pszFilename, fRet)); 3048 return fRet; 3049 } 3050 3051 3052 /** Kernel32 - GetFileAttributesW. */ 3053 static DWORD WINAPI kwSandbox_Kernel32_GetFileAttributesW(LPCWSTR pwszFilename) 3054 { 3055 DWORD fRet; 3056 if (kwFsIsCachablePathExtensionW(pwszFilename, K_TRUE /*fAttrQuery*/)) 3057 { 3058 /** @todo rewrite to pure UTF-16. */ 3059 char szTmp[2048]; 3060 KSIZE cch = kwUtf16ToStr(pwszFilename, szTmp, sizeof(szTmp)); 3061 if (cch < sizeof(szTmp)) 3062 return kwSandbox_Kernel32_GetFileAttributesA(szTmp); 3063 } 3064 3065 fRet = GetFileAttributesW(pwszFilename); 3066 KWFS_LOG(("GetFileAttributesW(%ls) -> %#x\n", pwszFilename, fRet)); 3067 return fRet; 3068 } 3069 3070 3071 /** Kernel32 - GetShortPathNameW - cl1[xx].dll of VS2010 does this to the 3072 * directory containing each include file. We cache the result to speed 3073 * things up a little. */ 3074 static DWORD WINAPI kwSandbox_Kernel32_GetShortPathNameW(LPCWSTR pwszLongPath, LPWSTR pwszShortPath, DWORD cwcShortPath) 3075 { 3076 DWORD cwcRet; 3077 if (kwFsIsCachablePathExtensionW(pwszLongPath, K_TRUE /*fAttrQuery*/)) 3078 { 3079 /** @todo proper implementation later, for now just copy it over as it. */ 3080 KSIZE cwcLongPath = kwUtf16Len(pwszLongPath); 3081 cwcRet = kwUtf16CopyStyle1(pwszLongPath, pwszShortPath, cwcShortPath); 3082 KWFS_LOG(("GetShortPathNameW(%ls) -> '%*.*ls' & %#x [cached]\n", 3083 pwszLongPath, K_MIN(cwcShortPath, cwcRet), K_MIN(cwcShortPath, cwcRet), pwszShortPath, cwcRet)); 3084 } 3085 else 3086 { 3087 cwcRet = GetShortPathNameW(pwszLongPath, pwszShortPath, cwcShortPath); 3088 KWFS_LOG(("GetShortPathNameW(%ls) -> '%*.*ls' & %#x\n", 3089 pwszLongPath, K_MIN(cwcShortPath, cwcRet), K_MIN(cwcShortPath, cwcRet), pwszShortPath, cwcRet)); 3090 } 3091 return cwcRet; 3092 } 3093 3094 3095 1915 3096 /** 1916 3097 * Functions that needs replacing for sandboxed execution. … … 1918 3099 KWREPLACEMENTFUNCTION const g_aSandboxReplacements[] = 1919 3100 { 1920 #define TUPLE(a_sz) a_sz, sizeof(a_sz) - 11921 3101 /* 1922 3102 * Kernel32.dll and friends. … … 1950 3130 { TUPLE("ExpandEnvironmentStringsW"), NULL, (KUPTR)kwSandbox_Kernel32_ExpandEnvironmentStringsW }, 1951 3131 3132 { TUPLE("CreateFileA"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileA }, 3133 { TUPLE("CreateFileW"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileW }, 3134 { TUPLE("ReadFile"), NULL, (KUPTR)kwSandbox_Kernel32_ReadFile }, 3135 { TUPLE("SetFilePointer"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointer }, 3136 { TUPLE("SetFilePointerEx"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointerEx }, 3137 { TUPLE("CloseHandle"), NULL, (KUPTR)kwSandbox_Kernel32_CloseHandle }, 3138 { TUPLE("GetFileAttributesA"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesA }, 3139 { TUPLE("GetFileAttributesW"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesW }, 3140 { TUPLE("GetShortPathNameW"), NULL, (KUPTR)kwSandbox_Kernel32_GetShortPathNameW }, 3141 1952 3142 /* 1953 3143 * MS Visual C++ CRTs. … … 1958 3148 { TUPLE("_c_exit"), NULL, (KUPTR)kwSandbox_msvcrt__c_exit }, 1959 3149 { TUPLE("_amsg_exit"), NULL, (KUPTR)kwSandbox_msvcrt__amsg_exit }, 3150 { TUPLE("terminate"), NULL, (KUPTR)kwSandbox_msvcrt_terminate }, 1960 3151 1961 3152 { TUPLE("_beginthread"), NULL, (KUPTR)kwSandbox_msvcrt__beginthread }, … … 1997 3188 { TUPLE("__p__environ"), NULL, (KUPTR)kwSandbox_msvcrt___p__environ }, 1998 3189 { TUPLE("__p__wenviron"), NULL, (KUPTR)kwSandbox_msvcrt___p__wenviron }, 1999 /// @todo terminate2000 3190 }; 2001 3191 /** Number of entries in g_aReplacements. */ 2002 3192 KU32 const g_cSandboxReplacements = K_ELEMENTS(g_aSandboxReplacements); 3193 3194 3195 /** 3196 * Functions that needs replacing in natively loaded DLLs when doing sandboxed 3197 * execution. 3198 */ 3199 KWREPLACEMENTFUNCTION const g_aSandboxNativeReplacements[] = 3200 { 3201 /* 3202 * Kernel32.dll and friends. 3203 */ 3204 { TUPLE("ExitProcess"), NULL, (KUPTR)kwSandbox_Kernel32_ExitProcess }, 3205 { TUPLE("TerminateProcess"), NULL, (KUPTR)kwSandbox_Kernel32_TerminateProcess }, 3206 3207 #if 0 3208 { TUPLE("CreateThread"), NULL, (KUPTR)kwSandbox_Kernel32_CreateThread }, 3209 #endif 3210 3211 #if 0 3212 { TUPLE("CreateFileA"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileA }, 3213 { TUPLE("CreateFileW"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileW }, 3214 { TUPLE("ReadFile"), NULL, (KUPTR)kwSandbox_Kernel32_ReadFile }, 3215 { TUPLE("SetFilePointer"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointer }, 3216 { TUPLE("SetFilePointerEx"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointerEx }, 3217 { TUPLE("CloseHandle"), NULL, (KUPTR)kwSandbox_Kernel32_CloseHandle }, 3218 #endif 3219 { TUPLE("GetFileAttributesA"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesA }, 3220 { TUPLE("GetFileAttributesW"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesW }, 3221 { TUPLE("GetShortPathNameW"), NULL, (KUPTR)kwSandbox_Kernel32_GetShortPathNameW }, 3222 3223 /* 3224 * MS Visual C++ CRTs. 3225 */ 3226 { TUPLE("exit"), NULL, (KUPTR)kwSandbox_msvcrt_exit }, 3227 { TUPLE("_exit"), NULL, (KUPTR)kwSandbox_msvcrt__exit }, 3228 { TUPLE("_cexit"), NULL, (KUPTR)kwSandbox_msvcrt__cexit }, 3229 { TUPLE("_c_exit"), NULL, (KUPTR)kwSandbox_msvcrt__c_exit }, 3230 { TUPLE("_amsg_exit"), NULL, (KUPTR)kwSandbox_msvcrt__amsg_exit }, 3231 { TUPLE("terminate"), NULL, (KUPTR)kwSandbox_msvcrt_terminate }, 3232 3233 #if 0 /* used by mspdbXXX.dll */ 3234 { TUPLE("_beginthread"), NULL, (KUPTR)kwSandbox_msvcrt__beginthread }, 3235 { TUPLE("_beginthreadex"), NULL, (KUPTR)kwSandbox_msvcrt__beginthreadex }, 3236 #endif 3237 }; 3238 /** Number of entries in g_aSandboxNativeReplacements. */ 3239 KU32 const g_cSandboxNativeReplacements = K_ELEMENTS(g_aSandboxNativeReplacements); 2003 3240 2004 3241 … … 2096 3333 pPeb->ProcessParameters->CommandLine.Length = (USHORT)cwc * sizeof(wchar_t); 2097 3334 3335 3336 g_uFsCacheGeneration++; 3337 if (g_uFsCacheGeneration == KFSWOBJ_CACHE_GEN_IGNORE) 3338 g_uFsCacheGeneration++; 2098 3339 return 0; 2099 3340 } … … 2113 3354 2114 3355 *prcExitCode = 256; 2115 kwDbgPrintf("GetCommandLineA: '%s'\n", GetCommandLineA());2116 3356 2117 3357 /* … … 2121 3361 if (rc == 0) 2122 3362 { 2123 2124 3363 /* 2125 3364 * Do module initialization. … … 2183 3422 { 2184 3423 case KWTOOLTYPE_SANDBOXED: 2185 kwDbgPrintf("Sandboxing tool %s\n", pTool->pszPath);3424 KW_LOG(("Sandboxing tool %s\n", pTool->pszPath)); 2186 3425 rc = kwSandboxExec(pTool, pszCmdLine, &rcExitCode); 2187 3426 break; 2188 3427 2189 3428 case KWTOOLTYPE_WATCOM: 2190 kwDbgPrintf("TODO: Watcom style tool %s\n", pTool->pszPath);3429 KW_LOG(("TODO: Watcom style tool %s\n", pTool->pszPath)); 2191 3430 rc = rcExitCode = 2; 2192 3431 break; 2193 3432 2194 3433 case KWTOOLTYPE_EXEC: 2195 kwDbgPrintf("TODO: Direct exec tool %s\n", pTool->pszPath);3434 KW_LOG(("TODO: Direct exec tool %s\n", pTool->pszPath)); 2196 3435 rc = rcExitCode = 2; 2197 3436 break; … … 2202 3441 break; 2203 3442 } 2204 kwDbgPrintf("rcExitCode=%d (rc=%d)\n", rcExitCode, rc);3443 KW_LOG(("rcExitCode=%d (rc=%d)\n", rcExitCode, rc)); 2205 3444 } 2206 3445 else … … 2212 3451 int main(int argc, char **argv) 2213 3452 { 3453 int rc = 0; 2214 3454 int i; 2215 int rc;2216 3455 argv[2] = "\"E:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/bin/amd64/cl.exe\" -c -c -TP -nologo -Zi -Zi -Zl -GR- -EHsc -GF -Zc:wchar_t- -Oy- -MT -W4 -Wall -wd4065 -wd4996 -wd4127 -wd4706 -wd4201 -wd4214 -wd4510 -wd4512 -wd4610 -wd4514 -wd4820 -wd4365 -wd4987 -wd4710 -wd4061 -wd4986 -wd4191 -wd4574 -wd4917 -wd4711 -wd4611 -wd4571 -wd4324 -wd4505 -wd4263 -wd4264 -wd4738 -wd4242 -wd4244 -WX -RTCsu -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/include -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/atlmfc/include -IE:/vbox/svn/trunk/tools/win.x86/sdk/v7.1/Include -IE:/vbox/svn/trunk/include -IE:/vbox/svn/trunk/out/win.amd64/debug -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/include -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/atlmfc/include -DVBOX -DVBOX_WITH_64_BITS_GUESTS -DVBOX_WITH_REM -DVBOX_WITH_RAW_MODE -DDEBUG -DDEBUG_bird -DDEBUG_USERNAME=bird -DRT_OS_WINDOWS -D__WIN__ -DRT_ARCH_AMD64 -D__AMD64__ -D__WIN64__ -DVBOX_WITH_DEBUGGER -DRT_LOCK_STRICT -DRT_LOCK_STRICT_ORDER -DIN_RING3 -DLOG_DISABLED -DIN_BLD_PROG -D_CRT_SECURE_NO_DEPRECATE -FdE:/vbox/svn/trunk/out/win.amd64/debug/obj/VBoxBs2Linker/VBoxBs2Linker-obj.pdb -FD -FoE:/vbox/svn/trunk/out/win.amd64/debug/obj/VBoxBs2Linker/VBoxBs2Linker.obj E:\\vbox\\svn\\trunk\\src\\VBox\\ValidationKit\\bootsectors\\VBoxBs2Linker.cpp"; 2217 //rc = kwExecCmdLine(argv[1], argv[2]); 2218 //rc = kwExecCmdLine(argv[1], argv[2]); 3456 #if 0 3457 rc = kwExecCmdLine(argv[1], argv[2]); 3458 rc = kwExecCmdLine(argv[1], argv[2]); 3459 K_NOREF(i); 3460 #else 2219 3461 // run 2: 34/1024 = 0x0 (0.033203125) 2220 3462 // run 1: 37/1024 = 0x0 (0.0361328125) … … 2224 3466 for (i = 0; i < 1024 && rc == 0; i++) 2225 3467 rc = kwExecCmdLine(argv[1], argv[2]); 3468 #endif 2226 3469 return rc; 2227 3470 }
Note:
See TracChangeset
for help on using the changeset viewer.