The default object security method should not directly call Se* routines on the Security Descriptors, since they belong to the object manger security descriptor cache, and they need to be referenced and dereferenced in order to make sure they don't disappear from beneath the caller.

Additionally, the code for the "Set" operation should actually go in SeSetSecurityDescriptorInfo API, which was unimplemented. By simply copying the code over, this API is now implemented, and the routine works as expected.
Also, the default method was not handling "delete" requests, but was ignoring them, resulting in memory leaks and never-dereferenced descriptors.
Thanks to Alex for finding these bugs. Alex also says SeSetSecurityDescriptorInfo should call the Rtl package (RtlSetObjectSecurity) but we don't implement those functions yet.

svn path=/trunk/; revision=32799
This commit is contained in:
Aleksey Bragin 2008-03-31 20:07:02 +00:00
parent f5b2746f9a
commit 89484a110d
4 changed files with 419 additions and 223 deletions

View file

@ -374,12 +374,6 @@ ObpAddSecurityDescriptor(
OUT PSECURITY_DESCRIPTOR *DestinationSD
);
NTSTATUS
NTAPI
ObpRemoveSecurityDescriptor(
IN PSECURITY_DESCRIPTOR SecurityDescriptor
);
PSECURITY_DESCRIPTOR
NTAPI
ObpReferenceCachedSecurityDescriptor(
@ -438,6 +432,44 @@ ObpCheckObjectReference(
OUT PNTSTATUS AccessStatus
);
//
// Default Object Security Callback Routines
//
NTSTATUS
NTAPI
ObAssignObjectSecurityDescriptor(
IN PVOID Object,
IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
IN POOL_TYPE PoolType
);
NTSTATUS
NTAPI
ObDeassignSecurity(
IN OUT PSECURITY_DESCRIPTOR *SecurityDescriptor
);
NTSTATUS
NTAPI
ObQuerySecurityDescriptorInfo(
IN PVOID Object,
IN PSECURITY_INFORMATION SecurityInformation,
OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
IN OUT PULONG Length,
IN PSECURITY_DESCRIPTOR *OutputSecurityDescriptor
);
NTSTATUS
NTAPI
ObSetSecurityDescriptorInfo(
IN PVOID Object,
IN PSECURITY_INFORMATION SecurityInformation,
IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
IN OUT PSECURITY_DESCRIPTOR *OutputSecurityDescriptor,
IN POOL_TYPE PoolType,
IN PGENERIC_MAPPING GenericMapping
);
//
// Executive Fast Referencing Functions
//

View file

@ -15,6 +15,157 @@
/* PRIVATE FUNCTIONS *********************************************************/
NTSTATUS
NTAPI
ObAssignObjectSecurityDescriptor(IN PVOID Object,
IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
IN POOL_TYPE PoolType)
{
POBJECT_HEADER ObjectHeader;
NTSTATUS Status;
PSECURITY_DESCRIPTOR NewSd;
PAGED_CODE();
/* Get the object header */
ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
if (!SecurityDescriptor)
{
/* Nothing to assign */
ObjectHeader->SecurityDescriptor = NULL;
return STATUS_SUCCESS;
}
/* Add it to our internal cache */
Status = ObpAddSecurityDescriptor(SecurityDescriptor, &NewSd);
if (NT_SUCCESS(Status))
{
/* Free the old copy */
ExFreePool(SecurityDescriptor);
/* Set the new pointer */
ASSERT(NewSd);
ObjectHeader->SecurityDescriptor = NewSd;
}
/* Return status */
return Status;
}
NTSTATUS
NTAPI
ObDeassignSecurity(IN OUT PSECURITY_DESCRIPTOR *SecurityDescriptor)
{
/* Dereference it */
ObpDereferenceCachedSecurityDescriptor(*SecurityDescriptor);
/* Don't free again later */
*SecurityDescriptor = NULL;
/* All done */
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
ObQuerySecurityDescriptorInfo(IN PVOID Object,
IN PSECURITY_INFORMATION SecurityInformation,
OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
IN OUT PULONG Length,
IN PSECURITY_DESCRIPTOR *OutputSecurityDescriptor)
{
POBJECT_HEADER ObjectHeader;
NTSTATUS Status;
PSECURITY_DESCRIPTOR ObjectSd;
PAGED_CODE();
/* Get the object header */
ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
/* Get the SD */
ObjectSd = ObpReferenceCachedSecurityDescriptor(ObjectHeader->SecurityDescriptor);
/* Query the information */
Status = SeQuerySecurityDescriptorInfo(SecurityInformation,
SecurityDescriptor,
Length,
&ObjectSd);
/* Check if we have an object SD and dereference it, if so */
if (ObjectSd) ObpDereferenceCachedSecurityDescriptor(ObjectSd);
/* Return status */
return Status;
}
NTSTATUS
NTAPI
ObSetSecurityDescriptorInfo(IN PVOID Object,
IN PSECURITY_INFORMATION SecurityInformation,
IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
IN OUT PSECURITY_DESCRIPTOR *OutputSecurityDescriptor,
IN POOL_TYPE PoolType,
IN PGENERIC_MAPPING GenericMapping)
{
NTSTATUS Status;
POBJECT_HEADER ObjectHeader;
PSECURITY_DESCRIPTOR OldDescriptor, NewDescriptor, CachedDescriptor;
PAGED_CODE();
/* Get the object header */
ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
while (TRUE)
{
/* Reference the old descriptor */
OldDescriptor = ObpReferenceCachedSecurityDescriptor(ObjectHeader->SecurityDescriptor);
NewDescriptor = OldDescriptor;
/* Set the SD information */
Status = SeSetSecurityDescriptorInfo(Object,
SecurityInformation,
SecurityDescriptor,
&NewDescriptor,
PoolType,
GenericMapping);
if (NT_SUCCESS(Status))
{
/* Now add this to the cache */
Status = ObpAddSecurityDescriptor(NewDescriptor, &CachedDescriptor);
/* Let go of our uncached copy */
ExFreePool(NewDescriptor);
/* Check for success */
if (NT_SUCCESS(Status))
{
/* Dereference the old one */
ASSERT(OldDescriptor == ObjectHeader->SecurityDescriptor);
/* Now set this as the new descriptor */
ObjectHeader->SecurityDescriptor = CachedDescriptor;
/* And dereference the old one */
ObpDereferenceCachedSecurityDescriptor(OldDescriptor);
break;
}
else
{
/* We failed, dereference the old one */
ObpDereferenceCachedSecurityDescriptor(OldDescriptor);
break;
}
}
else
{
/* We failed, dereference the old one */
if (OldDescriptor) ObpDereferenceCachedSecurityDescriptor(OldDescriptor);
break;
}
}
/* Return status */
return Status;
}
BOOLEAN
NTAPI
ObCheckCreateObjectAccess(IN PVOID Object,

View file

@ -882,18 +882,190 @@ SeReleaseSecurityDescriptor(
}
/*
* @unimplemented
* @implemented
*/
NTSTATUS STDCALL
SeSetSecurityDescriptorInfo(IN PVOID Object OPTIONAL,
IN PSECURITY_INFORMATION SecurityInformation,
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
IN POOL_TYPE PoolType,
IN PGENERIC_MAPPING GenericMapping)
IN PSECURITY_INFORMATION _SecurityInformation,
IN PSECURITY_DESCRIPTOR _SecurityDescriptor,
IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
IN POOL_TYPE PoolType,
IN PGENERIC_MAPPING GenericMapping)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
PISECURITY_DESCRIPTOR ObjectSd;
PISECURITY_DESCRIPTOR NewSd;
PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor;
PSID Owner = 0;
PSID Group = 0;
PACL Dacl = 0;
PACL Sacl = 0;
ULONG OwnerLength = 0;
ULONG GroupLength = 0;
ULONG DaclLength = 0;
ULONG SaclLength = 0;
ULONG Control = 0;
ULONG_PTR Current;
SECURITY_INFORMATION SecurityInformation;
ObjectSd = *ObjectsSecurityDescriptor;
SecurityInformation = *_SecurityInformation;
/* Get owner and owner size */
if (SecurityInformation & OWNER_SECURITY_INFORMATION)
{
if (SecurityDescriptor->Owner != NULL)
{
if( SecurityDescriptor->Control & SE_SELF_RELATIVE )
Owner = (PSID)((ULONG_PTR)SecurityDescriptor->Owner +
(ULONG_PTR)SecurityDescriptor);
else
Owner = (PSID)SecurityDescriptor->Owner;
OwnerLength = ROUND_UP(RtlLengthSid(Owner), 4);
}
Control |= (SecurityDescriptor->Control & SE_OWNER_DEFAULTED);
}
else
{
if (ObjectSd->Owner != NULL)
{
Owner = (PSID)((ULONG_PTR)ObjectSd->Owner + (ULONG_PTR)ObjectSd);
OwnerLength = ROUND_UP(RtlLengthSid(Owner), 4);
}
Control |= (ObjectSd->Control & SE_OWNER_DEFAULTED);
}
/* Get group and group size */
if (SecurityInformation & GROUP_SECURITY_INFORMATION)
{
if (SecurityDescriptor->Group != NULL)
{
if( SecurityDescriptor->Control & SE_SELF_RELATIVE )
Group = (PSID)((ULONG_PTR)SecurityDescriptor->Group +
(ULONG_PTR)SecurityDescriptor);
else
Group = (PSID)SecurityDescriptor->Group;
GroupLength = ROUND_UP(RtlLengthSid(Group), 4);
}
Control |= (SecurityDescriptor->Control & SE_GROUP_DEFAULTED);
}
else
{
if (ObjectSd->Group != NULL)
{
Group = (PSID)((ULONG_PTR)ObjectSd->Group + (ULONG_PTR)ObjectSd);
GroupLength = ROUND_UP(RtlLengthSid(Group), 4);
}
Control |= (ObjectSd->Control & SE_GROUP_DEFAULTED);
}
/* Get DACL and DACL size */
if (SecurityInformation & DACL_SECURITY_INFORMATION)
{
if ((SecurityDescriptor->Control & SE_DACL_PRESENT) &&
(SecurityDescriptor->Dacl != NULL))
{
if( SecurityDescriptor->Control & SE_SELF_RELATIVE )
Dacl = (PACL)((ULONG_PTR)SecurityDescriptor->Dacl +
(ULONG_PTR)SecurityDescriptor);
else
Dacl = (PACL)SecurityDescriptor->Dacl;
DaclLength = ROUND_UP((ULONG)Dacl->AclSize, 4);
}
Control |= (SecurityDescriptor->Control & (SE_DACL_DEFAULTED | SE_DACL_PRESENT));
}
else
{
if ((ObjectSd->Control & SE_DACL_PRESENT) &&
(ObjectSd->Dacl != NULL))
{
Dacl = (PACL)((ULONG_PTR)ObjectSd->Dacl + (ULONG_PTR)ObjectSd);
DaclLength = ROUND_UP((ULONG)Dacl->AclSize, 4);
}
Control |= (ObjectSd->Control & (SE_DACL_DEFAULTED | SE_DACL_PRESENT));
}
/* Get SACL and SACL size */
if (SecurityInformation & SACL_SECURITY_INFORMATION)
{
if ((SecurityDescriptor->Control & SE_SACL_PRESENT) &&
(SecurityDescriptor->Sacl != NULL))
{
if( SecurityDescriptor->Control & SE_SELF_RELATIVE )
Sacl = (PACL)((ULONG_PTR)SecurityDescriptor->Sacl +
(ULONG_PTR)SecurityDescriptor);
else
Sacl = (PACL)SecurityDescriptor->Sacl;
SaclLength = ROUND_UP((ULONG)Sacl->AclSize, 4);
}
Control |= (SecurityDescriptor->Control & (SE_SACL_DEFAULTED | SE_SACL_PRESENT));
}
else
{
if ((ObjectSd->Control & SE_SACL_PRESENT) &&
(ObjectSd->Sacl != NULL))
{
Sacl = (PACL)((ULONG_PTR)ObjectSd->Sacl + (ULONG_PTR)ObjectSd);
SaclLength = ROUND_UP((ULONG)Sacl->AclSize, 4);
}
Control |= (ObjectSd->Control & (SE_SACL_DEFAULTED | SE_SACL_PRESENT));
}
NewSd = ExAllocatePool(NonPagedPool,
sizeof(SECURITY_DESCRIPTOR) + OwnerLength + GroupLength +
DaclLength + SaclLength);
if (NewSd == NULL)
{
ObDereferenceObject(Object);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCreateSecurityDescriptor(NewSd,
SECURITY_DESCRIPTOR_REVISION1);
/* We always build a self-relative descriptor */
NewSd->Control = (USHORT)Control | SE_SELF_RELATIVE;
Current = (ULONG_PTR)NewSd + sizeof(SECURITY_DESCRIPTOR);
if (OwnerLength != 0)
{
RtlCopyMemory((PVOID)Current,
Owner,
OwnerLength);
NewSd->Owner = (PSID)(Current - (ULONG_PTR)NewSd);
Current += OwnerLength;
}
if (GroupLength != 0)
{
RtlCopyMemory((PVOID)Current,
Group,
GroupLength);
NewSd->Group = (PSID)(Current - (ULONG_PTR)NewSd);
Current += GroupLength;
}
if (DaclLength != 0)
{
RtlCopyMemory((PVOID)Current,
Dacl,
DaclLength);
NewSd->Dacl = (PACL)(Current - (ULONG_PTR)NewSd);
Current += DaclLength;
}
if (SaclLength != 0)
{
RtlCopyMemory((PVOID)Current,
Sacl,
SaclLength);
NewSd->Sacl = (PACL)(Current - (ULONG_PTR)NewSd);
Current += SaclLength;
}
*ObjectsSecurityDescriptor = NewSd;
return STATUS_SUCCESS;
}
/*

View file

@ -233,222 +233,63 @@ VOID SepDeReferenceLogonSession(PLUID AuthenticationId)
}
NTSTATUS
STDCALL
SeDefaultObjectMethod(PVOID Object,
SECURITY_OPERATION_CODE OperationType,
PSECURITY_INFORMATION _SecurityInformation,
PSECURITY_DESCRIPTOR _SecurityDescriptor,
PULONG ReturnLength,
PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
POOL_TYPE PoolType,
PGENERIC_MAPPING GenericMapping)
NTAPI
SeDefaultObjectMethod(IN PVOID Object,
IN SECURITY_OPERATION_CODE OperationType,
IN PSECURITY_INFORMATION SecurityInformation,
IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
IN OUT PULONG ReturnLength OPTIONAL,
IN OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
IN POOL_TYPE PoolType,
IN PGENERIC_MAPPING GenericMapping)
{
PISECURITY_DESCRIPTOR ObjectSd;
PISECURITY_DESCRIPTOR NewSd;
PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor;
POBJECT_HEADER Header = OBJECT_TO_OBJECT_HEADER(Object);
PSID Owner = 0;
PSID Group = 0;
PACL Dacl = 0;
PACL Sacl = 0;
ULONG OwnerLength = 0;
ULONG GroupLength = 0;
ULONG DaclLength = 0;
ULONG SaclLength = 0;
ULONG Control = 0;
ULONG_PTR Current;
NTSTATUS Status;
SECURITY_INFORMATION SecurityInformation;
PAGED_CODE();
if (OperationType == SetSecurityDescriptor)
{
ObjectSd = Header->SecurityDescriptor;
SecurityInformation = *_SecurityInformation;
/* Select the operation type */
switch (OperationType)
{
/* Setting a new descriptor */
case SetSecurityDescriptor:
/* Get owner and owner size */
if (SecurityInformation & OWNER_SECURITY_INFORMATION)
{
if (SecurityDescriptor->Owner != NULL)
{
if( SecurityDescriptor->Control & SE_SELF_RELATIVE )
Owner = (PSID)((ULONG_PTR)SecurityDescriptor->Owner +
(ULONG_PTR)SecurityDescriptor);
else
Owner = (PSID)SecurityDescriptor->Owner;
OwnerLength = ROUND_UP(RtlLengthSid(Owner), 4);
}
Control |= (SecurityDescriptor->Control & SE_OWNER_DEFAULTED);
}
else
{
if (ObjectSd->Owner != NULL)
{
Owner = (PSID)((ULONG_PTR)ObjectSd->Owner + (ULONG_PTR)ObjectSd);
OwnerLength = ROUND_UP(RtlLengthSid(Owner), 4);
}
Control |= (ObjectSd->Control & SE_OWNER_DEFAULTED);
}
/* Sanity check */
ASSERT((PoolType == PagedPool) || (PoolType == NonPagedPool));
/* Get group and group size */
if (SecurityInformation & GROUP_SECURITY_INFORMATION)
{
if (SecurityDescriptor->Group != NULL)
{
if( SecurityDescriptor->Control & SE_SELF_RELATIVE )
Group = (PSID)((ULONG_PTR)SecurityDescriptor->Group +
(ULONG_PTR)SecurityDescriptor);
else
Group = (PSID)SecurityDescriptor->Group;
GroupLength = ROUND_UP(RtlLengthSid(Group), 4);
}
Control |= (SecurityDescriptor->Control & SE_GROUP_DEFAULTED);
}
else
{
if (ObjectSd->Group != NULL)
{
Group = (PSID)((ULONG_PTR)ObjectSd->Group + (ULONG_PTR)ObjectSd);
GroupLength = ROUND_UP(RtlLengthSid(Group), 4);
}
Control |= (ObjectSd->Control & SE_GROUP_DEFAULTED);
}
/* Get DACL and DACL size */
if (SecurityInformation & DACL_SECURITY_INFORMATION)
{
if ((SecurityDescriptor->Control & SE_DACL_PRESENT) &&
(SecurityDescriptor->Dacl != NULL))
{
if( SecurityDescriptor->Control & SE_SELF_RELATIVE )
Dacl = (PACL)((ULONG_PTR)SecurityDescriptor->Dacl +
(ULONG_PTR)SecurityDescriptor);
else
Dacl = (PACL)SecurityDescriptor->Dacl;
DaclLength = ROUND_UP((ULONG)Dacl->AclSize, 4);
}
Control |= (SecurityDescriptor->Control & (SE_DACL_DEFAULTED | SE_DACL_PRESENT));
}
else
{
if ((ObjectSd->Control & SE_DACL_PRESENT) &&
(ObjectSd->Dacl != NULL))
{
Dacl = (PACL)((ULONG_PTR)ObjectSd->Dacl + (ULONG_PTR)ObjectSd);
DaclLength = ROUND_UP((ULONG)Dacl->AclSize, 4);
}
Control |= (ObjectSd->Control & (SE_DACL_DEFAULTED | SE_DACL_PRESENT));
}
/* Get SACL and SACL size */
if (SecurityInformation & SACL_SECURITY_INFORMATION)
{
if ((SecurityDescriptor->Control & SE_SACL_PRESENT) &&
(SecurityDescriptor->Sacl != NULL))
{
if( SecurityDescriptor->Control & SE_SELF_RELATIVE )
Sacl = (PACL)((ULONG_PTR)SecurityDescriptor->Sacl +
(ULONG_PTR)SecurityDescriptor);
else
Sacl = (PACL)SecurityDescriptor->Sacl;
SaclLength = ROUND_UP((ULONG)Sacl->AclSize, 4);
}
Control |= (SecurityDescriptor->Control & (SE_SACL_DEFAULTED | SE_SACL_PRESENT));
}
else
{
if ((ObjectSd->Control & SE_SACL_PRESENT) &&
(ObjectSd->Sacl != NULL))
{
Sacl = (PACL)((ULONG_PTR)ObjectSd->Sacl + (ULONG_PTR)ObjectSd);
SaclLength = ROUND_UP((ULONG)Sacl->AclSize, 4);
}
Control |= (ObjectSd->Control & (SE_SACL_DEFAULTED | SE_SACL_PRESENT));
}
NewSd = ExAllocatePool(NonPagedPool,
sizeof(SECURITY_DESCRIPTOR) + OwnerLength + GroupLength +
DaclLength + SaclLength);
if (NewSd == NULL)
{
ObDereferenceObject(Object);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCreateSecurityDescriptor(NewSd,
SECURITY_DESCRIPTOR_REVISION1);
/* We always build a self-relative descriptor */
NewSd->Control = (USHORT)Control | SE_SELF_RELATIVE;
Current = (ULONG_PTR)NewSd + sizeof(SECURITY_DESCRIPTOR);
if (OwnerLength != 0)
{
RtlCopyMemory((PVOID)Current,
Owner,
OwnerLength);
NewSd->Owner = (PSID)(Current - (ULONG_PTR)NewSd);
Current += OwnerLength;
}
if (GroupLength != 0)
{
RtlCopyMemory((PVOID)Current,
Group,
GroupLength);
NewSd->Group = (PSID)(Current - (ULONG_PTR)NewSd);
Current += GroupLength;
}
if (DaclLength != 0)
{
RtlCopyMemory((PVOID)Current,
Dacl,
DaclLength);
NewSd->Dacl = (PACL)(Current - (ULONG_PTR)NewSd);
Current += DaclLength;
}
if (SaclLength != 0)
{
RtlCopyMemory((PVOID)Current,
Sacl,
SaclLength);
NewSd->Sacl = (PACL)(Current - (ULONG_PTR)NewSd);
Current += SaclLength;
}
/* Add the new SD */
Status = ObpAddSecurityDescriptor(NewSd,
&Header->SecurityDescriptor);
if (NT_SUCCESS(Status))
{
/* Remove the old security descriptor */
ObpRemoveSecurityDescriptor(ObjectSd);
}
else
{
/* Restore the old security descriptor */
Header->SecurityDescriptor = ObjectSd;
}
ExFreePool(NewSd);
}
else if (OperationType == QuerySecurityDescriptor)
{
Status = SeQuerySecurityDescriptorInfo(_SecurityInformation,
/* Set the information */
return ObSetSecurityDescriptorInfo(Object,
SecurityInformation,
SecurityDescriptor,
ReturnLength,
&Header->SecurityDescriptor);
}
else if (OperationType == AssignSecurityDescriptor)
{
/* Assign the security descriptor to the object header */
Status = ObpAddSecurityDescriptor(SecurityDescriptor,
&Header->SecurityDescriptor);
OldSecurityDescriptor,
PoolType,
GenericMapping);
case QuerySecurityDescriptor:
/* Query the information */
return ObQuerySecurityDescriptorInfo(Object,
SecurityInformation,
SecurityDescriptor,
ReturnLength,
OldSecurityDescriptor);
case DeleteSecurityDescriptor:
/* De-assign it */
return ObDeassignSecurity(OldSecurityDescriptor);
case AssignSecurityDescriptor:
/* Assign it */
ObAssignObjectSecurityDescriptor(Object, SecurityDescriptor, PoolType);
return STATUS_SUCCESS;
default:
/* Bug check */
KeBugCheckEx(SECURITY_SYSTEM, 0, STATUS_INVALID_PARAMETER, 0, 0);
}
/* Should never reach here */
ASSERT(FALSE);
return STATUS_SUCCESS;
}