|
|
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
srvloadr.c
Abstract:
This is the server DLL loader module for the Server side of the Client Server Runtime Subsystem (CSRSS)
Author:
Steve Wood (stevewo) 08-Oct-1990
Environment:
User Mode Only
Revision History:
--*/
#include "csrsrv.h"
#include "windows.h"
#ifdef _IA64_
#include <ntia64.h>
#endif // _IA64_
EXCEPTION_DISPOSITION CsrUnhandledExceptionFilter( struct _EXCEPTION_POINTERS *ExceptionInfo ) { UNICODE_STRING UnicodeParameter; ULONG_PTR Parameters[ 4 ]; ULONG Response; BOOLEAN WasEnabled; NTSTATUS Status; LONG lReturn = EXCEPTION_EXECUTE_HANDLER; SYSTEM_KERNEL_DEBUGGER_INFORMATION KernelDebuggerInfo;
//
// Terminating will cause sm's wait to sense that we crashed. This will
// result in a clean shutdown due to sm's hard error logic
//
Status = NtQuerySystemInformation( SystemKernelDebuggerInformation, &KernelDebuggerInfo, sizeof(KernelDebuggerInfo), NULL );
//
// Under Hydra, we don't want to shutdown the system just
// because the Win32 subsystem is going away. In case of non-console CSRSS,
// causing the process to terminate is sufficient.
//
if ((NtCurrentPeb()->SessionId == 0) || (NT_SUCCESS(Status) && KernelDebuggerInfo.KernelDebuggerEnabled)) {
lReturn = RtlUnhandledExceptionFilter(ExceptionInfo);
if (lReturn != EXCEPTION_CONTINUE_EXECUTION) { //
// We are hosed, so raise a fatal system error to shutdown the system.
// (Basically a user mode KeBugCheck).
//
Status = RtlAdjustPrivilege( SE_SHUTDOWN_PRIVILEGE, (BOOLEAN)TRUE, TRUE, &WasEnabled );
if (Status == STATUS_NO_TOKEN) {
//
// No thread token, use the process token
//
Status = RtlAdjustPrivilege( SE_SHUTDOWN_PRIVILEGE, (BOOLEAN)TRUE, FALSE, &WasEnabled ); }
RtlInitUnicodeString( &UnicodeParameter, L"Windows SubSystem" ); Parameters[ 0 ] = (ULONG_PTR)&UnicodeParameter; Parameters[ 1 ] = (ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionCode; Parameters[ 2 ] = (ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionAddress; Parameters[ 3 ] = (ULONG_PTR)ExceptionInfo->ContextRecord; Status = NtRaiseHardError( STATUS_SYSTEM_PROCESS_TERMINATED, 4, 1, Parameters, OptionShutdownSystem, &Response ); } }
if (lReturn != EXCEPTION_CONTINUE_EXECUTION) { //
// If this returns, giveup
//
NtTerminateProcess(NtCurrentProcess(),ExceptionInfo->ExceptionRecord->ExceptionCode); }
return lReturn; }
NTSTATUS CsrLoadServerDll( IN PCH ModuleName, IN PCH InitRoutineString, IN ULONG ServerDllIndex ) { NTSTATUS Status; ANSI_STRING ModuleNameString; UNICODE_STRING ModuleNameString_U; HANDLE ModuleHandle; PCSR_SERVER_DLL LoadedServerDll; STRING ProcedureNameString; PCSR_SERVER_DLL_INIT_ROUTINE ServerDllInitialization; ULONG n;
if (ServerDllIndex >= CSR_MAX_SERVER_DLL) { return( STATUS_TOO_MANY_NAMES ); }
if (CsrLoadedServerDll[ ServerDllIndex ] != NULL) { return( STATUS_INVALID_PARAMETER ); }
ASSERT( ModuleName != NULL ); RtlInitAnsiString( &ModuleNameString, ModuleName );
if (ServerDllIndex != CSRSRV_SERVERDLL_INDEX) { Status = RtlAnsiStringToUnicodeString(&ModuleNameString_U, &ModuleNameString, TRUE); if (!NT_SUCCESS(Status)) { return Status; } Status = LdrLoadDll( UNICODE_NULL, NULL, &ModuleNameString_U, &ModuleHandle ); if ( !NT_SUCCESS(Status) ) {
PUNICODE_STRING ErrorStrings[2]; UNICODE_STRING ErrorDllPath; ULONG ErrorResponse; NTSTATUS ErrorStatus;
ErrorStrings[0] = &ModuleNameString_U; ErrorStrings[1] = &ErrorDllPath; RtlInitUnicodeString(&ErrorDllPath,L"Default Load Path");
//
// need to get image name
//
ErrorStatus = NtRaiseHardError( (NTSTATUS)STATUS_DLL_NOT_FOUND, 2, 0x00000003, (PULONG_PTR)ErrorStrings, OptionOk, &ErrorResponse );
} RtlFreeUnicodeString(&ModuleNameString_U); if (!NT_SUCCESS( Status )) { return( Status ); } } else { ModuleHandle = NULL; }
n = sizeof( *LoadedServerDll ) + ModuleNameString.MaximumLength;
LoadedServerDll = RtlAllocateHeap( CsrHeap, MAKE_TAG( INIT_TAG ), n ); if (LoadedServerDll == NULL) { if (ModuleHandle != NULL) { LdrUnloadDll( ModuleHandle ); }
return( STATUS_NO_MEMORY ); }
RtlZeroMemory( LoadedServerDll, n ); LoadedServerDll->SharedStaticServerData = CsrSrvSharedSectionHeap; LoadedServerDll->Length = n; LoadedServerDll->ModuleName.Length = ModuleNameString.Length; LoadedServerDll->ModuleName.MaximumLength = ModuleNameString.MaximumLength; LoadedServerDll->ModuleName.Buffer = (PCH)(LoadedServerDll+1); if (ModuleNameString.Length != 0) { strncpy( LoadedServerDll->ModuleName.Buffer, ModuleNameString.Buffer, ModuleNameString.Length ); }
LoadedServerDll->ServerDllIndex = ServerDllIndex; LoadedServerDll->ModuleHandle = ModuleHandle;
if (ModuleHandle != NULL) {
RtlInitString( &ProcedureNameString, (InitRoutineString == NULL) ? "ServerDllInitialization" : InitRoutineString);
Status = LdrGetProcedureAddress( ModuleHandle, &ProcedureNameString, 0, (PVOID *) &ServerDllInitialization ); } else { ServerDllInitialization = CsrServerDllInitialization; Status = STATUS_SUCCESS; }
if (NT_SUCCESS( Status )) { try { Status = (*ServerDllInitialization)( LoadedServerDll ); } except ( CsrUnhandledExceptionFilter( GetExceptionInformation() ) ){ Status = GetExceptionCode(); } if (NT_SUCCESS( Status )) { CsrTotalPerProcessDataLength += (ULONG)QUAD_ALIGN(LoadedServerDll->PerProcessDataLength);
CsrLoadedServerDll[ LoadedServerDll->ServerDllIndex ] = LoadedServerDll; if ( LoadedServerDll->SharedStaticServerData != CsrSrvSharedSectionHeap ) { CsrSrvSharedStaticServerData[LoadedServerDll->ServerDllIndex] = LoadedServerDll->SharedStaticServerData; } } else { if (ModuleHandle != NULL) { LdrUnloadDll( ModuleHandle ); }
RtlFreeHeap( CsrHeap, 0, LoadedServerDll ); } } else { if (ModuleHandle != NULL) { LdrUnloadDll( ModuleHandle ); }
RtlFreeHeap( CsrHeap, 0, LoadedServerDll ); }
return( Status ); }
ULONG CsrSrvClientConnect( IN OUT PCSR_API_MSG m, IN OUT PCSR_REPLY_STATUS ReplyStatus ) { NTSTATUS Status; PCSR_CLIENTCONNECT_MSG a = (PCSR_CLIENTCONNECT_MSG)&m->u.ApiMessageData; PCSR_SERVER_DLL LoadedServerDll;
*ReplyStatus = CsrReplyImmediate;
if (a->ServerDllIndex >= CSR_MAX_SERVER_DLL) { return( STATUS_TOO_MANY_NAMES ); }
if (CsrLoadedServerDll[ a->ServerDllIndex ] == NULL) { return( STATUS_INVALID_PARAMETER ); }
if (!CsrValidateMessageBuffer(m, &a->ConnectionInformation, a->ConnectionInformationLength, sizeof(BYTE))) { return( STATUS_INVALID_PARAMETER ); }
LoadedServerDll = CsrLoadedServerDll[ a->ServerDllIndex ];
if (LoadedServerDll->ConnectRoutine) {
Status = (LoadedServerDll->ConnectRoutine)( (CSR_SERVER_QUERYCLIENTTHREAD())->Process, a->ConnectionInformation, &a->ConnectionInformationLength ); } else { Status = STATUS_SUCCESS; }
return( Status ); }
NTSTATUS CsrSrvCreateSharedSection( IN PCH SizeParameter ) { NTSTATUS Status; LARGE_INTEGER SectionSize; SIZE_T ViewSize; ULONG HeapSize; ULONG AllocationAttributes; PCH s; ULONG FirstCsr = (NtCurrentPeb()->SessionId == 0);
#if defined(_WIN64)
PVOID BaseAddress; SIZE_T RegionSize; #endif
if (SizeParameter == NULL) { return STATUS_INVALID_PARAMETER; }
s = SizeParameter; while (*s) { if (*s == ',') { *s++ = '\0'; break; } else { s++; } }
if (!*s) { return( STATUS_INVALID_PARAMETER ); }
Status = RtlCharToInteger( SizeParameter, 0, &HeapSize ); if (!NT_SUCCESS( Status )) { return( Status ); }
HeapSize = ROUND_UP_TO_PAGES( HeapSize * 1024 ); CsrSrvSharedSectionSize = HeapSize;
SectionSize.LowPart = CsrSrvSharedSectionSize; SectionSize.HighPart = 0;
if (FirstCsr) { AllocationAttributes = SEC_BASED | SEC_RESERVE; } else { AllocationAttributes = SEC_RESERVE; }
Status = NtCreateSection( &CsrSrvSharedSection, SECTION_ALL_ACCESS, (POBJECT_ATTRIBUTES) NULL, &SectionSize, PAGE_EXECUTE_READWRITE, AllocationAttributes, (HANDLE) NULL ); if (!NT_SUCCESS( Status )) { return( Status ); }
ViewSize = 0;
#if defined(_WIN64)
CsrSrvSharedSectionBase = (PVOID)CSR_SYSTEM_SHARED_ADDRESS; #else
if (FirstCsr) { CsrSrvSharedSectionBase = NULL; } else {
//
// Retrieve the value of CsrSrvSharedSectionBase from registry
// This is saved by the First CSRSS process and used by others
//
HANDLE hKey; OBJECT_ATTRIBUTES Obja; ULONG Attributes; UNICODE_STRING KeyName;
Attributes = OBJ_CASE_INSENSITIVE;
RtlInitUnicodeString( &KeyName, CSR_BASE_PATH );
InitializeObjectAttributes(&Obja, &KeyName, Attributes, NULL, NULL);
Status = NtOpenKey(&hKey, KEY_READ, &Obja);
if (NT_SUCCESS(Status)) {
ULONG BufferLength; ULONG ResultLength; BYTE PrivateKeyValueInformation[ sizeof( KEY_VALUE_PARTIAL_INFORMATION ) + + sizeof(DWORD) ];
BufferLength = sizeof( PrivateKeyValueInformation );
RtlInitUnicodeString( &KeyName, L"CsrSrvSharedSectionBase" );
if (NT_SUCCESS(Status = NtQueryValueKey( hKey, &KeyName, KeyValuePartialInformation, PrivateKeyValueInformation, BufferLength, &ResultLength ))) {
RtlCopyMemory( &CsrSrvSharedSectionBase, (( PKEY_VALUE_PARTIAL_INFORMATION ) PrivateKeyValueInformation )->Data, (( PKEY_VALUE_PARTIAL_INFORMATION ) PrivateKeyValueInformation )->DataLength );
}
ASSERT(NT_SUCCESS(Status));
NtClose(hKey);
}
if (!NT_SUCCESS(Status)) {
ASSERT(NT_SUCCESS(Status));
return Status; }
} #endif
#if defined(_WIN64)
//
// For compatibility reasons, on Win64 the csrss shared section
// needs to be at an address below 2GB. Since it is difficult to
// find an address in the middle of the address space that is
// guaranteed to be available in all processes, the memory
// manager reserves an address at the top of the 2GB range.
// To use this memory, CSRSS first unreserves the memory and
// then maps in the section. A possible race condition exists
// if another thread tries to allocate the memory at the same
// time, but this is highly unlikely since in the current NT
// code the mapping and unmapping will always occur in DLL_PROCESS_ATTACH
// in kernel32.dll. This code executes when the first thread
// of the process is initialized, and all newly created threads
// are blocked untill this code completes.
//
BaseAddress = (PVOID)CSR_SYSTEM_SHARED_ADDRESS; RegionSize = CsrSrvSharedSectionSize;
Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &RegionSize, MEM_RELEASE );
if (!NT_SUCCESS(Status)) { NtClose( CsrSrvSharedSection ); return Status; } #endif
Status = NtMapViewOfSection( CsrSrvSharedSection, NtCurrentProcess(), &CsrSrvSharedSectionBase, 0, // Zerobits?
0, NULL, &ViewSize, ViewUnmap, MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE ); if (!NT_SUCCESS( Status )) {
#if defined(_WIN64)
//
// For this code to execute, either the race condition
// described above occured for some unknown reason or
// the memory manager or process is corrupt. With the lack
// of an atomic uncommit and map, the best that can be done is
// try to reallocate the memory. If this fails, everything
// is hopeless.
//
BaseAddress = (PVOID)CSR_SYSTEM_SHARED_ADDRESS; RegionSize = CsrSrvSharedSectionSize; NtAllocateVirtualMemory(NtCurrentProcess(), &BaseAddress, 0, &RegionSize, MEM_RESERVE, PAGE_READONLY ); #endif
NtClose( CsrSrvSharedSection ); return( Status ); } CsrSrvSharedSectionHeap = CsrSrvSharedSectionBase;
if (IsTerminalServer() && FirstCsr) { //
//save CsrSrvSharedSectionBase in registry for other csrs
//
HKEY hKey; OBJECT_ATTRIBUTES Obja; ULONG Attributes; UNICODE_STRING KeyName; DWORD dwDisposition;
Attributes = OBJ_CASE_INSENSITIVE;
RtlInitUnicodeString( &KeyName, CSR_BASE_PATH );
InitializeObjectAttributes(&Obja, &KeyName, Attributes, NULL, NULL);
Status = NtCreateKey(&hKey, KEY_WRITE, &Obja, 0, NULL, REG_OPTION_VOLATILE, &dwDisposition);
if (NT_SUCCESS(Status)) {
RtlInitUnicodeString( &KeyName, L"CsrSrvSharedSectionBase" );
Status = NtSetValueKey( hKey, &KeyName, 0, REG_DWORD, (LPBYTE)&CsrSrvSharedSectionBase, sizeof(CsrSrvSharedSectionBase) );
ASSERT(NT_SUCCESS(Status));
NtClose(hKey); } else {
ASSERT(NT_SUCCESS(Status));
}
}
if (RtlCreateHeap( HEAP_ZERO_MEMORY | HEAP_CLASS_7, CsrSrvSharedSectionHeap, HeapSize, 4*1024, 0, 0 ) == NULL ) { NtUnmapViewOfSection( NtCurrentProcess(), CsrSrvSharedSectionBase ); NtClose( CsrSrvSharedSection ); return( STATUS_NO_MEMORY ); }
CsrSharedBaseTag = RtlCreateTagHeap( CsrSrvSharedSectionHeap, 0, L"CSRSHR!", L"!CSRSHR\0" L"INIT\0" ); CsrSrvSharedStaticServerData = (PVOID *)RtlAllocateHeap( CsrSrvSharedSectionHeap, MAKE_SHARED_TAG( SHR_INIT_TAG ), CSR_MAX_SERVER_DLL * sizeof(PVOID) );
if (CsrSrvSharedStaticServerData == NULL) { return STATUS_NO_MEMORY; } NtCurrentPeb()->ReadOnlySharedMemoryBase = CsrSrvSharedSectionBase; NtCurrentPeb()->ReadOnlySharedMemoryHeap = CsrSrvSharedSectionHeap; NtCurrentPeb()->ReadOnlyStaticServerData = (PVOID *)CsrSrvSharedStaticServerData;
return( STATUS_SUCCESS ); }
NTSTATUS CsrSrvAttachSharedSection( IN PCSR_PROCESS Process OPTIONAL, OUT PCSR_API_CONNECTINFO p ) { NTSTATUS Status; SIZE_T ViewSize;
#if defined(_WIN64)
PVOID BaseAddress; SIZE_T RegionSize; #endif
if (ARGUMENT_PRESENT( Process )) {
#if defined(_WIN64)
BaseAddress = (PVOID)CSR_SYSTEM_SHARED_ADDRESS; RegionSize = CsrSrvSharedSectionSize;
Status = NtFreeVirtualMemory(Process->ProcessHandle, &BaseAddress, &RegionSize, MEM_RELEASE ); if(!NT_SUCCESS(Status)) { return Status; } #endif
ViewSize = 0; Status = NtMapViewOfSection( CsrSrvSharedSection, Process->ProcessHandle, &CsrSrvSharedSectionBase, 0, 0, NULL, &ViewSize, ViewUnmap, SEC_NO_CHANGE, PAGE_EXECUTE_READ ); if (!NT_SUCCESS( Status )) {
#if defined(_WIN64)
BaseAddress = (PVOID)CSR_SYSTEM_SHARED_ADDRESS; RegionSize = CsrSrvSharedSectionSize;
NtAllocateVirtualMemory(Process->ProcessHandle, &BaseAddress, 0, &RegionSize, MEM_RESERVE, PAGE_READONLY ); #endif
return( Status ); } }
p->SharedSectionBase = CsrSrvSharedSectionBase; p->SharedSectionHeap = CsrSrvSharedSectionHeap; p->SharedStaticServerData = CsrSrvSharedStaticServerData;
return( STATUS_SUCCESS ); }
|