diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c index d701251c837..dfc0a23452e 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) @@ -6267,6 +6271,151 @@ static void test_AddMandatoryAce(void) ok(ace->Mask == SYSTEM_MANDATORY_LABEL_NO_WRITE_UP, "Unexpected ACE mask %#x\n", ace->Mask); 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 && sacl != (void *)0xdeadbeef, "SACL not set\n"); + ok(!defaulted, "SACL defaulted\n"); + ok(!sacl->AceCount, "SACL contains an unexpected ACE count %u\n", sacl->AceCount); + + 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 && sacl != (void *)0xdeadbeef, "SACL not set\n"); + ok(!defaulted, "SACL defaulted\n"); + ok(!sacl->AceCount, "SACL contains an unexpected ACE count %u\n", sacl->AceCount); + + FreeSid(everyone); HeapFree(GetProcessHeap(), 0, sd2); CloseHandle(handle); } diff --git a/dlls/ntdll/sec.c b/dlls/ntdll/sec.c index 3f7aa793236..5c858b5bcbb 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 7d4512b183e..faa3a9f1367 100644 --- a/server/handle.c +++ b/server/handle.c @@ -687,7 +687,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; diff --git a/server/object.c b/server/object.c index e43fe3f2173..70872e8011c 100644 --- a/server/object.c +++ b/server/object.c @@ -542,6 +542,7 @@ int set_sd_defaults_from_token( struct object *obj, const struct security_descri int present; const SID *owner = NULL, *group = NULL; const ACL *sacl, *dacl; + ACL *replaced_sacl = NULL; char *ptr; if (!set_info) return 1; @@ -586,6 +587,14 @@ int set_sd_defaults_from_token( struct object *obj, const struct security_descri sacl = sd_get_sacl( sd, &present ); if (set_info & SACL_SECURITY_INFORMATION && present) new_sd.sacl_len = sd->sacl_len; + else if (set_info & LABEL_SECURITY_INFORMATION && present) + { + const ACL *old_sacl = NULL; + if (obj->sd && obj->sd->control & SE_SACL_PRESENT) old_sacl = sd_get_sacl( obj->sd, &present ); + if (!(replaced_sacl = replace_security_labels( old_sacl, sacl ))) return 0; + new_sd.sacl_len = replaced_sacl->AclSize; + sacl = replaced_sacl; + } else { if (obj->sd) sacl = sd_get_sacl( obj->sd, &present ); @@ -616,7 +625,11 @@ int set_sd_defaults_from_token( struct object *obj, const struct security_descri ptr = mem_alloc( sizeof(new_sd) + new_sd.owner_len + new_sd.group_len + new_sd.sacl_len + new_sd.dacl_len ); - if (!ptr) return 0; + if (!ptr) + { + free( replaced_sacl ); + return 0; + } new_sd_ptr = (struct security_descriptor*)ptr; memcpy( ptr, &new_sd, sizeof(new_sd) ); @@ -629,6 +642,7 @@ int set_sd_defaults_from_token( struct object *obj, const struct security_descri ptr += new_sd.sacl_len; memcpy( ptr, dacl, new_sd.dacl_len ); + free( replaced_sacl ); free( obj->sd ); obj->sd = new_sd_ptr; return 1; diff --git a/server/security.h b/server/security.h index 0c6f1815854..5c768218032 100644 --- a/server/security.h +++ b/server/security.h @@ -97,6 +97,7 @@ static inline int thread_single_check_privilege( struct thread *thread, const LU extern int sd_is_valid( const struct security_descriptor *sd, data_size_t size ); extern ACL *extract_security_labels( const ACL *sacl ); +extern ACL *replace_security_labels( const ACL *old_sacl, const ACL *new_sacl ); /* gets the discretionary access control list from a security descriptor */ static inline const ACL *sd_get_dacl( const struct security_descriptor *sd, int *present ) diff --git a/server/token.c b/server/token.c index 56529f2ff44..91835950366 100644 --- a/server/token.c +++ b/server/token.c @@ -377,6 +377,75 @@ ACL *extract_security_labels( const ACL *sacl ) return label_acl; } +/* replace security labels in an existing SACL */ +ACL *replace_security_labels( 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; + + 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 NULL; + + 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 ); + } + } + + return replaced_acl; +} + /* maps from generic rights to specific rights as given by a mapping */ static inline void map_generic_mask(unsigned int *mask, const GENERIC_MAPPING *mapping) {