Author: ekohl Date: Tue Jun 13 20:58:10 2017 New Revision: 75028
URL: http://svn.reactos.org/svn/reactos?rev=75028&view=rev Log: [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.
Modified: trunk/reactos/ntoskrnl/se/accesschk.c
Modified: trunk/reactos/ntoskrnl/se/accesschk.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/se/accesschk.c?rev... ============================================================================== --- trunk/reactos/ntoskrnl/se/accesschk.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/se/accesschk.c [iso-8859-1] Tue Jun 13 20:58:10 2017 @@ -316,6 +316,19 @@ 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 @@ 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 @@ 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) { @@ -602,6 +617,64 @@ DPRINT("Impersonation level < SecurityIdentification\n"); ObDereferenceObject(Token); 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 */