mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
partial implementation of NtAssignProcessToJobObject() and NtCreateJobObject()
svn path=/trunk/; revision=13184
This commit is contained in:
parent
b3dfa90a2f
commit
f67131616e
1 changed files with 184 additions and 10 deletions
|
@ -19,7 +19,7 @@
|
||||||
POBJECT_TYPE EXPORTED PsJobType = NULL;
|
POBJECT_TYPE EXPORTED PsJobType = NULL;
|
||||||
|
|
||||||
LIST_ENTRY PsJobListHead;
|
LIST_ENTRY PsJobListHead;
|
||||||
static KSPIN_LOCK PsJobListLock;
|
static FAST_MUTEX PsJobListLock;
|
||||||
|
|
||||||
static GENERIC_MAPPING PiJobMapping = {STANDARD_RIGHTS_READ | JOB_OBJECT_QUERY,
|
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,
|
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
|
VOID STDCALL
|
||||||
PiDeleteJob(PVOID ObjectBody)
|
PiDeleteJob(PVOID ObjectBody)
|
||||||
{
|
{
|
||||||
KIRQL oldIrql;
|
|
||||||
PEJOB Job = (PEJOB)ObjectBody;
|
PEJOB Job = (PEJOB)ObjectBody;
|
||||||
|
|
||||||
KeAcquireSpinLock(&PsJobListLock, &oldIrql);
|
/* remove the reference to the completion port if associated */
|
||||||
RemoveEntryList(&Job->JobLinks);
|
if(Job->CompletionPort != NULL)
|
||||||
KeReleaseSpinLock(&PsJobListLock, oldIrql);
|
{
|
||||||
|
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
|
VOID INIT_FUNCTION
|
||||||
|
@ -68,9 +79,18 @@ PsInitJobManagment(VOID)
|
||||||
ObpCreateTypeObject(PsJobType);
|
ObpCreateTypeObject(PsJobType);
|
||||||
|
|
||||||
InitializeListHead(&PsJobListHead);
|
InitializeListHead(&PsJobListHead);
|
||||||
KeInitializeSpinLock(&PsJobListLock);
|
ExInitializeFastMutex(&PsJobListLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
PspAssignProcessToJob(PEPROCESS Process,
|
||||||
|
PEJOB Job)
|
||||||
|
{
|
||||||
|
DPRINT("PspAssignProcessToJob() is unimplemented!\n");
|
||||||
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @unimplemented
|
* @unimplemented
|
||||||
*/
|
*/
|
||||||
|
@ -79,8 +99,80 @@ STDCALL
|
||||||
NtAssignProcessToJobObject(HANDLE JobHandle,
|
NtAssignProcessToJobObject(HANDLE JobHandle,
|
||||||
HANDLE ProcessHandle)
|
HANDLE ProcessHandle)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED;
|
PEPROCESS Process;
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
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,
|
ACCESS_MASK DesiredAccess,
|
||||||
POBJECT_ATTRIBUTES ObjectAttributes)
|
POBJECT_ATTRIBUTES ObjectAttributes)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED;
|
HANDLE hJob;
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue