1593 lines
55 KiB
C
1593 lines
55 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 2000 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
srvsxs.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Support for side-by-side (fusion) in the win32 base server.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Michael J. Grier (MGrier) 23-Feb-2000
|
||
|
|
||
|
Revision History:
|
||
|
Jay Krell (a-JayK) July 2000 moved file opening from csr/sxs to kernel32
|
||
|
marshal over large CreateProcess message with manifest, policy, and assembly path
|
||
|
pass IStreams to sxs
|
||
|
|
||
|
Jay Krell (a-JayK) September 2000
|
||
|
moved (assembly directory computation from manifest) from basesrv to kernel32
|
||
|
|
||
|
Jay Krell (a-JayK) October 2000 System Default Activation Context
|
||
|
(aka System Compatible Activation Context)
|
||
|
--*/
|
||
|
|
||
|
#include "basesrv.h"
|
||
|
#include "SxsApi.h"
|
||
|
#include "ntldr.h"
|
||
|
#include "nturtl.h"
|
||
|
#include "mmapstm.h"
|
||
|
#include <limits.h>
|
||
|
#if defined(_WIN64)
|
||
|
#include "wow64t.h"
|
||
|
#endif // defined(_WIN64)
|
||
|
|
||
|
#if !defined(BASE_SRV_SXS_HRESULT_FROM_STATUS)
|
||
|
#if defined(RTLP_HRESULT_FROM_STATUS)
|
||
|
#define BASE_SRV_SXS_HRESULT_FROM_STATUS(x) RTLP_HRESULT_FROM_STATUS(x)
|
||
|
#else
|
||
|
#define BASE_SRV_SXS_HRESULT_FROM_STATUS(x) HRESULT_FROM_WIN32(RtlNtStatusToDosErrorNoTeb(x))
|
||
|
//#define BASE_SRV_SXS_HRESULT_FROM_STATUS(x) HRESULT_FROM_WIN32(RtlNtStatusToDosError(x))
|
||
|
//#define BASE_SRV_SXS_HRESULT_FROM_STATUS(x) HRESULT_FROM_NT(x)
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#define DPFLTR_LEVEL_STATUS(x) ((NT_SUCCESS(x) \
|
||
|
|| (x) == STATUS_OBJECT_NAME_NOT_FOUND \
|
||
|
|| (x) == STATUS_OBJECT_PATH_NOT_FOUND \
|
||
|
|| (x) == STATUS_NO_SUCH_FILE \
|
||
|
|| (x) == STATUS_RESOURCE_DATA_NOT_FOUND \
|
||
|
|| (x) == STATUS_RESOURCE_TYPE_NOT_FOUND \
|
||
|
|| (x) == STATUS_RESOURCE_NAME_NOT_FOUND \
|
||
|
|| (x) == STATUS_SXS_CANT_GEN_ACTCTX \
|
||
|
|| (x) == STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY \
|
||
|
) \
|
||
|
? DPFLTR_TRACE_LEVEL : DPFLTR_ERROR_LEVEL)
|
||
|
|
||
|
#define DPFLTR_LEVEL_WIN32(x) ((x) ? DPFLTR_TRACE_LEVEL : DPFLTR_ERROR_LEVEL)
|
||
|
|
||
|
typedef union _BASE_SRV_SXS_STREAM_UNION_WITH_VTABLE {
|
||
|
BASE_SRV_MEMORY_MAPPED_STREAM_WITH_VTABLE Mmap;
|
||
|
RTL_OUT_OF_PROCESS_MEMORY_STREAM_WITH_VTABLE OutOfProcess;
|
||
|
} BASE_SRV_SXS_STREAM_UNION_WITH_VTABLE, *PBASE_SRV_SXS_STREAM_UNION_WITH_VTABLE;
|
||
|
|
||
|
#if BASESRV_UNLOAD_SXS_DLL
|
||
|
PVOID SxsDllHandle;
|
||
|
RTL_CRITICAL_SECTION BaseSrvSxsCritSec;
|
||
|
LONG SxsDllHandleRefCount;
|
||
|
#endif
|
||
|
LONG BaseSrvSxsGetActCtxGenCount;
|
||
|
PSXS_GENERATE_ACTIVATION_CONTEXT_FUNCTION SxsActivationContextGenerationFunction;
|
||
|
ULONG PinnedMsvcrtDll; // ULONG instead of BOOLEAN for atomicity of store?
|
||
|
|
||
|
const UNICODE_STRING EmptyString = RTL_CONSTANT_STRING(L"");
|
||
|
|
||
|
RTL_CRITICAL_SECTION BaseSrvSxsSystemDefaultActivationContextCriticalSection;
|
||
|
BASE_SRV_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT SxsSystemDefaultActivationContexts[] =
|
||
|
{
|
||
|
#ifdef _WIN64
|
||
|
{ NULL, RTL_CONSTANT_STRING(L"x86"), PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 },
|
||
|
#else
|
||
|
{ NULL, RTL_CONSTANT_STRING(L"x86"), PROCESSOR_ARCHITECTURE_INTEL },
|
||
|
#endif
|
||
|
{ NULL, RTL_CONSTANT_STRING(L"ia64"), PROCESSOR_ARCHITECTURE_IA64 },
|
||
|
{ NULL, RTL_CONSTANT_STRING(L"amd64"), PROCESSOR_ARCHITECTURE_AMD64 }
|
||
|
};
|
||
|
|
||
|
#define STRING(x) #x
|
||
|
#define IF_NOT_SUCCESS_TRACE_AND_EXIT(subfunction) \
|
||
|
do { \
|
||
|
if (!NT_SUCCESS(Status)) { \
|
||
|
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_LEVEL_STATUS(Status), "SXS: %s() " STRING(subfunction) " failed 0x%08lx\n", __FUNCTION__, Status)); \
|
||
|
goto Exit; \
|
||
|
} \
|
||
|
} while(0)
|
||
|
|
||
|
#define ASSERT_UNICODE_STRING_IS_NUL_TERMINATED(ustr) \
|
||
|
ASSERT((ustr)->MaximumLength >= ((ustr)->Length + sizeof(WCHAR))); \
|
||
|
ASSERT((ustr)->Buffer[(ustr)->Length / sizeof(WCHAR)] == 0);
|
||
|
|
||
|
#define IMPERSONATE_ENTIRE_SXS_CALL 1
|
||
|
|
||
|
#if !IMPERSONATE_ENTIRE_SXS_CALL
|
||
|
|
||
|
typedef struct _ACTIVATION_CONTEXT_GENERATION_IMPERSONATION_CONTEXT {
|
||
|
BOOL SuccessfulImpersonation;
|
||
|
} ACTIVATION_CONTEXT_GENERATION_IMPERSONATION_CONTEXT, *PACTIVATION_CONTEXT_GENERATION_IMPERSONATION_CONTEXT;
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
__stdcall
|
||
|
BaseSrvpSxsActivationContextGenerationImpersonationCallback(
|
||
|
PVOID ContextIn,
|
||
|
BOOL Impersonate
|
||
|
)
|
||
|
/*++
|
||
|
Routine Description:
|
||
|
This function is called back by the sxs.dll API to create an activation
|
||
|
context when it needs to impersonate or unimpersonate the client of the
|
||
|
CSR message.
|
||
|
Arguments:
|
||
|
ContextIn - PACTIVATION_CONTEXT_GENERATION_IMPERSONATION_CONTEXT
|
||
|
passed in to the create activation context API returned back
|
||
|
as a PVOID. We use it to track whether the previous impersonate
|
||
|
call succeeded.
|
||
|
Impersonate - nonzero (TRUE) if this function should impersonate the
|
||
|
client, zero (FALSE) if the function should revert to the normal
|
||
|
csrss identity.
|
||
|
Return Value:
|
||
|
// the old comment
|
||
|
TRUE on success; FALSE on failure. The last error state is as
|
||
|
CsrImpersonateClient() leaves it.
|
||
|
// a more accurate comment?
|
||
|
TRUE on successful impersonation, FALSE upon no successful impersonation
|
||
|
the last error status is defined
|
||
|
--*/
|
||
|
{
|
||
|
BOOL Success = FALSE;
|
||
|
PACTIVATION_CONTEXT_GENERATION_IMPERSONATION_CONTEXT Context =
|
||
|
(PACTIVATION_CONTEXT_GENERATION_IMPERSONATION_CONTEXT) ContextIn;
|
||
|
if (Impersonate) {
|
||
|
Context->SuccessfulImpersonation = CsrImpersonateClient(NULL);
|
||
|
if you enable this function, you must revisit its error handling
|
||
|
if (!Context->SuccessfulImpersonation)
|
||
|
goto Exit;
|
||
|
} else {
|
||
|
if (Context->SuccessfulImpersonation) {
|
||
|
CsrRevertToSelf();
|
||
|
Context->SuccessfulImpersonation = FALSE;
|
||
|
} else
|
||
|
goto Exit;
|
||
|
}
|
||
|
Success = TRUE;
|
||
|
Exit:
|
||
|
return Success;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
//#define TRACE_AND_EXECUTE(x) do { DbgPrint("%s\n", #x); x ; } while(0)
|
||
|
#define TRACE_AND_EXECUTE(x) x
|
||
|
|
||
|
NTSTATUS
|
||
|
BaseSrvSxsInvalidateSystemDefaultActivationContextCache(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
ULONG i;
|
||
|
HANDLE LocalSystemDefaultActivationContextSections[RTL_NUMBER_OF(SxsSystemDefaultActivationContexts)];
|
||
|
HANDLE SectionHandle;
|
||
|
RtlEnterCriticalSection(&BaseSrvSxsSystemDefaultActivationContextCriticalSection);
|
||
|
__try {
|
||
|
//
|
||
|
// First copy to locals to minimize time in the critical section.
|
||
|
//
|
||
|
for (i = 0 ; i != RTL_NUMBER_OF(SxsSystemDefaultActivationContexts) ; ++i) {
|
||
|
LocalSystemDefaultActivationContextSections[i] = SxsSystemDefaultActivationContexts[i].Section;
|
||
|
SxsSystemDefaultActivationContexts[i].Section = NULL;
|
||
|
}
|
||
|
} __finally {
|
||
|
RtlLeaveCriticalSection(&BaseSrvSxsSystemDefaultActivationContextCriticalSection);
|
||
|
}
|
||
|
//
|
||
|
// Then iterate over locals, closing.
|
||
|
//
|
||
|
for (i = 0 ; i != RTL_NUMBER_OF(LocalSystemDefaultActivationContextSections) ; ++i) {
|
||
|
SectionHandle = LocalSystemDefaultActivationContextSections[i];
|
||
|
if (SectionHandle != NULL) {
|
||
|
NTSTATUS Status1 = STATUS_SUCCESS;
|
||
|
RTL_SOFT_VERIFY(NT_SUCCESS(Status1 = NtClose(SectionHandle)));
|
||
|
}
|
||
|
}
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
BaseSrvSxsInit(
|
||
|
IN PBASE_STATIC_SERVER_DATA pStaticServerData
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Function called during csr/basesrv.dll initialization which
|
||
|
creates a critical section we use to guard loading and
|
||
|
unloading sxs.dll. We use a critical section rather
|
||
|
then just relying on the peb loader lock to manage the
|
||
|
reference count because we want to be able to call a
|
||
|
one-time initialization function on load and a one-time
|
||
|
uninitialization function on unload.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pStaticServerData - not used, but it's the standard parameter
|
||
|
passed to all the other sub-init routines by the main
|
||
|
csr init routine.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NTSTATUS indicating the disposition of the function.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
|
||
|
Status = RtlInitializeCriticalSection(&BaseSrvSxsSystemDefaultActivationContextCriticalSection);
|
||
|
if (!NT_SUCCESS(Status))
|
||
|
goto Exit;
|
||
|
#if BASESRV_UNLOAD_SXS_DLL
|
||
|
Status = RtlInitializeCriticalSection(&BaseSrvSxsCritSec);
|
||
|
if (!NT_SUCCESS(Status))
|
||
|
goto Exit;
|
||
|
ASSERT(SxsDllHandle == NULL);
|
||
|
ASSERT(SxsActivationContextGenerationFunction == NULL);
|
||
|
ASSERT(SxsDllHandleRefCount == 0);
|
||
|
#endif
|
||
|
ASSERT(BaseSrvSxsGetActCtxGenCount == 0);
|
||
|
Status = STATUS_SUCCESS;
|
||
|
Exit:
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
BaseSrvSxsMapViewOfSection(
|
||
|
OUT PVOID* Address,
|
||
|
IN HANDLE Process,
|
||
|
IN HANDLE Section,
|
||
|
IN ULONGLONG Offset,
|
||
|
IN SIZE_T Size,
|
||
|
IN ULONG Protect,
|
||
|
IN ULONG AllocationType
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
pare down the NtMapViewOfSection parameter list to the parameters
|
||
|
that actually ever vary in common use
|
||
|
allow for unaligned mappings, both in the offset and the size
|
||
|
the memory manager wants both aligned to 64k
|
||
|
change the parameters that aren't needed to be inout to only in
|
||
|
the out-ness of the native parameters doesn't seem useful,
|
||
|
esp. because the mm will not align your parameters and
|
||
|
return the aligned values
|
||
|
deprecate LARGE_INTEGER, use LONGLONG instead
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Subset of NtMapViewOfSection, but can be unaligned
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NTSTATUS
|
||
|
|
||
|
Note:
|
||
|
It is tempting to pare down the parameter list since many of them
|
||
|
are always the same: ZeroBits, CommitSize, InheritDisposition, AllocationType.
|
||
|
It is also tempting to move this to Rtl.
|
||
|
--*/
|
||
|
{
|
||
|
LARGE_INTEGER LargeIntegerOffset;
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
SIZE_T OffsetRemainder;
|
||
|
SIZE_T SizeRemainder;
|
||
|
|
||
|
#define SIXTY_FOUR_K (1UL << 16)
|
||
|
#define VIEW_OFFSET_ALIGNMENT SIXTY_FOUR_K
|
||
|
#define VIEW_SIZE_ALIGNMENT SIXTY_FOUR_K
|
||
|
|
||
|
KdPrintEx((
|
||
|
DPFLTR_SXS_ID,
|
||
|
DPFLTR_TRACE_LEVEL,
|
||
|
"SRVSXS: %s(\n"
|
||
|
"SRVSXS: Process %p\n"
|
||
|
"SRVSXS: Section %p\n"
|
||
|
"SRVSXS: Offset 0x%I64x\n"
|
||
|
"SRVSXS: Size 0x%Ix\n"
|
||
|
"SRVSXS: ) beginning\n",
|
||
|
__FUNCTION__,
|
||
|
Process,
|
||
|
Section,
|
||
|
Offset,
|
||
|
Size
|
||
|
));
|
||
|
|
||
|
ASSERT(Address != NULL);
|
||
|
*Address = NULL;
|
||
|
|
||
|
//
|
||
|
// round down offset, round up size
|
||
|
// must round offset first, since rounding it alters size
|
||
|
//
|
||
|
|
||
|
#if 1 // Mm comments allow this, but the code does not.
|
||
|
OffsetRemainder = (((SIZE_T)Offset) % VIEW_OFFSET_ALIGNMENT);
|
||
|
if (OffsetRemainder != 0) {
|
||
|
Offset -= OffsetRemainder;
|
||
|
if (Size != 0) {
|
||
|
Size += OffsetRemainder;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if 0 // Mm allows this.
|
||
|
SizeRemainder = Size % VIEW_SIZE_ALIGNMENT;
|
||
|
if (SizeRemainder != 0) {
|
||
|
Size = Size + (VIEW_SIZE_ALIGNMENT - SizeRemainder);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
LargeIntegerOffset.QuadPart = Offset;
|
||
|
|
||
|
Status =
|
||
|
NtMapViewOfSection(
|
||
|
Section,
|
||
|
Process,
|
||
|
Address,
|
||
|
0, // ZeroBits
|
||
|
0, // CommitSize
|
||
|
&LargeIntegerOffset,
|
||
|
&Size,
|
||
|
ViewShare, // InheritDisposition
|
||
|
AllocationType, // AllocationType
|
||
|
Protect);
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
*Address = ((PUCHAR)*Address) + OffsetRemainder;
|
||
|
|
||
|
Exit:
|
||
|
//
|
||
|
// If the Memory Manager returns STATUS_MAPPED_ALIGNMENT,
|
||
|
// then we have failed at our task.
|
||
|
//
|
||
|
ASSERT(Status != STATUS_MAPPED_ALIGNMENT);
|
||
|
#if DBG
|
||
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_LEVEL_STATUS(Status), "SXS: %s() exiting 0x%08lx\n", __FUNCTION__, Status);
|
||
|
#endif
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
BaseSrvSxsCreateActivationContextFromStruct(
|
||
|
HANDLE CsrClientProcess,
|
||
|
HANDLE SxsClientProcess,
|
||
|
PBASE_SXS_CREATE_ACTIVATION_CONTEXT_MSG Struct,
|
||
|
OUT HANDLE* OutSection
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function handles the CSR message both for CreateActCtx
|
||
|
and CreateProcess. Pointers in the "Struct" are trusted (vs.
|
||
|
pointers in a "message").
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
CsrClientProcess - the process that called CreateProcess or CreateActCtx
|
||
|
or NtCurrentProcess for creating system default activation context (csr)
|
||
|
|
||
|
SxsClientProcess - CreateProcess: the new process
|
||
|
CreateActCtx: the calling process (csr client process)
|
||
|
System default: NtCurrentProcess (csr)
|
||
|
|
||
|
Struct - the parameters marshaled from the csr client process
|
||
|
|
||
|
OutSection - for creating the system default context that gets mapped repeatedly
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NTSTATUS
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ASSERT(Struct != NULL);
|
||
|
if (Struct == NULL) {
|
||
|
return STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
#define BASE_MSG_SXS_MINIMAL_FLAGS \
|
||
|
( BASE_MSG_SXS_MANIFEST_PRESENT \
|
||
|
| BASE_MSG_SXS_SYSTEM_DEFAULT_TEXTUAL_ASSEMBLY_IDENTITY_PRESENT \
|
||
|
| BASE_MSG_SXS_TEXTUAL_ASSEMBLY_IDENTITY_PRESENT \
|
||
|
)
|
||
|
ASSERT(Struct->Flags & BASE_MSG_SXS_MINIMAL_FLAGS);
|
||
|
if ((Struct->Flags & BASE_MSG_SXS_MINIMAL_FLAGS) == 0) {
|
||
|
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() fast path\n", __FUNCTION__));
|
||
|
return STATUS_SUCCESS;
|
||
|
} else {
|
||
|
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
PVOID ViewBase = NULL;
|
||
|
SXS_GENERATE_ACTIVATION_CONTEXT_PARAMETERS SxsDllParameters = {0};
|
||
|
BASE_SRV_SXS_STREAM_UNION_WITH_VTABLE ManifestStream;
|
||
|
BASE_SRV_SXS_STREAM_UNION_WITH_VTABLE PolicyStream;
|
||
|
DWORD_PTR Cookie = 0;
|
||
|
BOOLEAN ReleaseCtxFunction = FALSE;
|
||
|
PSXS_GENERATE_ACTIVATION_CONTEXT_FUNCTION FunctionPointer = NULL;
|
||
|
LARGE_INTEGER SectionOffset = {0};
|
||
|
HRESULT Hr = NOERROR;
|
||
|
BOOL SxsFunctionSuccess = FALSE;
|
||
|
NTSTATUS Status1 = STATUS_SUCCESS;
|
||
|
|
||
|
#if IMPERSONATE_ENTIRE_SXS_CALL
|
||
|
BOOLEAN SuccessfulImpersonation = FALSE;
|
||
|
#else
|
||
|
ACTIVATION_CONTEXT_GENERATION_IMPERSONATION_CONTEXT ImpersonationContext = {0};
|
||
|
#endif
|
||
|
|
||
|
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() beginning\n", __FUNCTION__));
|
||
|
ASSERT(Struct != NULL);
|
||
|
ASSERT(Struct != NULL && Struct->Manifest.Path.Buffer != NULL);
|
||
|
|
||
|
|
||
|
if ( Struct->Flags & BASE_MSG_SXS_MANIFEST_PRESENT)
|
||
|
{
|
||
|
// because these are unions, " = {0}" won't necessarily clear them completely
|
||
|
RtlZeroMemory(&ManifestStream, sizeof(ManifestStream));
|
||
|
RtlZeroMemory(&PolicyStream, sizeof(PolicyStream));
|
||
|
|
||
|
|
||
|
Status = BaseSrvSxsCreateMemoryStream(
|
||
|
CsrClientProcess,
|
||
|
&Struct->Manifest,
|
||
|
&ManifestStream,
|
||
|
&IID_ISequentialStream,
|
||
|
(PVOID*)&SxsDllParameters.Manifest.Stream
|
||
|
);
|
||
|
IF_NOT_SUCCESS_TRACE_AND_EXIT(BaseSrvSxsCreateMemoryStream(manifest));
|
||
|
|
||
|
SxsDllParameters.Manifest.PathType = ACTIVATION_CONTEXT_PATH_TYPE_NONE;
|
||
|
|
||
|
if (Struct->Flags & BASE_MSG_SXS_POLICY_PRESENT) {
|
||
|
Status = BaseSrvSxsCreateMemoryStream(
|
||
|
CsrClientProcess,
|
||
|
&Struct->Policy,
|
||
|
&PolicyStream,
|
||
|
&IID_ISequentialStream,
|
||
|
(PVOID*)&SxsDllParameters.Policy.Stream
|
||
|
);
|
||
|
IF_NOT_SUCCESS_TRACE_AND_EXIT(BaseSrvSxsCreateMemoryStream(policy));
|
||
|
|
||
|
if (Struct->Policy.PathType != BASE_MSG_PATHTYPE_NONE
|
||
|
&& Struct->Policy.Path.Length != 0
|
||
|
&& Struct->Policy.Path.Buffer != NULL
|
||
|
) {
|
||
|
ASSERT_UNICODE_STRING_IS_NUL_TERMINATED(&Struct->Policy.Path);
|
||
|
SxsDllParameters.Policy.Path = Struct->Policy.Path.Buffer;
|
||
|
|
||
|
switch (Struct->Policy.PathType) {
|
||
|
case BASE_MSG_PATHTYPE_FILE:
|
||
|
SxsDllParameters.Manifest.PathType = ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE;
|
||
|
break;
|
||
|
case BASE_MSG_PATHTYPE_URL:
|
||
|
SxsDllParameters.Manifest.PathType = ACTIVATION_CONTEXT_PATH_TYPE_URL;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else // Textual AssemblyIdentity
|
||
|
{
|
||
|
SxsDllParameters.Flags |= SXS_GENERATE_ACTIVATION_CONTEXT_FLAG_TEXTUAL_ASSEMBLY_IDENTITY;
|
||
|
if ( Struct->Flags & BASE_MSG_SXS_SYSTEM_DEFAULT_TEXTUAL_ASSEMBLY_IDENTITY_PRESENT)
|
||
|
{
|
||
|
SxsDllParameters.Flags |= SXS_GENERATE_ACTIVATION_CONTEXT_FLAG_SYSTEM_DEFAULT_TEXTUAL_ASSEMBLY_IDENTITY;
|
||
|
}
|
||
|
SxsDllParameters.TextualAssemblyIdentity = Struct->TextualAssemblyIdentity.Buffer;
|
||
|
ASSERT_UNICODE_STRING_IS_NUL_TERMINATED(&Struct->TextualAssemblyIdentity);
|
||
|
}
|
||
|
|
||
|
SxsDllParameters.ProcessorArchitecture = Struct->ProcessorArchitecture;
|
||
|
SxsDllParameters.LangId = Struct->LangId;
|
||
|
|
||
|
SxsDllParameters.AssemblyDirectory = Struct->AssemblyDirectory.Buffer;
|
||
|
ASSERT_UNICODE_STRING_IS_NUL_TERMINATED(&Struct->AssemblyDirectory);
|
||
|
|
||
|
Status = BaseSrvSxsGetActivationContextGenerationFunction(&FunctionPointer, &Cookie);
|
||
|
if (Status == STATUS_DLL_NOT_FOUND) {
|
||
|
// This happens under stress.
|
||
|
// We will probably propagate STATUS_NO_MEMORY post beta1 here,
|
||
|
// if RtlAllocateHeap on a small amount fails.
|
||
|
// In Blackcomb we will maybe fix RtlSearchPath/LdrLoadDll to propagate
|
||
|
// accurate status.
|
||
|
DbgPrintEx(
|
||
|
DPFLTR_SXS_ID,
|
||
|
DPFLTR_ERROR_LEVEL,
|
||
|
"SXS: BaseSrvSxsGetActivationContextGenerationFunction() returned STATUS_DLL_NOT_FOUND, propagating.\n"
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Old bogus code actually returned a STATUS_SUCCESS when it was a genuine failure.
|
||
|
// Instead, we should return the actual status that is being generated. The other
|
||
|
// option is to return STATUS_NO_MEMORY, the generic "oops" error code. Our clients
|
||
|
// do the Smart Thing with an NT_SUCCESS() check, so returning STATUS_DLL_NOT_FOUND
|
||
|
// is just dandy. This if block just prints that fact, relying on the following
|
||
|
// IF_NOT_SUCCESS_TRACE_AND_EXIT to quit out.
|
||
|
//
|
||
|
}
|
||
|
IF_NOT_SUCCESS_TRACE_AND_EXIT(BaseSrvSxsGetActivationContextGenerationFunction);
|
||
|
|
||
|
// If we fail before we explicitly clean up, release the refcount on the sxs dll
|
||
|
// in the failure path.
|
||
|
ReleaseCtxFunction = TRUE;
|
||
|
|
||
|
if (Struct->Manifest.PathType != BASE_MSG_PATHTYPE_NONE
|
||
|
&& Struct->Manifest.Path.Length != 0
|
||
|
&& Struct->Manifest.Path.Buffer != NULL
|
||
|
) {
|
||
|
ASSERT(Struct->Manifest.Path.Buffer[Struct->Manifest.Path.Length / sizeof(WCHAR)] == 0);
|
||
|
SxsDllParameters.Manifest.Path = Struct->Manifest.Path.Buffer;
|
||
|
switch (Struct->Manifest.PathType) {
|
||
|
case BASE_MSG_PATHTYPE_FILE:
|
||
|
SxsDllParameters.Manifest.PathType = ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE;
|
||
|
break;
|
||
|
case BASE_MSG_PATHTYPE_URL:
|
||
|
SxsDllParameters.Manifest.PathType = ACTIVATION_CONTEXT_PATH_TYPE_URL;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if IMPERSONATE_ENTIRE_SXS_CALL
|
||
|
SuccessfulImpersonation = CsrImpersonateClient(NULL);
|
||
|
if (!SuccessfulImpersonation) {
|
||
|
//
|
||
|
// if we could not impersonate then exit
|
||
|
//
|
||
|
// DbgPrintEx(...);
|
||
|
//
|
||
|
Status = STATUS_BAD_IMPERSONATION_LEVEL;
|
||
|
goto Exit;
|
||
|
}
|
||
|
SxsDllParameters.ImpersonationCallback = NULL;
|
||
|
SxsDllParameters.ImpersonationContext = NULL;
|
||
|
#else
|
||
|
SxsDllParameters.ImpersonationCallback = BaseSrvpSxsActivationContextGenerationImpersonationCallback;
|
||
|
SxsDllParameters.ImpersonationContext = &ImpersonationContext;
|
||
|
#endif
|
||
|
|
||
|
SxsFunctionSuccess = (*FunctionPointer)(&SxsDllParameters);
|
||
|
|
||
|
if (SxsFunctionSuccess) // succeed but if for system default, we need check the status
|
||
|
{
|
||
|
if (Struct->Flags & BASE_MSG_SXS_SYSTEM_DEFAULT_TEXTUAL_ASSEMBLY_IDENTITY_PRESENT)
|
||
|
{
|
||
|
//
|
||
|
// For System Default, there are two ignorable cases when ActCtx is failed.
|
||
|
// case 1: that there is no system defult
|
||
|
// case 2: The dependency of system default has not been installed.
|
||
|
// Status is set to be STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY under this situation which would be ignored
|
||
|
// by BaseSrvCreateProcess, xiaoyuw@11/30/2000
|
||
|
//
|
||
|
if ((SxsDllParameters.SystemDefaultActCxtGenerationResult & BASESRV_SXS_RETURN_RESULT_SYSTEM_DEFAULT_NOT_FOUND) ||
|
||
|
(SxsDllParameters.SystemDefaultActCxtGenerationResult & BASESRV_SXS_RETURN_RESULT_SYSTEM_DEFAULT_DEPENDENCY_ASSEMBLY_NOT_FOUND))
|
||
|
{
|
||
|
Status = STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY; // ActCtx of system default is not generated
|
||
|
goto Exit;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if (!SxsFunctionSuccess) {
|
||
|
DbgPrintEx(
|
||
|
DPFLTR_SXS_ID,
|
||
|
DPFLTR_INFO_LEVEL,
|
||
|
"SXS: Activation Context generation function failed.\n");
|
||
|
|
||
|
Status = STATUS_SXS_CANT_GEN_ACTCTX;
|
||
|
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
if (SxsDllParameters.SectionObjectHandle != NULL) {
|
||
|
if (Struct->ActivationContextData != NULL) {
|
||
|
// Now let's map the section read-only into the target process...
|
||
|
Status =
|
||
|
BaseSrvSxsMapViewOfSection(
|
||
|
&ViewBase,
|
||
|
SxsClientProcess,
|
||
|
SxsDllParameters.SectionObjectHandle,
|
||
|
0, // offset
|
||
|
0, // size
|
||
|
PAGE_READONLY,
|
||
|
SEC_NO_CHANGE);
|
||
|
IF_NOT_SUCCESS_TRACE_AND_EXIT(BaseSrvSxsMapViewOfSection);
|
||
|
|
||
|
//
|
||
|
// And now push that duplicated handle into the process's PEB
|
||
|
//
|
||
|
// On 64bit we are writing into a 64bit PEB that then is copied
|
||
|
// into a 32bit PEB if the process is 32bit.
|
||
|
//
|
||
|
// Or we are writing into a CreateActCtx local, but again 64bit,
|
||
|
// and copied back to 32bit for 32bit processes.
|
||
|
//
|
||
|
Status =
|
||
|
NtWriteVirtualMemory(
|
||
|
SxsClientProcess,
|
||
|
Struct->ActivationContextData,
|
||
|
&ViewBase,
|
||
|
sizeof(ViewBase),
|
||
|
NULL);
|
||
|
IF_NOT_SUCCESS_TRACE_AND_EXIT(NtWriteVirtualMemory);
|
||
|
}
|
||
|
|
||
|
if (OutSection != NULL) {
|
||
|
*OutSection = SxsDllParameters.SectionObjectHandle;
|
||
|
SxsDllParameters.SectionObjectHandle = NULL;
|
||
|
} else {
|
||
|
Status = NtClose(SxsDllParameters.SectionObjectHandle);
|
||
|
SxsDllParameters.SectionObjectHandle = NULL;
|
||
|
IF_NOT_SUCCESS_TRACE_AND_EXIT(NtClose);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Status = BaseSrvSxsReleaseActivationContextGenerationFunction(Cookie);
|
||
|
ReleaseCtxFunction = FALSE;
|
||
|
IF_NOT_SUCCESS_TRACE_AND_EXIT(BaseSrvSxsReleaseActivationContextGenerationFunction);
|
||
|
|
||
|
Status = STATUS_SUCCESS;
|
||
|
ViewBase = NULL;
|
||
|
|
||
|
Exit:
|
||
|
RTL_SOFT_VERIFY(NT_SUCCESS(Status1 = RTL_UNMAP_VIEW_OF_SECTION2(SxsClientProcess, ViewBase)));
|
||
|
RTL_SOFT_VERIFY(NT_SUCCESS(Status1 = RTL_CLOSE_HANDLE(SxsDllParameters.SectionObjectHandle)));
|
||
|
if (ReleaseCtxFunction) {
|
||
|
Status1 = BaseSrvSxsReleaseActivationContextGenerationFunction(Cookie);
|
||
|
RTL_SOFT_ASSERT(NT_SUCCESS(Status1));
|
||
|
}
|
||
|
|
||
|
#if IMPERSONATE_ENTIRE_SXS_CALL
|
||
|
if (SuccessfulImpersonation) {
|
||
|
CsrRevertToSelf();
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if ( Struct->Flags & BASE_MSG_SXS_MANIFEST_PRESENT)
|
||
|
{
|
||
|
RTL_RELEASE(SxsDllParameters.Manifest.Stream);
|
||
|
RTL_RELEASE(SxsDllParameters.Policy.Stream);
|
||
|
#if DBG
|
||
|
if (ManifestStream.Mmap.MemStream.Data.ReferenceCount != 0) {
|
||
|
DbgPrintEx(
|
||
|
DPFLTR_SXS_ID,
|
||
|
DPFLTR_ERROR_LEVEL,
|
||
|
"SRVSXS: ManifestStream.Mmap.MemStream.Data.ReferenceCount: %ld\n",
|
||
|
ManifestStream.Mmap.MemStream.Data.ReferenceCount);
|
||
|
}
|
||
|
if (PolicyStream.Mmap.MemStream.Data.ReferenceCount != 0) {
|
||
|
DbgPrintEx(
|
||
|
DPFLTR_SXS_ID,
|
||
|
DPFLTR_ERROR_LEVEL,
|
||
|
"SRVSXS: PolicyStream.Mmap.MemStream.Data.ReferenceCount: %ld\n",
|
||
|
PolicyStream.Mmap.MemStream.Data.ReferenceCount );
|
||
|
}
|
||
|
ASSERT(ManifestStream.Mmap.MemStream.Data.ReferenceCount == 0
|
||
|
&& PolicyStream.Mmap.MemStream.Data.ReferenceCount == 0);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
#if DBG
|
||
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_LEVEL_STATUS(Status), "SXS: %s() exiting 0x%08lx\n", __FUNCTION__, Status);
|
||
|
#endif
|
||
|
|
||
|
return Status;
|
||
|
}}
|
||
|
|
||
|
NTSTATUS
|
||
|
BaseSrvSxsValidateMessageStrings(
|
||
|
IN CONST CSR_API_MSG* Message,
|
||
|
IN ULONG NumberOfStrings,
|
||
|
IN CONST PCUNICODE_STRING* Strings
|
||
|
)
|
||
|
{
|
||
|
ULONG i = 0;
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
|
||
|
for (i = 0 ; i != NumberOfStrings ; ++i) {
|
||
|
if (Strings[i] != NULL && Strings[i]->Buffer != NULL) {
|
||
|
if (!CsrValidateMessageBuffer(
|
||
|
Message,
|
||
|
&Strings[i]->Buffer,
|
||
|
Strings[i]->Length + sizeof(WCHAR),
|
||
|
sizeof(BYTE))) {
|
||
|
|
||
|
DbgPrintEx(
|
||
|
DPFLTR_SXS_ID,
|
||
|
DPFLTR_ERROR_LEVEL,
|
||
|
"SXS: Validation of message buffer 0x%lx failed.\n"
|
||
|
" Message:%p\n"
|
||
|
" String %p{Length:0x%x, MaximumLength:0x%x, Buffer:%p}\n",
|
||
|
i,
|
||
|
Message,
|
||
|
Strings[i],
|
||
|
Strings[i]->Length,
|
||
|
Strings[i]->MaximumLength,
|
||
|
Strings[i]->Buffer
|
||
|
);
|
||
|
|
||
|
Status = STATUS_INVALID_PARAMETER;
|
||
|
goto Exit;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
Status = STATUS_SUCCESS;
|
||
|
Exit:
|
||
|
#if DBG
|
||
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_LEVEL_STATUS(Status), "SXS: %s() exiting 0x%08lx\n", __FUNCTION__, Status);
|
||
|
#endif
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
BaseSrvSxsCreateActivationContextFromMessage(
|
||
|
IN OUT PCSR_API_MSG m,
|
||
|
IN OUT PCSR_REPLY_STATUS ReplyStatus
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function handles the CSR message requesting that an activation
|
||
|
context be created.
|
||
|
|
||
|
It loads sxs.dll if it is not loaded, calls the sxs.dll api to
|
||
|
create an activation context, maps the activation context into the
|
||
|
client API and sets the address of the created activation context
|
||
|
into the client's address space.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
m - the message sent to csr from the win32 client
|
||
|
|
||
|
ReplyStatus - an indicator of the status of the reply
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
ULONG return value to the win32 client; in this case we return
|
||
|
the NTSTATUS disposition of the function's execution.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PBASE_SXS_CREATE_ACTIVATION_CONTEXT_MSG Message =
|
||
|
(PBASE_SXS_CREATE_ACTIVATION_CONTEXT_MSG) &m->u.ApiMessageData;
|
||
|
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
HANDLE CsrClientProcess = NULL;
|
||
|
PCUNICODE_STRING StringsInMessageToValidate[4];
|
||
|
ULONG i = 0;
|
||
|
|
||
|
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() beginning\n", __FUNCTION__));
|
||
|
|
||
|
StringsInMessageToValidate[0] = &Message->Manifest.Path;
|
||
|
StringsInMessageToValidate[1] = &Message->Policy.Path;
|
||
|
StringsInMessageToValidate[2] = &Message->AssemblyDirectory;
|
||
|
StringsInMessageToValidate[3] = &Message->TextualAssemblyIdentity;
|
||
|
Status = BaseSrvSxsValidateMessageStrings(m, RTL_NUMBER_OF(StringsInMessageToValidate), StringsInMessageToValidate);
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
KdPrintEx((
|
||
|
DPFLTR_SXS_ID,
|
||
|
DPFLTR_TRACE_LEVEL,
|
||
|
"SXS: %s() Manifest=%wZ; Policy=%wZ; TextualAssemblyIdentity=%wZ\n",
|
||
|
__FUNCTION__,
|
||
|
&Message->Manifest.Path,
|
||
|
&Message->Policy.Path,
|
||
|
&Message->TextualAssemblyIdentity
|
||
|
));
|
||
|
|
||
|
CsrClientProcess = CSR_SERVER_QUERYCLIENTTHREAD()->Process->ProcessHandle;
|
||
|
|
||
|
Status = BaseSrvSxsCreateActivationContextFromStruct(CsrClientProcess, CsrClientProcess, Message, NULL);
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
Status = STATUS_SUCCESS;
|
||
|
Exit:
|
||
|
#if DBG
|
||
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_LEVEL_STATUS(Status), "SXS: %s() exiting 0x%08lx\n", __FUNCTION__, Status);
|
||
|
#endif
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
BaseSrvSxsCreateActivationContext(
|
||
|
IN OUT PCSR_API_MSG m,
|
||
|
IN OUT PCSR_REPLY_STATUS ReplyStatus
|
||
|
)
|
||
|
{
|
||
|
return BaseSrvSxsCreateActivationContextFromMessage(m, ReplyStatus);
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
BaseSrvSxsGetActivationContextGenerationFunction(
|
||
|
PSXS_GENERATE_ACTIVATION_CONTEXT_FUNCTION* FunctionPointer,
|
||
|
PDWORD_PTR Cookie
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function loads sxs.dll if it is not loaded and returns a pointer
|
||
|
to the function to call to generate an activation context.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
FunctionPointer - pointer to activation context generation function pointer
|
||
|
returned.
|
||
|
|
||
|
Cookie - returned DWORD_PTR value which must later be passed in
|
||
|
to BaseSrvSxsReleaseActivationContextGenerationFunction() to
|
||
|
lower the refcount on sxs.dll.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NTSTATUS indicating the disposition of the function's execution.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
static STRING SxsProcedureName = RTL_CONSTANT_STRING( "SxsGenerateActivationContext" );
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
BOOLEAN FreeDll = FALSE;
|
||
|
DWORD_PTR NewCookie = 0;
|
||
|
NTSTATUS Status1 = STATUS_SUCCESS;
|
||
|
#if BASESRV_UNLOAD_SXS_DLL
|
||
|
BOOLEAN CritSecLocked = FALSE;
|
||
|
#else
|
||
|
PVOID SxsDllHandle = NULL;
|
||
|
#endif
|
||
|
|
||
|
#if BASESRV_UNLOAD_SXS_DLL
|
||
|
__try
|
||
|
#endif
|
||
|
{
|
||
|
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() beginning\n", __FUNCTION__));
|
||
|
|
||
|
if (!(ARGUMENT_PRESENT(FunctionPointer) && ARGUMENT_PRESENT(Cookie))) {
|
||
|
Status = STATUS_INVALID_PARAMETER;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
#if BASESRV_UNLOAD_SXS_DLL
|
||
|
//
|
||
|
// It's tempting to want to optimize away locking the critical section
|
||
|
// when looking at the pointer, because we know if it's not NULL, we can
|
||
|
// just use it, but we're keeping a reference count on the SXS.DLL
|
||
|
// so that we can unload it, so to avoid this race, we need to lock the
|
||
|
// critical section.
|
||
|
//
|
||
|
|
||
|
Status = RtlEnterCriticalSection(&BaseSrvSxsCritSec);
|
||
|
if (!NT_SUCCESS(Status))
|
||
|
goto Exit;
|
||
|
|
||
|
CritSecLocked = TRUE;
|
||
|
#endif
|
||
|
if (SxsActivationContextGenerationFunction == NULL) {
|
||
|
|
||
|
Status = LdrLoadDll(
|
||
|
NULL,
|
||
|
NULL,
|
||
|
&BaseSrvSxsDllPath,
|
||
|
&SxsDllHandle);
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
DbgPrintEx(
|
||
|
DPFLTR_SXS_ID,
|
||
|
DPFLTR_LEVEL_STATUS(Status),
|
||
|
"SXS: %s: LdrLoadDll(%wZ) failed 0x%08lx\n",
|
||
|
__FUNCTION__,
|
||
|
&BaseSrvSxsDllPath,
|
||
|
Status
|
||
|
);
|
||
|
|
||
|
if (Status == STATUS_DLL_NOT_FOUND) {
|
||
|
PVOID p = RtlAllocateHeap(RtlProcessHeap(), 0, sizeof(L"c:\\windows\\system32\\sxs.dll"));
|
||
|
RtlFreeHeap(RtlProcessHeap(), 0, p);
|
||
|
if (p == NULL) {
|
||
|
DbgPrintEx(
|
||
|
DPFLTR_SXS_ID,
|
||
|
DPFLTR_LEVEL_STATUS(Status),
|
||
|
"SXS: %s: LdrLoadDll(%wZ) actually probably out of memory in RtlSearchPath (RtlAllocateHeap failure)\n",
|
||
|
__FUNCTION__,
|
||
|
&BaseSrvSxsDllPath
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
FreeDll = TRUE;
|
||
|
|
||
|
Status = LdrGetProcedureAddress(SxsDllHandle, &SxsProcedureName, 0, (PVOID *) &SxsActivationContextGenerationFunction);
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
DbgPrintEx(
|
||
|
DPFLTR_SXS_ID,
|
||
|
DPFLTR_LEVEL_STATUS(Status),
|
||
|
"SXS: %s: LdrGetProcedureAddress(%wZ:%Z) failed 0x%08lx\n",
|
||
|
__FUNCTION__,
|
||
|
&BaseSrvSxsDllPath,
|
||
|
&SxsProcedureName,
|
||
|
Status
|
||
|
);
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
FreeDll = FALSE;
|
||
|
}
|
||
|
|
||
|
NewCookie = BaseSrvSxsGetActCtxGenCount++;
|
||
|
#if BASESRV_UNLOAD_SXS_DLL
|
||
|
SxsDllHandleRefCount++;
|
||
|
RtlLeaveCriticalSection(&BaseSrvSxsCritSec);
|
||
|
CritSecLocked = FALSE;
|
||
|
#endif
|
||
|
|
||
|
*FunctionPointer = SxsActivationContextGenerationFunction;
|
||
|
*Cookie = NewCookie;
|
||
|
|
||
|
Status = STATUS_SUCCESS;
|
||
|
Exit:
|
||
|
if (FreeDll) {
|
||
|
#if BASESRV_UNLOAD_SXS_DLL
|
||
|
ASSERT(CritSecLocked);
|
||
|
ASSERT(SxsDllHandle != NULL);
|
||
|
ASSERT(SxsActivationContextGenerationFunction == NULL);
|
||
|
#endif
|
||
|
SxsActivationContextGenerationFunction = NULL;
|
||
|
Status1 = LdrUnloadDll(SxsDllHandle);
|
||
|
RTL_SOFT_ASSERT(NT_SUCCESS(Status1));
|
||
|
SxsDllHandle = NULL;
|
||
|
}
|
||
|
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_LEVEL_STATUS(Status), "SXS: %s() exiting 0x%08lx\n", __FUNCTION__, Status));
|
||
|
}
|
||
|
#if BASESRV_UNLOAD_SXS_DLL
|
||
|
__finally
|
||
|
{
|
||
|
if (CritSecLocked)
|
||
|
RtlLeaveCriticalSection(&BaseSrvSxsCritSec);
|
||
|
}
|
||
|
#endif
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
BaseSrvSxsReleaseActivationContextGenerationFunction(
|
||
|
DWORD_PTR Cookie
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function decrements the reference count on sxs.dll and unloads it
|
||
|
if the reference count is zero.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Cookie - value returned by BaseSrvSxsGetActivationContextGenerationFunction
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NTSTATUS indicating the disposition of the function's execution.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
#if BASESRV_UNLOAD_SXS_DLL
|
||
|
BOOLEAN CritSecLocked = FALSE;
|
||
|
|
||
|
__try {
|
||
|
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() beginning\n", __FUNCTION__));
|
||
|
|
||
|
(Cookie); // maybe someday we'll actively track this in debug builds...
|
||
|
|
||
|
Status = RtlEnterCriticalSection(&BaseSrvSxsCritSec);
|
||
|
if (!NT_SUCCESS(Status))
|
||
|
goto Exit;
|
||
|
|
||
|
CritSecLocked = TRUE;
|
||
|
|
||
|
// We shouldn't have gotten here if the DLL wasn't loaded - someone either
|
||
|
// released more than once or called release without having called
|
||
|
// get previously.
|
||
|
ASSERT(SxsDllHandle != NULL);
|
||
|
ASSERT(SxsDllHandleRefCount != 0);
|
||
|
|
||
|
--SxsDllHandleRefCount;
|
||
|
|
||
|
if (SxsDllHandleRefCount == 0) {
|
||
|
#if DBG
|
||
|
Status = LdrUnloadDll(SxsDllHandle);
|
||
|
SxsDllHandle = NULL;
|
||
|
SxsActivationContextGenerationFunction = NULL;
|
||
|
if (!NT_SUCCESS(Status))
|
||
|
goto Exit;
|
||
|
#endif // DBG
|
||
|
}
|
||
|
|
||
|
RtlLeaveCriticalSection(&BaseSrvSxsCritSec);
|
||
|
CritSecLocked = FALSE;
|
||
|
|
||
|
Status = STATUS_SUCCESS;
|
||
|
Exit:
|
||
|
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_LEVEL_STATUS(Status), "SXS: %s() exiting 0x%08lx\n", __FUNCTION__, Status));
|
||
|
} __finally {
|
||
|
if (CritSecLocked)
|
||
|
RtlLeaveCriticalSection(&BaseSrvSxsCritSec);
|
||
|
}
|
||
|
#endif // BASESRV_UNLOAD_SXS_DLL
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
BaseSrvSxsDuplicateObject(
|
||
|
HANDLE FromProcess,
|
||
|
HANDLE FromHandle,
|
||
|
HANDLE* ToHandle
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Shrink the parameter list of NtDuplicateObject to a smaller common case.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
FromProcess -
|
||
|
FromHandle -
|
||
|
ToHandle -
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NTSTATUS from NtDuplicateObject
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
|
||
|
Status =
|
||
|
NtDuplicateObject(
|
||
|
FromProcess,
|
||
|
FromHandle,
|
||
|
NtCurrentProcess(),
|
||
|
ToHandle,
|
||
|
0,
|
||
|
0,
|
||
|
DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES
|
||
|
);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
BaseSrvSxsCreateMemoryStream(
|
||
|
HANDLE CsrClientProcess,
|
||
|
IN PCBASE_MSG_SXS_STREAM MsgStream,
|
||
|
OUT PBASE_SRV_SXS_STREAM_UNION_WITH_VTABLE StreamUnion,
|
||
|
IN const IID* IIDStream,
|
||
|
OUT PVOID* OutIStream
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Based on MsgStream->HandleType, this initializes the correct
|
||
|
union member of StreamUnion and returns an IStream* to it.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
CsrClientProcess - the process MsgStream->Handle is valid in,
|
||
|
and the value of the handle if MsgStream->HandleType == BASE_MSG_HANDLETYPE_CLIENT_PROCESS
|
||
|
|
||
|
MsgStream - a description of an IStream that is easily remoted across to csrss.exe
|
||
|
|
||
|
StreamUnion - a union of all our IStream implementations
|
||
|
|
||
|
OutIStream - resulting IStream*
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NTSTATUS indicating the disposition of the function.
|
||
|
|
||
|
Note:
|
||
|
All the handles in MsgStream are valid in CsrClientProcess.
|
||
|
Therefore, we don't close them. We duplicate them, and close the duplicates.
|
||
|
--*/
|
||
|
{
|
||
|
HANDLE Handle = NULL;
|
||
|
HANDLE FileHandle = NULL;
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
HRESULT Hr = NOERROR;
|
||
|
PVOID ViewBase = NULL;
|
||
|
NTSTATUS Status1 = STATUS_SUCCESS;
|
||
|
ULONG i = 0;
|
||
|
|
||
|
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SRVSXS: %s() beginning\n", __FUNCTION__));
|
||
|
|
||
|
ASSERT(CsrClientProcess != NULL);
|
||
|
ASSERT(MsgStream != NULL);
|
||
|
ASSERT(StreamUnion != NULL);
|
||
|
ASSERT(IIDStream != NULL);
|
||
|
ASSERT(OutIStream != NULL);
|
||
|
|
||
|
// If the manifest is actually just a VA region in the client process, dup the client process
|
||
|
// handle from our own address space to our own address space; otherwise, it's a handle
|
||
|
// in the client address space so we need to dup it from the client space to ours.
|
||
|
if (MsgStream->HandleType == BASE_MSG_HANDLETYPE_CLIENT_PROCESS) {
|
||
|
Status = BaseSrvSxsDuplicateObject(NtCurrentProcess(), CsrClientProcess, &Handle);
|
||
|
} else {
|
||
|
Status = BaseSrvSxsDuplicateObject(CsrClientProcess, MsgStream->Handle, &Handle);
|
||
|
}
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
Handle = NULL;
|
||
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "SRVSXS: %s(): NtDuplicateObject failed; Status = %08lx\n", __FUNCTION__, Status);
|
||
|
goto Exit;
|
||
|
}
|
||
|
if (MsgStream->FileHandle != NULL) {
|
||
|
Status = BaseSrvSxsDuplicateObject(CsrClientProcess, MsgStream->FileHandle, &FileHandle);
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "SRVSXS: %s(): NtDuplicateObject(FileHandle) failed.\n", __FUNCTION__));
|
||
|
goto Exit;
|
||
|
}
|
||
|
}
|
||
|
switch (MsgStream->HandleType) {
|
||
|
default:
|
||
|
ASSERTMSG("Bad HandleType", FALSE);
|
||
|
Status = STATUS_INVALID_PARAMETER;
|
||
|
goto Exit;
|
||
|
case BASE_MSG_HANDLETYPE_CLIENT_PROCESS:
|
||
|
case BASE_MSG_HANDLETYPE_PROCESS:
|
||
|
// This is the app-compat case.
|
||
|
//
|
||
|
// REVIEW: if Offset happens to be in a section in the process
|
||
|
// (you can find out with NtQuerySection(SectionBasicInformation)),
|
||
|
// we should instead map it. That would be more efficient.
|
||
|
//
|
||
|
// That logic could just as well be in kernel32 though, and for
|
||
|
// the sake of minimizing csr code and time, that's where we'd do it.
|
||
|
//
|
||
|
RtlInitOutOfProcessMemoryStream(&StreamUnion->OutOfProcess);
|
||
|
StreamUnion->OutOfProcess.Data.Process = Handle;
|
||
|
Handle = NULL; // the stream owns it now
|
||
|
StreamUnion->OutOfProcess.Data.Begin = (PUCHAR)MsgStream->Offset;
|
||
|
StreamUnion->OutOfProcess.Data.Current = StreamUnion->OutOfProcess.Data.Begin;
|
||
|
StreamUnion->OutOfProcess.Data.End = StreamUnion->OutOfProcess.Data.Begin + MsgStream->Size;
|
||
|
break;
|
||
|
|
||
|
case BASE_MSG_HANDLETYPE_SECTION: {
|
||
|
Status =
|
||
|
BaseSrvSxsMapViewOfSection(
|
||
|
&ViewBase,
|
||
|
NtCurrentProcess(),
|
||
|
Handle,
|
||
|
MsgStream->Offset,
|
||
|
MsgStream->Size,
|
||
|
PAGE_READONLY,
|
||
|
SEC_NO_CHANGE
|
||
|
);
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
goto Exit;
|
||
|
}
|
||
|
BaseSrvInitMemoryMappedStream(&StreamUnion->Mmap);
|
||
|
StreamUnion->Mmap.MemStream.Data.Begin = (PUCHAR)ViewBase;
|
||
|
ViewBase = NULL; // the stream owns it now
|
||
|
StreamUnion->Mmap.MemStream.Data.Current = StreamUnion->Mmap.MemStream.Data.Begin;
|
||
|
StreamUnion->Mmap.MemStream.Data.End = StreamUnion->Mmap.MemStream.Data.Begin + MsgStream->Size;
|
||
|
StreamUnion->Mmap.FileHandle = FileHandle;
|
||
|
FileHandle = NULL; // the stream owns it now
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
// it does not matter here which member of the union we use, we are only using
|
||
|
// members of the members that are at the same offset
|
||
|
Hr = StreamUnion->Mmap.MemStream.StreamVTable->QueryInterface(
|
||
|
(IStream*)&StreamUnion->Mmap.MemStream,
|
||
|
IIDStream,
|
||
|
OutIStream);
|
||
|
ASSERT(SUCCEEDED(Hr));
|
||
|
|
||
|
Status = STATUS_SUCCESS;
|
||
|
Exit:
|
||
|
RTL_SOFT_VERIFY(NT_SUCCESS(RTL_CLOSE_HANDLE(FileHandle)));
|
||
|
RTL_SOFT_VERIFY(NT_SUCCESS(RTL_CLOSE_HANDLE(Handle)));
|
||
|
RTL_SOFT_VERIFY(NT_SUCCESS(RTL_UNMAP_VIEW_OF_SECTION1(ViewBase)));
|
||
|
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_LEVEL_STATUS(Status), "SXS: %s() exiting 0x%08lx\n", __FUNCTION__, Status));
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
BaseSrvSxsCreateProcess(
|
||
|
HANDLE CsrClientProcess,
|
||
|
HANDLE NewProcess,
|
||
|
IN OUT PCSR_API_MSG CsrMessage,
|
||
|
PPEB NewProcessPeb
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Runs during kernel32.dll::CreateProcessW's calls to csrss.exe.
|
||
|
Munges the csr message into something more Win32-ish (IStreams) and calls into sxs.dll to
|
||
|
create the processes default activation context.
|
||
|
|
||
|
Munges the create process message to look like a CreateActCtx message, which isn't much work,
|
||
|
and then delegates to code common with CreateActCtx.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Process - the csr client process, the "old" process, the "parent" process that called
|
||
|
CreateProcess
|
||
|
|
||
|
Message - a bunch of parameters
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NTSTATUS indicating the disposition of the function.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PROCESS_BASIC_INFORMATION ProcessBasicInfo;
|
||
|
BASE_SXS_CREATE_ACTIVATION_CONTEXT_MSG Struct = {0};
|
||
|
PCUNICODE_STRING StringsInMessageToValidate[3];
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
PBASE_CREATEPROCESS_MSG CreateProcessMessage = (PBASE_CREATEPROCESS_MSG)&CsrMessage->u.ApiMessageData;
|
||
|
PBASE_SXS_CREATEPROCESS_MSG SxsMessage = &CreateProcessMessage->Sxs;
|
||
|
|
||
|
ASSERT(CsrMessage != NULL);
|
||
|
|
||
|
if ((SxsMessage->Flags & BASE_MSG_SXS_MANIFEST_PRESENT) == 0) {
|
||
|
|
||
|
KdPrintEx((
|
||
|
DPFLTR_SXS_ID,
|
||
|
DPFLTR_TRACE_LEVEL,
|
||
|
"SXS: %s() fast path, no manifest.\n",
|
||
|
__FUNCTION__
|
||
|
));
|
||
|
Status = STATUS_SUCCESS;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() beginning\n", __FUNCTION__));
|
||
|
|
||
|
StringsInMessageToValidate[0] = &SxsMessage->Manifest.Path;
|
||
|
StringsInMessageToValidate[1] = &SxsMessage->Policy.Path;
|
||
|
StringsInMessageToValidate[2] = &SxsMessage->AssemblyDirectory;
|
||
|
Status = BaseSrvSxsValidateMessageStrings(CsrMessage, RTL_NUMBER_OF(StringsInMessageToValidate), StringsInMessageToValidate);
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
KdPrintEx((
|
||
|
DPFLTR_SXS_ID,
|
||
|
DPFLTR_TRACE_LEVEL,
|
||
|
"SXS: %s() Manifest=%wZ; Policy=%wZ, AssemblyDirectory=%wZ\n",
|
||
|
__FUNCTION__,
|
||
|
&SxsMessage->Manifest.Path,
|
||
|
&SxsMessage->Policy.Path,
|
||
|
&SxsMessage->AssemblyDirectory
|
||
|
));
|
||
|
|
||
|
if (CsrImpersonateClient(NULL)) {
|
||
|
__try {
|
||
|
Status = NtQueryDefaultUILanguage(&Struct.LangId);
|
||
|
} __finally {
|
||
|
CsrRevertToSelf();
|
||
|
}
|
||
|
} else {
|
||
|
Status = NtQueryInstallUILanguage(&Struct.LangId);
|
||
|
}
|
||
|
|
||
|
if (!NT_SUCCESS(Status))
|
||
|
goto Exit;
|
||
|
|
||
|
Struct.Flags = SxsMessage->Flags;
|
||
|
Struct.Manifest = SxsMessage->Manifest;
|
||
|
Struct.Policy = SxsMessage->Policy;
|
||
|
Struct.AssemblyDirectory = SxsMessage->AssemblyDirectory;
|
||
|
Struct.ActivationContextData = &NewProcessPeb->ActivationContextData;
|
||
|
Struct.ProcessorArchitecture = CreateProcessMessage->ProcessorArchitecture;
|
||
|
|
||
|
Status = BaseSrvSxsCreateActivationContextFromStruct(CsrClientProcess, NewProcess, &Struct, NULL);
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
goto Exit;
|
||
|
}
|
||
|
Status = STATUS_SUCCESS;
|
||
|
Exit:
|
||
|
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_LEVEL_STATUS(Status), "SXS: %s() exiting 0x%08lx\n", __FUNCTION__, Status));
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
BaseSrvSxsGetCachedSystemDefaultActivationContext(
|
||
|
IN USHORT ProcessorArchitecture,
|
||
|
OUT PBASE_SRV_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT *SystemDefaultActivationContext
|
||
|
)
|
||
|
/*++
|
||
|
if (SystemDefaultActivationContext != NULL)
|
||
|
then the caller must take the BaseSrvSxsSystemDefaultActivationContextCriticalSection.
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
ULONG i;
|
||
|
|
||
|
for (i = 0 ; i != RTL_NUMBER_OF(SxsSystemDefaultActivationContexts) ; ++i) {
|
||
|
if (SxsSystemDefaultActivationContexts[i].ProcessorArchitecture == ProcessorArchitecture) {
|
||
|
*SystemDefaultActivationContext = &SxsSystemDefaultActivationContexts[i];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (*SystemDefaultActivationContext == NULL) {
|
||
|
ASSERTMSG("Unknown Processor Architecture", FALSE);
|
||
|
Status = STATUS_UNSUCCESSFUL;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
Status = STATUS_SUCCESS;
|
||
|
Exit:
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
BaseSrvSxsDoSystemDefaultActivationContext(
|
||
|
USHORT ProcessorArchitecture,
|
||
|
HANDLE NewProcess,
|
||
|
PPEB NewPeb
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Runs during kernel32.dll::CreateProcessW's calls to csrss.exe.
|
||
|
FOR ALL PROCESSES (except the special first few, system, idle, smss, csrss),
|
||
|
on demand create the default activation context, and write it into
|
||
|
the new process's peb.
|
||
|
|
||
|
Within this function, the textual-assembly-identity string for System Default is created
|
||
|
and passed to BaseSrvSxsCreateActivationContextFromStruct, which would pass this string to
|
||
|
SXS.dll, where manifest file would be located using this textual-string.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
LangID - user's ui language for the new process
|
||
|
ProcessorArchitecture - the ProcessorArchitecture for the new process
|
||
|
NewProcess -
|
||
|
NewPeb -
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NTSTATUS indicating the disposition of the function.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
HANDLE ActivationContextSection = NULL;
|
||
|
PBASE_SRV_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT SystemDefaultActivationContext = NULL;
|
||
|
|
||
|
LANGID LangId = 0;
|
||
|
BOOLEAN RevertToSelfNeeded = FALSE;
|
||
|
BASE_SXS_CREATE_ACTIVATION_CONTEXT_MSG Struct = {0};
|
||
|
RTL_UNICODE_STRING_BUFFER SystemDefaultAssemblyDirectoryBuffer = {0};
|
||
|
// The size of the following buffer is only heuristic, we will grow via the heap if necessary.
|
||
|
UCHAR SystemDefaultAssemblyDirectoryStaticBuffer[sizeof(L"c:\\windows8.123\\winsxs")];
|
||
|
UNICODE_STRING SystemRoot;
|
||
|
USHORT AssemblyDirectoryLength = 0;
|
||
|
const UNICODE_STRING SystemDefaultContextString = RTL_CONSTANT_STRING(L"System Default Context");
|
||
|
RTL_UNICODE_STRING_BUFFER SystemDefaultTextualAssemblyIdentityBuffer = {0};
|
||
|
UCHAR SystemDefaultTextualAssemblyIdentityStaticBuffer[
|
||
|
sizeof(LSYSTEM_COMPATIBLE_ASSEMBLY_NAME L",version=\"65535.65535.65535.65535\",type=\"win32\",publicKeyToken=\"6595b64144ccf1df\",processorArchitecture=\"alpha\"...padding...")
|
||
|
];
|
||
|
PVOID ViewBase = NULL;
|
||
|
WCHAR WindowsMajorDotMinorVersionBuffer[sizeof("65535.65535")]; // eg: 5.1 for Whistler
|
||
|
SIZE_T WindowsMajorDotMinorVersionBufferLength;
|
||
|
PPEB Peb;
|
||
|
BOOLEAN Locked = FALSE;
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
Status = BaseSrvSxsGetCachedSystemDefaultActivationContext(ProcessorArchitecture, &SystemDefaultActivationContext);
|
||
|
if (!NT_SUCCESS(Status) && SystemDefaultActivationContext == NULL) {
|
||
|
goto Exit;
|
||
|
}
|
||
|
//
|
||
|
// Enter the critical section to read the Section member data.
|
||
|
//
|
||
|
RtlEnterCriticalSection(&BaseSrvSxsSystemDefaultActivationContextCriticalSection);
|
||
|
Locked = TRUE;
|
||
|
if (SystemDefaultActivationContext->Section != NULL) {
|
||
|
goto GotActivationContext;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Leave the critical section a while, in order to reduce stress failure.
|
||
|
//
|
||
|
RtlLeaveCriticalSection(&BaseSrvSxsSystemDefaultActivationContextCriticalSection);
|
||
|
Locked = FALSE;
|
||
|
|
||
|
if (CsrImpersonateClient(NULL)) {
|
||
|
__try {
|
||
|
Status = NtQueryDefaultUILanguage(&LangId);
|
||
|
} __finally {
|
||
|
CsrRevertToSelf();
|
||
|
}
|
||
|
} else {
|
||
|
Status = NtQueryInstallUILanguage(&LangId);
|
||
|
}
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "SRVSXS: %s(): NtQueryDefaultUILanguage failed; status = 0x%08lx.\n", __FUNCTION__, Status));
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
RtlInitUnicodeStringBuffer(&SystemDefaultAssemblyDirectoryBuffer, SystemDefaultAssemblyDirectoryStaticBuffer, sizeof(SystemDefaultAssemblyDirectoryStaticBuffer));
|
||
|
SystemRoot = BaseSrvWindowsDirectory;
|
||
|
RtlRemoveTrailingPathSeperators(0, &SystemRoot);
|
||
|
|
||
|
{
|
||
|
#define X(x) { (x).Length, (x).MaximumLength, (x).Buffer }
|
||
|
/*static*/ const UNICODE_STRING Strings1[] =
|
||
|
{
|
||
|
X(SystemRoot),
|
||
|
RTL_CONSTANT_STRING(L"\\WinSxs")
|
||
|
};
|
||
|
#undef X
|
||
|
Status = RtlMultiAppendUnicodeStringBuffer(&SystemDefaultAssemblyDirectoryBuffer, RTL_NUMBER_OF(Strings1), Strings1);
|
||
|
IF_NOT_SUCCESS_TRACE_AND_EXIT(RtlMultiAppendUnicodeStringBuffer#1);
|
||
|
|
||
|
AssemblyDirectoryLength = SystemDefaultAssemblyDirectoryBuffer.String.Length; // AssemblyDirectory = "x:\winnt\winsxs\manifests"
|
||
|
}
|
||
|
|
||
|
Peb = NtCurrentPeb();
|
||
|
_snwprintf(
|
||
|
WindowsMajorDotMinorVersionBuffer,
|
||
|
RTL_NUMBER_OF(WindowsMajorDotMinorVersionBuffer),
|
||
|
L"%lu.%lu",
|
||
|
(ULONG)Peb->OSMajorVersion,
|
||
|
(ULONG)Peb->OSMinorVersion
|
||
|
);
|
||
|
WindowsMajorDotMinorVersionBufferLength = sizeof(WCHAR) * wcslen(WindowsMajorDotMinorVersionBuffer);
|
||
|
|
||
|
RtlInitUnicodeStringBuffer(&SystemDefaultTextualAssemblyIdentityBuffer,
|
||
|
SystemDefaultTextualAssemblyIdentityStaticBuffer, sizeof(SystemDefaultTextualAssemblyIdentityStaticBuffer));
|
||
|
{
|
||
|
#define X(x) { (x).Length, (x).MaximumLength, (x).Buffer }
|
||
|
/*static*/ const UNICODE_STRING Strings1[] =
|
||
|
{
|
||
|
RTL_CONSTANT_STRING(LSYSTEM_COMPATIBLE_ASSEMBLY_NAME L",version=\""),
|
||
|
{
|
||
|
(USHORT)WindowsMajorDotMinorVersionBufferLength,
|
||
|
(USHORT)WindowsMajorDotMinorVersionBufferLength + sizeof(WCHAR),
|
||
|
WindowsMajorDotMinorVersionBuffer
|
||
|
},
|
||
|
RTL_CONSTANT_STRING(L".0.0\",type=\"win32\",publicKeyToken=\"6595b64144ccf1df\",processorArchitecture=\""),
|
||
|
X(SystemDefaultActivationContext->ProcessorArchitectureString),
|
||
|
RTL_CONSTANT_STRING(L"\"")
|
||
|
};
|
||
|
#undef X
|
||
|
|
||
|
Status = RtlMultiAppendUnicodeStringBuffer(&SystemDefaultTextualAssemblyIdentityBuffer, RTL_NUMBER_OF(Strings1), Strings1);
|
||
|
IF_NOT_SUCCESS_TRACE_AND_EXIT(RtlMultiAppendUnicodeStringBuffer#3);
|
||
|
ASSERT_UNICODE_STRING_IS_NUL_TERMINATED(&SystemDefaultTextualAssemblyIdentityBuffer.String);
|
||
|
}
|
||
|
|
||
|
Struct.Flags = BASE_MSG_SXS_SYSTEM_DEFAULT_TEXTUAL_ASSEMBLY_IDENTITY_PRESENT;
|
||
|
Struct.Flags |= BASE_MSG_SXS_TEXTUAL_ASSEMBLY_IDENTITY_PRESENT;
|
||
|
Struct.TextualAssemblyIdentity.Buffer = SystemDefaultTextualAssemblyIdentityBuffer.String.Buffer;
|
||
|
Struct.TextualAssemblyIdentity.Length = SystemDefaultTextualAssemblyIdentityBuffer.String.Length;
|
||
|
Struct.TextualAssemblyIdentity.MaximumLength = SystemDefaultTextualAssemblyIdentityBuffer.String.MaximumLength;
|
||
|
Struct.AssemblyDirectory = SystemDefaultAssemblyDirectoryBuffer.String;
|
||
|
Struct.AssemblyDirectory.Length = AssemblyDirectoryLength;
|
||
|
Struct.AssemblyDirectory.Buffer[Struct.AssemblyDirectory.Length / sizeof(WCHAR)] = 0;
|
||
|
Struct.Manifest.PathType = BASE_MSG_PATHTYPE_FILE;
|
||
|
Struct.Manifest.Path = SystemDefaultContextString;
|
||
|
Struct.LangId = LangId;
|
||
|
Struct.ProcessorArchitecture = ProcessorArchitecture;
|
||
|
|
||
|
|
||
|
//
|
||
|
// BaseSrvSxsCreateActivationContextFromStruct would return STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY
|
||
|
// if the failure from ActCtx generation is ignorable.
|
||
|
//
|
||
|
Status =
|
||
|
BaseSrvSxsCreateActivationContextFromStruct(
|
||
|
NtCurrentProcess(),
|
||
|
NtCurrentProcess(),
|
||
|
&Struct,
|
||
|
&ActivationContextSection
|
||
|
);
|
||
|
IF_NOT_SUCCESS_TRACE_AND_EXIT(BaseSrvSxsCreateActivationContextFromStruct);
|
||
|
|
||
|
RtlEnterCriticalSection(&BaseSrvSxsSystemDefaultActivationContextCriticalSection);
|
||
|
Locked = TRUE;
|
||
|
if (SystemDefaultActivationContext->Section == NULL) {
|
||
|
SystemDefaultActivationContext->Section = ActivationContextSection;
|
||
|
} else {
|
||
|
NtClose(ActivationContextSection);
|
||
|
}
|
||
|
ActivationContextSection = NULL;
|
||
|
GotActivationContext:
|
||
|
//
|
||
|
// Hold the critical section until we
|
||
|
// finish with SystemDefaultActivationContext->Section.
|
||
|
//
|
||
|
ASSERT(ActivationContextSection == NULL);
|
||
|
ASSERT(SystemDefaultActivationContext != NULL
|
||
|
&& SystemDefaultActivationContext->Section != NULL);
|
||
|
ASSERT(Locked);
|
||
|
Status =
|
||
|
BaseSrvSxsMapViewOfSection(
|
||
|
&ViewBase,
|
||
|
NewProcess,
|
||
|
SystemDefaultActivationContext->Section,
|
||
|
0, // offset
|
||
|
0, // size
|
||
|
PAGE_READONLY,
|
||
|
SEC_NO_CHANGE);
|
||
|
RtlLeaveCriticalSection(&BaseSrvSxsSystemDefaultActivationContextCriticalSection);
|
||
|
Locked = FALSE;
|
||
|
IF_NOT_SUCCESS_TRACE_AND_EXIT(BaseSrvSxsMapViewOfSection);
|
||
|
|
||
|
Status =
|
||
|
NtWriteVirtualMemory(
|
||
|
NewProcess,
|
||
|
&NewPeb->SystemDefaultActivationContextData,
|
||
|
&ViewBase,
|
||
|
(ProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA32_ON_WIN64) ? sizeof(ULONG) : sizeof(ViewBase),
|
||
|
NULL);
|
||
|
IF_NOT_SUCCESS_TRACE_AND_EXIT(NtWriteVirtualMemory);
|
||
|
|
||
|
Status = STATUS_SUCCESS;
|
||
|
ViewBase = NULL;
|
||
|
Exit:
|
||
|
;
|
||
|
} __finally {
|
||
|
//
|
||
|
// do the critical section first because
|
||
|
// 1) it doesn't guard any of the others, they are all local
|
||
|
// 2) to keep the critical section held shorter
|
||
|
// 3) in case we exception out from any of the others
|
||
|
//
|
||
|
if (Locked) {
|
||
|
RtlLeaveCriticalSection(&BaseSrvSxsSystemDefaultActivationContextCriticalSection);
|
||
|
Locked = FALSE;
|
||
|
}
|
||
|
RtlFreeUnicodeStringBuffer(&SystemDefaultAssemblyDirectoryBuffer);
|
||
|
RtlFreeUnicodeStringBuffer(&SystemDefaultTextualAssemblyIdentityBuffer);
|
||
|
if (AbnormalTermination()) {
|
||
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "Abnormal termination in " __FUNCTION__ ".\n");
|
||
|
}
|
||
|
RTL_UNMAP_VIEW_OF_SECTION2(NewProcess, ViewBase);
|
||
|
|
||
|
if (RevertToSelfNeeded) {
|
||
|
CsrRevertToSelf(); // This unstacks client contexts
|
||
|
}
|
||
|
}
|
||
|
KdPrintEx((DPFLTR_SXS_ID, DPFLTR_LEVEL_STATUS(Status), "SXS: %s() exiting 0x%08lx\n", __FUNCTION__, Status));
|
||
|
return Status;
|
||
|
}
|