mirror of
https://github.com/reactos/reactos.git
synced 2024-09-06 10:52:52 +00:00
![George Bișoc](/assets/img/avatar_default.png)
NtQueryInformationToken is by far the only system call in NT where ReturnLength simply cannot be optional. On Windows this parameter is always probed and an argument to NULL directly leads to an access violation exception. This is due to the fact of how tokens work, as its information contents (token user, owner, primary group, et al) are dynamic and can vary throughout over time in memory. What happens on current ReactOS master however is that ReturnLength is only probed if the parameter is not NULL. On a NULL case scenario the probing checks succeed and NtQueryInformationToken fails later. For this, just get rid of CompleteProbing parameter and opt in for a bit mask flag based approach, with ICIF_FORCE_RETURN_LENGTH_PROBE being set on DefaultQueryInfoBufferCheck which NtQueryInformationToken calls it to do sanity checks. In addition to that... - Document the ICIF probe helpers - Annotate the ICIF prope helpers with SAL - With the riddance of CompleteProbing and adoption of flags based approach, add ICIF_PROBE_READ_WRITE and ICIF_PROBE_READ flags alongside with ICIF_FORCE_RETURN_LENGTH_PROBE
366 lines
10 KiB
C
366 lines
10 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Kernel
|
|
* FILE: ntoskrnl/ex/mutant.c
|
|
* PURPOSE: Executive Management of Mutants
|
|
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
|
|
* Thomas Weidenmueller
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#include <ntoskrnl.h>
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* DATA **********************************************************************/
|
|
|
|
POBJECT_TYPE ExMutantObjectType = NULL;
|
|
|
|
GENERIC_MAPPING ExpMutantMapping =
|
|
{
|
|
STANDARD_RIGHTS_READ | MUTANT_QUERY_STATE,
|
|
STANDARD_RIGHTS_WRITE,
|
|
STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
|
|
MUTANT_ALL_ACCESS
|
|
};
|
|
|
|
static const INFORMATION_CLASS_INFO ExMutantInfoClass[] =
|
|
{
|
|
/* MutantBasicInformation */
|
|
IQS_SAME(MUTANT_BASIC_INFORMATION, ULONG, ICIF_QUERY),
|
|
};
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
VOID
|
|
NTAPI
|
|
ExpDeleteMutant(PVOID ObjectBody)
|
|
{
|
|
DPRINT("ExpDeleteMutant(ObjectBody 0x%p)\n", ObjectBody);
|
|
|
|
/* Make sure to release the Mutant */
|
|
KeReleaseMutant((PKMUTANT)ObjectBody,
|
|
MUTANT_INCREMENT,
|
|
TRUE,
|
|
FALSE);
|
|
}
|
|
|
|
CODE_SEG("INIT")
|
|
BOOLEAN
|
|
NTAPI
|
|
ExpInitializeMutantImplementation(VOID)
|
|
{
|
|
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
|
|
UNICODE_STRING Name;
|
|
NTSTATUS Status;
|
|
DPRINT("Creating Mutant Object Type\n");
|
|
|
|
/* Create the Event Pair Object Type */
|
|
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
|
|
RtlInitUnicodeString(&Name, L"Mutant");
|
|
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
|
|
ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KMUTANT);
|
|
ObjectTypeInitializer.GenericMapping = ExpMutantMapping;
|
|
ObjectTypeInitializer.PoolType = NonPagedPool;
|
|
ObjectTypeInitializer.DeleteProcedure = ExpDeleteMutant;
|
|
ObjectTypeInitializer.ValidAccessMask = MUTANT_ALL_ACCESS;
|
|
ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
|
|
Status = ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ExMutantObjectType);
|
|
if (!NT_SUCCESS(Status)) return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
NtCreateMutant(OUT PHANDLE MutantHandle,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
|
|
IN BOOLEAN InitialOwner)
|
|
{
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
|
HANDLE hMutant;
|
|
PKMUTANT Mutant;
|
|
NTSTATUS Status;
|
|
PAGED_CODE();
|
|
DPRINT("NtCreateMutant(0x%p, 0x%x, 0x%p)\n",
|
|
MutantHandle, DesiredAccess, ObjectAttributes);
|
|
|
|
/* Check if we were called from user-mode */
|
|
if (PreviousMode != KernelMode)
|
|
{
|
|
/* Enter SEH Block */
|
|
_SEH2_TRY
|
|
{
|
|
/* Check handle pointer */
|
|
ProbeForWriteHandle(MutantHandle);
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
/* Return the exception code */
|
|
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
|
}
|
|
_SEH2_END;
|
|
}
|
|
|
|
/* Create the Mutant Object*/
|
|
Status = ObCreateObject(PreviousMode,
|
|
ExMutantObjectType,
|
|
ObjectAttributes,
|
|
PreviousMode,
|
|
NULL,
|
|
sizeof(KMUTANT),
|
|
0,
|
|
0,
|
|
(PVOID*)&Mutant);
|
|
|
|
/* Check for success */
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
/* Initialize the Kernel Mutant */
|
|
DPRINT("Initializing the Mutant\n");
|
|
KeInitializeMutant(Mutant, InitialOwner);
|
|
|
|
/* Insert the Object */
|
|
Status = ObInsertObject((PVOID)Mutant,
|
|
NULL,
|
|
DesiredAccess,
|
|
0,
|
|
NULL,
|
|
&hMutant);
|
|
|
|
/* Check for success */
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Enter SEH for return */
|
|
_SEH2_TRY
|
|
{
|
|
/* Return the handle to the caller */
|
|
*MutantHandle = hMutant;
|
|
}
|
|
_SEH2_EXCEPT(ExSystemExceptionFilter())
|
|
{
|
|
/* Get the exception code */
|
|
Status = _SEH2_GetExceptionCode();
|
|
}
|
|
_SEH2_END;
|
|
}
|
|
}
|
|
|
|
/* Return Status */
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
NtOpenMutant(OUT PHANDLE MutantHandle,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes)
|
|
{
|
|
HANDLE hMutant;
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
|
NTSTATUS Status;
|
|
PAGED_CODE();
|
|
DPRINT("NtOpenMutant(0x%p, 0x%x, 0x%p)\n",
|
|
MutantHandle, DesiredAccess, ObjectAttributes);
|
|
|
|
/* Check if we were called from user-mode */
|
|
if (PreviousMode != KernelMode)
|
|
{
|
|
/* Enter SEH Block */
|
|
_SEH2_TRY
|
|
{
|
|
/* Check handle pointer */
|
|
ProbeForWriteHandle(MutantHandle);
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
/* Return the exception code */
|
|
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
|
}
|
|
_SEH2_END;
|
|
}
|
|
|
|
/* Open the Object */
|
|
Status = ObOpenObjectByName(ObjectAttributes,
|
|
ExMutantObjectType,
|
|
PreviousMode,
|
|
NULL,
|
|
DesiredAccess,
|
|
NULL,
|
|
&hMutant);
|
|
|
|
/* Check for success */
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
/* Enter SEH for return */
|
|
_SEH2_TRY
|
|
{
|
|
/* Return the handle to the caller */
|
|
*MutantHandle = hMutant;
|
|
}
|
|
_SEH2_EXCEPT(ExSystemExceptionFilter())
|
|
{
|
|
Status = _SEH2_GetExceptionCode();
|
|
}
|
|
_SEH2_END;
|
|
}
|
|
|
|
/* Return Status */
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
NtQueryMutant(IN HANDLE MutantHandle,
|
|
IN MUTANT_INFORMATION_CLASS MutantInformationClass,
|
|
OUT PVOID MutantInformation,
|
|
IN ULONG MutantInformationLength,
|
|
OUT PULONG ResultLength OPTIONAL)
|
|
{
|
|
PKMUTANT Mutant;
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
|
NTSTATUS Status;
|
|
PMUTANT_BASIC_INFORMATION BasicInfo =
|
|
(PMUTANT_BASIC_INFORMATION)MutantInformation;
|
|
PAGED_CODE();
|
|
|
|
/* Check buffers and parameters */
|
|
Status = DefaultQueryInfoBufferCheck(MutantInformationClass,
|
|
ExMutantInfoClass,
|
|
sizeof(ExMutantInfoClass) /
|
|
sizeof(ExMutantInfoClass[0]),
|
|
ICIF_PROBE_READ_WRITE,
|
|
MutantInformation,
|
|
MutantInformationLength,
|
|
ResultLength,
|
|
NULL,
|
|
PreviousMode);
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("NtQueryMutant() failed, Status: 0x%x\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
/* Open the Object */
|
|
Status = ObReferenceObjectByHandle(MutantHandle,
|
|
MUTANT_QUERY_STATE,
|
|
ExMutantObjectType,
|
|
PreviousMode,
|
|
(PVOID*)&Mutant,
|
|
NULL);
|
|
/* Check for Status */
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Enter SEH Block for return */
|
|
_SEH2_TRY
|
|
{
|
|
/* Fill out the Basic Information Requested */
|
|
DPRINT("Returning Mutant Information\n");
|
|
BasicInfo->CurrentCount = KeReadStateMutant(Mutant);
|
|
BasicInfo->OwnedByCaller = (Mutant->OwnerThread ==
|
|
KeGetCurrentThread());
|
|
BasicInfo->AbandonedState = Mutant->Abandoned;
|
|
|
|
/* Return the Result Length if requested */
|
|
if (ResultLength) *ResultLength = sizeof(MUTANT_BASIC_INFORMATION);
|
|
}
|
|
_SEH2_EXCEPT(ExSystemExceptionFilter())
|
|
{
|
|
Status = _SEH2_GetExceptionCode();
|
|
}
|
|
_SEH2_END;
|
|
|
|
/* Release the Object */
|
|
ObDereferenceObject(Mutant);
|
|
}
|
|
|
|
/* Return Status */
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
NtReleaseMutant(IN HANDLE MutantHandle,
|
|
IN PLONG PreviousCount OPTIONAL)
|
|
{
|
|
PKMUTANT Mutant;
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
|
NTSTATUS Status;
|
|
PAGED_CODE();
|
|
DPRINT("NtReleaseMutant(MutantHandle 0x%p PreviousCount 0x%p)\n",
|
|
MutantHandle,
|
|
PreviousCount);
|
|
|
|
/* Check if we were called from user-mode */
|
|
if ((PreviousCount) && (PreviousMode != KernelMode))
|
|
{
|
|
/* Entry SEH Block */
|
|
_SEH2_TRY
|
|
{
|
|
/* Make sure the state pointer is valid */
|
|
ProbeForWriteLong(PreviousCount);
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
/* Return the exception code */
|
|
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
|
}
|
|
_SEH2_END;
|
|
}
|
|
|
|
/* Open the Object */
|
|
Status = ObReferenceObjectByHandle(MutantHandle,
|
|
0, /* No access rights required */
|
|
ExMutantObjectType,
|
|
PreviousMode,
|
|
(PVOID*)&Mutant,
|
|
NULL);
|
|
|
|
/* Check for Success and release if such */
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/*
|
|
* Release the mutant. doing so might raise an exception which we're
|
|
* required to catch!
|
|
*/
|
|
_SEH2_TRY
|
|
{
|
|
/* Release the mutant */
|
|
LONG Prev = KeReleaseMutant(Mutant,
|
|
MUTANT_INCREMENT,
|
|
FALSE,
|
|
FALSE);
|
|
|
|
/* Return the previous count if requested */
|
|
if (PreviousCount) *PreviousCount = Prev;
|
|
}
|
|
_SEH2_EXCEPT(ExSystemExceptionFilter())
|
|
{
|
|
/* Get the exception code */
|
|
Status = _SEH2_GetExceptionCode();
|
|
}
|
|
_SEH2_END;
|
|
|
|
/* Dereference it */
|
|
ObDereferenceObject(Mutant);
|
|
}
|
|
|
|
/* Return Status */
|
|
return Status;
|
|
}
|
|
|
|
/* EOF */
|