[SMSS2]: Implement SmpCallCsrCreateProcess and SmpLoadSubsystem. We now load CSRSS and everything works 100%! Winlogon is now launched by SMSS2 and no regressions have been found.

[SMSS]: Turn off all code other than setting up the pagefile.
There's a lot of debug prints, as soon as things seem stable after a few days, SMSS will be gone and SMSS2 will take over and DPRINT1s will mostly be gone.

svn path=/trunk/; revision=55509
This commit is contained in:
Alex Ionescu 2012-02-09 02:21:56 +00:00
parent e23e0ca401
commit 14ba04899c
2 changed files with 395 additions and 7 deletions

View file

@ -24,8 +24,8 @@ struct {
} InitRoutine [] = {
{TRUE, SmCreateHeap, "create private heap, aborting"},
// {TRUE, SmCreateObjectDirectories, "create object directories"},
{TRUE, SmCreateApiPort, "create \\SmApiPort"},
{TRUE, SmCreateEnvironment, "create the system environment"},
// {TRUE, SmCreateApiPort, "create \\SmApiPort"},
// {TRUE, SmCreateEnvironment, "create the system environment"},
// {TRUE, SmSetEnvironmentVariables, "set system environment variables"},
// {TRUE, SmInitDosDevices, "create dos device links"},
// {TRUE, SmRunBootApplications, "run boot applications"},
@ -34,8 +34,8 @@ struct {
// {FALSE, SmLoadKnownDlls, "preload system DLLs"},
{TRUE, SmCreatePagingFiles, "create paging files"},
// {TRUE, SmInitializeRegistry, "initialize the registry"},
{TRUE, SmInitializeClientManagement, "initialize client management"},
{TRUE, SmLoadSubsystems, "load subsystems"}
// {TRUE, SmInitializeClientManagement, "initialize client management"},
// {TRUE, SmLoadSubsystems, "load subsystems"}
};
NTSTATUS

View file

@ -23,6 +23,24 @@ WCHAR InitialCommandBuffer[256];
/* FUNCTIONS ******************************************************************/
NTSTATUS
NTAPI
SmpCallCsrCreateProcess(IN PSB_API_MSG SbApiMsg,
IN USHORT MessageLength,
IN HANDLE PortHandle)
{
NTSTATUS Status;
/* Initialize the header and send the message to CSRSS */
SbApiMsg->h.u2.ZeroInit = 0;
SbApiMsg->h.u1.s1.DataLength = MessageLength + 8;
SbApiMsg->h.u1.s1.TotalLength = sizeof(SB_API_MSG);
SbApiMsg->ApiNumber = SbpCreateProcess;
Status = NtRequestWaitReplyPort(PortHandle, &SbApiMsg->h, &SbApiMsg->h);
if (NT_SUCCESS(Status)) Status = SbApiMsg->ReturnValue;
return Status;
}
VOID
NTAPI
SmpDereferenceSubsystem(IN PSMP_SUBSYSTEM SubSystem)
@ -60,7 +78,7 @@ SmpLocateKnownSubSysByCid(IN PCLIENT_ID ClientId)
{
/* Check if this one matches the client ID and is still valid */
Subsystem = CONTAINING_RECORD(NextEntry, SMP_SUBSYSTEM, Entry);
if ((*(PULONGLONG)&Subsystem->ClientId == *(PULONGLONG)&ClientId) &&
if ((*(PULONGLONG)&Subsystem->ClientId == *(PULONGLONG)ClientId) &&
!(Subsystem->Terminating))
{
/* Add a reference and return it */
@ -123,8 +141,378 @@ SmpLoadSubSystem(IN PUNICODE_STRING FileName,
OUT PHANDLE ProcessId,
IN ULONG Flags)
{
DPRINT1("Should start subsystem %wZ for Session: %lx\n", FileName, MuSessionId);
return STATUS_SUCCESS;
PSMP_SUBSYSTEM Subsystem, NewSubsystem, KnownSubsystem = NULL;
HANDLE SubSysProcessId;
NTSTATUS Status = STATUS_SUCCESS;
SB_API_MSG SbApiMsg, SbApiMsg2;
RTL_USER_PROCESS_INFORMATION ProcessInformation;
LARGE_INTEGER Timeout;
PVOID State;
PSB_CREATE_PROCESS_MSG CreateProcess = &SbApiMsg.CreateProcess;
PSB_CREATE_SESSION_MSG CreateSession = &SbApiMsg.CreateSession;
DPRINT1("Loading subsystem: %wZ\n", FileName);
/* Make sure this is a found subsystem */
if (Flags & SMP_INVALID_PATH)
{
DPRINT1("SMSS: Unable to find subsystem - %wZ\n", FileName);
return STATUS_OBJECT_NAME_NOT_FOUND;
}
/* Don't use a session if the flag is set */
if (Flags & 0x80) MuSessionId = 0;
/* Lock the subsystems while we do a look up */
RtlEnterCriticalSection(&SmpKnownSubSysLock);
while (TRUE)
{
/* Check if we found a subsystem not yet fully iniitalized */
Subsystem = SmpLocateKnownSubSysByType(MuSessionId, -1);
if (!Subsystem) break;
RtlLeaveCriticalSection(&SmpKnownSubSysLock);
/* Wait on it to initialize */
NtWaitForSingleObject(Subsystem->Event, FALSE, NULL);
/* Dereference it and try the next one */
RtlEnterCriticalSection(&SmpKnownSubSysLock);
SmpDereferenceSubsystem(Subsystem);
}
/* Check if this is a POSIX subsystem */
if (Flags & SMP_POSIX_FLAG)
{
/* Do we already have it? */
Subsystem = SmpLocateKnownSubSysByType(MuSessionId, IMAGE_SUBSYSTEM_POSIX_CUI);
}
else if (Flags & SMP_OS2_FLAG)
{
/* This is an OS/2 subsystem, do we we already have it? */
Subsystem = SmpLocateKnownSubSysByType(MuSessionId, IMAGE_SUBSYSTEM_OS2_CUI);
}
/* Check if we already have one of the optional subsystems for the session */
if (Subsystem)
{
/* Dereference and return, no work to do */
SmpDereferenceSubsystem(Subsystem);
RtlLeaveCriticalSection(&SmpKnownSubSysLock);
return STATUS_SUCCESS;
}
/* Allocate a new subsystem! */
NewSubsystem = RtlAllocateHeap(SmpHeap, SmBaseTag, sizeof(SMP_SUBSYSTEM));
DPRINT1("new subsystem created: %p\n", NewSubsystem);
if (!NewSubsystem)
{
RtlLeaveCriticalSection(&SmpKnownSubSysLock);
return STATUS_NO_MEMORY;
}
/* Initialize its header and reference count */
NewSubsystem->ReferenceCount = 1;
NewSubsystem->MuSessionId = MuSessionId;
NewSubsystem->ImageType = -1;
/* Clear out all the other data for now */
NewSubsystem->Terminating = FALSE;
NewSubsystem->ProcessHandle = NULL;
NewSubsystem->Event = NULL;
NewSubsystem->PortHandle = NULL;
NewSubsystem->SbApiPort = NULL;
/* Create the event we'll be wating on for initialization */
Status = NtCreateEvent(&NewSubsystem->Event,
EVENT_ALL_ACCESS,
NULL,
NotificationEvent,
FALSE);
if (!NT_SUCCESS(Status))
{
/* This failed, bail out */
RtlFreeHeap(SmpHeap, 0, NewSubsystem);
RtlLeaveCriticalSection(&SmpKnownSubSysLock);
return STATUS_NO_MEMORY;
}
/* Insert the subsystem and release the lock. It can now be found */
InsertTailList(&SmpKnownSubSysHead, &NewSubsystem->Entry);
RtlLeaveCriticalSection(&SmpKnownSubSysLock);
/* The OS/2 and POSIX subsystems are actually Windows applications! */
if (Flags & (SMP_POSIX_FLAG | SMP_OS2_FLAG))
{
/* Locate the Windows subsystem for this session */
KnownSubsystem = SmpLocateKnownSubSysByType(MuSessionId,
IMAGE_SUBSYSTEM_WINDOWS_GUI);
if (!KnownSubsystem)
{
DPRINT1("SMSS: SmpLoadSubSystem - SmpLocateKnownSubSysByType Failed\n");
goto Quickie2;
}
/* Fill out all the process details and call CSRSS to launch it */
CreateProcess->In.ImageName = FileName;
CreateProcess->In.CurrentDirectory = Directory;
CreateProcess->In.CommandLine = CommandLine;
CreateProcess->In.DllPath = SmpDefaultLibPath.Length ?
&SmpDefaultLibPath : NULL;
CreateProcess->In.Flags = Flags | SMP_DEFERRED_FLAG;
CreateProcess->In.DebugFlags = SmpDebug;
Status = SmpCallCsrCreateProcess(&SbApiMsg,
sizeof(*CreateProcess),
KnownSubsystem->SbApiPort);
if (!NT_SUCCESS(Status))
{
/* Handle failures */
DPRINT1("SMSS: SmpLoadSubSystem - SmpCallCsrCreateProcess Failed with Status %lx\n",
Status);
goto Quickie2;
}
/* Save the process information we'll need for the create session */
ProcessInformation.ProcessHandle = CreateProcess->Out.ProcessHandle;
ProcessInformation.ThreadHandle = CreateProcess->Out.ThreadHandle;
ProcessInformation.ClientId = CreateProcess->Out.ClientId;
ProcessInformation.ImageInformation.SubSystemType = CreateProcess->Out.SubsystemType;
}
else
{
/* This must be CSRSS itself, so just launch it and that's it */
DPRINT1("Executing CSRSS\n");
Status = SmpExecuteImage(FileName,
Directory,
CommandLine,
MuSessionId,
Flags | SMP_DEFERRED_FLAG,
&ProcessInformation);
if (!NT_SUCCESS(Status))
{
/* Handle failures */
DPRINT1("SMSS: SmpLoadSubSystem - SmpExecuteImage Failed with Status %lx\n",
Status);
goto Quickie2;
}
}
/* Fill out the handle and client ID in the subsystem structure now */
NewSubsystem->ProcessHandle = ProcessInformation.ProcessHandle;
NewSubsystem->ClientId = ProcessInformation.ClientId;
/* Check if we launched a native image or a subsystem-backed image */
if (ProcessInformation.ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_NATIVE)
{
/* This must be CSRSS itself, since it's a native subsystem image */
SubSysProcessId = ProcessInformation.ClientId.UniqueProcess;
if ((ProcessId) && !(*ProcessId)) *ProcessId = SubSysProcessId;
/* Was this the initial CSRSS on Session 0? */
if (!MuSessionId)
{
/* Then save it in the global variables */
SmpWindowsSubSysProcessId = SubSysProcessId;
SmpWindowsSubSysProcess = ProcessInformation.ProcessHandle;
}
ASSERT(NT_SUCCESS(Status));
DPRINT1("CSRSS is up and running: %lx %lx\n", SmpWindowsSubSysProcessId, SmpWindowsSubSysProcess);
}
else
{
/* This is the POSIX or OS/2 subsystem process, copy its information */
RtlCopyMemory(&CreateSession->ProcessInfo,
&ProcessInformation,
sizeof(&CreateSession->ProcessInfo));
/* Not sure these field mean what I think they do -- but clear them */
*(PULONGLONG)&CreateSession->ClientId = 0;
CreateSession->MuSessionId = 0;
/* This should find CSRSS because they are POSIX or OS/2 subsystems */
Subsystem = SmpLocateKnownSubSysByType(MuSessionId,
ProcessInformation.ImageInformation.SubSystemType);
if (!Subsystem)
{
/* Odd failure -- but handle it anyway */
Status = STATUS_NO_SUCH_PACKAGE;
DPRINT1("SMSS: SmpLoadSubSystem - SmpLocateKnownSubSysByType Failed with Status %lx for sessionid %ld\n",
Status,
MuSessionId);
goto Quickie;
}
/* Duplicate the parent process handle for the subsystem to have */
Status = NtDuplicateObject(NtCurrentProcess(),
ProcessInformation.ProcessHandle,
Subsystem->ProcessHandle,
&CreateSession->ProcessInfo.ProcessHandle,
PROCESS_ALL_ACCESS,
0,
0);
if (!NT_SUCCESS(Status))
{
/* Fail since this is critical */
DPRINT1("SMSS: SmpLoadSubSystem - NtDuplicateObject Failed with Status %lx for sessionid %ld\n",
Status,
MuSessionId);
goto Quickie;
}
/* Duplicate the initial thread handle for the subsystem to have */
Status = NtDuplicateObject(NtCurrentProcess(),
ProcessInformation.ThreadHandle,
Subsystem->ProcessHandle,
&CreateSession->ProcessInfo.ThreadHandle,
THREAD_ALL_ACCESS,
0,
0);
if (!NT_SUCCESS(Status))
{
/* Fail since this is critical */
DPRINT1("SMSS: SmpLoadSubSystem - NtDuplicateObject Failed with Status %lx for sessionid %ld\n",
Status,
MuSessionId);
goto Quickie;
}
/* Allocate an internal Session ID for this subsystem */
MuSessionId = SmpAllocateSessionId(Subsystem, 0);
CreateSession->SessionId = MuSessionId;
/* Send the create session message to the subsystem */
SbApiMsg2.ReturnValue = STATUS_SUCCESS;
SbApiMsg2.h.u2.ZeroInit = 0;
SbApiMsg2.h.u1.s1.DataLength = sizeof(SB_CREATE_SESSION_MSG) + 8;
SbApiMsg2.h.u1.s1.TotalLength = sizeof(SB_API_MSG);
Status = NtRequestWaitReplyPort(Subsystem->SbApiPort,
&SbApiMsg2.h,
&SbApiMsg2.h);
if (NT_SUCCESS(Status)) Status = SbApiMsg2.ReturnValue;
if (!NT_SUCCESS(Status))
{
/* Delete the session and handle failure if the LPC call failed */
SmpDeleteSession(CreateSession->SessionId);
DPRINT1("SMSS: SmpLoadSubSystem - NtRequestWaitReplyPort Failed with Status %lx for sessionid %ld\n",
Status,
CreateSession->SessionId);
goto Quickie;
}
}
/* Okay, everything looks good to go, initialize this subsystem now! */
DPRINT1("Resuming the subsystem!\n");
Status = NtResumeThread(ProcessInformation.ThreadHandle, NULL);
if (!NT_SUCCESS(Status))
{
/* That didn't work -- back out of everything */
DPRINT1("SMSS: SmpLoadSubSystem - NtResumeThread failed Status %lx\n", Status);
goto Quickie;
}
/* Check if this was the subsystem for a different session */
if (MuSessionId)
{
/* Wait up to 60 seconds for it to initialize */
Timeout.QuadPart = -600000000;
Status = NtWaitForSingleObject(NewSubsystem->Event, FALSE, &Timeout);
/* Timeout is done -- does this session still exist? */
if (!SmpCheckDuplicateMuSessionId(MuSessionId))
{
/* Nope, it died. Cleanup should've ocurred in a different path. */
DPRINT1("SMSS: SmpLoadSubSystem - session deleted\n");
return STATUS_DELETE_PENDING;
}
/* Check if we timed our or there was another error with the wait */
if (Status != STATUS_WAIT_0)
{
/* Something is wrong with the subsystem, so back out of everything */
DPRINT1("SMSS: SmpLoadSubSystem - Timeout waiting for subsystem connect with Status %lx for sessionid %ld\n",
Status,
MuSessionId);
goto Quickie;
}
}
else
{
/* This a session 0 subsystem, just wait for it to initialize */
DPRINT1("Waiting on the subsystem to initialize...\n");
NtWaitForSingleObject(NewSubsystem->Event, FALSE, NULL);
DPRINT1("Subsystem is ready!!!\n");
}
/* Subsystem is created, resumed, and initialized. Close handles and exit */
NtClose(ProcessInformation.ThreadHandle);
Status = STATUS_SUCCESS;
DPRINT1("Returning success\n");
goto Quickie2;
Quickie:
/* This is the failure path. First check if we need to detach from session */
if ((AttachedSessionId == -1) || (Flags & (SMP_POSIX_FLAG | SMP_OS2_FLAG)))
{
/* We were not attached, or did not launch subsystems that required it */
DPRINT1("SMSS: Did not detach from Session Space: SessionId=%x Flags=%x Status=%x\n",
AttachedSessionId,
Flags | SMP_DEFERRED_FLAG,
Status);
}
else
{
/* Get the privilege we need for detachment */
Status = SmpAcquirePrivilege(SE_LOAD_DRIVER_PRIVILEGE, &State);
if (!NT_SUCCESS(Status))
{
/* We can't detach without it */
DPRINT1("SMSS: Did not detach from Session Space: SessionId=%x Flags=%x Status=%x\n",
AttachedSessionId,
Flags | SMP_DEFERRED_FLAG,
Status);
}
else
{
/* Now detach from the session */
Status = NtSetSystemInformation(SystemSessionDetach,
&AttachedSessionId,
sizeof(AttachedSessionId));
if (!NT_SUCCESS(Status))
{
/* Failed to detach. Note the DPRINT1 has a typo in Windows */
DPRINT1("SMSS: SmpStartCsr, Couldn't Detach from Session Space. Status=%x\n", Status);
ASSERT(NT_SUCCESS(Status));
}
else
{
/* Detachment worked, reset our attached session ID */
AttachedSessionId = -1;
}
/* And release the privilege we acquired */
SmpReleasePrivilege(State);
}
}
/* Since this is the failure path, terminate the subsystem process */
NtTerminateProcess(ProcessInformation.ProcessHandle, Status);
NtClose(ProcessInformation.ThreadHandle);
Quickie2:
/* This is the cleanup path -- first dereference our subsystems */
RtlEnterCriticalSection(&SmpKnownSubSysLock);
if (Subsystem) SmpDereferenceSubsystem(Subsystem);
if (KnownSubsystem) SmpDereferenceSubsystem(KnownSubsystem);
/* In the failure case, destroy the new subsystem we just created */
if (!NT_SUCCESS(Status))
{
RemoveEntryList(&NewSubsystem->Entry);
NtSetEvent(NewSubsystem->Event, 0);
if (NewSubsystem) SmpDereferenceSubsystem(NewSubsystem);
}
/* Finally, we're all done! */
RtlLeaveCriticalSection(&SmpKnownSubSysLock);
return Status;
}
NTSTATUS