From 5ebaa3c3ddfdbe08a0e603f6a554a87500cbf7ad Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Tue, 18 Feb 2014 17:51:45 +0000 Subject: [PATCH] [NTOSKRNL] - Implement SeCheckAuditPrivilege and use it instead of SeSinglePrivilegeCheck, because the latter uses the effective token and we want the primary token - Implement SePrivilegedServiceAuditAlarm - Add and initialize missing SeLocalServiceSid and SeNetworkServiceSid svn path=/trunk/; revision=62245 --- reactos/ntoskrnl/include/internal/se.h | 16 ++++ reactos/ntoskrnl/se/audit.c | 110 +++++++++++++++++++------ reactos/ntoskrnl/se/priv.c | 42 +++++++++- reactos/ntoskrnl/se/semgr.c | 5 ++ reactos/ntoskrnl/se/sid.c | 13 ++- 5 files changed, 157 insertions(+), 29 deletions(-) diff --git a/reactos/ntoskrnl/include/internal/se.h b/reactos/ntoskrnl/include/internal/se.h index ec516eb6047..8c80fac07a3 100644 --- a/reactos/ntoskrnl/include/internal/se.h +++ b/reactos/ntoskrnl/include/internal/se.h @@ -143,6 +143,8 @@ extern PSID SeAliasBackupOpsSid; extern PSID SeAuthenticatedUsersSid; extern PSID SeRestrictedSid; extern PSID SeAnonymousLogonSid; +extern PSID SeLocalServiceSid; +extern PSID SeNetworkServiceSid; /* Privileges */ extern const LUID SeCreateTokenPrivilege; @@ -531,6 +533,20 @@ SeFastTraverseCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor, IN ACCESS_MASK DesiredAccess, IN KPROCESSOR_MODE AccessMode); +BOOLEAN +NTAPI +SeCheckAuditPrivilege( + _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext, + _In_ KPROCESSOR_MODE PreviousMode); + +VOID +NTAPI +SePrivilegedServiceAuditAlarm( + _In_opt_ PUNICODE_STRING ServiceName, + _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext, + _In_ PPRIVILEGE_SET PrivilegeSet, + _In_ BOOLEAN AccessGranted); + #endif /* EOF */ diff --git a/reactos/ntoskrnl/se/audit.c b/reactos/ntoskrnl/se/audit.c index 1e583e81ee6..f3d826e39f3 100644 --- a/reactos/ntoskrnl/se/audit.c +++ b/reactos/ntoskrnl/se/audit.c @@ -16,6 +16,8 @@ #define SEP_PRIVILEGE_SET_MAX_COUNT 60 +UNICODE_STRING SeSubsystemName = RTL_CONSTANT_STRING(L"Security"); + /* PRIVATE FUNCTIONS***********************************************************/ BOOLEAN @@ -202,11 +204,59 @@ SepAdtPrivilegedServiceAuditAlarm( _In_ PTOKEN Token, _In_ PTOKEN PrimaryToken, _In_ PPRIVILEGE_SET Privileges, - _In_ BOOLEAN AccessGranted ) + _In_ BOOLEAN AccessGranted) { UNIMPLEMENTED; } +VOID +NTAPI +SePrivilegedServiceAuditAlarm( + _In_opt_ PUNICODE_STRING ServiceName, + _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext, + _In_ PPRIVILEGE_SET PrivilegeSet, + _In_ BOOLEAN AccessGranted) +{ + PTOKEN EffectiveToken; + PSID UserSid; + PAGED_CODE(); + + /* Get the effective token */ + if (SubjectContext->ClientToken != NULL) + EffectiveToken = SubjectContext->ClientToken; + else + EffectiveToken = SubjectContext->PrimaryToken; + + /* Get the user SID */ + UserSid = EffectiveToken->UserAndGroups->Sid; + + /* Check if this is the local system SID */ + if (RtlEqualSid(UserSid, SeLocalSystemSid)) + { + /* Nothing to do */ + return; + } + + /* Check if this is the network service or local service SID */ + if (RtlEqualSid(UserSid, SeExports->SeNetworkServiceSid) || + RtlEqualSid(UserSid, SeExports->SeLocalServiceSid)) + { + // FIXME: should continue for a certain set of privileges + return; + } + + /* Call the worker function */ + SepAdtPrivilegedServiceAuditAlarm(SubjectContext, + &SeSubsystemName, + ServiceName, + SubjectContext->ClientToken, + SubjectContext->PrimaryToken, + PrivilegeSet, + AccessGranted); + +} + + static NTSTATUS SeCaptureObjectTypeList( @@ -477,7 +527,7 @@ SepAccessCheckAndAuditAlarm( } /* Check for audit privilege */ - HaveAuditPrivilege = SeSinglePrivilegeCheck(SeAuditPrivilege, UserMode); + HaveAuditPrivilege = SeCheckAuditPrivilege(&SubjectContext, UserMode); if (!HaveAuditPrivilege && !(Flags & AUDIT_ALLOW_NO_PRIVILEGE)) { DPRINT1("Caller does not have SeAuditPrivilege\n"); @@ -811,6 +861,7 @@ NtCloseObjectAuditAlarm( PVOID HandleId, BOOLEAN GenerateOnClose) { + SECURITY_SUBJECT_CONTEXT SubjectContext; UNICODE_STRING CapturedSubsystemName; KPROCESSOR_MODE PreviousMode; BOOLEAN UseImpersonationToken; @@ -832,11 +883,15 @@ NtCloseObjectAuditAlarm( return STATUS_SUCCESS; } - /* Validate privilege */ - if (!SeSinglePrivilegeCheck(SeAuditPrivilege, PreviousMode)) + /* Capture the security subject context */ + SeCaptureSubjectContext(&SubjectContext); + + /* Check for audit privilege */ + if (!SeCheckAuditPrivilege(&SubjectContext, PreviousMode)) { DPRINT1("Caller does not have SeAuditPrivilege\n"); - return STATUS_PRIVILEGE_NOT_HELD; + Status = STATUS_PRIVILEGE_NOT_HELD; + goto Cleanup; } /* Probe and capture the subsystem name */ @@ -846,7 +901,7 @@ NtCloseObjectAuditAlarm( if (!NT_SUCCESS(Status)) { DPRINT1("Failed to capture subsystem name!\n"); - return Status; + goto Cleanup; } /* Get the current thread and check if it's impersonating */ @@ -887,7 +942,14 @@ NtCloseObjectAuditAlarm( PsDereferencePrimaryToken(Token); } - return STATUS_SUCCESS; + Status = STATUS_SUCCESS; + +Cleanup: + + /* Release the security subject context */ + SeReleaseSubjectContext(&SubjectContext); + + return Status; } @@ -986,6 +1048,9 @@ NtOpenObjectAuditAlarm( return Status; } + /* Capture the security subject context */ + SeCaptureSubjectContext(&SubjectContext); + /* Validate the token's impersonation level */ if ((ClientToken->TokenType == TokenImpersonation) && (ClientToken->ImpersonationLevel < SecurityIdentification)) @@ -996,7 +1061,7 @@ NtOpenObjectAuditAlarm( } /* Check for audit privilege */ - if (!SeSinglePrivilegeCheck(SeAuditPrivilege, UserMode)) + if (!SeCheckAuditPrivilege(&SubjectContext, UserMode)) { DPRINT1("Caller does not have SeAuditPrivilege\n"); Status = STATUS_PRIVILEGE_NOT_HELD; @@ -1106,9 +1171,6 @@ NtOpenObjectAuditAlarm( goto Cleanup; } - /* Capture the security subject context */ - SeCaptureSubjectContext(&SubjectContext); - /* Call the internal function */ SepOpenObjectAuditAlarm(&SubjectContext, &CapturedSubsystemName, @@ -1124,9 +1186,6 @@ NtOpenObjectAuditAlarm( AccessGranted, &LocalGenerateOnClose); - /* Release the security subject context */ - SeReleaseSubjectContext(&SubjectContext); - Status = STATUS_SUCCESS; /* Enter SEH to copy the data back to user mode */ @@ -1158,6 +1217,9 @@ Cleanup: if (CapturedPrivilegeSet != NULL) ExFreePoolWithTag(CapturedPrivilegeSet, 'rPeS'); + /* Release the security subject context */ + SeReleaseSubjectContext(&SubjectContext); + ObDereferenceObject(ClientToken); return Status; @@ -1213,12 +1275,15 @@ NtPrivilegedServiceAuditAlarm( return STATUS_BAD_IMPERSONATION_LEVEL; } - /* Validate privilege */ - if (!SeSinglePrivilegeCheck(SeAuditPrivilege, PreviousMode)) + /* Capture the security subject context */ + SeCaptureSubjectContext(&SubjectContext); + + /* Check for audit privilege */ + if (!SeCheckAuditPrivilege(&SubjectContext, PreviousMode)) { DPRINT1("Caller does not have SeAuditPrivilege\n"); - ObDereferenceObject(ClientToken); - return STATUS_PRIVILEGE_NOT_HELD; + Status = STATUS_PRIVILEGE_NOT_HELD; + goto Cleanup; } /* Do we have a subsystem name? */ @@ -1290,9 +1355,6 @@ NtPrivilegedServiceAuditAlarm( } _SEH2_END; - /* Capture the security subject context */ - SeCaptureSubjectContext(&SubjectContext); - /* Call the internal function */ SepAdtPrivilegedServiceAuditAlarm(&SubjectContext, SubsystemName ? &CapturedSubsystemName : NULL, @@ -1302,9 +1364,6 @@ NtPrivilegedServiceAuditAlarm( CapturedPrivileges, AccessGranted); - /* Release the security subject context */ - SeReleaseSubjectContext(&SubjectContext); - Status = STATUS_SUCCESS; Cleanup: @@ -1318,6 +1377,9 @@ Cleanup: if (CapturedPrivileges != NULL) ExFreePoolWithTag(CapturedPrivileges, 'rPeS'); + /* Release the security subject context */ + SeReleaseSubjectContext(&SubjectContext); + ObDereferenceObject(ClientToken); return Status; diff --git a/reactos/ntoskrnl/se/priv.c b/reactos/ntoskrnl/se/priv.c index 292da12e71a..9014fa895a1 100644 --- a/reactos/ntoskrnl/se/priv.c +++ b/reactos/ntoskrnl/se/priv.c @@ -252,6 +252,40 @@ SePrivilegePolicyCheck( return STATUS_SUCCESS; } +BOOLEAN +NTAPI +SeCheckAuditPrivilege( + _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext, + _In_ KPROCESSOR_MODE PreviousMode) +{ + PRIVILEGE_SET PrivilegeSet; + BOOLEAN Result; + PAGED_CODE(); + + /* Initialize the privilege set with the single privilege */ + PrivilegeSet.PrivilegeCount = 1; + PrivilegeSet.Control = PRIVILEGE_SET_ALL_NECESSARY; + PrivilegeSet.Privilege[0].Luid = SeAuditPrivilege; + PrivilegeSet.Privilege[0].Attributes = 0; + + /* Check against the primary token! */ + Result = SepPrivilegeCheck(SubjectContext->PrimaryToken, + &PrivilegeSet.Privilege[0], + 1, + PRIVILEGE_SET_ALL_NECESSARY, + PreviousMode); + + if (PreviousMode != KernelMode) + { + SePrivilegedServiceAuditAlarm(NULL, + SubjectContext, + &PrivilegeSet, + Result); + } + + return Result; +} + NTSTATUS NTAPI SeCaptureLuidAndAttributesArray(PLUID_AND_ATTRIBUTES Src, @@ -506,11 +540,11 @@ SeSinglePrivilegeCheck(IN LUID PrivilegeValue, if (PreviousMode != KernelMode) { -#if 0 - SePrivilegedServiceAuditAlarm(0, + SePrivilegedServiceAuditAlarm(NULL, &SubjectContext, - &PrivilegeValue); -#endif + &Priv, + Result); + } SeReleaseSubjectContext(&SubjectContext); diff --git a/reactos/ntoskrnl/se/semgr.c b/reactos/ntoskrnl/se/semgr.c index 4d7c776cc5b..2c14c93c802 100644 --- a/reactos/ntoskrnl/se/semgr.c +++ b/reactos/ntoskrnl/se/semgr.c @@ -74,10 +74,15 @@ SepInitExports(VOID) SepExports.SeAuthenticatedUsersSid = SeAuthenticatedUsersSid; SepExports.SeRestrictedSid = SeRestrictedSid; SepExports.SeAnonymousLogonSid = SeAnonymousLogonSid; + SepExports.SeLocalServiceSid = SeLocalServiceSid; + SepExports.SeNetworkServiceSid = SeNetworkServiceSid; SepExports.SeUndockPrivilege = SeUndockPrivilege; SepExports.SeSyncAgentPrivilege = SeSyncAgentPrivilege; SepExports.SeEnableDelegationPrivilege = SeEnableDelegationPrivilege; + SepExports.SeManageVolumePrivilege = SeManageVolumePrivilege; + SepExports.SeImpersonatePrivilege = SeImpersonatePrivilege; + SepExports.SeCreateGlobalPrivilege = SeCreateGlobalPrivilege; SeExports = &SepExports; return TRUE; diff --git a/reactos/ntoskrnl/se/sid.c b/reactos/ntoskrnl/se/sid.c index 2ccbdf3a3df..6cf3c19eca1 100644 --- a/reactos/ntoskrnl/se/sid.c +++ b/reactos/ntoskrnl/se/sid.c @@ -55,6 +55,8 @@ PSID SeAliasBackupOpsSid = NULL; PSID SeAuthenticatedUsersSid = NULL; PSID SeRestrictedSid = NULL; PSID SeAnonymousLogonSid = NULL; +PSID SeLocalServiceSid = NULL; +PSID SeNetworkServiceSid = NULL; /* FUNCTIONS ******************************************************************/ @@ -135,6 +137,8 @@ SepInitSecurityIDs(VOID) SeAuthenticatedUsersSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); SeRestrictedSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); SeAnonymousLogonSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); + SeLocalServiceSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); + SeNetworkServiceSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); if (SeNullSid == NULL || SeWorldSid == NULL || SeLocalSid == NULL || SeCreatorOwnerSid == NULL || @@ -149,7 +153,8 @@ SepInitSecurityIDs(VOID) SeAliasAccountOpsSid == NULL || SeAliasSystemOpsSid == NULL || SeAliasPrintOpsSid == NULL || SeAliasBackupOpsSid == NULL || SeAuthenticatedUsersSid == NULL || SeRestrictedSid == NULL || - SeAnonymousLogonSid == NULL) + SeAnonymousLogonSid == NULL || SeLocalServiceSid == NULL || + SeNetworkServiceSid == NULL) { FreeInitializedSids(); return FALSE; @@ -183,6 +188,8 @@ SepInitSecurityIDs(VOID) RtlInitializeSid(SeAuthenticatedUsersSid, &SeNtSidAuthority, 1); RtlInitializeSid(SeRestrictedSid, &SeNtSidAuthority, 1); RtlInitializeSid(SeAnonymousLogonSid, &SeNtSidAuthority, 1); + RtlInitializeSid(SeLocalServiceSid, &SeNtSidAuthority, 1); + RtlInitializeSid(SeNetworkServiceSid, &SeNtSidAuthority, 1); SubAuthority = RtlSubAuthoritySid(SeNullSid, 0); *SubAuthority = SECURITY_NULL_RID; @@ -254,6 +261,10 @@ SepInitSecurityIDs(VOID) *SubAuthority = SECURITY_RESTRICTED_CODE_RID; SubAuthority = RtlSubAuthoritySid(SeAnonymousLogonSid, 0); *SubAuthority = SECURITY_ANONYMOUS_LOGON_RID; + SubAuthority = RtlSubAuthoritySid(SeLocalServiceSid, 0); + *SubAuthority = SECURITY_LOCAL_SERVICE_RID; + SubAuthority = RtlSubAuthoritySid(SeNetworkServiceSid, 0); + *SubAuthority = SECURITY_NETWORK_SERVICE_RID; return TRUE; }