- Fix OB_SECURITY_METHOD prototype, callers, and implementors.

- Add call to SeOpenObjectAuditAlarm in ObCheckObjectAccess.
- Start adding Ob Callout validation on checked builds. For now only done around security functions.
- Set *MemoryAllocated to FALSE in ObGetObjectSecurity early on to avoid inconcistent state if the callback failed.
- Implement new XP function ObSetSecurityObjectByPointer and simplify NtSetSecurityObject by making it use it.
- More Win 2003 SecurityDescriptor Cache functions to sdcache instead of obsecure.c.

svn path=/trunk/; revision=25240
This commit is contained in:
Alex Ionescu 2006-12-29 22:17:29 +00:00
parent 635dda87ec
commit 8f2eb74d99
12 changed files with 279 additions and 164 deletions

View file

@ -215,7 +215,7 @@ typedef NTSTATUS
(NTAPI *OB_SECURITY_METHOD)(
IN PVOID Object,
IN SECURITY_OPERATION_CODE OperationType,
IN SECURITY_INFORMATION SecurityInformation, // FIXME: <= should be a pointer
IN PSECURITY_INFORMATION SecurityInformation,
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN OUT PULONG CapturedLength,
IN OUT PSECURITY_DESCRIPTOR *ObjectSecurityDescriptor,

View file

@ -165,7 +165,7 @@ CmiObjectDelete(PVOID DeletedObject);
NTSTATUS STDCALL
CmiObjectSecurity(PVOID ObjectBody,
SECURITY_OPERATION_CODE OperationCode,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR SecurityDescriptor,
PULONG BufferLength,
PSECURITY_DESCRIPTOR *OldSecurityDescriptor,

View file

@ -669,7 +669,7 @@ CmiAssignSecurityDescriptor(PKEY_OBJECT KeyObject,
NTSTATUS STDCALL
CmiObjectSecurity(PVOID ObjectBody,
SECURITY_OPERATION_CODE OperationCode,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR SecurityDescriptor,
PULONG BufferLength,
PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
@ -687,7 +687,7 @@ CmiObjectSecurity(PVOID ObjectBody,
case QuerySecurityDescriptor:
DPRINT("Query security descriptor\n");
return CmiQuerySecurityDescriptor((PKEY_OBJECT)ObjectBody,
SecurityInformation,
*SecurityInformation,
SecurityDescriptor,
BufferLength);

View file

@ -898,7 +898,7 @@ NTAPI
IopSecurityFile(
IN PVOID ObjectBody,
IN SECURITY_OPERATION_CODE OperationCode,
IN SECURITY_INFORMATION SecurityInformation,
IN PSECURITY_INFORMATION SecurityInformation,
IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
IN OUT PULONG BufferLength,
OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor,

View file

@ -6,6 +6,53 @@
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
#if DBG
VOID
FORCEINLINE
ObpCalloutStart(IN PKIRQL CalloutIrql)
{
/* Save the callout IRQL */
*CalloutIrql = KeGetCurrentIrql();
}
VOID
FORCEINLINE
ObpCalloutEnd(IN KIRQL CalloutIrql,
IN PCHAR Procedure,
IN POBJECT_TYPE ObjectType,
IN PVOID Object)
{
/* Detect IRQL change */
if (CalloutIrql != KeGetCurrentIrql())
{
/* Print error */
DbgPrint("OB: ObjectType: %wZ Procedure: %s Object: %08x\n",
&ObjectType->Name, Procedure, Object);
DbgPrint(" Returned at %x IRQL, but was called at %x IRQL\n",
KeGetCurrentIrql(), CalloutIrql);
DbgBreakPoint();
}
}
#else
VOID
FORCEINLINE
ObpCalloutStart(IN PKIRQL CalloutIrql)
{
/* No-op */
UNREFERENCED_PARAMETER(CalloutIrql);
}
VOID
FORCEINLINE
ObpCalloutEnd(IN KIRQL CalloutIrql,
IN PCHAR Procedure,
IN POBJECT_TYPE ObjectType,
IN PVOID Object)
{
UNREFERENCED_PARAMETER(CalloutIrql);
}
#endif
VOID
FORCEINLINE
ObpEnterObjectTypeMutex(IN POBJECT_TYPE ObjectType)

View file

@ -299,7 +299,7 @@ NTAPI
SeDefaultObjectMethod(
PVOID Object,
SECURITY_OPERATION_CODE OperationType,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR NewSecurityDescriptor,
PULONG ReturnLength,
PSECURITY_DESCRIPTOR *OldSecurityDescriptor,

View file

@ -162,5 +162,6 @@
#define TAG_SEPA TAG('S', 'e', 'P', 'a')
#define TAG_WAIT TAG('W', 'a', 'i', 't')
#define TAG_SEC_QUERY TAG('O', 'b', 'S', 'q')
#endif /* _NTOSKRNL_TAG_H */

View file

@ -1055,7 +1055,7 @@ NTSTATUS
NTAPI
IopSecurityFile(IN PVOID ObjectBody,
IN SECURITY_OPERATION_CODE OperationCode,
IN SECURITY_INFORMATION SecurityInformation,
IN PSECURITY_INFORMATION SecurityInformation,
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN OUT PULONG BufferLength,
IN OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
@ -1183,7 +1183,7 @@ IopSecurityFile(IN PVOID ObjectBody,
/* Set the major function and parameters */
StackPtr->MajorFunction = IRP_MJ_QUERY_SECURITY;
StackPtr->Parameters.QuerySecurity.SecurityInformation =
SecurityInformation;
*SecurityInformation;
StackPtr->Parameters.QuerySecurity.Length = *BufferLength;
Irp->UserBuffer = SecurityDescriptor;
}
@ -1192,7 +1192,7 @@ IopSecurityFile(IN PVOID ObjectBody,
/* Set the major function and parameters for a set */
StackPtr->MajorFunction = IRP_MJ_SET_SECURITY;
StackPtr->Parameters.SetSecurity.SecurityInformation =
SecurityInformation;
*SecurityInformation;
StackPtr->Parameters.SetSecurity.SecurityDescriptor =
SecurityDescriptor;
}
@ -1246,7 +1246,7 @@ IopSecurityFile(IN PVOID ObjectBody,
if (OperationCode == QuerySecurityDescriptor)
{
/* Set a World Security Descriptor */
Status = SeSetWorldSecurityDescriptor(SecurityInformation,
Status = SeSetWorldSecurityDescriptor(*SecurityInformation,
SecurityDescriptor,
BufferLength);
}

View file

@ -13,8 +13,6 @@
#define NDEBUG
#include <internal/debug.h>
#define TAG_SEC_QUERY TAG('O', 'b', 'S', 'q')
/* PRIVATE FUNCTIONS *********************************************************/
/*++
@ -109,6 +107,17 @@ ObCheckObjectAccess(IN PVOID Object,
AccessState->PreviouslyGrantedAccess |= GrantedAccess;
}
/* Do audit alarm */
SeOpenObjectAuditAlarm(&ObjectType->Name,
Object,
NULL,
SecurityDescriptor,
AccessState,
FALSE,
Result,
AccessMode,
&AccessState->GenerateOnClose);
/* We're done, unlock the context and release security */
SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
@ -149,6 +158,7 @@ ObAssignSecurity(IN PACCESS_STATE AccessState,
{
PSECURITY_DESCRIPTOR NewDescriptor;
NTSTATUS Status;
KIRQL CalloutIrql;
PAGED_CODE();
/* Build the new security descriptor */
@ -162,19 +172,19 @@ ObAssignSecurity(IN PACCESS_STATE AccessState,
if (!NT_SUCCESS(Status)) return Status;
/* Call the security method */
ObpCalloutStart(&CalloutIrql);
Status = Type->TypeInfo.SecurityProcedure(Object,
AssignSecurityDescriptor,
0,
NULL,
NewDescriptor,
NULL,
NULL,
PagedPool,
&Type->TypeInfo.GenericMapping);
if (!NT_SUCCESS(Status))
{
/* Release the new security descriptor */
SeDeassignSecurity(&NewDescriptor);
}
ObpCalloutEnd(CalloutIrql, "Security", Type, Object);
/* Check for failure and deassign security if so */
if (!NT_SUCCESS(Status)) SeDeassignSecurity(&NewDescriptor);
/* Return to caller */
return Status;
@ -208,39 +218,47 @@ ObGetObjectSecurity(IN PVOID Object,
{
POBJECT_HEADER Header;
POBJECT_TYPE Type;
ULONG Length;
ULONG Length = 0;
NTSTATUS Status;
SECURITY_INFORMATION SecurityInformation;
KIRQL CalloutIrql;
PAGED_CODE();
/* Get the object header and type */
Header = OBJECT_TO_OBJECT_HEADER(Object);
Type = Header->Type;
/* Tell the caller that we didn't have to allocate anything yet */
*MemoryAllocated = FALSE;
/* Check if the object uses default security */
if (Type->TypeInfo.SecurityProcedure == SeDefaultObjectMethod)
{
/* Reference the descriptor */
*SecurityDescriptor =
ObpReferenceCachedSecurityDescriptor(Header->SecurityDescriptor);
/* Tell the caller that we didn't have to allocate anything */
*MemoryAllocated = FALSE;
return STATUS_SUCCESS;
}
/* Set mask to query */
SecurityInformation = OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION |
SACL_SECURITY_INFORMATION;
/* Get the security descriptor size */
Length = 0;
ObpCalloutStart(&CalloutIrql);
Status = Type->TypeInfo.SecurityProcedure(Object,
QuerySecurityDescriptor,
OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION |
SACL_SECURITY_INFORMATION,
&SecurityInformation,
*SecurityDescriptor,
&Length,
&Header->SecurityDescriptor,
Type->TypeInfo.PoolType,
&Type->TypeInfo.GenericMapping);
ObpCalloutEnd(CalloutIrql, "Security", Type, Object);
/* Check for failure */
if (Status != STATUS_BUFFER_TOO_SMALL) return Status;
/* Allocate security descriptor */
@ -248,20 +266,21 @@ ObGetObjectSecurity(IN PVOID Object,
Length,
TAG_SEC_QUERY);
if (!(*SecurityDescriptor)) return STATUS_INSUFFICIENT_RESOURCES;
*MemoryAllocated = TRUE;
/* Query security descriptor */
*MemoryAllocated = TRUE;
ObpCalloutStart(&CalloutIrql);
Status = Type->TypeInfo.SecurityProcedure(Object,
QuerySecurityDescriptor,
OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION |
SACL_SECURITY_INFORMATION,
&SecurityInformation,
*SecurityDescriptor,
&Length,
&Header->SecurityDescriptor,
Type->TypeInfo.PoolType,
&Type->TypeInfo.GenericMapping);
ObpCalloutEnd(CalloutIrql, "Security", Type, Object);
/* Check for failure */
if (!NT_SUCCESS(Status))
{
/* Free the descriptor and tell the caller we failed */
@ -313,6 +332,51 @@ ObReleaseObjectSecurity(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
}
}
/*++
* @name ObSetSecurityObjectByPointer
* @implemented NT5.1
*
* The ObSetSecurityObjectByPointer routine <FILLMEIN>
*
* @param SecurityDescriptor
* <FILLMEIN>
*
* @param MemoryAllocated
* <FILLMEIN>
*
* @return STATUS_SUCCESS or appropriate error value.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
ObSetSecurityObjectByPointer(IN PVOID Object,
IN SECURITY_INFORMATION SecurityInformation,
IN PSECURITY_DESCRIPTOR SecurityDescriptor)
{
POBJECT_TYPE Type;
POBJECT_HEADER Header;
PAGED_CODE();
/* Get the header and type */
Header = OBJECT_TO_OBJECT_HEADER(Object);
Type = Header->Type;
/* Sanity check */
ASSERT(SecurityDescriptor);
/* Call the security procedure */
return Type->TypeInfo.SecurityProcedure(Object,
SetSecurityDescriptor,
&SecurityInformation,
SecurityDescriptor,
NULL,
&Header->SecurityDescriptor,
Type->TypeInfo.PoolType,
&Type->TypeInfo.GenericMapping);
}
/*++
* @name NtQuerySecurityObject
* @implemented NT4
@ -395,7 +459,7 @@ NtQuerySecurityObject(IN HANDLE Handle,
/* Call the security procedure's query function */
Status = Type->TypeInfo.SecurityProcedure(Object,
QuerySecurityDescriptor,
SecurityInformation,
&SecurityInformation,
SecurityDescriptor,
&Length,
&Header->SecurityDescriptor,
@ -450,8 +514,6 @@ NtSetSecurityObject(IN HANDLE Handle,
{
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
PVOID Object;
POBJECT_HEADER Header;
POBJECT_TYPE Type;
SECURITY_DESCRIPTOR_RELATIVE *CapturedDescriptor;
ACCESS_MASK DesiredAccess;
NTSTATUS Status;
@ -460,66 +522,63 @@ NtSetSecurityObject(IN HANDLE Handle,
/* Make sure the caller doesn't pass a NULL security descriptor! */
if (!SecurityDescriptor) return STATUS_ACCESS_VIOLATION;
/* Capture and make a copy of the security descriptor */
Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
PreviousMode,
PagedPool,
TRUE,
(PSECURITY_DESCRIPTOR*)
&CapturedDescriptor);
if (!NT_SUCCESS(Status)) return Status;
/* Set the required access rights for the operation */
SeSetSecurityAccessMask(SecurityInformation, &DesiredAccess);
/*
* Make sure the security descriptor passed by the caller
* is valid for the operation we're about to perform
*/
if (((SecurityInformation & OWNER_SECURITY_INFORMATION) &&
!(CapturedDescriptor->Owner)) ||
((SecurityInformation & GROUP_SECURITY_INFORMATION) &&
!(CapturedDescriptor->Group)))
/* Reference the object */
Status = ObReferenceObjectByHandle(Handle,
DesiredAccess,
NULL,
PreviousMode,
&Object,
NULL);
if (NT_SUCCESS(Status))
{
/* Set the failure status */
Status = STATUS_INVALID_SECURITY_DESCR;
}
else
{
/* Set the required access rights for the operation */
SeSetSecurityAccessMask(SecurityInformation, &DesiredAccess);
/* Reference the object */
Status = ObReferenceObjectByHandle(Handle,
DesiredAccess,
NULL,
PreviousMode,
&Object,
NULL);
if (NT_SUCCESS(Status))
/* Capture and make a copy of the security descriptor */
Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
PreviousMode,
PagedPool,
TRUE,
(PSECURITY_DESCRIPTOR*)
&CapturedDescriptor);
if (!NT_SUCCESS(Status))
{
/* Get the Object Header and Type */
Header = OBJECT_TO_OBJECT_HEADER(Object);
Type = Header->Type;
/* Call the security procedure's set function */
Status = Type->TypeInfo.SecurityProcedure(Object,
SetSecurityDescriptor,
SecurityInformation,
SecurityDescriptor,
NULL,
&Header->
SecurityDescriptor,
Type->TypeInfo.PoolType,
&Type->
TypeInfo.GenericMapping);
/* Now we can dereference the object */
/* Fail */
ObDereferenceObject(Object);
return Status;
}
/* Sanity check */
ASSERT(CapturedDescriptor->Control & SE_SELF_RELATIVE);
/*
* Make sure the security descriptor passed by the caller
* is valid for the operation we're about to perform
*/
if (((SecurityInformation & OWNER_SECURITY_INFORMATION) &&
!(CapturedDescriptor->Owner)) ||
((SecurityInformation & GROUP_SECURITY_INFORMATION) &&
!(CapturedDescriptor->Group)))
{
/* Set the failure status */
Status = STATUS_INVALID_SECURITY_DESCR;
}
else
{
/* Set security */
Status = ObSetSecurityObjectByPointer(Object,
SecurityInformation,
CapturedDescriptor);
}
/* Release the descriptor and return status */
SeReleaseSecurityDescriptor((PSECURITY_DESCRIPTOR)CapturedDescriptor,
PreviousMode,
TRUE);
}
/* Release the descriptor and return status */
SeReleaseSecurityDescriptor((PSECURITY_DESCRIPTOR)CapturedDescriptor,
PreviousMode,
TRUE);
/* Now we can dereference the object */
ObDereferenceObject(Object);
return Status;
}
@ -588,66 +647,4 @@ ObQueryObjectAuditingByHandle(IN HANDLE Handle,
return Status;
}
/*++
* @name ObLogSecurityDescriptor
* @unimplemented NT5.2
*
* The ObLogSecurityDescriptor routine <FILLMEIN>
*
* @param InputSecurityDescriptor
* <FILLMEIN>
*
* @param OutputSecurityDescriptor
* <FILLMEIN>
*
* @param RefBias
* <FILLMEIN>
*
* @return STATUS_SUCCESS or appropriate error value.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
ObLogSecurityDescriptor(IN PSECURITY_DESCRIPTOR InputSecurityDescriptor,
OUT PSECURITY_DESCRIPTOR *OutputSecurityDescriptor,
IN ULONG RefBias)
{
/* HACK: Return the same descriptor back */
PISECURITY_DESCRIPTOR SdCopy;
DPRINT1("ObLogSecurityDescriptor is not implemented!\n",
InputSecurityDescriptor);
SdCopy = ExAllocatePool(PagedPool, sizeof(*SdCopy));
RtlCopyMemory(SdCopy, InputSecurityDescriptor, sizeof(*SdCopy));
*OutputSecurityDescriptor = SdCopy;
return STATUS_SUCCESS;
}
/*++
* @name ObDereferenceSecurityDescriptor
* @unimplemented NT5.2
*
* The ObDereferenceSecurityDescriptor routine <FILLMEIN>
*
* @param SecurityDescriptor
* <FILLMEIN>
*
* @param Count
* <FILLMEIN>
*
* @return STATUS_SUCCESS or appropriate error value.
*
* @remarks None.
*
*--*/
VOID
NTAPI
ObDereferenceSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN ULONG Count)
{
DPRINT1("ObDereferenceSecurityDescriptor is not implemented!\n");
}
/* EOF */

View file

@ -343,4 +343,66 @@ ObpDereferenceCachedSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescripto
DPRINT("ObpDereferenceCachedSecurityDescriptor() done\n");
}
/*++
* @name ObLogSecurityDescriptor
* @unimplemented NT5.2
*
* The ObLogSecurityDescriptor routine <FILLMEIN>
*
* @param InputSecurityDescriptor
* <FILLMEIN>
*
* @param OutputSecurityDescriptor
* <FILLMEIN>
*
* @param RefBias
* <FILLMEIN>
*
* @return STATUS_SUCCESS or appropriate error value.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
ObLogSecurityDescriptor(IN PSECURITY_DESCRIPTOR InputSecurityDescriptor,
OUT PSECURITY_DESCRIPTOR *OutputSecurityDescriptor,
IN ULONG RefBias)
{
/* HACK: Return the same descriptor back */
PISECURITY_DESCRIPTOR SdCopy;
DPRINT1("ObLogSecurityDescriptor is not implemented!\n",
InputSecurityDescriptor);
SdCopy = ExAllocatePool(PagedPool, sizeof(*SdCopy));
RtlCopyMemory(SdCopy, InputSecurityDescriptor, sizeof(*SdCopy));
*OutputSecurityDescriptor = SdCopy;
return STATUS_SUCCESS;
}
/*++
* @name ObDereferenceSecurityDescriptor
* @unimplemented NT5.2
*
* The ObDereferenceSecurityDescriptor routine <FILLMEIN>
*
* @param SecurityDescriptor
* <FILLMEIN>
*
* @param Count
* <FILLMEIN>
*
* @return STATUS_SUCCESS or appropriate error value.
*
* @remarks None.
*
*--*/
VOID
NTAPI
ObDereferenceSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN ULONG Count)
{
DPRINT1("ObDereferenceSecurityDescriptor is not implemented!\n");
}
/* EOF */

View file

@ -376,24 +376,30 @@ SeDeleteObjectAuditAlarm(IN PVOID Object,
UNIMPLEMENTED;
}
/*
* @unimplemented
*/
VOID STDCALL
VOID
NTAPI
SeOpenObjectAuditAlarm(IN PUNICODE_STRING ObjectTypeName,
IN PVOID Object OPTIONAL,
IN PUNICODE_STRING AbsoluteObjectName OPTIONAL,
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN PACCESS_STATE AccessState,
IN BOOLEAN ObjectCreated,
IN BOOLEAN AccessGranted,
IN KPROCESSOR_MODE AccessMode,
OUT PBOOLEAN GenerateOnClose)
IN PVOID Object OPTIONAL,
IN PUNICODE_STRING AbsoluteObjectName OPTIONAL,
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN PACCESS_STATE AccessState,
IN BOOLEAN ObjectCreated,
IN BOOLEAN AccessGranted,
IN KPROCESSOR_MODE AccessMode,
OUT PBOOLEAN GenerateOnClose)
{
DPRINT1("SeOpenObjectAuditAlarm is UNIMPLEMENTED!\n");
}
PAGED_CODE();
/* Audits aren't done on kernel-mode access */
if (AccessMode == KernelMode) return;
/* Otherwise, unimplemented! */
//UNIMPLEMENTED;
return;
}
/*
* @unimplemented

View file

@ -203,7 +203,7 @@ NTSTATUS
STDCALL
SeDefaultObjectMethod(PVOID Object,
SECURITY_OPERATION_CODE OperationType,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_INFORMATION _SecurityInformation,
PSECURITY_DESCRIPTOR _SecurityDescriptor,
PULONG ReturnLength,
PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
@ -225,10 +225,12 @@ SeDefaultObjectMethod(PVOID Object,
ULONG Control = 0;
ULONG_PTR Current;
NTSTATUS Status;
SECURITY_INFORMATION SecurityInformation;
if (OperationType == SetSecurityDescriptor)
{
ObjectSd = Header->SecurityDescriptor;
SecurityInformation = *_SecurityInformation;
/* Get owner and owner size */
if (SecurityInformation & OWNER_SECURITY_INFORMATION)
@ -401,7 +403,7 @@ SeDefaultObjectMethod(PVOID Object,
}
else if (OperationType == QuerySecurityDescriptor)
{
Status = SeQuerySecurityDescriptorInfo(&SecurityInformation,
Status = SeQuerySecurityDescriptorInfo(_SecurityInformation,
SecurityDescriptor,
ReturnLength,
&Header->SecurityDescriptor);