mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 16:36:33 +00:00
- secure access to buffers in NtPrivilegeCheck()
- fixed SeCaptureLuidAndAttributesArray() and SeReleaseLuidAndAttributesArray() to securely capture the buffers svn path=/trunk/; revision=20986
This commit is contained in:
parent
92804170a5
commit
cdf8bdd8d5
2 changed files with 162 additions and 63 deletions
|
@ -153,7 +153,7 @@ SeCaptureLuidAndAttributesArray(
|
||||||
PLUID_AND_ATTRIBUTES AllocatedMem,
|
PLUID_AND_ATTRIBUTES AllocatedMem,
|
||||||
ULONG AllocatedLength,
|
ULONG AllocatedLength,
|
||||||
POOL_TYPE PoolType,
|
POOL_TYPE PoolType,
|
||||||
ULONG d,
|
BOOLEAN CaptureIfKernel,
|
||||||
PLUID_AND_ATTRIBUTES* Dest,
|
PLUID_AND_ATTRIBUTES* Dest,
|
||||||
PULONG Length
|
PULONG Length
|
||||||
);
|
);
|
||||||
|
@ -163,7 +163,7 @@ NTAPI
|
||||||
SeReleaseLuidAndAttributesArray(
|
SeReleaseLuidAndAttributesArray(
|
||||||
PLUID_AND_ATTRIBUTES Privilege,
|
PLUID_AND_ATTRIBUTES Privilege,
|
||||||
KPROCESSOR_MODE PreviousMode,
|
KPROCESSOR_MODE PreviousMode,
|
||||||
ULONG a
|
BOOLEAN CaptureIfKernel
|
||||||
);
|
);
|
||||||
|
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
|
|
|
@ -180,51 +180,96 @@ SeCaptureLuidAndAttributesArray (PLUID_AND_ATTRIBUTES Src,
|
||||||
PLUID_AND_ATTRIBUTES AllocatedMem,
|
PLUID_AND_ATTRIBUTES AllocatedMem,
|
||||||
ULONG AllocatedLength,
|
ULONG AllocatedLength,
|
||||||
POOL_TYPE PoolType,
|
POOL_TYPE PoolType,
|
||||||
ULONG d,
|
BOOLEAN CaptureIfKernel,
|
||||||
PLUID_AND_ATTRIBUTES* Dest,
|
PLUID_AND_ATTRIBUTES* Dest,
|
||||||
PULONG Length)
|
PULONG Length)
|
||||||
{
|
{
|
||||||
PLUID_AND_ATTRIBUTES* NewMem;
|
ULONG BufferSize;
|
||||||
ULONG SrcLength;
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
if (PrivilegeCount == 0)
|
if (PrivilegeCount == 0)
|
||||||
{
|
{
|
||||||
*Dest = 0;
|
*Dest = 0;
|
||||||
*Length = 0;
|
*Length = 0;
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PreviousMode == KernelMode && d == 0)
|
if (PreviousMode == KernelMode && !CaptureIfKernel)
|
||||||
{
|
{
|
||||||
*Dest = Src;
|
*Dest = Src;
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrcLength = ((PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)) + 3) & 0xfc;
|
/* FIXME - check PrivilegeCount for a valid number so we don't
|
||||||
*Length = SrcLength;
|
cause an integer overflow or exhaust system resources! */
|
||||||
if (AllocatedMem == NULL)
|
|
||||||
{
|
|
||||||
NewMem = ExAllocatePool (PoolType,
|
|
||||||
SrcLength);
|
|
||||||
*Dest = (PLUID_AND_ATTRIBUTES)NewMem;
|
|
||||||
if (NewMem == NULL)
|
|
||||||
{
|
|
||||||
return STATUS_UNSUCCESSFUL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (SrcLength > AllocatedLength)
|
|
||||||
{
|
|
||||||
return STATUS_UNSUCCESSFUL;
|
|
||||||
}
|
|
||||||
*Dest = AllocatedMem;
|
|
||||||
}
|
|
||||||
memmove (*Dest, Src, SrcLength);
|
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
BufferSize = PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
|
||||||
|
*Length = ROUND_UP(BufferSize, 4); /* round up to a 4 byte alignment */
|
||||||
|
|
||||||
|
/* probe the buffer */
|
||||||
|
if (PreviousMode != KernelMode)
|
||||||
|
{
|
||||||
|
_SEH_TRY
|
||||||
|
{
|
||||||
|
ProbeForRead(Src,
|
||||||
|
BufferSize,
|
||||||
|
sizeof(ULONG));
|
||||||
|
}
|
||||||
|
_SEH_HANDLE
|
||||||
|
{
|
||||||
|
Status = _SEH_GetExceptionCode();
|
||||||
|
}
|
||||||
|
_SEH_END;
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate enough memory or check if the provided buffer is
|
||||||
|
large enough to hold the array */
|
||||||
|
if (AllocatedMem != NULL)
|
||||||
|
{
|
||||||
|
if (AllocatedLength < BufferSize)
|
||||||
|
{
|
||||||
|
return STATUS_BUFFER_TOO_SMALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*Dest = AllocatedMem;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*Dest = ExAllocatePool(PoolType,
|
||||||
|
BufferSize);
|
||||||
|
|
||||||
|
if (&Dest == NULL)
|
||||||
|
{
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy the array to the buffer */
|
||||||
|
_SEH_TRY
|
||||||
|
{
|
||||||
|
RtlCopyMemory(*Dest,
|
||||||
|
Src,
|
||||||
|
BufferSize);
|
||||||
|
}
|
||||||
|
_SEH_HANDLE
|
||||||
|
{
|
||||||
|
Status = _SEH_GetExceptionCode();
|
||||||
|
}
|
||||||
|
_SEH_END;
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status) && AllocatedMem == NULL)
|
||||||
|
{
|
||||||
|
ExFreePool(*Dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -232,11 +277,15 @@ VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
SeReleaseLuidAndAttributesArray (PLUID_AND_ATTRIBUTES Privilege,
|
SeReleaseLuidAndAttributesArray (PLUID_AND_ATTRIBUTES Privilege,
|
||||||
KPROCESSOR_MODE PreviousMode,
|
KPROCESSOR_MODE PreviousMode,
|
||||||
ULONG a)
|
BOOLEAN CaptureIfKernel)
|
||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
ExFreePool (Privilege);
|
if (Privilege != NULL &&
|
||||||
|
(PreviousMode != KernelMode || CaptureIfKernel))
|
||||||
|
{
|
||||||
|
ExFreePool(Privilege);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -245,18 +294,58 @@ NtPrivilegeCheck (IN HANDLE ClientToken,
|
||||||
IN PPRIVILEGE_SET RequiredPrivileges,
|
IN PPRIVILEGE_SET RequiredPrivileges,
|
||||||
IN PBOOLEAN Result)
|
IN PBOOLEAN Result)
|
||||||
{
|
{
|
||||||
PLUID_AND_ATTRIBUTES Privilege;
|
PLUID_AND_ATTRIBUTES Privileges;
|
||||||
PTOKEN Token;
|
PTOKEN Token;
|
||||||
ULONG PrivilegeCount;
|
ULONG PrivilegeCount = 0;
|
||||||
ULONG PrivilegeControl;
|
ULONG PrivilegeControl = 0;
|
||||||
ULONG Length;
|
ULONG Length;
|
||||||
|
BOOLEAN CheckResult;
|
||||||
KPROCESSOR_MODE PreviousMode;
|
KPROCESSOR_MODE PreviousMode;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
PreviousMode = KeGetPreviousMode();
|
PreviousMode = KeGetPreviousMode();
|
||||||
|
|
||||||
|
/* probe the buffers */
|
||||||
|
if (PreviousMode != KernelMode)
|
||||||
|
{
|
||||||
|
_SEH_TRY
|
||||||
|
{
|
||||||
|
ProbeForWrite(RequiredPrivileges,
|
||||||
|
sizeof(PRIVILEGE_SET),
|
||||||
|
sizeof(ULONG));
|
||||||
|
|
||||||
|
PrivilegeCount = RequiredPrivileges->PrivilegeCount;
|
||||||
|
PrivilegeControl = RequiredPrivileges->Control;
|
||||||
|
|
||||||
|
/* probe all of the array */
|
||||||
|
ProbeForWrite(RequiredPrivileges,
|
||||||
|
sizeof(FIELD_OFFSET(PRIVILEGE_SET,
|
||||||
|
Privilege[PrivilegeCount])),
|
||||||
|
sizeof(ULONG));
|
||||||
|
|
||||||
|
ProbeForWriteBoolean(Result);
|
||||||
|
}
|
||||||
|
_SEH_HANDLE
|
||||||
|
{
|
||||||
|
Status = _SEH_GetExceptionCode();
|
||||||
|
}
|
||||||
|
_SEH_END;
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PrivilegeCount = RequiredPrivileges->PrivilegeCount;
|
||||||
|
PrivilegeControl = RequiredPrivileges->Control;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reference the token and make sure we're
|
||||||
|
not doing an anonymous impersonation */
|
||||||
Status = ObReferenceObjectByHandle (ClientToken,
|
Status = ObReferenceObjectByHandle (ClientToken,
|
||||||
TOKEN_QUERY,
|
TOKEN_QUERY,
|
||||||
SepTokenObjectType,
|
SepTokenObjectType,
|
||||||
|
@ -269,45 +358,55 @@ NtPrivilegeCheck (IN HANDLE ClientToken,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Token->TokenType == TokenImpersonation &&
|
if (Token->TokenType == TokenImpersonation &&
|
||||||
Token->ImpersonationLevel < SecurityAnonymous)
|
Token->ImpersonationLevel < SecurityIdentification)
|
||||||
{
|
{
|
||||||
ObDereferenceObject (Token);
|
ObDereferenceObject (Token);
|
||||||
return STATUS_UNSUCCESSFUL;
|
return STATUS_BAD_IMPERSONATION_LEVEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrivilegeCount = RequiredPrivileges->PrivilegeCount;
|
/* capture the privileges */
|
||||||
PrivilegeControl = RequiredPrivileges->Control;
|
|
||||||
Privilege = 0;
|
|
||||||
Status = SeCaptureLuidAndAttributesArray (RequiredPrivileges->Privilege,
|
Status = SeCaptureLuidAndAttributesArray (RequiredPrivileges->Privilege,
|
||||||
PrivilegeCount,
|
PrivilegeCount,
|
||||||
UserMode,
|
PreviousMode,
|
||||||
NULL,
|
NULL,
|
||||||
0,
|
0,
|
||||||
PagedPool,
|
PagedPool,
|
||||||
1,
|
TRUE,
|
||||||
&Privilege,
|
&Privileges,
|
||||||
&Length);
|
&Length);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
ObDereferenceObject (Token);
|
ObDereferenceObject (Token);
|
||||||
return STATUS_UNSUCCESSFUL;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
*Result = SepPrivilegeCheck (Token,
|
CheckResult = SepPrivilegeCheck (Token,
|
||||||
Privilege,
|
Privileges,
|
||||||
PrivilegeCount,
|
PrivilegeCount,
|
||||||
PrivilegeControl,
|
PrivilegeControl,
|
||||||
UserMode);
|
PreviousMode);
|
||||||
|
|
||||||
memmove (RequiredPrivileges->Privilege,
|
ObDereferenceObject (Token);
|
||||||
Privilege,
|
|
||||||
Length);
|
|
||||||
|
|
||||||
SeReleaseLuidAndAttributesArray (Privilege,
|
/* return the array */
|
||||||
UserMode,
|
_SEH_TRY
|
||||||
1);
|
{
|
||||||
|
RtlCopyMemory(RequiredPrivileges->Privilege,
|
||||||
|
Privileges,
|
||||||
|
PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));;
|
||||||
|
Status = STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
_SEH_HANDLE
|
||||||
|
{
|
||||||
|
Status = _SEH_GetExceptionCode();
|
||||||
|
}
|
||||||
|
_SEH_END;
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
SeReleaseLuidAndAttributesArray (Privileges,
|
||||||
|
PreviousMode,
|
||||||
|
TRUE);
|
||||||
|
|
||||||
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue