1799 lines
61 KiB
C
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;
|
|
}
|
|
|