From 7b4db0480347129a44bda0e60b5957ebda77dcfc Mon Sep 17 00:00:00 2001 From: Eric Kohl Date: Tue, 13 Jun 2017 20:58:10 +0000 Subject: [PATCH] [NTOSKRNL] NtAccessCheck: Call SePrivilegePolicyCheck to get the list of required privileges and return it to the caller. This fixes the ERROR_INSUFFICIENT_BUFFER failures in the advapi32 security winetest. svn path=/trunk/; revision=75028 --- reactos/ntoskrnl/se/accesschk.c | 77 ++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/reactos/ntoskrnl/se/accesschk.c b/reactos/ntoskrnl/se/accesschk.c index 9b84b463ad5..a7784b1c2b6 100644 --- a/reactos/ntoskrnl/se/accesschk.c +++ b/reactos/ntoskrnl/se/accesschk.c @@ -316,6 +316,19 @@ SepGetSDGroup(IN PSECURITY_DESCRIPTOR _SecurityDescriptor) return Group; } +static +ULONG +SepGetPrivilegeSetLength(IN PPRIVILEGE_SET PrivilegeSet) +{ + if (PrivilegeSet == NULL) + return 0; + + if (PrivilegeSet->PrivilegeCount == 0) + return (ULONG)(sizeof(PRIVILEGE_SET) - sizeof(LUID_AND_ATTRIBUTES)); + + return (ULONG)(sizeof(PRIVILEGE_SET) + + (PrivilegeSet->PrivilegeCount - 1) * sizeof(LUID_AND_ATTRIBUTES)); +} /* PUBLIC FUNCTIONS ***********************************************************/ @@ -526,6 +539,8 @@ NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor, SECURITY_SUBJECT_CONTEXT SubjectSecurityContext; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); ACCESS_MASK PreviouslyGrantedAccess = 0; + PPRIVILEGE_SET Privileges = NULL; + ULONG CapturedPrivilegeSetLength, RequiredPrivilegeSetLength; PTOKEN Token; NTSTATUS Status; PAGED_CODE(); @@ -561,8 +576,8 @@ NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor, ProbeForWrite(GrantedAccess, sizeof(ACCESS_MASK), sizeof(ULONG)); ProbeForWrite(AccessStatus, sizeof(NTSTATUS), sizeof(ULONG)); - /* Initialize the privilege set */ - PrivilegeSet->PrivilegeCount = 0; + /* Capture the privilege set length and the mapping */ + CapturedPrivilegeSetLength = *PrivilegeSetLength; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { @@ -604,6 +619,64 @@ NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor, return STATUS_BAD_IMPERSONATION_LEVEL; } + /* Check for ACCESS_SYSTEM_SECURITY and WRITE_OWNER access */ + Status = SePrivilegePolicyCheck(&DesiredAccess, + &PreviouslyGrantedAccess, + NULL, + Token, + &Privileges, + PreviousMode); + if (!NT_SUCCESS(Status)) + { + DPRINT("SePrivilegePolicyCheck failed (Status 0x%08lx)\n", Status); + ObDereferenceObject(Token); + *AccessStatus = Status; + *GrantedAccess = 0; + return STATUS_SUCCESS; + } + + /* Check the size of the privilege set and return the privileges */ + if (Privileges != NULL) + { + DPRINT("Privileges != NULL\n"); + + /* Calculate the required privilege set buffer size */ + RequiredPrivilegeSetLength = SepGetPrivilegeSetLength(Privileges); + + /* Fail if the privilege set buffer is too small */ + if (CapturedPrivilegeSetLength < RequiredPrivilegeSetLength) + { + ObDereferenceObject(Token); + SeFreePrivileges(Privileges); + *PrivilegeSetLength = RequiredPrivilegeSetLength; + return STATUS_BUFFER_TOO_SMALL; + } + + /* Copy the privilege set to the caller */ + RtlCopyMemory(PrivilegeSet, + Privileges, + RequiredPrivilegeSetLength); + + /* Free the local privilege set */ + SeFreePrivileges(Privileges); + } + else + { + DPRINT("Privileges == NULL\n"); + + /* Fail if the privilege set buffer is too small */ + if (CapturedPrivilegeSetLength < sizeof(PRIVILEGE_SET)) + { + ObDereferenceObject(Token); + *PrivilegeSetLength = sizeof(PRIVILEGE_SET); + return STATUS_BUFFER_TOO_SMALL; + } + + /* Initialize the privilege set */ + PrivilegeSet->PrivilegeCount = 0; + PrivilegeSet->Control = 0; + } + /* Capture the security descriptor */ Status = SeCaptureSecurityDescriptor(SecurityDescriptor, PreviousMode,