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
367 lines
10 KiB
C
367 lines
10 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Kernel
|
|
* FILE: ntoskrnl/ex/sem.c
|
|
* PURPOSE: Semaphore Implementation
|
|
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
|
|
* Thomas Weidenmueller
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#include <ntoskrnl.h>
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
#if defined (ALLOC_PRAGMA)
|
|
#pragma alloc_text(INIT, ExpInitializeSemaphoreImplementation)
|
|
#endif
|
|
|
|
/* GLOBALS ******************************************************************/
|
|
|
|
POBJECT_TYPE ExSemaphoreObjectType;
|
|
|
|
GENERIC_MAPPING ExSemaphoreMapping =
|
|
{
|
|
STANDARD_RIGHTS_READ | SEMAPHORE_QUERY_STATE,
|
|
STANDARD_RIGHTS_WRITE | SEMAPHORE_MODIFY_STATE,
|
|
STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
|
|
SEMAPHORE_ALL_ACCESS
|
|
};
|
|
|
|
static const INFORMATION_CLASS_INFO ExSemaphoreInfoClass[] =
|
|
{
|
|
/* SemaphoreBasicInformation */
|
|
IQS_SAME(SEMAPHORE_BASIC_INFORMATION, ULONG, ICIF_QUERY),
|
|
};
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
CODE_SEG("INIT")
|
|
BOOLEAN
|
|
NTAPI
|
|
ExpInitializeSemaphoreImplementation(VOID)
|
|
{
|
|
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
|
|
UNICODE_STRING Name;
|
|
NTSTATUS Status;
|
|
DPRINT("Creating Semaphore Object Type\n");
|
|
|
|
/* Create the Event Pair Object Type */
|
|
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
|
|
RtlInitUnicodeString(&Name, L"Semaphore");
|
|
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
|
|
ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KSEMAPHORE);
|
|
ObjectTypeInitializer.GenericMapping = ExSemaphoreMapping;
|
|
ObjectTypeInitializer.PoolType = NonPagedPool;
|
|
ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
|
|
ObjectTypeInitializer.ValidAccessMask = SEMAPHORE_ALL_ACCESS;
|
|
Status = ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ExSemaphoreObjectType);
|
|
if (!NT_SUCCESS(Status)) return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
NtCreateSemaphore(OUT PHANDLE SemaphoreHandle,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
|
|
IN LONG InitialCount,
|
|
IN LONG MaximumCount)
|
|
{
|
|
PKSEMAPHORE Semaphore;
|
|
HANDLE hSemaphore;
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
|
NTSTATUS Status;
|
|
PAGED_CODE();
|
|
|
|
/* Check if we were called from user-mode */
|
|
if (PreviousMode != KernelMode)
|
|
{
|
|
/* Enter SEH Block */
|
|
_SEH2_TRY
|
|
{
|
|
/* Check handle pointer */
|
|
ProbeForWriteHandle(SemaphoreHandle);
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
/* Return the exception code */
|
|
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
|
}
|
|
_SEH2_END;
|
|
}
|
|
|
|
/* Make sure the counts make sense */
|
|
if ((MaximumCount <= 0) ||
|
|
(InitialCount < 0) ||
|
|
(InitialCount > MaximumCount))
|
|
{
|
|
DPRINT("Invalid Count Data!\n");
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* Create the Semaphore Object */
|
|
Status = ObCreateObject(PreviousMode,
|
|
ExSemaphoreObjectType,
|
|
ObjectAttributes,
|
|
PreviousMode,
|
|
NULL,
|
|
sizeof(KSEMAPHORE),
|
|
0,
|
|
0,
|
|
(PVOID*)&Semaphore);
|
|
|
|
/* Check for Success */
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Initialize it */
|
|
KeInitializeSemaphore(Semaphore,
|
|
InitialCount,
|
|
MaximumCount);
|
|
|
|
/* Insert it into the Object Tree */
|
|
Status = ObInsertObject((PVOID)Semaphore,
|
|
NULL,
|
|
DesiredAccess,
|
|
0,
|
|
NULL,
|
|
&hSemaphore);
|
|
|
|
/* Check for success */
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Enter SEH Block for return */
|
|
_SEH2_TRY
|
|
{
|
|
/* Return the handle */
|
|
*SemaphoreHandle = hSemaphore;
|
|
}
|
|
_SEH2_EXCEPT(ExSystemExceptionFilter())
|
|
{
|
|
/* Get the exception code */
|
|
Status = _SEH2_GetExceptionCode();
|
|
}
|
|
_SEH2_END;
|
|
}
|
|
}
|
|
|
|
/* Return Status */
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
NtOpenSemaphore(OUT PHANDLE SemaphoreHandle,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes)
|
|
{
|
|
HANDLE hSemaphore;
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
|
NTSTATUS Status;
|
|
PAGED_CODE();
|
|
|
|
/* Check if we were called from user-mode */
|
|
if (PreviousMode != KernelMode)
|
|
{
|
|
/* Enter SEH Block */
|
|
_SEH2_TRY
|
|
{
|
|
/* Check handle pointer */
|
|
ProbeForWriteHandle(SemaphoreHandle);
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
/* Return the exception code */
|
|
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
|
}
|
|
_SEH2_END;
|
|
}
|
|
|
|
/* Open the Object */
|
|
Status = ObOpenObjectByName(ObjectAttributes,
|
|
ExSemaphoreObjectType,
|
|
PreviousMode,
|
|
NULL,
|
|
DesiredAccess,
|
|
NULL,
|
|
&hSemaphore);
|
|
|
|
/* Check for success */
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Enter SEH Block for return */
|
|
_SEH2_TRY
|
|
{
|
|
/* Return the handle */
|
|
*SemaphoreHandle = hSemaphore;
|
|
}
|
|
_SEH2_EXCEPT(ExSystemExceptionFilter())
|
|
{
|
|
/* Get the exception code */
|
|
Status = _SEH2_GetExceptionCode();
|
|
}
|
|
_SEH2_END;
|
|
}
|
|
|
|
/* Return Status */
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
NtQuerySemaphore(IN HANDLE SemaphoreHandle,
|
|
IN SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass,
|
|
OUT PVOID SemaphoreInformation,
|
|
IN ULONG SemaphoreInformationLength,
|
|
OUT PULONG ReturnLength OPTIONAL)
|
|
{
|
|
PKSEMAPHORE Semaphore;
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
|
NTSTATUS Status;
|
|
PAGED_CODE();
|
|
|
|
/* Check buffers and class validity */
|
|
Status = DefaultQueryInfoBufferCheck(SemaphoreInformationClass,
|
|
ExSemaphoreInfoClass,
|
|
sizeof(ExSemaphoreInfoClass) /
|
|
sizeof(ExSemaphoreInfoClass[0]),
|
|
ICIF_PROBE_READ_WRITE,
|
|
SemaphoreInformation,
|
|
SemaphoreInformationLength,
|
|
ReturnLength,
|
|
NULL,
|
|
PreviousMode);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* Invalid buffers */
|
|
DPRINT("NtQuerySemaphore() failed, Status: 0x%x\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
/* Get the Object */
|
|
Status = ObReferenceObjectByHandle(SemaphoreHandle,
|
|
SEMAPHORE_QUERY_STATE,
|
|
ExSemaphoreObjectType,
|
|
PreviousMode,
|
|
(PVOID*)&Semaphore,
|
|
NULL);
|
|
|
|
/* Check for success */
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Entry SEH Block */
|
|
_SEH2_TRY
|
|
{
|
|
PSEMAPHORE_BASIC_INFORMATION BasicInfo =
|
|
(PSEMAPHORE_BASIC_INFORMATION)SemaphoreInformation;
|
|
|
|
/* Return the basic information */
|
|
BasicInfo->CurrentCount = KeReadStateSemaphore(Semaphore);
|
|
BasicInfo->MaximumCount = Semaphore->Limit;
|
|
|
|
/* Return the length */
|
|
if (ReturnLength) *ReturnLength = sizeof(*BasicInfo);
|
|
}
|
|
_SEH2_EXCEPT(ExSystemExceptionFilter())
|
|
{
|
|
/* Get the exception code */
|
|
Status = _SEH2_GetExceptionCode();
|
|
}
|
|
_SEH2_END;
|
|
|
|
/* Dereference the Object */
|
|
ObDereferenceObject(Semaphore);
|
|
}
|
|
|
|
/* Return status */
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
NtReleaseSemaphore(IN HANDLE SemaphoreHandle,
|
|
IN LONG ReleaseCount,
|
|
OUT PLONG PreviousCount OPTIONAL)
|
|
{
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
|
PKSEMAPHORE Semaphore;
|
|
NTSTATUS Status;
|
|
PAGED_CODE();
|
|
|
|
/* 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;
|
|
}
|
|
|
|
/* Make sure count makes sense */
|
|
if (ReleaseCount <= 0)
|
|
{
|
|
DPRINT("Invalid Release Count\n");
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* Get the Object */
|
|
Status = ObReferenceObjectByHandle(SemaphoreHandle,
|
|
SEMAPHORE_MODIFY_STATE,
|
|
ExSemaphoreObjectType,
|
|
PreviousMode,
|
|
(PVOID*)&Semaphore,
|
|
NULL);
|
|
|
|
/* Check for success */
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Enter SEH Block */
|
|
_SEH2_TRY
|
|
{
|
|
/* Release the semaphore */
|
|
LONG PrevCount = KeReleaseSemaphore(Semaphore,
|
|
IO_NO_INCREMENT,
|
|
ReleaseCount,
|
|
FALSE);
|
|
|
|
/* Return the old count if requested */
|
|
if (PreviousCount) *PreviousCount = PrevCount;
|
|
}
|
|
_SEH2_EXCEPT(ExSystemExceptionFilter())
|
|
{
|
|
/* Get the exception code */
|
|
Status = _SEH2_GetExceptionCode();
|
|
}
|
|
_SEH2_END;
|
|
|
|
/* Dereference the Semaphore */
|
|
ObDereferenceObject(Semaphore);
|
|
}
|
|
|
|
/* Return Status */
|
|
return Status;
|
|
}
|
|
|
|
/* EOF */
|