Author: tkreuzer
Date: Thu Feb 6 19:26:05 2014
New Revision: 62016
URL:
http://svn.reactos.org/svn/reactos?rev=62016&view=rev
Log:
[NTOSKRNL]
Implement SepAccessCheckAndAuditAlarm, which now does proper argument capturing and
forwards those to SepAccessCheckAndAuditAlarmWorker, which for now only grants access
without checking.
Modified:
trunk/reactos/ntoskrnl/se/audit.c
Modified: trunk/reactos/ntoskrnl/se/audit.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/se/audit.c?rev=62…
==============================================================================
--- trunk/reactos/ntoskrnl/se/audit.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/se/audit.c [iso-8859-1] Thu Feb 6 19:26:05 2014
@@ -207,13 +207,119 @@
UNIMPLEMENTED;
}
+static
+NTSTATUS
+SeCaptureObjectTypeList(
+ _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
+ _In_ ULONG ObjectTypeListLength,
+ _In_ KPROCESSOR_MODE PreviousMode,
+ _Out_ POBJECT_TYPE_LIST *CapturedObjectTypeList)
+{
+ SIZE_T Size;
+
+ if (PreviousMode == KernelMode)
+ {
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (ObjectTypeListLength == 0)
+ {
+ *CapturedObjectTypeList = NULL;
+ return STATUS_SUCCESS;
+ }
+
+ if (ObjectTypeList == NULL)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Calculate the list size and check for integer overflow */
+ Size = ObjectTypeListLength * sizeof(OBJECT_TYPE_LIST);
+ if (Size == 0)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Allocate a new list */
+ *CapturedObjectTypeList = ExAllocatePoolWithTag(PagedPool, Size, TAG_SEPA);
+ if (*CapturedObjectTypeList == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ _SEH2_TRY
+ {
+ ProbeForRead(ObjectTypeList, Size, sizeof(ULONG));
+ RtlCopyMemory(*CapturedObjectTypeList, ObjectTypeList, Size);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ExFreePoolWithTag(*CapturedObjectTypeList, TAG_SEPA);
+ *CapturedObjectTypeList = NULL;
+ return _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ return STATUS_SUCCESS;
+}
+
+static
+VOID
+SeReleaseObjectTypeList(
+ _In_ _Post_invalid_ POBJECT_TYPE_LIST CapturedObjectTypeList,
+ _In_ KPROCESSOR_MODE PreviousMode)
+{
+ if ((PreviousMode != KernelMode) && (CapturedObjectTypeList != NULL))
+ ExFreePoolWithTag(CapturedObjectTypeList, TAG_SEPA);
+}
+
+_Must_inspect_result_
+static
+NTSTATUS
+SepAccessCheckAndAuditAlarmWorker(
+ _In_ PUNICODE_STRING SubsystemName,
+ _In_opt_ PVOID HandleId,
+ _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
+ _In_ PUNICODE_STRING ObjectTypeName,
+ _In_ PUNICODE_STRING ObjectName,
+ _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _In_opt_ PSID PrincipalSelfSid,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ AUDIT_EVENT_TYPE AuditType,
+ _In_ BOOLEAN HaveAuditPrivilege,
+ _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
+ _In_ ULONG ObjectTypeListLength,
+ _In_ PGENERIC_MAPPING GenericMapping,
+ _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccessList,
+ _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatusList,
+ _Out_ PBOOLEAN GenerateOnClose,
+ _In_ BOOLEAN UseResultList)
+{
+ ULONG ResultListLength, i;
+
+ /* Get the length of the result list */
+ ResultListLength = UseResultList ? ObjectTypeListLength : 1;
+
+ /// FIXME: we should do some real work here...
+ UNIMPLEMENTED;
+
+ /// HACK: we just pretend all access is granted!
+ for (i = 0; i < ResultListLength; i++)
+ {
+ GrantedAccessList[i] = DesiredAccess;
+ AccessStatusList[i] = STATUS_SUCCESS;
+ }
+
+ return STATUS_SUCCESS;
+}
+
_Must_inspect_result_
NTSTATUS
NTAPI
SepAccessCheckAndAuditAlarm(
_In_ PUNICODE_STRING SubsystemName,
_In_opt_ PVOID HandleId,
- _In_ PHANDLE ClientToken,
+ _In_ PHANDLE ClientTokenHandle,
_In_ PUNICODE_STRING ObjectTypeName,
_In_ PUNICODE_STRING ObjectName,
_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
@@ -232,13 +338,32 @@
SECURITY_SUBJECT_CONTEXT SubjectContext;
ULONG ResultListLength;
GENERIC_MAPPING LocalGenericMapping;
+ PTOKEN SubjectContextToken, ClientToken;
+ BOOLEAN AllocatedResultLists;
+ BOOLEAN HaveAuditPrivilege;
+ PISECURITY_DESCRIPTOR CapturedSecurityDescriptor;
+ UNICODE_STRING CapturedSubsystemName, CapturedObjectTypeName, CapturedObjectName;
+ ACCESS_MASK GrantedAccess, *SafeGrantedAccessList;
+ NTSTATUS AccessStatus, *SafeAccessStatusList;
+ PSID CapturedPrincipalSelfSid;
+ POBJECT_TYPE_LIST CapturedObjectTypeList;
+ ULONG i;
+ BOOLEAN LocalGenerateOnClose;
NTSTATUS Status;
PAGED_CODE();
- DBG_UNREFERENCED_LOCAL_VARIABLE(LocalGenericMapping);
-
/* Only user mode is supported! */
ASSERT(ExGetPreviousMode() != KernelMode);
+
+ /* Start clean */
+ AllocatedResultLists = FALSE;
+ ClientToken = NULL;
+ CapturedSecurityDescriptor = NULL;
+ CapturedSubsystemName.Buffer = NULL;
+ CapturedObjectTypeName.Buffer = NULL;
+ CapturedObjectName.Buffer = NULL;
+ CapturedPrincipalSelfSid = NULL;
+ CapturedObjectTypeList = NULL;
/* Validate AuditType */
if ((AuditType != AuditEventObjectAccess) &&
@@ -252,12 +377,13 @@
SeCaptureSubjectContext(&SubjectContext);
/* Did the caller pass a token handle? */
- if (ClientToken == NULL)
+ if (ClientTokenHandle == NULL)
{
/* Check if we have a token in the subject context */
if (SubjectContext.ClientToken == NULL)
{
Status = STATUS_NO_IMPERSONATION_TOKEN;
+ DPRINT1("No token\n");
goto Cleanup;
}
@@ -265,6 +391,8 @@
if (SubjectContext.ImpersonationLevel < SecurityIdentification)
{
Status = STATUS_BAD_IMPERSONATION_LEVEL;
+ DPRINT1("Invalid impersonation level 0x%lx\n",
+ SubjectContext.ImpersonationLevel);
goto Cleanup;
}
}
@@ -277,13 +405,30 @@
if ((ResultListLength == 0) || (ResultListLength > 0x1000))
{
Status = STATUS_INVALID_PARAMETER;
+ DPRINT1("Invalud ResultListLength: 0x%lx\n", ResultListLength);
goto Cleanup;
}
+
+ /* Allocate a safe buffer from paged pool */
+ SafeGrantedAccessList = ExAllocatePoolWithTag(PagedPool,
+ 2 * ResultListLength *
sizeof(ULONG),
+ TAG_SEPA);
+ if (SafeGrantedAccessList == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ DPRINT1("Failed to allocate access lists\n");
+ goto Cleanup;
+ }
+
+ SafeAccessStatusList = (PNTSTATUS)&SafeGrantedAccessList[ResultListLength];
+ AllocatedResultLists = TRUE;
}
else
{
/* List length is 1 */
ResultListLength = 1;
+ SafeGrantedAccessList = &GrantedAccess;
+ SafeAccessStatusList = &AccessStatus;
}
_SEH2_TRY
@@ -303,17 +448,193 @@
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
+ DPRINT1("Exception while probing parameters: 0x%lx\n", Status);
goto Cleanup;
}
_SEH2_END;
-
- UNIMPLEMENTED;
-
- /* For now pretend everything else is ok */
- Status = STATUS_SUCCESS;
+ /* Do we have a client token? */
+ if (ClientTokenHandle != NULL)
+ {
+ /* Reference the client token */
+ Status = ObReferenceObjectByHandle(*ClientTokenHandle,
+ TOKEN_QUERY,
+ SeTokenObjectType,
+ UserMode,
+ (PVOID*)&ClientToken,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to reference token handle %p: %lx\n",
+ *ClientTokenHandle, Status);
+ goto Cleanup;
+ }
+
+ SubjectContextToken = SubjectContext.ClientToken;
+ SubjectContext.ClientToken = ClientToken;
+ }
+
+ /* Check for audit privilege */
+ HaveAuditPrivilege = SeSinglePrivilegeCheck(SeAuditPrivilege, UserMode);
+ if (!HaveAuditPrivilege && !(Flags & AUDIT_ALLOW_NO_PRIVILEGE))
+ {
+ DPRINT1("Caller does not have SeAuditPrivilege\n");
+ Status = STATUS_PRIVILEGE_NOT_HELD;
+ goto Cleanup;
+ }
+
+ /* Generic access must already be mapped to non-generic access types! */
+ if (DesiredAccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE |
GENERIC_ALL))
+ {
+ DPRINT1("Generic access rights requested: 0x%lx\n", DesiredAccess);
+ Status = STATUS_GENERIC_NOT_MAPPED;
+ goto Cleanup;
+ }
+
+ /* Capture the security descriptor */
+ Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
+ UserMode,
+ PagedPool,
+ FALSE,
+ &CapturedSecurityDescriptor);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to capture security descriptor!\n");
+ goto Cleanup;
+ }
+
+ /* Validate the Security descriptor */
+ if ((SepGetOwnerFromDescriptor(CapturedSecurityDescriptor) == NULL) ||
+ (SepGetGroupFromDescriptor(CapturedSecurityDescriptor) == NULL))
+ {
+ Status = STATUS_INVALID_SECURITY_DESCR;
+ DPRINT1("Invalid security descriptor\n");
+ goto Cleanup;
+ }
+
+ /* Probe and capture the subsystem name */
+ Status = ProbeAndCaptureUnicodeString(&CapturedSubsystemName,
+ UserMode,
+ SubsystemName);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to capture subsystem name!\n");
+ goto Cleanup;
+ }
+
+ /* Probe and capture the object type name */
+ Status = ProbeAndCaptureUnicodeString(&CapturedObjectTypeName,
+ UserMode,
+ ObjectTypeName);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to capture object type name!\n");
+ goto Cleanup;
+ }
+
+ /* Probe and capture the object name */
+ Status = ProbeAndCaptureUnicodeString(&CapturedObjectName,
+ UserMode,
+ ObjectName);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to capture object name!\n");
+ goto Cleanup;
+ }
+
+ /* Check if we have a PrincipalSelfSid */
+ if (PrincipalSelfSid != NULL)
+ {
+ /* Capture it */
+ Status = SepCaptureSid(PrincipalSelfSid,
+ UserMode,
+ PagedPool,
+ FALSE,
+ &CapturedPrincipalSelfSid);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to capture PrincipalSelfSid!\n");
+ goto Cleanup;
+ }
+ }
+
+ /* Capture the object type list */
+ Status = SeCaptureObjectTypeList(ObjectTypeList,
+ ObjectTypeListLength,
+ UserMode,
+ &CapturedObjectTypeList);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to capture object type list!\n");
+ goto Cleanup;
+ }
+
+ /* Call the worker routine with the captured buffers */
+ SepAccessCheckAndAuditAlarmWorker(&CapturedSubsystemName,
+ HandleId,
+ &SubjectContext,
+ &CapturedObjectTypeName,
+ &CapturedObjectName,
+ CapturedSecurityDescriptor,
+ CapturedPrincipalSelfSid,
+ DesiredAccess,
+ AuditType,
+ HaveAuditPrivilege,
+ CapturedObjectTypeList,
+ ObjectTypeListLength,
+ &LocalGenericMapping,
+ SafeGrantedAccessList,
+ SafeAccessStatusList,
+ &LocalGenerateOnClose,
+ UseResultList);
+
+ /* Enter SEH to copy the data back to user mode */
+ _SEH2_TRY
+ {
+ /* Loop all result entries (only 1 when no list was requested) */
+ NT_ASSERT(UseResultList || (ResultListLength == 1));
+ for (i = 0; i < ResultListLength; i++)
+ {
+ AccessStatusList[i] = SafeAccessStatusList[i];
+ GrantedAccessList[i] = SafeGrantedAccessList[i];
+ }
+
+ *GenerateOnClose = LocalGenerateOnClose;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ DPRINT1("Exception while copying back data: 0x%lx\n", Status);
+ }
Cleanup:
+
+ if (CapturedObjectTypeList != NULL)
+ SeReleaseObjectTypeList(CapturedObjectTypeList, UserMode);
+
+ if (CapturedPrincipalSelfSid != NULL)
+ SepReleaseSid(CapturedPrincipalSelfSid, UserMode, FALSE);
+
+ if (CapturedObjectName.Buffer != NULL)
+ ReleaseCapturedUnicodeString(&CapturedObjectName, UserMode);
+
+ if (CapturedObjectTypeName.Buffer != NULL)
+ ReleaseCapturedUnicodeString(&CapturedObjectTypeName, UserMode);
+
+ if (CapturedSubsystemName.Buffer != NULL)
+ ReleaseCapturedUnicodeString(&CapturedSubsystemName, UserMode);
+
+ if (CapturedSecurityDescriptor != NULL)
+ SeReleaseSecurityDescriptor(CapturedSecurityDescriptor, UserMode, FALSE);
+
+ if (ClientToken != NULL)
+ {
+ ObDereferenceObject(ClientToken);
+ SubjectContext.ClientToken = SubjectContextToken;
+ }
+
+ if (AllocatedResultLists)
+ ExFreePoolWithTag(SafeGrantedAccessList, TAG_SEPA);
/* Release the security subject context */
SeReleaseSubjectContext(&SubjectContext);
@@ -620,6 +941,9 @@
PreviousMode = ExGetPreviousMode();
ASSERT(PreviousMode != KernelMode);
+ CapturedSubsystemName.Buffer = NULL;
+ CapturedServiceName.Buffer = NULL;
+
/* Reference the client token */
Status = ObReferenceObjectByHandle(ClientToken,
TOKEN_QUERY,
@@ -724,8 +1048,8 @@
/* Call the internal function */
SepAdtPrivilegedServiceAuditAlarm(&SubjectContext,
- &CapturedSubsystemName,
- &CapturedServiceName,
+ SubsystemName ? &CapturedSubsystemName : NULL,
+ ServiceName ? &CapturedServiceName : NULL,
Token,
SubjectContext.PrimaryToken,
CapturedPrivileges,
@@ -738,9 +1062,9 @@
Cleanup:
/* Cleanup resources */
- if (SubsystemName != NULL)
+ if (CapturedSubsystemName.Buffer != NULL)
ReleaseCapturedUnicodeString(&CapturedSubsystemName, PreviousMode);
- if (ServiceName != NULL)
+ if (CapturedServiceName.Buffer != NULL)
ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
if (CapturedPrivileges != NULL)
ExFreePoolWithTag(CapturedPrivileges, 0);