|
|
/*++
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 <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <sxsp.h>
#include <stdlib.h>
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; i<ExtHeader->EntryCount; 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; j<TocHeader->EntryCount; 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; jx<TocHeader->EntryCount; 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; i<TocHeader->EntryCount; 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; i<Bucket->ChainCount; 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; i<Bucket->ChainCount; 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 "<GUID buffer too small>"; }
if (Guid == NULL) return "<null>";
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; }
|