From f67131616e4795e272a23d4e26ccf9f945c31a96 Mon Sep 17 00:00:00 2001 From: Thomas Bluemel Date: Fri, 21 Jan 2005 14:12:03 +0000 Subject: [PATCH] partial implementation of NtAssignProcessToJobObject() and NtCreateJobObject() svn path=/trunk/; revision=13184 --- reactos/ntoskrnl/ps/job.c | 194 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 184 insertions(+), 10 deletions(-) diff --git a/reactos/ntoskrnl/ps/job.c b/reactos/ntoskrnl/ps/job.c index 906af79c0cc..32ddfc797a7 100644 --- a/reactos/ntoskrnl/ps/job.c +++ b/reactos/ntoskrnl/ps/job.c @@ -19,7 +19,7 @@ POBJECT_TYPE EXPORTED PsJobType = NULL; LIST_ENTRY PsJobListHead; -static KSPIN_LOCK PsJobListLock; +static FAST_MUTEX PsJobListLock; static GENERIC_MAPPING PiJobMapping = {STANDARD_RIGHTS_READ | JOB_OBJECT_QUERY, STANDARD_RIGHTS_WRITE | JOB_OBJECT_ASSIGN_PROCESS | JOB_OBJECT_SET_ATTRIBUTES | JOB_OBJECT_TERMINATE | JOB_OBJECT_SET_SECURITY_ATTRIBUTES, @@ -31,12 +31,23 @@ static GENERIC_MAPPING PiJobMapping = {STANDARD_RIGHTS_READ | JOB_OBJECT_QUERY, VOID STDCALL PiDeleteJob(PVOID ObjectBody) { - KIRQL oldIrql; PEJOB Job = (PEJOB)ObjectBody; - KeAcquireSpinLock(&PsJobListLock, &oldIrql); - RemoveEntryList(&Job->JobLinks); - KeReleaseSpinLock(&PsJobListLock, oldIrql); + /* remove the reference to the completion port if associated */ + if(Job->CompletionPort != NULL) + { + ObDereferenceObject(Job->CompletionPort); + } + + /* unlink the job object */ + if(Job->JobLinks.Flink != NULL) + { + ExAcquireFastMutex(&PsJobListLock); + RemoveEntryList(&Job->JobLinks); + ExReleaseFastMutex(&PsJobListLock); + } + + ExDeleteResource(&Job->JobLock); } VOID INIT_FUNCTION @@ -68,9 +79,18 @@ PsInitJobManagment(VOID) ObpCreateTypeObject(PsJobType); InitializeListHead(&PsJobListHead); - KeInitializeSpinLock(&PsJobListLock); + ExInitializeFastMutex(&PsJobListLock); } +NTSTATUS +PspAssignProcessToJob(PEPROCESS Process, + PEJOB Job) +{ + DPRINT("PspAssignProcessToJob() is unimplemented!\n"); + return STATUS_NOT_IMPLEMENTED; +} + + /* * @unimplemented */ @@ -79,8 +99,80 @@ STDCALL NtAssignProcessToJobObject(HANDLE JobHandle, HANDLE ProcessHandle) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + PEPROCESS Process; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status; + + PreviousMode = ExGetPreviousMode(); + + /* make sure we're having a handle with enough rights, especially the to + terminate the process. otherwise one could abuse the job objects to + terminate processes without having rights granted to do so! The reason + I open the process handle before the job handle is that a simple test showed + that it first complains about a invalid process handle! The other way around + would be simpler though... */ + Status = ObReferenceObjectByHandle(ProcessHandle, + PROCESS_TERMINATE, + PsProcessType, + PreviousMode, + (PVOID*)&Process, + NULL); + if(NT_SUCCESS(Status)) + { + if(Process->Job == NULL) + { + PEJOB Job; + + Status = ObReferenceObjectByHandle(JobHandle, + JOB_OBJECT_ASSIGN_PROCESS, + PsJobType, + PreviousMode, + (PVOID*)&Job, + NULL); + if(NT_SUCCESS(Status)) + { + /* lock the process so we can safely assign the process. Note that in the + meanwhile another thread could have assigned this process to a job! */ + + Status = PsLockProcess(Process, FALSE); + if(NT_SUCCESS(Status)) + { + if(Process->Job == NULL && Process->SessionId == Job->SessionId) + { + /* Just store the pointer to the job object in the process, we'll + assign it later. The reason we can't do this here is that locking + the job object might require it to wait, which is a bad thing + while holding the process lock! */ + Process->Job = Job; + } + else + { + /* process is already assigned to a job or session id differs! */ + Status = STATUS_ACCESS_DENIED; + } + PsUnlockProcess(Process); + + if(NT_SUCCESS(Status)) + { + /* let's actually assign the process to the job as we're not holding + the process lock anymore! */ + Status = PspAssignProcessToJob(Process, Job); + } + } + + ObDereferenceObject(Job); + } + } + else + { + /* process is already assigned to a job or session id differs! */ + Status = STATUS_ACCESS_DENIED; + } + + ObDereferenceObject(Process); + } + + return Status; } @@ -93,8 +185,90 @@ NtCreateJobObject(PHANDLE JobHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + HANDLE hJob; + PEJOB Job; + KPROCESSOR_MODE PreviousMode; + PEPROCESS CurrentProcess; + NTSTATUS Status = STATUS_SUCCESS; + + PreviousMode = ExGetPreviousMode(); + CurrentProcess = PsGetCurrentProcess(); + + /* check for valid buffers */ + if(PreviousMode == UserMode) + { + _SEH_TRY + { + /* probe with 32bit alignment */ + ProbeForWrite(JobHandle, + sizeof(HANDLE), + sizeof(ULONG)); + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(!NT_SUCCESS(Status)) + { + return Status; + } + } + + Status = ObCreateObject(PreviousMode, + PsJobType, + ObjectAttributes, + PreviousMode, + NULL, + sizeof(EJOB), + 0, + 0, + (PVOID*)&Job); + + if(NT_SUCCESS(Status)) + { + /* FIXME - Zero all fields as we don't yet implement all of them */ + RtlZeroMemory(Job, sizeof(EJOB)); + + /* make sure that early destruction doesn't attempt to remove the object from + the list before it even gets added! */ + Job->JobLinks.Flink = NULL; + + /* setup the job object */ + InitializeListHead(&Job->ProcessListHead); + Job->SessionId = CurrentProcess->SessionId; /* inherit the session id from the caller */ + + Status = ExInitializeResource(&Job->JobLock); + if(!NT_SUCCESS(Status)) + { + DPRINT1("Failed to initialize job lock!!!\n"); + ObDereferenceObject(Job); + return Status; + } + KeInitializeEvent(&Job->Event, NotificationEvent, FALSE); + + /* link the object into the global job list */ + ExAcquireFastMutex(&PsJobListLock); + InsertTailList(&PsJobListHead, &Job->JobLinks); + ExReleaseFastMutex(&PsJobListLock); + + /* pass the handle back to the caller */ + _SEH_TRY + { + /* NOTE: if the caller passed invalid buffers to receive the handle it's his + own fault! the object will still be created and live... It's possible + to find the handle using ObFindHandleForObject()! */ + *JobHandle = hJob; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } + + return Status; }