[NTOSKRNL]

Fix the s*** out of SepCreateToken and NtCreateToken: respect optional arguments, do not access usermode memory without SEH, instead properly capture them, don't allocate 0 bytes from the pool, better argument verification. The function isn't perfect yet, but better and more secure.

svn path=/trunk/; revision=61662
This commit is contained in:
Timo Kreuzer 2014-01-17 22:11:10 +00:00
parent 56b0d82c30
commit b9fdfea09e

View file

@ -738,6 +738,7 @@ SepCreateToken(OUT PHANDLE TokenHandle,
for (i = 0; i < GroupCount; i++) for (i = 0; i < GroupCount; i++)
uLength += RtlLengthSid(Groups[i].Sid); uLength += RtlLengthSid(Groups[i].Sid);
// FIXME: should use the object itself
AccessToken->UserAndGroups = ExAllocatePoolWithTag(PagedPool, AccessToken->UserAndGroups = ExAllocatePoolWithTag(PagedPool,
uLength, uLength,
TAG_TOKEN_USERS); TAG_TOKEN_USERS);
@ -775,7 +776,9 @@ SepCreateToken(OUT PHANDLE TokenHandle,
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
goto done; goto done;
// FIXME: should use the object itself
uLength = PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES); uLength = PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
if (uLength == 0) uLength = sizeof(PVOID);
AccessToken->Privileges = ExAllocatePoolWithTag(PagedPool, AccessToken->Privileges = ExAllocatePoolWithTag(PagedPool,
uLength, uLength,
TAG_TOKEN_PRIVILAGES); TAG_TOKEN_PRIVILAGES);
@ -812,18 +815,26 @@ SepCreateToken(OUT PHANDLE TokenHandle,
/* Update privilege flags */ /* Update privilege flags */
SepUpdatePrivilegeFlagsToken(AccessToken); SepUpdatePrivilegeFlagsToken(AccessToken);
AccessToken->DefaultDacl = ExAllocatePoolWithTag(PagedPool, if (DefaultDacl != NULL)
DefaultDacl->AclSize,
TAG_TOKEN_ACL);
if (AccessToken->DefaultDacl == NULL)
{ {
Status = STATUS_INSUFFICIENT_RESOURCES; // FIXME: should use the object itself
goto done; AccessToken->DefaultDacl = ExAllocatePoolWithTag(PagedPool,
} DefaultDacl->AclSize,
TAG_TOKEN_ACL);
if (AccessToken->DefaultDacl == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}
RtlCopyMemory(AccessToken->DefaultDacl, RtlCopyMemory(AccessToken->DefaultDacl,
DefaultDacl, DefaultDacl,
DefaultDacl->AclSize); DefaultDacl->AclSize);
}
else
{
AccessToken->DefaultDacl = NULL;
}
if (!SystemToken) if (!SystemToken)
{ {
@ -2376,24 +2387,37 @@ Cleanup:
NTSTATUS NTSTATUS
NTAPI NTAPI
NtCreateToken(OUT PHANDLE TokenHandle, NtCreateToken(
IN ACCESS_MASK DesiredAccess, _Out_ PHANDLE TokenHandle,
IN POBJECT_ATTRIBUTES ObjectAttributes, _In_ ACCESS_MASK DesiredAccess,
IN TOKEN_TYPE TokenType, _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
IN PLUID AuthenticationId, _In_ TOKEN_TYPE TokenType,
IN PLARGE_INTEGER ExpirationTime, _In_ PLUID AuthenticationId,
IN PTOKEN_USER TokenUser, _In_ PLARGE_INTEGER ExpirationTime,
IN PTOKEN_GROUPS TokenGroups, _In_ PTOKEN_USER TokenUser,
IN PTOKEN_PRIVILEGES TokenPrivileges, _In_ PTOKEN_GROUPS TokenGroups,
IN PTOKEN_OWNER TokenOwner, _In_ PTOKEN_PRIVILEGES TokenPrivileges,
IN PTOKEN_PRIMARY_GROUP TokenPrimaryGroup, _In_opt_ PTOKEN_OWNER TokenOwner,
IN PTOKEN_DEFAULT_DACL TokenDefaultDacl, _In_ PTOKEN_PRIMARY_GROUP TokenPrimaryGroup,
IN PTOKEN_SOURCE TokenSource) _In_opt_ PTOKEN_DEFAULT_DACL TokenDefaultDacl,
_In_ PTOKEN_SOURCE TokenSource)
{ {
HANDLE hToken; HANDLE hToken;
KPROCESSOR_MODE PreviousMode; KPROCESSOR_MODE PreviousMode;
ULONG nTokenPrivileges = 0; ULONG PrivilegeCount, GroupCount;
PSID OwnerSid, PrimaryGroupSid;
PACL DefaultDacl;
LARGE_INTEGER LocalExpirationTime = {{0, 0}}; LARGE_INTEGER LocalExpirationTime = {{0, 0}};
LUID LocalAuthenticationId;
TOKEN_SOURCE LocalTokenSource;
SECURITY_QUALITY_OF_SERVICE LocalSecurityQos;
PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
PSID_AND_ATTRIBUTES CapturedUser = NULL;
PSID_AND_ATTRIBUTES CapturedGroups = NULL;
PSID CapturedOwnerSid = NULL;
PSID CapturedPrimaryGroupSid = NULL;
PACL CapturedDefaultDacl = NULL;
ULONG PrivilegesLength, UserLength, GroupsLength;
NTSTATUS Status; NTSTATUS Status;
PAGED_CODE(); PAGED_CODE();
@ -2405,64 +2429,197 @@ NtCreateToken(OUT PHANDLE TokenHandle,
_SEH2_TRY _SEH2_TRY
{ {
ProbeForWriteHandle(TokenHandle); ProbeForWriteHandle(TokenHandle);
if (ObjectAttributes != NULL)
{
ProbeForRead(ObjectAttributes,
sizeof(OBJECT_ATTRIBUTES),
sizeof(ULONG));
LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService;
}
ProbeForRead(AuthenticationId, ProbeForRead(AuthenticationId,
sizeof(LUID), sizeof(LUID),
sizeof(ULONG)); sizeof(ULONG));
LocalAuthenticationId = *AuthenticationId;
LocalExpirationTime = ProbeForReadLargeInteger(ExpirationTime); LocalExpirationTime = ProbeForReadLargeInteger(ExpirationTime);
ProbeForRead(TokenUser, ProbeForRead(TokenUser,
sizeof(TOKEN_USER), sizeof(TOKEN_USER),
sizeof(ULONG)); sizeof(ULONG));
ProbeForRead(TokenGroups, ProbeForRead(TokenGroups,
sizeof(TOKEN_GROUPS), sizeof(TOKEN_GROUPS),
sizeof(ULONG)); sizeof(ULONG));
GroupCount = TokenGroups->GroupCount;
ProbeForRead(TokenPrivileges, ProbeForRead(TokenPrivileges,
sizeof(TOKEN_PRIVILEGES), sizeof(TOKEN_PRIVILEGES),
sizeof(ULONG)); sizeof(ULONG));
ProbeForRead(TokenOwner, PrivilegeCount = TokenPrivileges->PrivilegeCount;
sizeof(TOKEN_OWNER),
sizeof(ULONG)); if (TokenOwner != NULL)
{
ProbeForRead(TokenOwner,
sizeof(TOKEN_OWNER),
sizeof(ULONG));
OwnerSid = TokenOwner->Owner;
}
else
{
OwnerSid = NULL;
}
ProbeForRead(TokenPrimaryGroup, ProbeForRead(TokenPrimaryGroup,
sizeof(TOKEN_PRIMARY_GROUP), sizeof(TOKEN_PRIMARY_GROUP),
sizeof(ULONG)); sizeof(ULONG));
ProbeForRead(TokenDefaultDacl, PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup;
sizeof(TOKEN_DEFAULT_DACL),
sizeof(ULONG)); if (TokenDefaultDacl != NULL)
{
ProbeForRead(TokenDefaultDacl,
sizeof(TOKEN_DEFAULT_DACL),
sizeof(ULONG));
DefaultDacl = TokenDefaultDacl->DefaultDacl;
}
else
{
DefaultDacl = NULL;
}
ProbeForRead(TokenSource, ProbeForRead(TokenSource,
sizeof(TOKEN_SOURCE), sizeof(TOKEN_SOURCE),
sizeof(ULONG)); sizeof(ULONG));
nTokenPrivileges = TokenPrivileges->PrivilegeCount; LocalTokenSource = *TokenSource;
} }
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{ {
/* Return the exception code */ /* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode()); return _SEH2_GetExceptionCode();
} }
_SEH2_END; _SEH2_END;
} }
else else
{ {
nTokenPrivileges = TokenPrivileges->PrivilegeCount; if (ObjectAttributes != NULL)
LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService;
LocalAuthenticationId = *AuthenticationId;
LocalExpirationTime = *ExpirationTime; LocalExpirationTime = *ExpirationTime;
GroupCount = TokenGroups->GroupCount;
PrivilegeCount = TokenPrivileges->PrivilegeCount;
OwnerSid = TokenOwner ? TokenOwner->Owner : NULL;
PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup;
DefaultDacl = TokenDefaultDacl ? TokenDefaultDacl->DefaultDacl : NULL;
LocalTokenSource = *TokenSource;
} }
/* Check token type */
if ((TokenType < TokenPrimary) ||
(TokenType > TokenImpersonation))
{
return STATUS_BAD_TOKEN_TYPE;
}
/* Capture the user SID and attributes */
Status = SeCaptureSidAndAttributesArray(&TokenUser->User,
1,
PreviousMode,
NULL,
0,
PagedPool,
FALSE,
&CapturedUser,
&UserLength);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* Capture the groups SID and attributes array */
Status = SeCaptureSidAndAttributesArray(&TokenGroups->Groups[0],
GroupCount,
PreviousMode,
NULL,
0,
PagedPool,
FALSE,
&CapturedGroups,
&GroupsLength);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* Capture privileges */
Status = SeCaptureLuidAndAttributesArray(&TokenPrivileges->Privileges[0],
PrivilegeCount,
PreviousMode,
NULL,
0,
PagedPool,
FALSE,
&CapturedPrivileges,
&PrivilegesLength);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* Capture the token owner SID */
if (TokenOwner != NULL)
{
Status = SepCaptureSid(OwnerSid,
PreviousMode,
PagedPool,
FALSE,
&CapturedOwnerSid);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
}
/* Capture the token primary group SID */
Status = SepCaptureSid(PrimaryGroupSid,
PreviousMode,
PagedPool,
FALSE,
&CapturedPrimaryGroupSid);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* Capture DefaultDacl */
if (DefaultDacl != NULL)
{
Status = SepCaptureAcl(DefaultDacl,
PreviousMode,
NonPagedPool,
FALSE,
&CapturedDefaultDacl);
}
/* Call the internal function */
Status = SepCreateToken(&hToken, Status = SepCreateToken(&hToken,
PreviousMode, PreviousMode,
DesiredAccess, DesiredAccess,
ObjectAttributes, ObjectAttributes,
TokenType, TokenType,
((PSECURITY_QUALITY_OF_SERVICE)(ObjectAttributes->SecurityQualityOfService))->ImpersonationLevel, LocalSecurityQos.ImpersonationLevel,
AuthenticationId, &LocalAuthenticationId,
&LocalExpirationTime, &LocalExpirationTime,
&TokenUser->User, CapturedUser,
TokenGroups->GroupCount, GroupCount,
TokenGroups->Groups, CapturedGroups,
0, // FIXME: Should capture 0, // FIXME: Should capture
nTokenPrivileges, PrivilegeCount,
TokenPrivileges->Privileges, CapturedPrivileges,
TokenOwner->Owner, CapturedOwnerSid,
TokenPrimaryGroup->PrimaryGroup, CapturedPrimaryGroupSid,
TokenDefaultDacl->DefaultDacl, CapturedDefaultDacl,
TokenSource, &LocalTokenSource,
FALSE); FALSE);
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{ {
@ -2477,6 +2634,16 @@ NtCreateToken(OUT PHANDLE TokenHandle,
_SEH2_END; _SEH2_END;
} }
Cleanup:
/* Release what we captured */
SeReleaseSidAndAttributesArray(CapturedUser, PreviousMode, FALSE);
SeReleaseSidAndAttributesArray(CapturedGroups, PreviousMode, FALSE);
SeReleaseLuidAndAttributesArray(CapturedPrivileges, PreviousMode, FALSE);
SepReleaseSid(CapturedOwnerSid, PreviousMode, FALSE);
SepReleaseSid(CapturedPrimaryGroupSid, PreviousMode, FALSE);
SepReleaseAcl(CapturedDefaultDacl, PreviousMode, FALSE);
return Status; return Status;
} }