1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS NT User-Mode DLL 4 * FILE: lib/ntdll/rtl/libsup.c 5 * PURPOSE: RTL Support Routines 6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 7 * Gunnar Dalsnes 8 */ 9 10 /* INCLUDES *****************************************************************/ 11 12 #include <ntdll.h> 13 #include <apisets.h> 14 #include <compat_undoc.h> 15 16 #define NDEBUG 17 #include <debug.h> 18 19 SIZE_T RtlpAllocDeallocQueryBufferSize = PAGE_SIZE; 20 PTEB LdrpTopLevelDllBeingLoadedTeb = NULL; 21 PVOID MmHighestUserAddress = (PVOID)MI_HIGHEST_USER_ADDRESS; 22 23 /* FUNCTIONS ***************************************************************/ 24 25 BOOLEAN 26 NTAPI 27 RtlpCheckForActiveDebugger(VOID) 28 { 29 /* Return the flag in the PEB */ 30 return NtCurrentPeb()->BeingDebugged; 31 } 32 33 BOOLEAN 34 NTAPI 35 RtlpSetInDbgPrint(VOID) 36 { 37 /* Check if it's already set and return TRUE if so */ 38 if (NtCurrentTeb()->InDbgPrint) return TRUE; 39 40 /* Set it and return */ 41 NtCurrentTeb()->InDbgPrint = TRUE; 42 return FALSE; 43 } 44 45 VOID 46 NTAPI 47 RtlpClearInDbgPrint(VOID) 48 { 49 /* Clear the flag */ 50 NtCurrentTeb()->InDbgPrint = FALSE; 51 } 52 53 KPROCESSOR_MODE 54 NTAPI 55 RtlpGetMode(VOID) 56 { 57 return UserMode; 58 } 59 60 /* 61 * @implemented 62 */ 63 PPEB 64 NTAPI 65 RtlGetCurrentPeb(VOID) 66 { 67 return NtCurrentPeb(); 68 } 69 70 /* 71 * @implemented 72 */ 73 VOID NTAPI 74 RtlAcquirePebLock(VOID) 75 { 76 PPEB Peb = NtCurrentPeb (); 77 RtlEnterCriticalSection(Peb->FastPebLock); 78 } 79 80 /* 81 * @implemented 82 */ 83 VOID NTAPI 84 RtlReleasePebLock(VOID) 85 { 86 PPEB Peb = NtCurrentPeb (); 87 RtlLeaveCriticalSection(Peb->FastPebLock); 88 } 89 90 /* 91 * @implemented 92 */ 93 ULONG 94 NTAPI 95 RtlGetNtGlobalFlags(VOID) 96 { 97 PPEB pPeb = NtCurrentPeb(); 98 return pPeb->NtGlobalFlag; 99 } 100 101 NTSTATUS 102 NTAPI 103 RtlDeleteHeapLock(IN OUT PHEAP_LOCK Lock) 104 { 105 return RtlDeleteCriticalSection(&Lock->CriticalSection); 106 } 107 108 NTSTATUS 109 NTAPI 110 RtlEnterHeapLock(IN OUT PHEAP_LOCK Lock, IN BOOLEAN Exclusive) 111 { 112 UNREFERENCED_PARAMETER(Exclusive); 113 114 return RtlEnterCriticalSection(&Lock->CriticalSection); 115 } 116 117 BOOLEAN 118 NTAPI 119 RtlTryEnterHeapLock(IN OUT PHEAP_LOCK Lock, IN BOOLEAN Exclusive) 120 { 121 UNREFERENCED_PARAMETER(Exclusive); 122 123 return RtlTryEnterCriticalSection(&Lock->CriticalSection); 124 } 125 126 NTSTATUS 127 NTAPI 128 RtlInitializeHeapLock(IN OUT PHEAP_LOCK *Lock) 129 { 130 return RtlInitializeCriticalSection(&(*Lock)->CriticalSection); 131 } 132 133 NTSTATUS 134 NTAPI 135 RtlLeaveHeapLock(IN OUT PHEAP_LOCK Lock) 136 { 137 return RtlLeaveCriticalSection(&Lock->CriticalSection); 138 } 139 140 PVOID 141 NTAPI 142 RtlpAllocateMemory(UINT Bytes, 143 ULONG Tag) 144 { 145 UNREFERENCED_PARAMETER(Tag); 146 147 return RtlAllocateHeap(RtlGetProcessHeap(), 148 0, 149 Bytes); 150 } 151 152 153 VOID 154 NTAPI 155 RtlpFreeMemory(PVOID Mem, 156 ULONG Tag) 157 { 158 UNREFERENCED_PARAMETER(Tag); 159 160 RtlFreeHeap(RtlGetProcessHeap(), 161 0, 162 Mem); 163 } 164 165 166 #if DBG 167 VOID FASTCALL 168 CHECK_PAGED_CODE_RTL(char *file, int line) 169 { 170 /* meaningless in user mode */ 171 } 172 #endif 173 174 VOID 175 NTAPI 176 RtlpSetHeapParameters(IN PRTL_HEAP_PARAMETERS Parameters) 177 { 178 PPEB Peb; 179 180 /* Get PEB */ 181 Peb = RtlGetCurrentPeb(); 182 183 /* Apply defaults for non-set parameters */ 184 if (!Parameters->SegmentCommit) Parameters->SegmentCommit = Peb->HeapSegmentCommit; 185 if (!Parameters->SegmentReserve) Parameters->SegmentReserve = Peb->HeapSegmentReserve; 186 if (!Parameters->DeCommitFreeBlockThreshold) Parameters->DeCommitFreeBlockThreshold = Peb->HeapDeCommitFreeBlockThreshold; 187 if (!Parameters->DeCommitTotalFreeThreshold) Parameters->DeCommitTotalFreeThreshold = Peb->HeapDeCommitTotalFreeThreshold; 188 } 189 190 BOOLEAN 191 NTAPI 192 RtlpHandleDpcStackException(IN PEXCEPTION_REGISTRATION_RECORD RegistrationFrame, 193 IN ULONG_PTR RegistrationFrameEnd, 194 IN OUT PULONG_PTR StackLow, 195 IN OUT PULONG_PTR StackHigh) 196 { 197 /* There's no such thing as a DPC stack in user-mode */ 198 return FALSE; 199 } 200 201 VOID 202 NTAPI 203 RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord, 204 IN PCONTEXT ContextRecord, 205 IN PVOID ContextData, 206 IN ULONG Size) 207 { 208 /* Exception logging is not done in user-mode */ 209 } 210 211 BOOLEAN 212 NTAPI 213 RtlpCaptureStackLimits(IN ULONG_PTR Ebp, 214 IN ULONG_PTR *StackBegin, 215 IN ULONG_PTR *StackEnd) 216 { 217 /* FIXME: Verify */ 218 *StackBegin = (ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit; 219 *StackEnd = (ULONG_PTR)NtCurrentTeb()->NtTib.StackBase; 220 return TRUE; 221 } 222 223 #ifndef _M_AMD64 224 /* 225 * @implemented 226 */ 227 ULONG 228 NTAPI 229 RtlWalkFrameChain(OUT PVOID *Callers, 230 IN ULONG Count, 231 IN ULONG Flags) 232 { 233 ULONG_PTR Stack, NewStack, StackBegin, StackEnd = 0; 234 ULONG Eip; 235 BOOLEAN Result, StopSearch = FALSE; 236 ULONG i = 0; 237 238 /* Get current EBP */ 239 #if defined(_M_IX86) 240 #if defined __GNUC__ 241 __asm__("mov %%ebp, %0" : "=r" (Stack) : ); 242 #elif defined(_MSC_VER) 243 __asm mov Stack, ebp 244 #endif 245 #elif defined(_M_MIPS) 246 __asm__("move $sp, %0" : "=r" (Stack) : ); 247 #elif defined(_M_PPC) 248 __asm__("mr %0,1" : "=r" (Stack) : ); 249 #elif defined(_M_ARM) 250 #if defined __GNUC__ 251 __asm__("mov sp, %0" : "=r"(Stack) : ); 252 #elif defined(_MSC_VER) 253 // FIXME: Hack. Probably won't work if this ever actually manages to run someday. 254 Stack = (ULONG_PTR)&Stack; 255 #endif 256 #else 257 #error Unknown architecture 258 #endif 259 260 /* Set it as the stack begin limit as well */ 261 StackBegin = (ULONG_PTR)Stack; 262 263 /* Check if we're called for non-logging mode */ 264 if (!Flags) 265 { 266 /* Get the actual safe limits */ 267 Result = RtlpCaptureStackLimits((ULONG_PTR)Stack, 268 &StackBegin, 269 &StackEnd); 270 if (!Result) return 0; 271 } 272 273 /* Use a SEH block for maximum protection */ 274 _SEH2_TRY 275 { 276 /* Loop the frames */ 277 for (i = 0; i < Count; i++) 278 { 279 /* 280 * Leave if we're past the stack, 281 * if we're before the stack, 282 * or if we've reached ourselves. 283 */ 284 if ((Stack >= StackEnd) || 285 (!i ? (Stack < StackBegin) : (Stack <= StackBegin)) || 286 ((StackEnd - Stack) < (2 * sizeof(ULONG_PTR)))) 287 { 288 /* We're done or hit a bad address */ 289 break; 290 } 291 292 /* Get new stack and EIP */ 293 NewStack = *(PULONG_PTR)Stack; 294 Eip = *(PULONG_PTR)(Stack + sizeof(ULONG_PTR)); 295 296 /* Check if the new pointer is above the oldone and past the end */ 297 if (!((Stack < NewStack) && (NewStack < StackEnd))) 298 { 299 /* Stop searching after this entry */ 300 StopSearch = TRUE; 301 } 302 303 /* Also make sure that the EIP isn't a stack address */ 304 if ((StackBegin < Eip) && (Eip < StackEnd)) break; 305 306 /* FIXME: Check that EIP is inside a loaded module */ 307 308 /* Save this frame */ 309 Callers[i] = (PVOID)Eip; 310 311 /* Check if we should continue */ 312 if (StopSearch) 313 { 314 /* Return the next index */ 315 i++; 316 break; 317 } 318 319 /* Move to the next stack */ 320 Stack = NewStack; 321 } 322 } 323 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 324 { 325 /* No index */ 326 i = 0; 327 } 328 _SEH2_END; 329 330 /* Return frames parsed */ 331 return i; 332 } 333 #endif 334 335 VOID 336 NTAPI 337 RtlpGetStackLimits( 338 OUT PULONG_PTR LowLimit, 339 OUT PULONG_PTR HighLimit) 340 { 341 *LowLimit = (ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit; 342 *HighLimit = (ULONG_PTR)NtCurrentTeb()->NtTib.StackBase; 343 } 344 345 BOOLEAN 346 NTAPI 347 RtlIsThreadWithinLoaderCallout(VOID) 348 { 349 return LdrpTopLevelDllBeingLoadedTeb == NtCurrentTeb(); 350 } 351 352 /* RTL Atom Tables ************************************************************/ 353 354 typedef struct _RTL_ATOM_HANDLE 355 { 356 RTL_HANDLE_TABLE_ENTRY Handle; 357 PRTL_ATOM_TABLE_ENTRY AtomEntry; 358 } RTL_ATOM_HANDLE, *PRTL_ATOM_HANDLE; 359 360 NTSTATUS 361 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable) 362 { 363 RtlInitializeCriticalSection(&AtomTable->CriticalSection); 364 return STATUS_SUCCESS; 365 } 366 367 368 VOID 369 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable) 370 { 371 RtlDeleteCriticalSection(&AtomTable->CriticalSection); 372 } 373 374 375 BOOLEAN 376 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable) 377 { 378 RtlEnterCriticalSection(&AtomTable->CriticalSection); 379 return TRUE; 380 } 381 382 383 VOID 384 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable) 385 { 386 RtlLeaveCriticalSection(&AtomTable->CriticalSection); 387 } 388 389 390 /* handle functions */ 391 392 BOOLEAN 393 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable) 394 { 395 RtlInitializeHandleTable(0xCFFF, 396 sizeof(RTL_ATOM_HANDLE), 397 &AtomTable->RtlHandleTable); 398 399 return TRUE; 400 } 401 402 VOID 403 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable) 404 { 405 RtlDestroyHandleTable(&AtomTable->RtlHandleTable); 406 } 407 408 PRTL_ATOM_TABLE 409 RtlpAllocAtomTable(ULONG Size) 410 { 411 return (PRTL_ATOM_TABLE)RtlAllocateHeap(RtlGetProcessHeap(), 412 HEAP_ZERO_MEMORY, 413 Size); 414 } 415 416 VOID 417 RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable) 418 { 419 RtlFreeHeap(RtlGetProcessHeap(), 420 0, 421 AtomTable); 422 } 423 424 PRTL_ATOM_TABLE_ENTRY 425 RtlpAllocAtomTableEntry(ULONG Size) 426 { 427 return (PRTL_ATOM_TABLE_ENTRY)RtlAllocateHeap(RtlGetProcessHeap(), 428 HEAP_ZERO_MEMORY, 429 Size); 430 } 431 432 VOID 433 RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry) 434 { 435 RtlFreeHeap(RtlGetProcessHeap(), 436 0, 437 Entry); 438 } 439 440 VOID 441 RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry) 442 { 443 PRTL_HANDLE_TABLE_ENTRY RtlHandleEntry; 444 445 if (RtlIsValidIndexHandle(&AtomTable->RtlHandleTable, 446 (ULONG)Entry->HandleIndex, 447 &RtlHandleEntry)) 448 { 449 RtlFreeHandle(&AtomTable->RtlHandleTable, 450 RtlHandleEntry); 451 } 452 } 453 454 BOOLEAN 455 RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry) 456 { 457 ULONG HandleIndex; 458 PRTL_HANDLE_TABLE_ENTRY RtlHandle; 459 460 RtlHandle = RtlAllocateHandle(&AtomTable->RtlHandleTable, 461 &HandleIndex); 462 if (RtlHandle != NULL) 463 { 464 PRTL_ATOM_HANDLE AtomHandle = (PRTL_ATOM_HANDLE)RtlHandle; 465 466 /* FIXME - Handle Indexes >= 0xC000 ?! */ 467 if (HandleIndex < 0xC000) 468 { 469 Entry->HandleIndex = (USHORT)HandleIndex; 470 Entry->Atom = 0xC000 + (USHORT)HandleIndex; 471 472 AtomHandle->AtomEntry = Entry; 473 AtomHandle->Handle.Flags = RTL_HANDLE_VALID; 474 475 return TRUE; 476 } 477 else 478 { 479 /* set the valid flag, otherwise RtlFreeHandle will fail! */ 480 AtomHandle->Handle.Flags = RTL_HANDLE_VALID; 481 482 RtlFreeHandle(&AtomTable->RtlHandleTable, 483 RtlHandle); 484 } 485 } 486 487 return FALSE; 488 } 489 490 PRTL_ATOM_TABLE_ENTRY 491 RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable, ULONG Index) 492 { 493 PRTL_HANDLE_TABLE_ENTRY RtlHandle; 494 495 if (RtlIsValidIndexHandle(&AtomTable->RtlHandleTable, 496 Index, 497 &RtlHandle)) 498 { 499 PRTL_ATOM_HANDLE AtomHandle = (PRTL_ATOM_HANDLE)RtlHandle; 500 501 return AtomHandle->AtomEntry; 502 } 503 504 return NULL; 505 } 506 507 /* Ldr SEH-Protected access to IMAGE_NT_HEADERS */ 508 509 /* Rtl SEH-Free version of this */ 510 NTSTATUS 511 NTAPI 512 RtlpImageNtHeaderEx( 513 _In_ ULONG Flags, 514 _In_ PVOID Base, 515 _In_ ULONG64 Size, 516 _Out_ PIMAGE_NT_HEADERS *OutHeaders); 517 518 519 /* 520 * @implemented 521 * @note: This is here, so that we do not drag SEH into rosload, freeldr and bootmgfw 522 */ 523 NTSTATUS 524 NTAPI 525 RtlImageNtHeaderEx( 526 _In_ ULONG Flags, 527 _In_ PVOID Base, 528 _In_ ULONG64 Size, 529 _Out_ PIMAGE_NT_HEADERS *OutHeaders) 530 { 531 NTSTATUS Status; 532 533 /* Assume failure. This is also done in RtlpImageNtHeaderEx, but this is guarded by SEH. */ 534 if (OutHeaders != NULL) 535 *OutHeaders = NULL; 536 537 _SEH2_TRY 538 { 539 Status = RtlpImageNtHeaderEx(Flags, Base, Size, OutHeaders); 540 } 541 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 542 { 543 /* Fail with the SEH error */ 544 Status = _SEH2_GetExceptionCode(); 545 } 546 _SEH2_END; 547 548 return Status; 549 } 550 551 /* 552 * Ldr Resource support code 553 */ 554 555 IMAGE_RESOURCE_DIRECTORY *find_entry_by_name( IMAGE_RESOURCE_DIRECTORY *dir, 556 LPCWSTR name, void *root, 557 int want_dir ); 558 IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( IMAGE_RESOURCE_DIRECTORY *dir, 559 WORD id, void *root, int want_dir ); 560 IMAGE_RESOURCE_DIRECTORY *find_first_entry( IMAGE_RESOURCE_DIRECTORY *dir, 561 void *root, int want_dir ); 562 int push_language( USHORT *list, ULONG pos, WORD lang ); 563 564 /********************************************************************** 565 * find_entry 566 * 567 * Find a resource entry 568 */ 569 NTSTATUS find_entry( PVOID BaseAddress, LDR_RESOURCE_INFO *info, 570 ULONG level, void **ret, int want_dir ) 571 { 572 ULONG size; 573 void *root; 574 IMAGE_RESOURCE_DIRECTORY *resdirptr; 575 USHORT list[9]; /* list of languages to try */ 576 int i, pos = 0; 577 LCID user_lcid, system_lcid; 578 579 root = RtlImageDirectoryEntryToData( BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size ); 580 if (!root) return STATUS_RESOURCE_DATA_NOT_FOUND; 581 if (size < sizeof(*resdirptr)) return STATUS_RESOURCE_DATA_NOT_FOUND; 582 resdirptr = root; 583 584 if (!level--) goto done; 585 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Type, root, want_dir || level ))) 586 return STATUS_RESOURCE_TYPE_NOT_FOUND; 587 if (!level--) return STATUS_SUCCESS; 588 589 resdirptr = *ret; 590 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Name, root, want_dir || level ))) 591 return STATUS_RESOURCE_NAME_NOT_FOUND; 592 if (!level--) return STATUS_SUCCESS; 593 if (level) return STATUS_INVALID_PARAMETER; /* level > 3 */ 594 595 /* 1. specified language */ 596 pos = push_language( list, pos, info->Language ); 597 598 /* 2. specified language with neutral sublanguage */ 599 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(info->Language), SUBLANG_NEUTRAL ) ); 600 601 /* 3. neutral language with neutral sublanguage */ 602 pos = push_language( list, pos, MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ) ); 603 604 /* if no explicitly specified language, try some defaults */ 605 if (PRIMARYLANGID(info->Language) == LANG_NEUTRAL) 606 { 607 /* user defaults, unless SYS_DEFAULT sublanguage specified */ 608 if (SUBLANGID(info->Language) != SUBLANG_SYS_DEFAULT) 609 { 610 /* 4. current thread locale language */ 611 pos = push_language( list, pos, LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale) ); 612 613 if (NT_SUCCESS(NtQueryDefaultLocale(TRUE, &user_lcid))) 614 { 615 /* 5. user locale language */ 616 pos = push_language( list, pos, LANGIDFROMLCID(user_lcid) ); 617 618 /* 6. user locale language with neutral sublanguage */ 619 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(user_lcid), SUBLANG_NEUTRAL ) ); 620 } 621 } 622 623 /* now system defaults */ 624 625 if (NT_SUCCESS(NtQueryDefaultLocale(FALSE, &system_lcid))) 626 { 627 /* 7. system locale language */ 628 pos = push_language( list, pos, LANGIDFROMLCID( system_lcid ) ); 629 630 /* 8. system locale language with neutral sublanguage */ 631 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(system_lcid), SUBLANG_NEUTRAL ) ); 632 } 633 634 /* 9. English */ 635 pos = push_language( list, pos, MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT ) ); 636 } 637 638 resdirptr = *ret; 639 for (i = 0; i < pos; i++) 640 if ((*ret = find_entry_by_id( resdirptr, list[i], root, want_dir ))) return STATUS_SUCCESS; 641 642 /* if no explicitly specified language, return the first entry */ 643 if (PRIMARYLANGID(info->Language) == LANG_NEUTRAL) 644 { 645 if ((*ret = find_first_entry( resdirptr, root, want_dir ))) return STATUS_SUCCESS; 646 } 647 return STATUS_RESOURCE_LANG_NOT_FOUND; 648 649 done: 650 *ret = resdirptr; 651 return STATUS_SUCCESS; 652 } 653 654 /* 655 * @implemented 656 */ 657 PVOID NTAPI 658 RtlPcToFileHeader(IN PVOID PcValue, 659 PVOID* BaseOfImage) 660 { 661 PLIST_ENTRY ModuleListHead; 662 PLIST_ENTRY Entry; 663 PLDR_DATA_TABLE_ENTRY Module; 664 PVOID ImageBase = NULL; 665 666 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock); 667 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; 668 Entry = ModuleListHead->Flink; 669 while (Entry != ModuleListHead) 670 { 671 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); 672 673 if ((ULONG_PTR)PcValue >= (ULONG_PTR)Module->DllBase && 674 (ULONG_PTR)PcValue < (ULONG_PTR)Module->DllBase + Module->SizeOfImage) 675 { 676 ImageBase = Module->DllBase; 677 break; 678 } 679 Entry = Entry->Flink; 680 } 681 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock); 682 683 *BaseOfImage = ImageBase; 684 return ImageBase; 685 } 686 687 NTSTATUS get_buffer(LPWSTR *buffer, SIZE_T needed, PUNICODE_STRING CallerBuffer, BOOLEAN bAllocateBuffer) 688 { 689 WCHAR *p; 690 691 if (CallerBuffer && CallerBuffer->MaximumLength > needed) 692 { 693 p = CallerBuffer->Buffer; 694 CallerBuffer->Length = needed - sizeof(WCHAR); 695 } 696 else 697 { 698 if (!bAllocateBuffer) 699 return STATUS_BUFFER_TOO_SMALL; 700 701 if (CallerBuffer) 702 CallerBuffer->Buffer[0] = 0; 703 704 p = RtlAllocateHeap(RtlGetProcessHeap(), 0, needed ); 705 if (!p) 706 return STATUS_NO_MEMORY; 707 } 708 *buffer = p; 709 710 return STATUS_SUCCESS; 711 } 712 713 /* NOTE: Remove this one once our actctx support becomes better */ 714 NTSTATUS find_actctx_dll( PUNICODE_STRING pnameW, LPWSTR *fullname, PUNICODE_STRING CallerBuffer, BOOLEAN bAllocateBuffer) 715 { 716 static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s','\\'}; 717 static const WCHAR dotManifestW[] = {'.','m','a','n','i','f','e','s','t',0}; 718 719 ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *info; 720 ACTCTX_SECTION_KEYED_DATA data; 721 NTSTATUS status; 722 SIZE_T needed, size = 1024; 723 WCHAR *p; 724 725 data.cbSize = sizeof(data); 726 status = RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL, 727 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, 728 pnameW, &data ); 729 if (status != STATUS_SUCCESS) 730 { 731 //DPRINT1("RtlFindActivationContextSectionString returned 0x%x for %wZ\n", status, pnameW); 732 return status; 733 } 734 735 for (;;) 736 { 737 if (!(info = RtlAllocateHeap( RtlGetProcessHeap(), 0, size ))) 738 { 739 status = STATUS_NO_MEMORY; 740 goto done; 741 } 742 status = RtlQueryInformationActivationContext( 0, data.hActCtx, &data.ulAssemblyRosterIndex, 743 AssemblyDetailedInformationInActivationContext, 744 info, size, &needed ); 745 if (status == STATUS_SUCCESS) break; 746 if (status != STATUS_BUFFER_TOO_SMALL) goto done; 747 RtlFreeHeap( RtlGetProcessHeap(), 0, info ); 748 size = needed; 749 } 750 751 DPRINT("manifestpath === %S\n", info->lpAssemblyManifestPath); 752 DPRINT("DirectoryName === %S\n", info->lpAssemblyDirectoryName); 753 if (!info->lpAssemblyManifestPath /*|| !info->lpAssemblyDirectoryName*/) 754 { 755 status = STATUS_SXS_KEY_NOT_FOUND; 756 goto done; 757 } 758 759 if ((p = wcsrchr( info->lpAssemblyManifestPath, '\\' ))) 760 { 761 DWORD dirlen = info->ulAssemblyDirectoryNameLength / sizeof(WCHAR); 762 763 p++; 764 if (!info->lpAssemblyDirectoryName || _wcsnicmp( p, info->lpAssemblyDirectoryName, dirlen ) || _wcsicmp( p + dirlen, dotManifestW )) 765 { 766 /* manifest name does not match directory name, so it's not a global 767 * windows/winsxs manifest; use the manifest directory name instead */ 768 dirlen = p - info->lpAssemblyManifestPath; 769 needed = (dirlen + 1) * sizeof(WCHAR) + pnameW->Length; 770 771 status = get_buffer(fullname, needed, CallerBuffer, bAllocateBuffer); 772 if (!NT_SUCCESS(status)) 773 goto done; 774 775 p = *fullname; 776 777 memcpy( p, info->lpAssemblyManifestPath, dirlen * sizeof(WCHAR) ); 778 p += dirlen; 779 memcpy( p, pnameW->Buffer, pnameW->Length); 780 p += (pnameW->Length / sizeof(WCHAR)); 781 *p = L'\0'; 782 783 goto done; 784 } 785 } 786 787 needed = (wcslen(SharedUserData->NtSystemRoot) * sizeof(WCHAR) + 788 sizeof(winsxsW) + info->ulAssemblyDirectoryNameLength + pnameW->Length + 2*sizeof(WCHAR)); 789 790 status = get_buffer(fullname, needed, CallerBuffer, bAllocateBuffer); 791 if (!NT_SUCCESS(status)) 792 goto done; 793 794 p = *fullname; 795 796 wcscpy( p, SharedUserData->NtSystemRoot ); 797 p += wcslen(p); 798 memcpy( p, winsxsW, sizeof(winsxsW) ); 799 p += sizeof(winsxsW) / sizeof(WCHAR); 800 memcpy( p, info->lpAssemblyDirectoryName, info->ulAssemblyDirectoryNameLength ); 801 p += info->ulAssemblyDirectoryNameLength / sizeof(WCHAR); 802 *p++ = L'\\'; 803 memcpy( p, pnameW->Buffer, pnameW->Length); 804 p += (pnameW->Length / sizeof(WCHAR)); 805 *p = L'\0'; 806 807 done: 808 RtlFreeHeap( RtlGetProcessHeap(), 0, info ); 809 RtlReleaseActivationContext( data.hActCtx ); 810 DPRINT("%S\n", fullname); 811 return status; 812 } 813 814 /* 815 * @unimplemented 816 */ 817 NTSYSAPI 818 NTSTATUS 819 NTAPI 820 RtlDosApplyFileIsolationRedirection_Ustr(IN ULONG Flags, 821 IN PUNICODE_STRING OriginalName, 822 IN PUNICODE_STRING Extension, 823 IN OUT PUNICODE_STRING StaticString, 824 IN OUT PUNICODE_STRING DynamicString, 825 IN OUT PUNICODE_STRING *NewName, 826 IN PULONG NewFlags, 827 IN PSIZE_T FileNameSize, 828 IN PSIZE_T RequiredLength) 829 { 830 NTSTATUS Status; 831 LPWSTR fullname; 832 WCHAR buffer [MAX_PATH]; 833 UNICODE_STRING localStr, localStr2, *pstrParam; 834 WCHAR *p; 835 BOOLEAN GotExtension; 836 WCHAR c; 837 C_ASSERT(sizeof(UNICODE_NULL) == sizeof(WCHAR)); 838 839 840 /* Check for invalid parameters */ 841 if (!OriginalName) 842 { 843 return STATUS_INVALID_PARAMETER; 844 } 845 846 if (!DynamicString && !StaticString) 847 { 848 return STATUS_INVALID_PARAMETER; 849 } 850 851 if ((DynamicString) && (StaticString) && !(NewName)) 852 { 853 return STATUS_INVALID_PARAMETER; 854 } 855 856 if (!OriginalName->Buffer || OriginalName->Length == 0) 857 { 858 return STATUS_SXS_KEY_NOT_FOUND; 859 } 860 861 if (StaticString && (OriginalName == StaticString || OriginalName->Buffer == StaticString->Buffer)) 862 { 863 return STATUS_SXS_KEY_NOT_FOUND; 864 } 865 866 if ((Flags & RTL_DOS_APPLY_FILE_REDIRECTION_USTR_FLAG_RESPECT_DOT_LOCAL) && 867 NtCurrentPeb()->ProcessParameters && 868 (NtCurrentPeb()->ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_PRIVATE_DLL_PATH)) 869 { 870 UNICODE_STRING RealName, LocalName; 871 WCHAR RealNameBuf[MAX_PATH], LocalNameBuf[MAX_PATH]; 872 873 RtlInitEmptyUnicodeString(&RealName, RealNameBuf, sizeof(RealNameBuf)); 874 RtlInitEmptyUnicodeString(&LocalName, LocalNameBuf, sizeof(LocalNameBuf)); 875 876 Status = RtlComputePrivatizedDllName_U(OriginalName, &RealName, &LocalName); 877 if (!NT_SUCCESS(Status)) 878 { 879 DPRINT1("RtlComputePrivatizedDllName_U failed for %wZ: 0x%lx\n", OriginalName, Status); 880 return Status; 881 } 882 883 if (RtlDoesFileExists_UStr(&LocalName)) 884 { 885 Status = get_buffer(&fullname, LocalName.Length + sizeof(UNICODE_NULL), StaticString, DynamicString != NULL); 886 if (NT_SUCCESS(Status)) 887 { 888 RtlCopyMemory(fullname, LocalName.Buffer, LocalName.Length + sizeof(UNICODE_NULL)); 889 } 890 else 891 { 892 DPRINT1("Error while retrieving buffer for %wZ: 0x%lx\n", OriginalName, Status); 893 } 894 } 895 else if (RtlDoesFileExists_UStr(&RealName)) 896 { 897 Status = get_buffer(&fullname, RealName.Length + sizeof(UNICODE_NULL), StaticString, DynamicString != NULL); 898 if (NT_SUCCESS(Status)) 899 { 900 RtlCopyMemory(fullname, RealName.Buffer, RealName.Length + sizeof(UNICODE_NULL)); 901 } 902 else 903 { 904 DPRINT1("Error while retrieving buffer for %wZ: 0x%lx\n", OriginalName, Status); 905 } 906 } 907 else 908 { 909 Status = STATUS_NOT_FOUND; 910 } 911 912 if (RealName.Buffer != RealNameBuf) 913 RtlFreeUnicodeString(&RealName); 914 if (LocalName.Buffer != LocalNameBuf) 915 RtlFreeUnicodeString(&LocalName); 916 917 if (NT_SUCCESS(Status)) 918 { 919 DPRINT("Redirecting %wZ to %S\n", OriginalName, fullname); 920 if (!StaticString || StaticString->Buffer != fullname) 921 { 922 RtlInitUnicodeString(DynamicString, fullname); 923 *NewName = DynamicString; 924 } 925 else 926 { 927 *NewName = StaticString; 928 } 929 return Status; 930 } 931 } 932 933 pstrParam = OriginalName; 934 935 /* Get the file name with an extension */ 936 p = OriginalName->Buffer + OriginalName->Length / sizeof(WCHAR) - 1; 937 GotExtension = FALSE; 938 while (p >= OriginalName->Buffer) 939 { 940 c = *p--; 941 if (c == L'.') 942 { 943 GotExtension = TRUE; 944 } 945 else if (c == L'\\') 946 { 947 localStr.Buffer = p + 2; 948 localStr.Length = OriginalName->Length - ((ULONG_PTR)localStr.Buffer - (ULONG_PTR)OriginalName->Buffer); 949 localStr.MaximumLength = OriginalName->MaximumLength - ((ULONG_PTR)localStr.Buffer - (ULONG_PTR)OriginalName->Buffer); 950 pstrParam = &localStr; 951 break; 952 } 953 } 954 955 if (!GotExtension) 956 { 957 if (!Extension) 958 { 959 return STATUS_SXS_KEY_NOT_FOUND; 960 } 961 962 if (pstrParam->Length + Extension->Length > sizeof(buffer)) 963 { 964 //FIXME! 965 return STATUS_NO_MEMORY; 966 } 967 968 RtlInitEmptyUnicodeString(&localStr2, buffer, sizeof(buffer)); 969 RtlAppendUnicodeStringToString(&localStr2, pstrParam); 970 RtlAppendUnicodeStringToString(&localStr2, Extension); 971 pstrParam = &localStr2; 972 } 973 974 /* Use wine's function as long as we use wine's sxs implementation in ntdll */ 975 Status = find_actctx_dll(pstrParam, &fullname, StaticString, DynamicString != NULL); 976 if (!NT_SUCCESS(Status)) 977 { 978 return Status; 979 } 980 981 DPRINT("Redirecting %wZ to %S\n", OriginalName, fullname); 982 983 if (!StaticString || StaticString->Buffer != fullname) 984 { 985 RtlInitUnicodeString(DynamicString, fullname); 986 *NewName = DynamicString; 987 } 988 else 989 { 990 *NewName = StaticString; 991 } 992 993 return Status; 994 } 995 996 #ifndef TAG_USTR 997 #define TAG_USTR 'RTSU' 998 #endif 999 #ifndef RtlpAllocateStringMemory 1000 #define RtlpAllocateStringMemory(Bytes, Tag) RtlpAllocateMemory(Bytes, Tag) 1001 #endif 1002 1003 static DWORD 1004 LdrpApisetVersion(VOID) 1005 { 1006 static DWORD CachedApisetVersion = ~0u; 1007 1008 if (CachedApisetVersion == ~0u) 1009 { 1010 DWORD CompatVersion = RosGetProcessCompatVersion(); 1011 1012 switch (CompatVersion) 1013 { 1014 case 0: 1015 break; 1016 case _WIN32_WINNT_VISTA: 1017 /* No apisets in vista yet*/ 1018 CachedApisetVersion = 0; 1019 break; 1020 case _WIN32_WINNT_WIN7: 1021 CachedApisetVersion = APISET_WIN7; 1022 DPRINT1("Activating apisets for Win7\n"); 1023 break; 1024 case _WIN32_WINNT_WIN8: 1025 CachedApisetVersion = APISET_WIN8; 1026 DPRINT1("Activating apisets for Win8\n"); 1027 break; 1028 case _WIN32_WINNT_WINBLUE: 1029 CachedApisetVersion = APISET_WIN81; 1030 DPRINT1("Activating apisets for Win8.1\n"); 1031 break; 1032 case _WIN32_WINNT_WIN10: 1033 CachedApisetVersion = APISET_WIN10; 1034 DPRINT1("Activating apisets for Win10\n"); 1035 break; 1036 default: 1037 DPRINT1("Unknown version 0x%x\n", CompatVersion); 1038 CachedApisetVersion = 0; 1039 break; 1040 } 1041 } 1042 1043 return CachedApisetVersion; 1044 } 1045 1046 NTSYSAPI 1047 NTSTATUS 1048 NTAPI 1049 LdrpApplyFileNameRedirection( 1050 _In_ PUNICODE_STRING OriginalName, 1051 _In_ PUNICODE_STRING Extension, 1052 _Inout_opt_ PUNICODE_STRING StaticString, 1053 _Inout_opt_ PUNICODE_STRING DynamicString, 1054 _Inout_ PUNICODE_STRING *NewName, 1055 _Out_ PBOOLEAN RedirectedDll) 1056 { 1057 1058 /* Check for invalid parameters */ 1059 if (!OriginalName) 1060 { 1061 return STATUS_INVALID_PARAMETER; 1062 } 1063 1064 if (!DynamicString && !StaticString) 1065 { 1066 return STATUS_INVALID_PARAMETER; 1067 } 1068 1069 if (!NewName) 1070 { 1071 return STATUS_INVALID_PARAMETER; 1072 } 1073 1074 *RedirectedDll = FALSE; 1075 1076 PCUNICODE_STRING PrevNewName = *NewName; 1077 UNICODE_STRING ApisetName = {0}; 1078 NTSTATUS Status = STATUS_SUCCESS; 1079 1080 DWORD ApisetVersion = LdrpApisetVersion(); 1081 if (ApisetVersion) 1082 { 1083 Status = ApiSetResolveToHost(ApisetVersion, OriginalName, RedirectedDll, &ApisetName); 1084 if (!NT_SUCCESS(Status)) 1085 { 1086 DPRINT1("ApiSetResolveToHost FAILED: (Status 0x%x)\n", Status); 1087 return Status; 1088 } 1089 } 1090 1091 if (*RedirectedDll) 1092 { 1093 UNICODE_STRING NtSystemRoot; 1094 static const UNICODE_STRING System32 = RTL_CONSTANT_STRING(L"\\System32\\"); 1095 PUNICODE_STRING ResultPath = NULL; 1096 1097 /* This is an apiset we can use */ 1098 RtlInitUnicodeString(&NtSystemRoot, SharedUserData->NtSystemRoot); 1099 1100 SIZE_T Needed = System32.Length + ApisetName.Length + NtSystemRoot.Length + sizeof(UNICODE_NULL); 1101 1102 if (StaticString && StaticString->MaximumLength >= (USHORT)Needed) 1103 { 1104 StaticString->Length = 0; 1105 ResultPath = StaticString; 1106 } 1107 else if (DynamicString) 1108 { 1109 DynamicString->Buffer = RtlpAllocateStringMemory(Needed, TAG_USTR); 1110 if (DynamicString->Buffer == NULL) 1111 { 1112 DPRINT1("LdrpApplyFileNameRedirection out of memory\n"); 1113 return STATUS_NO_MEMORY; 1114 } 1115 DynamicString->MaximumLength = (USHORT)Needed; 1116 DynamicString->Length = 0; 1117 1118 ResultPath = DynamicString; 1119 } 1120 else 1121 { 1122 DPRINT1("ERROR: LdrpApplyFileNameRedirection no inputbuffer valid\n"); 1123 return STATUS_INVALID_PARAMETER; 1124 } 1125 1126 RtlAppendUnicodeStringToString(ResultPath, &NtSystemRoot); 1127 RtlAppendUnicodeStringToString(ResultPath, &System32); 1128 RtlAppendUnicodeStringToString(ResultPath, &ApisetName); 1129 DPRINT1("ApiSetResolveToHost redirected %wZ to %wZ\n", OriginalName, ResultPath); 1130 *NewName = ResultPath; 1131 } 1132 else 1133 { 1134 /* Check if the SxS Assemblies specify another file */ 1135 Status = RtlDosApplyFileIsolationRedirection_Ustr(RTL_DOS_APPLY_FILE_REDIRECTION_USTR_FLAG_RESPECT_DOT_LOCAL, OriginalName, Extension, StaticString, DynamicString, NewName, NULL, NULL, NULL); 1136 1137 /* Check success */ 1138 if (NT_SUCCESS(Status)) 1139 { 1140 /* Let Ldrp know */ 1141 *RedirectedDll = TRUE; 1142 } 1143 else if (Status == STATUS_SXS_KEY_NOT_FOUND) 1144 { 1145 ASSERT(*NewName == PrevNewName); 1146 Status = STATUS_SUCCESS; 1147 } 1148 else 1149 { 1150 /* Unrecoverable SxS failure; did we get a string? */ 1151 if (DynamicString && DynamicString->Buffer) 1152 RtlFreeUnicodeString(DynamicString); 1153 return Status; 1154 } 1155 } 1156 1157 return Status; 1158 } 1159 1160 /* 1161 * @implemented 1162 */ 1163 NTSYSAPI 1164 NTSTATUS 1165 NTAPI 1166 RtlWow64EnableFsRedirection(IN BOOLEAN Wow64FsEnableRedirection) 1167 { 1168 /* This is what Windows returns on x86 */ 1169 return STATUS_NOT_IMPLEMENTED; 1170 } 1171 1172 /* 1173 * @implemented 1174 */ 1175 NTSYSAPI 1176 NTSTATUS 1177 NTAPI 1178 RtlWow64EnableFsRedirectionEx(IN PVOID Wow64FsEnableRedirection, 1179 OUT PVOID *OldFsRedirectionLevel) 1180 { 1181 /* This is what Windows returns on x86 */ 1182 return STATUS_NOT_IMPLEMENTED; 1183 } 1184 1185 /* 1186 * @unimplemented 1187 */ 1188 NTSYSAPI 1189 NTSTATUS 1190 NTAPI 1191 RtlComputeImportTableHash(IN HANDLE FileHandle, 1192 OUT PCHAR Hash, 1193 IN ULONG ImportTableHashSize) 1194 { 1195 UNIMPLEMENTED; 1196 return STATUS_NOT_IMPLEMENTED; 1197 } 1198 1199 NTSTATUS 1200 NTAPI 1201 RtlpSafeCopyMemory( 1202 _Out_writes_bytes_all_(Length) VOID UNALIGNED *Destination, 1203 _In_reads_bytes_(Length) CONST VOID UNALIGNED *Source, 1204 _In_ SIZE_T Length) 1205 { 1206 _SEH2_TRY 1207 { 1208 RtlCopyMemory(Destination, Source, Length); 1209 } 1210 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1211 { 1212 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1213 } 1214 _SEH2_END; 1215 1216 return STATUS_SUCCESS; 1217 } 1218 1219 /* FIXME: code duplication with kernel32/client/time.c */ 1220 ULONG 1221 NTAPI 1222 RtlGetTickCount(VOID) 1223 { 1224 ULARGE_INTEGER TickCount; 1225 1226 #ifdef _WIN64 1227 TickCount.QuadPart = *((volatile ULONG64*)&SharedUserData->TickCount); 1228 #else 1229 while (TRUE) 1230 { 1231 TickCount.HighPart = (ULONG)SharedUserData->TickCount.High1Time; 1232 TickCount.LowPart = SharedUserData->TickCount.LowPart; 1233 1234 if (TickCount.HighPart == (ULONG)SharedUserData->TickCount.High2Time) 1235 break; 1236 1237 YieldProcessor(); 1238 } 1239 #endif 1240 1241 return (ULONG)((UInt32x32To64(TickCount.LowPart, 1242 SharedUserData->TickCountMultiplier) >> 24) + 1243 UInt32x32To64((TickCount.HighPart << 8) & 0xFFFFFFFF, 1244 SharedUserData->TickCountMultiplier)); 1245 } 1246 1247 /* EOF */ 1248