partial implementation of NtAssignProcessToJobObject() and NtCreateJobObject()

svn path=/trunk/; revision=13184
This commit is contained in:
Thomas Bluemel 2005-01-21 14:12:03 +00:00
parent b3dfa90a2f
commit f67131616e

View file

@ -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;
}