You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2587 lines
92 KiB
2587 lines
92 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
sxs.c
|
|
|
|
Abstract:
|
|
|
|
Side-by-side activation APIs for Win32
|
|
|
|
Author:
|
|
|
|
Michael Grier (MGrier) 2/29/2000
|
|
|
|
Revision History:
|
|
|
|
Jay Krell (a-JayK) June - July 2000
|
|
factored/merged with sxs.c, source code duplication eliminated
|
|
moved file opening out of csrss.exe to client process
|
|
merged with MGrier: flag per added api struct field, assembly dir support
|
|
|
|
Jon Wiswall (jonwis) Dec. 2000
|
|
Moved code here from csrsxs.c to make csrsxs.c tiny and more in-line with general
|
|
csrxxxx.c coding patterns, and to fix when we look in system32 vs. when
|
|
we look in syswow64
|
|
|
|
Jon Wiswall (jonwis) December 2000
|
|
ACTCTX's that don't specify what resource ID they want now automagically
|
|
search through the sources to find a resource type in the "actctx
|
|
source." This requires a gross EnumResourceNamesW call, after a
|
|
stomach-churning LoadLibraryExW to load the object.
|
|
|
|
Jay Krell (JayKrell) May 2001
|
|
CreateActCtx now honors "administrative" override for .dlls. (foo.dll.2.manifest)
|
|
(not) CreateActCtx now implements ACTCTX_FLAG_LIKE_CREATEPROCESS flag (foo.exe.manifest)
|
|
|
|
Jay Krell (JayKrell) March 2002
|
|
remove never finished, never used, dead ACTCTX_FLAG_LIKE_CREATEPROCESS code
|
|
|
|
Jon Wiswall (jonwis) May 2002
|
|
Change probing order to look for resources in PE's first and then look for
|
|
foo.exe.manifest
|
|
--*/
|
|
|
|
#include "basedll.h"
|
|
#include <sxstypes.h>
|
|
#include "sxsapi.h"
|
|
#include "winuser.h"
|
|
#include "wow64t.h"
|
|
#include "ntwow64.h"
|
|
|
|
#if DBG
|
|
BOOLEAN DebugFilter_SxsTrace;
|
|
#endif
|
|
|
|
#define DPFLTR_LEVEL_STATUS(x) ((NT_SUCCESS(x) \
|
|
|| (x) == STATUS_OBJECT_NAME_NOT_FOUND \
|
|
|| (x) == STATUS_RESOURCE_DATA_NOT_FOUND \
|
|
|| (x) == STATUS_RESOURCE_TYPE_NOT_FOUND \
|
|
|| (x) == STATUS_RESOURCE_NAME_NOT_FOUND \
|
|
|| (x) == STATUS_RESOURCE_LANG_NOT_FOUND \
|
|
|| (x) == STATUS_SXS_CANT_GEN_ACTCTX \
|
|
|| (x) == STATUS_SXS_ASSEMBLY_NOT_FOUND \
|
|
|| (x) == STATUS_NO_SUCH_FILE \
|
|
) \
|
|
? DPFLTR_TRACE_LEVEL : DPFLTR_ERROR_LEVEL)
|
|
|
|
#define ACTCTX_VALID_FLAGS \
|
|
( \
|
|
ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID | \
|
|
ACTCTX_FLAG_LANGID_VALID | \
|
|
ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID | \
|
|
ACTCTX_FLAG_RESOURCE_NAME_VALID | \
|
|
ACTCTX_FLAG_SET_PROCESS_DEFAULT | \
|
|
ACTCTX_FLAG_APPLICATION_NAME_VALID | \
|
|
ACTCTX_FLAG_HMODULE_VALID \
|
|
)
|
|
|
|
// This is the name for the manifest if we are given an assembly root directory but no manifest name is specified.
|
|
const WCHAR ManifestDefaultName[] = L"Application.Manifest";
|
|
|
|
#define MAXSIZE_T (~(SIZE_T)0)
|
|
|
|
extern const UNICODE_STRING SxsManifestSuffix = RTL_CONSTANT_STRING(L".Manifest");
|
|
extern const UNICODE_STRING SxsPolicySuffix = RTL_CONSTANT_STRING(L".Config");
|
|
|
|
#define MEDIUM_PATH (64)
|
|
|
|
#define IsSxsAcceptablePathType(x) ((x == RtlPathTypeUncAbsolute) || (x == RtlPathTypeDriveAbsolute) || (x == RtlPathTypeLocalDevice))
|
|
|
|
VOID
|
|
BasepSxsOverrideStreamToMessageStream(
|
|
IN PCSXS_OVERRIDE_STREAM OverrideStream,
|
|
OUT PBASE_MSG_SXS_STREAM MessageStream
|
|
);
|
|
|
|
HANDLE
|
|
WINAPI
|
|
CreateActCtxA(
|
|
PCACTCTXA pParamsA
|
|
)
|
|
{
|
|
ACTCTXW ParamsW = {sizeof(ParamsW)};
|
|
PUNICODE_STRING UnicodeString;
|
|
ANSI_STRING AnsiString;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
HANDLE ActivationContextHandle = INVALID_HANDLE_VALUE;
|
|
UNICODE_STRING AssemblyDir = {0};
|
|
WCHAR AssemblyDirBuffer[STATIC_UNICODE_BUFFER_LENGTH];
|
|
ULONG_PTR MappedResourceName = 0;
|
|
const PTEB Teb = NtCurrentTeb();
|
|
|
|
if (pParamsA == NULL
|
|
|| !RTL_CONTAINS_FIELD(pParamsA, pParamsA->cbSize, lpSource)
|
|
) {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: %s() Null %p or size 0x%lx too small\n",
|
|
__FUNCTION__,
|
|
pParamsA,
|
|
pParamsA->cbSize
|
|
);
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
ParamsW.dwFlags = pParamsA->dwFlags;
|
|
|
|
if (((ParamsW.dwFlags & ~ACTCTX_VALID_FLAGS) != 0) ||
|
|
((ParamsW.dwFlags & ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID) && !RTL_CONTAINS_FIELD(pParamsA, pParamsA->cbSize, wProcessorArchitecture)) ||
|
|
((ParamsW.dwFlags & ACTCTX_FLAG_LANGID_VALID) && !RTL_CONTAINS_FIELD(pParamsA, pParamsA->cbSize, wLangId)) ||
|
|
((ParamsW.dwFlags & ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID) && !RTL_CONTAINS_FIELD(pParamsA, pParamsA->cbSize, lpAssemblyDirectory)) ||
|
|
((ParamsW.dwFlags & ACTCTX_FLAG_RESOURCE_NAME_VALID) && !RTL_CONTAINS_FIELD(pParamsA, pParamsA->cbSize, lpResourceName)) ||
|
|
((ParamsW.dwFlags & ACTCTX_FLAG_APPLICATION_NAME_VALID) && !RTL_CONTAINS_FIELD(pParamsA, pParamsA->cbSize, lpApplicationName)) ||
|
|
((ParamsW.dwFlags & ACTCTX_FLAG_HMODULE_VALID) && !RTL_CONTAINS_FIELD(pParamsA, pParamsA->cbSize, hModule))) {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: %s() Bad flags/size 0x%lx/0x%lx\n",
|
|
__FUNCTION__,
|
|
pParamsA->dwFlags,
|
|
pParamsA->cbSize);
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
if (pParamsA->lpSource != NULL) {
|
|
UnicodeString = &Teb->StaticUnicodeString;
|
|
RtlInitAnsiString(&AnsiString, pParamsA->lpSource);
|
|
Status = Basep8BitStringToUnicodeString(UnicodeString, &AnsiString, FALSE);
|
|
if (!NT_SUCCESS(Status)) {
|
|
if (Status == STATUS_BUFFER_OVERFLOW) {
|
|
Status = STATUS_NAME_TOO_LONG;
|
|
}
|
|
goto Exit;
|
|
}
|
|
ParamsW.lpSource = UnicodeString->Buffer;
|
|
} else {
|
|
if ((ParamsW.dwFlags & ACTCTX_FLAG_HMODULE_VALID) == 0) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
ParamsW.lpSource = NULL;
|
|
}
|
|
|
|
if (ParamsW.dwFlags & ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID) {
|
|
ParamsW.wProcessorArchitecture = pParamsA->wProcessorArchitecture;
|
|
}
|
|
|
|
if (ParamsW.dwFlags & ACTCTX_FLAG_LANGID_VALID) {
|
|
ParamsW.wLangId = pParamsA->wLangId;
|
|
}
|
|
|
|
if (ParamsW.dwFlags & ACTCTX_FLAG_HMODULE_VALID) {
|
|
ParamsW.hModule = pParamsA->hModule;
|
|
}
|
|
|
|
if (ParamsW.dwFlags & ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID) {
|
|
RtlInitAnsiString(&AnsiString, pParamsA->lpAssemblyDirectory);
|
|
AssemblyDir.MaximumLength = sizeof(AssemblyDirBuffer);
|
|
AssemblyDir.Buffer = AssemblyDirBuffer;
|
|
|
|
Status = Basep8BitStringToUnicodeString(&AssemblyDir, &AnsiString, FALSE);
|
|
|
|
#if 0 // This is inconsistent. Two string ANSI APIs like MoveFileA are only
|
|
// documented to support MAX_PATH. They actually support one of the strings
|
|
// being unlimited, but let's stick to what is documented.
|
|
if (Status == STATUS_BUFFER_OVERFLOW) {
|
|
// Try again, this time with dynamic allocation
|
|
Status = Basep8BitStringToUnicodeString(&AssemblyDir, &AnsiString, TRUE);
|
|
}
|
|
#endif
|
|
if (Status == STATUS_BUFFER_OVERFLOW) {
|
|
Status = STATUS_NAME_TOO_LONG;
|
|
}
|
|
|
|
if (NT_ERROR(Status))
|
|
goto Exit;
|
|
|
|
ParamsW.lpAssemblyDirectory = AssemblyDir.Buffer;
|
|
}
|
|
|
|
if (ParamsW.dwFlags & ACTCTX_FLAG_RESOURCE_NAME_VALID) {
|
|
MappedResourceName = BaseDllMapResourceIdA(pParamsA->lpResourceName);
|
|
if (MappedResourceName == -1) {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: %s() BaseDllMapResourceIdA failed\n",
|
|
__FUNCTION__);
|
|
Status = Teb->LastStatusValue;
|
|
goto Exit;
|
|
}
|
|
ParamsW.lpResourceName = (PCWSTR) MappedResourceName;
|
|
}
|
|
|
|
ActivationContextHandle = CreateActCtxW(&ParamsW);
|
|
if (ActivationContextHandle == INVALID_HANDLE_VALUE) {
|
|
Status = Teb->LastStatusValue;
|
|
}
|
|
Exit:
|
|
if (AssemblyDir.Buffer != NULL
|
|
&& AssemblyDir.Buffer != AssemblyDirBuffer) {
|
|
RtlFreeUnicodeString(&AssemblyDir);
|
|
}
|
|
BaseDllFreeResourceId(MappedResourceName);
|
|
if (ActivationContextHandle == INVALID_HANDLE_VALUE) {
|
|
BaseSetLastNTError(Status);
|
|
}
|
|
#if DBG
|
|
if ( ActivationContextHandle == INVALID_HANDLE_VALUE ) {
|
|
DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_LEVEL_STATUS(Status),
|
|
"SXS: Exiting %s(%s, %p), Handle:%p, Status:0x%lx\n",
|
|
__FUNCTION__,
|
|
(pParamsA != NULL) ? pParamsA->lpSource : NULL,
|
|
(pParamsA != NULL) ? pParamsA->lpResourceName : NULL,
|
|
ActivationContextHandle,
|
|
Status
|
|
);
|
|
}
|
|
#endif
|
|
return ActivationContextHandle;
|
|
}
|
|
|
|
USHORT
|
|
BasepSxsGetProcessorArchitecture(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Return the processor architecture of the currently executing code/process.
|
|
//
|
|
USHORT Result;
|
|
#if defined(BUILD_WOW6432)
|
|
Result = PROCESSOR_ARCHITECTURE_IA32_ON_WIN64;
|
|
#elif defined(_M_IX86)
|
|
Result = PROCESSOR_ARCHITECTURE_INTEL;
|
|
#elif defined(_M_IA64)
|
|
Result = PROCESSOR_ARCHITECTURE_IA64;
|
|
#elif defined(_M_AMD64)
|
|
Result = PROCESSOR_ARCHITECTURE_AMD64;
|
|
#else
|
|
static USHORT StaticResult;
|
|
static BOOL Inited = FALSE;
|
|
if (!Inited) {
|
|
SYSTEM_INFO SystemInfo;
|
|
|
|
SystemInfo.wProcessorArchictecure = 0;
|
|
GetSystemInfo(&SystemInfo);
|
|
StaticResult = SystemInfo.wProcessorArchictecure;
|
|
Inited = TRUE;
|
|
}
|
|
Result = StaticResult;
|
|
#endif
|
|
return Result;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
BasepSxsActivationContextNotification(
|
|
IN ULONG NotificationType,
|
|
IN PACTIVATION_CONTEXT ActivationContext,
|
|
IN const VOID *ActivationContextData,
|
|
IN PVOID NotificationContext,
|
|
IN PVOID NotificationData,
|
|
IN OUT PBOOLEAN DisableNotification
|
|
)
|
|
{
|
|
switch (NotificationType)
|
|
{
|
|
case ACTIVATION_CONTEXT_NOTIFICATION_DESTROY:
|
|
RTL_SOFT_VERIFY(NT_SUCCESS(NtUnmapViewOfSection(NtCurrentProcess(), (PVOID) ActivationContextData)));
|
|
break;
|
|
|
|
default:
|
|
// Otherwise, we don't need to see this notification ever again.
|
|
*DisableNotification = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
VOID
|
|
DbgPrintActCtx(
|
|
PCSTR FunctionPlus,
|
|
PCACTCTXW ActCtx
|
|
)
|
|
{
|
|
// odd but correct
|
|
if (NtQueryDebugFilterState(DPFLTR_SXS_ID, DPFLTR_INFO_LEVEL) != TRUE)
|
|
return;
|
|
|
|
DbgPrint("%s Flags 0x%08lx(%s%s%s%s%s%s%s%s)\n",
|
|
FunctionPlus,
|
|
ActCtx->dwFlags,
|
|
(ActCtx->dwFlags & ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID ) ? " processor" : "",
|
|
(ActCtx->dwFlags & ACTCTX_FLAG_LANGID_VALID ) ? " langid" : "",
|
|
(ActCtx->dwFlags & ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID ) ? " directory" : "",
|
|
(ActCtx->dwFlags & ACTCTX_FLAG_RESOURCE_NAME_VALID ) ? " resource" : "",
|
|
(ActCtx->dwFlags & ACTCTX_FLAG_SET_PROCESS_DEFAULT ) ? " setdefault" : "",
|
|
(ActCtx->dwFlags & ACTCTX_FLAG_APPLICATION_NAME_VALID ) ? " appname" : "",
|
|
(ActCtx->dwFlags & ACTCTX_FLAG_SOURCE_IS_ASSEMBLYREF ) ? " asmref" : "",
|
|
(ActCtx->dwFlags & ACTCTX_FLAG_HMODULE_VALID ) ? " hmodule" : ""
|
|
);
|
|
|
|
DbgPrint("%s Source %ls\n", FunctionPlus, ActCtx->lpSource);
|
|
|
|
if (ActCtx->dwFlags & ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID)
|
|
DbgPrint("%s ProcessorArchitecture 0x%08lx\n", FunctionPlus, ActCtx->wProcessorArchitecture);
|
|
|
|
if (ActCtx->dwFlags & ACTCTX_FLAG_LANGID_VALID)
|
|
DbgPrint("%s LangId 0x%08lx\n", FunctionPlus, ActCtx->wLangId);
|
|
|
|
if (ActCtx->dwFlags & ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID)
|
|
DbgPrint("%s AssemblyDirectory %ls\n", FunctionPlus, ActCtx->lpAssemblyDirectory);
|
|
|
|
if (ActCtx->dwFlags & ACTCTX_FLAG_RESOURCE_NAME_VALID)
|
|
DbgPrint("%s ResourceName %p (%Id)\n", FunctionPlus, ActCtx->lpResourceName, (ULONG_PTR) ActCtx->lpResourceName);
|
|
|
|
if (ActCtx->dwFlags & ACTCTX_FLAG_APPLICATION_NAME_VALID)
|
|
DbgPrint("%s ApplicationName %ls\n", FunctionPlus, ActCtx->lpApplicationName);
|
|
|
|
if (ActCtx->dwFlags & ACTCTX_FLAG_HMODULE_VALID)
|
|
DbgPrint("%s hModule = %p\n", FunctionPlus, ActCtx->hModule);
|
|
|
|
}
|
|
#endif
|
|
|
|
typedef struct EnumResParams {
|
|
ULONG_PTR *MappedResourceName;
|
|
BOOL FoundManifest;
|
|
BOOL ErrorEncountered;
|
|
} EnumResParams;
|
|
|
|
BOOL CALLBACK
|
|
BasepSxsSuitableManifestCallback(
|
|
HMODULE hModule,
|
|
PCWSTR lpszType,
|
|
PWSTR lpszName,
|
|
LONG_PTR lParam
|
|
)
|
|
{
|
|
EnumResParams *pParams = (EnumResParams*)lParam;
|
|
BOOL fContinueEnumeration = FALSE;
|
|
|
|
#if DBG
|
|
if (DebugFilter_SxsTrace)
|
|
DbgPrintEx( DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL,
|
|
"Sxs.c: %s(%p, %p, %p, %p)\n",
|
|
__FUNCTION__, hModule, lpszType, lpszName, lParam
|
|
);
|
|
#endif
|
|
|
|
ASSERT((pParams != NULL) &&
|
|
(!pParams->ErrorEncountered) &&
|
|
(!pParams->FoundManifest) &&
|
|
(pParams->MappedResourceName != NULL));
|
|
|
|
ASSERT(lpszType == MAKEINTRESOURCEW(RT_MANIFEST));
|
|
|
|
// Boo! Boooooo!
|
|
if ((pParams == NULL) ||
|
|
(pParams->ErrorEncountered) ||
|
|
(pParams->FoundManifest) ||
|
|
(pParams->MappedResourceName == NULL)) {
|
|
// None of these should be able to happen except if there is a coding error in the caller
|
|
// of EnumResourceNamesW() or in the code for EnumResourceNamesW().
|
|
if (pParams != NULL)
|
|
pParams->ErrorEncountered = TRUE;
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
fContinueEnumeration = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
#if DBG
|
|
if (DebugFilter_SxsTrace)
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_TRACE_LEVEL,
|
|
" Params (start): { ResName: *(%p) = %p, Found: %s, Error: %s }",
|
|
pParams->MappedResourceName, pParams->MappedResourceName,
|
|
pParams->FoundManifest ? "true" : "false",
|
|
pParams->ErrorEncountered ? "true" : "false");
|
|
#endif
|
|
|
|
if (lpszType == MAKEINTRESOURCEW(RT_MANIFEST)) {
|
|
// We found one - we don't care about others
|
|
*pParams->MappedResourceName = BaseDllMapResourceIdW(lpszName);
|
|
pParams->FoundManifest = TRUE;
|
|
fContinueEnumeration = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
// This should not be able to happen; we should only be called for
|
|
// RT_MANIFEST resources, but in case it somehow does happen, go on to the
|
|
// next one.
|
|
fContinueEnumeration = TRUE;
|
|
|
|
Exit:
|
|
|
|
#if DBG
|
|
if ((pParams != NULL) && (pParams->MappedResourceName))
|
|
if (DebugFilter_SxsTrace)
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_TRACE_LEVEL,
|
|
" Params (end): { ResName: *(%p) = %p, Found: %s, Error: %s }",
|
|
pParams->MappedResourceName, pParams->MappedResourceName,
|
|
pParams->FoundManifest ? "true" : "false",
|
|
pParams->ErrorEncountered ? "true" : "false");
|
|
#endif
|
|
|
|
return fContinueEnumeration;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
BasepSxsFindSuitableManifestResourceFor(
|
|
PCACTCTXW Params,
|
|
ULONG_PTR *MappedResourceName,
|
|
BOOL *FoundManifest
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
EnumResParams FinderParameters = { MappedResourceName, FALSE, FALSE };
|
|
HMODULE hSourceItem = NULL;
|
|
BOOL FreeSourceModule = FALSE;
|
|
|
|
if (FoundManifest != NULL)
|
|
*FoundManifest = FALSE;
|
|
|
|
if (MappedResourceName != NULL)
|
|
*MappedResourceName = 0;
|
|
|
|
if ((FoundManifest == NULL) ||
|
|
(MappedResourceName == NULL)) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// General pattern - open Params->lpSource and attempt to find the first
|
|
// resource with type == RT_MANIFEST (24). Stuff its resource name into
|
|
// MappedResourceName.
|
|
//
|
|
|
|
if (Params->dwFlags & ACTCTX_FLAG_HMODULE_VALID) {
|
|
hSourceItem = Params->hModule;
|
|
FreeSourceModule = FALSE;
|
|
} else {
|
|
//
|
|
// Map the dll/exe/etc. If this fails, then there's a good chance that the
|
|
// thing isn't a dll or exe, so don't fail out, just indicate that no manifest
|
|
// was found.
|
|
//
|
|
hSourceItem = LoadLibraryExW(Params->lpSource, NULL, LOAD_LIBRARY_AS_DATAFILE);
|
|
if ((hSourceItem == NULL) || (hSourceItem == INVALID_HANDLE_VALUE)) {
|
|
Status = NtCurrentTeb()->LastStatusValue;
|
|
goto Exit;
|
|
}
|
|
|
|
FreeSourceModule = TRUE;
|
|
}
|
|
|
|
//
|
|
// If this fails with something other than ERROR_RESOURCE_TYPE_NOT_FOUND
|
|
// then we're in an interesting state.
|
|
//
|
|
if (!EnumResourceNamesW(
|
|
hSourceItem,
|
|
MAKEINTRESOURCEW(RT_MANIFEST),
|
|
&BasepSxsSuitableManifestCallback,
|
|
(LONG_PTR) &FinderParameters)) {
|
|
DWORD dwError = GetLastError();
|
|
if ((dwError != ERROR_SUCCESS) && (dwError != ERROR_RESOURCE_TYPE_NOT_FOUND)) {
|
|
Status = NtCurrentTeb()->LastStatusValue;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
if (DebugFilter_SxsTrace && FreeSourceModule && *MappedResourceName != 0) {
|
|
// Debugging code for mgrier to see what DLLs we're actually using the enum pattern for.
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_TRACE_LEVEL,
|
|
"SXS: Found resource %d in %ls (process %wZ) by enumeration\n",
|
|
(INT) *MappedResourceName,
|
|
Params->lpSource,
|
|
&NtCurrentPeb()->ProcessParameters->ImagePathName);
|
|
}
|
|
#endif
|
|
|
|
Status = STATUS_SUCCESS;
|
|
Exit:
|
|
if ((hSourceItem != NULL) &&
|
|
(hSourceItem != INVALID_HANDLE_VALUE) &&
|
|
(FreeSourceModule))
|
|
FreeLibrary(hSourceItem);
|
|
|
|
return Status;
|
|
}
|
|
|
|
HANDLE
|
|
WINAPI
|
|
CreateActCtxW(
|
|
PCACTCTXW pParamsW
|
|
)
|
|
{
|
|
HANDLE ActivationContextHandle = INVALID_HANDLE_VALUE;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
ACTCTXW Params = { sizeof(Params) };
|
|
ULONG_PTR MappedResourceName = 0;
|
|
PVOID ActivationContextData = NULL;
|
|
// lpTempSourcePath is used to hold a pointer to the source path if it needs to be created
|
|
// in this function. It should be freed before leaving the function.
|
|
LPWSTR lpTempSourcePath = NULL;
|
|
PPEB Peb = NULL;
|
|
RTL_UNICODE_STRING_BUFFER AssemblyDirectoryFromSourceBuffer = { 0 };
|
|
RTL_UNICODE_STRING_BUFFER SourceBuffer = { 0 };
|
|
RTL_UNICODE_STRING_BUFFER ApplicationNameManifest = { 0 };
|
|
UCHAR StaticBuffer[256];
|
|
UCHAR SourceStaticBuffer[256];
|
|
UCHAR ApplicationNameStaticBuffer[128];
|
|
BOOLEAN PebLockAcquired = FALSE;
|
|
ULONG BasepCreateActCtxFlags = 0;
|
|
|
|
#if DBG
|
|
DebugFilter_SxsTrace = (NtQueryDebugFilterState(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL) == TRUE);
|
|
|
|
DbgPrintActCtx(__FUNCTION__ " before munging", pParamsW);
|
|
#endif
|
|
|
|
if ((pParamsW == NULL) ||
|
|
!RTL_CONTAINS_FIELD(pParamsW, pParamsW->cbSize, lpSource)) {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: %s() Null %p or size 0x%lx too small\n",
|
|
__FUNCTION__,
|
|
pParamsW,
|
|
pParamsW->cbSize
|
|
);
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
Params.dwFlags = pParamsW->dwFlags;
|
|
|
|
if ((Params.dwFlags & ~ACTCTX_VALID_FLAGS) ||
|
|
((Params.dwFlags & ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID) && !RTL_CONTAINS_FIELD(pParamsW, pParamsW->cbSize, wProcessorArchitecture)) ||
|
|
((Params.dwFlags & ACTCTX_FLAG_LANGID_VALID) && !RTL_CONTAINS_FIELD(pParamsW, pParamsW->cbSize, wLangId)) ||
|
|
((Params.dwFlags & ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID) && !RTL_CONTAINS_FIELD(pParamsW, pParamsW->cbSize, lpAssemblyDirectory)) ||
|
|
((Params.dwFlags & ACTCTX_FLAG_RESOURCE_NAME_VALID) && !RTL_CONTAINS_FIELD(pParamsW, pParamsW->cbSize, lpResourceName)) ||
|
|
((Params.dwFlags & ACTCTX_FLAG_APPLICATION_NAME_VALID) && !RTL_CONTAINS_FIELD(pParamsW, pParamsW->cbSize, lpApplicationName)) ||
|
|
((Params.dwFlags & ACTCTX_FLAG_HMODULE_VALID) && !RTL_CONTAINS_FIELD(pParamsW, pParamsW->cbSize, hModule))) {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: %s() Bad flags/size 0x%lx/0x%lx\n",
|
|
__FUNCTION__,
|
|
pParamsW->dwFlags,
|
|
pParamsW->cbSize);
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
if (Params.dwFlags & ACTCTX_FLAG_SET_PROCESS_DEFAULT) {
|
|
Peb = NtCurrentPeb();
|
|
if (Peb->ActivationContextData != NULL) {
|
|
Status = STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Params.lpSource = pParamsW->lpSource;
|
|
|
|
// We need at least either a source path or an HMODULE.
|
|
if ((Params.lpSource == NULL) &&
|
|
((Params.dwFlags & ACTCTX_FLAG_HMODULE_VALID) == 0) &&
|
|
((Params.dwFlags & ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID) == 0)) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
if (Params.dwFlags & ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID) {
|
|
USHORT wProcessorArchitecture = pParamsW->wProcessorArchitecture;
|
|
#if defined(BUILD_WOW6432)
|
|
if (wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
|
|
wProcessorArchitecture = PROCESSOR_ARCHITECTURE_IA32_ON_WIN64;
|
|
#endif
|
|
|
|
if ((wProcessorArchitecture != PROCESSOR_ARCHITECTURE_UNKNOWN) &&
|
|
(wProcessorArchitecture != BasepSxsGetProcessorArchitecture())) {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: %s() bad wProcessorArchitecture 0x%x\n",
|
|
__FUNCTION__,
|
|
pParamsW->wProcessorArchitecture);
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
Params.wProcessorArchitecture = wProcessorArchitecture;
|
|
} else {
|
|
Params.wProcessorArchitecture = BasepSxsGetProcessorArchitecture();
|
|
Params.dwFlags |= ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID;
|
|
}
|
|
|
|
if (Params.dwFlags & ACTCTX_FLAG_LANGID_VALID) {
|
|
Params.wLangId = pParamsW->wLangId;
|
|
} else {
|
|
Params.wLangId = GetUserDefaultUILanguage();
|
|
Params.dwFlags |= ACTCTX_FLAG_LANGID_VALID;
|
|
}
|
|
|
|
if (Params.dwFlags & ACTCTX_FLAG_HMODULE_VALID)
|
|
Params.hModule = pParamsW->hModule;
|
|
|
|
if (Params.dwFlags & ACTCTX_FLAG_APPLICATION_NAME_VALID)
|
|
Params.lpApplicationName = pParamsW->lpApplicationName;
|
|
|
|
// If the assembly root dir is specified, then the valid values for lpSource are
|
|
// NULL - This implies that we look for a file called "application.manifest" in the assembly root dir.
|
|
// Relative FilePath - if lpSource is relative then we combine it with the assembly root dir to get the path.
|
|
// Absolute path - used unmodified.
|
|
|
|
Params.lpAssemblyDirectory = pParamsW->lpAssemblyDirectory;
|
|
|
|
if (Params.dwFlags & ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID) {
|
|
RTL_PATH_TYPE AssemblyPathType;
|
|
RTL_PATH_TYPE SourcePathType;
|
|
// if this is true, implies we will make the source path from the assembly dir.
|
|
BOOL MakeSourcePath = FALSE ;
|
|
LPCWSTR RelativePath = NULL;
|
|
|
|
if ((Params.lpAssemblyDirectory == NULL) ||
|
|
(Params.lpAssemblyDirectory[0] == 0)) {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: %s() Bad lpAssemblyDirectory %ls\n",
|
|
__FUNCTION__,
|
|
Params.lpAssemblyDirectory);
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
// Next check that the assembly dir is an absolute file name.
|
|
AssemblyPathType = RtlDetermineDosPathNameType_U(Params.lpAssemblyDirectory);
|
|
if (!IsSxsAcceptablePathType(AssemblyPathType)) {
|
|
#if DBG
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: %s() Bad lpAssemblyDirectory PathType %ls, 0x%lx\n",
|
|
__FUNCTION__,
|
|
Params.lpAssemblyDirectory,
|
|
(LONG) AssemblyPathType);
|
|
#endif
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
if (Params.lpSource != NULL) {
|
|
SourcePathType = RtlDetermineDosPathNameType_U(Params.lpSource);
|
|
if (IsSxsAcceptablePathType(SourcePathType)){
|
|
MakeSourcePath = FALSE ; // We don't need to mess with lpSource in this case.
|
|
} else if ( SourcePathType == RtlPathTypeRelative ) {
|
|
MakeSourcePath = TRUE ;
|
|
RelativePath = Params.lpSource;
|
|
} else {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: %s() Bad lpSource PathType %ls, 0x%lx\n",
|
|
__FUNCTION__,
|
|
Params.lpSource,
|
|
(LONG)SourcePathType);
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
}
|
|
else {
|
|
MakeSourcePath = TRUE;
|
|
|
|
// If they told us an application name, then try using it instead. There's no
|
|
// validation done here, as we'll just fail later on with a 'bad path' error
|
|
// if the application name is invalid.
|
|
if (Params.dwFlags & ACTCTX_FLAG_APPLICATION_NAME_VALID) {
|
|
|
|
UNICODE_STRING TempBuffer;
|
|
|
|
if ((Params.lpApplicationName == NULL) ||
|
|
(Params.lpApplicationName[0] == UNICODE_NULL)) {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: %s() Bad lpApplication name '%ls'\n",
|
|
__FUNCTION__,
|
|
Params.lpApplicationName);
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
RtlInitUnicodeString(&TempBuffer, Params.lpApplicationName);
|
|
RtlInitUnicodeStringBuffer(&ApplicationNameManifest, ApplicationNameStaticBuffer, sizeof(ApplicationNameStaticBuffer));
|
|
|
|
Status = RtlAssignUnicodeStringBuffer(&ApplicationNameManifest, &TempBuffer);
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Exit;
|
|
}
|
|
|
|
Status = RtlAppendUnicodeStringBuffer(&ApplicationNameManifest, &SxsManifestSuffix);
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Exit;
|
|
}
|
|
|
|
// Ensure that we null-terminate the name we're building is NUL terminated
|
|
Status = RtlEnsureUnicodeStringBufferSizeBytes(&ApplicationNameManifest, ApplicationNameManifest.String.Length + sizeof(WCHAR));
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Exit;
|
|
}
|
|
|
|
RTL_STRING_NUL_TERMINATE(&ApplicationNameManifest.String);
|
|
|
|
RelativePath = ApplicationNameManifest.String.Buffer;
|
|
}
|
|
else {
|
|
RelativePath = ManifestDefaultName;
|
|
}
|
|
}
|
|
|
|
if (MakeSourcePath) {
|
|
ULONG LengthAssemblyDir;
|
|
ULONG LengthRelativePath ;
|
|
ULONG Length ; // Will hold total number of characters we
|
|
BOOL AddTrailingSlash = FALSE;
|
|
LPWSTR lpCurrent;
|
|
|
|
LengthAssemblyDir = wcslen(Params.lpAssemblyDirectory);
|
|
AddTrailingSlash = (Params.lpAssemblyDirectory[LengthAssemblyDir - 1] != L'\\');
|
|
LengthRelativePath = wcslen(RelativePath);
|
|
|
|
// Do this at least once with the given path, do it again if we have to switch
|
|
// from the relative path to Assembly.Manifest.
|
|
RepeatAssemblyPathProbing:
|
|
|
|
Length = LengthAssemblyDir + (AddTrailingSlash ? 1 : 0) + LengthRelativePath;
|
|
Length++ ; // For NULL terminator
|
|
|
|
ASSERT(lpTempSourcePath == NULL);
|
|
lpTempSourcePath = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
|
|
Length * sizeof(WCHAR));
|
|
|
|
if (lpTempSourcePath == NULL) {
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Exit;
|
|
}
|
|
|
|
lpCurrent = lpTempSourcePath;
|
|
|
|
memcpy(lpCurrent, Params.lpAssemblyDirectory, LengthAssemblyDir * sizeof(WCHAR));
|
|
lpCurrent += LengthAssemblyDir;
|
|
|
|
if (AddTrailingSlash) {
|
|
*lpCurrent = L'\\';
|
|
lpCurrent++;
|
|
}
|
|
|
|
memcpy(lpCurrent, RelativePath, LengthRelativePath * sizeof(WCHAR));
|
|
lpCurrent += LengthRelativePath;
|
|
|
|
*lpCurrent = L'\0';
|
|
|
|
// If the resulting file doesn't exist and the current 'relativepath' is
|
|
// the same as the ApplicationNameManifest stringbuffer, then reset it
|
|
// and try again with Application.Manifest (making sure to free the
|
|
// temp source path too.
|
|
if (!RtlDoesFileExists_U(lpTempSourcePath) &&
|
|
(RelativePath == ApplicationNameManifest.String.Buffer)) {
|
|
|
|
RelativePath = ManifestDefaultName;
|
|
LengthRelativePath = RTL_NUMBER_OF(ManifestDefaultName) - 1;
|
|
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, lpTempSourcePath);
|
|
lpTempSourcePath = NULL;
|
|
goto RepeatAssemblyPathProbing;
|
|
}
|
|
|
|
// make this the new lpSource member.
|
|
Params.lpSource = lpTempSourcePath;
|
|
}
|
|
} else {
|
|
SIZE_T SourceLength;
|
|
|
|
//
|
|
// Ensure that this is a full absolute path. If it's relative, then this
|
|
// must be expanded out to the full path before we use it to default the
|
|
// lpAssemblyDirectory member.
|
|
//
|
|
// There is no precedent for using the peb lock this way, but it is the correct
|
|
// thing. FullPaths can change as the current working directory is modified
|
|
// on other threads. The behavior isn't predictable either way, but our
|
|
// code works better.
|
|
//
|
|
Status = STATUS_SUCCESS;
|
|
RtlAcquirePebLock();
|
|
__try {
|
|
RtlInitUnicodeStringBuffer(&SourceBuffer, SourceStaticBuffer, sizeof(SourceStaticBuffer));
|
|
SourceLength = RtlGetFullPathName_U( Params.lpSource, (ULONG)SourceBuffer.ByteBuffer.Size, SourceBuffer.String.Buffer, NULL );
|
|
if (SourceLength == 0) {
|
|
Status = STATUS_NO_MEMORY;
|
|
leave;
|
|
} else if (SourceLength > SourceBuffer.ByteBuffer.Size) {
|
|
Status = RtlEnsureUnicodeStringBufferSizeBytes(&SourceBuffer, SourceLength);
|
|
if ( !NT_SUCCESS(Status) )
|
|
leave;
|
|
SourceLength = RtlGetFullPathName_U( Params.lpSource, (ULONG)SourceBuffer.ByteBuffer.Size, SourceBuffer.String.Buffer, NULL );
|
|
if (SourceLength == 0) {
|
|
Status = STATUS_NO_MEMORY;
|
|
leave;
|
|
}
|
|
}
|
|
SourceBuffer.String.Length = (USHORT)SourceLength;
|
|
Params.lpSource = SourceBuffer.String.Buffer;
|
|
} __finally {
|
|
RtlReleasePebLock();
|
|
}
|
|
|
|
if ( !NT_SUCCESS(Status) )
|
|
goto Exit;
|
|
|
|
// This would be a nice place to use
|
|
// RtlTakeRemainingStaticBuffer(&SourceBuffer, &DirectoryBuffer, &DirectoryBufferSize);
|
|
// RtlInitUnicodeStringBuffer(&DirectoryBuffer, &DirectoryBuffer, &DirectoryBufferSize);
|
|
// but RtlTakeRemainingStaticBuffer has not yet been tested.
|
|
|
|
RtlInitUnicodeStringBuffer(&AssemblyDirectoryFromSourceBuffer, StaticBuffer, sizeof(StaticBuffer));
|
|
Status = RtlAssignUnicodeStringBuffer(&AssemblyDirectoryFromSourceBuffer, &SourceBuffer.String);
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Exit;
|
|
}
|
|
Status = RtlRemoveLastFullDosOrNtPathElement(0, &AssemblyDirectoryFromSourceBuffer);
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Exit;
|
|
}
|
|
RTL_NUL_TERMINATE_STRING(&AssemblyDirectoryFromSourceBuffer.String);
|
|
Params.lpAssemblyDirectory = AssemblyDirectoryFromSourceBuffer.String.Buffer;
|
|
Params.dwFlags |= ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID;
|
|
}
|
|
|
|
if (Params.dwFlags & ACTCTX_FLAG_RESOURCE_NAME_VALID) {
|
|
if (pParamsW->lpResourceName == 0) {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: %s() ACTCTX_FLAG_RESOURCE_NAME_VALID set but lpResourceName == 0\n",
|
|
__FUNCTION__
|
|
);
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
MappedResourceName = BaseDllMapResourceIdW(pParamsW->lpResourceName);
|
|
if (MappedResourceName == -1) {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: %s() BaseDllMapResourceIdW failed\n",
|
|
__FUNCTION__
|
|
);
|
|
Status = NtCurrentTeb()->LastStatusValue;
|
|
goto Exit;
|
|
}
|
|
|
|
Params.lpResourceName = (PCWSTR) MappedResourceName;
|
|
} else {
|
|
BOOL ProbeFoundManifestResource;
|
|
//
|
|
// Otherwise, probe through the filename that was passed in via the resource
|
|
// enumeration functions to find the first suitable manifest.
|
|
//
|
|
Status = BasepSxsFindSuitableManifestResourceFor(&Params, &MappedResourceName, &ProbeFoundManifestResource);
|
|
if ((!NT_SUCCESS(Status)) &&
|
|
(Status != STATUS_INVALID_IMAGE_FORMAT))
|
|
goto Exit;
|
|
|
|
if (ProbeFoundManifestResource) {
|
|
Params.lpResourceName = (PCWSTR) MappedResourceName;
|
|
Params.dwFlags |= ACTCTX_FLAG_RESOURCE_NAME_VALID;
|
|
}
|
|
BasepCreateActCtxFlags = BASEP_CREATE_ACTCTX_FLAG_NO_ADMIN_OVERRIDE;
|
|
}
|
|
|
|
#if DBG
|
|
DbgPrintActCtx(__FUNCTION__ " after munging", &Params);
|
|
#endif
|
|
|
|
Status = BasepCreateActCtx(BasepCreateActCtxFlags, &Params, &ActivationContextData);
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Exit;
|
|
}
|
|
|
|
if (Params.dwFlags & ACTCTX_FLAG_SET_PROCESS_DEFAULT) {
|
|
if (Peb->ActivationContextData != NULL) {
|
|
Status = STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET;
|
|
goto Exit;
|
|
}
|
|
if (InterlockedCompareExchangePointer(
|
|
(PVOID*)&Peb->ActivationContextData,
|
|
ActivationContextData,
|
|
NULL
|
|
)
|
|
!= NULL) {
|
|
Status = STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET;
|
|
goto Exit;
|
|
}
|
|
ActivationContextData = NULL; // don't unmap it
|
|
ActivationContextHandle = NULL; // unusual success value, INVALID_HANDLE_VALUE is failure
|
|
// and we don't need to return anything to be cleaned up
|
|
Status = STATUS_SUCCESS;
|
|
goto Exit;
|
|
}
|
|
|
|
Status = RtlCreateActivationContext(
|
|
0,
|
|
ActivationContextData,
|
|
0, // no extra bytes required today
|
|
BasepSxsActivationContextNotification,
|
|
NULL,
|
|
(PACTIVATION_CONTEXT *) &ActivationContextHandle);
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_LEVEL_STATUS(Status),
|
|
"SXS: RtlCreateActivationContext() failed 0x%08lx\n", Status);
|
|
|
|
// Just in case RtlCreateActivationContext() set it to NULL...
|
|
ActivationContextHandle = INVALID_HANDLE_VALUE;
|
|
goto Exit;
|
|
}
|
|
|
|
ActivationContextData = NULL; // Don't unmap in exit if we actually succeeded.
|
|
Status = STATUS_SUCCESS;
|
|
Exit:
|
|
if (ActivationContextData != NULL) {
|
|
NtUnmapViewOfSection(NtCurrentProcess(), ActivationContextData);
|
|
}
|
|
BaseDllFreeResourceId(MappedResourceName);
|
|
if (!NT_SUCCESS(Status)) {
|
|
BaseSetLastNTError(Status);
|
|
ActivationContextHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
#if DBG
|
|
if (ActivationContextHandle == INVALID_HANDLE_VALUE) {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_LEVEL_STATUS(Status),
|
|
"SXS: Exiting %s(%ls / %ls, %p), ActivationContextHandle:%p, Status:0x%lx\n",
|
|
__FUNCTION__,
|
|
Params.lpSource, pParamsW->lpSource,
|
|
Params.lpResourceName,
|
|
ActivationContextHandle,
|
|
Status
|
|
);
|
|
}
|
|
#endif
|
|
|
|
// Do these after DbgPrintEx because at least one of them can get printed.
|
|
RtlFreeUnicodeStringBuffer(&AssemblyDirectoryFromSourceBuffer);
|
|
RtlFreeUnicodeStringBuffer(&SourceBuffer);
|
|
RtlFreeUnicodeStringBuffer(&ApplicationNameManifest);
|
|
if (lpTempSourcePath != NULL) {
|
|
// Set the lpSource value back to the original so we don't access freed memory.
|
|
Params.lpSource = pParamsW->lpSource;
|
|
RtlFreeHeap(RtlProcessHeap(), 0, lpTempSourcePath);
|
|
}
|
|
return ActivationContextHandle;
|
|
}
|
|
|
|
VOID
|
|
WINAPI
|
|
AddRefActCtx(
|
|
HANDLE hActCtx
|
|
)
|
|
{
|
|
RtlAddRefActivationContext((PACTIVATION_CONTEXT) hActCtx);
|
|
}
|
|
|
|
VOID
|
|
WINAPI
|
|
ReleaseActCtx(
|
|
HANDLE hActCtx
|
|
)
|
|
{
|
|
RtlReleaseActivationContext((PACTIVATION_CONTEXT) hActCtx);
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
ZombifyActCtx(
|
|
HANDLE hActCtx
|
|
)
|
|
{
|
|
NTSTATUS Status = RtlZombifyActivationContext((PACTIVATION_CONTEXT) hActCtx);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BaseSetLastNTError(Status);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
ActivateActCtx(
|
|
HANDLE hActCtx,
|
|
ULONG_PTR *lpCookie
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
if (hActCtx == INVALID_HANDLE_VALUE) {
|
|
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
Status = RtlActivateActivationContext(0, (PACTIVATION_CONTEXT) hActCtx, lpCookie);
|
|
if (!NT_SUCCESS(Status)) {
|
|
BaseSetLastNTError(Status);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
DeactivateActCtx(
|
|
DWORD dwFlags,
|
|
ULONG_PTR ulCookie
|
|
)
|
|
{
|
|
DWORD dwFlagsDown = 0;
|
|
|
|
if ((dwFlags & ~(DEACTIVATE_ACTCTX_FLAG_FORCE_EARLY_DEACTIVATION)) != 0) {
|
|
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
if (dwFlags & DEACTIVATE_ACTCTX_FLAG_FORCE_EARLY_DEACTIVATION)
|
|
dwFlagsDown |= RTL_DEACTIVATE_ACTIVATION_CONTEXT_FLAG_FORCE_EARLY_DEACTIVATION;
|
|
|
|
// The Rtl function does not fail...
|
|
RtlDeactivateActivationContext(dwFlagsDown, ulCookie);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
GetCurrentActCtx(
|
|
HANDLE *lphActCtx)
|
|
{
|
|
NTSTATUS Status;
|
|
BOOL fSuccess = FALSE;
|
|
|
|
if (lphActCtx == NULL) {
|
|
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
|
goto Exit;
|
|
}
|
|
|
|
Status = RtlGetActiveActivationContext((PACTIVATION_CONTEXT *) lphActCtx);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BaseSetLastNTError(Status);
|
|
goto Exit;
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
NTSTATUS
|
|
BasepAllocateActivationContextActivationBlock(
|
|
IN DWORD Flags,
|
|
IN PVOID Callback,
|
|
IN PVOID CallbackContext,
|
|
OUT PBASE_ACTIVATION_CONTEXT_ACTIVATION_BLOCK *ActivationBlock
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
ACTIVATION_CONTEXT_BASIC_INFORMATION acbi = {0};
|
|
|
|
if (ActivationBlock != NULL)
|
|
*ActivationBlock = NULL;
|
|
|
|
if ((Flags & ~(
|
|
BASEP_ALLOCATE_ACTIVATION_CONTEXT_ACTIVATION_BLOCK_FLAG_DO_NOT_FREE_AFTER_CALLBACK |
|
|
BASEP_ALLOCATE_ACTIVATION_CONTEXT_ACTIVATION_BLOCK_FLAG_DO_NOT_ALLOCATE_IF_PROCESS_DEFAULT)) != 0) {
|
|
Status = STATUS_INVALID_PARAMETER_1;
|
|
goto Exit;
|
|
}
|
|
|
|
if (ActivationBlock == NULL) {
|
|
Status = STATUS_INVALID_PARAMETER_4;
|
|
goto Exit;
|
|
}
|
|
|
|
Status =
|
|
RtlQueryInformationActivationContext(
|
|
RTL_QUERY_INFORMATION_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT,
|
|
NULL,
|
|
0,
|
|
ActivationContextBasicInformation,
|
|
&acbi,
|
|
sizeof(acbi),
|
|
NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_LEVEL_STATUS(Status), "SXS: %s - Failure getting active activation context; ntstatus %08lx\n", __FUNCTION__, Status);
|
|
goto Exit;
|
|
}
|
|
|
|
if (acbi.Flags & ACTIVATION_CONTEXT_FLAG_NO_INHERIT) {
|
|
RtlReleaseActivationContext(acbi.ActivationContext);
|
|
acbi.ActivationContext = NULL;
|
|
}
|
|
|
|
// If the activation context is non-NULL or the caller always wants the block allocated
|
|
if (((Flags & BASEP_ALLOCATE_ACTIVATION_CONTEXT_ACTIVATION_BLOCK_FLAG_DO_NOT_ALLOCATE_IF_PROCESS_DEFAULT) == 0) ||
|
|
(acbi.ActivationContext != NULL)) {
|
|
|
|
*ActivationBlock = (PBASE_ACTIVATION_CONTEXT_ACTIVATION_BLOCK) RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG), sizeof(BASE_ACTIVATION_CONTEXT_ACTIVATION_BLOCK));
|
|
if (*ActivationBlock == NULL) {
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Exit;
|
|
}
|
|
|
|
(*ActivationBlock)->Flags = 0;
|
|
(*ActivationBlock)->ActivationContext = acbi.ActivationContext;
|
|
acbi.ActivationContext = NULL; // don't release in exit path...
|
|
|
|
if (Flags & BASEP_ALLOCATE_ACTIVATION_CONTEXT_ACTIVATION_BLOCK_FLAG_DO_NOT_FREE_AFTER_CALLBACK)
|
|
(*ActivationBlock)->Flags |= BASE_ACTIVATION_CONTEXT_ACTIVATION_BLOCK_FLAG_DO_NOT_FREE_AFTER_CALLBACK;
|
|
|
|
(*ActivationBlock)->CallbackFunction = Callback;
|
|
(*ActivationBlock)->CallbackContext = CallbackContext;
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
Exit:
|
|
if (acbi.ActivationContext != NULL)
|
|
RtlReleaseActivationContext(acbi.ActivationContext);
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
BasepFreeActivationContextActivationBlock(
|
|
PBASE_ACTIVATION_CONTEXT_ACTIVATION_BLOCK ActivationBlock
|
|
)
|
|
{
|
|
if (ActivationBlock != NULL) {
|
|
if (ActivationBlock->ActivationContext != NULL) {
|
|
RtlReleaseActivationContext(ActivationBlock->ActivationContext);
|
|
ActivationBlock->ActivationContext = NULL;
|
|
}
|
|
RtlFreeHeap(RtlProcessHeap(), 0, ActivationBlock);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
BasepSxsCloseHandles(
|
|
IN PCBASE_MSG_SXS_HANDLES Handles
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
ASSERT(Handles != NULL);
|
|
|
|
//
|
|
// We are never asked to unmap a section from another process.
|
|
//
|
|
ASSERT(Handles->Process == NULL || Handles->Process == NtCurrentProcess());
|
|
|
|
if (Handles->File != NULL) {
|
|
Status = NtClose(Handles->File);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
}
|
|
if (Handles->Section != NULL) {
|
|
Status = NtClose(Handles->Section);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
}
|
|
if (Handles->ViewBase != 0) {
|
|
Status = NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)(ULONG_PTR)Handles->ViewBase);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
BasepCreateActCtx(
|
|
ULONG Flags,
|
|
IN PCACTCTXW ActParams,
|
|
OUT PVOID* ActivationContextData
|
|
)
|
|
{
|
|
RTL_PATH_TYPE PathType = RtlPathTypeUnknown;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
UCHAR Win32PolicyPathStaticBuffer[MEDIUM_PATH * sizeof(WCHAR)];
|
|
UCHAR NtPolicyPathStaticBuffer[MEDIUM_PATH * sizeof(WCHAR)];
|
|
UNICODE_STRING Win32ManifestPath;
|
|
UNICODE_STRING NtManifestPath;
|
|
CONST SXS_CONSTANT_WIN32_NT_PATH_PAIR ManifestPathPair = { &Win32ManifestPath, &NtManifestPath };
|
|
RTL_UNICODE_STRING_BUFFER Win32PolicyPath;
|
|
RTL_UNICODE_STRING_BUFFER NtPolicyPath;
|
|
CONST SXS_CONSTANT_WIN32_NT_PATH_PAIR PolicyPathPair = { &Win32PolicyPath.String, &NtPolicyPath.String };
|
|
USHORT RemoveManifestExtensionFromPolicy = 0;
|
|
BASE_SXS_CREATE_ACTIVATION_CONTEXT_MSG Message;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
UNICODE_STRING PolicyPathPieces[3];
|
|
WCHAR PolicyManifestResourceId[sizeof(".65535\0")];
|
|
BOOL IsImage = FALSE;
|
|
BOOL IsExe = FALSE;
|
|
PIMAGE_NT_HEADERS ImageNtHeader = NULL;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
SIZE_T ViewSize = 0;
|
|
PBASE_MSG_SXS_HANDLES ManifestFileHandles = NULL;
|
|
PBASE_MSG_SXS_HANDLES ManifestImageHandles = NULL;
|
|
BASE_MSG_SXS_HANDLES ManifestHandles = { 0 };
|
|
BASE_MSG_SXS_HANDLES ManifestHandles2 = { 0 };
|
|
BASE_MSG_SXS_HANDLES PolicyHandles = { 0 };
|
|
BOOL CloseManifestImageHandles = TRUE;
|
|
PCWSTR ManifestExtension = NULL;
|
|
ULONG LdrCreateOutOfProcessImageFlags = 0;
|
|
UCHAR Win32ManifestAdminOverridePathStaticBuffer[MEDIUM_PATH * sizeof(WCHAR)];
|
|
UCHAR NtManifestAdminOverridePathStaticBuffer[MEDIUM_PATH * sizeof(WCHAR)];
|
|
RTL_UNICODE_STRING_BUFFER Win32ManifestAdminOverridePath;
|
|
RTL_UNICODE_STRING_BUFFER NtManifestAdminOverridePath;
|
|
UNICODE_STRING ManifestAdminOverridePathPieces[3];
|
|
CONST SXS_CONSTANT_WIN32_NT_PATH_PAIR ManifestAdminOverridePathPair =
|
|
{ &Win32ManifestAdminOverridePath.String, &NtManifestAdminOverridePath.String };
|
|
BOOL PassFilePair = FALSE;
|
|
PCSXS_CONSTANT_WIN32_NT_PATH_PAIR FilePairToPass = NULL;
|
|
ULONG BasepSxsCreateStreamsFlags = 0;
|
|
ULONG RtlImageNtHeaderExFlags = 0;
|
|
|
|
#if DBG
|
|
if (DebugFilter_SxsTrace) {
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() beginning\n", __FUNCTION__);
|
|
}
|
|
|
|
ASSERT(ActParams != NULL);
|
|
ASSERT(ActParams->cbSize == sizeof(*ActParams));
|
|
ASSERT(ActParams->dwFlags & ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID);
|
|
ASSERT(ActParams->dwFlags & ACTCTX_FLAG_LANGID_VALID);
|
|
ASSERT(ActParams->dwFlags & ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID);
|
|
ASSERT(ActivationContextData != NULL);
|
|
ASSERT(*ActivationContextData == NULL);
|
|
#endif
|
|
|
|
RtlZeroMemory(&Message, sizeof(Message));
|
|
RtlInitUnicodeStringBuffer(&Win32PolicyPath, Win32PolicyPathStaticBuffer, sizeof(Win32PolicyPathStaticBuffer));
|
|
RtlInitUnicodeStringBuffer(&NtPolicyPath, NtPolicyPathStaticBuffer, sizeof(NtPolicyPathStaticBuffer));
|
|
RtlInitUnicodeStringBuffer(&Win32ManifestAdminOverridePath, Win32ManifestAdminOverridePathStaticBuffer, sizeof(Win32ManifestAdminOverridePathStaticBuffer));
|
|
RtlInitUnicodeStringBuffer(&NtManifestAdminOverridePath, NtManifestAdminOverridePathStaticBuffer, sizeof(NtManifestAdminOverridePathStaticBuffer));
|
|
NtManifestPath.Buffer = NULL;
|
|
|
|
Message.ProcessorArchitecture = ActParams->wProcessorArchitecture;
|
|
Message.LangId = ActParams->wLangId;
|
|
RtlInitUnicodeString(&Message.AssemblyDirectory, RTL_CONST_CAST(PWSTR)(ActParams->lpAssemblyDirectory));
|
|
if (Message.AssemblyDirectory.Length != 0) {
|
|
ASSERT(RTL_STRING_IS_NUL_TERMINATED(&Message.AssemblyDirectory));
|
|
if (!RTL_STRING_IS_NUL_TERMINATED(&Message.AssemblyDirectory)) {
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "SXS: %s() AssemblyDirectory is not null terminated\n", __FUNCTION__);
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if (ActParams->lpSource == NULL || ActParams->lpSource[0] == 0) {
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "SXS: %s() empty lpSource %ls\n", __FUNCTION__, ActParams->lpSource);
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
if ((ActParams->dwFlags & ACTCTX_FLAG_SOURCE_IS_ASSEMBLYREF) != 0) {
|
|
Message.Flags = BASE_MSG_SXS_SYSTEM_DEFAULT_TEXTUAL_ASSEMBLY_IDENTITY_PRESENT;
|
|
RtlInitUnicodeString(&Message.TextualAssemblyIdentity, ActParams->lpSource);
|
|
// no streams, no handles, no manifest
|
|
// no policy, no last modified time
|
|
// no paths
|
|
goto CsrMessageFilledIn;
|
|
}
|
|
|
|
RtlInitUnicodeString(&Win32ManifestPath, ActParams->lpSource);
|
|
PathType = RtlDetermineDosPathNameType_U(ActParams->lpSource);
|
|
if (!RtlDosPathNameToNtPathName_U(
|
|
Win32ManifestPath.Buffer,
|
|
&NtManifestPath,
|
|
NULL,
|
|
NULL)) {
|
|
//
|
|
// NTRAID#NTBUG9-147881-2000/7/21-a-JayK errors mutated into bools in ntdll
|
|
//
|
|
Status = STATUS_OBJECT_PATH_NOT_FOUND;
|
|
goto Exit;
|
|
}
|
|
|
|
// If there's an explicitly set HMODULE, we need to verify that the HMODULE came from the lpSource
|
|
// specified and then we can avoid opening/mapping the file.
|
|
if (ActParams->dwFlags & ACTCTX_FLAG_HMODULE_VALID) {
|
|
ManifestHandles.File = NULL;
|
|
ManifestHandles.Section = NULL;
|
|
ManifestHandles.ViewBase = (ULONG_PTR)ActParams->hModule;
|
|
|
|
RtlImageNtHeaderExFlags |= RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK;
|
|
|
|
if (LDR_IS_DATAFILE(ActParams->hModule))
|
|
LdrCreateOutOfProcessImageFlags = LDR_DLL_MAPPED_AS_DATA;
|
|
else
|
|
LdrCreateOutOfProcessImageFlags = LDR_DLL_MAPPED_AS_IMAGE;
|
|
|
|
// Don't try to close the handles or unmap the view on exit of this function...
|
|
CloseManifestImageHandles = FALSE;
|
|
} else {
|
|
InitializeObjectAttributes(
|
|
&Obja,
|
|
&NtManifestPath,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status =
|
|
NtOpenFile(
|
|
&ManifestHandles.File,
|
|
FILE_GENERIC_READ | FILE_EXECUTE,
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ,
|
|
FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
if (DPFLTR_LEVEL_STATUS(Status) == DPFLTR_ERROR_LEVEL) {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_LEVEL_STATUS(Status),
|
|
"SXS: %s() NtOpenFile(%wZ) failed\n",
|
|
__FUNCTION__,
|
|
Obja.ObjectName
|
|
);
|
|
}
|
|
goto Exit;
|
|
}
|
|
#if DBG
|
|
if (DebugFilter_SxsTrace) {
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() NtOpenFile(%wZ) succeeded\n", __FUNCTION__, Obja.ObjectName);
|
|
}
|
|
#endif
|
|
Status =
|
|
NtCreateSection(
|
|
&ManifestHandles.Section,
|
|
SECTION_MAP_READ,
|
|
NULL, // ObjectAttributes
|
|
NULL, // MaximumSize (whole file)
|
|
PAGE_READONLY, // SectionPageProtection
|
|
SEC_COMMIT, // AllocationAttributes
|
|
ManifestHandles.File
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_LEVEL_STATUS(Status), "SXS: %s() NtCreateSection() failed\n", __FUNCTION__);
|
|
goto Exit;
|
|
}
|
|
#if DBG
|
|
if (DebugFilter_SxsTrace) {
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() NtCreateSection() succeeded\n", __FUNCTION__);
|
|
}
|
|
#endif
|
|
{
|
|
PVOID ViewBase = 0;
|
|
|
|
Status =
|
|
NtMapViewOfSection(
|
|
ManifestHandles.Section,
|
|
NtCurrentProcess(),
|
|
&ViewBase,
|
|
0, // ZeroBits,
|
|
0, // CommitSize,
|
|
NULL, // SectionOffset,
|
|
&ViewSize, // ViewSize,
|
|
ViewShare, // InheritDisposition,
|
|
0, // AllocationType,
|
|
PAGE_READONLY // Protect
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_LEVEL_STATUS(Status), "SXS: %s() NtMapViewOfSection failed\n", __FUNCTION__);
|
|
goto Exit;
|
|
}
|
|
ManifestHandles.ViewBase = (ULONG_PTR)ViewBase;
|
|
}
|
|
|
|
LdrCreateOutOfProcessImageFlags = LDR_DLL_MAPPED_AS_DATA;
|
|
}
|
|
|
|
Status = RtlImageNtHeaderEx(RtlImageNtHeaderExFlags, LDR_DATAFILE_TO_VIEW(ManifestHandles.ViewBase), ViewSize, &ImageNtHeader);
|
|
if (NT_SUCCESS(Status)) {
|
|
IsImage = TRUE;
|
|
ASSERT(ImageNtHeader != NULL);
|
|
} else if (Status != STATUS_INVALID_IMAGE_FORMAT) {
|
|
goto Exit;
|
|
} else {
|
|
IsImage = FALSE;
|
|
}
|
|
if (IsImage) {
|
|
IsExe = ((ImageNtHeader->FileHeader.Characteristics & IMAGE_FILE_DLL) == 0);
|
|
ManifestImageHandles = &ManifestHandles;
|
|
ManifestFileHandles = &ManifestHandles2;
|
|
} else {
|
|
IsExe = FALSE;
|
|
ManifestFileHandles = &ManifestHandles;
|
|
ManifestImageHandles = NULL;
|
|
}
|
|
|
|
// See if someone's trying to load a resource from something that is not an EXE
|
|
if ((!IsImage) && (ActParams->lpResourceName != NULL)) {
|
|
// Yup...
|
|
Status = STATUS_INVALID_IMAGE_FORMAT;
|
|
goto Exit;
|
|
}
|
|
// or if an exe but no resource (and none found by probing earlier)
|
|
else if (IsImage && (ActParams->dwFlags & ACTCTX_FLAG_RESOURCE_NAME_VALID) == 0) {
|
|
Status = STATUS_RESOURCE_TYPE_NOT_FOUND;
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// form up the policy path
|
|
// foo.manifest => foo.policy
|
|
// foo.dll, resourceid == n, resourceid != 1 => foo.dll.n.policy
|
|
// foo.dll, resourceid == 1 => foo.dll.policy
|
|
// foo.dll, resourceid == "bar" => foo.dll.bar.policy
|
|
//
|
|
PolicyPathPieces[0] = Win32ManifestPath;
|
|
|
|
PolicyPathPieces[1].Length = 0;
|
|
PolicyPathPieces[1].MaximumLength = 0;
|
|
PolicyPathPieces[1].Buffer = NULL;
|
|
if (ActParams->dwFlags & ACTCTX_FLAG_RESOURCE_NAME_VALID) {
|
|
if (IS_INTRESOURCE(ActParams->lpResourceName)) {
|
|
if (ActParams->lpResourceName != MAKEINTRESOURCEW(CREATEPROCESS_MANIFEST_RESOURCE_ID)) {
|
|
PolicyPathPieces[1].Length = (USHORT) (_snwprintf(PolicyManifestResourceId, RTL_NUMBER_OF(PolicyManifestResourceId) - 1, L".%lu", (ULONG)(ULONG_PTR)ActParams->lpResourceName) * sizeof(WCHAR));
|
|
PolicyManifestResourceId[RTL_NUMBER_OF(PolicyManifestResourceId) - 1] = 0;
|
|
ASSERT(PolicyPathPieces[1].Length < sizeof(PolicyManifestResourceId));
|
|
PolicyPathPieces[1].MaximumLength = sizeof(PolicyManifestResourceId);
|
|
PolicyPathPieces[1].Buffer = PolicyManifestResourceId;
|
|
}
|
|
} else {
|
|
RtlInitUnicodeString(&PolicyPathPieces[1], ActParams->lpResourceName);
|
|
}
|
|
}
|
|
PolicyPathPieces[2] = SxsPolicySuffix;
|
|
ManifestExtension = wcsrchr(Win32ManifestPath.Buffer, L'.');
|
|
if (ManifestExtension != NULL && _wcsicmp(ManifestExtension, SxsManifestSuffix.Buffer) == 0) {
|
|
RemoveManifestExtensionFromPolicy = SxsManifestSuffix.Length;
|
|
PolicyPathPieces[0].Length -= RemoveManifestExtensionFromPolicy;
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status = RtlMultiAppendUnicodeStringBuffer(&Win32PolicyPath, RTL_NUMBER_OF(PolicyPathPieces), PolicyPathPieces))) {
|
|
goto Exit;
|
|
}
|
|
PolicyPathPieces[0] = NtManifestPath;
|
|
PolicyPathPieces[0].Length -= RemoveManifestExtensionFromPolicy;
|
|
if (!NT_SUCCESS(Status = RtlMultiAppendUnicodeStringBuffer(&NtPolicyPath, RTL_NUMBER_OF(PolicyPathPieces), PolicyPathPieces))) {
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// form up the path to the administrative override file for manifests in resources
|
|
//
|
|
// not an image => no override
|
|
// manifest=foo.dll, resourceid=n, n != 1 => foo.dll.n.manifest
|
|
// manifest=foo.dll, resourceid=n, n == 1 => foo.dll.manifest
|
|
//
|
|
// the second to last element is the same as for the policy file
|
|
//
|
|
if (IsImage) {
|
|
ManifestAdminOverridePathPieces[0] = Win32ManifestPath;
|
|
ManifestAdminOverridePathPieces[1] = PolicyPathPieces[1];
|
|
ManifestAdminOverridePathPieces[2] = SxsManifestSuffix;
|
|
if (!NT_SUCCESS(Status = RtlMultiAppendUnicodeStringBuffer(
|
|
&Win32ManifestAdminOverridePath,
|
|
RTL_NUMBER_OF(ManifestAdminOverridePathPieces),
|
|
ManifestAdminOverridePathPieces))
|
|
) {
|
|
goto Exit;
|
|
}
|
|
ManifestAdminOverridePathPieces[0] = NtManifestPath;
|
|
if (!NT_SUCCESS(Status = RtlMultiAppendUnicodeStringBuffer(
|
|
&NtManifestAdminOverridePath,
|
|
RTL_NUMBER_OF(ManifestAdminOverridePathPieces),
|
|
ManifestAdminOverridePathPieces))
|
|
) {
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Message.ActivationContextData = ActivationContextData;
|
|
ManifestHandles.Process = NtCurrentProcess();
|
|
|
|
#if DBG
|
|
if (DebugFilter_SxsTrace) {
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s: Win32ManifestPath: \"%wZ\"\n", __FUNCTION__, &Win32ManifestPath);
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s: NtManifestPath: \"%wZ\"\n", __FUNCTION__, &NtManifestPath);
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s: Win32ManifestAdminPath: \"%wZ\"\n", __FUNCTION__, &Win32ManifestAdminOverridePath);
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s: NtManifestAdminPath: \"%wZ\"\n", __FUNCTION__, &NtManifestAdminOverridePath);
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s: Win32PolicyPath: \"%wZ\"\n", __FUNCTION__, &Win32PolicyPath);
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s: Nt32PolicyPath: \"%wZ\"\n", __FUNCTION__, &NtPolicyPath);
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s: ManifestHandles.Process: %p\n", __FUNCTION__, ManifestHandles.Process);
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s: ManifestHandles.File: %p\n", __FUNCTION__, ManifestHandles.File);
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s: ManifestHandles.Section: %p\n", __FUNCTION__, ManifestHandles.Section);
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s: ManifestHandles.ViewBase: 0x%I64x\n", __FUNCTION__, ManifestHandles.ViewBase);
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s: IsImage: %lu\n", __FUNCTION__, (ULONG) IsImage);
|
|
}
|
|
#endif
|
|
|
|
PassFilePair = (!IsImage || (Flags & BASEP_CREATE_ACTCTX_FLAG_NO_ADMIN_OVERRIDE) == 0);
|
|
FilePairToPass = IsImage ? &ManifestAdminOverridePathPair : &ManifestPathPair;
|
|
|
|
Status =
|
|
BasepSxsCreateStreams(
|
|
BasepSxsCreateStreamsFlags,
|
|
LdrCreateOutOfProcessImageFlags,
|
|
FILE_GENERIC_READ | FILE_EXECUTE, // AccessMask,
|
|
NULL, // override manifest
|
|
NULL, // override policy
|
|
PassFilePair ? FilePairToPass : NULL,
|
|
ManifestFileHandles,
|
|
IsImage ? &ManifestPathPair : NULL,
|
|
ManifestImageHandles,
|
|
(ULONG_PTR)(ActParams->lpResourceName),
|
|
&PolicyPathPair,
|
|
&PolicyHandles,
|
|
&Message.Flags,
|
|
&Message.Manifest,
|
|
&Message.Policy
|
|
);
|
|
CsrMessageFilledIn:
|
|
if (Message.Flags == 0) {
|
|
ASSERT(!NT_SUCCESS(Status));
|
|
//
|
|
// BasepSxsCreateStreams doesn't DbgPrint for the file not found, but
|
|
// we want to.
|
|
//
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_LEVEL_STATUS(Status),
|
|
"SXS: %s() BasepSxsCreateStreams() failed\n",
|
|
__FUNCTION__
|
|
);
|
|
goto Exit;
|
|
}
|
|
ASSERT(Message.Flags & (BASE_MSG_SXS_MANIFEST_PRESENT | BASE_MSG_SXS_TEXTUAL_ASSEMBLY_IDENTITY_PRESENT));
|
|
|
|
//
|
|
// file not found for .policy is ok
|
|
//
|
|
if (((Message.Flags & BASE_MSG_SXS_POLICY_PRESENT) == 0) &&
|
|
BasepSxsIsStatusFileNotFoundEtc(Status)) {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_LEVEL_STATUS(Status), "SXS: %s() BasepSxsCreateStreams() failed\n", __FUNCTION__);
|
|
goto Exit;
|
|
}
|
|
|
|
// Fly my pretties, fly!
|
|
Status = CsrBasepCreateActCtx( &Message );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
ASSERT(*ActivationContextData == NULL);
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_LEVEL_STATUS(Status), "SXS: %s() Calling csrss server failed\n", __FUNCTION__);
|
|
goto Exit;
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
Exit:
|
|
if (ManifestFileHandles != NULL) {
|
|
BasepSxsCloseHandles(ManifestFileHandles);
|
|
}
|
|
if (ManifestImageHandles != NULL && CloseManifestImageHandles) {
|
|
BasepSxsCloseHandles(ManifestImageHandles);
|
|
}
|
|
BasepSxsCloseHandles(&PolicyHandles);
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, NtManifestPath.Buffer);
|
|
RtlFreeUnicodeStringBuffer(&Win32PolicyPath);
|
|
RtlFreeUnicodeStringBuffer(&NtPolicyPath);
|
|
RtlFreeUnicodeStringBuffer(&Win32ManifestAdminOverridePath);
|
|
RtlFreeUnicodeStringBuffer(&NtManifestAdminOverridePath);
|
|
if (!NT_SUCCESS(Status) && (ActivationContextData != NULL) && (*ActivationContextData != NULL)) {
|
|
NtUnmapViewOfSection(NtCurrentProcess(), *ActivationContextData);
|
|
}
|
|
|
|
#if DBG
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_LEVEL_STATUS(Status),
|
|
"SXS: %s(%ls) exiting 0x%08lx\n",
|
|
__FUNCTION__,
|
|
(ActParams != NULL ? ActParams->lpSource : NULL),
|
|
Status
|
|
);
|
|
#endif
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
BasepSxsCreateResourceStream(
|
|
IN ULONG LdrCreateOutOfProcessImageFlags,
|
|
PCSXS_CONSTANT_WIN32_NT_PATH_PAIR Win32NtPathPair,
|
|
IN OUT PBASE_MSG_SXS_HANDLES Handles,
|
|
IN ULONG_PTR MappedResourceName,
|
|
OUT PBASE_MSG_SXS_STREAM MessageStream
|
|
)
|
|
{
|
|
//
|
|
// Any handles passed in, we do not close.
|
|
// Any handles we open, we close, except the ones passed out in MessageStream.
|
|
//
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
IMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;
|
|
FILE_BASIC_INFORMATION FileBasicInfo;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
LDR_OUT_OF_PROCESS_IMAGE OutOfProcessImage = {0};
|
|
ULONG_PTR ResourcePath[] = { ((ULONG_PTR)RT_MANIFEST), 0, 0 };
|
|
ULONG64 ResourceAddress = 0;
|
|
ULONG ResourceSize = 0;
|
|
|
|
#if DBG
|
|
if (DebugFilter_SxsTrace)
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_TRACE_LEVEL,
|
|
"SXS: %s(%wZ) beginning\n",
|
|
__FUNCTION__,
|
|
(Win32NtPathPair != NULL) ? Win32NtPathPair->Win32 : (PCUNICODE_STRING)NULL
|
|
);
|
|
#endif
|
|
|
|
ASSERT(Handles != NULL);
|
|
ASSERT(Handles->Process != NULL);
|
|
ASSERT(MessageStream != NULL);
|
|
ASSERT(Win32NtPathPair != NULL);
|
|
|
|
// LdrFindCreateProcessManifest currently does not search on id or langid, just type.
|
|
// If you give it a nonzero id, it will only find it if is the first one.
|
|
// Another approach would be to have LdrFindOutOfProcessResource return the id it found.
|
|
ASSERT((MappedResourceName == (ULONG_PTR)CREATEPROCESS_MANIFEST_RESOURCE_ID) || (Handles->Process == NtCurrentProcess()));
|
|
|
|
//
|
|
// We could open any null handles like CreateFileStream does, but we happen to know
|
|
// that our clients open all of them.
|
|
//
|
|
|
|
// CreateActCtx maps the view earlier to determine if it starts MZ.
|
|
// CreateProcess gives us the view from the peb.
|
|
// .policy files are never resources.
|
|
ASSERT(Handles->ViewBase != 0);
|
|
|
|
Status =
|
|
LdrCreateOutOfProcessImage(
|
|
LdrCreateOutOfProcessImageFlags,
|
|
Handles->Process,
|
|
Handles->ViewBase,
|
|
&OutOfProcessImage
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
if (DebugFilter_SxsTrace)
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() LdrCreateOutOfProcessImage failed\n", __FUNCTION__);
|
|
#endif
|
|
goto Exit;
|
|
}
|
|
|
|
ResourcePath[1] = MappedResourceName;
|
|
|
|
Status =
|
|
LdrFindCreateProcessManifest(
|
|
0, // flags
|
|
&OutOfProcessImage,
|
|
ResourcePath,
|
|
RTL_NUMBER_OF(ResourcePath),
|
|
&ResourceDataEntry
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
if (DebugFilter_SxsTrace)
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() LdrFindOutOfProcessResource failed; nt status = %08lx\n", __FUNCTION__, Status);
|
|
#endif
|
|
goto Exit;
|
|
}
|
|
|
|
Status =
|
|
LdrAccessOutOfProcessResource(
|
|
0, // flags
|
|
&OutOfProcessImage,
|
|
&ResourceDataEntry,
|
|
&ResourceAddress,
|
|
&ResourceSize);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
if (DebugFilter_SxsTrace)
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() LdrAccessOutOfProcessResource failed; nt status = %08lx\n", __FUNCTION__, Status);
|
|
#endif
|
|
goto Exit;
|
|
}
|
|
|
|
MessageStream->Handle = Handles->Process;
|
|
MessageStream->FileHandle = Handles->File;
|
|
MessageStream->PathType = BASE_MSG_PATHTYPE_FILE;
|
|
MessageStream->FileType = BASE_MSG_FILETYPE_XML;
|
|
MessageStream->Path = *Win32NtPathPair->Win32; // it will be put in the csr capture buffer later
|
|
MessageStream->HandleType = BASE_MSG_HANDLETYPE_PROCESS;
|
|
MessageStream->Offset = ResourceAddress;
|
|
MessageStream->Size = ResourceSize;
|
|
|
|
#if DBG
|
|
if (DebugFilter_SxsTrace) {
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() ResourceAddress:0x%I64x\n", __FUNCTION__, ResourceAddress);
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() OutOfProcessImage.DllHandle:0x%I64x\n", __FUNCTION__, OutOfProcessImage.DllHandle);
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() MessageStream->Offset:0x%I64x\n", __FUNCTION__, MessageStream->Offset);
|
|
}
|
|
#endif
|
|
|
|
Status = STATUS_SUCCESS;
|
|
Exit:
|
|
LdrDestroyOutOfProcessImage(&OutOfProcessImage);
|
|
#if DBG
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_LEVEL_STATUS(Status),
|
|
"SXS: %s(%wZ) exiting 0x%08lx\n",
|
|
__FUNCTION__,
|
|
(Win32NtPathPair != NULL) ? Win32NtPathPair->Win32 : (PCUNICODE_STRING)NULL,
|
|
Status
|
|
);
|
|
#endif
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
BasepSxsOverrideStreamToMessageStream(
|
|
IN PCSXS_OVERRIDE_STREAM OverrideStream,
|
|
OUT PBASE_MSG_SXS_STREAM MessageStream
|
|
)
|
|
{
|
|
MessageStream->FileType = BASE_MSG_FILETYPE_XML;
|
|
MessageStream->PathType = BASE_MSG_PATHTYPE_OVERRIDE;
|
|
MessageStream->Path = OverrideStream->Name;
|
|
MessageStream->FileHandle = NULL;
|
|
MessageStream->HandleType = BASE_MSG_HANDLETYPE_CLIENT_PROCESS;
|
|
MessageStream->Handle = NULL;
|
|
MessageStream->Offset = (ULONGLONG)OverrideStream->Address;
|
|
MessageStream->Size = OverrideStream->Size;
|
|
}
|
|
|
|
NTSTATUS
|
|
BasepSxsCreateStreams(
|
|
IN ULONG Flags,
|
|
IN ULONG LdrCreateOutOfProcessImageFlags,
|
|
IN ACCESS_MASK AccessMask,
|
|
IN PCSXS_OVERRIDE_STREAM OverrideManifest OPTIONAL,
|
|
IN PCSXS_OVERRIDE_STREAM OverridePolicy OPTIONAL,
|
|
IN PCSXS_CONSTANT_WIN32_NT_PATH_PAIR ManifestFilePathPair,
|
|
IN OUT PBASE_MSG_SXS_HANDLES ManifestFileHandles,
|
|
IN PCSXS_CONSTANT_WIN32_NT_PATH_PAIR ManifestExePathPair,
|
|
IN OUT PBASE_MSG_SXS_HANDLES ManifestExeHandles,
|
|
IN ULONG_PTR MappedManifestResourceName OPTIONAL,
|
|
IN PCSXS_CONSTANT_WIN32_NT_PATH_PAIR PolicyPathPair,
|
|
IN OUT PBASE_MSG_SXS_HANDLES PolicyHandles,
|
|
OUT PULONG MessageFlags,
|
|
OUT PBASE_MSG_SXS_STREAM ManifestMessageStream,
|
|
OUT PBASE_MSG_SXS_STREAM PolicyMessageStream OPTIONAL
|
|
)
|
|
/*
|
|
A mismash of combined code for CreateActCtx and CreateProcess.
|
|
*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
NTSTATUS FirstProbeStatus = STATUS_SUCCESS;
|
|
BOOLEAN LookForPolicy = TRUE;
|
|
|
|
#if DBG
|
|
ASSERT(MessageFlags != NULL);
|
|
ASSERT(ManifestMessageStream != NULL);
|
|
ASSERT((ManifestFilePathPair != NULL) || (ManifestExePathPair != NULL));
|
|
ASSERT((MappedManifestResourceName == 0) || (ManifestExePathPair != NULL));
|
|
ASSERT((PolicyPathPair != NULL) == (PolicyMessageStream != NULL));
|
|
if (ManifestFilePathPair != NULL) {
|
|
ASSERT(ManifestFilePathPair->Win32 != NULL);
|
|
ASSERT(ManifestFilePathPair->Nt != NULL);
|
|
}
|
|
if (ManifestExePathPair != NULL) {
|
|
ASSERT(ManifestExePathPair->Win32 != NULL);
|
|
ASSERT(ManifestExePathPair->Nt != NULL);
|
|
}
|
|
if (PolicyPathPair != NULL) {
|
|
ASSERT(PolicyPathPair->Win32 != NULL);
|
|
ASSERT(PolicyPathPair->Nt != NULL);
|
|
}
|
|
if (OverrideManifest != NULL && OverrideManifest->Size != 0) {
|
|
ASSERT(OverrideManifest->Address != NULL);
|
|
}
|
|
if (OverridePolicy != NULL && OverridePolicy->Size != 0) {
|
|
ASSERT(OverridePolicy->Address != NULL);
|
|
}
|
|
|
|
if (DebugFilter_SxsTrace)
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_TRACE_LEVEL,
|
|
"SXS: %s(ManifestFilePath:%wZ, ManifestExePath:%wZ, PolicyPath:%wZ) beginning\n",
|
|
__FUNCTION__,
|
|
(ManifestFilePathPair != NULL) ? ManifestFilePathPair->Win32 : (PCUNICODE_STRING)NULL,
|
|
(ManifestExePathPair != NULL) ? ManifestExePathPair->Win32 : (PCUNICODE_STRING)NULL,
|
|
(PolicyPathPair != NULL) ? PolicyPathPair->Win32 : (PCUNICODE_STRING)NULL
|
|
);
|
|
#endif
|
|
|
|
if (OverrideManifest != NULL) {
|
|
BasepSxsOverrideStreamToMessageStream(OverrideManifest, ManifestMessageStream);
|
|
Status = STATUS_SUCCESS;
|
|
//
|
|
// When appcompat provides a manifest, do not look for a policy.
|
|
// This let's us fix the Matrix DVD.
|
|
//
|
|
LookForPolicy = FALSE;
|
|
goto ManifestFound;
|
|
}
|
|
|
|
if (ManifestExePathPair != NULL) {
|
|
Status =
|
|
BasepSxsCreateResourceStream(
|
|
LdrCreateOutOfProcessImageFlags,
|
|
ManifestExePathPair,
|
|
ManifestExeHandles,
|
|
MappedManifestResourceName,
|
|
ManifestMessageStream);
|
|
if (NT_SUCCESS(Status)) {
|
|
goto ManifestFound;
|
|
}
|
|
if (!BasepSxsIsStatusResourceNotFound(Status)) {
|
|
goto Exit;
|
|
}
|
|
|
|
FirstProbeStatus = Status;
|
|
}
|
|
|
|
if (ManifestFilePathPair != NULL) {
|
|
Status =
|
|
BasepSxsCreateFileStream(
|
|
AccessMask,
|
|
ManifestFilePathPair,
|
|
ManifestFileHandles,
|
|
ManifestMessageStream);
|
|
if (NT_SUCCESS(Status)) {
|
|
goto ManifestFound;
|
|
}
|
|
if (!BasepSxsIsStatusFileNotFoundEtc(Status)) {
|
|
goto Exit;
|
|
}
|
|
|
|
if (FirstProbeStatus != STATUS_SUCCESS)
|
|
Status = FirstProbeStatus;
|
|
}
|
|
|
|
ASSERT(!NT_SUCCESS(Status)); // otherwise this should be unreachable
|
|
goto Exit;
|
|
ManifestFound:
|
|
// indicate partial success even if policy file not found
|
|
*MessageFlags |= BASE_MSG_SXS_MANIFEST_PRESENT;
|
|
|
|
if (OverridePolicy != NULL) {
|
|
BasepSxsOverrideStreamToMessageStream(OverridePolicy, PolicyMessageStream);
|
|
*MessageFlags |= BASE_MSG_SXS_POLICY_PRESENT;
|
|
Status = STATUS_SUCCESS;
|
|
} else if (LookForPolicy && PolicyPathPair != NULL) {
|
|
Status = BasepSxsCreateFileStream(AccessMask, PolicyPathPair, PolicyHandles, PolicyMessageStream);
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Exit; // our caller knows this is not necessarily fatal
|
|
}
|
|
*MessageFlags |= BASE_MSG_SXS_POLICY_PRESENT;
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
Exit:
|
|
#if DBG
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_LEVEL_STATUS(Status),
|
|
"SXS: %s(MessageFlags=%lu) exiting 0x%08lx\n",
|
|
__FUNCTION__,
|
|
*MessageFlags,
|
|
Status);
|
|
#endif // DBG
|
|
|
|
return Status;
|
|
}
|
|
|
|
BOOL
|
|
BasepSxsIsStatusFileNotFoundEtc(
|
|
NTSTATUS Status
|
|
)
|
|
{
|
|
DWORD Error;
|
|
if (NT_SUCCESS(Status)) {
|
|
return FALSE;
|
|
}
|
|
|
|
// First check the most obvious sounding, probably the most common.
|
|
if (
|
|
Status == STATUS_OBJECT_PATH_NOT_FOUND
|
|
|| Status == STATUS_OBJECT_NAME_NOT_FOUND
|
|
|| Status == STATUS_NO_SUCH_FILE
|
|
)
|
|
{
|
|
return TRUE;
|
|
}
|
|
// Then get the eight or so less obvious ones by their mapping
|
|
// to the two obvious Win32 values and the two inobvious Win32 values.
|
|
Error = RtlNtStatusToDosErrorNoTeb(Status);
|
|
// REVIEW
|
|
// STATUS_PATH_NOT_COVERED, ERROR_HOST_UNREACHABLE,
|
|
if ( Error == ERROR_FILE_NOT_FOUND
|
|
|| Error == ERROR_PATH_NOT_FOUND
|
|
|| Error == ERROR_BAD_NETPATH // \\a\b
|
|
|| Error == ERROR_BAD_NET_NAME // \\a-jayk2\b
|
|
)
|
|
{
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
BasepSxsIsStatusResourceNotFound(
|
|
NTSTATUS Status
|
|
)
|
|
{
|
|
if (NT_SUCCESS(Status))
|
|
return FALSE;
|
|
if (
|
|
Status == STATUS_RESOURCE_DATA_NOT_FOUND
|
|
|| Status == STATUS_RESOURCE_TYPE_NOT_FOUND
|
|
|| Status == STATUS_RESOURCE_NAME_NOT_FOUND
|
|
|| Status == STATUS_RESOURCE_LANG_NOT_FOUND
|
|
)
|
|
{
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
#if defined(BUILD_WOW6432)
|
|
#define BasepSxsNativeQueryInformationProcess NtWow64QueryInformationProcess64
|
|
#define BasepSxsNativeReadVirtualMemory NtWow64ReadVirtualMemory64
|
|
#else
|
|
#define BasepSxsNativeQueryInformationProcess NtQueryInformationProcess
|
|
#define BasepSxsNativeReadVirtualMemory NtReadVirtualMemory
|
|
#endif
|
|
|
|
NTSTATUS
|
|
BasepSxsGetProcessImageBaseAddress(
|
|
PBASE_MSG_SXS_HANDLES Handles
|
|
)
|
|
{
|
|
NATIVE_PROCESS_BASIC_INFORMATION ProcessBasicInfo;
|
|
NATIVE_ULONG_PTR ViewBase;
|
|
C_ASSERT(RTL_FIELD_SIZE(NATIVE_PEB, ImageBaseAddress) == sizeof(ViewBase));
|
|
NTSTATUS Status;
|
|
|
|
Status =
|
|
BasepSxsNativeQueryInformationProcess(
|
|
Handles->Process,
|
|
ProcessBasicInformation,
|
|
&ProcessBasicInfo,
|
|
sizeof(ProcessBasicInfo),
|
|
NULL
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Exit;
|
|
}
|
|
//
|
|
// Wow6432 could save a syscall in CreateProcess by passing
|
|
// ProcessBasicInfo.PebBaseAddress out to a->RealPeb in CreateProcessInternal.
|
|
//
|
|
Status =
|
|
BasepSxsNativeReadVirtualMemory(
|
|
Handles->Process,
|
|
(NATIVE_PVOID)(((NATIVE_ULONG_PTR)ProcessBasicInfo.PebBaseAddress) + FIELD_OFFSET(NATIVE_PEB, ImageBaseAddress)),
|
|
&ViewBase,
|
|
sizeof(ViewBase),
|
|
NULL
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Exit;
|
|
}
|
|
Handles->ViewBase = ViewBase;
|
|
Status = STATUS_SUCCESS;
|
|
Exit:
|
|
return Status;
|
|
}
|
|
|
|
extern const SXS_OVERRIDE_STREAM SxsForceEmptyPolicy =
|
|
{
|
|
RTL_CONSTANT_STRING(L"SxsForceEmptyPolicy"),
|
|
NULL,
|
|
0
|
|
};
|
|
|
|
NTSTATUS
|
|
BasepSxsCreateProcessCsrMessage(
|
|
IN PCSXS_OVERRIDE_STREAM OverrideManifest OPTIONAL,
|
|
IN PCSXS_OVERRIDE_STREAM OverridePolicy OPTIONAL,
|
|
IN OUT PCSXS_WIN32_NT_PATH_PAIR ManifestPathPair,
|
|
IN OUT PBASE_MSG_SXS_HANDLES ManifestFileHandles,
|
|
IN PCSXS_CONSTANT_WIN32_NT_PATH_PAIR ExePathPair,
|
|
IN OUT PBASE_MSG_SXS_HANDLES ManifestExeHandles,
|
|
IN OUT PCSXS_WIN32_NT_PATH_PAIR PolicyPathPair,
|
|
IN OUT PBASE_MSG_SXS_HANDLES PolicyHandles,
|
|
IN OUT PRTL_UNICODE_STRING_BUFFER Win32AssemblyDirectoryBuffer,
|
|
OUT PBASE_SXS_CREATEPROCESS_MSG Message
|
|
)
|
|
{
|
|
UNICODE_STRING PathPieces[2];
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
CONST SXS_CONSTANT_WIN32_NT_PATH_PAIR ConstantManifestPathPair =
|
|
{ &ManifestPathPair->Win32->String, &ManifestPathPair->Nt->String };
|
|
|
|
CONST SXS_CONSTANT_WIN32_NT_PATH_PAIR ConstantPolicyPathPair =
|
|
{ &PolicyPathPair->Win32->String, &PolicyPathPair->Nt->String };
|
|
|
|
#if DBG
|
|
DebugFilter_SxsTrace = (NtQueryDebugFilterState(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL) == TRUE);
|
|
|
|
//
|
|
// assertions are anded to avoid access violating
|
|
//
|
|
ASSERT(ExePathPair != NULL
|
|
&& ExePathPair->Win32 != NULL
|
|
&& NT_SUCCESS(RtlValidateUnicodeString(0, ExePathPair->Win32))
|
|
&& (ExePathPair->Win32->Buffer[1] == '\\'
|
|
|| ExePathPair->Win32->Buffer[1] == ':')
|
|
&& ExePathPair->Nt != NULL
|
|
&& ExePathPair->Nt->Buffer[0] == '\\'
|
|
&& NT_SUCCESS(RtlValidateUnicodeString(0, ExePathPair->Nt)));
|
|
ASSERT(ManifestPathPair != NULL
|
|
&& ManifestPathPair->Win32 != NULL
|
|
&& NT_SUCCESS(RtlValidateUnicodeString(0, &ManifestPathPair->Win32->String))
|
|
&& ManifestPathPair->Nt != NULL
|
|
&& NT_SUCCESS(RtlValidateUnicodeString(0, &ManifestPathPair->Nt->String)));
|
|
ASSERT(PolicyPathPair != NULL
|
|
&& PolicyPathPair->Win32 != NULL
|
|
&& NT_SUCCESS(RtlValidateUnicodeString(0, &PolicyPathPair->Win32->String))
|
|
&& PolicyPathPair->Nt != NULL
|
|
&& NT_SUCCESS(RtlValidateUnicodeString(0, &PolicyPathPair->Nt->String)));
|
|
ASSERT(Win32AssemblyDirectoryBuffer != NULL
|
|
&& NT_SUCCESS(RtlValidateUnicodeString(0, &Win32AssemblyDirectoryBuffer->String)));
|
|
ASSERT(ManifestExeHandles != NULL
|
|
&& ManifestExeHandles->Process != NULL
|
|
&& ManifestExeHandles->ViewBase == 0);
|
|
ASSERT(Message != NULL);
|
|
if (DebugFilter_SxsTrace) {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_TRACE_LEVEL,
|
|
"SXS: %s(%wZ) beginning\n",
|
|
__FUNCTION__,
|
|
(ExePathPair != NULL) ? ExePathPair->Win32 : (PCUNICODE_STRING)NULL
|
|
);
|
|
}
|
|
#endif
|
|
|
|
// C_ASSERT didn't work.
|
|
ASSERT(BASE_MSG_FILETYPE_NONE == 0);
|
|
ASSERT(BASE_MSG_PATHTYPE_NONE == 0);
|
|
RtlZeroMemory(Message, sizeof(*Message));
|
|
|
|
Status = BasepSxsGetProcessImageBaseAddress(ManifestExeHandles);
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// form up foo.exe.manifest and foo.exe.policy, nt and win32 flavors
|
|
//
|
|
PathPieces[0] = *ExePathPair->Win32;
|
|
PathPieces[1] = SxsManifestSuffix;
|
|
if (!NT_SUCCESS(Status = RtlMultiAppendUnicodeStringBuffer(ManifestPathPair->Win32, 2, PathPieces)))
|
|
goto Exit;
|
|
PathPieces[1] = SxsPolicySuffix;
|
|
if (!NT_SUCCESS(Status = RtlMultiAppendUnicodeStringBuffer(PolicyPathPair->Win32, 2, PathPieces)))
|
|
goto Exit;
|
|
PathPieces[0] = *ExePathPair->Nt;
|
|
PathPieces[1] = SxsManifestSuffix;
|
|
if (!NT_SUCCESS(Status = RtlMultiAppendUnicodeStringBuffer(ManifestPathPair->Nt, 2, PathPieces)))
|
|
goto Exit;
|
|
PathPieces[1] = SxsPolicySuffix;
|
|
if (!NT_SUCCESS(Status = RtlMultiAppendUnicodeStringBuffer(PolicyPathPair->Nt, 2, PathPieces)))
|
|
goto Exit;
|
|
|
|
Status =
|
|
BasepSxsCreateStreams(
|
|
0,
|
|
LDR_DLL_MAPPED_AS_UNFORMATED_IMAGE, // LdrCreateOutOfProcessImageFlags
|
|
FILE_GENERIC_READ | FILE_EXECUTE,
|
|
OverrideManifest,
|
|
OverridePolicy,
|
|
&ConstantManifestPathPair,
|
|
ManifestFileHandles,
|
|
ExePathPair,
|
|
ManifestExeHandles,
|
|
(ULONG_PTR)CREATEPROCESS_MANIFEST_RESOURCE_ID,
|
|
&ConstantPolicyPathPair,
|
|
PolicyHandles,
|
|
&Message->Flags,
|
|
&Message->Manifest,
|
|
&Message->Policy
|
|
);
|
|
|
|
//
|
|
// did we find manifest and policy
|
|
// it's ok to find neither but if either then always manifest
|
|
//
|
|
if (BasepSxsIsStatusFileNotFoundEtc(Status)
|
|
|| BasepSxsIsStatusResourceNotFound(Status)) {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Exit;
|
|
}
|
|
if (Message->Flags == 0) {
|
|
Status = STATUS_SUCCESS;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Set the assembly directory. Use a copy to not violate const.
|
|
// We can't just shorten the path because basesrv expects the string to be nul
|
|
// terminated, and better to meet that expection here than there.
|
|
//
|
|
Status = RtlAssignUnicodeStringBuffer(Win32AssemblyDirectoryBuffer, ExePathPair->Win32);
|
|
if (!NT_SUCCESS(Status))
|
|
goto Exit;
|
|
Status = RtlRemoveLastFullDosOrNtPathElement(0, Win32AssemblyDirectoryBuffer);
|
|
if (!NT_SUCCESS(Status))
|
|
goto Exit;
|
|
RTL_NUL_TERMINATE_STRING(&Win32AssemblyDirectoryBuffer->String);
|
|
Message->AssemblyDirectory = Win32AssemblyDirectoryBuffer->String;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
Exit:
|
|
|
|
#if DBG
|
|
if (DebugFilter_SxsTrace) {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_TRACE_LEVEL,
|
|
"SXS: %s() Message {\n"
|
|
"SXS: Flags:(%s | %s | %s)\n"
|
|
"SXS: }\n",
|
|
__FUNCTION__,
|
|
(Message->Flags & BASE_MSG_SXS_MANIFEST_PRESENT) ? "MANIFEST_PRESENT" : "0",
|
|
(Message->Flags & BASE_MSG_SXS_POLICY_PRESENT) ? "POLICY_PRESENT" : "0",
|
|
(Message->Flags & BASE_MSG_SXS_TEXTUAL_ASSEMBLY_IDENTITY_PRESENT) ? "TEXTUAL_ASSEMBLY_IDENTITY_PRESENT" : "0"
|
|
);
|
|
if (Message->Flags & BASE_MSG_SXS_MANIFEST_PRESENT) {
|
|
BasepSxsDbgPrintMessageStream(__FUNCTION__, "Manifest", &Message->Manifest);
|
|
}
|
|
if (Message->Flags & BASE_MSG_SXS_POLICY_PRESENT) {
|
|
BasepSxsDbgPrintMessageStream(__FUNCTION__, "Policy", &Message->Policy);
|
|
}
|
|
//
|
|
// CreateProcess does not support textual identities.
|
|
//
|
|
ASSERT((Message->Flags & BASE_MSG_SXS_TEXTUAL_ASSEMBLY_IDENTITY_PRESENT) == 0);
|
|
}
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_LEVEL_STATUS(Status),
|
|
"SXS: %s(%wZ) exiting 0x%08lx\n",
|
|
__FUNCTION__,
|
|
(ExePathPair != NULL) ? ExePathPair->Win32 : (PCUNICODE_STRING)NULL,
|
|
Status
|
|
);
|
|
#endif
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
BasepSxsCreateFileStream(
|
|
IN ACCESS_MASK AccessMask,
|
|
PCSXS_CONSTANT_WIN32_NT_PATH_PAIR Win32NtPathPair,
|
|
IN OUT PBASE_MSG_SXS_HANDLES Handles,
|
|
PBASE_MSG_SXS_STREAM MessageStream
|
|
)
|
|
{
|
|
OBJECT_ATTRIBUTES Obja;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
NTSTATUS Status1 = STATUS_SUCCESS;
|
|
FILE_STANDARD_INFORMATION FileBasicInformation;
|
|
|
|
#if DBG
|
|
DebugFilter_SxsTrace = (NtQueryDebugFilterState(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL) == TRUE);
|
|
|
|
ASSERT(Win32NtPathPair != NULL);
|
|
if (Win32NtPathPair != NULL) {
|
|
ASSERT(Win32NtPathPair->Win32 != NULL);
|
|
ASSERT(Win32NtPathPair->Nt != NULL);
|
|
}
|
|
ASSERT(MessageStream != NULL);
|
|
if (DebugFilter_SxsTrace) {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_TRACE_LEVEL,
|
|
"SXS: %s(Path:%wZ, Handles:%p(Process:%p, File:%p, Section:%p), MessageStream:%p) beginning\n",
|
|
__FUNCTION__,
|
|
(Win32NtPathPair != NULL) ? Win32NtPathPair->Win32 : (PCUNICODE_STRING)NULL,
|
|
Handles,
|
|
(Handles != NULL) ? Handles->Process : NULL,
|
|
(Handles != NULL) ? Handles->File : NULL,
|
|
(Handles != NULL) ? Handles->Section : NULL,
|
|
MessageStream
|
|
);
|
|
}
|
|
#endif
|
|
|
|
if (Handles->File == NULL) {
|
|
|
|
CONST PCUNICODE_STRING NtPath = Win32NtPathPair->Nt;
|
|
|
|
InitializeObjectAttributes(
|
|
&Obja,
|
|
RTL_CONST_CAST(PUNICODE_STRING)(NtPath),
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status =
|
|
NtOpenFile(
|
|
&Handles->File,
|
|
AccessMask,
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ,
|
|
FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
if (DPFLTR_LEVEL_STATUS(Status) == DPFLTR_ERROR_LEVEL) {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_LEVEL_STATUS(Status),
|
|
"SXS: %s() NtOpenFile(%wZ) failed\n",
|
|
__FUNCTION__,
|
|
Obja.ObjectName
|
|
);
|
|
}
|
|
goto Exit;
|
|
}
|
|
#if DBG
|
|
if (DebugFilter_SxsTrace) {
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() NtOpenFile(%wZ) succeeded\n", __FUNCTION__, Obja.ObjectName);
|
|
}
|
|
#endif
|
|
}
|
|
if (Handles->Section == NULL) {
|
|
Status =
|
|
NtCreateSection(
|
|
&Handles->Section,
|
|
SECTION_MAP_READ,
|
|
NULL, // ObjectAttributes
|
|
NULL, // MaximumSize (whole file)
|
|
PAGE_READONLY, // SectionPageProtection
|
|
SEC_COMMIT, // AllocationAttributes
|
|
Handles->File
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "SXS: %s() NtCreateSection() failed\n", __FUNCTION__);
|
|
goto Exit;
|
|
}
|
|
#if DBG
|
|
if (DebugFilter_SxsTrace) {
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() NtCreateSection() succeeded\n", __FUNCTION__);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
Status =
|
|
NtQueryInformationFile(
|
|
Handles->File,
|
|
&IoStatusBlock,
|
|
&FileBasicInformation,
|
|
sizeof(FileBasicInformation),
|
|
FileStandardInformation
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "SXS: %s() NtQueryInformationFile failed\n", __FUNCTION__);
|
|
goto Exit;
|
|
}
|
|
// clamp >4gig on 32bit to 4gig (instead of modulo)
|
|
// we should get an error later like STATUS_SECTION_TOO_BIG
|
|
if (FileBasicInformation.EndOfFile.QuadPart > MAXSIZE_T) {
|
|
FileBasicInformation.EndOfFile.QuadPart = MAXSIZE_T;
|
|
}
|
|
|
|
MessageStream->FileHandle = Handles->File;
|
|
MessageStream->PathType = BASE_MSG_PATHTYPE_FILE;
|
|
MessageStream->FileType = BASE_MSG_FILETYPE_XML;
|
|
MessageStream->Path = *Win32NtPathPair->Win32; // it will be put in the csr capture buffer later
|
|
MessageStream->HandleType = BASE_MSG_HANDLETYPE_SECTION;
|
|
MessageStream->Handle = Handles->Section;
|
|
MessageStream->Offset = 0;
|
|
// cast to 32bits on 32bit platform
|
|
MessageStream->Size = (SIZE_T)FileBasicInformation.EndOfFile.QuadPart;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
Exit:
|
|
#if DBG
|
|
DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_LEVEL_STATUS(Status), "SXS: %s() exiting 0x%08lx\n", __FUNCTION__, Status);
|
|
#endif // DBG
|
|
|
|
return Status;
|
|
}
|
|
|
|
WINBASEAPI
|
|
BOOL
|
|
WINAPI
|
|
QueryActCtxW(
|
|
IN DWORD dwFlags,
|
|
IN HANDLE hActCtx,
|
|
IN PVOID pvSubInstance,
|
|
IN ULONG ulInfoClass,
|
|
OUT PVOID pvBuffer,
|
|
IN SIZE_T cbBuffer OPTIONAL,
|
|
OUT SIZE_T *pcbWrittenOrRequired OPTIONAL
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
BOOL fSuccess = FALSE;
|
|
ULONG FlagsToRtl = 0;
|
|
ULONG ValidFlags =
|
|
QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX
|
|
| QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE
|
|
| QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS
|
|
| QUERY_ACTCTX_FLAG_NO_ADDREF
|
|
;
|
|
|
|
if (pcbWrittenOrRequired != NULL)
|
|
*pcbWrittenOrRequired = 0;
|
|
|
|
//
|
|
// compatibility with old values
|
|
// define QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX (0x00000001)
|
|
// define QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE (0x00000002)
|
|
// define QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS (0x00000003)
|
|
//
|
|
// 80000003 is in heavy use by -DISOLATION_AWARE_ENABLED.
|
|
//
|
|
switch (dwFlags & 3)
|
|
{
|
|
case 0: break; // It is legal to pass none of the flags, like if a real hActCtx is passed.
|
|
case 1: dwFlags |= QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX; break;
|
|
case 2: dwFlags |= QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE; break;
|
|
case 3: dwFlags |= QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS; break;
|
|
}
|
|
dwFlags &= ~3; // These bits have been abandoned.
|
|
|
|
if (dwFlags & ~ValidFlags) {
|
|
#if DBG
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: %s() bad flags(passed: 0x%lx, allowed: 0x%lx, bad: 0x%lx)\n",
|
|
__FUNCTION__,
|
|
dwFlags,
|
|
ValidFlags,
|
|
(dwFlags & ~ValidFlags)
|
|
);
|
|
#endif
|
|
BaseSetLastNTError(STATUS_INVALID_PARAMETER_1);
|
|
goto Exit;
|
|
}
|
|
|
|
switch (ulInfoClass)
|
|
{
|
|
default:
|
|
#if DBG
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: %s() bad InfoClass(0x%lx)\n",
|
|
__FUNCTION__,
|
|
ulInfoClass
|
|
);
|
|
#endif
|
|
BaseSetLastNTError(STATUS_INVALID_PARAMETER_2);
|
|
goto Exit;
|
|
|
|
case ActivationContextBasicInformation:
|
|
case ActivationContextDetailedInformation:
|
|
break;
|
|
|
|
case AssemblyDetailedInformationInActivationContext:
|
|
case FileInformationInAssemblyOfAssemblyInActivationContext:
|
|
if (pvSubInstance == NULL)
|
|
{
|
|
#if DBG
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: %s() InfoClass 0x%lx requires SubInstance != NULL\n",
|
|
__FUNCTION__,
|
|
ulInfoClass
|
|
);
|
|
#endif
|
|
BaseSetLastNTError(STATUS_INVALID_PARAMETER_3);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
|
|
if ((pvBuffer == NULL) && (cbBuffer != 0)) {
|
|
// This probably means that they forgot to check for a failed allocation so we'll
|
|
// attribute the failure to parameter 3.
|
|
#if DBG
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: %s() (pvBuffer == NULL) && ((cbBuffer=0x%lu) != 0)\n",
|
|
__FUNCTION__,
|
|
cbBuffer
|
|
);
|
|
#endif
|
|
BaseSetLastNTError(STATUS_INVALID_PARAMETER_4);
|
|
goto Exit;
|
|
}
|
|
|
|
if ((pvBuffer == NULL) && (pcbWrittenOrRequired == NULL)) {
|
|
#if DBG
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: %s() (pvBuffer == NULL) && (pcbWrittenOrRequired == NULL)\n",
|
|
__FUNCTION__
|
|
);
|
|
#endif
|
|
BaseSetLastNTError(STATUS_INVALID_PARAMETER_5);
|
|
goto Exit;
|
|
}
|
|
|
|
ValidFlags =
|
|
QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX
|
|
| QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE
|
|
| QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS
|
|
;
|
|
switch (dwFlags & ValidFlags)
|
|
{
|
|
default:
|
|
#if DBG
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: %s(dwFlags=0x%lx) more than one flag in 0x%lx was passed\n",
|
|
__FUNCTION__,
|
|
dwFlags,
|
|
ValidFlags
|
|
);
|
|
#endif
|
|
BaseSetLastNTError(STATUS_INVALID_PARAMETER_1);
|
|
goto Exit;
|
|
case 0: // It is legal to pass none of the flags, like if a real hActCtx is passed.
|
|
break;
|
|
case QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX:
|
|
FlagsToRtl |= RTL_QUERY_INFORMATION_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT;
|
|
break;
|
|
case QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE:
|
|
FlagsToRtl |= RTL_QUERY_INFORMATION_ACTIVATION_CONTEXT_FLAG_ACTIVATION_CONTEXT_IS_MODULE;
|
|
break;
|
|
case QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS:
|
|
FlagsToRtl |= RTL_QUERY_INFORMATION_ACTIVATION_CONTEXT_FLAG_ACTIVATION_CONTEXT_IS_ADDRESS;
|
|
break;
|
|
}
|
|
if ((dwFlags & QUERY_ACTCTX_FLAG_NO_ADDREF) != 0)
|
|
FlagsToRtl |= RTL_QUERY_INFORMATION_ACTIVATION_CONTEXT_FLAG_NO_ADDREF;
|
|
|
|
Status = RtlQueryInformationActivationContext(FlagsToRtl, (PACTIVATION_CONTEXT) hActCtx, pvSubInstance, ulInfoClass, pvBuffer, cbBuffer, pcbWrittenOrRequired);
|
|
if (!NT_SUCCESS(Status)) {
|
|
BaseSetLastNTError(Status);
|
|
goto Exit;
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
BasepProbeForDllManifest(
|
|
IN PVOID DllBase,
|
|
IN PCWSTR FullDllPath,
|
|
OUT PVOID *ActivationContextOut
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_INTERNAL_ERROR;
|
|
PACTIVATION_CONTEXT ActivationContext = NULL;
|
|
ACTCTXW acw = { sizeof(acw) };
|
|
static const ULONG_PTR ResourceIdPath[2] = { (ULONG_PTR) RT_MANIFEST, (ULONG_PTR) ISOLATIONAWARE_MANIFEST_RESOURCE_ID };
|
|
PIMAGE_RESOURCE_DIRECTORY ResourceDirectory = NULL;
|
|
|
|
if (ActivationContextOut != NULL)
|
|
*ActivationContextOut = NULL;
|
|
|
|
ASSERT(ActivationContextOut != NULL);
|
|
if (ActivationContextOut == NULL) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
Status = LdrFindResourceDirectory_U(DllBase, ResourceIdPath, RTL_NUMBER_OF(ResourceIdPath), &ResourceDirectory);
|
|
if (!NT_SUCCESS(Status))
|
|
goto Exit;
|
|
|
|
acw.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
|
|
acw.lpSource = FullDllPath;
|
|
acw.lpResourceName = MAKEINTRESOURCEW(ISOLATIONAWARE_MANIFEST_RESOURCE_ID);
|
|
acw.hModule = DllBase;
|
|
|
|
ActivationContext = (PACTIVATION_CONTEXT) CreateActCtxW(&acw);
|
|
|
|
if (ActivationContext == INVALID_HANDLE_VALUE) {
|
|
Status = NtCurrentTeb()->LastStatusValue;
|
|
goto Exit;
|
|
}
|
|
|
|
*ActivationContextOut = ActivationContext;
|
|
Status = STATUS_SUCCESS;
|
|
|
|
Exit:
|
|
return Status;
|
|
}
|
|
|