partial implementation of NtAssignProcessToJobObject() and
NtCreateJobObject()
Modified: trunk/reactos/ntoskrnl/ps/job.c
_____
Modified: trunk/reactos/ntoskrnl/ps/job.c
--- trunk/reactos/ntoskrnl/ps/job.c 2005-01-21 13:25:28 UTC (rev
13183)
+++ trunk/reactos/ntoskrnl/ps/job.c 2005-01-21 14:12:03 UTC (rev
13184)
@@ -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 @@
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 @@
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 @@
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 @@
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;
}