- 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:
Thomas Bluemel 2006-01-22 22:46:23 +00:00
parent 92804170a5
commit cdf8bdd8d5
2 changed files with 162 additions and 63 deletions

View file

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

View file

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