[PATCH 3/6] server: Implement changing the label of a security descriptor.
Matteo Bruni
mbruni at codeweavers.com
Mon Jun 12 13:34:38 CDT 2017
From: Michael Müller <michael at fds-team.de>
Signed-off-by: Matteo Bruni <mbruni at codeweavers.com>
---
dlls/advapi32/tests/security.c | 153 ++++++++++++++++++++++++++++++++++++++++-
dlls/ntdll/sec.c | 3 +-
server/handle.c | 130 +++++++++++++++++++++++++++++++++-
3 files changed, 282 insertions(+), 4 deletions(-)
diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
index d701251c83..9f30a89546 100644
--- a/dlls/advapi32/tests/security.c
+++ b/dlls/advapi32/tests/security.c
@@ -6163,9 +6163,12 @@ static void test_AddMandatoryAce(void)
{
static SID low_level = {SID_REVISION, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY},
{SECURITY_MANDATORY_LOW_RID}};
+ static SID medium_level = {SID_REVISION, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY},
+ {SECURITY_MANDATORY_MEDIUM_RID}};
+ static SID_IDENTIFIER_AUTHORITY sia_world = {SECURITY_WORLD_SID_AUTHORITY};
char buffer_sd[SECURITY_DESCRIPTOR_MIN_LENGTH];
SECURITY_DESCRIPTOR *sd2, *sd = (SECURITY_DESCRIPTOR *)&buffer_sd;
- BOOL defaulted, present, ret, found;
+ BOOL defaulted, present, ret, found, found2;
ACL_SIZE_INFORMATION acl_size_info;
SYSTEM_MANDATORY_LABEL_ACE *ace;
char buffer_acl[256];
@@ -6173,6 +6176,7 @@ static void test_AddMandatoryAce(void)
SECURITY_ATTRIBUTES sa;
DWORD index, size;
HANDLE handle;
+ SID *everyone;
ACL *sacl;
if (!pAddMandatoryAce)
@@ -6268,6 +6272,153 @@ static void test_AddMandatoryAce(void)
ok(EqualSid(&ace->SidStart, &low_level), "Expected low integrity level\n");
HeapFree(GetProcessHeap(), 0, sd2);
+
+ ret = pAddMandatoryAce(acl, ACL_REVISION, 0, SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP, &medium_level);
+ ok(ret, "AddMandatoryAce failed with error %u\n", GetLastError());
+
+ ret = SetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd);
+ ok(ret, "SetKernelObjectSecurity failed with error %u\n", GetLastError());
+
+ ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
+ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+ "Unexpected GetKernelObjectSecurity return value %u, error %u\n", ret, GetLastError());
+
+ sd2 = HeapAlloc(GetProcessHeap(), 0, size);
+ ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd2, size, &size);
+ ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
+
+ sacl = (void *)0xdeadbeef;
+ present = FALSE;
+ defaulted = TRUE;
+ ret = GetSecurityDescriptorSacl(sd2, &present, &sacl, &defaulted);
+ ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
+ ok(present, "SACL not present\n");
+ ok(sacl != (void *)0xdeadbeef, "SACL not set\n");
+ ok(sacl->AceCount == 2, "Expected 2 ACEs, got %d\n", sacl->AceCount);
+ ok(!defaulted, "SACL defaulted\n");
+
+ index = 0;
+ found = found2 = FALSE;
+ while (pGetAce(sacl, index++, (void **)&ace))
+ {
+ if (ace->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE)
+ {
+ if (EqualSid(&ace->SidStart, &low_level))
+ {
+ found = TRUE;
+ ok(!ace->Header.AceFlags, "Expected 0 as flags, got %#x\n", ace->Header.AceFlags);
+ ok(ace->Mask == SYSTEM_MANDATORY_LABEL_NO_WRITE_UP,
+ "Expected SYSTEM_MANDATORY_LABEL_NO_WRITE_UP as mask, got %#x\n", ace->Mask);
+ }
+ if (EqualSid(&ace->SidStart, &medium_level))
+ {
+ found2 = TRUE;
+ ok(!ace->Header.AceFlags, "Expected 0 as flags, got %#x\n", ace->Header.AceFlags);
+ ok(ace->Mask == SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP,
+ "Expected SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP as mask, got %#x\n", ace->Mask);
+ }
+ }
+ }
+ ok(found, "Could not find low mandatory label\n");
+ ok(found2, "Could not find medium mandatory label\n");
+
+ HeapFree(GetProcessHeap(), 0, sd2);
+
+ ret = SetSecurityDescriptorSacl(sd, FALSE, NULL, FALSE);
+ ok(ret, "SetSecurityDescriptorSacl failed with error %u\n", GetLastError());
+
+ ret = SetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd);
+ ok(ret, "SetKernelObjectSecurity failed with error %u\n", GetLastError());
+
+ ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
+ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+ "Unexpected GetKernelObjectSecurity return value %d, error %u\n", ret, GetLastError());
+
+ sd2 = HeapAlloc(GetProcessHeap(), 0, size);
+ ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd2, size, &size);
+ ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
+
+ sacl = (void *)0xdeadbeef;
+ present = FALSE;
+ defaulted = TRUE;
+ ret = GetSecurityDescriptorSacl(sd2, &present, &sacl, &defaulted);
+ ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
+ ok(present, "SACL not present\n");
+ ok(sacl != (void *)0xdeadbeef, "SACL not set\n");
+ ok(!sacl->AceCount, "SACL contains an unexpected ACE count %u\n", sacl->AceCount);
+ ok(!defaulted, "SACL defaulted\n");
+
+ HeapFree(GetProcessHeap(), 0, sd2);
+
+ ret = InitializeAcl(acl, 256, ACL_REVISION);
+ ok(ret, "InitializeAcl failed with error %u\n", GetLastError());
+
+ ret = pAddMandatoryAce(acl, ACL_REVISION3, 0, SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP, &medium_level);
+ ok(ret, "AddMandatoryAce failed with error %u\n", GetLastError());
+
+ ret = SetSecurityDescriptorSacl(sd, TRUE, acl, FALSE);
+ ok(ret, "SetSecurityDescriptorSacl failed with error %u\n", GetLastError());
+
+ ret = SetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd);
+ ok(ret, "SetKernelObjectSecurity failed with error %u\n", GetLastError());
+
+ ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
+ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+ "Unexpected GetKernelObjectSecurity return value %d, error %u\n", ret, GetLastError());
+
+ sd2 = HeapAlloc(GetProcessHeap(), 0, size);
+ ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd2, size, &size);
+ ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
+
+ sacl = (void *)0xdeadbeef;
+ present = FALSE;
+ defaulted = TRUE;
+ ret = GetSecurityDescriptorSacl(sd2, &present, &sacl, &defaulted);
+ ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
+ ok(present, "SACL not present\n");
+ ok(sacl != (void *)0xdeadbeef, "SACL not set\n");
+ ok(sacl->AclRevision == ACL_REVISION3, "Expected revision 3, got %d\n", sacl->AclRevision);
+ ok(!defaulted, "SACL defaulted\n");
+
+ HeapFree(GetProcessHeap(), 0, sd2);
+
+ ret = InitializeAcl(acl, 256, ACL_REVISION);
+ ok(ret, "InitializeAcl failed with error %u\n", GetLastError());
+
+ ret = AllocateAndInitializeSid(&sia_world, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, (void **)&everyone);
+ ok(ret, "AllocateAndInitializeSid failed with error %u\n", GetLastError());
+
+ ret = AddAccessAllowedAce(acl, ACL_REVISION, KEY_READ, everyone);
+ ok(ret, "AddAccessAllowedAce failed with error %u\n", GetLastError());
+
+ ret = SetSecurityDescriptorSacl(sd, TRUE, acl, FALSE);
+ ok(ret, "SetSecurityDescriptorSacl failed with error %u\n", GetLastError());
+
+ ret = SetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd);
+ ok(ret, "SetKernelObjectSecurity failed with error %u\n", GetLastError());
+
+ ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
+ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+ "Unexpected GetKernelObjectSecurity return value %d, error %u\n", ret, GetLastError());
+
+ sd2 = HeapAlloc(GetProcessHeap(), 0, size);
+ ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd2, size, &size);
+ ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
+
+ sacl = (void *)0xdeadbeef;
+ present = FALSE;
+ defaulted = TRUE;
+ ret = GetSecurityDescriptorSacl(sd2, &present, &sacl, &defaulted);
+ ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
+ ok(present, "SACL not present\n");
+ ok(sacl != (void *)0xdeadbeef, "SACL not set\n");
+ ok(!defaulted, "SACL defaulted\n");
+ ret = pGetAclInformation(sacl, &acl_size_info, sizeof(acl_size_info), AclSizeInformation);
+ ok(ret, "GetAclInformation failed with error %u\n", GetLastError());
+ ok(!acl_size_info.AceCount, "SACL contains an unexpected ACE count %u\n", acl_size_info.AceCount);
+
+ FreeSid(everyone);
+ HeapFree(GetProcessHeap(), 0, sd2);
CloseHandle(handle);
}
diff --git a/dlls/ntdll/sec.c b/dlls/ntdll/sec.c
index 3f7aa79323..5c858b5bcb 100644
--- a/dlls/ntdll/sec.c
+++ b/dlls/ntdll/sec.c
@@ -1775,7 +1775,8 @@ NTSTATUS WINAPI NtSetSecurityObject(HANDLE Handle,
return STATUS_INVALID_SECURITY_DESCR;
}
- if (SecurityInformation & SACL_SECURITY_INFORMATION)
+ if (SecurityInformation & SACL_SECURITY_INFORMATION ||
+ SecurityInformation & LABEL_SECURITY_INFORMATION)
{
status = RtlGetSaclSecurityDescriptor( SecurityDescriptor, &present, &sacl, &defaulted );
if (status != STATUS_SUCCESS) return status;
diff --git a/server/handle.c b/server/handle.c
index 237310d508..065e5b188a 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -673,10 +673,86 @@ DECL_HANDLER(get_object_info)
release_object( obj );
}
+/* replace security labels in an existing SACL */
+static int replace_security_labels( ACL **out, const ACL *old_sacl, const ACL *new_sacl )
+{
+ const ACE_HEADER *ace;
+ ACE_HEADER *replaced_ace;
+ size_t size = sizeof(ACL);
+ unsigned int i, count = 0;
+ BYTE revision = ACL_REVISION;
+ ACL *replaced_acl;
+
+ *out = NULL;
+ if (!old_sacl && !new_sacl) return 1;
+
+ if (old_sacl)
+ {
+ revision = max( revision, old_sacl->AclRevision );
+ ace = (const ACE_HEADER *)(old_sacl + 1);
+ for (i = 0; i < old_sacl->AceCount; i++, ace = ace_next( ace ))
+ {
+ if (ace->AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE) continue;
+ size += ace->AceSize;
+ count++;
+ }
+ }
+
+ if (new_sacl)
+ {
+ revision = max( revision, new_sacl->AclRevision );
+ ace = (const ACE_HEADER *)(new_sacl + 1);
+ for (i = 0; i < new_sacl->AceCount; i++, ace = ace_next( ace ))
+ {
+ if (ace->AceType != SYSTEM_MANDATORY_LABEL_ACE_TYPE) continue;
+ size += ace->AceSize;
+ count++;
+ }
+ }
+
+ replaced_acl = mem_alloc( size );
+ if (!replaced_acl) return 0;
+
+ replaced_acl->AclRevision = revision;
+ replaced_acl->Sbz1 = 0;
+ replaced_acl->AclSize = size;
+ replaced_acl->AceCount = count;
+ replaced_acl->Sbz2 = 0;
+ replaced_ace = (ACE_HEADER *)(replaced_acl + 1);
+
+ if (old_sacl)
+ {
+ ace = (const ACE_HEADER *)(old_sacl + 1);
+ for (i = 0; i < old_sacl->AceCount; i++, ace = ace_next( ace ))
+ {
+ if (ace->AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE) continue;
+ memcpy( replaced_ace, ace, ace->AceSize );
+ replaced_ace = (ACE_HEADER *)ace_next( replaced_ace );
+ }
+ }
+
+ if (new_sacl)
+ {
+ ace = (const ACE_HEADER *)(new_sacl + 1);
+ for (i = 0; i < new_sacl->AceCount; i++, ace = ace_next( ace ))
+ {
+ if (ace->AceType != SYSTEM_MANDATORY_LABEL_ACE_TYPE) continue;
+ memcpy( replaced_ace, ace, ace->AceSize );
+ replaced_ace = (ACE_HEADER *)ace_next( replaced_ace );
+ }
+ }
+
+ *out = replaced_acl;
+ return 1;
+}
+
DECL_HANDLER(set_security_object)
{
data_size_t sd_size = get_req_data_size();
const struct security_descriptor *sd = get_req_data();
+ unsigned int security_info = req->security_info;
+ struct security_descriptor *replaced_sd = NULL;
+ ACL *replaced_sacl = NULL;
struct object *obj;
unsigned int access = 0;
@@ -687,7 +763,8 @@ DECL_HANDLER(set_security_object)
}
if (req->security_info & OWNER_SECURITY_INFORMATION ||
- req->security_info & GROUP_SECURITY_INFORMATION)
+ req->security_info & GROUP_SECURITY_INFORMATION ||
+ req->security_info & LABEL_SECURITY_INFORMATION)
access |= WRITE_OWNER;
if (req->security_info & SACL_SECURITY_INFORMATION)
access |= ACCESS_SYSTEM_SECURITY;
@@ -696,8 +773,57 @@ DECL_HANDLER(set_security_object)
if (!(obj = get_handle_obj( current->process, req->handle, access, NULL ))) return;
- obj->ops->set_sd( obj, sd, req->security_info );
+ /* check if we need to replace the security labels in the existing SACL */
+ if ((security_info & LABEL_SECURITY_INFORMATION) &&
+ !(security_info & SACL_SECURITY_INFORMATION) &&
+ (sd->control & SE_SACL_PRESENT))
+ {
+ const struct security_descriptor *old_sd;
+ const ACL *old_sacl = NULL;
+ int present;
+ char *ptr;
+
+ if ((old_sd = obj->ops->get_sd( obj )))
+ {
+ old_sacl = sd_get_sacl( old_sd, &present );
+ if (!present) old_sacl = NULL;
+ }
+
+ if (!replace_security_labels( &replaced_sacl, old_sacl, sd_get_sacl( sd, &present ) )) goto error;
+
+ /* allocate a new SD and replace the SACL with the updated version */
+ replaced_sd = mem_alloc( sizeof(*replaced_sd) + sd->owner_len + sd->group_len +
+ (replaced_sacl ? replaced_sacl->AclSize : 0) + sd->dacl_len );
+ if (!replaced_sd) goto error;
+
+ replaced_sd->control = sd->control;
+ replaced_sd->owner_len = sd->owner_len;
+ replaced_sd->group_len = sd->group_len;
+ replaced_sd->sacl_len = replaced_sacl ? replaced_sacl->AclSize : 0;
+ replaced_sd->dacl_len = sd->dacl_len;
+
+ ptr = (char *)(replaced_sd + 1);
+ memcpy( ptr, sd_get_owner( sd ), sd->owner_len );
+ ptr += sd->owner_len;
+ memcpy( ptr, sd_get_group( sd ), sd->group_len );
+ ptr += sd->group_len;
+ if (replaced_sacl)
+ {
+ memcpy( ptr, replaced_sacl, replaced_sacl->AclSize );
+ ptr += replaced_sacl->AclSize;
+ }
+ memcpy( ptr, sd_get_dacl( sd, &present ), sd->dacl_len );
+
+ security_info |= SACL_SECURITY_INFORMATION;
+ sd = replaced_sd;
+ }
+
+ obj->ops->set_sd( obj, sd, security_info );
+
+error:
release_object( obj );
+ free( replaced_sacl );
+ free( replaced_sd );
}
/* extract security labels from SACL */
--
2.13.0
More information about the wine-patches
mailing list