mirror of
https://github.com/reactos/reactos.git
synced 2025-08-04 03:05:40 +00:00
[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:
parent
56b0d82c30
commit
b9fdfea09e
1 changed files with 211 additions and 44 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue