windows-nt/Source/XPSP1/NT/base/ntdll/sxsctxsrch.c
2020-09-26 16:20:57 +08:00

1799 lines
61 KiB
C

/*++
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;
}