From f4539b703744cf7c38db6a27fabf1090f1e2c1b4 Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Sun, 9 Jul 2006 18:54:13 +0000 Subject: [PATCH] - Massive re-write of some parts of Ps, based on a patch I wrote almost a year ago and peer-reviewed with Thomas and Filip. Causes some shutdown regressions and process leaks (will fix). Needs more work. Changelog: - Architectural changes to match information in Windows Internals 4 and other documented sources of information (Windows Internals II by Probert). Code should match Win2003 layout. - Handle almost any possible process/thread sub structure and add its cleanup code stubs, so that when we actually implement them, we won't forget to clean them up in the process code. - Add interlocked usage of process and thread flags in order to make everything more thread-safe. - Better handle cases where threads die instantly, race conditions, and other weird issues. - Better handle process termination and thread termination. - Implement NtCreateProcessEx and update PspCreateProcess/NtCreateProcess. - Improve cleanup of process object in PspProcessDelete. - Optimize some things like User Thread startup. - Add some extra asserts, paged_code checks and also user-mode security check. - Implement helper API PsGetNextProcessThread - Optimize thread reaper (thanks Filip) - Do proper referencing/dereferencing of thread/processes (thanks Thomas) - Document FIXMEs needed for Ps code to be up to standards and complete. svn path=/trunk/; revision=22976 --- reactos/ntoskrnl/dbgk/dbgkutil.c | 14 + reactos/ntoskrnl/dbgk/debug.c | 9 + reactos/ntoskrnl/ex/power.c | 2 +- reactos/ntoskrnl/include/internal/dbgk.h | 15 + reactos/ntoskrnl/include/internal/ke.h | 3 +- reactos/ntoskrnl/include/internal/lpc.h | 6 +- reactos/ntoskrnl/include/internal/mm.h | 18 +- reactos/ntoskrnl/include/internal/ntoskrnl.h | 20 + reactos/ntoskrnl/include/internal/ob.h | 20 +- reactos/ntoskrnl/include/internal/po.h | 4 + reactos/ntoskrnl/include/internal/ps.h | 51 +- reactos/ntoskrnl/include/internal/se.h | 8 + reactos/ntoskrnl/include/internal/tag.h | 3 + reactos/ntoskrnl/ke/kthread.c | 65 +- reactos/ntoskrnl/ke/process.c | 3 +- reactos/ntoskrnl/lpc/close.c | 18 + reactos/ntoskrnl/lpc/send.c | 31 - reactos/ntoskrnl/mm/mm.c | 56 +- reactos/ntoskrnl/mm/process.c | 91 ++ reactos/ntoskrnl/ntoskrnl.mc | 25 + reactos/ntoskrnl/ob/obhandle.c | 9 +- reactos/ntoskrnl/ob/obname.c | 44 + reactos/ntoskrnl/ob/obref.c | 4 +- reactos/ntoskrnl/po/power.c | 7 + reactos/ntoskrnl/ps/job.c | 31 +- reactos/ntoskrnl/ps/kill.c | 1171 ++++++++++++------ reactos/ntoskrnl/ps/process.c | 597 +++++---- reactos/ntoskrnl/ps/psmgr.c | 9 - reactos/ntoskrnl/ps/security.c | 34 + reactos/ntoskrnl/ps/thread.c | 424 ++++--- reactos/ntoskrnl/ps/win32.c | 47 +- reactos/ntoskrnl/se/audit.c | 16 + 32 files changed, 1887 insertions(+), 968 deletions(-) diff --git a/reactos/ntoskrnl/dbgk/dbgkutil.c b/reactos/ntoskrnl/dbgk/dbgkutil.c index b8aec4c212c..550512c440c 100644 --- a/reactos/ntoskrnl/dbgk/dbgkutil.c +++ b/reactos/ntoskrnl/dbgk/dbgkutil.c @@ -54,4 +54,18 @@ DbgkCreateThread(PVOID StartAddress) #endif } +VOID +NTAPI +DbgkExitProcess(IN NTSTATUS ExitStatus) +{ + /* FIXME */ +} + +VOID +NTAPI +DbgkExitThread(IN NTSTATUS ExitStatus) +{ + /* FIXME */ +} + /* EOF */ diff --git a/reactos/ntoskrnl/dbgk/debug.c b/reactos/ntoskrnl/dbgk/debug.c index 1c67cb15fdd..ab8fbdd46f1 100644 --- a/reactos/ntoskrnl/dbgk/debug.c +++ b/reactos/ntoskrnl/dbgk/debug.c @@ -14,8 +14,17 @@ #include POBJECT_TYPE DbgkDebugObjectType; + /* FUNCTIONS *****************************************************************/ +VOID +NTAPI +DbgkCopyProcessDebugPort(IN PEPROCESS Process, + IN PEPROCESS Parent) +{ + /* FIXME: Implement */ +} + NTSTATUS NTAPI NtCreateDebugObject(OUT PHANDLE DebugHandle, diff --git a/reactos/ntoskrnl/ex/power.c b/reactos/ntoskrnl/ex/power.c index 3dd62dbc351..fe0fe8b9dbe 100644 --- a/reactos/ntoskrnl/ex/power.c +++ b/reactos/ntoskrnl/ex/power.c @@ -153,7 +153,7 @@ ShutdownThreadMain(PVOID Context) sizeof(PCH))]); } - PiShutdownProcessManager(); + PspShutdownProcessManager(); Waittime.QuadPart = (LONGLONG)-10000000; /* 1sec */ KeDelayExecutionThread(KernelMode, FALSE, &Waittime); diff --git a/reactos/ntoskrnl/include/internal/dbgk.h b/reactos/ntoskrnl/include/internal/dbgk.h index d50b48f38ea..a1a622674da 100644 --- a/reactos/ntoskrnl/include/internal/dbgk.h +++ b/reactos/ntoskrnl/include/internal/dbgk.h @@ -5,6 +5,21 @@ VOID STDCALL DbgkCreateThread(PVOID StartAddress); +VOID +NTAPI +DbgkExitProcess(IN NTSTATUS ExitStatus); + +VOID +NTAPI +DbgkExitThread(IN NTSTATUS ExitStatus); + +VOID +NTAPI +DbgkCopyProcessDebugPort( + IN PEPROCESS Process, + IN PEPROCESS Parent +); + #endif /* EOF */ diff --git a/reactos/ntoskrnl/include/internal/ke.h b/reactos/ntoskrnl/include/internal/ke.h index 65a450c4435..b45333f78df 100644 --- a/reactos/ntoskrnl/include/internal/ke.h +++ b/reactos/ntoskrnl/include/internal/ke.h @@ -498,7 +498,8 @@ ULONG STDCALL KeSetProcess( struct _KPROCESS* Process, - KPRIORITY Increment + KPRIORITY Increment, + BOOLEAN InWait ); VOID diff --git a/reactos/ntoskrnl/include/internal/lpc.h b/reactos/ntoskrnl/include/internal/lpc.h index 5755fd27144..af40b0e14d0 100644 --- a/reactos/ntoskrnl/include/internal/lpc.h +++ b/reactos/ntoskrnl/include/internal/lpc.h @@ -88,7 +88,7 @@ LpcSendTerminationPort( LARGE_INTEGER CreationTime ); -/* Code in ntoskrnl/lpc/close.h */ +/* Code in ntoskrnl/lpc/close.c */ VOID STDCALL @@ -104,6 +104,10 @@ VOID STDCALL LpcpDeletePort(IN PVOID ObjectBody); +VOID +NTAPI +LpcExitThread(IN PETHREAD Thread); + /* Code in ntoskrnl/lpc/queue.c */ VOID diff --git a/reactos/ntoskrnl/include/internal/mm.h b/reactos/ntoskrnl/include/internal/mm.h index 4829e24a4bc..9b9de19c6b5 100644 --- a/reactos/ntoskrnl/include/internal/mm.h +++ b/reactos/ntoskrnl/include/internal/mm.h @@ -619,7 +619,7 @@ MmShowOutOfSpaceMessagePagingFile(VOID); NTSTATUS STDCALL MmCreateProcessAddressSpace( - IN struct _EPROCESS* Process, + IN PEPROCESS Process, IN PROS_SECTION_OBJECT Section OPTIONAL ); @@ -627,7 +627,7 @@ NTSTATUS STDCALL MmCreatePeb(struct _EPROCESS *Process); -struct _TEB* +PTEB STDCALL MmCreateTeb( struct _EPROCESS *Process, @@ -639,9 +639,21 @@ VOID STDCALL MmDeleteTeb( struct _EPROCESS *Process, - struct _TEB* Teb + PTEB Teb ); +VOID +NTAPI +MmCleanProcessAddressSpace(IN PEPROCESS Process); + +NTSTATUS +NTAPI +MmDeleteProcessAddressSpace(IN PEPROCESS Process); + +ULONG +NTAPI +MmGetSessionLocaleId(VOID); + /* i386/pfault.c *************************************************************/ NTSTATUS diff --git a/reactos/ntoskrnl/include/internal/ntoskrnl.h b/reactos/ntoskrnl/include/internal/ntoskrnl.h index 65b6e2b7c9a..4cfbc4f0e06 100644 --- a/reactos/ntoskrnl/include/internal/ntoskrnl.h +++ b/reactos/ntoskrnl/include/internal/ntoskrnl.h @@ -101,6 +101,26 @@ InterlockedAnd(IN OUT LONG volatile *Target, return j; } +FORCEINLINE +LONG +InterlockedOr(IN OUT LONG volatile *Target, + IN LONG Set) +{ + LONG i; + LONG j; + + j = *Target; + do { + i = j; + j = InterlockedCompareExchange((PLONG)Target, + i | Set, + i); + + } while (i != j); + + return j; +} + /* * generic information class probing code */ diff --git a/reactos/ntoskrnl/include/internal/ob.h b/reactos/ntoskrnl/include/internal/ob.h index 275d14f6560..f1af06233a6 100644 --- a/reactos/ntoskrnl/include/internal/ob.h +++ b/reactos/ntoskrnl/include/internal/ob.h @@ -198,6 +198,17 @@ ObpReapObject( IN PVOID Unused ); +VOID +NTAPI +ObDereferenceDeviceMap(IN PEPROCESS Process); + +VOID +NTAPI +ObInheritDeviceMap( + IN PEPROCESS Parent, + IN PEPROCESS Process +); + VOID FASTCALL ObpSetPermanentObject( @@ -211,9 +222,12 @@ ObpDeleteNameCheck( IN PVOID Object ); -// -// Security functions -// +VOID +NTAPI +ObClearProcessHandleTable(IN PEPROCESS Process); + +/* Security descriptor cache functions */ + NTSTATUS NTAPI ObpInitSdCache( diff --git a/reactos/ntoskrnl/include/internal/po.h b/reactos/ntoskrnl/include/internal/po.h index dccdf8cc4f9..a96f8a51fde 100644 --- a/reactos/ntoskrnl/include/internal/po.h +++ b/reactos/ntoskrnl/include/internal/po.h @@ -14,4 +14,8 @@ NTSTATUS NTAPI PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState); +VOID +NTAPI +PopCleanupPowerState(IN PPOWER_STATE PowerState); + #endif /* __NTOSKRNL_INCLUDE_INTERNAL_PO_H */ diff --git a/reactos/ntoskrnl/include/internal/ps.h b/reactos/ntoskrnl/include/internal/ps.h index e6968884579..76137d648af 100644 --- a/reactos/ntoskrnl/include/internal/ps.h +++ b/reactos/ntoskrnl/include/internal/ps.h @@ -40,7 +40,7 @@ PiInitProcessManager(VOID); VOID NTAPI -PiShutdownProcessManager(VOID); +PspShutdownProcessManager(VOID); VOID NTAPI @@ -172,6 +172,13 @@ PspAssignPrimaryToken( HANDLE TokenHandle ); +PETHREAD +NTAPI +PsGetNextProcessThread( + IN PEPROCESS Process, + IN PETHREAD Thread OPTIONAL +); + VOID STDCALL PsExitSpecialApc( @@ -218,14 +225,15 @@ VOID STDCALL PspExitThread(NTSTATUS ExitStatus); -VOID +NTSTATUS STDCALL PspTerminateThreadByPointer( PETHREAD Thread, - NTSTATUS ExitStatus + NTSTATUS ExitStatus, + BOOLEAN bSelf ); -VOID +NTSTATUS NTAPI PsUnfreezeOtherThread(PETHREAD Thread); @@ -287,9 +295,10 @@ VOID NTAPI PsInitialiseSuspendImplementation(VOID); -NTSTATUS +VOID STDCALL -PspExitProcess(PEPROCESS Process); +PspExitProcess(BOOLEAN LastThread, + PEPROCESS Process); VOID STDCALL @@ -376,4 +385,34 @@ VOID NTAPI PsUnlockProcess(PEPROCESS Process); +VOID +NTAPI +PspRemoveProcessFromJob( + IN PEPROCESS Process, + IN PEJOB Job +); + +NTSTATUS +NTAPI +PspDeleteLdt(IN PEPROCESS Process); + +NTSTATUS +NTAPI +PspDeleteVdmObjects(IN PEPROCESS Process); + +VOID +NTAPI +PspDeleteProcessSecurity(IN PEPROCESS Process); + +VOID +NTAPI +PspDeleteThreadSecurity(IN PETHREAD Thread); + +VOID +NTAPI +PspExitProcessFromJob( + IN PEJOB Job, + IN PEPROCESS Process +); + #endif /* __INCLUDE_INTERNAL_PS_H */ diff --git a/reactos/ntoskrnl/include/internal/se.h b/reactos/ntoskrnl/include/internal/se.h index 3dc8c062bf9..b6808d3c208 100644 --- a/reactos/ntoskrnl/include/internal/se.h +++ b/reactos/ntoskrnl/include/internal/se.h @@ -136,6 +136,14 @@ PTOKEN STDCALL SepCreateSystemProcessToken(VOID); +BOOLEAN +NTAPI +SeDetailedAuditingWithToken(IN PTOKEN Token); + +VOID +NTAPI +SeAuditProcessExit(IN PEPROCESS Process); + NTSTATUS NTAPI SeExchangePrimaryToken( diff --git a/reactos/ntoskrnl/include/internal/tag.h b/reactos/ntoskrnl/include/internal/tag.h index d7657d295cc..01e32c460de 100644 --- a/reactos/ntoskrnl/include/internal/tag.h +++ b/reactos/ntoskrnl/include/internal/tag.h @@ -156,4 +156,7 @@ #define TAG_LPC_MESSAGE TAG('L', 'p', 'c', 'M') #define TAG_LPC_ZONE TAG('L', 'p', 'c', 'Z') +/* Se Process Audit */ +#define TAG_SEPA TAG('S', 'e', 'P', 'a') + #endif /* _NTOSKRNL_TAG_H */ diff --git a/reactos/ntoskrnl/ke/kthread.c b/reactos/ntoskrnl/ke/kthread.c index 145e6b65dff..073462f4388 100644 --- a/reactos/ntoskrnl/ke/kthread.c +++ b/reactos/ntoskrnl/ke/kthread.c @@ -22,7 +22,7 @@ extern EX_WORK_QUEUE ExWorkerQueue[MaximumWorkQueue]; LIST_ENTRY PriorityListHead[MAXIMUM_PRIORITY]; static ULONG PriorityListMask = 0; ULONG IdleProcessorMask = 0; -extern PETHREAD PspReaperList; +extern LIST_ENTRY PspReaperListHead; /* FUNCTIONS *****************************************************************/ @@ -1383,34 +1383,56 @@ KeTerminateThread(IN KPRIORITY Increment) { KIRQL OldIrql; PKTHREAD Thread = KeGetCurrentThread(); + PKPROCESS Process = Thread->ApcState.Process; + PLIST_ENTRY *ListHead; + PETHREAD Entry, SavedEntry; + PETHREAD *ThreadAddr; + DPRINT("Terminating\n"); /* Lock the Dispatcher Database and the APC Queue */ - DPRINT("Terminating\n"); + ASSERT_IRQL(DISPATCH_LEVEL); OldIrql = KeAcquireDispatcherDatabaseLock(); + ASSERT(Thread->SwapBusy == FALSE); - /* Remove the thread from the list */ - RemoveEntryList(&Thread->ThreadListEntry); + /* Make sure we won't get Swapped */ + Thread->SwapBusy = TRUE; + + /* Save the Kernel and User Times */ + Process->KernelTime += Thread->KernelTime; + Process->UserTime += Thread->UserTime; + + /* Get the current entry and our Port */ + Entry = (PETHREAD)PspReaperListHead.Flink; + ThreadAddr = &((PETHREAD)Thread)->ReaperLink; + + /* Add it to the reaper's list */ + do + { + /* Get the list head */ + ListHead = &PspReaperListHead.Flink; + + /* Link ourselves */ + *ThreadAddr = Entry; + SavedEntry = Entry; - /* Insert into the Reaper List */ - DPRINT("List: %p\n", PspReaperList); - ((PETHREAD)Thread)->ReaperLink = PspReaperList; - PspReaperList = (PETHREAD)Thread; - DPRINT("List: %p\n", PspReaperList); + /* Now try to do the exchange */ + Entry = InterlockedCompareExchangePointer(ListHead, ThreadAddr, Entry); - /* Check if it's active */ - if (PspReaping == FALSE) { + /* Break out if the change was succesful */ + } while (Entry != SavedEntry); - /* Activate it. We use the internal function for speed, and use the Hyper Critical Queue */ - PspReaping = TRUE; - DPRINT("Terminating\n"); + /* Check if the reaper wasn't active */ + if (!Entry) + { + /* Activate it as a work item, directly through its Queue */ KiInsertQueue(&ExWorkerQueue[HyperCriticalWorkQueue].WorkerQueue, &PspReaperWorkItem.List, FALSE); } /* Handle Kernel Queues */ - if (Thread->Queue) { - + if (Thread->Queue) + { DPRINT("Waking Queue\n"); RemoveEntryList(&Thread->QueueListEntry); KiWakeQueue(Thread->Queue); @@ -1418,12 +1440,19 @@ KeTerminateThread(IN KPRIORITY Increment) /* Signal the thread */ Thread->DispatcherHeader.SignalState = TRUE; - if (IsListEmpty(&Thread->DispatcherHeader.WaitListHead) != TRUE) { - + if (IsListEmpty(&Thread->DispatcherHeader.WaitListHead) != TRUE) + { /* Satisfy waits */ KiWaitTest((PVOID)Thread, Increment); } + /* Remove the thread from the list */ + RemoveEntryList(&Thread->ThreadListEntry); + + /* Set us as terminated, decrease the Process's stack count */ + Thread->State = Terminated; + Process->StackCount--; + /* Find a new Thread */ KiDispatchThreadNoLock(Terminated); } diff --git a/reactos/ntoskrnl/ke/process.c b/reactos/ntoskrnl/ke/process.c index 8631d2fc47d..e1360511eb2 100644 --- a/reactos/ntoskrnl/ke/process.c +++ b/reactos/ntoskrnl/ke/process.c @@ -145,7 +145,8 @@ KeInitializeProcess(PKPROCESS Process, ULONG NTAPI KeSetProcess(PKPROCESS Process, - KPRIORITY Increment) + KPRIORITY Increment, + BOOLEAN InWait) { KIRQL OldIrql; ULONG OldState; diff --git a/reactos/ntoskrnl/lpc/close.c b/reactos/ntoskrnl/lpc/close.c index 00516454bd3..b74f5015675 100644 --- a/reactos/ntoskrnl/lpc/close.c +++ b/reactos/ntoskrnl/lpc/close.c @@ -16,6 +16,24 @@ /* FUNCTIONS *****************************************************************/ +VOID +NTAPI +LpcExitThread(IN PETHREAD Thread) +{ + /* Make sure that the Reply Chain is empty */ + if (!IsListEmpty(&Thread->LpcReplyChain)) + { + /* It's not, remove the entry */ + RemoveEntryList(&Thread->LpcReplyChain); + } + + /* Set the thread in exit mode */ + Thread->LpcExitThreadCalled = TRUE; + Thread->LpcReplyMessageId = 0; + + /* FIXME: Reply to the LpcReplyMessage */ +} + /********************************************************************** * NAME * diff --git a/reactos/ntoskrnl/lpc/send.c b/reactos/ntoskrnl/lpc/send.c index 8725e56d544..e5641da0310 100644 --- a/reactos/ntoskrnl/lpc/send.c +++ b/reactos/ntoskrnl/lpc/send.c @@ -15,37 +15,6 @@ #define NDEBUG #include - -/********************************************************************** - * NAME - * LpcSendTerminationPort/2 - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * - * REVISIONS - */ -NTSTATUS STDCALL -LpcSendTerminationPort (IN PEPORT Port, - IN LARGE_INTEGER CreateTime) -{ - NTSTATUS Status; - CLIENT_DIED_MSG Msg; - -#ifdef __USE_NT_LPC__ - Msg.h.u2.s2.Type = LPC_CLIENT_DIED; -#endif - Msg.h.u1.s1.TotalLength = sizeof(Msg); - Msg.h.u1.s1.DataLength = sizeof(Msg) - sizeof(PORT_MESSAGE); - Msg.CreateTime = CreateTime; - Status = LpcRequestPort (Port, &Msg.h); - return(Status); -} - - /********************************************************************** * NAME * LpcSendDebugMessagePort/3 diff --git a/reactos/ntoskrnl/mm/mm.c b/reactos/ntoskrnl/mm/mm.c index 1cec79d3641..9d9e342df35 100644 --- a/reactos/ntoskrnl/mm/mm.c +++ b/reactos/ntoskrnl/mm/mm.c @@ -22,66 +22,12 @@ ULONG MmUserProbeAddress = 0; PVOID MmHighestUserAddress = NULL; PBOOLEAN Mm64BitPhysicalAddress = FALSE; PVOID MmSystemRangeStart = NULL; +ULONG MmReadClusterSize; MM_STATS MmStats; /* FUNCTIONS ****************************************************************/ - -NTSTATUS -NTAPI -MmReleaseMmInfo(PEPROCESS Process) -{ - PVOID Address; - PMEMORY_AREA MemoryArea; - - DPRINT("MmReleaseMmInfo(Process %x (%s))\n", Process, - Process->ImageFileName); - - MmLockAddressSpace((PMADDRESS_SPACE)&Process->VadRoot); - - while ((MemoryArea = ((PMADDRESS_SPACE)&Process->VadRoot)->MemoryAreaRoot) != NULL) - { - switch (MemoryArea->Type) - { - case MEMORY_AREA_SECTION_VIEW: - Address = (PVOID)MemoryArea->StartingAddress; - MmUnlockAddressSpace((PMADDRESS_SPACE)&Process->VadRoot); - MmUnmapViewOfSection((PEPROCESS)Process, Address); - MmLockAddressSpace((PMADDRESS_SPACE)&Process->VadRoot); - break; - - case MEMORY_AREA_VIRTUAL_MEMORY: - case MEMORY_AREA_PEB_OR_TEB: - MmFreeVirtualMemory(Process, MemoryArea); - break; - - case MEMORY_AREA_SHARED_DATA: - case MEMORY_AREA_NO_ACCESS: - MmFreeMemoryArea((PMADDRESS_SPACE)&Process->VadRoot, - MemoryArea, - NULL, - NULL); - break; - - case MEMORY_AREA_MDL_MAPPING: - KEBUGCHECK(PROCESS_HAS_LOCKED_PAGES); - break; - - default: - KEBUGCHECK(0); - } - } - - Mmi386ReleaseMmInfo(Process); - - MmUnlockAddressSpace((PMADDRESS_SPACE)&Process->VadRoot); - MmDestroyAddressSpace((PMADDRESS_SPACE)&Process->VadRoot); - - DPRINT("Finished MmReleaseMmInfo()\n"); - return(STATUS_SUCCESS); -} - /* * @implemented */ diff --git a/reactos/ntoskrnl/mm/process.c b/reactos/ntoskrnl/mm/process.c index c88c45dae4a..7b54aa9833e 100644 --- a/reactos/ntoskrnl/mm/process.c +++ b/reactos/ntoskrnl/mm/process.c @@ -23,6 +23,33 @@ extern ULONG NtGlobalFlag; /* FUNCTIONS *****************************************************************/ +LCID +NTAPI +MmGetSessionLocaleId(VOID) +{ + PEPROCESS Process; + PAGED_CODE(); + + /* Get the current process */ + Process = PsGetCurrentProcess(); + + /* Check if it's the Session Leader */ + if (Process->Vm.Flags.SessionLeader) + { + /* Make sure it has a valid Session */ + if (Process->Session) + { + /* Get the Locale ID */ +#if ROS_HAS_SESSIONS + return ((PMM_SESSION_SPACE)Process->Session)->LocaleId; +#endif + } + } + + /* Not a session leader, return the default */ + return PsDefaultThreadLocaleId; +} + PVOID STDCALL MiCreatePebOrTeb(PEPROCESS Process, @@ -489,6 +516,9 @@ MmCreateProcessAddressSpace(IN PEPROCESS Process, goto exit; } + /* The process now has an address space */ + Process->HasAddressSpace = TRUE; + /* Check if there's a Section Object */ if (Section) { @@ -559,3 +589,64 @@ exit: /* Return status to caller */ return Status; } + +VOID +NTAPI +MmCleanProcessAddressSpace(IN PEPROCESS Process) +{ + /* FIXME: Add part of MmDeleteProcessAddressSpace here */ +} + +NTSTATUS +NTAPI +MmDeleteProcessAddressSpace(PEPROCESS Process) +{ + PVOID Address; + PMEMORY_AREA MemoryArea; + + DPRINT("MmDeleteProcessAddressSpace(Process %x (%s))\n", Process, + Process->ImageFileName); + + MmLockAddressSpace((PMADDRESS_SPACE)&Process->VadRoot); + + while ((MemoryArea = ((PMADDRESS_SPACE)&Process->VadRoot)->MemoryAreaRoot) != NULL) + { + switch (MemoryArea->Type) + { + case MEMORY_AREA_SECTION_VIEW: + Address = (PVOID)MemoryArea->StartingAddress; + MmUnlockAddressSpace((PMADDRESS_SPACE)&Process->VadRoot); + MmUnmapViewOfSection(Process, Address); + MmLockAddressSpace((PMADDRESS_SPACE)&Process->VadRoot); + break; + + case MEMORY_AREA_VIRTUAL_MEMORY: + case MEMORY_AREA_PEB_OR_TEB: + MmFreeVirtualMemory(Process, MemoryArea); + break; + + case MEMORY_AREA_SHARED_DATA: + case MEMORY_AREA_NO_ACCESS: + MmFreeMemoryArea((PMADDRESS_SPACE)&Process->VadRoot, + MemoryArea, + NULL, + NULL); + break; + + case MEMORY_AREA_MDL_MAPPING: + KEBUGCHECK(PROCESS_HAS_LOCKED_PAGES); + break; + + default: + KEBUGCHECK(0); + } + } + + Mmi386ReleaseMmInfo(Process); + + MmUnlockAddressSpace((PMADDRESS_SPACE)&Process->VadRoot); + MmDestroyAddressSpace((PMADDRESS_SPACE)&Process->VadRoot); + + DPRINT("Finished MmReleaseMmInfo()\n"); + return(STATUS_SUCCESS); +} diff --git a/reactos/ntoskrnl/ntoskrnl.mc b/reactos/ntoskrnl/ntoskrnl.mc index 12987c73379..f10792278c0 100644 --- a/reactos/ntoskrnl/ntoskrnl.mc +++ b/reactos/ntoskrnl/ntoskrnl.mc @@ -979,6 +979,14 @@ Language=English SPIN_LOCK_INIT_FAILURE . +MessageId=0x94 +Severity=Success +Facility=System +SymbolicName=KERNEL_STACK_LOCKED_AT_EXIT +Language=English +KERNEL_STACK_LOCKED_AT_EXIT +. + MessageId=0x96 Severity=Success Facility=System @@ -1085,6 +1093,23 @@ Language=English certain\n conditions. There is absolutely no warranty for ReactOS.\n . +MessageId=0xE9 +Severity=Success +Facility=System +SymbolicName=ACTIVE_EX_WORKER_THREAD_TERMINATION +Language=English +ACTIVE_EX_WORKER_THREAD_TERMINATION +. + +MessageId=0xEF +Severity=Success +Facility=System +SymbolicName=CRITICAL_PROCESS_DIED +Language=English +CRITICAL_PROCESS_DIED +. + + MessageId=0xFC Severity=Success Facility=System diff --git a/reactos/ntoskrnl/ob/obhandle.c b/reactos/ntoskrnl/ob/obhandle.c index ce4adff43b9..c7088db1365 100644 --- a/reactos/ntoskrnl/ob/obhandle.c +++ b/reactos/ntoskrnl/ob/obhandle.c @@ -244,7 +244,7 @@ ObpCloseHandleTableEntry(IN PHANDLE_TABLE HandleTable, // // WE DONT CLOSE REGISTRY HANDLES BECAUSE CM IS BRAINDEAD // - DPRINT1("NOT CLOSING THE KEY\n"); + DPRINT("NOT CLOSING THE KEY\n"); } else { @@ -1119,6 +1119,13 @@ ObpDuplicateHandleCallback(IN PHANDLE_TABLE HandleTable, return Ret; } +VOID +NTAPI +ObClearProcessHandleTable(IN PEPROCESS Process) +{ + /* FIXME */ +} + /*++ * @name ObpCreateHandleTable * diff --git a/reactos/ntoskrnl/ob/obname.c b/reactos/ntoskrnl/ob/obname.c index a670238e1a6..6ab686164af 100644 --- a/reactos/ntoskrnl/ob/obname.c +++ b/reactos/ntoskrnl/ob/obname.c @@ -11,6 +11,7 @@ /* INCLUDES ******************************************************************/ +#define NTDDI_VERSION NTDDI_WINXP #include #define NDEBUG #include @@ -20,6 +21,49 @@ POBJECT_DIRECTORY ObpTypeDirectoryObject = NULL; /* PRIVATE FUNCTIONS *********************************************************/ +VOID +NTAPI +ObDereferenceDeviceMap(IN PEPROCESS Process) +{ + //KIRQL OldIrql; + PDEVICE_MAP DeviceMap = Process->DeviceMap; + + /* FIXME: We don't use Process Devicemaps yet */ + if (DeviceMap) + { + /* FIXME: Acquire the DeviceMap Spinlock */ + // KeAcquireSpinLock(DeviceMap->Lock, &OldIrql); + + /* Delete the device map link and dereference it */ + Process->DeviceMap = NULL; + if (--DeviceMap->ReferenceCount) + { + /* Nobody is referencing it anymore, unlink the DOS directory */ + DeviceMap->DosDevicesDirectory->DeviceMap = NULL; + + /* FIXME: Release the DeviceMap Spinlock */ + // KeReleasepinLock(DeviceMap->Lock, OldIrql); + + /* Dereference the DOS Devices Directory and free the Device Map */ + ObDereferenceObject(DeviceMap->DosDevicesDirectory); + ExFreePool(DeviceMap); + } + else + { + /* FIXME: Release the DeviceMap Spinlock */ + // KeReleasepinLock(DeviceMap->Lock, OldIrql); + } + } +} + +VOID +NTAPI +ObInheritDeviceMap(IN PEPROCESS Parent, + IN PEPROCESS Process) +{ + /* FIXME: Devicemap Support */ +} + /*++ * @name ObpDeleteNameCheck * diff --git a/reactos/ntoskrnl/ob/obref.c b/reactos/ntoskrnl/ob/obref.c index 7d61b226dfe..b09affdd24f 100644 --- a/reactos/ntoskrnl/ob/obref.c +++ b/reactos/ntoskrnl/ob/obref.c @@ -90,7 +90,7 @@ ObfDereferenceObject(IN PVOID Object) if (Header->PointerCount < Header->HandleCount) { - DPRINT1("Misbehaving object: %wZ\n", &Header->Type->Name); + DPRINT("Misbehaving object: %wZ\n", &Header->Type->Name); return; } @@ -100,7 +100,7 @@ ObfDereferenceObject(IN PVOID Object) /* Sanity check */ if (Header->HandleCount) { - DPRINT1("Misbehaving object: %wZ\n", &Header->Type->Name); + DPRINT("Misbehaving object: %wZ\n", &Header->Type->Name); return; } diff --git a/reactos/ntoskrnl/po/power.c b/reactos/ntoskrnl/po/power.c index 18aef5d8175..a5babbe1e2d 100644 --- a/reactos/ntoskrnl/po/power.c +++ b/reactos/ntoskrnl/po/power.c @@ -183,6 +183,13 @@ PoSetDeviceBusy( { } +VOID +NTAPI +PopCleanupPowerState(IN PPOWER_STATE PowerState) +{ + /* FIXME */ +} + /* * @unimplemented */ diff --git a/reactos/ntoskrnl/ps/job.c b/reactos/ntoskrnl/ps/job.c index 9c59db7a43f..fe53a04962c 100644 --- a/reactos/ntoskrnl/ps/job.c +++ b/reactos/ntoskrnl/ps/job.c @@ -4,16 +4,14 @@ * PROJECT: ReactOS kernel * FILE: ntoskrnl/ps/job.c * PURPOSE: Job Native Functions - * * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) (stubs) * Thomas Weidenmueller */ -/* Note: Jobs are only supported on Win2K+ */ /* INCLUDES *****************************************************************/ -#define NDEBUG #include +#define NDEBUG #include #if defined (ALLOC_PRAGMA) @@ -39,7 +37,8 @@ static GENERIC_MAPPING PiJobMapping = /* FUNCTIONS *****************************************************************/ -VOID STDCALL +VOID +NTAPI PiDeleteJob ( PVOID ObjectBody ) { PEJOB Job = (PEJOB)ObjectBody; @@ -89,8 +88,7 @@ PsInitJobManagment ( VOID ) NTSTATUS NTAPI -PspAssignProcessToJob ( - PEPROCESS Process, +PspAssignProcessToJob(PEPROCESS Process, PEJOB Job) { DPRINT("PspAssignProcessToJob() is unimplemented!\n"); @@ -99,8 +97,7 @@ PspAssignProcessToJob ( NTSTATUS NTAPI -PspTerminateJobObject ( - PEJOB Job, +PspTerminateJobObject(PEJOB Job, KPROCESSOR_MODE AccessMode, NTSTATUS ExitStatus ) { @@ -108,6 +105,21 @@ PspTerminateJobObject ( return STATUS_NOT_IMPLEMENTED; } +VOID +NTAPI +PspRemoveProcessFromJob(IN PEPROCESS Process, + IN PEJOB Job) +{ + /* FIXME */ +} + +VOID +NTAPI +PspExitProcessFromJob(IN PEJOB Job, + IN PEPROCESS Process) +{ + /* FIXME */ +} /* * @unimplemented @@ -547,8 +559,7 @@ PsGetJobUIRestrictionsClass ( PEJOB Job ) */ VOID STDCALL -PsSetJobUIRestrictionsClass ( - PEJOB Job, +PsSetJobUIRestrictionsClass(PEJOB Job, ULONG UIRestrictionsClass) { ASSERT(Job); diff --git a/reactos/ntoskrnl/ps/kill.c b/reactos/ntoskrnl/ps/kill.c index 518b78beccb..58c0828cdbe 100644 --- a/reactos/ntoskrnl/ps/kill.c +++ b/reactos/ntoskrnl/ps/kill.c @@ -1,11 +1,11 @@ /* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory * FILE: ntoskrnl/ps/kill.c - * PURPOSE: Thread Termination and Reaping - * - * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - * David Welch (welch@cwcom.net) + * PURPOSE: Process Manager: Process and Thread Termination + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + * Filip Navara (xnavara@reactos.org) + * Thomas Weidenmueller (w3seek@reactos.org */ /* INCLUDES *****************************************************************/ @@ -21,188 +21,297 @@ /* GLOBALS *******************************************************************/ -PETHREAD PspReaperList = NULL; +LIST_ENTRY PspReaperListHead = {0}; WORK_QUEUE_ITEM PspReaperWorkItem; -BOOLEAN PspReaping = FALSE; extern LIST_ENTRY PsActiveProcessHead; extern FAST_MUTEX PspActiveProcessMutex; extern PHANDLE_TABLE PspCidTable; +extern PKWIN32_PROCESS_CALLOUT PspW32ProcessCallout; +extern PKWIN32_THREAD_CALLOUT PspW32ThreadCallout; +extern PEPROCESS PsInitialSystemProcess; +extern PEPROCESS PsIdleProcess; /* FUNCTIONS *****************************************************************/ -VOID -STDCALL -PspReapRoutine(PVOID Context) +NTSTATUS +NTAPI +PspTerminateProcess(IN PEPROCESS Process, + IN NTSTATUS ExitStatus) { - KIRQL OldIrql; - PETHREAD Thread, NewThread; - - /* Acquire lock */ - DPRINT("Evil reaper running!!\n"); - OldIrql = KeAcquireDispatcherDatabaseLock(); - - /* Get the first Thread Entry */ - Thread = PspReaperList; - PspReaperList = NULL; - DPRINT("PspReaperList: %x\n", Thread); - - /* Check to see if the list is empty */ - do { - - /* Unlock the Dispatcher */ - KeReleaseDispatcherDatabaseLock(OldIrql); - - /* Is there a thread on the list? */ - while (Thread) { + PAGED_CODE(); + PETHREAD Thread = NULL; - /* Get the next Thread */ - DPRINT("Thread: %x\n", Thread); - DPRINT("Thread: %x\n", Thread->ReaperLink); - NewThread = Thread->ReaperLink; + /* Check if this is a Critical Process, and Bugcheck */ + if (Process->BreakOnTermination) + { + /* FIXME: Add critical Process support */ + DPRINT1("A critical Process is being terminated\n"); + KEBUGCHECK(0); + } - /* Remove reference to current thread */ - ObDereferenceObject(Thread); + /* Set the delete flag */ + InterlockedOr(&Process->Flags, 8); - /* Move to next Thread */ - Thread = NewThread; + /* Get the first thread */ + while ((Thread = PsGetNextProcessThread(Process, Thread))) + { + /* Kill it */ + PspTerminateThreadByPointer(Thread, ExitStatus, FALSE); } - /* No more linked threads... Reacquire the Lock */ - OldIrql = KeAcquireDispatcherDatabaseLock(); - - /* Now try to get a new thread from the list */ - Thread = PspReaperList; - PspReaperList = NULL; - DPRINT("PspReaperList: %x\n", Thread); + /* Clear the handle table */ + ObClearProcessHandleTable(Process); - /* Loop again if there is a new thread */ - } while (Thread); - - PspReaping = FALSE; - DPRINT("Done reaping\n"); - KeReleaseDispatcherDatabaseLock(OldIrql); + /* Return success*/ + return STATUS_SUCCESS; } VOID -STDCALL -PspKillMostProcesses(VOID) +NTAPI +PspShutdownProcessManager(VOID) { - PLIST_ENTRY current_entry; - PEPROCESS current; - - ASSERT(PsGetCurrentProcessId() == PsInitialSystemProcess->UniqueProcessId); + PEPROCESS Process = NULL; - /* Acquire the Active Process Lock */ - ExAcquireFastMutex(&PspActiveProcessMutex); - - /* Loop all processes on the list */ - current_entry = PsActiveProcessHead.Flink; - while (current_entry != &PsActiveProcessHead) + /* Loop every process */ + while ((Process == PsGetNextProcess(Process))) { - current = CONTAINING_RECORD(current_entry, EPROCESS, ActiveProcessLinks); - current_entry = current_entry->Flink; - - if (current->UniqueProcessId != PsInitialSystemProcess->UniqueProcessId) + /* Make sure this isn't the idle or initial process */ + if ((Process != PsInitialSystemProcess) && (Process != PsIdleProcess)) { - /* Terminate all the Threads in this Process */ - PspTerminateProcessThreads(current, STATUS_SUCCESS); + /* Kill it */ + PspTerminateProcess(Process, STATUS_SYSTEM_SHUTDOWN); } } +} - /* Release the lock */ - ExReleaseFastMutex(&PspActiveProcessMutex); +VOID +NTAPI +PspExitApcRundown(IN PKAPC Apc) +{ + PAGED_CODE(); + + /* Free the APC */ + ExFreePool(Apc); } VOID -STDCALL -PspTerminateProcessThreads(PEPROCESS Process, - NTSTATUS ExitStatus) +NTAPI +PspReapRoutine(PVOID Context) { - PLIST_ENTRY CurrentEntry; - PETHREAD Thread, CurrentThread = PsGetCurrentThread(); + PLIST_ENTRY *ListAddr; + PLIST_ENTRY NextEntry; + PETHREAD Thread; - CurrentEntry = Process->ThreadListHead.Flink; - while (CurrentEntry != &Process->ThreadListHead) { + /* Get the Reaper Address Pointer */ + ListAddr = &PspReaperListHead.Flink; - /* Get the Current Thread */ - Thread = CONTAINING_RECORD(CurrentEntry, ETHREAD, ThreadListEntry); + /* Start main loop */ + do + { + /* Write magic value and return the next entry to process */ + NextEntry = InterlockedExchangePointer(ListAddr, (PVOID)1); + ASSERT((NextEntry != NULL) && (NextEntry != (PVOID)1)); - /* Move to the Next Thread */ - CurrentEntry = CurrentEntry->Flink; + /* Start inner loop */ + do + { + /* Get the first Thread Entry */ + Thread = CONTAINING_RECORD(NextEntry, ETHREAD, ReaperLink); - /* Make sure it's not the one we're in */ - if (Thread != CurrentThread) { + /* Delete this entry's kernel stack */ + MmDeleteKernelStack((PVOID)Thread->Tcb.StackLimit, + Thread->Tcb.LargeStack); + Thread->Tcb.InitialStack = NULL; - /* Make sure it didn't already terminate */ - if (!Thread->Terminated) { + /* Move to the next entry */ + NextEntry = NextEntry->Flink; - Thread->Terminated = TRUE; + /* Dereference this thread */ + ObDereferenceObject(Thread); + } while ((NextEntry != NULL) && (NextEntry != (PVOID)1)); - /* Terminate it by APC */ - PspTerminateThreadByPointer(Thread, ExitStatus); - } - } - } + /* Remove magic value, keep looping if it got changed */ + } while (InterlockedCompareExchangePointer(ListAddr, 0, 1) != (PVOID)1); } VOID -STDCALL +NTAPI PspDeleteProcess(PVOID ObjectBody) { PEPROCESS Process = (PEPROCESS)ObjectBody; + KAPC_STATE ApcState; + DPRINT1("PspDeleteProcess(ObjectBody %x)\n", ObjectBody); + PAGED_CODE(); + DPRINT1("Name: %.16s\n", &Process->ImageFileName); - DPRINT("PiDeleteProcess(ObjectBody %x)\n", ObjectBody); - + /* Check if it has an Active Process Link */ + if (Process->ActiveProcessLinks.Flink) + { /* Remove it from the Active List */ ExAcquireFastMutex(&PspActiveProcessMutex); RemoveEntryList(&Process->ActiveProcessLinks); ExReleaseFastMutex(&PspActiveProcessMutex); + } - /* Delete the CID Handle */ - if(Process->UniqueProcessId) + /* Check for Auditing information */ + if (Process->SeAuditProcessCreationInfo.ImageFileName) + { + /* Free it */ + ExFreePool(Process->SeAuditProcessCreationInfo.ImageFileName); + Process->SeAuditProcessCreationInfo.ImageFileName = NULL; + } + + /* Check if we have a job */ + if (Process->Job) + { + /* Remove the process from the job */ + PspRemoveProcessFromJob(Process, Process->Job); + + /* Dereference it */ + ObDereferenceObject(Process->Job); + Process->Job = NULL; + } + + /* Increase the stack count */ + Process->Pcb.StackCount++; + + /* Check if we have a debug port */ + if (Process->DebugPort) { - ExDestroyHandle(PspCidTable, Process->UniqueProcessId); + /* Dererence the Debug Port */ + ObDereferenceObject(Process->DebugPort); + Process->DebugPort = NULL; } - /* Delete the process lock */ - ExFreePool(Process->LockEvent); + /* Check if we have an exception port */ + if (Process->ExceptionPort) + { + /* Dererence the Exception Port */ + ObDereferenceObject(Process->ExceptionPort); + Process->ExceptionPort = NULL; + } + + /* Check if we have a section object */ + if (Process->SectionObject) + { + /* Dererence the Section Object */ + ObDereferenceObject(Process->SectionObject); + Process->SectionObject = NULL; + } + + /* Clean LDT and VDM_OBJECTS */ + PspDeleteLdt(Process); + PspDeleteVdmObjects(Process); + + /* Delete the Object Table */ + if (Process->ObjectTable) + { + /* Attach to the process */ + KeStackAttachProcess(&Process->Pcb, &ApcState); + + /* Kill the Object Info */ + ObKillProcess(Process); + + /* Dettach */ + KeUnstackDetachProcess(&ApcState); + } /* KDB hook */ KDB_DELETEPROCESS_HOOK(Process); - /* Dereference the Token */ - SeDeassignPrimaryToken(Process); + /* Check if we have an address space, and clean it */ + if (Process->HasAddressSpace) + { + /* Attach to the process */ + KeStackAttachProcess(&Process->Pcb, &ApcState); + + /* Clean the Address Space */ + PspExitProcess(FALSE, Process); + + /* Dettach */ + KeUnstackDetachProcess(&ApcState); + + /* Completely delete the Address Space */ + MmDeleteProcessAddressSpace(Process); +} + + /* See if we have a PID */ + if(Process->UniqueProcessId) + { + /* Delete the PID */ + if (!(ExDestroyHandle(PspCidTable, Process->UniqueProcessId))) + { + /* Something wrong happened, bugcheck */ + KEBUGCHECK(CID_HANDLE_DELETION); + } + } + + /* Cleanup security information */ + PspDeleteProcessSecurity(Process); + + /* Check if we have kept information on the Working Set */ + if (Process->WorkingSetWatch) + { + /* Free it */ + ExFreePool(Process->WorkingSetWatch); + + /* And return the quota it was taking up */ + PsReturnProcessNonPagedPoolQuota(Process, 0x2000); + } - /* Release Memory Information */ - MmReleaseMmInfo(Process); + /* Dereference the Device Map */ + ObDereferenceDeviceMap(Process); - /* Delete the W32PROCESS structure if there's one associated */ - if(Process->Win32Process != NULL) ExFreePool(Process->Win32Process); + /* Destroy the Quota Block */ + PspDestroyQuotaBlock(Process); } VOID -STDCALL +NTAPI PspDeleteThread(PVOID ObjectBody) { PETHREAD Thread = (PETHREAD)ObjectBody; PEPROCESS Process = Thread->ThreadsProcess; + DPRINT1("PspDeleteThread(Thread %p, Process %p)\n", ObjectBody, Process); + PAGED_CODE(); + //ASSERT(Thread->Tcb.Win32Thread == NULL); FIXME - DPRINT("PiDeleteThread(ObjectBody 0x%x, process 0x%x)\n",ObjectBody, Thread->ThreadsProcess); - - /* Deassociate the Process */ - Thread->ThreadsProcess = NULL; + /* Check if we have a stack */ + if (Thread->Tcb.InitialStack) + { + /* Release it */ + MmDeleteKernelStack((PVOID)Thread->Tcb.StackLimit, + Thread->Tcb.LargeStack); + } /* Delete the CID Handle */ if(Thread->Cid.UniqueThread) { - ExDestroyHandle(PspCidTable, Thread->Cid.UniqueThread); + if (!(ExDestroyHandle(PspCidTable, Thread->Cid.UniqueThread))) + { + /* Something wrong happened, bugcheck */ + KEBUGCHECK(CID_HANDLE_DELETION); + } } - /* Free the W32THREAD structure if present */ - if(Thread->Tcb.Win32Thread != NULL) ExFreePool (Thread->Tcb.Win32Thread); + /* Cleanup impersionation information */ + PspDeleteThreadSecurity(Thread); + + /* Make sure the thread was inserted, before continuing */ + if (!Process) return; - /* Release the Kernel Stack */ - MmDeleteKernelStack((PVOID)Thread->Tcb.StackLimit, Thread->Tcb.LargeStack); + /* Check if the thread list is valid */ + if (Thread->ThreadListEntry.Flink) + { + /* Lock the thread's process */ + PsLockProcess(Process, FALSE); + + /* Remove us from the list */ + RemoveEntryList(&Thread->ThreadListEntry); + + /* Release the lock */ + PsUnlockProcess(Process); + } /* Dereference the Process */ ObDereferenceObject(Process); @@ -213,143 +322,364 @@ PspDeleteThread(PVOID ObjectBody) * See "Windows Internals" - Chapter 13, Page 50-53 */ VOID -STDCALL +NTAPI PspExitThread(NTSTATUS ExitStatus) { - PETHREAD CurrentThread; - BOOLEAN Last; - PEPROCESS CurrentProcess; - PTERMINATION_PORT TerminationPort; + CLIENT_DIED_MSG TerminationMsg; + NTSTATUS Status; PTEB Teb; - KIRQL oldIrql; + PEPROCESS CurrentProcess; + PETHREAD Thread; + PVOID DeallocationStack; + ULONG Dummy; + BOOLEAN Last = FALSE; + PTERMINATION_PORT TerminationPort, NextPort; PLIST_ENTRY FirstEntry, CurrentEntry; PKAPC Apc; - - DPRINT("PspExitThread(ExitStatus %x), Current: 0x%x\n", ExitStatus, PsGetCurrentThread()); + PTOKEN PrimaryToken; + PAGED_CODE(); + DPRINT1("PspExitThread(%p, %lx)\n", PsGetCurrentThread(), ExitStatus); /* Get the Current Thread and Process */ - CurrentThread = PsGetCurrentThread(); - CurrentProcess = CurrentThread->ThreadsProcess; - - /* Set the Exit Status and Exit Time */ - CurrentThread->ExitStatus = ExitStatus; - KeQuerySystemTime(&CurrentThread->ExitTime); + Thread = PsGetCurrentThread(); + CurrentProcess = Thread->ThreadsProcess; + ASSERT((Thread) == PsGetCurrentThread()); /* Can't terminate a thread if it attached another process */ - if (KeIsAttachedProcess()) { - - KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT, (ULONG) CurrentProcess, - (ULONG) CurrentThread->Tcb.ApcState.Process, - (ULONG) CurrentThread->Tcb.ApcStateIndex, - (ULONG) CurrentThread); + if (KeIsAttachedProcess()) + { + KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT, + (ULONG)CurrentProcess, + (ULONG)Thread->Tcb.ApcState.Process, + (ULONG)Thread->Tcb.ApcStateIndex, + (ULONG)Thread); } /* Lower to Passive Level */ - KeLowerIrql(PASSIVE_LEVEL); + KfLowerIrql(PASSIVE_LEVEL); + + /* Can't be a worker thread */ + if (Thread->ActiveExWorker) + { + KEBUGCHECKEX(ACTIVE_EX_WORKER_THREAD_TERMINATION, + (ULONG)Thread, + 0, + 0, + 0); + } + + /* Can't have pending APCs */ + if (Thread->Tcb.CombinedApcDisable != 0) + { + KEBUGCHECKEX(KERNEL_APC_PENDING_DURING_EXIT, + 0, + Thread->Tcb.KernelApcDisable, + APC_LEVEL, + 0); + } + + /* FIXME: Lock the thread + * ExAcquireRundownProtect(&Thread->RundownProtect); + */ + + /* Cleanup the power state */ + PopCleanupPowerState((PPOWER_STATE)&Thread->Tcb.PowerState); + + /* Call the WMI Callback for Threads */ + //WmiTraceThread(Thread, NULL, FALSE); + + /* Run Thread Notify Routines before we desintegrate the thread */ + PspRunCreateThreadNotifyRoutines(Thread, FALSE); /* Lock the Process before we modify its thread entries */ PsLockProcess(CurrentProcess, FALSE); - /* wake up the thread so we don't deadlock on PsLockProcess */ - KeForceResumeThread(&CurrentThread->Tcb); + /* Wake up the thread so we don't deadlock on PsLockProcess */ + KeForceResumeThread(&Thread->Tcb); - /* Run Thread Notify Routines before we desintegrate the thread */ - PspRunCreateThreadNotifyRoutines(CurrentThread, FALSE); + /* Decrease the active thread count, and check if it's 0 */ + if (!(--CurrentProcess->ActiveThreads)) + { + /* Set the delete flag */ + InterlockedOr(&CurrentProcess->Flags, 8); - /* Remove the thread from the thread list of its process */ - RemoveEntryList(&CurrentThread->ThreadListEntry); - Last = IsListEmpty(&CurrentProcess->ThreadListHead); + /* Remember we are last */ + Last = TRUE; - /* Set the last Thread Exit Status */ + /* Check if this termination is due to the thread dying */ + if (ExitStatus == STATUS_THREAD_IS_TERMINATING) + { + /* Check if the last thread was pending */ + if (CurrentProcess->ExitStatus == STATUS_PENDING) + { + /* Use the last exit status */ + CurrentProcess->ExitStatus = CurrentProcess->LastThreadExitStatus; + } + } + else + { + /* Just a normal exit, write the code */ + CurrentProcess->ExitStatus = ExitStatus; + } + + /* FIXME: Wait on the other threads to finish */ + } + else if (ExitStatus != STATUS_THREAD_IS_TERMINATING) + { + /* Write down the exit status of the last thread to get killed */ CurrentProcess->LastThreadExitStatus = ExitStatus; + } - if (Last) { + /* Unlock the Process */ + PsUnlockProcess(CurrentProcess); - /* Save the Exit Time if not already done by NtTerminateProcess. This - happens when the last thread just terminates without explicitly - terminating the process. */ - CurrentProcess->ExitTime = CurrentThread->ExitTime; - CurrentProcess->ExitStatus = ExitStatus; + /* Check if the process has a debug port and if this is a user thread */ + if ((CurrentProcess->DebugPort) && + !(Thread->SystemThread)) + { + /* Notify the Debug API. */ + Last ? DbgkExitProcess(CurrentProcess->ExitStatus) : + DbgkExitThread(ExitStatus); } - /* Check if the process has a debug port */ - if (CurrentProcess->DebugPort) { + /* Check if this is a Critical Thread */ + if ((KdDebuggerEnabled) && (Thread->BreakOnTermination)) + { + /* FIXME: Add critical thread support */ + KEBUGCHECK(0); + } - /* Notify the Debug API. TODO */ - //Last ? DbgkExitProcess(ExitStatus) : DbgkExitThread(ExitStatus); + /* Check if it's the last thread and this is a Critical Process */ + if ((Last) && (CurrentProcess->BreakOnTermination)) + { + /* Check if a debugger is here to handle this */ + if (KdDebuggerEnabled) + { + /* FIXME: Add critical process support */ + DbgBreakPoint(); } + else + { + /* Bugcheck, we can't allow this */ + KEBUGCHECKEX(CRITICAL_PROCESS_DIED, + (ULONG_PTR)CurrentProcess, + 0, + 0, + 0); + } + } + + /* Sanity check */ + ASSERT(Thread->Tcb.CombinedApcDisable == 0); /* Process the Termination Ports */ - while ((TerminationPort = CurrentThread->TerminationPort)) { + TerminationPort = Thread->TerminationPort; + if (TerminationPort) + { + /* Setup the message header */ + TerminationMsg.h.u2.s2.Type = LPC_CLIENT_DIED; + TerminationMsg.h.u1.s1.TotalLength = sizeof(TerminationMsg); + TerminationMsg.h.u1.s1.DataLength = sizeof(TerminationMsg) - + sizeof(PORT_MESSAGE); + + /* Loop each port */ + do + { + /* Save the Create Time */ + TerminationMsg.CreateTime = Thread->CreateTime; + +TryAgain: + /* Send the LPC Message */ + Status = LpcRequestPort(TerminationPort->Port, &TerminationMsg.h); + if ((Status == STATUS_NO_MEMORY) || + (Status == STATUS_INSUFFICIENT_RESOURCES)) + { + /* Wait a bit and try again */ + KeDelayExecutionThread(KernelMode, FALSE, &ShortPsLockDelay); + goto TryAgain; + } - DPRINT("TerminationPort: %p\n", TerminationPort); + /* Dereference this LPC Port */ + ObDereferenceObject(TerminationPort->Port); - /* Get the next one */ - CurrentThread->TerminationPort = TerminationPort->Next; + /* Move to the next one */ + NextPort = TerminationPort->Next; - /* Send the LPC Message */ - LpcSendTerminationPort(TerminationPort->Port, CurrentThread->CreateTime); - ObDereferenceObject(TerminationPort->Port); + /* Free the Termination Port Object */ + ExFreePool(TerminationPort); - /* Free the Port */ - ExFreePool(TerminationPort); + /* Keep looping as long as there is a port */ + } while ((TerminationPort = NextPort)); + } + else if (((ExitStatus == STATUS_THREAD_IS_TERMINATING) && + (Thread->DeadThread)) || + !(Thread->DeadThread)) + { + /* + * This case is special and deserves some extra comments. What + * basically happens here is that this thread doesn't have a termination + * port, which means that it died before being fully created. Since we + * still have to notify an LPC Server, we'll use the exception port, + * which we know exists. However, we need to know how far the thread + * actually got created. We have three possibilites: + * + * - NtCreateThread returned an error really early: DeadThread is set. + * - NtCreateThread managed to create the thread: DeadThread is off. + * - NtCreateThread was creating the thread (with Deadthread set, + * but the thread got killed prematurely: STATUS_THREAD_IS_TERMINATING + * is our exit code.) + * + * For the 2 & 3rd scenarios, the thread has been created far enough to + * warrant notification to the LPC Server. + */ + + /* Setup the message header */ + TerminationMsg.h.u2.s2.Type = LPC_CLIENT_DIED; + TerminationMsg.h.u1.s1.TotalLength = sizeof(TerminationMsg); + TerminationMsg.h.u1.s1.DataLength = sizeof(TerminationMsg) - + sizeof(PORT_MESSAGE); + + /* Make sure the process has an exception port */ + if (CurrentProcess->ExceptionPort) + { + /* Save the Create Time */ + TerminationMsg.CreateTime = Thread->CreateTime; + +TryAgain2: + /* Send the LPC Message */ + Status = LpcRequestPort(CurrentProcess->ExceptionPort, + &TerminationMsg.h); + if ((Status == STATUS_NO_MEMORY) || + (Status == STATUS_INSUFFICIENT_RESOURCES)) + { + /* Wait a bit and try again */ + KeDelayExecutionThread(KernelMode, FALSE, &ShortPsLockDelay); + goto TryAgain2; + } + } } - /* Rundown Win32 Structures */ - PsTerminateWin32Thread(CurrentThread); - if (Last) PsTerminateWin32Process(CurrentProcess); + /* Rundown Win32 Thread if there is one */ + if (Thread->Tcb.Win32Thread) PspW32ThreadCallout(Thread, FALSE); - /* Rundown Registry Notifications. TODO (refers to NtChangeNotify, not Cm callbacks) */ - //CmNotifyRunDown(CurrentThread); + /* If we are the last thread and have a W32 Process */ + if ((Last) && (CurrentProcess->Win32Process)) + { + /* Run it down too */ + PspW32ProcessCallout(CurrentProcess, FALSE); + } + + /* Make sure Stack Swap isn't enabled */ + if (Thread->Tcb.EnableStackSwap) + { + /* Stack swap really shouldn't be on during exit !*/ + KEBUGCHECKEX(KERNEL_STACK_LOCKED_AT_EXIT, 0, 0, 0, 0); + } + + /* Cancel I/O for the thread. */ + IoCancelThreadIo(Thread); + + /* Rundown Timers */ + ExTimerRundown(); + + /* FIXME: Rundown Registry Notifications (NtChangeNotify) + CmNotifyRunDown(Thread); */ + + /* Clear NPX Thread */ + InterlockedCompareExchangePointer(&KeGetCurrentPrcb()->NpxThread, NULL, Thread); + + /* Rundown Mutexes */ + KeRundownThread(); /* Free the TEB */ - if((Teb = CurrentThread->Tcb.Teb)) + if((Teb = Thread->Tcb.Teb)) { - /* Clean up the stack first, if requested */ - if (Teb->FreeStackOnTermination) + /* Check if the thread isn't terminated and if we should free stack */ + if (!(Thread->Terminated) && (Teb->FreeStackOnTermination)) { - ULONG Dummy = 0; + /* Set the TEB's Deallocation Stack as the Base Address */ + Dummy = 0; + DeallocationStack = Teb->DeallocationStack; + + /* Free the Thread's Stack */ ZwFreeVirtualMemory(NtCurrentProcess(), - &Teb->DeallocationStack, + &DeallocationStack, &Dummy, MEM_RELEASE); } - DPRINT("Decommit teb at %p\n", Teb); + /* Free the debug handle */ + if (Teb->DbgSsReserved[2]) NtClose(Teb->DbgSsReserved[2]); + + /* Decommit the TEB */ MmDeleteTeb(CurrentProcess, Teb); - CurrentThread->Tcb.Teb = NULL; + Thread->Tcb.Teb = NULL; } - /* The last Thread shuts down the Process */ - if (Last) PspExitProcess(CurrentProcess); + /* Free LPC Data */ + LpcExitThread(Thread); - /* Unlock the Process */ - PsUnlockProcess(CurrentProcess); + /* Save the exit status and exit time */ + Thread->ExitStatus = ExitStatus; + KeQuerySystemTime(&Thread->ExitTime); - /* Cancel I/O for the thread. */ - IoCancelThreadIo(CurrentThread); + /* Sanity check */ + ASSERT(Thread->Tcb.CombinedApcDisable == 0); - /* Rundown Timers */ - ExTimerRundown(); - KeCancelTimer(&CurrentThread->Tcb.Timer); + /* Check if this is the final thread or not */ + if (Last) + { + /* Set the process exit time */ + CurrentProcess->ExitTime = Thread->ExitTime; - /* If the Processor Control Block's NpxThread points to the current thread - * unset it. - */ - KeRaiseIrql(DISPATCH_LEVEL, &oldIrql); - (void)InterlockedCompareExchangePointer(&KeGetCurrentPrcb()->NpxThread, - NULL, - (PVOID)CurrentThread); - KeLowerIrql(oldIrql); + /* Exit the process */ + PspExitProcess(TRUE, CurrentProcess); - /* Rundown Mutexes */ - KeRundownThread(); + /* Get the process token and check if we need to audit */ + PrimaryToken = PsReferencePrimaryToken(CurrentProcess); + if (SeDetailedAuditingWithToken(PrimaryToken)) + { + /* Audit the exit */ + SeAuditProcessExit(CurrentProcess); + } + + /* Dereference the process token */ + ObFastDereferenceObject(&CurrentProcess->Token, PrimaryToken); - /* Disable new APC Queuing, this is as far as we'll let them go */ - KeDisableThreadApcQueueing(&CurrentThread->Tcb); + /* Check if this is a VDM Process and rundown the VDM DPCs if so */ + if (CurrentProcess->VdmObjects);// VdmRundownDpcs(CurrentProcess); + + /* Kill the process in the Object Manager */ + ObKillProcess(CurrentProcess); + + /* Check if we have a section object */ + if (CurrentProcess->SectionObject) + { + /* Dereference and clear the Section Object */ + ObDereferenceObject(CurrentProcess->SectionObject); + CurrentProcess->SectionObject = NULL; + } + + /* Check if the process is part of a job */ + if (CurrentProcess->Job) + { + /* Remove the process from the job */ + PspExitProcessFromJob(CurrentProcess->Job, CurrentProcess); + } + } + + /* Disable APCs */ + KeEnterCriticalRegion(); + + /* Disable APC queueing, force a resumption */ + Thread->Tcb.ApcQueueable = FALSE; + KeForceResumeThread(&Thread->Tcb); + + /* Re-enable APCs */ + KeLeaveCriticalRegion(); /* Flush the User APCs */ - FirstEntry = KeFlushQueueApc(&CurrentThread->Tcb, UserMode); + FirstEntry = KeFlushQueueApc(&Thread->Tcb, UserMode); if (FirstEntry != NULL) { CurrentEntry = FirstEntry; @@ -376,269 +706,372 @@ PspExitThread(NTSTATUS ExitStatus) while (CurrentEntry != FirstEntry); } + /* Clean address space if this was the last thread */ + if (Last) MmCleanProcessAddressSpace(CurrentProcess); + /* Call the Lego routine */ - if (CurrentThread->Tcb.LegoData) PspRunLegoRoutine(&CurrentThread->Tcb); + if (Thread->Tcb.LegoData) PspRunLegoRoutine(&Thread->Tcb); /* Flush the APC queue, which should be empty */ - if ((FirstEntry = KeFlushQueueApc(&CurrentThread->Tcb, KernelMode))) + if ((FirstEntry = KeFlushQueueApc(&Thread->Tcb, KernelMode))) { /* Bugcheck time */ KEBUGCHECKEX(KERNEL_APC_PENDING_DURING_EXIT, (ULONG_PTR)FirstEntry, - CurrentThread->Tcb.KernelApcDisable, - oldIrql, + Thread->Tcb.KernelApcDisable, + KeGetCurrentIrql(), 0); } + /* Signal the process if this was the last thread */ + if (Last) KeSetProcess(&CurrentProcess->Pcb, 0, FALSE); + /* Terminate the Thread from the Scheduler */ KeTerminateThread(0); - DPRINT1("Unexpected return, CurrentThread %x PsGetCurrentThread() %x\n", CurrentThread, PsGetCurrentThread()); - KEBUGCHECK(0); } VOID -STDCALL +NTAPI PsExitSpecialApc(PKAPC Apc, PKNORMAL_ROUTINE* NormalRoutine, PVOID* NormalContext, PVOID* SystemArgument1, PVOID* SystemArguemnt2) { - DPRINT("PsExitSpecialApc called: 0x%x (proc: 0x%x, '%.16s')\n", - PsGetCurrentThread(), PsGetCurrentProcess(), PsGetCurrentProcess()->ImageFileName); + NTSTATUS Status; + PAGED_CODE(); + DPRINT1("PsExitSpecialApc: [%p:%p], '%.16s')\n", + PsGetCurrentThread(), + PsGetCurrentProcess(), + PsGetCurrentProcess()->ImageFileName); /* Don't do anything unless we are in User-Mode */ if (Apc->SystemArgument2) { - NTSTATUS ExitStatus = (NTSTATUS)Apc->NormalContext; - /* Free the APC */ - ExFreePool(Apc); + Status = (NTSTATUS)Apc->NormalContext; + PspExitApcRundown(Apc); /* Terminate the Thread */ - PspExitThread(ExitStatus); - - /* we should never reach this point! */ - KEBUGCHECK(0); + PspExitThread(Status); } } VOID -STDCALL +NTAPI PspExitNormalApc(PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2) { PKAPC Apc = (PKAPC)SystemArgument1; PETHREAD Thread = PsGetCurrentThread(); - NTSTATUS ExitStatus; - - DPRINT("PspExitNormalApc called: 0x%x (proc: 0x%x, '%.16s')\n", - PsGetCurrentThread(), PsGetCurrentProcess(), PsGetCurrentProcess()->ImageFileName); + PAGED_CODE(); + DPRINT1("PspExitNormalApc: [%p:%p], '%.16s')\n", + PsGetCurrentThread(), + PsGetCurrentProcess(), + PsGetCurrentProcess()->ImageFileName); /* This should never happen */ - ASSERT(!SystemArgument2); - - /* If this is a system thread, we can safely kill it from Kernel-Mode */ - if (PsIsSystemThread(Thread)) - { - /* Get the Exit Status */ - DPRINT1("Killing System Thread\n"); - ExitStatus = (NTSTATUS)Apc->NormalContext; - - /* Free the APC */ - ExFreePool(Apc); - - /* Exit the Thread */ - PspExitThread(ExitStatus); - } + ASSERT(!(((ULONG_PTR)SystemArgument2) & 1)); /* If we're here, this is not a System Thread, so kill it from User-Mode */ - DPRINT("Initializing User-Mode APC\n"); + DPRINT1("Initializing User-Mode APC\n"); KeInitializeApc(Apc, &Thread->Tcb, OriginalApcEnvironment, PsExitSpecialApc, - NULL, + PspExitApcRundown, PspExitNormalApc, UserMode, NormalContext); /* Now insert the APC with the User-Mode Flag */ - KeInsertQueueApc(Apc, Apc, (PVOID)UserMode, 2); + if (!(KeInsertQueueApc(Apc, + Apc, + (PVOID)((ULONG_PTR)SystemArgument2 | 1), + 2))) + { + /* Failed to insert, free the APC */ + PspExitApcRundown(Apc); + } - /* Forcefully resume the thread */ - KeForceResumeThread(&Thread->Tcb); + /* Set the APC Pending flag */ + Thread->Tcb.ApcState.UserApcPending = TRUE; } /* * See "Windows Internals" - Chapter 13, Page 49 */ -VOID -STDCALL +NTSTATUS +NTAPI PspTerminateThreadByPointer(PETHREAD Thread, - NTSTATUS ExitStatus) + NTSTATUS ExitStatus, + BOOLEAN bSelf) { PKAPC Apc; + NTSTATUS Status = STATUS_SUCCESS; + ULONG Flags; + PAGED_CODE(); + DPRINT1("PspTerminateThreadByPointer(%p, %lx)\n", Thread, ExitStatus); - DPRINT("PspTerminatedThreadByPointer(Thread %x, ExitStatus %x)\n", - Thread, ExitStatus); + /* Check if this is a Critical Thread, and Bugcheck */ + if (Thread->BreakOnTermination) + { + /* FIXME: Add critical thread support */ + DPRINT1("A critical thread is being terminated\n"); + KEBUGCHECK(0); + } + + /* Check if we are already inside the thread */ + if (bSelf || (PsGetCurrentThread() == Thread)) + { + /* This should only happen at passive */ + ASSERT_IRQL(PASSIVE_LEVEL); - /* Check if we are already in the right context */ - if (PsGetCurrentThread() == Thread) { + /* Mark it as terminated */ + InterlockedOr(&Thread->CrossThreadFlags, 1); /* Directly terminate the thread */ PspExitThread(ExitStatus); + } - /* we should never reach this point! */ - KEBUGCHECK(0); + /* This shouldn't be a system thread */ + if (Thread->SystemThread) + { + DPRINT1("A system thread is being illegaly terminated\n"); + return STATUS_ACCESS_DENIED; } /* Allocate the APC */ Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_TERMINATE_APC); - /* Initialize a Kernel Mode APC to Kill the Thread */ - KeInitializeApc(Apc, - &Thread->Tcb, - OriginalApcEnvironment, - PsExitSpecialApc, - NULL, - PspExitNormalApc, - KernelMode, - (PVOID)ExitStatus); + /* Set the Terminated Flag */ + Flags = Thread->CrossThreadFlags | 1; - /* Insert it into the APC Queue */ - KeInsertQueueApc(Apc, - Apc, - NULL, - 2); + /* Set it, and check if it was already set while we were running */ + if (!(InterlockedExchange(&Thread->CrossThreadFlags, Flags) & 1)) + { + /* Initialize a Kernel Mode APC to Kill the Thread */ + KeInitializeApc(Apc, + &Thread->Tcb, + OriginalApcEnvironment, + PsExitSpecialApc, + PspExitApcRundown, + PspExitNormalApc, + KernelMode, + (PVOID)ExitStatus); + + /* Insert it into the APC Queue */ + if (!KeInsertQueueApc(Apc, Apc, NULL, 2)) + { + /* The APC was already in the queue, fail */ + ExFreePool(Apc); + Status = STATUS_UNSUCCESSFUL; + } + else + { + /* Forcefully resume the thread and return */ + KeForceResumeThread(&Thread->Tcb); + return Status; + } + } - /* Forcefully resume the thread */ - KeForceResumeThread(&Thread->Tcb); + /* We failed, free the APC */ + ExFreePool(Apc); + + /* Return Status */ + DPRINT1("Fail return: %lx\n", Status); + return Status; } -NTSTATUS -STDCALL -PspExitProcess(PEPROCESS Process) +VOID +NTAPI +PspExitProcess(IN BOOLEAN LastThread, + IN PEPROCESS Process) { - DPRINT("PspExitProcess 0x%x\n", Process); + ULONG Actual; + PAGED_CODE(); + DPRINT1("PspExitProcess %p\n", Process); - PspRunCreateProcessNotifyRoutines(Process, FALSE); + /* Set Process Delete flag */ + InterlockedOr(&Process->Flags, 4); - PspDestroyQuotaBlock(Process); + /* Check if we are the last thread */ + if (LastThread) + { + /* Notify the WMI Process Callback */ + //WmiTraceProcess(Process, FALSE); + + /* Run the Notification Routines */ + PspRunCreateProcessNotifyRoutines(Process, FALSE); + } - /* close all handles associated with our process, this needs to be done - when the last thread still runs */ - ObKillProcess(Process); + /* Cleanup the power state */ + PopCleanupPowerState((PPOWER_STATE)&Process->Pcb.PowerState); + + /* Clear the security port */ + if (!Process->SecurityPort) + { + /* So we don't double-dereference */ + Process->SecurityPort = (PVOID)1; + } + else if (Process->SecurityPort != (PVOID)1) + { + /* Dereference it */ + ObDereferenceObject(Process->SecurityPort); + Process->SecurityPort = (PVOID)1; + } - KeSetProcess(&Process->Pcb, IO_NO_INCREMENT); + /* Check if we are the last thread */ + if (LastThread) + { + /* Check if we have to set the Timer Resolution */ + if (Process->SetTimerResolution) + { + /* Set it to default */ + ZwSetTimerResolution(KeMaximumIncrement, 0, &Actual); + } - /* release the keep-alive reference of the process object */ - ObDereferenceObject(Process); + /* + * Check if we are part of a Job, and if the job has a completion port + */ + if ((Process->Job) && (Process->Job->CompletionPort)) + { + /* FIXME: Check job status code and do I/O completion if needed */ + } - return(STATUS_SUCCESS); + /* FIXME: Notify the Prefetcher */ + } + else + { + /* Clear process' address space here */ + MmCleanProcessAddressSpace(Process); + } } NTSTATUS -STDCALL +NTAPI NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL, IN NTSTATUS ExitStatus) { NTSTATUS Status; - PEPROCESS Process; - PETHREAD CurrentThread; + PEPROCESS Process, CurrentProcess = PsGetCurrentProcess(); + PETHREAD Thread, CurrentThread = PsGetCurrentThread(); BOOLEAN KillByHandle; - PAGED_CODE(); - - DPRINT("NtTerminateProcess(ProcessHandle %x, ExitStatus %x)\n", + DPRINT1("NtTerminateProcess(ProcessHandle %x, ExitStatus %x)\n", ProcessHandle, ExitStatus); + /* Remember how we will kill it */ KillByHandle = (ProcessHandle != NULL); /* Get the Process Object */ - Status = ObReferenceObjectByHandle((KillByHandle ? ProcessHandle : NtCurrentProcess()), + Status = ObReferenceObjectByHandle((KillByHandle) ? + ProcessHandle : NtCurrentProcess(), PROCESS_TERMINATE, PsProcessType, KeGetPreviousMode(), (PVOID*)&Process, NULL); - if (!NT_SUCCESS(Status)) { - + if (!NT_SUCCESS(Status)) + { DPRINT1("Invalid handle to Process\n"); return(Status); } - CurrentThread = PsGetCurrentThread(); - - PsLockProcess(Process, FALSE); - - if(Process->ExitTime.QuadPart != 0) + /* Check if this is a Critical Process, and Bugcheck */ + if (Process->BreakOnTermination) { - PsUnlockProcess(Process); - ObDereferenceObject(Process); - return STATUS_PROCESS_IS_TERMINATING; + /* FIXME: Add critical Process support */ + DPRINT1("A critical Process is being terminated\n"); + KEBUGCHECK(0); } - /* Terminate all the Process's Threads */ - PspTerminateProcessThreads(Process, ExitStatus); + /* Lock the Process */ + PsLockProcess(Process, FALSE); - /* only kill the calling thread if it either passed a process handle or - NtCurrentProcess() */ - if (KillByHandle) { + /* Set the exit flag */ + if (!KillByHandle) InterlockedOr(&Process->Flags, 8); - /* set the exit time as we're about to release the process lock before - we kill ourselves to prevent threads outside of our process trying - to kill us */ - KeQuerySystemTime(&Process->ExitTime); - Process->ExitStatus = ExitStatus; + /* Get the first thread */ + Status = STATUS_NOTHING_TO_TERMINATE; + if ((Thread = PsGetNextProcessThread(Process, NULL))) + { + /* We know we have at least a thread */ + Status = STATUS_SUCCESS; - /* Only master thread remains... kill it off */ - if (CurrentThread->ThreadsProcess == Process) { + /* Loop and kill the others */ + do + { + /* Ensure it's not ours*/ + if (Thread != CurrentThread) + { + /* Kill it */ + PspTerminateThreadByPointer(Thread, ExitStatus, FALSE); + } - /* mark our thread as terminating so attempts to terminate it, when - unlocking the process, fail */ - CurrentThread->Terminated = TRUE; + /* Move to the next thread */ + } while((Thread = PsGetNextProcessThread(Process, Thread))); + } - PsUnlockProcess(Process); + /* Unlock the process */ + PsUnlockProcess(Process); - /* we can safely dereference the process because the current thread - holds a reference to it until it gets reaped */ - ObDereferenceObject(Process); + /* Check if we are killing ourselves */ + if (Process != CurrentProcess) + { + /* Check for the DBG_TERMINATE_PROCESS exit code */ + if (ExitStatus == DBG_TERMINATE_PROCESS) + { + /* FIXME: Disable debugging on this process */ + } + } + /* Make sure that we got a handle */ + else if (KillByHandle) + { + /* Dereference the project */ + ObDereferenceObject(Process); - /* now the other threads get a chance to terminate, we don't wait but - just kill ourselves right now. The process will be run down when the - last thread terminates */ + /* Terminate ourselves */ + PspTerminateThreadByPointer(CurrentThread, ExitStatus, TRUE); + } - PspExitThread(ExitStatus); + /* Check if there was nothing to terminate, or if we have a Debug Port */ + if ((Status == STATUS_NOTHING_TO_TERMINATE) || + (Process->DebugPort && KillByHandle)) + { + /* Clear the handle table */ + DPRINT1("Clearing OB Table\n"); + ObClearProcessHandleTable(Process); - /* we should never reach this point! */ - KEBUGCHECK(0); - } + /* Return status now */ + Status = STATUS_SUCCESS; } - /* unlock and dereference the process so the threads can kill themselves */ - PsUnlockProcess(Process); + /* Decrease the reference count we added */ ObDereferenceObject(Process); - return(STATUS_SUCCESS); + /* Return status */ + DPRINT1("Returning: %lx\n", Status); + return Status; } NTSTATUS -STDCALL +NTAPI NtTerminateThread(IN HANDLE ThreadHandle, IN NTSTATUS ExitStatus) { PETHREAD Thread; + PETHREAD CurrentThread = PsGetCurrentThread(); NTSTATUS Status; - PAGED_CODE(); + DPRINT1("NtTerminateThread: %lx %lx\n", ThreadHandle, ExitStatus); /* Handle the special NULL case */ if (!ThreadHandle) { /* Check if we're the only thread left */ - if (IsListEmpty(&PsGetCurrentProcess()->Pcb.ThreadListHead)) + if (PsGetCurrentProcess()->ActiveThreads == 1) { /* This is invalid */ DPRINT1("Can't terminate self\n"); @@ -646,105 +1079,79 @@ NtTerminateThread(IN HANDLE ThreadHandle, } else { - /* Use current handle */ - ThreadHandle = NtCurrentThread(); + /* Terminate us directly */ + goto TerminateSelf; } } + else if (ThreadHandle == NtCurrentThread()) + { +TerminateSelf: + /* Terminate this thread */ + return PspTerminateThreadByPointer(CurrentThread, + ExitStatus, + TRUE); + } - /* Get the Thread Object */ + /* We are terminating another thread, get the Thread Object */ Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_TERMINATE, PsThreadType, KeGetPreviousMode(), (PVOID*)&Thread, NULL); - if (!NT_SUCCESS(Status)) { - + if (!NT_SUCCESS(Status)) + { DPRINT1("Could not reference thread object\n"); - return(Status); - } - - /* Make sure this is not a system thread */ - if (PsIsSystemThread(Thread)) { - - DPRINT1("Trying to Terminate a system thread!\n"); - ObDereferenceObject(Thread); - return STATUS_INVALID_PARAMETER; + return Status; } /* Check to see if we're running in the same thread */ - if (Thread != PsGetCurrentThread()) { - - /* we need to lock the process to make sure it's not already terminating */ - PsLockProcess(Thread->ThreadsProcess, FALSE); - - /* This isn't our thread, terminate it if not already done */ - if (!Thread->Terminated) { - - Thread->Terminated = TRUE; - + if (Thread != CurrentThread) + { /* Terminate it */ - PspTerminateThreadByPointer(Thread, ExitStatus); - } - - PsUnlockProcess(Thread->ThreadsProcess); + Status = PspTerminateThreadByPointer(Thread, ExitStatus, FALSE); /* Dereference the Thread and return */ ObDereferenceObject(Thread); - - } else { - - Thread->Terminated = TRUE; - - /* it's safe to dereference thread, there's at least the keep-alive - reference which will be removed by the thread reaper causing the - thread to be finally destroyed */ + } + else + { + /* Dereference the thread and terminate ourselves */ ObDereferenceObject(Thread); - - /* Terminate him, he's ours */ - PspExitThread(ExitStatus); - - /* We do never reach this point */ - KEBUGCHECK(0); + goto TerminateSelf; } - return(STATUS_SUCCESS); + return Status; } /* * @implemented */ NTSTATUS -STDCALL +NTAPI PsTerminateSystemThread(NTSTATUS ExitStatus) { PETHREAD Thread = PsGetCurrentThread(); /* Make sure this is a system thread */ - if (!PsIsSystemThread(Thread)) { - + if (Thread->SystemThread) + { DPRINT1("Trying to Terminate a non-system thread!\n"); return STATUS_INVALID_PARAMETER; } /* Terminate it for real */ - PspExitThread(ExitStatus); - - /* we should never reach this point! */ - KEBUGCHECK(0); - - return(STATUS_SUCCESS); + return PspTerminateThreadByPointer(Thread, ExitStatus, TRUE); } NTSTATUS -STDCALL +NTAPI NtRegisterThreadTerminatePort(HANDLE PortHandle) { NTSTATUS Status; PTERMINATION_PORT TerminationPort; PVOID TerminationLpcPort; PETHREAD Thread; - PAGED_CODE(); /* Get the Port */ @@ -768,10 +1175,8 @@ NtRegisterThreadTerminatePort(HANDLE PortHandle) /* Associate the Port */ Thread = PsGetCurrentThread(); TerminationPort->Port = TerminationLpcPort; - DPRINT("TerminationPort: %p\n", TerminationPort); TerminationPort->Next = Thread->TerminationPort; Thread->TerminationPort = TerminationPort; - DPRINT("TerminationPort: %p\n", Thread->TerminationPort); /* Return success */ return(STATUS_SUCCESS); diff --git a/reactos/ntoskrnl/ps/process.c b/reactos/ntoskrnl/ps/process.c index 628f7e205be..0ddcc093d5a 100644 --- a/reactos/ntoskrnl/ps/process.c +++ b/reactos/ntoskrnl/ps/process.c @@ -1,11 +1,10 @@ /* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory * FILE: ntoskrnl/ps/process.c - * PURPOSE: Process managment - * - * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - * David Welch (welch@cwcom.net) + * PURPOSE: Process Manager: Process Management + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + * Thomas Weidenmueller (w3seek@reactos.org */ /* INCLUDES ******************************************************************/ @@ -24,15 +23,34 @@ PEPROCESS PsInitialSystemProcess = NULL; PEPROCESS PsIdleProcess = NULL; POBJECT_TYPE PsProcessType = NULL; extern PHANDLE_TABLE PspCidTable; +extern POBJECT_TYPE DbgkDebugObjectType; EPROCESS_QUOTA_BLOCK PspDefaultQuotaBlock; +ULONG PsMinimumWorkingSet, PsMaximumWorkingSet; + LIST_ENTRY PsActiveProcessHead; FAST_MUTEX PspActiveProcessMutex; LARGE_INTEGER ShortPsLockDelay, PsLockTimeout; /* INTERNAL FUNCTIONS *****************************************************************/ +NTSTATUS +NTAPI +PspDeleteLdt(PEPROCESS Process) +{ + /* FIXME */ + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +PspDeleteVdmObjects(PEPROCESS Process) +{ + /* FIXME */ + return STATUS_SUCCESS; +} + NTSTATUS NTAPI PsLockProcess(PEPROCESS Process, BOOLEAN Timeout) @@ -109,12 +127,59 @@ PsUnlockProcess(PEPROCESS Process) KeLeaveCriticalRegion(); } +PETHREAD +NTAPI +PsGetNextProcessThread(IN PEPROCESS Process, + IN PETHREAD Thread OPTIONAL) +{ + PETHREAD FoundThread = NULL; + PLIST_ENTRY ListHead, Entry; + PAGED_CODE(); + + /* Lock the process */ + PsLockProcess(Process, FALSE); + + /* Check if we're already starting somewhere */ + if (Thread) + { + /* Start where we left off */ + Entry = Thread->ThreadListEntry.Flink; + } + else + { + /* Start at the beginning */ + Entry = Process->ThreadListHead.Flink; + } + + /* Set the list head and start looping */ + ListHead = &Process->ThreadListHead; + while (ListHead != Entry) + { + /* Get the Thread */ + FoundThread = CONTAINING_RECORD(Entry, ETHREAD, ThreadListEntry); + + /* Reference the thread. FIXME: Race, use ObSafeReferenceObject */ + ObReferenceObject(FoundThread); + break; + } + + /* Unlock the process */ + PsUnlockProcess(Process); + + /* Check if we had a starting thread, and dereference it */ + if (Thread) ObDereferenceObject(Thread); + + /* Return what we found */ + return FoundThread; +} + PEPROCESS -STDCALL +NTAPI PsGetNextProcess(PEPROCESS OldProcess) { PEPROCESS NextProcess; NTSTATUS Status; + PAGED_CODE(); /* Check if we have a previous process */ if (OldProcess == NULL) @@ -176,59 +241,77 @@ PsGetNextProcess(PEPROCESS OldProcess) } NTSTATUS -STDCALL +NTAPI PspCreateProcess(OUT PHANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN HANDLE ParentProcess OPTIONAL, - IN BOOLEAN InheritObjectTable, + IN DWORD Flags, IN HANDLE SectionHandle OPTIONAL, IN HANDLE DebugPort OPTIONAL, - IN HANDLE ExceptionPort OPTIONAL) + IN HANDLE ExceptionPort OPTIONAL, + IN BOOLEAN InJob) { HANDLE hProcess; - PEPROCESS Process = NULL; - PEPROCESS pParentProcess = NULL; - PEPORT pDebugPort = NULL; - PEPORT pExceptionPort = NULL; - PSECTION_OBJECT SectionObject = NULL; - NTSTATUS Status = STATUS_SUCCESS; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + PEPROCESS Process, Parent; + PEPORT ExceptionPortObject; + PDBGK_DEBUG_OBJECT DebugObject; + PSECTION_OBJECT SectionObject; + NTSTATUS Status; + KPROCESSOR_MODE PreviousMode; PHYSICAL_ADDRESS DirectoryTableBase; KAFFINITY Affinity; HANDLE_TABLE_ENTRY CidEntry; - BOOLEAN ProcessCreated = FALSE; + PETHREAD CurrentThread; + PEPROCESS CurrentProcess; + ULONG MinWs, MaxWs; + PAGED_CODE(); + DirectoryTableBase.QuadPart = 0; - DirectoryTableBase.QuadPart = (ULONGLONG)0; + /* Get the current thread, process and cpu ring mode */ + CurrentThread = PsGetCurrentThread(); + ASSERT(&CurrentThread->Tcb == KeGetCurrentThread()); + PreviousMode = ExGetPreviousMode(); + ASSERT((CurrentThread) == PsGetCurrentThread()); + CurrentProcess = (PEPROCESS)CurrentThread->Tcb.ApcState.Process; - DPRINT("PspCreateProcess(ObjectAttributes %x)\n", ObjectAttributes); + /* Validate flags */ + if (Flags & ~PS_ALL_FLAGS) return STATUS_INVALID_PARAMETER; - /* Reference the Parent if there is one */ - if(ParentProcess != NULL) + /* Check for parent */ + if(ParentProcess) { + /* Reference it */ Status = ObReferenceObjectByHandle(ParentProcess, PROCESS_CREATE_PROCESS, PsProcessType, PreviousMode, - (PVOID*)&pParentProcess, + (PVOID*)&Parent, NULL); - if (!NT_SUCCESS(Status)) { DPRINT1("Failed to reference the parent process: Status: 0x%x\n", Status); - goto Cleanup; + return Status; } - /* Inherit Parent process's Affinity. */ - Affinity = pParentProcess->Pcb.Affinity; + /* If this process should be in a job but the parent isn't */ + if ((InJob) && (!Parent->Job)) + { + /* This is illegal. Dereference the parent and fail */ + ObDereferenceObject(Parent); + return STATUS_INVALID_PARAMETER; + } + /* Inherit Parent process's Affinity. */ + Affinity = Parent->Pcb.Affinity; } else { - pParentProcess = NULL; + /* We have no parent */ + Parent = NULL; #ifdef CONFIG_SMP - /* FIXME: - * Only the boot cpu is initialized in the early boot phase. + /* + * FIXME: Only the boot cpu is initialized in the early boot phase. */ Affinity = 0xffffffff; #else @@ -236,42 +319,55 @@ PspCreateProcess(OUT PHANDLE ProcessHandle, #endif } - /* Add the debug port */ - if (DebugPort != NULL) + /* Save working set data */ + MinWs = PsMinimumWorkingSet; + MaxWs = PsMaximumWorkingSet; + + /* Create the Object */ + Status = ObCreateObject(PreviousMode, + PsProcessType, + ObjectAttributes, + PreviousMode, + NULL, + sizeof(EPROCESS), + 0, + 0, + (PVOID*)&Process); + if (!NT_SUCCESS(Status)) { - Status = ObReferenceObjectByHandle(DebugPort, - PORT_ALL_ACCESS, - LpcPortObjectType, - PreviousMode, - (PVOID*)&pDebugPort, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to reference the debug port: Status: 0x%x\n", Status); - goto Cleanup; - } + DPRINT1("Failed to create process object, Status: 0x%x\n", Status); + goto Cleanup; } - /* Add the exception port */ - if (ExceptionPort != NULL) - { - Status = ObReferenceObjectByHandle(ExceptionPort, - PORT_ALL_ACCESS, - LpcPortObjectType, - PreviousMode, - (PVOID*)&pExceptionPort, - NULL); + /* Clean up the Object */ + RtlZeroMemory(Process, sizeof(EPROCESS)); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to reference the exception port: Status: 0x%x\n", Status); - goto Cleanup; - } + /* Setup the Thread List Head */ + InitializeListHead(&Process->ThreadListHead); + + /* Set up the Quota Block from the Parent */ + PspInheritQuota(Process, Parent); + + /* Set up Dos Device Map from the Parent */ + ObInheritDeviceMap(Parent, Process); + + /* Check if we have a parent */ + if (Parent) + { + /* Ineherit PID and Hard Error Processing */ + Process->InheritedFromUniqueProcessId = Parent->UniqueProcessId; + Process->DefaultHardErrorProcessing = Parent->DefaultHardErrorProcessing; + } + else + { + /* Use default hard error processing */ + Process->DefaultHardErrorProcessing = TRUE; } - /* Add the Section */ - if (SectionHandle != NULL) + /* Check for a section handle */ + if (SectionHandle) { + /* Get a pointer to it */ Status = ObReferenceObjectByHandle(SectionHandle, SECTION_MAP_EXECUTE, MmSectionObjectType, @@ -281,180 +377,257 @@ PspCreateProcess(OUT PHANDLE ProcessHandle, if (!NT_SUCCESS(Status)) { DPRINT1("Failed to reference process image section: Status: 0x%x\n", Status); - goto Cleanup; + goto CleanupWithRef; } } + else + { + /* Is the parent the initial process? */ + if (Parent != PsInitialSystemProcess) + { + /* It's not, so acquire the process rundown */ + // FIXME - /* Create the Object */ - DPRINT("Creating Process Object\n"); - Status = ObCreateObject(PreviousMode, - PsProcessType, - ObjectAttributes, - PreviousMode, - NULL, - sizeof(EPROCESS), - 0, - 0, - (PVOID*)&Process); + /* If the parent has a section, use it */ + SectionObject = Parent->SectionObject; + if (SectionObject) ObReferenceObject(SectionObject); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to create process object, Status: 0x%x\n", Status); - goto Cleanup; + /* Release process rundown */ + // FIXME + + /* If we don't have a section object */ + if (!SectionObject) + { + /* Then the process is in termination, so fail */ + Status = STATUS_PROCESS_IS_TERMINATING; + goto CleanupWithRef; + } + } } - /* Clean up the Object */ - DPRINT("Cleaning Process Object\n"); - RtlZeroMemory(Process, sizeof(EPROCESS)); + /* Save the pointer to the section object */ + Process->SectionObject = SectionObject; - /* Inherit stuff from the Parent since we now have the object created */ - if (pParentProcess) + /* Check for the debug port */ + if (DebugPort) { - Process->InheritedFromUniqueProcessId = pParentProcess->UniqueProcessId; - Process->Session = pParentProcess->Session; - } + /* Reference it */ + Status = ObReferenceObjectByHandle(DebugPort, + DEBUG_OBJECT_ADD_REMOVE_PROCESS, + DbgkDebugObjectType, + PreviousMode, + (PVOID*)&DebugObject, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to reference the debug port: Status: 0x%x\n", Status); + goto CleanupWithRef; + } - /* Set up the Quota Block from the Parent */ - PspInheritQuota(Process, pParentProcess); + /* Save the debug object */ + Process->DebugPort = DebugObject; + + /* Check if the caller doesn't want the debug stuff inherited */ + if (Flags & PS_NO_DEBUG_INHERIT) InterlockedOr(&Process->Flags, 2); + } + else + { + /* Do we have a parent? Copy his debug port */ + if (Parent) DbgkCopyProcessDebugPort(Process, Parent); + } - /* FIXME: Set up Dos Device Map from the Parent - ObInheritDeviceMap(Parent, Process) */ + /* Now check for an exception port */ + if (ExceptionPort) + { + /* Reference it */ + Status = ObReferenceObjectByHandle(ExceptionPort, + PORT_ALL_ACCESS, + LpcPortObjectType, + PreviousMode, + (PVOID*)&ExceptionPortObject, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to reference the exception port: Status: 0x%x\n", Status); + goto CleanupWithRef; + } - /* Set the Process' LPC Ports */ - Process->DebugPort = pDebugPort; - Process->ExceptionPort = pExceptionPort; + /* Save the exception port */ + Process->ExceptionPort = ExceptionPortObject; + } /* Save the pointer to the section object */ Process->SectionObject = SectionObject; /* Setup the Lock Event */ - DPRINT("Initialzing Process Lock\n"); Process->LockEvent = ExAllocatePoolWithTag(PagedPool, - sizeof(KEVENT), - TAG('P', 's', 'L', 'k')); + sizeof(KEVENT), + TAG('P', 's', 'L', 'k')); KeInitializeEvent(Process->LockEvent, SynchronizationEvent, FALSE); - /* Setup the Thread List Head */ - DPRINT("Initialzing Process ThreadListHead\n"); - InitializeListHead(&Process->ThreadListHead); + /* Set default exit code */ + Process->ExitStatus = STATUS_TIMEOUT; /* Create or Clone the Handle Table */ - DPRINT("Initialzing Process Handle Table\n"); - ObpCreateHandleTable(pParentProcess, Process); - DPRINT("Handle Table: %x\n", Process->ObjectTable); + ObpCreateHandleTable(Parent, Process); /* Set Process's Directory Base */ - DPRINT("Initialzing Process Directory Base\n"); - MmCopyMmInfo((pParentProcess ? pParentProcess : PsInitialSystemProcess), + MmCopyMmInfo(Parent ? Parent : PsInitialSystemProcess, Process, &DirectoryTableBase); + /* We now have an address space */ + InterlockedOr(&Process->Flags, 0x40000); + + /* Set the maximum WS */ + Process->Vm.MaximumWorkingSetSize = MaxWs; + /* Now initialize the Kernel Process */ - DPRINT("Initialzing Kernel Process\n"); KeInitializeProcess(&Process->Pcb, PROCESS_PRIORITY_NORMAL, Affinity, DirectoryTableBase); /* Duplicate Parent Token */ - DPRINT("Initialzing Process Token\n"); - Status = PspInitializeProcessSecurity(Process, pParentProcess); + Status = PspInitializeProcessSecurity(Process, Parent); if (!NT_SUCCESS(Status)) { - DbgPrint("PspInitializeProcessSecurity failed (Status %x)\n", Status); - goto Cleanup; + DPRINT1("PspInitializeProcessSecurity failed (Status %x)\n", Status); + goto CleanupWithRef; } + /* Set default priority class */ + Process->PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL; + /* Create the Process' Address Space */ - DPRINT("Initialzing Process Address Space\n"); Status = MmCreateProcessAddressSpace(Process, (PROS_SECTION_OBJECT)SectionObject); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to create Address Space\n"); - goto Cleanup; + goto CleanupWithRef; + } + + /* Check for parent again */ +#if 0 + if (!Parent) + { + /* Allocate our Audit info */ + Process->SeAuditProcessCreationInfo.ImageFileName = + ExAllocatePoolWithTag(PagedPool, + sizeof(SE_AUDIT_PROCESS_CREATION_INFO), + TAG_SEPA); + RtlZeroMemory(Process->SeAuditProcessCreationInfo.ImageFileName, + sizeof(SE_AUDIT_PROCESS_CREATION_INFO)); } + else + { + /* Allocate our Audit info */ + Process->SeAuditProcessCreationInfo.ImageFileName = + ExAllocatePoolWithTag(PagedPool, + sizeof(SE_AUDIT_PROCESS_CREATION_INFO) + + Parent->SeAuditProcessCreationInfo. + ImageFileName->Name.MaximumLength, + TAG_SEPA); + + /* Copy from parent */ + RtlCopyMemory(Process->SeAuditProcessCreationInfo.ImageFileName, + Parent->SeAuditProcessCreationInfo.ImageFileName, + sizeof(SE_AUDIT_PROCESS_CREATION_INFO) + + Parent->SeAuditProcessCreationInfo.ImageFileName-> + Name.MaximumLength); + + /* Update buffer pointer */ + Process->SeAuditProcessCreationInfo.ImageFileName->Name.Buffer = + (PVOID)(Process->SeAuditProcessCreationInfo.ImageFileName + 1); + } +#endif + /* Check if we have a section object */ if (SectionObject) { /* Map the System Dll */ - DPRINT("Mapping System DLL\n"); PspMapSystemDll(Process, NULL); } /* Create a handle for the Process */ - DPRINT("Initialzing Process CID Handle\n"); CidEntry.Object = Process; CidEntry.GrantedAccess = 0; Process->UniqueProcessId = ExCreateHandle(PspCidTable, &CidEntry); - DPRINT("Created CID: %d\n", Process->UniqueProcessId); if(!Process->UniqueProcessId) { DPRINT1("Failed to create CID handle\n"); - Status = STATUS_UNSUCCESSFUL; /* FIXME - what error should we return? */ - goto Cleanup; + Status = STATUS_INSUFFICIENT_RESOURCES; + goto CleanupWithRef; } /* FIXME: Insert into Job Object */ /* Create PEB only for User-Mode Processes */ - if (pParentProcess) + if (Parent) { - DPRINT("Creating PEB\n"); Status = MmCreatePeb(Process); if (!NT_SUCCESS(Status)) { - DbgPrint("NtCreateProcess() Peb creation failed: Status %x\n",Status); - goto Cleanup; + DPRINT("NtCreateProcess() Peb creation failed: Status %x\n",Status); + goto CleanupWithRef; } } - /* W00T! The process can now be activated */ - DPRINT("Inserting into Active Process List\n"); + /* The process can now be activated */ ExAcquireFastMutex(&PspActiveProcessMutex); InsertTailList(&PsActiveProcessHead, &Process->ActiveProcessLinks); ExReleaseFastMutex(&PspActiveProcessMutex); - - ProcessCreated = TRUE; /* FIXME: SeCreateAccessStateEx */ /* Insert the Process into the Object Directory */ - DPRINT("Inserting Process Object\n"); Status = ObInsertObject(Process, NULL, DesiredAccess, 1, (PVOID*)&Process, &hProcess); + + /* FIXME: Compute Quantum and Priority */ + + /* + * FIXME: ObGetObjectSecurity(Process, &SecurityDescriptor) + * SeAccessCheck + */ + ObReferenceObject(Process); // <- Act as if we called ObGetObjectSecurity + + /* Check for success */ if (NT_SUCCESS(Status)) { /* Set the Creation Time */ KeQuerySystemTime(&Process->CreateTime); - DPRINT("Done. Returning handle: %x\n", hProcess); + /* Protect against bad user-mode pointer */ _SEH_TRY { + /* Save the process handle */ *ProcessHandle = hProcess; } _SEH_HANDLE { Status = _SEH_GetExceptionCode(); - } _SEH_END; - /* FIXME: ObGetObjectSecurity(Process, &SecurityDescriptor) - SeAccessCheck - */ + } + _SEH_END; } +CleanupWithRef: + /* + * Dereference the process. For failures, kills the process and does + * cleanup present in PspDeleteProcess. For success, kills the extra + * reference added by ObGetObjectSecurity + */ + ObDereferenceObject(Process); + Cleanup: - if(pParentProcess != NULL) ObDereferenceObject(pParentProcess); - if(SectionObject != NULL) ObDereferenceObject(SectionObject); - if (!ProcessCreated) - { - if(pExceptionPort != NULL) ObDereferenceObject(pExceptionPort); - if(pDebugPort != NULL) ObDereferenceObject(pDebugPort); - if(Process != NULL) ObDereferenceObject(Process); - } + /* Dereference the parent */ + if (Parent) ObDereferenceObject(Parent); + /* Return status to caller */ return Status; } @@ -464,7 +637,7 @@ Cleanup: * @implemented */ NTSTATUS -STDCALL +NTAPI PsCreateSystemProcess(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) @@ -472,18 +645,19 @@ PsCreateSystemProcess(PHANDLE ProcessHandle, return PspCreateProcess(ProcessHandle, DesiredAccess, ObjectAttributes, - NULL, /* no parent process */ - FALSE, + NULL, + 0, NULL, NULL, - NULL); + NULL, + FALSE); } /* * @implemented */ NTSTATUS -STDCALL +NTAPI PsLookupProcessByProcessId(IN HANDLE ProcessId, OUT PEPROCESS *Process) { @@ -491,7 +665,6 @@ PsLookupProcessByProcessId(IN HANDLE ProcessId, PEPROCESS FoundProcess; NTSTATUS Status = STATUS_INVALID_PARAMETER; PAGED_CODE(); - KeEnterCriticalRegion(); /* Get the CID Handle Entry */ @@ -513,10 +686,9 @@ PsLookupProcessByProcessId(IN HANDLE ProcessId, /* Unlock the Entry */ ExUnlockHandleTableEntry(PspCidTable, CidEntry); } - - KeLeaveCriticalRegion(); /* Return to caller */ + KeLeaveCriticalRegion(); return Status; } @@ -524,7 +696,7 @@ PsLookupProcessByProcessId(IN HANDLE ProcessId, * @implemented */ NTSTATUS -STDCALL +NTAPI PsLookupProcessThreadByCid(IN PCLIENT_ID Cid, OUT PEPROCESS *Process OPTIONAL, OUT PETHREAD *Thread) @@ -533,7 +705,6 @@ PsLookupProcessThreadByCid(IN PCLIENT_ID Cid, PETHREAD FoundThread; NTSTATUS Status = STATUS_INVALID_CID; PAGED_CODE(); - KeEnterCriticalRegion(); /* Get the CID Handle Entry */ @@ -565,9 +736,8 @@ PsLookupProcessThreadByCid(IN PCLIENT_ID Cid, ExUnlockHandleTableEntry(PspCidTable, CidEntry); } - KeLeaveCriticalRegion(); - /* Return to caller */ + KeLeaveCriticalRegion(); return Status; } @@ -605,7 +775,7 @@ PsGetProcessExitTime(VOID) * @implemented */ LONGLONG -STDCALL +NTAPI PsGetProcessCreateTimeQuadPart(PEPROCESS Process) { return Process->CreateTime.QuadPart; @@ -615,7 +785,7 @@ PsGetProcessCreateTimeQuadPart(PEPROCESS Process) * @implemented */ PVOID -STDCALL +NTAPI PsGetProcessDebugPort(PEPROCESS Process) { return Process->DebugPort; @@ -625,7 +795,7 @@ PsGetProcessDebugPort(PEPROCESS Process) * @implemented */ BOOLEAN -STDCALL +NTAPI PsGetProcessExitProcessCalled(PEPROCESS Process) { return Process->ProcessExiting; @@ -635,7 +805,7 @@ PsGetProcessExitProcessCalled(PEPROCESS Process) * @implemented */ NTSTATUS -STDCALL +NTAPI PsGetProcessExitStatus(PEPROCESS Process) { return Process->ExitStatus; @@ -645,7 +815,7 @@ PsGetProcessExitStatus(PEPROCESS Process) * @implemented */ HANDLE -STDCALL +NTAPI PsGetProcessId(PEPROCESS Process) { return (HANDLE)Process->UniqueProcessId; @@ -655,7 +825,7 @@ PsGetProcessId(PEPROCESS Process) * @implemented */ LPSTR -STDCALL +NTAPI PsGetProcessImageFileName(PEPROCESS Process) { return (LPSTR)Process->ImageFileName; @@ -665,7 +835,7 @@ PsGetProcessImageFileName(PEPROCESS Process) * @implemented */ HANDLE -STDCALL +NTAPI PsGetProcessInheritedFromUniqueProcessId(PEPROCESS Process) { return Process->InheritedFromUniqueProcessId; @@ -675,7 +845,7 @@ PsGetProcessInheritedFromUniqueProcessId(PEPROCESS Process) * @implemented */ PEJOB -STDCALL +NTAPI PsGetProcessJob(PEPROCESS Process) { return Process->Job; @@ -685,7 +855,7 @@ PsGetProcessJob(PEPROCESS Process) * @implemented */ PPEB -STDCALL +NTAPI PsGetProcessPeb(PEPROCESS Process) { return Process->Peb; @@ -695,7 +865,7 @@ PsGetProcessPeb(PEPROCESS Process) * @implemented */ ULONG -STDCALL +NTAPI PsGetProcessPriorityClass(PEPROCESS Process) { return Process->PriorityClass; @@ -714,7 +884,7 @@ PsGetCurrentProcessId(VOID) * @implemented */ ULONG -STDCALL +NTAPI PsGetCurrentProcessSessionId(VOID) { return PsGetCurrentProcess()->Session; @@ -724,7 +894,7 @@ PsGetCurrentProcessSessionId(VOID) * @implemented */ PVOID -STDCALL +NTAPI PsGetProcessSectionBaseAddress(PEPROCESS Process) { return Process->SectionBaseAddress; @@ -734,7 +904,7 @@ PsGetProcessSectionBaseAddress(PEPROCESS Process) * @implemented */ PVOID -STDCALL +NTAPI PsGetProcessSecurityPort(PEPROCESS Process) { return Process->SecurityPort; @@ -744,7 +914,7 @@ PsGetProcessSecurityPort(PEPROCESS Process) * @implemented */ HANDLE -STDCALL +NTAPI PsGetProcessSessionId(PEPROCESS Process) { return (HANDLE)Process->Session; @@ -768,7 +938,7 @@ PsGetWin32Process(VOID) * @implemented */ PVOID -STDCALL +NTAPI PsGetProcessWin32Process(PEPROCESS Process) { return Process->Win32Process; @@ -778,7 +948,7 @@ PsGetProcessWin32Process(PEPROCESS Process) * @implemented */ PVOID -STDCALL +NTAPI PsGetProcessWin32WindowStation(PEPROCESS Process) { return Process->Win32WindowStation; @@ -798,7 +968,7 @@ PsIsProcessBeingDebugged(PEPROCESS Process) * @implemented */ VOID -STDCALL +NTAPI PsSetProcessPriorityClass(PEPROCESS Process, ULONG PriorityClass) { @@ -809,7 +979,7 @@ PsSetProcessPriorityClass(PEPROCESS Process, * @implemented */ VOID -STDCALL +NTAPI PsSetProcessSecurityPort(PEPROCESS Process, PVOID SecurityPort) { @@ -820,7 +990,7 @@ PsSetProcessSecurityPort(PEPROCESS Process, * @implemented */ VOID -STDCALL +NTAPI PsSetProcessWin32Process(PEPROCESS Process, PVOID Win32Process) { @@ -831,7 +1001,7 @@ PsSetProcessWin32Process(PEPROCESS Process, * @implemented */ VOID -STDCALL +NTAPI PsSetProcessWindowStation(PEPROCESS Process, PVOID WindowStation) { @@ -842,7 +1012,7 @@ PsSetProcessWindowStation(PEPROCESS Process, * @unimplemented */ NTSTATUS -STDCALL +NTAPI PsSetProcessPriorityByClass(IN PEPROCESS Process, IN ULONG Type) { @@ -851,38 +1021,19 @@ PsSetProcessPriorityByClass(IN PEPROCESS Process, } /* - * FUNCTION: Creates a process. - * ARGUMENTS: - * ProcessHandle (OUT) = Caller supplied storage for the resulting - * handle - * DesiredAccess = Specifies the allowed or desired access to the - * process can be a combination of - * STANDARD_RIGHTS_REQUIRED| .. - * ObjectAttribute = Initialized attributes for the object, contains - * the rootdirectory and the filename - * ParentProcess = Handle to the parent process. - * InheritObjectTable = Specifies to inherit the objects of the parent - * process if true. - * SectionHandle = Handle to a section object to back the image file - * DebugPort = Handle to a DebugPort if NULL the system default debug - * port will be used. - * ExceptionPort = Handle to a exception port. - * REMARKS: - * This function maps to the win32 CreateProcess. - * RETURNS: Status - * * @implemented */ NTSTATUS -STDCALL -NtCreateProcess(OUT PHANDLE ProcessHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, - IN HANDLE ParentProcess, - IN BOOLEAN InheritObjectTable, - IN HANDLE SectionHandle OPTIONAL, - IN HANDLE DebugPort OPTIONAL, - IN HANDLE ExceptionPort OPTIONAL) +NTAPI +NtCreateProcessEx(OUT PHANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN HANDLE ParentProcess, + IN ULONG Flags, + IN HANDLE SectionHandle OPTIONAL, + IN HANDLE DebugPort OPTIONAL, + IN HANDLE ExceptionPort OPTIONAL, + IN BOOLEAN InJob) { KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); NTSTATUS Status = STATUS_SUCCESS; @@ -906,7 +1057,7 @@ NtCreateProcess(OUT PHANDLE ProcessHandle, } /* Make sure there's a parent process */ - if(ParentProcess == NULL) + if(!ParentProcess) { /* Can't create System Processes like this */ Status = STATUS_INVALID_PARAMETER; @@ -918,10 +1069,11 @@ NtCreateProcess(OUT PHANDLE ProcessHandle, DesiredAccess, ObjectAttributes, ParentProcess, - InheritObjectTable, + Flags, SectionHandle, DebugPort, - ExceptionPort); + ExceptionPort, + InJob); } /* Return Status */ @@ -932,11 +1084,44 @@ NtCreateProcess(OUT PHANDLE ProcessHandle, * @implemented */ NTSTATUS -STDCALL +NTAPI +NtCreateProcess(OUT PHANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN HANDLE ParentProcess, + IN BOOLEAN InheritObjectTable, + IN HANDLE SectionHandle OPTIONAL, + IN HANDLE DebugPort OPTIONAL, + IN HANDLE ExceptionPort OPTIONAL) +{ + ULONG Flags = 0; + + /* Set new-style flags */ + if ((ULONG)SectionHandle & 1) Flags = PS_REQUEST_BREAKAWAY; + if ((ULONG)DebugPort & 1) Flags |= PS_NO_DEBUG_INHERIT; + if (InheritObjectTable) Flags |= PS_INHERIT_HANDLES; + + /* Call the new API */ + return NtCreateProcessEx(ProcessHandle, + DesiredAccess, + ObjectAttributes, + ParentProcess, + Flags, + SectionHandle, + DebugPort, + ExceptionPort, + FALSE); +} + +/* + * @implemented + */ +NTSTATUS +NTAPI NtOpenProcess(OUT PHANDLE ProcessHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN PCLIENT_ID ClientId) + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN PCLIENT_ID ClientId) { KPROCESSOR_MODE PreviousMode; CLIENT_ID SafeClientId; @@ -997,11 +1182,9 @@ NtOpenProcess(OUT PHANDLE ProcessHandle, } /* Open by name if one was given */ - DPRINT("Checking type\n"); if (HasObjectName) { /* Open it */ - DPRINT("Opening by name\n"); Status = ObOpenObjectByName(ObjectAttributes, PsProcessType, PreviousMode, @@ -1021,7 +1204,6 @@ NtOpenProcess(OUT PHANDLE ProcessHandle, if (ClientId->UniqueThread) { /* Get the Process */ - DPRINT("Opening by Thread ID: %x\n", ClientId->UniqueThread); Status = PsLookupProcessThreadByCid(ClientId, &Process, &Thread); @@ -1029,7 +1211,6 @@ NtOpenProcess(OUT PHANDLE ProcessHandle, else { /* Get the Process */ - DPRINT("Opening by Process ID: %x\n", ClientId->UniqueProcess); Status = PsLookupProcessByProcessId(ClientId->UniqueProcess, &Process); } diff --git a/reactos/ntoskrnl/ps/psmgr.c b/reactos/ntoskrnl/ps/psmgr.c index d1b32f6d16c..c2aea28e6f1 100644 --- a/reactos/ntoskrnl/ps/psmgr.c +++ b/reactos/ntoskrnl/ps/psmgr.c @@ -64,15 +64,6 @@ NTSTATUS STDCALL INIT_FUNCTION PspLookupKernelUserEntryPoints(VOID); /* FUNCTIONS ***************************************************************/ -VOID -NTAPI -PiShutdownProcessManager(VOID) -{ - DPRINT("PiShutdownProcessManager()\n"); - - PspKillMostProcesses(); -} - VOID INIT_FUNCTION NTAPI diff --git a/reactos/ntoskrnl/ps/security.c b/reactos/ntoskrnl/ps/security.c index cb64047fc95..f61028d86a0 100644 --- a/reactos/ntoskrnl/ps/security.c +++ b/reactos/ntoskrnl/ps/security.c @@ -39,6 +39,40 @@ PspUnlockProcessSecurityShared(PEPROCESS Process) KeLeaveGuardedRegion(); } +VOID +NTAPI +PspDeleteProcessSecurity(IN PEPROCESS Process) +{ + /* Check if we have a token */ + if (Process->Token.Object) + { + /* Deassign it */ + SeDeassignPrimaryToken(Process); + Process->Token.Object = NULL; + } +} + +VOID +NTAPI +PspDeleteThreadSecurity(IN PETHREAD Thread) +{ + /* Check if we have active impersonation info */ + if (Thread->ActiveImpersonationInfo) + { + /* Dereference its token */ + ObDereferenceObject(Thread->ImpersonationInfo->Token); + } + + /* Check if we have impersonation info */ + if (Thread->ImpersonationInfo) + { + /* Free it */ + ExFreePool(Thread->ImpersonationInfo); + Thread->ActiveImpersonationInfo = FALSE; + Thread->ImpersonationInfo = NULL; + } +} + /* FUNCTIONS *****************************************************************/ /* diff --git a/reactos/ntoskrnl/ps/thread.c b/reactos/ntoskrnl/ps/thread.c index 4c4028949ba..37a7ab906d1 100644 --- a/reactos/ntoskrnl/ps/thread.c +++ b/reactos/ntoskrnl/ps/thread.c @@ -1,11 +1,23 @@ /* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory * FILE: ntoskrnl/ps/thread.c - * PURPOSE: Thread managment - * - * PROGRAMMERS: David Welch (welch@mcmail.com) - * Phillip Susi + * PURPOSE: Process Manager: Thread Management + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + * Thomas Weidenmueller (w3seek@reactos.org + */ + +/* + * Alex FIXMEs: + * - CRITICAL: NtCurrentTeb returns KPCR. + * - CRITICAL: Verify rundown APIs (ex/rundown.c) and use them where necessary. + * - MAJOR: Implement Pushlocks and use them as process lock. + * - MAJOR: Implement Safe Referencing (See PsGetNextProcess/Thread). + * - MAJOR: Implement Fast Referencing (mostly for tokens). + * - MAJOR: Use Guarded Mutex instead of Fast Mutex for Active Process Locks. + * - Generate process cookie for user-more thread. + * - Add security calls where necessary. + * - KeInit/StartThread for better isolation of code */ /* INCLUDES ****************************************************************/ @@ -19,83 +31,112 @@ extern LIST_ENTRY PsActiveProcessHead; extern PEPROCESS PsIdleProcess; extern PVOID PspSystemDllEntryPoint; +extern PVOID PspSystemDllBase; extern PHANDLE_TABLE PspCidTable; - +extern BOOLEAN CcPfEnablePrefetcher; +extern ULONG MmReadClusterSize; POBJECT_TYPE PsThreadType = NULL; /* FUNCTIONS ***************************************************************/ VOID -STDCALL -PspThreadSpecialApc(PKAPC Apc, - PKNORMAL_ROUTINE* NormalRoutine, - PVOID* NormalContext, - PVOID* SystemArgument1, - PVOID* SystemArgument2) -{ - ExFreePool(Apc); -} - -VOID -STDCALL +NTAPI PspUserThreadStartup(PKSTART_ROUTINE StartRoutine, PVOID StartContext) { - PKAPC ThreadApc; - PETHREAD Thread = PsGetCurrentThread(); + PETHREAD Thread; + PTEB Teb; + BOOLEAN DeadThread = FALSE; + PAGED_CODE(); - DPRINT("I am a new USER thread. This is my start routine: %p. This my context: %p." - "This is my IRQL: %d. This is my Thread Pointer: %x.\n", StartRoutine, - StartContext, KeGetCurrentIrql(), Thread); + /* Go to Passive Level */ + KeLowerIrql(PASSIVE_LEVEL); + Thread = PsGetCurrentThread(); - if (!Thread->Terminated) { + /* Check if the thread is dead */ + if (Thread->DeadThread) + { + /* Remember that we're dead */ + DPRINT1("This thread is already dead\n"); + DeadThread = TRUE; +} + else + { + /* Get the Locale ID and save Preferred Proc */ + Teb = NtCurrentTeb(); /* FIXME: This returns KPCR!!! */ + //Teb->CurrentLocale = MmGetSessionLocaleId(); + //Teb->IdealProcessor = Thread->Tcb.IdealProcessor; + } - /* Allocate the APC */ - ThreadApc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG('T', 'h', 'r','d')); + /* Check if this is a system thread, or if we're hiding */ + if ((Thread->SystemThread) || (Thread->HideFromDebugger)) +{ + /* Notify the debugger */ + DbgkCreateThread(StartContext); + } - /* Initialize it */ - KeInitializeApc(ThreadApc, - &Thread->Tcb, - OriginalApcEnvironment, - PspThreadSpecialApc, + /* Make sure we're not already dead */ + if (!DeadThread) + { + /* Check if the Prefetcher is enabled */ + if (CcPfEnablePrefetcher) + { + /* FIXME: Prepare to prefetch this process */ + } + + /* Raise to APC */ + KfRaiseIrql(APC_LEVEL); + + /* Queue the User APC */ + KiInitializeUserApc(NULL, + (PVOID)((ULONG_PTR)Thread->Tcb.InitialStack - + sizeof(KTRAP_FRAME) - + sizeof(FX_SAVE_AREA)), + PspSystemDllEntryPoint, NULL, - PspSystemDllEntryPoint, - UserMode, + PspSystemDllBase, NULL); - /* Insert it into the queue */ - KeInsertQueueApc(ThreadApc, NULL, NULL, IO_NO_INCREMENT); - Thread->Tcb.ApcState.UserApcPending = TRUE; + /* Lower it back to passive */ + KeLowerIrql(PASSIVE_LEVEL); + } + else + { + /* We're dead, kill us now */ + PspTerminateThreadByPointer(Thread, STATUS_THREAD_IS_TERMINATING, TRUE); } - /* Go to Passive Level and notify debugger */ - KeLowerIrql(PASSIVE_LEVEL); - DbgkCreateThread(StartContext); + /* Do we have a cookie set yet? */ + if (!SharedUserData->Cookie) + { + /* FIXME: Generate cookie */ + } } VOID -STDCALL +NTAPI PspSystemThreadStartup(PKSTART_ROUTINE StartRoutine, PVOID StartContext) { - PETHREAD Thread = PsGetCurrentThread(); + PETHREAD Thread; /* Unlock the dispatcher Database */ KeLowerIrql(PASSIVE_LEVEL); + Thread = PsGetCurrentThread(); - /* Make sure it's not terminated by now */ - if (!Thread->Terminated) { - - /* Call it */ - (StartRoutine)(StartContext); + /* Make sure the thread isn't gone */ + if (!(Thread->Terminated) || !(Thread->DeadThread)) + { + /* Call it the Start Routine */ + StartRoutine(StartContext); } /* Exit the thread */ - PspExitThread(STATUS_SUCCESS); + PspTerminateThreadByPointer(Thread, STATUS_SUCCESS, TRUE); } NTSTATUS -STDCALL +NTAPI PspCreateThread(OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, @@ -117,46 +158,54 @@ PspCreateThread(OUT PHANDLE ThreadHandle, NTSTATUS Status; HANDLE_TABLE_ENTRY CidEntry; ULONG_PTR KernelStack; + PAGED_CODE(); - /* Reference the Process by handle or pointer, depending on what we got */ - DPRINT("PspCreateThread: %x, %x, %x\n", ProcessHandle, TargetProcess, ThreadContext); - if (ProcessHandle) { + /* If we were called from PsCreateSystemThread, then we're kernel mode */ + if (StartRoutine) PreviousMode = KernelMode; + /* Reference the Process by handle or pointer, depending on what we got */ + if (ProcessHandle) + { /* Normal thread or System Thread */ - DPRINT("Referencing Parent Process\n"); Status = ObReferenceObjectByHandle(ProcessHandle, PROCESS_CREATE_THREAD, PsProcessType, PreviousMode, (PVOID*)&Process, NULL); - } else { - + } + else + { /* System thread inside System Process, or Normal Thread with a bug */ - if (StartRoutine) { - + if (StartRoutine) + { /* Reference the Process by Pointer */ - DPRINT("Referencing Parent System Process\n"); ObReferenceObject(TargetProcess); Process = TargetProcess; Status = STATUS_SUCCESS; - - } else { - + } + else + { /* Fake ObReference returning this */ Status = STATUS_INVALID_HANDLE; } } /* Check for success */ - if(!NT_SUCCESS(Status)) { - + if(!NT_SUCCESS(Status)) + { DPRINT1("Invalid Process Handle, or no handle given\n"); - return(Status); + return Status; + } + + /* Also make sure that User-Mode isn't trying to create a system thread */ + if ((PreviousMode != KernelMode) && (Process == PsInitialSystemProcess)) + { + ObDereferenceObject(Process); + return STATUS_INVALID_HANDLE; } /* Create Thread Object */ - DPRINT("Creating Thread Object\n"); Status = ObCreateObject(PreviousMode, PsThreadType, ObjectAttributes, @@ -166,69 +215,61 @@ PspCreateThread(OUT PHANDLE ThreadHandle, 0, 0, (PVOID*)&Thread); - - /* Check for success */ - if (!NT_SUCCESS(Status)) { - - /* Dereference the Process */ + if (!NT_SUCCESS(Status)) + { + /* We failed; dereference the process and exit */ DPRINT1("Failed to Create Thread Object\n"); ObDereferenceObject(Process); - return(Status); + return Status; } /* Zero the Object entirely */ - DPRINT("Cleaning Thread Object\n"); RtlZeroMemory(Thread, sizeof(ETHREAD)); + /* Set the Process CID */ + Thread->ThreadsProcess = Process; + Thread->Cid.UniqueProcess = Process->UniqueProcessId; + /* Create Cid Handle */ - DPRINT("Creating Thread Handle (CID)\n"); CidEntry.Object = Thread; CidEntry.GrantedAccess = 0; Thread->Cid.UniqueThread = ExCreateHandle(PspCidTable, &CidEntry); - if (!Thread->Cid.UniqueThread) { - + if (!Thread->Cid.UniqueThread) + { + /* We couldn't create the CID, dereference everything and fail */ DPRINT1("Failed to create Thread Handle (CID)\n"); ObDereferenceObject(Process); ObDereferenceObject(Thread); return STATUS_INSUFFICIENT_RESOURCES; } - /* Initialize Lists */ - DPRINT("Initialliazing Thread Lists and Locks\n"); + /* Save the read cluster size */ + Thread->ReadClusterSize = MmReadClusterSize; + + /* Initialize the LPC Reply Semaphore */ + KeInitializeSemaphore(&Thread->LpcReplySemaphore, 0, MAXLONG); + + /* Initialize the list heads and locks */ InitializeListHead(&Thread->LpcReplyChain); InitializeListHead(&Thread->IrpList); + InitializeListHead(&Thread->PostBlockList); InitializeListHead(&Thread->ActiveTimerListHead); KeInitializeSpinLock(&Thread->ActiveTimerListLock); - /* Initialize LPC */ - DPRINT("Initialliazing Thread Semaphore\n"); - KeInitializeSemaphore(&Thread->LpcReplySemaphore, 0, MAXLONG); - /* Allocate Stack for non-GUI Thread */ - DPRINT("Initialliazing Thread Stack\n"); KernelStack = (ULONG_PTR)MmCreateKernelStack(FALSE) + KERNEL_STACK_SIZE; - /* Set the Process CID */ - DPRINT("Initialliazing Thread PID and Parent Process\n"); - Thread->Cid.UniqueProcess = Process->UniqueProcessId; - Thread->ThreadsProcess = Process; - /* Now let the kernel initialize the context */ - if (ThreadContext) { - - /* User-mode Thread */ - - /* Create Teb */ - DPRINT("Initialliazing Thread PEB\n"); + if (ThreadContext) + { + /* User-mode Thread, create Teb */ TebBase = MmCreateTeb(Process, &Thread->Cid, InitialTeb); /* Set the Start Addresses */ - DPRINT("Initialliazing Thread Start Addresses :%x, %x\n", ThreadContext->Eip, ThreadContext->Eax); Thread->StartAddress = (PVOID)ThreadContext->Eip; Thread->Win32StartAddress = (PVOID)ThreadContext->Eax; /* Let the kernel intialize the Thread */ - DPRINT("Initialliazing Kernel Thread\n"); KeInitializeThread(&Process->Pcb, &Thread->Tcb, PspUserThreadStartup, @@ -237,16 +278,14 @@ PspCreateThread(OUT PHANDLE ThreadHandle, ThreadContext, TebBase, (PVOID)KernelStack); - - } else { - + } + else + { /* System Thread */ - DPRINT("Initialliazing Thread Start Address :%x\n", StartRoutine); Thread->StartAddress = StartRoutine; - Thread->SystemThread = TRUE; + InterlockedOr(&Thread->CrossThreadFlags, 0x10); /* Let the kernel intialize the Thread */ - DPRINT("Initialliazing Kernel Thread\n"); KeInitializeThread(&Process->Pcb, &Thread->Tcb, PspSystemThreadStartup, @@ -262,61 +301,63 @@ PspCreateThread(OUT PHANDLE ThreadHandle, * Note, this is the ETHREAD Thread List. It is removed in * ps/kill.c!PspExitThread. */ - DPRINT("Inserting into Process Thread List \n"); InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry); + Process->ActiveThreads++; + + /* Notify WMI */ + //WmiTraceProcess(Process, TRUE); + //WmiTraceThread(Thread, InitialTeb, TRUE); /* Notify Thread Creation */ - DPRINT("Running Thread Notify \n"); PspRunCreateThreadNotifyRoutines(Thread, TRUE); /* Suspend the Thread if we have to */ - if (CreateSuspended) { - - DPRINT("Suspending Thread\n"); + if (CreateSuspended) + { KeSuspendThread(&Thread->Tcb); } + /* Check if we were already terminated */ + if (Thread->Terminated) + { + /* Force us to wake up to terminate */ + KeForceResumeThread(&Thread->Tcb); + } + /* Reference ourselves as a keep-alive */ ObReferenceObject(Thread); /* Insert the Thread into the Object Manager */ - DPRINT("Inserting Thread\n"); Status = ObInsertObject((PVOID)Thread, NULL, DesiredAccess, 0, NULL, &hThread); - - /* Return Cid and Handle */ - DPRINT("All worked great!\n"); - if(NT_SUCCESS(Status)) { - - _SEH_TRY { - - if(ClientId != NULL) { - - *ClientId = Thread->Cid; - } + if(NT_SUCCESS(Status)) + { + /* Wrap in SEH to protect against bad user-mode pointers */ + _SEH_TRY + { + /* Return Cid and Handle */ + if(ClientId) *ClientId = Thread->Cid; *ThreadHandle = hThread; - - } _SEH_HANDLE { - + } + _SEH_HANDLE + { Status = _SEH_GetExceptionCode(); - - } _SEH_END; + } + _SEH_END; } /* FIXME: SECURITY */ /* Dispatch thread */ - DPRINT("About to dispatch the thread: %x!\n", &Thread->Tcb); OldIrql = KeAcquireDispatcherDatabaseLock (); KiUnblockThread(&Thread->Tcb, NULL, 0); KeReleaseDispatcherDatabaseLock(OldIrql); /* Return */ - DPRINT("Returning\n"); return Status; } @@ -324,7 +365,7 @@ PspCreateThread(OUT PHANDLE ThreadHandle, * @implemented */ NTSTATUS -STDCALL +NTAPI PsCreateSystemThread(PHANDLE ThreadHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, @@ -335,10 +376,11 @@ PsCreateSystemThread(PHANDLE ThreadHandle, { PEPROCESS TargetProcess = NULL; HANDLE Handle = ProcessHandle; + PAGED_CODE(); /* Check if we have a handle. If not, use the System Process */ - if (!ProcessHandle) { - + if (!ProcessHandle) + { Handle = NULL; TargetProcess = PsInitialSystemProcess; } @@ -361,7 +403,7 @@ PsCreateSystemThread(PHANDLE ThreadHandle, * @implemented */ NTSTATUS -STDCALL +NTAPI PsLookupThreadByThreadId(IN HANDLE ThreadId, OUT PETHREAD *Thread) { @@ -369,7 +411,6 @@ PsLookupThreadByThreadId(IN HANDLE ThreadId, PETHREAD FoundThread; NTSTATUS Status = STATUS_INVALID_PARAMETER; PAGED_CODE(); - KeEnterCriticalRegion(); /* Get the CID Handle Entry */ @@ -392,9 +433,8 @@ PsLookupThreadByThreadId(IN HANDLE ThreadId, ExUnlockHandleTableEntry(PspCidTable, CidEntry); } - KeLeaveCriticalRegion(); - /* Return to caller */ + KeLeaveCriticalRegion(); return Status; } @@ -402,7 +442,7 @@ PsLookupThreadByThreadId(IN HANDLE ThreadId, * @implemented */ HANDLE -STDCALL +NTAPI PsGetCurrentThreadId(VOID) { return(PsGetCurrentThread()->Cid.UniqueThread); @@ -412,7 +452,7 @@ PsGetCurrentThreadId(VOID) * @implemented */ ULONG -STDCALL +NTAPI PsGetThreadFreezeCount(PETHREAD Thread) { return Thread->Tcb.FreezeCount; @@ -422,7 +462,7 @@ PsGetThreadFreezeCount(PETHREAD Thread) * @implemented */ BOOLEAN -STDCALL +NTAPI PsGetThreadHardErrorsAreDisabled(PETHREAD Thread) { return Thread->HardErrorsAreDisabled; @@ -432,7 +472,7 @@ PsGetThreadHardErrorsAreDisabled(PETHREAD Thread) * @implemented */ HANDLE -STDCALL +NTAPI PsGetThreadId(PETHREAD Thread) { return Thread->Cid.UniqueThread; @@ -442,7 +482,7 @@ PsGetThreadId(PETHREAD Thread) * @implemented */ PEPROCESS -STDCALL +NTAPI PsGetThreadProcess(PETHREAD Thread) { return Thread->ThreadsProcess; @@ -452,7 +492,7 @@ PsGetThreadProcess(PETHREAD Thread) * @implemented */ HANDLE -STDCALL +NTAPI PsGetThreadProcessId(PETHREAD Thread) { return Thread->Cid.UniqueProcess; @@ -462,7 +502,7 @@ PsGetThreadProcessId(PETHREAD Thread) * @implemented */ HANDLE -STDCALL +NTAPI PsGetThreadSessionId(PETHREAD Thread) { return (HANDLE)Thread->ThreadsProcess->Session; @@ -472,7 +512,7 @@ PsGetThreadSessionId(PETHREAD Thread) * @implemented */ PTEB -STDCALL +NTAPI PsGetThreadTeb(PETHREAD Thread) { return Thread->Tcb.Teb; @@ -482,7 +522,7 @@ PsGetThreadTeb(PETHREAD Thread) * @implemented */ PVOID -STDCALL +NTAPI PsGetThreadWin32Thread(PETHREAD Thread) { return Thread->Tcb.Win32Thread; @@ -492,7 +532,7 @@ PsGetThreadWin32Thread(PETHREAD Thread) * @implemented */ KPROCESSOR_MODE -STDCALL +NTAPI PsGetCurrentThreadPreviousMode(VOID) { return (KPROCESSOR_MODE)PsGetCurrentThread()->Tcb.PreviousMode; @@ -502,7 +542,7 @@ PsGetCurrentThreadPreviousMode(VOID) * @implemented */ PVOID -STDCALL +NTAPI PsGetCurrentThreadStackBase(VOID) { return PsGetCurrentThread()->Tcb.StackBase; @@ -512,7 +552,7 @@ PsGetCurrentThreadStackBase(VOID) * @implemented */ PVOID -STDCALL +NTAPI PsGetCurrentThreadStackLimit(VOID) { return (PVOID)PsGetCurrentThread()->Tcb.StackLimit; @@ -522,7 +562,7 @@ PsGetCurrentThreadStackLimit(VOID) * @implemented */ BOOLEAN -STDCALL +NTAPI PsIsThreadTerminating(IN PETHREAD Thread) { return (Thread->Terminated ? TRUE : FALSE); @@ -532,7 +572,7 @@ PsIsThreadTerminating(IN PETHREAD Thread) * @implemented */ BOOLEAN -STDCALL +NTAPI PsIsSystemThread(PETHREAD Thread) { return (Thread->SystemThread ? TRUE: FALSE); @@ -542,7 +582,7 @@ PsIsSystemThread(PETHREAD Thread) * @implemented */ BOOLEAN -STDCALL +NTAPI PsIsThreadImpersonating(PETHREAD Thread) { return Thread->ActiveImpersonationInfo; @@ -552,7 +592,7 @@ PsIsThreadImpersonating(PETHREAD Thread) * @implemented */ VOID -STDCALL +NTAPI PsSetThreadHardErrorsAreDisabled(PETHREAD Thread, BOOLEAN HardErrorsAreDisabled) { @@ -563,7 +603,7 @@ PsSetThreadHardErrorsAreDisabled(PETHREAD Thread, * @implemented */ VOID -STDCALL +NTAPI PsSetThreadWin32Thread(PETHREAD Thread, PVOID Win32Thread) { @@ -571,7 +611,7 @@ PsSetThreadWin32Thread(PETHREAD Thread, } NTSTATUS -STDCALL +NTAPI NtCreateThread(OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, @@ -582,55 +622,53 @@ NtCreateThread(OUT PHANDLE ThreadHandle, IN BOOLEAN CreateSuspended) { INITIAL_TEB SafeInitialTeb; - CONTEXT SafeContext; NTSTATUS Status = STATUS_SUCCESS; - PAGED_CODE(); - DPRINT("NtCreateThread(ThreadHandle %x, PCONTEXT %x)\n", - ThreadHandle,ThreadContext); - - if(KeGetPreviousMode() != KernelMode) { - - if (ThreadContext == NULL) { + /* Check if this was from user-mode */ + if(KeGetPreviousMode() != KernelMode) + { + /* Make sure that we got a context */ + if (!ThreadContext) + { DPRINT1("No context for User-Mode Thread!!\n"); return STATUS_INVALID_PARAMETER; } - _SEH_TRY { - + /* Protect checks */ + _SEH_TRY + { + /* Make sure the handle pointer we got is valid */ ProbeForWriteHandle(ThreadHandle); - if(ClientId != NULL) { - - ProbeForWrite(ClientId, - sizeof(CLIENT_ID), - sizeof(ULONG)); + /* Check if the caller wants a client id */ + if(ClientId) + { + /* Make sure we can write to it */ + ProbeForWrite(ClientId, sizeof(CLIENT_ID), sizeof(ULONG)); } - if(ThreadContext != NULL) { - - ProbeForRead(ThreadContext, - sizeof(CONTEXT), - sizeof(ULONG)); - SafeContext = *ThreadContext; - ThreadContext = &SafeContext; - } + /* Make sure that the entire context is readable */ + ProbeForRead(ThreadContext, sizeof(CONTEXT), sizeof(ULONG)); - ProbeForRead(InitialTeb, - sizeof(INITIAL_TEB), - sizeof(ULONG)); + /* Check the Initial TEB */ + ProbeForRead(InitialTeb, sizeof(INITIAL_TEB), sizeof(ULONG)); SafeInitialTeb = *InitialTeb; - InitialTeb = &SafeInitialTeb; - - } _SEH_HANDLE { - + } + _SEH_HANDLE + { Status = _SEH_GetExceptionCode(); + } + _SEH_END; - } _SEH_END; - + /* Handle any failures in our SEH checks */ if (!NT_SUCCESS(Status)) return Status; } + else + { + /* Use the Initial TEB as is */ + SafeInitialTeb = *InitialTeb; + } /* Call the shared function */ return PspCreateThread(ThreadHandle, @@ -640,7 +678,7 @@ NtCreateThread(OUT PHANDLE ThreadHandle, NULL, ClientId, ThreadContext, - InitialTeb, + &SafeInitialTeb, CreateSuspended, NULL, NULL); @@ -650,7 +688,7 @@ NtCreateThread(OUT PHANDLE ThreadHandle, * @implemented */ NTSTATUS -STDCALL +NTAPI NtOpenThread(OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, @@ -724,19 +762,14 @@ NtOpenThread(OUT PHANDLE ThreadHandle, DesiredAccess, NULL, &hThread); - - if (!NT_SUCCESS(Status)) - { - DPRINT1("Could not open object by name\n"); + if (!NT_SUCCESS(Status)) DPRINT1("Could not open object by name\n"); } - } else if (ClientId != NULL) { /* Open by Thread ID */ if (ClientId->UniqueProcess) { /* Get the Process */ - DPRINT("Opening by Process ID: %x\n", ClientId->UniqueProcess); Status = PsLookupProcessThreadByCid(ClientId, NULL, &Thread); @@ -744,7 +777,6 @@ NtOpenThread(OUT PHANDLE ThreadHandle, else { /* Get the Process */ - DPRINT("Opening by Thread ID: %x\n", ClientId->UniqueThread); Status = PsLookupThreadByThreadId(ClientId->UniqueThread, &Thread); } @@ -777,11 +809,13 @@ NtOpenThread(OUT PHANDLE ThreadHandle, return STATUS_INVALID_PARAMETER_MIX; } - /* Write back the handle */ + /* Check for success */ if(NT_SUCCESS(Status)) { + /* Protect against bad user-mode pointers */ _SEH_TRY { + /* Write back the handle */ *ThreadHandle = hThread; } _SEH_HANDLE @@ -796,7 +830,7 @@ NtOpenThread(OUT PHANDLE ThreadHandle, } NTSTATUS -STDCALL +NTAPI NtYieldExecution(VOID) { KiDispatchThread(Ready); @@ -804,7 +838,7 @@ NtYieldExecution(VOID) } NTSTATUS -STDCALL +NTAPI NtTestAlert(VOID) { /* Check and Alert Thread if needed */ @@ -815,7 +849,7 @@ NtTestAlert(VOID) * @implemented */ KPROCESSOR_MODE -STDCALL +NTAPI ExGetPreviousMode (VOID) { return (KPROCESSOR_MODE)PsGetCurrentThread()->Tcb.PreviousMode; diff --git a/reactos/ntoskrnl/ps/win32.c b/reactos/ntoskrnl/ps/win32.c index f974e424301..75824c348a9 100644 --- a/reactos/ntoskrnl/ps/win32.c +++ b/reactos/ntoskrnl/ps/win32.c @@ -16,8 +16,8 @@ /* GLOBALS ******************************************************************/ -static PKWIN32_PROCESS_CALLOUT PspWin32ProcessCallback = NULL; -static PKWIN32_THREAD_CALLOUT PspWin32ThreadCallback = NULL; +PKWIN32_PROCESS_CALLOUT PspW32ProcessCallout = NULL; +PKWIN32_THREAD_CALLOUT PspW32ThreadCallout = NULL; extern PKWIN32_PARSEMETHOD_CALLOUT ExpWindowStationObjectParse; extern PKWIN32_DELETEMETHOD_CALLOUT ExpWindowStationObjectDelete; extern PKWIN32_DELETEMETHOD_CALLOUT ExpDesktopObjectDelete; @@ -53,8 +53,8 @@ VOID STDCALL PsEstablishWin32Callouts(PWIN32_CALLOUTS_FPNS CalloutData) { - PspWin32ProcessCallback = CalloutData->ProcessCallout; - PspWin32ThreadCallback = CalloutData->ThreadCallout; + PspW32ProcessCallout = CalloutData->ProcessCallout; + PspW32ThreadCallout = CalloutData->ThreadCallout; ExpWindowStationObjectParse = CalloutData->WindowStationParseProcedure; ExpWindowStationObjectDelete = CalloutData->WindowStationDeleteProcedure; ExpDesktopObjectDelete = CalloutData->DesktopDeleteProcedure; @@ -79,7 +79,7 @@ PsConvertToGuiThread(VOID) } /* Make sure win32k is here */ - if (!PspWin32ProcessCallback) + if (!PspW32ProcessCallout) { DPRINT1("Danger: Win32K call attempted but Win32k not ready!\n"); return STATUS_ACCESS_DENIED; @@ -122,7 +122,7 @@ PsConvertToGuiThread(VOID) if (!Process->Win32Process) { /* Now tell win32k about us */ - Status = PspWin32ProcessCallback(Process, TRUE); + Status = PspW32ProcessCallout(Process, TRUE); if (!NT_SUCCESS(Status)) { DPRINT1("Danger: Win32k wasn't happy about us!\n"); @@ -135,7 +135,7 @@ PsConvertToGuiThread(VOID) ASSERT(Thread->Tcb.Win32Thread == 0); /* Tell Win32k about our thread */ - Status = PspWin32ThreadCallback(Thread, PsW32ThreadCalloutInitialize); + Status = PspW32ThreadCallout(Thread, PsW32ThreadCalloutInitialize); if (!NT_SUCCESS(Status)) { /* Revert our table */ @@ -147,39 +147,6 @@ PsConvertToGuiThread(VOID) return Status; } -VOID -NTAPI -PsTerminateWin32Process (PEPROCESS Process) -{ - if (Process->Win32Process == NULL) - return; - - if (PspWin32ProcessCallback != NULL) - { - PspWin32ProcessCallback (Process, FALSE); - } - - /* don't delete the W32PROCESS structure at this point, wait until the - EPROCESS structure is being freed */ -} - - -VOID -NTAPI -PsTerminateWin32Thread (PETHREAD Thread) -{ - if (Thread->Tcb.Win32Thread != NULL) - { - if (PspWin32ThreadCallback != NULL) - { - PspWin32ThreadCallback (Thread, PsW32ThreadCalloutExit); - } - - /* don't delete the W32THREAD structure at this point, wait until the - ETHREAD structure is being freed */ - } -} - NTSTATUS STDCALL NtW32Call(IN ULONG RoutineIndex, diff --git a/reactos/ntoskrnl/se/audit.c b/reactos/ntoskrnl/se/audit.c index 9455418d554..2cfca0d6f39 100644 --- a/reactos/ntoskrnl/se/audit.c +++ b/reactos/ntoskrnl/se/audit.c @@ -13,6 +13,22 @@ #include #include +/* INTERNAL *****************************************************************/ + +BOOLEAN +NTAPI +SeDetailedAuditingWithToken(IN PTOKEN Token) +{ + /* FIXME */ + return FALSE; +} + +VOID +NTAPI +SeAuditProcessExit(IN PEPROCESS Process) +{ + /* FIXME */ +} /* FUNCTIONS ****************************************************************/ -- 2.17.1