/*++ Copyright (c) 1989 Microsoft Corporation Module Name: sxsctxsrch.c Abstract: Side-by-side activation support for Windows/NT Implementation of context stack searching Author: Michael Grier (MGrier) 2/2/2000 Revision History: --*/ #pragma warning(disable:4214) // bit field types other than int #pragma warning(disable:4201) // nameless struct/union #pragma warning(disable:4115) // named type definition in parentheses #pragma warning(disable:4127) // condition expression is constant #include #include #include #include #include typedef const void *PCVOID; //#undef DBG_SXS #define DBG_SXS 0 //#if DBG_SXS //#undef DPFLTR_TRACE_LEVEL //#undef DPFLTR_INFO_LEVEL //#define DPFLTR_TRACE_LEVEL DPFLTR_ERROR_LEVEL //#define DPFLTR_INFO_LEVEL DPFLTR_ERROR_LEVEL //#endif #define ARRAY_FITS(_base, _count, _elemtype, _limit) ((((ULONG) (_base)) < (_limit)) && ((((ULONG) ((_base) + ((_count) * (sizeof(_elemtype)))))) <= (_limit))) #define SINGLETON_FITS(_base, _elemtype, _limit) ARRAY_FITS((_base), 1, _elemtype, (_limit)) // // Comparison of unsigned numbers by subtraction does Not work! // #define RTLP_COMPARE_NUMBER(x, y) \ (((x) < (y)) ? -1 : ((x) > (y)) ? +1 : 0) int __cdecl RtlpCompareActivationContextDataTOCEntryById( CONST VOID* VoidElement1, CONST VOID* VoidElement2 ) /*++ This code must kinda sorta mimic code in sxs.dll. base\win32\fusion\dll\whistler\actctxgenctxctb.cpp CActivationContextGenerationContextContributor::Compare But we handle extended sections differently. --*/ { const ACTIVATION_CONTEXT_DATA_TOC_ENTRY UNALIGNED * Element1 = (const ACTIVATION_CONTEXT_DATA_TOC_ENTRY UNALIGNED *)VoidElement1; const ACTIVATION_CONTEXT_DATA_TOC_ENTRY UNALIGNED * Element2 = (const ACTIVATION_CONTEXT_DATA_TOC_ENTRY UNALIGNED *)VoidElement2; return RTLP_COMPARE_NUMBER(Element1->Id, Element2->Id); } NTSTATUS RtlpLocateActivationContextSection( PCACTIVATION_CONTEXT_DATA ActivationContextData, const GUID *ExtensionGuid, ULONG Id, PVOID *SectionData, ULONG *SectionLength ) { NTSTATUS Status = STATUS_SUCCESS; const ACTIVATION_CONTEXT_DATA_TOC_HEADER UNALIGNED * TocHeader = NULL; const ACTIVATION_CONTEXT_DATA_TOC_ENTRY UNALIGNED * TocEntries = NULL; const ACTIVATION_CONTEXT_DATA_TOC_ENTRY UNALIGNED * TocEntry = NULL; ULONG i; #if DBG_SXS DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "Entered RtlpLocateActivationContextSection() Id = %u\n", Id); #endif if ((ActivationContextData->TotalSize < sizeof(ACTIVATION_CONTEXT_DATA)) || (ActivationContextData->HeaderSize < sizeof(ACTIVATION_CONTEXT_DATA))) { DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "SXS/RTL: Activation context data at %p too small; TotalSize = %lu; HeaderSize = %lu\n", ActivationContextData, ActivationContextData->TotalSize, ActivationContextData->HeaderSize); Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT; goto Exit; } if (ExtensionGuid != NULL) { if (ActivationContextData->ExtendedTocOffset != 0) { const ACTIVATION_CONTEXT_DATA_EXTENDED_TOC_HEADER UNALIGNED * ExtHeader = NULL; const ACTIVATION_CONTEXT_DATA_EXTENDED_TOC_ENTRY UNALIGNED * ExtEntry = NULL; if (!SINGLETON_FITS(ActivationContextData->ExtendedTocOffset, ACTIVATION_CONTEXT_DATA_EXTENDED_TOC_HEADER, ActivationContextData->TotalSize)) { DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "SXS/RTL: Extended TOC offset (%ld) is outside bounds of activation context data (%lu bytes)\n", ActivationContextData->ExtendedTocOffset, ActivationContextData->TotalSize); Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT; goto Exit; } ExtHeader = (PCACTIVATION_CONTEXT_DATA_EXTENDED_TOC_HEADER) (((LONG_PTR) ActivationContextData) + ActivationContextData->ExtendedTocOffset); if (!ARRAY_FITS(ExtHeader->FirstEntryOffset, ExtHeader->EntryCount, ACTIVATION_CONTEXT_DATA_EXTENDED_TOC_ENTRY, ActivationContextData->TotalSize)) { DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "SXS/RTL: Extended TOC entry array (starting at offset %ld; count = %lu; entry size = %u) is outside bounds of activation context data (%lu bytes)\n", ExtHeader->FirstEntryOffset, ExtHeader->EntryCount, sizeof(ACTIVATION_CONTEXT_DATA_EXTENDED_TOC_ENTRY), ActivationContextData->TotalSize); Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT; goto Exit; } ExtEntry = (PCACTIVATION_CONTEXT_DATA_EXTENDED_TOC_ENTRY) (((LONG_PTR) ActivationContextData) + ExtHeader->FirstEntryOffset); // No fancy searching for the extension; just a dumb linear search. for (i=0; iEntryCount; i++) { if (IsEqualGUID(ExtensionGuid, &ExtEntry[i].ExtensionGuid)) { if (!SINGLETON_FITS(ExtEntry[i].TocOffset, ACTIVATION_CONTEXT_DATA_TOC_HEADER, ActivationContextData->TotalSize)) { DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "SXS/RTL: Extended TOC section TOC %d (offset: %ld, size: %u) is outside activation context data bounds (%lu bytes)\n", i, ExtEntry[i].TocOffset, sizeof(ACTIVATION_CONTEXT_DATA_TOC_HEADER), ActivationContextData->TotalSize); Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT; goto Exit; } TocHeader = (PCACTIVATION_CONTEXT_DATA_TOC_HEADER) (((LONG_PTR) ActivationContextData) + ExtEntry[i].TocOffset); break; } } } } else if (ActivationContextData->DefaultTocOffset != 0) { TocHeader = (PCACTIVATION_CONTEXT_DATA_TOC_HEADER) (((LONG_PTR) ActivationContextData) + ActivationContextData->DefaultTocOffset); } if ((TocHeader == NULL) || (TocHeader->EntryCount == 0)) { Status = STATUS_SXS_SECTION_NOT_FOUND; goto Exit; } if (!ARRAY_FITS(TocHeader->FirstEntryOffset, TocHeader->EntryCount, ACTIVATION_CONTEXT_DATA_TOC_ENTRY, ActivationContextData->TotalSize)) { DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "SXS/RTL: TOC entry array (offset: %ld; count = %lu; entry size = %u) is outside bounds of activation context data (%lu bytes)\n", TocHeader->FirstEntryOffset, TocHeader->EntryCount, sizeof(ACTIVATION_CONTEXT_DATA_TOC_ENTRY), ActivationContextData->TotalSize); Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT; goto Exit; } TocEntries = (PCACTIVATION_CONTEXT_DATA_TOC_ENTRY) (((LONG_PTR) ActivationContextData) + TocHeader->FirstEntryOffset); if (TocHeader->Flags & ACTIVATION_CONTEXT_DATA_TOC_HEADER_INORDER) { #if DBG // Paranoia while we're writing the code to encode the data structure... ULONG j; for (j=1; jEntryCount; j++) ASSERT(TocEntries[j-1].Id < TocEntries[j].Id); #endif // DBG if (Id < TocEntries[0].Id) { Status = STATUS_SXS_SECTION_NOT_FOUND; goto Exit; } if (TocHeader->Flags & ACTIVATION_CONTEXT_DATA_TOC_HEADER_DENSE) { const ULONG Index = Id - TocEntries[0].Id; #if DBG ULONG jx; for (jx=1; jxEntryCount; jx++) ASSERT((TocEntries[jx-1].Id + 1) == TocEntries[jx].Id); #endif // DBG if (Index >= TocHeader->EntryCount) { Status = STATUS_SXS_SECTION_NOT_FOUND; goto Exit; } // The entries are dense and in order; we can just do an array index. TocEntry = &TocEntries[Index]; } else { ACTIVATION_CONTEXT_DATA_TOC_ENTRY Key; Key.Id = Id; TocEntry = (const ACTIVATION_CONTEXT_DATA_TOC_ENTRY UNALIGNED *) bsearch( &Key, TocEntries, TocHeader->EntryCount, sizeof(*TocEntries), RtlpCompareActivationContextDataTOCEntryById ); } } else { // They're not in order; just do a linear search. for (i=0; iEntryCount; i++) { if (TocEntries[i].Id == Id) { TocEntry = &TocEntries[i]; break; } } } if ((TocEntry == NULL) || (TocEntry->Offset == 0)) { Status = STATUS_SXS_SECTION_NOT_FOUND; goto Exit; } if (!SINGLETON_FITS(TocEntry->Offset, TocEntry->Length, ActivationContextData->TotalSize)) { DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "SXS/RTL: Section found (offset %ld; length %lu) extends past end of activation context data (%lu bytes)\n", TocEntry->Offset, TocEntry->Length, ActivationContextData->TotalSize); Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT; goto Exit; } *SectionData = (PVOID) (((LONG_PTR) ActivationContextData) + TocEntry->Offset); *SectionLength = TocEntry->Length; Status = STATUS_SUCCESS; Exit: #if DBG_SXS DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "Leaving RtlpLocateActivationContextSection() with NTSTATUS 0x%08lx\n", Status); #endif // DBG_SXS return Status; } NTSTATUS RtlpFindNextActivationContextSection( PFINDFIRSTACTIVATIONCONTEXTSECTION Context, PVOID *SectionData, ULONG *SectionLength, PACTIVATION_CONTEXT *ActivationContextOut ) { NTSTATUS Status = STATUS_SUCCESS; PCACTIVATION_CONTEXT_DATA ActivationContextData = NULL; PACTIVATION_CONTEXT ActivationContextWeAreTrying = NULL; const PTEB Teb = NtCurrentTeb(); const PPEB Peb = Teb->ProcessEnvironmentBlock; #if DBG_SXS DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "Entered RtlpFindNextActivationContextSection()\n"); #endif // DBG_SXS if (ActivationContextOut != NULL) *ActivationContextOut = NULL; for (;;) { switch (Context->Depth) { case 0: // first time through; select the activation context at the head of the stack. if (Teb->ActivationContextStack.ActiveFrame != NULL) { PRTL_ACTIVATION_CONTEXT_STACK_FRAME Frame = (PRTL_ACTIVATION_CONTEXT_STACK_FRAME) Teb->ActivationContextStack.ActiveFrame; ActivationContextWeAreTrying = Frame->ActivationContext; if ((ActivationContextWeAreTrying != NULL) && (ActivationContextWeAreTrying != ACTCTX_PROCESS_DEFAULT)) { if (ActivationContextWeAreTrying == ACTCTX_SYSTEM_DEFAULT) { ActivationContextData = Peb->SystemDefaultActivationContextData; } else { ActivationContextData = ActivationContextWeAreTrying->ActivationContextData; } } if (ActivationContextData != NULL) { // We got what we were looking for... Context->Depth = 1; break; } // We explicitly fall through in the other case... } case 1: // try the process default ActivationContextWeAreTrying = ACTCTX_PROCESS_DEFAULT; ActivationContextData = Peb->ActivationContextData; if (ActivationContextData != NULL) { Context->Depth = 2; break; } // explicit fall through... case 2: // try system default ActivationContextWeAreTrying = ACTCTX_SYSTEM_DEFAULT; ActivationContextData = Peb->SystemDefaultActivationContextData; if (ActivationContextData != NULL) { Context->Depth = 3; break; } default: ASSERT(Context->Depth <= 3); if (Context->Depth > 3) { Status = STATUS_INTERNAL_ERROR; goto Exit; } break; } // Hmm... no data. if (ActivationContextData == NULL) { Status = STATUS_SXS_SECTION_NOT_FOUND; goto Exit; } Status = RtlpLocateActivationContextSection( ActivationContextData, Context->ExtensionGuid, Context->Id, SectionData, SectionLength); if (NT_SUCCESS(Status)) break; // If we're not at the end of the search list and we get an error other // than STATUS_SXS_SECTION_NOT_FOUND, report it. If it is // STATUS_SXS_SECTION_NOT_FOUND and we're not at the end of the list, // iterate again. if ((Status != STATUS_SXS_SECTION_NOT_FOUND) || (Context->Depth == 3)) goto Exit; } Context->OutFlags = ((ActivationContextWeAreTrying == ACTCTX_SYSTEM_DEFAULT) ? FIND_ACTIVATION_CONTEXT_SECTION_OUTFLAG_FOUND_IN_SYSTEM_DEFAULT : 0) | ((ActivationContextWeAreTrying == ACTCTX_PROCESS_DEFAULT) ? FIND_ACTIVATION_CONTEXT_SECTION_OUTFLAG_FOUND_IN_PROCESS_DEFAULT : 0) ; if (ActivationContextOut != NULL) { if (ActivationContextWeAreTrying == ACTCTX_SYSTEM_DEFAULT) { // Hide this new value from old code that doesn't understand it. ActivationContextWeAreTrying = ACTCTX_PROCESS_DEFAULT; } *ActivationContextOut = ActivationContextWeAreTrying; } Status = STATUS_SUCCESS; Exit: #if DBG_SXS DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "Leaving RtlpFindNextActivationContextSection() with NTSTATUS 0x%08lx\n", Status); #endif // DBG_SXS return Status; } NTSTATUS NTAPI RtlFindFirstActivationContextSection( IN PFINDFIRSTACTIVATIONCONTEXTSECTION Context, OUT PVOID *SectionData, OUT ULONG *SectionLength, OUT PACTIVATION_CONTEXT *ActivationContextFound OPTIONAL ) { NTSTATUS Status = STATUS_SUCCESS; PACTIVATION_CONTEXT ActivationContextTemp = NULL; #if DBG_SXS DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "Entered RtlFindFirstActivationContextSection()\n"); #endif // DBG_SXS if (ActivationContextFound != NULL) *ActivationContextFound = NULL; if ((Context == NULL) || (Context->Size < sizeof(FINDFIRSTACTIVATIONCONTEXTSECTION)) || (Context->Flags & ~( FIND_ACTIVATION_CONTEXT_SECTION_KEY_RETURN_ACTIVATION_CONTEXT | FIND_ACTIVATION_CONTEXT_SECTION_KEY_RETURN_FLAGS)) || (SectionData == NULL) || (SectionLength == NULL)) { Status = STATUS_INVALID_PARAMETER; goto Exit; } Context->Depth = 0; Status = RtlpFindNextActivationContextSection(Context, SectionData, SectionLength, &ActivationContextTemp); if (!NT_SUCCESS(Status)) goto Exit; if (ActivationContextFound != NULL) { RtlAddRefActivationContext(ActivationContextTemp); *ActivationContextFound = ActivationContextTemp; } Status = STATUS_SUCCESS; Exit: #if DBG_SXS DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "Leaving RtlFindFirstActivationContextSection() with NTSTATUS 0x%08lx\n", Status); #endif // DBG_SXS return Status; } NTSTATUS RtlpFindFirstActivationContextSection( IN PFINDFIRSTACTIVATIONCONTEXTSECTION Context, OUT PVOID *SectionData, OUT ULONG *SectionLength, OUT PACTIVATION_CONTEXT *ActivationContextFound OPTIONAL ) { NTSTATUS Status = STATUS_SUCCESS; #if DBG_SXS DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "Entered %s()\n", __FUNCTION__); #endif // DBG_SXS if (ActivationContextFound != NULL) *ActivationContextFound = NULL; if ((Context == NULL) || (Context->Size < sizeof(FINDFIRSTACTIVATIONCONTEXTSECTION)) || (Context->Flags & ~( FIND_ACTIVATION_CONTEXT_SECTION_KEY_RETURN_ACTIVATION_CONTEXT | FIND_ACTIVATION_CONTEXT_SECTION_KEY_RETURN_FLAGS)) || (SectionData == NULL) || (SectionLength == NULL)) { Status = STATUS_INVALID_PARAMETER; goto Exit; } Context->Depth = 0; Status = RtlpFindNextActivationContextSection(Context, SectionData, SectionLength, ActivationContextFound); if (!NT_SUCCESS(Status)) goto Exit; Status = STATUS_SUCCESS; Exit: #if DBG_SXS DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "Leaving %s() with NTSTATUS 0x%08lx\n", __FUNCTION__, Status); #endif // DBG_SXS return Status; } NTSTATUS NTAPI RtlFindNextActivationContextSection( IN PFINDFIRSTACTIVATIONCONTEXTSECTION Context, OUT PVOID *SectionData, OUT ULONG *SectionLength, OUT PACTIVATION_CONTEXT *ActivationContextFound OPTIONAL ) { NTSTATUS Status = STATUS_SUCCESS; PACTIVATION_CONTEXT ActivationContextTemp = NULL; #if DBG_SXS DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "Entered RtlFindNextActivationContextSection()\n"); #endif // DBG_SXS if (ActivationContextFound != NULL) *ActivationContextFound = NULL; if ((Context == NULL) || (Context->Size < sizeof(FINDFIRSTACTIVATIONCONTEXTSECTION)) || (Context->Flags & ~( FIND_ACTIVATION_CONTEXT_SECTION_KEY_RETURN_ACTIVATION_CONTEXT | FIND_ACTIVATION_CONTEXT_SECTION_KEY_RETURN_FLAGS)) || (SectionData == NULL) || (SectionLength == NULL)) { Status = STATUS_INVALID_PARAMETER; goto Exit; } Status = RtlpFindNextActivationContextSection( Context, SectionData, SectionLength, &ActivationContextTemp); if (!NT_SUCCESS(Status)) goto Exit; if (ActivationContextFound != NULL) { RtlAddRefActivationContext(ActivationContextTemp); *ActivationContextFound = ActivationContextTemp; } Status = STATUS_SUCCESS; Exit: #if DBG_SXS DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "Leaving RtlFindNextActivationContextSection() with NTSTATUS 0x%08lx\n", Status); #endif // DBG_SXS return Status; } VOID NTAPI RtlEndFindActivationContextSection( IN PFINDFIRSTACTIVATIONCONTEXTSECTION Context ) { // We don't maintain any state, so nothing to do today. Who knows what we might // do in the future however... UNREFERENCED_PARAMETER (Context); } NTSTATUS RtlpFindActivationContextSection_FillOutReturnedData( IN ULONG Flags, OUT PACTIVATION_CONTEXT_SECTION_KEYED_DATA ReturnedData, IN OUT PACTIVATION_CONTEXT ActivationContext, IN PCFINDFIRSTACTIVATIONCONTEXTSECTION Context, IN const VOID * UNALIGNED Header, IN ULONG Header_UserDataOffset, IN ULONG Header_UserDataSize, IN ULONG SectionLength ) { NTSTATUS Status; PCACTIVATION_CONTEXT_DATA ActivationContextData; PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER AssemblyRosterHeader; PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_ENTRY AssemblyRosterEntryList; PCACTIVATION_CONTEXT_DATA_ASSEMBLY_INFORMATION AssemblyDataInfo; #if DBG Status = STATUS_INTERNAL_ERROR; #if !defined(INVALID_HANDLE_VALUE) #define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1) #endif ActivationContextData = (PCACTIVATION_CONTEXT_DATA)INVALID_HANDLE_VALUE; AssemblyRosterHeader = (PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER)INVALID_HANDLE_VALUE; AssemblyRosterEntryList = (PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_ENTRY)INVALID_HANDLE_VALUE; AssemblyDataInfo = (PCACTIVATION_CONTEXT_DATA_ASSEMBLY_INFORMATION)INVALID_HANDLE_VALUE; #endif if (Context == NULL) { Status = STATUS_INVALID_PARAMETER; goto Exit; } if (Header == NULL) { Status = STATUS_INVALID_PARAMETER; goto Exit; } if (ReturnedData == NULL) { Status = STATUS_SUCCESS; goto Exit; } if (Header_UserDataOffset != 0) { ReturnedData->SectionGlobalData = (PVOID) (((ULONG_PTR) Header) + Header_UserDataOffset); ReturnedData->SectionGlobalDataLength = Header_UserDataSize; } ReturnedData->SectionBase = (PVOID)Header; ReturnedData->SectionTotalLength = SectionLength; if (Flags & FIND_ACTIVATION_CONTEXT_SECTION_KEY_RETURN_ACTIVATION_CONTEXT) { ASSERT(RTL_CONTAINS_FIELD(ReturnedData, ReturnedData->Size, ActivationContext)); RtlAddRefActivationContext(ActivationContext); ReturnedData->ActivationContext = ActivationContext; } if (Flags & FIND_ACTIVATION_CONTEXT_SECTION_KEY_RETURN_FLAGS) { ASSERT(RTL_CONTAINS_FIELD(ReturnedData, ReturnedData->Size, Flags)); ReturnedData->Flags = ((Context->OutFlags & FIND_ACTIVATION_CONTEXT_SECTION_OUTFLAG_FOUND_IN_PROCESS_DEFAULT) ? ACTIVATION_CONTEXT_SECTION_KEYED_DATA_FLAG_FOUND_IN_PROCESS_DEFAULT : 0) | ((Context->OutFlags & FIND_ACTIVATION_CONTEXT_SECTION_OUTFLAG_FOUND_IN_SYSTEM_DEFAULT) ? ACTIVATION_CONTEXT_SECTION_KEYED_DATA_FLAG_FOUND_IN_SYSTEM_DEFAULT : 0) ; } if (Flags & FIND_ACTIVATION_CONTEXT_SECTION_KEY_RETURN_ASSEMBLY_METADATA) { typedef ACTIVATION_CONTEXT_SECTION_KEYED_DATA RETURNED_DATA; PCACTIVATION_CONTEXT_STRING_SECTION_HEADER AssemblyMetadataStringSectionHeader; PVOID AssemblyMetadataSectionBase; ULONG AssemblyMetadataSectionLength; ULONG AssemblyRosterIndex; #if DBG AssemblyRosterIndex = ~0UL; AssemblyMetadataStringSectionHeader = (PCACTIVATION_CONTEXT_STRING_SECTION_HEADER)INVALID_HANDLE_VALUE; AssemblyMetadataSectionBase = (PVOID)INVALID_HANDLE_VALUE; AssemblyMetadataSectionLength = ~0UL; #endif ASSERT(RTL_CONTAINS_FIELD(ReturnedData, ReturnedData->Size, AssemblyMetadata)); Status = RtlpGetActivationContextData( 0, ActivationContext, Context, /* for its flags */ &ActivationContextData ); if (!NT_SUCCESS(Status)) goto Exit; if (!RTL_VERIFY(ActivationContextData != NULL)) { Status = STATUS_INTERNAL_ERROR; goto Exit; } AssemblyRosterIndex = ReturnedData->AssemblyRosterIndex; ASSERT(AssemblyRosterIndex >= 1); AssemblyRosterHeader = (PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER) (((ULONG_PTR) ActivationContextData) + ActivationContextData->AssemblyRosterOffset); ASSERT(AssemblyRosterIndex < AssemblyRosterHeader->EntryCount); AssemblyRosterEntryList = (PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_ENTRY) (((ULONG_PTR) ActivationContextData) + AssemblyRosterHeader->FirstEntryOffset); AssemblyDataInfo = (PACTIVATION_CONTEXT_DATA_ASSEMBLY_INFORMATION)((ULONG_PTR)ActivationContextData + AssemblyRosterEntryList[AssemblyRosterIndex].AssemblyInformationOffset); ReturnedData->AssemblyMetadata.Information = RTL_CONST_CAST(PACTIVATION_CONTEXT_DATA_ASSEMBLY_INFORMATION)(AssemblyDataInfo); Status = RtlpLocateActivationContextSection( ActivationContextData, NULL, // ExtensionGuid ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION, &AssemblyMetadataSectionBase, &AssemblyMetadataSectionLength ); if (!NT_SUCCESS(Status)) goto Exit; ReturnedData->AssemblyMetadata.SectionBase = AssemblyMetadataSectionBase; ReturnedData->AssemblyMetadata.SectionLength = AssemblyMetadataSectionLength; if (AssemblyMetadataSectionBase != NULL && AssemblyMetadataSectionLength != 0) { ULONG HeaderSize; ULONG Magic; AssemblyMetadataStringSectionHeader = (PCACTIVATION_CONTEXT_STRING_SECTION_HEADER)(((ULONG_PTR)AssemblyMetadataSectionBase) + AssemblyMetadataSectionLength); if (!RTL_CONTAINS_FIELD(AssemblyMetadataStringSectionHeader, AssemblyMetadataSectionLength, Magic)) { Status = STATUS_INTERNAL_ERROR; goto Exit; } if (!RTL_CONTAINS_FIELD(AssemblyMetadataStringSectionHeader, AssemblyMetadataSectionLength, HeaderSize)) { Status = STATUS_INTERNAL_ERROR; goto Exit; } Magic = AssemblyMetadataStringSectionHeader->Magic; if (AssemblyMetadataStringSectionHeader->Magic != ACTIVATION_CONTEXT_STRING_SECTION_MAGIC) { Status = STATUS_INTERNAL_ERROR; goto Exit; } HeaderSize = AssemblyMetadataStringSectionHeader->HeaderSize; if (HeaderSize > AssemblyMetadataSectionLength) { Status = STATUS_INTERNAL_ERROR; goto Exit; } if (AssemblyMetadataSectionLength < sizeof(ACTIVATION_CONTEXT_STRING_SECTION_HEADER)) { Status = STATUS_INTERNAL_ERROR; goto Exit; } if (HeaderSize < sizeof(ACTIVATION_CONTEXT_STRING_SECTION_HEADER)) { Status = STATUS_INTERNAL_ERROR; goto Exit; } if (!RTL_CONTAINS_FIELD(AssemblyMetadataStringSectionHeader, HeaderSize, Magic)) { Status = STATUS_INTERNAL_ERROR; goto Exit; } if (!RTL_CONTAINS_FIELD(AssemblyMetadataStringSectionHeader, HeaderSize, HeaderSize)) { Status = STATUS_INTERNAL_ERROR; goto Exit; } if (!RTL_CONTAINS_FIELD(AssemblyMetadataStringSectionHeader, HeaderSize, UserDataOffset)) { Status = STATUS_INTERNAL_ERROR; goto Exit; } if (!RTL_CONTAINS_FIELD(AssemblyMetadataStringSectionHeader, HeaderSize, UserDataSize)) { Status = STATUS_INTERNAL_ERROR; goto Exit; } ReturnedData->AssemblyMetadata.SectionGlobalDataBase = (PVOID)(((ULONG_PTR)AssemblyMetadataStringSectionHeader) + AssemblyMetadataStringSectionHeader->UserDataOffset); ReturnedData->AssemblyMetadata.SectionGlobalDataLength = AssemblyMetadataStringSectionHeader->UserDataSize; } } Status = STATUS_SUCCESS; Exit: return Status; } NTSTATUS RtlpFindActivationContextSection_CheckParameters( IN ULONG Flags, IN const GUID *ExtensionGuid OPTIONAL, IN ULONG SectionId, IN PCVOID ThingToFind, OUT PACTIVATION_CONTEXT_SECTION_KEYED_DATA ReturnedData OPTIONAL ) { NTSTATUS Status = STATUS_INTERNAL_ERROR; UNREFERENCED_PARAMETER(ExtensionGuid); UNREFERENCED_PARAMETER(SectionId); if ((ThingToFind == NULL) || ((Flags & ~( FIND_ACTIVATION_CONTEXT_SECTION_KEY_RETURN_ACTIVATION_CONTEXT | FIND_ACTIVATION_CONTEXT_SECTION_KEY_RETURN_FLAGS | FIND_ACTIVATION_CONTEXT_SECTION_KEY_RETURN_ASSEMBLY_METADATA )) != 0) || (((Flags & ( FIND_ACTIVATION_CONTEXT_SECTION_KEY_RETURN_ACTIVATION_CONTEXT | FIND_ACTIVATION_CONTEXT_SECTION_KEY_RETURN_FLAGS | FIND_ACTIVATION_CONTEXT_SECTION_KEY_RETURN_ASSEMBLY_METADATA )) != 0) && (ReturnedData == NULL)) || ((ReturnedData != NULL) && (ReturnedData->Size < (FIELD_OFFSET(ACTIVATION_CONTEXT_SECTION_KEYED_DATA, ActivationContext) + sizeof(ReturnedData->ActivationContext))) )) { Status = STATUS_INVALID_PARAMETER; goto Exit; } if ((Flags & FIND_ACTIVATION_CONTEXT_SECTION_KEY_RETURN_FLAGS) != 0 && !RTL_CONTAINS_FIELD(ReturnedData, ReturnedData->Size, Flags) ) { Status = STATUS_INVALID_PARAMETER; DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "SXS: %s() flags contains return_flags but they don't fit in size, return invalid_parameter 0x%08lx.\n", __FUNCTION__, STATUS_INVALID_PARAMETER); goto Exit; } if ((Flags & FIND_ACTIVATION_CONTEXT_SECTION_KEY_RETURN_ASSEMBLY_METADATA) != 0 && !RTL_CONTAINS_FIELD(ReturnedData, ReturnedData->Size, AssemblyMetadata) ) { Status = STATUS_INVALID_PARAMETER; DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "SXS: %s() flags contains return_assembly_metadata but they don't fit in size, return invalid_parameter 0x%08lx.\n", __FUNCTION__, STATUS_INVALID_PARAMETER); goto Exit; } Status = STATUS_SUCCESS; Exit: #if DBG_SXS DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "Leaving RtlFindActivationContextSectionString() with NTSTATUS 0x%08lx\n", Status); #endif // DBG_SXS return Status; } NTSTATUS NTAPI RtlFindActivationContextSectionString( IN ULONG Flags, IN const GUID *ExtensionGuid OPTIONAL, IN ULONG SectionId, IN PCUNICODE_STRING StringToFind, OUT PACTIVATION_CONTEXT_SECTION_KEYED_DATA ReturnedData OPTIONAL ) { NTSTATUS Status = STATUS_INTERNAL_ERROR; FINDFIRSTACTIVATIONCONTEXTSECTION Context; const ACTIVATION_CONTEXT_STRING_SECTION_HEADER UNALIGNED * Header; ULONG StringSectionLength; BOOLEAN EndSearch; ULONG HashAlgorithm; ULONG PseudoKey; PACTIVATION_CONTEXT ActivationContext; #if DBG_SXS CHAR ExtensionGuidBuffer[39]; #endif const PTEB Teb = NtCurrentTeb(); const PPEB Peb = Teb->ProcessEnvironmentBlock; // Super short circuit... if ((Peb->ActivationContextData == NULL) && (Peb->SystemDefaultActivationContextData == NULL) && (Teb->ActivationContextStack.ActiveFrame == NULL)) return STATUS_SXS_SECTION_NOT_FOUND; // Move variable initialization after the short-circuiting so that we truly // do the least amount of work possible prior to the early exit. StringSectionLength = 0; EndSearch = FALSE; HashAlgorithm = HASH_STRING_ALGORITHM_INVALID; PseudoKey = 0; ActivationContext = NULL; #if DBG_SXS DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "Entered RtlFindActivationContextSectionString()\n" " Flags = 0x%08lx\n" " ExtensionGuid = %s\n" " SectionId = %lu\n" " StringToFind = %wZ\n" " ReturnedData = %p\n", Flags, RtlpFormatGuidANSI(ExtensionGuid, ExtensionGuidBuffer, sizeof(ExtensionGuidBuffer)), SectionId, StringToFind, ReturnedData); #endif // DBG_SXS Status = RtlpFindActivationContextSection_CheckParameters(Flags, ExtensionGuid, SectionId, StringToFind, ReturnedData); if (!NT_SUCCESS(Status)) goto Exit; Context.Size = sizeof(Context); Context.Flags = Flags; Context.OutFlags = 0; Context.ExtensionGuid = ExtensionGuid; Context.Id = SectionId; Status = RtlpFindFirstActivationContextSection(&Context, (PVOID *) &Header, &StringSectionLength, &ActivationContext); if (!NT_SUCCESS(Status)) goto Exit; for (;;) { // Validate that this actually looks like a string section... if ((StringSectionLength < sizeof(ACTIVATION_CONTEXT_STRING_SECTION_HEADER)) || (Header->Magic != ACTIVATION_CONTEXT_STRING_SECTION_MAGIC)) { DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "RtlFindActivationContextSectionString() found section at %p (length %lu) which is not a string section\n", Header, StringSectionLength); Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT; goto Exit; } Status = RtlpFindUnicodeStringInSection( Header, StringSectionLength, StringToFind, ReturnedData, &HashAlgorithm, &PseudoKey, NULL, NULL); if (NT_SUCCESS(Status)) break; if (Status != STATUS_SXS_KEY_NOT_FOUND) goto Exit; Status = RtlFindNextActivationContextSection(&Context, (PVOID *) &Header, &StringSectionLength, &ActivationContext); if (!NT_SUCCESS(Status)) { // Convert from section not found to string not found so that the // caller can get an indication that at least some indirection // information was available but just not the particular key that // they're looking for. if (Status == STATUS_SXS_SECTION_NOT_FOUND) Status = STATUS_SXS_KEY_NOT_FOUND; goto Exit; } } SEND_ACTIVATION_CONTEXT_NOTIFICATION(ActivationContext, USED, NULL); if (ReturnedData != NULL) { Status = RtlpFindActivationContextSection_FillOutReturnedData( Flags, ReturnedData, ActivationContext, &Context, Header, Header->UserDataOffset, Header->UserDataSize, StringSectionLength ); if (!NT_SUCCESS(Status)) goto Exit; } Status = STATUS_SUCCESS; Exit: #if DBG_SXS DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "Leaving RtlFindActivationContextSectionString() with NTSTATUS 0x%08lx\n", Status); #endif // DBG_SXS return Status; } int __cdecl RtlpCompareActivationContextStringSectionEntryByPseudoKey( const void *elem1, const void *elem2 ) /*++ This code must mimic code in sxs.dll (base\win32\fusion\dll\whistler\ssgenctx.cpp CSSGenCtx::CompareStringSectionEntries) --*/ { const ACTIVATION_CONTEXT_STRING_SECTION_ENTRY UNALIGNED * pEntry1 = (const ACTIVATION_CONTEXT_STRING_SECTION_ENTRY UNALIGNED *)elem1; const ACTIVATION_CONTEXT_STRING_SECTION_ENTRY UNALIGNED * pEntry2 = (const ACTIVATION_CONTEXT_STRING_SECTION_ENTRY UNALIGNED *)elem2; return RTLP_COMPARE_NUMBER(pEntry1->PseudoKey, pEntry2->PseudoKey); } NTSTATUS RtlpFindUnicodeStringInSection( const ACTIVATION_CONTEXT_STRING_SECTION_HEADER UNALIGNED * Header, SIZE_T SectionSize, PCUNICODE_STRING String, PACTIVATION_CONTEXT_SECTION_KEYED_DATA DataOut, PULONG HashAlgorithm, PULONG PseudoKey, PULONG UserDataSize, PCVOID *UserData ) { NTSTATUS Status = STATUS_SUCCESS; BOOLEAN CaseInsensitiveFlag; BOOLEAN UseHashTable = TRUE; BOOLEAN UsePseudoKey = TRUE; const ACTIVATION_CONTEXT_STRING_SECTION_ENTRY UNALIGNED * Entry = NULL; if (Header->Flags & ACTIVATION_CONTEXT_STRING_SECTION_CASE_INSENSITIVE) { CaseInsensitiveFlag = TRUE; } else { CaseInsensitiveFlag = FALSE; } #if DBG_SXS DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "Entered RtlpFindUnicodeStringInSection() for string %p (->Length = %u; ->Buffer = %p) \"%wZ\"\n", String, (String != NULL) ? String->Length : 0, (String != NULL) ? String->Buffer : 0, String); #endif // DBG_SXS if (UserDataSize != NULL) *UserDataSize = 0; if (UserData != NULL) *UserData = NULL; ASSERT(HashAlgorithm != NULL); ASSERT(PseudoKey != NULL); if (Header->Magic != ACTIVATION_CONTEXT_STRING_SECTION_MAGIC) { #if DBG_SXS DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "RtlpFindUnicodeStringInSection: String section header has invalid .Magic value.\n"); #endif Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT; goto Exit; } // Eliminate the zero element case to make later code simpler. if (Header->ElementCount == 0) { Status = STATUS_SXS_KEY_NOT_FOUND; goto Exit; } if (Header->HashAlgorithm == HASH_STRING_ALGORITHM_INVALID) { UseHashTable = FALSE; UsePseudoKey = FALSE; } else if (*HashAlgorithm != Header->HashAlgorithm) { Status = RtlHashUnicodeString(String, CaseInsensitiveFlag, Header->HashAlgorithm, PseudoKey); if (!NT_SUCCESS(Status)) { if (Status == STATUS_INVALID_PARAMETER) { ULONG TempPseudoKey = 0; // The only likely reason for invalid parameter is that the hash algorithm // wasn't understood. We'll be pedantic and see if everything else is OK... Status = RtlHashUnicodeString(String, CaseInsensitiveFlag, HASH_STRING_ALGORITHM_DEFAULT, &TempPseudoKey); if (!NT_SUCCESS(Status)) { // Something's wrong, probably with the "String" parameter. Punt. goto Exit; } DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "RtlpFindUnicodeStringInSection: Unsupported hash algorithm %lu found in string section.\n", Header->HashAlgorithm); // Ok, it's an algorithm ID that we don't understand. We can't use the hash // table or the pseudokey. UseHashTable = FALSE; UsePseudoKey = FALSE; } else goto Exit; } else { // Record the hash algorithm we used so that we can avoid re-hashing if we have // to search another section. *HashAlgorithm = Header->HashAlgorithm; } } // If we don't understand the format version, we have to do the manual search. if (Header->FormatVersion != ACTIVATION_CONTEXT_STRING_SECTION_FORMAT_WHISTLER) UseHashTable = FALSE; // If there's no hash table, we can't use it! if (Header->SearchStructureOffset == 0) UseHashTable = FALSE; if (UseHashTable) { ULONG i; const ACTIVATION_CONTEXT_STRING_SECTION_HASH_TABLE UNALIGNED * Table = (const ACTIVATION_CONTEXT_STRING_SECTION_HASH_TABLE UNALIGNED *) (((LONG_PTR) Header) + Header->SearchStructureOffset); ULONG Index = ((*PseudoKey) % Table->BucketTableEntryCount); const ACTIVATION_CONTEXT_STRING_SECTION_HASH_BUCKET UNALIGNED * Bucket = ((const ACTIVATION_CONTEXT_STRING_SECTION_HASH_BUCKET UNALIGNED *) (((LONG_PTR) Header) + Table->BucketTableOffset)) + Index; const LONG UNALIGNED *Chain = (const LONG UNALIGNED *) (((LONG_PTR) Header) + Bucket->ChainOffset); for (i=0; iChainCount; i++) { const ACTIVATION_CONTEXT_STRING_SECTION_ENTRY UNALIGNED *TmpEntry = NULL; UNICODE_STRING TmpEntryString; if (((SIZE_T) Chain[i]) > SectionSize) { DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "SXS: String hash collision chain offset at %p (= %ld) out of bounds\n", &Chain[i], Chain[i]); Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT; goto Exit; } TmpEntry = (const ACTIVATION_CONTEXT_STRING_SECTION_ENTRY UNALIGNED *) (((LONG_PTR) Header) + Chain[i]); #if DBG_SXS DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_INFO_LEVEL, "SXS: Searching bucket collision %d; Chain[%d] = %ld\n" " TmpEntry = %p; ->KeyLength = %lu; ->KeyOffset = %lu\n", i, i, Chain[i], TmpEntry, TmpEntry->KeyLength, TmpEntry->KeyOffset); #endif DBG_SXS if (!UsePseudoKey || (TmpEntry->PseudoKey == *PseudoKey)) { if (((SIZE_T) TmpEntry->KeyOffset) > SectionSize) { DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "SXS: String hash table entry at %p has invalid key offset (= %ld)\n" " Header = %p; Index = %lu; Bucket = %p; Chain = %p\n", TmpEntry, TmpEntry->KeyOffset, Header, Index, Bucket, Chain); Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT; goto Exit; } TmpEntryString.Length = (USHORT) TmpEntry->KeyLength; TmpEntryString.MaximumLength = TmpEntryString.Length; TmpEntryString.Buffer = (PWSTR) (((LONG_PTR) Header) + TmpEntry->KeyOffset); if (RtlCompareUnicodeString((PUNICODE_STRING) String, &TmpEntryString, CaseInsensitiveFlag) == 0) { Entry = TmpEntry; break; } } } } else if (UsePseudoKey && ((Header->Flags & ACTIVATION_CONTEXT_STRING_SECTION_ENTRIES_IN_PSEUDOKEY_ORDER) != 0)) { const ACTIVATION_CONTEXT_STRING_SECTION_ENTRY UNALIGNED * const first = (PCACTIVATION_CONTEXT_STRING_SECTION_ENTRY) (((LONG_PTR) Header) + Header->ElementListOffset); const ACTIVATION_CONTEXT_STRING_SECTION_ENTRY UNALIGNED * const last = first + (Header->ElementCount - 1); ACTIVATION_CONTEXT_STRING_SECTION_ENTRY Key; Key.PseudoKey = *PseudoKey; Entry = (const ACTIVATION_CONTEXT_STRING_SECTION_ENTRY UNALIGNED *) bsearch( &Key, first, Header->ElementCount, sizeof(*first), RtlpCompareActivationContextStringSectionEntryByPseudoKey ); if (Entry != NULL) { // Wow, we found the same pseudokey. We need to search all the equal // pseudokeys, so back off to the first entry with this PK while ((Entry != first) && (Entry->PseudoKey == *PseudoKey)) Entry--; // We may have stopped because we found a different pseudokey, or we may // have stopped because we hit the beginning of the list. If we found a // different PK, move ahead one entry. if (Entry->PseudoKey != *PseudoKey) Entry++; do { UNICODE_STRING TmpEntryString; TmpEntryString.Length = (USHORT) Entry->KeyLength; TmpEntryString.MaximumLength = TmpEntryString.Length; TmpEntryString.Buffer = (PWSTR) (((LONG_PTR) Header) + Entry->KeyOffset); if (RtlCompareUnicodeString((PUNICODE_STRING) String, &TmpEntryString, CaseInsensitiveFlag) == 0) break; Entry++; } while ((Entry <= last) && (Entry->PseudoKey == *PseudoKey)); if ((Entry > last) || (Entry->PseudoKey != *PseudoKey)) Entry = NULL; } } else { // Argh; we just have to do it the hard way. const ACTIVATION_CONTEXT_STRING_SECTION_ENTRY UNALIGNED * TmpEntry = (PCACTIVATION_CONTEXT_STRING_SECTION_ENTRY) (((LONG_PTR) Header) + Header->ElementListOffset); ULONG Count; #if DBG_SXS DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_INFO_LEVEL, "RtlpFindUnicodeStringInSection: About to do linear search of %d entries.\n", Header->ElementCount); #endif // DBG_SXS for (Count = Header->ElementCount; Count != 0; Count--, TmpEntry++) { UNICODE_STRING TmpEntryString; TmpEntryString.Length = (USHORT) TmpEntry->KeyLength; TmpEntryString.MaximumLength = TmpEntryString.Length; TmpEntryString.Buffer = (PWSTR) (((LONG_PTR) Header) + TmpEntry->KeyOffset); if (!UsePseudoKey || (TmpEntry->PseudoKey == *PseudoKey)) { if (RtlCompareUnicodeString((PUNICODE_STRING) String, &TmpEntryString, CaseInsensitiveFlag) == 0) { Entry = TmpEntry; break; } } } } if ((Entry == NULL) || (Entry->Offset == 0)) { Status = STATUS_SXS_KEY_NOT_FOUND; goto Exit; } if (DataOut != NULL) { DataOut->DataFormatVersion = Header->DataFormatVersion; DataOut->Data = (PVOID) (((ULONG_PTR) Header) + Entry->Offset); DataOut->Length = Entry->Length; if (RTL_CONTAINS_FIELD(DataOut, DataOut->Size, AssemblyRosterIndex)) DataOut->AssemblyRosterIndex = Entry->AssemblyRosterIndex; } if (UserDataSize != NULL) *UserDataSize = Header->UserDataSize; if ((UserData != NULL) && (Header->UserDataOffset != 0)) *UserData = (PCVOID) (((ULONG_PTR) Header) + Header->UserDataOffset); Status = STATUS_SUCCESS; Exit: #if DBG_SXS DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "Leaving RtlpFindUnicodeStringInSection() with NTSTATUS 0x%08lx\n", Status); #endif // DBG_SXS return Status; } NTSTATUS NTAPI RtlFindActivationContextSectionGuid( IN ULONG Flags, IN const GUID *ExtensionGuid OPTIONAL, IN ULONG SectionId, IN const GUID *GuidToFind, OUT PACTIVATION_CONTEXT_SECTION_KEYED_DATA ReturnedData ) { NTSTATUS Status; FINDFIRSTACTIVATIONCONTEXTSECTION Context; const ACTIVATION_CONTEXT_GUID_SECTION_HEADER UNALIGNED *Header; ULONG GuidSectionLength; BOOLEAN EndSearch; PACTIVATION_CONTEXT ActivationContext; #if DBG CHAR GuidBuffer[39]; CHAR ExtensionGuidBuffer[39]; BOOLEAN DbgPrintSxsTraceLevel; #endif PTEB Teb = NtCurrentTeb(); PPEB Peb = Teb->ProcessEnvironmentBlock; // Super short circuit... if ((Peb->ActivationContextData == NULL) && (Peb->SystemDefaultActivationContextData == NULL) && (Teb->ActivationContextStack.ActiveFrame == NULL)) { #if DBG_SXS DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, __FUNCTION__"({%s}) super short circuited\n", RtlpFormatGuidANSI(GuidToFind, GuidBuffer, sizeof(GuidBuffer)); ); #endif return STATUS_SXS_SECTION_NOT_FOUND; } // Perform initialization after the above test so that we really do the minimal amount of // work before bailing out when there's no side-by-side stuff going on in either the // process or thread. Status = STATUS_INTERNAL_ERROR; GuidSectionLength = 0; EndSearch = FALSE; ActivationContext = NULL; #if DBG // // Comparison to TRUE is odd, but such is NtQueryDebugFilterState. // if (NtQueryDebugFilterState(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL) == TRUE) { DbgPrintSxsTraceLevel = TRUE; } else { DbgPrintSxsTraceLevel = FALSE; } if (DbgPrintSxsTraceLevel) { DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "Entered RtlFindActivationContextSectionGuid()\n" " Flags = 0x%08lx\n" " ExtensionGuid = %s\n" " SectionId = %lu\n" " GuidToFind = %s\n" " ReturnedData = %p\n", Flags, RtlpFormatGuidANSI(ExtensionGuid, ExtensionGuidBuffer, sizeof(ExtensionGuidBuffer)), SectionId, RtlpFormatGuidANSI(GuidToFind, GuidBuffer, sizeof(GuidBuffer)), ReturnedData); } #endif Status = RtlpFindActivationContextSection_CheckParameters(Flags, ExtensionGuid, SectionId, GuidToFind, ReturnedData); if (!NT_SUCCESS(Status)) goto Exit; Context.Size = sizeof(Context); Context.Flags = 0; Context.ExtensionGuid = ExtensionGuid; Context.Id = SectionId; Context.OutFlags = 0; Status = RtlpFindFirstActivationContextSection(&Context, (PVOID *) &Header, &GuidSectionLength, &ActivationContext); if (!NT_SUCCESS(Status)) goto Exit; for (;;) { // Validate that this actually looks like a guid section... if ((GuidSectionLength < sizeof(ACTIVATION_CONTEXT_GUID_SECTION_HEADER)) || (Header->Magic != ACTIVATION_CONTEXT_GUID_SECTION_MAGIC)) { DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "RtlFindActivationContextSectionGuid() found section at %p (length %lu) which is not a GUID section\n", Header, GuidSectionLength); Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT; goto Exit; } Status = RtlpFindGuidInSection( Header, GuidToFind, ReturnedData); if (NT_SUCCESS(Status)) break; // If we failed for any reason other than not finding the key in the section, bail out. if (Status != STATUS_SXS_KEY_NOT_FOUND) goto Exit; Status = RtlpFindNextActivationContextSection(&Context, (PVOID *) &Header, &GuidSectionLength, &ActivationContext); if (!NT_SUCCESS(Status)) { // Convert from section not found to key not found so that the // caller can get an indication that at least some indirection // information was available but just not the particular key that // they're looking for. if (Status == STATUS_SXS_SECTION_NOT_FOUND) Status = STATUS_SXS_KEY_NOT_FOUND; goto Exit; } } SEND_ACTIVATION_CONTEXT_NOTIFICATION(ActivationContext, USED, NULL); if (ReturnedData != NULL) { Status = RtlpFindActivationContextSection_FillOutReturnedData( Flags, ReturnedData, ActivationContext, &Context, Header, Header->UserDataOffset, Header->UserDataSize, GuidSectionLength ); if (!NT_SUCCESS(Status)) goto Exit; } Status = STATUS_SUCCESS; Exit: #if DBG_SXS if (DbgPrintSxsTraceLevel) { DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "Leaving "__FUNCTION__"(%s) with NTSTATUS 0x%08lx\n", RtlpFormatGuidANSI(GuidToFind, GuidBuffer, sizeof(GuidBuffer)), Status); } #endif return Status; } int __cdecl RtlpCompareActivationContextGuidSectionEntryByGuid( const void *elem1, const void *elem2 ) /*++ This code must mimic code in sxs.dll (base\win32\fusion\dll\whistler\gsgenctx.cpp CGSGenCtx::SortGuidSectionEntries) --*/ { const ACTIVATION_CONTEXT_GUID_SECTION_ENTRY UNALIGNED * pLeft = (const ACTIVATION_CONTEXT_GUID_SECTION_ENTRY*)elem1; const ACTIVATION_CONTEXT_GUID_SECTION_ENTRY UNALIGNED * pRight = (const ACTIVATION_CONTEXT_GUID_SECTION_ENTRY*)elem2; return memcmp( &pLeft->Guid, &pRight->Guid, sizeof(GUID) ); } NTSTATUS RtlpFindGuidInSection( const ACTIVATION_CONTEXT_GUID_SECTION_HEADER UNALIGNED *Header, const GUID *Guid, PACTIVATION_CONTEXT_SECTION_KEYED_DATA DataOut ) { NTSTATUS Status = STATUS_SUCCESS; BOOLEAN UseHashTable = TRUE; const ACTIVATION_CONTEXT_GUID_SECTION_ENTRY UNALIGNED *Entry = NULL; #if DBG_SXS CHAR GuidBuffer[39]; DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "Entered "__FUNCTION__"({%s})\n", RtlpFormatGuidANSI(Guid, GuidBuffer, sizeof(GuidBuffer)) ); #endif if (Header->Magic != ACTIVATION_CONTEXT_GUID_SECTION_MAGIC) { #if DBG_SXS DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "RtlpFindGuidInSection: Guid section header has invalid .Magic value.\n"); #endif Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT; goto Exit; } // Eliminate the zero element case to make later code simpler. if (Header->ElementCount == 0) { Status = STATUS_SXS_KEY_NOT_FOUND; goto Exit; } // If we don't understand the format version, we have to do the manual search. if (Header->FormatVersion != ACTIVATION_CONTEXT_GUID_SECTION_FORMAT_WHISTLER) UseHashTable = FALSE; // If there's no hash table, we can't use it! if (Header->SearchStructureOffset == 0) UseHashTable = FALSE; if (UseHashTable) { ULONG i; const ACTIVATION_CONTEXT_GUID_SECTION_HASH_TABLE UNALIGNED *Table = (PCACTIVATION_CONTEXT_GUID_SECTION_HASH_TABLE) (((LONG_PTR) Header) + Header->SearchStructureOffset); ULONG Index = ((Guid->Data1) % Table->BucketTableEntryCount); const ACTIVATION_CONTEXT_GUID_SECTION_HASH_BUCKET UNALIGNED *Bucket = ((PCACTIVATION_CONTEXT_GUID_SECTION_HASH_BUCKET) (((LONG_PTR) Header) + Table->BucketTableOffset)) + Index; const ULONG UNALIGNED *Chain = (PULONG) (((LONG_PTR) Header) + Bucket->ChainOffset); for (i=0; iChainCount; i++) { const ACTIVATION_CONTEXT_GUID_SECTION_ENTRY UNALIGNED * TmpEntry = (PCACTIVATION_CONTEXT_GUID_SECTION_ENTRY) (((LONG_PTR) Header) + *Chain++); if (RtlCompareMemory(&TmpEntry->Guid, Guid, sizeof(GUID)) == sizeof(GUID)) { Entry = TmpEntry; break; } } } else if ((Header->Flags & ACTIVATION_CONTEXT_GUID_SECTION_ENTRIES_IN_ORDER) != 0) { const ACTIVATION_CONTEXT_GUID_SECTION_ENTRY UNALIGNED * const first = (PCACTIVATION_CONTEXT_GUID_SECTION_ENTRY) (((LONG_PTR) Header) + Header->ElementListOffset); ACTIVATION_CONTEXT_GUID_SECTION_ENTRY Key; Key.Guid = *Guid; Entry = (const ACTIVATION_CONTEXT_GUID_SECTION_ENTRY UNALIGNED *) bsearch( &Key, first, Header->ElementCount, sizeof(*first), RtlpCompareActivationContextGuidSectionEntryByGuid ); } else { // Argh; we just have to do it the hard way. const ACTIVATION_CONTEXT_GUID_SECTION_ENTRY UNALIGNED * TmpEntry = (const ACTIVATION_CONTEXT_GUID_SECTION_ENTRY UNALIGNED *) (((LONG_PTR) Header) + Header->ElementListOffset); ULONG Count; #if DBG_SXS DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_INFO_LEVEL, __FUNCTION__"({%s}): About to do linear search of %d entries.\n", RtlpFormatGuidANSI(Guid, GuidBuffer, sizeof(GuidBuffer)), Header->ElementCount); #endif // DBG_SXS for (Count = Header->ElementCount; Count != 0; Count--, TmpEntry++) { if (RtlCompareMemory(&TmpEntry->Guid, Guid, sizeof(GUID)) == sizeof(GUID)) { Entry = TmpEntry; break; } } } if ((Entry == NULL) || (Entry->Offset == 0)) { Status = STATUS_SXS_KEY_NOT_FOUND; goto Exit; } if (DataOut != NULL) { DataOut->DataFormatVersion = Header->DataFormatVersion; DataOut->Data = (PVOID) (((ULONG_PTR) Header) + Entry->Offset); DataOut->Length = Entry->Length; if (RTL_CONTAINS_FIELD(DataOut, DataOut->Size, AssemblyRosterIndex)) DataOut->AssemblyRosterIndex = Entry->AssemblyRosterIndex; } Status = STATUS_SUCCESS; Exit: #if DBG_SXS DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "Leaving "__FUNCTION__"({%s}) with NTSTATUS 0x%08lx\n", RtlpFormatGuidANSI(Guid, GuidBuffer, sizeof(GuidBuffer)), Status); #endif // DBG_SXS return Status; } #define tohexdigit(_x) ((CHAR) (((_x) < 10) ? ((_x) + '0') : ((_x) + 'A' - 10))) PSTR RtlpFormatGuidANSI( const GUID *Guid, PSTR Buffer, SIZE_T BufferLength ) { CHAR *pch = Buffer; ASSERT(BufferLength > 38); if (BufferLength <= 38) { return ""; } if (Guid == NULL) return ""; pch = Buffer; *pch++ = '{'; *pch++ = tohexdigit((Guid->Data1 >> 28) & 0xf); *pch++ = tohexdigit((Guid->Data1 >> 24) & 0xf); *pch++ = tohexdigit((Guid->Data1 >> 20) & 0xf); *pch++ = tohexdigit((Guid->Data1 >> 16) & 0xf); *pch++ = tohexdigit((Guid->Data1 >> 12) & 0xf); *pch++ = tohexdigit((Guid->Data1 >> 8) & 0xf); *pch++ = tohexdigit((Guid->Data1 >> 4) & 0xf); *pch++ = tohexdigit((Guid->Data1 >> 0) & 0xf); *pch++ = '-'; *pch++ = tohexdigit((Guid->Data2 >> 12) & 0xf); *pch++ = tohexdigit((Guid->Data2 >> 8) & 0xf); *pch++ = tohexdigit((Guid->Data2 >> 4) & 0xf); *pch++ = tohexdigit((Guid->Data2 >> 0) & 0xf); *pch++ = '-'; *pch++ = tohexdigit((Guid->Data3 >> 12) & 0xf); *pch++ = tohexdigit((Guid->Data3 >> 8) & 0xf); *pch++ = tohexdigit((Guid->Data3 >> 4) & 0xf); *pch++ = tohexdigit((Guid->Data3 >> 0) & 0xf); *pch++ = '-'; *pch++ = tohexdigit((Guid->Data4[0] >> 4) & 0xf); *pch++ = tohexdigit((Guid->Data4[0] >> 0) & 0xf); *pch++ = tohexdigit((Guid->Data4[1] >> 4) & 0xf); *pch++ = tohexdigit((Guid->Data4[1] >> 0) & 0xf); *pch++ = '-'; *pch++ = tohexdigit((Guid->Data4[2] >> 4) & 0xf); *pch++ = tohexdigit((Guid->Data4[2] >> 0) & 0xf); *pch++ = tohexdigit((Guid->Data4[3] >> 4) & 0xf); *pch++ = tohexdigit((Guid->Data4[3] >> 0) & 0xf); *pch++ = tohexdigit((Guid->Data4[4] >> 4) & 0xf); *pch++ = tohexdigit((Guid->Data4[4] >> 0) & 0xf); *pch++ = tohexdigit((Guid->Data4[5] >> 4) & 0xf); *pch++ = tohexdigit((Guid->Data4[5] >> 0) & 0xf); *pch++ = tohexdigit((Guid->Data4[6] >> 4) & 0xf); *pch++ = tohexdigit((Guid->Data4[6] >> 0) & 0xf); *pch++ = tohexdigit((Guid->Data4[7] >> 4) & 0xf); *pch++ = tohexdigit((Guid->Data4[7] >> 0) & 0xf); *pch++ = '}'; *pch++ = '\0'; return Buffer; } NTSTATUS RtlpGetActivationContextData( IN ULONG Flags, IN PCACTIVATION_CONTEXT ActivationContext, IN PCFINDFIRSTACTIVATIONCONTEXTSECTION FindContext, OPTIONAL /* This is used for its flags. */ OUT PCACTIVATION_CONTEXT_DATA* ActivationContextData ) { NTSTATUS Status = STATUS_INTERNAL_ERROR; // in case someone forgets to set it... SIZE_T PebOffset; if (ActivationContextData == NULL) { Status = STATUS_INVALID_PARAMETER_4; goto Exit; } if (Flags & ~(RTLP_GET_ACTIVATION_CONTEXT_DATA_MAP_NULL_TO_EMPTY)) { Status = STATUS_INVALID_PARAMETER_1; goto Exit; } *ActivationContextData = NULL; PebOffset = 0; // // We should use RtlpMapSpecialValuesToBuiltInActivationContexts here, but // it doesn't handle all the values and it isn't worth fixing it right now. // switch ((ULONG_PTR)ActivationContext) { case ((ULONG_PTR)NULL): if (FindContext == NULL) { PebOffset = FIELD_OFFSET(PEB, ActivationContextData); } else { switch ( FindContext->OutFlags & ( FIND_ACTIVATION_CONTEXT_SECTION_OUTFLAG_FOUND_IN_PROCESS_DEFAULT | FIND_ACTIVATION_CONTEXT_SECTION_OUTFLAG_FOUND_IN_SYSTEM_DEFAULT )) { case 0: // FALLTHROUGH case FIND_ACTIVATION_CONTEXT_SECTION_OUTFLAG_FOUND_IN_PROCESS_DEFAULT: PebOffset = FIELD_OFFSET(PEB, ActivationContextData); break; case FIND_ACTIVATION_CONTEXT_SECTION_OUTFLAG_FOUND_IN_SYSTEM_DEFAULT: PebOffset = FIELD_OFFSET(PEB, SystemDefaultActivationContextData); break; case (FIND_ACTIVATION_CONTEXT_SECTION_OUTFLAG_FOUND_IN_PROCESS_DEFAULT | FIND_ACTIVATION_CONTEXT_SECTION_OUTFLAG_FOUND_IN_SYSTEM_DEFAULT): Status = STATUS_INVALID_PARAMETER_2; goto Exit; break; } } break; case ((ULONG_PTR)ACTCTX_EMPTY): *ActivationContextData = &RtlpTheEmptyActivationContextData; break; case ((ULONG_PTR)ACTCTX_SYSTEM_DEFAULT): PebOffset = FIELD_OFFSET(PEB, SystemDefaultActivationContextData); break; default: *ActivationContextData = ActivationContext->ActivationContextData; break; } if (PebOffset != 0) *ActivationContextData = *(PCACTIVATION_CONTEXT_DATA*)(((ULONG_PTR)NtCurrentPeb()) + PebOffset); // // special transmutation of lack of actctx into the empty actctx // if (*ActivationContextData == NULL) if ((Flags & RTLP_GET_ACTIVATION_CONTEXT_DATA_MAP_NULL_TO_EMPTY) != 0) *ActivationContextData = &RtlpTheEmptyActivationContextData; Status = STATUS_SUCCESS; Exit: return Status; }