diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index 82508ef5..52064cb6 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -290,6 +290,7 @@ patch_enable_all () enable_server_File_Permissions="$1" enable_server_Inherited_ACLs="$1" enable_server_Key_State="$1" + enable_server_LABEL_SECURITY_INFORMATION="$1" enable_server_Map_EXDEV_Error="$1" enable_server_Misc_ACL="$1" enable_server_PeekMessage="$1" @@ -1069,6 +1070,9 @@ patch_enable () server-Key_State) enable_server_Key_State="$2" ;; + server-LABEL_SECURITY_INFORMATION) + enable_server_LABEL_SECURITY_INFORMATION="$2" + ;; server-Map_EXDEV_Error) enable_server_Map_EXDEV_Error="$2" ;; @@ -2246,6 +2250,25 @@ if test "$enable_server_Pipe_ObjectName" -eq 1; then enable_kernel32_Named_Pipe=1 fi +if test "$enable_server_LABEL_SECURITY_INFORMATION" -eq 1; then + if test "$enable_advapi32_AddMandatoryAce" -gt 1; then + abort "Patchset advapi32-AddMandatoryAce disabled, but server-LABEL_SECURITY_INFORMATION depends on that." + fi + if test "$enable_advapi32_GetExplicitEntriesFromAclW" -gt 1; then + abort "Patchset advapi32-GetExplicitEntriesFromAclW disabled, but server-LABEL_SECURITY_INFORMATION depends on that." + fi + if test "$enable_server_Misc_ACL" -gt 1; then + abort "Patchset server-Misc_ACL disabled, but server-LABEL_SECURITY_INFORMATION depends on that." + fi + if test "$enable_server_Stored_ACLs" -gt 1; then + abort "Patchset server-Stored_ACLs disabled, but server-LABEL_SECURITY_INFORMATION depends on that." + fi + enable_advapi32_AddMandatoryAce=1 + enable_advapi32_GetExplicitEntriesFromAclW=1 + enable_server_Misc_ACL=1 + enable_server_Stored_ACLs=1 +fi + if test "$enable_server_Inherited_ACLs" -eq 1; then if test "$enable_server_Stored_ACLs" -gt 1; then abort "Patchset server-Stored_ACLs disabled, but server-Inherited_ACLs depends on that." @@ -6413,6 +6436,39 @@ if test "$enable_server_Key_State" -eq 1; then ) >> "$patchlist" fi +# Patchset server-LABEL_SECURITY_INFORMATION +# | +# | This patchset has the following (direct or indirect) dependencies: +# | * advapi32-AddMandatoryAce, advapi32-GetExplicitEntriesFromAclW, server-Misc_ACL, ntdll-DOS_Attributes, server- +# | File_Permissions, server-Stored_ACLs +# | +# | Modified files: +# | * dlls/advapi32/tests/security.c, dlls/ntdll/nt.c, dlls/ntdll/sec.c, include/winnt.h, server/handle.c, server/object.c, +# | server/process.c, server/protocol.def, server/security.h, server/token.c +# | +if test "$enable_server_LABEL_SECURITY_INFORMATION" -eq 1; then + patch_apply server-LABEL_SECURITY_INFORMATION/0001-server-Implement-querying-the-security-label-of-a-se.patch + patch_apply server-LABEL_SECURITY_INFORMATION/0002-server-Implement-changing-the-label-of-a-security-de.patch + patch_apply server-LABEL_SECURITY_INFORMATION/0003-server-Do-not-set-SE_-D-S-ACL_PRESENT-if-no-D-S-ACL-.patch + patch_apply server-LABEL_SECURITY_INFORMATION/0004-server-Implement-setting-a-security-descriptor-when-.patch + patch_apply server-LABEL_SECURITY_INFORMATION/0005-advapi32-tests-Add-basic-tests-for-token-security-de.patch + patch_apply server-LABEL_SECURITY_INFORMATION/0006-advapi32-tests-Show-that-tokens-do-not-inherit-secur.patch + patch_apply server-LABEL_SECURITY_INFORMATION/0007-advapi32-tests-Show-that-tokens-do-not-inherit-dacls.patch + patch_apply server-LABEL_SECURITY_INFORMATION/0008-advapi32-tests-Show-that-tokens-do-not-inherit-sacls.patch + patch_apply server-LABEL_SECURITY_INFORMATION/0009-server-Assign-a-default-label-high-to-all-tokens.patch + ( + echo '+ { "Michael Müller", "server: Implement querying the security label of a security descriptor.", 1 },'; + echo '+ { "Michael Müller", "server: Implement changing the label of a security descriptor.", 1 },'; + echo '+ { "Michael Müller", "server: Do not set SE_{D,S}ACL_PRESENT if no {D,S}ACL was set.", 1 },'; + echo '+ { "Michael Müller", "server: Implement setting a security descriptor when duplicating tokens.", 1 },'; + echo '+ { "Michael Müller", "advapi32/tests: Add basic tests for token security descriptors.", 1 },'; + echo '+ { "Michael Müller", "advapi32/tests: Show that tokens do not inherit security descriptors during duplication.", 1 },'; + echo '+ { "Michael Müller", "advapi32/tests: Show that tokens do not inherit dacls while creating child processes.", 1 },'; + echo '+ { "Michael Müller", "advapi32/tests: Show that tokens do not inherit sacls / mandatory labels while creating child processes.", 1 },'; + echo '+ { "Michael Müller", "server: Assign a default label (high) to all tokens.", 1 },'; + ) >> "$patchlist" +fi + # Patchset server-Map_EXDEV_Error # | # | Modified files: diff --git a/patches/server-LABEL_SECURITY_INFORMATION/0001-server-Implement-querying-the-security-label-of-a-se.patch b/patches/server-LABEL_SECURITY_INFORMATION/0001-server-Implement-querying-the-security-label-of-a-se.patch new file mode 100644 index 00000000..d3b535f8 --- /dev/null +++ b/patches/server-LABEL_SECURITY_INFORMATION/0001-server-Implement-querying-the-security-label-of-a-se.patch @@ -0,0 +1,222 @@ +From a05c00f17a61a2d34a5e439b5c4f835f011187b0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Mon, 29 Aug 2016 20:35:51 +0200 +Subject: server: Implement querying the security label of a security + descriptor. + +--- + dlls/advapi32/tests/security.c | 80 ++++++++++++++++++++++++++++++++++++++++-- + include/winnt.h | 1 + + server/handle.c | 55 +++++++++++++++++++++++++++++ + 3 files changed, 134 insertions(+), 2 deletions(-) + +diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c +index 98f98721a0c..877250c1ebf 100644 +--- a/dlls/advapi32/tests/security.c ++++ b/dlls/advapi32/tests/security.c +@@ -6435,10 +6435,15 @@ static void test_integrity(void) + static SID low_level = {SID_REVISION, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY}, + {SECURITY_MANDATORY_LOW_RID}}; + SYSTEM_MANDATORY_LABEL_ACE *ace; ++ char buffer_sd[SECURITY_DESCRIPTOR_MIN_LENGTH]; ++ SECURITY_DESCRIPTOR *sd2, *sd = (SECURITY_DESCRIPTOR *)&buffer_sd; ++ SECURITY_ATTRIBUTES sa; + char buffer_acl[256]; + ACL *pAcl = (ACL*)&buffer_acl; +- BOOL ret, found; +- DWORD index; ++ ACL *sAcl; ++ BOOL defaulted, present, ret, found; ++ HANDLE handle; ++ DWORD index, size; + + if (!pAddMandatoryAce) + { +@@ -6446,6 +6451,36 @@ static void test_integrity(void) + return; + } + ++ ret = InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION); ++ ok(ret, "InitializeSecurityDescriptor failed with %u\n", GetLastError()); ++ ++ sa.nLength = sizeof(SECURITY_ATTRIBUTES); ++ sa.lpSecurityDescriptor = sd; ++ sa.bInheritHandle = FALSE; ++ ++ handle = CreateEventA(&sa, TRUE, TRUE, "test_event"); ++ ok(handle != NULL, "CreateEventA failed with error %u\n", GetLastError()); ++ ++ ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, NULL, 0, &size); ++ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, ++ "GetKernelObjectSecurity failed with %u\n", GetLastError()); ++ ++ sd2 = HeapAlloc(GetProcessHeap(), 0, size); ++ ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd2, size, &size); ++ ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError()); ++ ++ sAcl = (void *)0xdeadbeef; ++ present = TRUE; ++ defaulted = TRUE; ++ ret = GetSecurityDescriptorSacl(sd2, &present, &sAcl, &defaulted); ++ ok(ret, "GetSecurityDescriptorSacl failed with %u\n", GetLastError()); ++ todo_wine ok(!present, "sAcl is present\n"); ++ todo_wine ok(sAcl == (void *)0xdeadbeef, "sAcl is set\n"); ++ ok(!defaulted, "sAcl defaulted\n"); ++ ++ HeapFree(GetProcessHeap(), 0, sd2); ++ CloseHandle(handle); ++ + ret = InitializeAcl(pAcl, 256, ACL_REVISION); + ok(ret, "InitializeAcl failed with %u\n", GetLastError()); + +@@ -6470,6 +6505,47 @@ static void test_integrity(void) + } + } + ok(found, "Could not find mandatory label\n"); ++ ++ ret = SetSecurityDescriptorSacl(sd, TRUE, pAcl, FALSE); ++ ok(ret, "SetSecurityDescriptorSacl failed with %u\n", GetLastError()); ++ ++ handle = CreateEventA(&sa, TRUE, TRUE, "test_event"); ++ ok(handle != NULL, "CreateEventA failed with error %u\n", GetLastError()); ++ ++ ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, NULL, 0, &size); ++ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, ++ "GetKernelObjectSecurity failed with %u\n", GetLastError()); ++ ++ sd2 = HeapAlloc(GetProcessHeap(), 0, size); ++ ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd2, size, &size); ++ ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError()); ++ ++ sAcl = (void *)0xdeadbeef; ++ present = FALSE; ++ defaulted = TRUE; ++ ret = GetSecurityDescriptorSacl(sd2, &present, &sAcl, &defaulted); ++ ok(ret, "GetSecurityDescriptorSacl failed with %u\n", GetLastError()); ++ ok(present, "sAcl not present\n"); ++ ok(sAcl != (void *)0xdeadbeef, "sAcl not set\n"); ++ ok(!defaulted, "sAcl defaulted\n"); ++ ++ index = 0; ++ found = FALSE; ++ while (pGetAce( sAcl, index++, (void **)&ace )) ++ { ++ if (ace->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE) ++ { ++ found = TRUE; ++ ok(ace->Header.AceFlags == 0, "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 flag, got %x\n", ace->Mask); ++ ok(EqualSid(&ace->SidStart, &low_level), "Expected low integrity level\n"); ++ } ++ } ++ ok(found, "Could not find mandatory label\n"); ++ ++ HeapFree(GetProcessHeap(), 0, sd2); ++ CloseHandle(handle); + } + + static void test_AdjustTokenPrivileges(void) +diff --git a/include/winnt.h b/include/winnt.h +index 392f77b217d..97d6295bdef 100644 +--- a/include/winnt.h ++++ b/include/winnt.h +@@ -5282,6 +5282,7 @@ typedef struct _TAPE_GET_MEDIA_PARAMETERS { + #define GROUP_SECURITY_INFORMATION 0x00000002 + #define DACL_SECURITY_INFORMATION 0x00000004 + #define SACL_SECURITY_INFORMATION 0x00000008 ++#define LABEL_SECURITY_INFORMATION 0x00000010 + + #define REG_OPTION_RESERVED 0x00000000 + #define REG_OPTION_NON_VOLATILE 0x00000000 +diff --git a/server/handle.c b/server/handle.c +index 391f4688b6a..3d5485fcdf9 100644 +--- a/server/handle.c ++++ b/server/handle.c +@@ -710,6 +710,52 @@ DECL_HANDLER(set_security_object) + release_object( obj ); + } + ++/* extract security labels from SACL */ ++static int extract_security_label( ACL **out, const ACL *sacl ) ++{ ++ const ACE_HEADER *ace; ++ ACE_HEADER *label_ace; ++ size_t size = sizeof(ACL); ++ int i, count = 0; ++ ACL *label_acl; ++ ++ *out = NULL; ++ if (!sacl) return 1; ++ ++ ace = (const ACE_HEADER *)(sacl + 1); ++ for (i = 0; i < sacl->AceCount; i++, ace = ace_next( ace )) ++ { ++ if (ace->AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE) ++ { ++ size += ace->AceSize; ++ count++; ++ } ++ } ++ ++ label_acl = mem_alloc( size ); ++ if (!label_acl) return 0; ++ ++ label_acl->AclRevision = sacl->AclRevision; ++ label_acl->Sbz1 = 0; ++ label_acl->AclSize = size; ++ label_acl->AceCount = count; ++ label_acl->Sbz2 = 0; ++ label_ace = (ACE_HEADER *)(label_acl + 1); ++ ++ ace = (const ACE_HEADER *)(sacl + 1); ++ for (i = 0; i < sacl->AceCount; i++, ace = ace_next( ace )) ++ { ++ if (ace->AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE) ++ { ++ memcpy( label_ace, ace, ace->AceSize ); ++ label_ace = (ACE_HEADER *)ace_next( label_ace ); ++ } ++ } ++ ++ *out = label_acl; ++ return 1; ++} ++ + DECL_HANDLER(get_security_object) + { + const struct security_descriptor *sd; +@@ -719,6 +765,7 @@ DECL_HANDLER(get_security_object) + int present; + const SID *owner, *group; + const ACL *sacl, *dacl; ++ ACL *label_acl = NULL; + + if (req->security_info & SACL_SECURITY_INFORMATION) + access |= ACCESS_SYSTEM_SECURITY; +@@ -746,6 +793,12 @@ DECL_HANDLER(get_security_object) + sacl = sd_get_sacl( sd, &present ); + if (req->security_info & SACL_SECURITY_INFORMATION && present) + req_sd.sacl_len = sd->sacl_len; ++ else if (req->security_info & LABEL_SECURITY_INFORMATION && present) ++ { ++ if (!extract_security_label( &label_acl, sacl )) goto error; ++ req_sd.sacl_len = label_acl ? label_acl->AclSize : 0; ++ sacl = label_acl; ++ } + else + req_sd.sacl_len = 0; + +@@ -776,7 +829,9 @@ DECL_HANDLER(get_security_object) + set_error(STATUS_BUFFER_TOO_SMALL); + } + ++error: + release_object( obj ); ++ free( label_acl ); + } + + struct enum_handle_info +-- +2.11.0 + diff --git a/patches/server-LABEL_SECURITY_INFORMATION/0002-server-Implement-changing-the-label-of-a-security-de.patch b/patches/server-LABEL_SECURITY_INFORMATION/0002-server-Implement-changing-the-label-of-a-security-de.patch new file mode 100644 index 00000000..16195ab0 --- /dev/null +++ b/patches/server-LABEL_SECURITY_INFORMATION/0002-server-Implement-changing-the-label-of-a-security-de.patch @@ -0,0 +1,329 @@ +From 703cd39ce88d6b50c0ca7da3ba7533ac3ce91950 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Tue, 30 Aug 2016 01:15:44 +0200 +Subject: server: Implement changing the label of a security descriptor. + +--- + dlls/advapi32/tests/security.c | 113 ++++++++++++++++++++++++++++++++++- + dlls/ntdll/sec.c | 3 +- + server/handle.c | 131 ++++++++++++++++++++++++++++++++++++++++- + 3 files changed, 243 insertions(+), 4 deletions(-) + +diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c +index 877250c1ebf..84a451eb834 100644 +--- a/dlls/advapi32/tests/security.c ++++ b/dlls/advapi32/tests/security.c +@@ -6434,6 +6434,8 @@ static void test_integrity(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}}; + SYSTEM_MANDATORY_LABEL_ACE *ace; + char buffer_sd[SECURITY_DESCRIPTOR_MIN_LENGTH]; + SECURITY_DESCRIPTOR *sd2, *sd = (SECURITY_DESCRIPTOR *)&buffer_sd; +@@ -6441,7 +6443,7 @@ static void test_integrity(void) + char buffer_acl[256]; + ACL *pAcl = (ACL*)&buffer_acl; + ACL *sAcl; +- BOOL defaulted, present, ret, found; ++ BOOL defaulted, present, ret, found, found2; + HANDLE handle; + DWORD index, size; + +@@ -6545,6 +6547,115 @@ static void test_integrity(void) + ok(found, "Could not find mandatory label\n"); + + HeapFree(GetProcessHeap(), 0, sd2); ++ ++ ret = pAddMandatoryAce(pAcl, ACL_REVISION, 0, SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP, &medium_level); ++ ok(ret, "AddMandatoryAce failed with %u\n", GetLastError()); ++ ++ ret = SetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd); ++ ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError()); ++ ++ ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, NULL, 0, &size); ++ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, ++ "GetKernelObjectSecurity failed with %u\n", GetLastError()); ++ ++ sd2 = HeapAlloc(GetProcessHeap(), 0, size); ++ ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd2, size, &size); ++ ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError()); ++ ++ sAcl = (void *)0xdeadbeef; ++ present = FALSE; ++ defaulted = TRUE; ++ ret = GetSecurityDescriptorSacl(sd2, &present, &sAcl, &defaulted); ++ ok(ret, "GetSecurityDescriptorSacl failed with %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 == 0, "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 flag, got %x\n", ace->Mask); ++ } ++ if (EqualSid(&ace->SidStart, &medium_level)) ++ { ++ found2 = TRUE; ++ ok(ace->Header.AceFlags == 0, "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 flag, 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 %u\n", GetLastError()); ++ ++ ret = SetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd); ++ ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError()); ++ ++ ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, NULL, 0, &size); ++ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, ++ "GetKernelObjectSecurity failed with %u\n", GetLastError()); ++ ++ sd2 = HeapAlloc(GetProcessHeap(), 0, size); ++ ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd2, size, &size); ++ ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError()); ++ ++ sAcl = (void *)0xdeadbeef; ++ present = FALSE; ++ defaulted = TRUE; ++ ret = GetSecurityDescriptorSacl(sd2, &present, &sAcl, &defaulted); ++ ok(ret, "GetSecurityDescriptorSacl failed with %u\n", GetLastError()); ++ ok(present, "sAcl not present\n"); ++ ok(sAcl != (void *)0xdeadbeef, "sAcl not set\n"); ++ ok(sAcl->AceCount == 0, "Expected 0 ACEs, got %d\n", sAcl->AceCount); ++ ok(!defaulted, "sAcl defaulted\n"); ++ ++ HeapFree(GetProcessHeap(), 0, sd2); ++ ++ ret = InitializeAcl(pAcl, 256, ACL_REVISION); ++ ok(ret, "InitializeAcl failed with %u\n", GetLastError()); ++ ++ ret = pAddMandatoryAce(pAcl, ACL_REVISION3, 0, SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP, &medium_level); ++ ok(ret, "AddMandatoryAce failed with %u\n", GetLastError()); ++ ++ ret = SetSecurityDescriptorSacl(sd, TRUE, pAcl, FALSE); ++ ok(ret, "SetSecurityDescriptorSacl failed with %u\n", GetLastError()); ++ ++ ret = SetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd); ++ ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError()); ++ ++ ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, NULL, 0, &size); ++ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, ++ "GetKernelObjectSecurity failed with %u\n", GetLastError()); ++ ++ sd2 = HeapAlloc(GetProcessHeap(), 0, size); ++ ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd2, size, &size); ++ ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError()); ++ ++ sAcl = (void *)0xdeadbeef; ++ present = FALSE; ++ defaulted = TRUE; ++ ret = GetSecurityDescriptorSacl(sd2, &present, &sAcl, &defaulted); ++ ok(ret, "GetSecurityDescriptorSacl failed with %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); + CloseHandle(handle); + } + +diff --git a/dlls/ntdll/sec.c b/dlls/ntdll/sec.c +index f588545f322..5cf6c788ffb 100644 +--- a/dlls/ntdll/sec.c ++++ b/dlls/ntdll/sec.c +@@ -1782,7 +1782,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 3d5485fcdf9..a0e27b9507e 100644 +--- a/server/handle.c ++++ b/server/handle.c +@@ -683,12 +683,89 @@ DECL_HANDLER(get_object_info) + release_object( obj ); + } + ++/* merge security labels into an existing SACL */ ++static int merge_security_labels( ACL **out, const ACL *old_sacl, const ACL *new_sacl ) ++{ ++ const ACE_HEADER *ace; ++ ACE_HEADER *merged_ace; ++ size_t size = sizeof(ACL); ++ int i, count = 0; ++ BYTE revision = ACL_REVISION; ++ ACL *merged_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 )) ++ { ++ /* FIXME: Should this be handled as error? */ ++ if (ace->AceType != SYSTEM_MANDATORY_LABEL_ACE_TYPE) continue; ++ size += ace->AceSize; ++ count++; ++ } ++ } ++ ++ merged_acl = mem_alloc( size ); ++ if (!merged_acl) return 0; ++ ++ merged_acl->AclRevision = revision; ++ merged_acl->Sbz1 = 0; ++ merged_acl->AclSize = size; ++ merged_acl->AceCount = count; ++ merged_acl->Sbz2 = 0; ++ merged_ace = (ACE_HEADER *)(merged_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( merged_ace, ace, ace->AceSize ); ++ merged_ace = (ACE_HEADER *)ace_next( merged_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( merged_ace, ace, ace->AceSize ); ++ merged_ace = (ACE_HEADER *)ace_next( merged_ace ); ++ } ++ } ++ ++ *out = merged_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(); ++ struct security_descriptor *merged_sd = NULL; ++ ACL *merged_sacl = NULL; + struct object *obj; + unsigned int access = 0; ++ unsigned int security_info = req->security_info; + + if (!sd_is_valid( sd, sd_size )) + { +@@ -697,7 +774,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; +@@ -706,8 +784,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 merge the security labels with the existing SACLs */ ++ 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 (!merge_security_labels( &merged_sacl, old_sacl, sd_get_sacl( sd, &present ) )) goto error; ++ ++ /* allocate a new SD and replace SACL with merged version */ ++ merged_sd = mem_alloc( sizeof(*merged_sd) + sd->owner_len + sd->group_len + ++ (merged_sacl ? merged_sacl->AclSize : 0) + sd->dacl_len ); ++ if (!merged_sd) goto error; ++ ++ merged_sd->control = sd->control; ++ merged_sd->owner_len = sd->owner_len; ++ merged_sd->group_len = sd->group_len; ++ merged_sd->sacl_len = merged_sacl ? merged_sacl->AclSize : 0; ++ merged_sd->dacl_len = sd->dacl_len; ++ ++ ptr = (char *)(merged_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 (merged_sacl) ++ { ++ memcpy( ptr, merged_sacl, merged_sacl->AclSize ); ++ ptr += merged_sacl->AclSize; ++ } ++ memcpy( ptr, sd_get_dacl( sd, &present ), sd->dacl_len ); ++ ++ security_info |= SACL_SECURITY_INFORMATION; ++ sd = merged_sd; ++ } ++ ++ obj->ops->set_sd( obj, sd, security_info ); ++ ++error: + release_object( obj ); ++ free( merged_sacl ); ++ free( merged_sd ); + } + + /* extract security labels from SACL */ +-- +2.11.0 + diff --git a/patches/server-LABEL_SECURITY_INFORMATION/0003-server-Do-not-set-SE_-D-S-ACL_PRESENT-if-no-D-S-ACL-.patch b/patches/server-LABEL_SECURITY_INFORMATION/0003-server-Do-not-set-SE_-D-S-ACL_PRESENT-if-no-D-S-ACL-.patch new file mode 100644 index 00000000..f3cb389f --- /dev/null +++ b/patches/server-LABEL_SECURITY_INFORMATION/0003-server-Do-not-set-SE_-D-S-ACL_PRESENT-if-no-D-S-ACL-.patch @@ -0,0 +1,102 @@ +From 048c4e74b36eacac239ab61997f756ed956ab7f2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Tue, 30 Aug 2016 02:10:32 +0200 +Subject: server: Do not set SE_{D,S}ACL_PRESENT if no {D,S}ACL was set. + +--- + dlls/advapi32/tests/security.c | 6 +++--- + server/handle.c | 2 -- + server/object.c | 15 +++++++++++++-- + 3 files changed, 16 insertions(+), 7 deletions(-) + +diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c +index 84a451eb834..263d2f11544 100644 +--- a/dlls/advapi32/tests/security.c ++++ b/dlls/advapi32/tests/security.c +@@ -6476,9 +6476,9 @@ static void test_integrity(void) + defaulted = TRUE; + ret = GetSecurityDescriptorSacl(sd2, &present, &sAcl, &defaulted); + ok(ret, "GetSecurityDescriptorSacl failed with %u\n", GetLastError()); +- todo_wine ok(!present, "sAcl is present\n"); +- todo_wine ok(sAcl == (void *)0xdeadbeef, "sAcl is set\n"); +- ok(!defaulted, "sAcl defaulted\n"); ++ ok(!present, "sAcl is present\n"); ++ ok(sAcl == (void *)0xdeadbeef, "sAcl is set\n"); ++ todo_wine ok(!defaulted, "sAcl defaulted\n"); + + HeapFree(GetProcessHeap(), 0, sd2); + CloseHandle(handle); +diff --git a/server/handle.c b/server/handle.c +index a0e27b9507e..57e0c060e03 100644 +--- a/server/handle.c ++++ b/server/handle.c +@@ -916,7 +916,6 @@ DECL_HANDLER(get_security_object) + else + req_sd.group_len = 0; + +- req_sd.control |= SE_SACL_PRESENT; + sacl = sd_get_sacl( sd, &present ); + if (req->security_info & SACL_SECURITY_INFORMATION && present) + req_sd.sacl_len = sd->sacl_len; +@@ -929,7 +928,6 @@ DECL_HANDLER(get_security_object) + else + req_sd.sacl_len = 0; + +- req_sd.control |= SE_DACL_PRESENT; + dacl = sd_get_dacl( sd, &present ); + if (req->security_info & DACL_SECURITY_INFORMATION && present) + req_sd.dacl_len = sd->dacl_len; +diff --git a/server/object.c b/server/object.c +index b4af10e811c..703875db248 100644 +--- a/server/object.c ++++ b/server/object.c +@@ -573,33 +573,44 @@ struct security_descriptor *set_sd_from_token_internal( const struct security_de + } + else new_sd.group_len = 0; + +- new_sd.control |= SE_SACL_PRESENT; + sacl = sd_get_sacl( sd, &present ); + if (set_info & SACL_SECURITY_INFORMATION && present) ++ { ++ new_sd.control |= SE_SACL_PRESENT; + new_sd.sacl_len = sd->sacl_len; ++ } + else + { + if (old_sd) sacl = sd_get_sacl( old_sd, &present ); + + if (old_sd && present) ++ { ++ new_sd.control |= SE_SACL_PRESENT; + new_sd.sacl_len = old_sd->sacl_len; ++ } + else + new_sd.sacl_len = 0; + } + +- new_sd.control |= SE_DACL_PRESENT; + dacl = sd_get_dacl( sd, &present ); + if (set_info & DACL_SECURITY_INFORMATION && present) ++ { ++ new_sd.control |= SE_DACL_PRESENT; + new_sd.dacl_len = sd->dacl_len; ++ } + else + { + if (old_sd) dacl = sd_get_dacl( old_sd, &present ); + + if (old_sd && present) ++ { ++ new_sd.control |= SE_DACL_PRESENT; + new_sd.dacl_len = old_sd->dacl_len; ++ } + else if (token) + { + dacl = token_get_default_dacl( token ); ++ new_sd.control |= SE_DACL_PRESENT; + new_sd.dacl_len = dacl->AclSize; + } + else new_sd.dacl_len = 0; +-- +2.11.0 + diff --git a/patches/server-LABEL_SECURITY_INFORMATION/0004-server-Implement-setting-a-security-descriptor-when-.patch b/patches/server-LABEL_SECURITY_INFORMATION/0004-server-Implement-setting-a-security-descriptor-when-.patch new file mode 100644 index 00000000..c9a9230c --- /dev/null +++ b/patches/server-LABEL_SECURITY_INFORMATION/0004-server-Implement-setting-a-security-descriptor-when-.patch @@ -0,0 +1,147 @@ +From 402dca4fe8a333c8d76035c6b81c549be07882c8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Thu, 12 Jan 2017 05:23:57 +0100 +Subject: server: Implement setting a security descriptor when duplicating + tokens. + +--- + dlls/ntdll/nt.c | 7 ++++++- + server/process.c | 2 +- + server/protocol.def | 2 +- + server/security.h | 2 +- + server/token.c | 20 +++++++++++++++++--- + 5 files changed, 26 insertions(+), 7 deletions(-) + +diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c +index 9347170a593..cc5c653d23e 100644 +--- a/dlls/ntdll/nt.c ++++ b/dlls/ntdll/nt.c +@@ -87,11 +87,15 @@ NTSTATUS WINAPI NtDuplicateToken( + OUT PHANDLE NewToken) + { + NTSTATUS status; ++ data_size_t len; ++ struct object_attributes *objattr; + + TRACE("(%p,0x%08x,%s,0x%08x,0x%08x,%p)\n", + ExistingToken, DesiredAccess, debugstr_ObjectAttributes(ObjectAttributes), + ImpersonationLevel, TokenType, NewToken); + ++ if ((status = alloc_object_attributes( ObjectAttributes, &objattr, &len ))) return status; ++ + if (ObjectAttributes && ObjectAttributes->SecurityQualityOfService) + { + SECURITY_QUALITY_OF_SERVICE *SecurityQOS = ObjectAttributes->SecurityQualityOfService; +@@ -106,14 +110,15 @@ NTSTATUS WINAPI NtDuplicateToken( + { + req->handle = wine_server_obj_handle( ExistingToken ); + req->access = DesiredAccess; +- req->attributes = ObjectAttributes ? ObjectAttributes->Attributes : 0; + req->primary = (TokenType == TokenPrimary); + req->impersonation_level = ImpersonationLevel; ++ wine_server_add_data( req, objattr, len ); + status = wine_server_call( req ); + if (!status) *NewToken = wine_server_ptr_handle( reply->new_handle ); + } + SERVER_END_REQ; + ++ RtlFreeHeap( GetProcessHeap(), 0, objattr ); + return status; + } + +diff --git a/server/process.c b/server/process.c +index ca5982fe061..f476cfaf0fe 100644 +--- a/server/process.c ++++ b/server/process.c +@@ -569,7 +569,7 @@ struct thread *create_process( int fd, struct thread *parent_thread, int inherit + : alloc_handle_table( process, 0 ); + /* Note: for security reasons, starting a new process does not attempt + * to use the current impersonation token for the new process */ +- process->token = token_duplicate( parent->token, TRUE, 0 ); ++ process->token = token_duplicate( parent->token, TRUE, 0, NULL ); + process->affinity = parent->affinity; + } + if (!process->handles || !process->token) goto error; +diff --git a/server/protocol.def b/server/protocol.def +index 97cf5adf298..3da579650fa 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -3361,9 +3361,9 @@ enum caret_state + @REQ(duplicate_token) + obj_handle_t handle; /* handle to the token to duplicate */ + unsigned int access; /* access rights to the new token */ +- unsigned int attributes; /* object attributes */ + int primary; /* is the new token to be a primary one? */ + int impersonation_level; /* impersonation level of the new token */ ++ VARARG(objattr,object_attributes); /* object attributes */ + @REPLY + obj_handle_t new_handle; /* duplicated handle */ + @END +diff --git a/server/security.h b/server/security.h +index bdb7d42f09d..0342f643187 100644 +--- a/server/security.h ++++ b/server/security.h +@@ -54,7 +54,7 @@ extern const PSID security_domain_users_sid; + + extern struct token *token_create_admin(void); + extern struct token *token_duplicate( struct token *src_token, unsigned primary, +- int impersonation_level ); ++ int impersonation_level, const struct security_descriptor *sd ); + extern int token_check_privileges( struct token *token, int all_required, + const LUID_AND_ATTRIBUTES *reqprivs, + unsigned int count, LUID_AND_ATTRIBUTES *usedprivs); +diff --git a/server/token.c b/server/token.c +index b903420bbe3..74a97bb1319 100644 +--- a/server/token.c ++++ b/server/token.c +@@ -521,7 +521,7 @@ static struct token *create_token( unsigned primary, const SID *user, + } + + struct token *token_duplicate( struct token *src_token, unsigned primary, +- int impersonation_level ) ++ int impersonation_level, const struct security_descriptor *sd ) + { + const luid_t *modified_id = + primary || (impersonation_level == src_token->impersonation_level) ? +@@ -571,6 +571,15 @@ struct token *token_duplicate( struct token *src_token, unsigned primary, + return NULL; + } + ++ if (sd) ++ { ++ default_set_sd( &token->obj, sd, ++ OWNER_SECURITY_INFORMATION | ++ GROUP_SECURITY_INFORMATION | ++ DACL_SECURITY_INFORMATION | ++ SACL_SECURITY_INFORMATION ); ++ } ++ + return token; + } + +@@ -1141,15 +1150,20 @@ DECL_HANDLER(get_token_privileges) + DECL_HANDLER(duplicate_token) + { + struct token *src_token; ++ struct unicode_str name; ++ const struct security_descriptor *sd; ++ const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, NULL ); ++ ++ if (!objattr) return; + + if ((src_token = (struct token *)get_handle_obj( current->process, req->handle, + TOKEN_DUPLICATE, + &token_ops ))) + { +- struct token *token = token_duplicate( src_token, req->primary, req->impersonation_level ); ++ struct token *token = token_duplicate( src_token, req->primary, req->impersonation_level, sd ); + if (token) + { +- reply->new_handle = alloc_handle( current->process, token, req->access, req->attributes); ++ reply->new_handle = alloc_handle_no_access_check( current->process, token, req->access, objattr->attributes ); + release_object( token ); + } + release_object( src_token ); +-- +2.11.0 + diff --git a/patches/server-LABEL_SECURITY_INFORMATION/0005-advapi32-tests-Add-basic-tests-for-token-security-de.patch b/patches/server-LABEL_SECURITY_INFORMATION/0005-advapi32-tests-Add-basic-tests-for-token-security-de.patch new file mode 100644 index 00000000..2b0cafa3 --- /dev/null +++ b/patches/server-LABEL_SECURITY_INFORMATION/0005-advapi32-tests-Add-basic-tests-for-token-security-de.patch @@ -0,0 +1,129 @@ +From 5ee9eaecad03eda9e6eb45abc23ce20f49f17c13 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Thu, 12 Jan 2017 05:28:30 +0100 +Subject: advapi32/tests: Add basic tests for token security descriptors. + +--- + dlls/advapi32/tests/security.c | 87 +++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 86 insertions(+), 1 deletion(-) + +diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c +index 263d2f11544..8af1d0604a4 100644 +--- a/dlls/advapi32/tests/security.c ++++ b/dlls/advapi32/tests/security.c +@@ -217,6 +217,7 @@ static void init(void) + pGetWindowsAccountDomainSid = (void *)GetProcAddress(hmod, "GetWindowsAccountDomainSid"); + pGetSidIdentifierAuthority = (void *)GetProcAddress(hmod, "GetSidIdentifierAuthority"); + pGetExplicitEntriesFromAclW = (void *)GetProcAddress(hmod, "GetExplicitEntriesFromAclW"); ++ pDuplicateTokenEx = (void *)GetProcAddress(hmod, "DuplicateTokenEx"); + + myARGC = winetest_get_mainargs( &myARGV ); + } +@@ -3117,7 +3118,6 @@ static void test_impersonation_level(void) + HKEY hkey; + DWORD error; + +- pDuplicateTokenEx = (void *)GetProcAddress(hmod, "DuplicateTokenEx"); + if( !pDuplicateTokenEx ) { + win_skip("DuplicateTokenEx is not available\n"); + return; +@@ -7136,6 +7136,90 @@ static void test_GetExplicitEntriesFromAclW(void) + HeapFree(GetProcessHeap(), 0, old_acl); + } + ++static void test_token_security_descriptor(void) ++{ ++ ACCESS_ALLOWED_ACE *ace; ++ char buffer_sd[SECURITY_DESCRIPTOR_MIN_LENGTH]; ++ SECURITY_DESCRIPTOR *sd = (SECURITY_DESCRIPTOR *)&buffer_sd, *sd2; ++ char buffer_acl[256]; ++ ACL *pAcl = (ACL *)&buffer_acl, *pAcl2; ++ BOOL defaulted, present, ret, found; ++ HANDLE token, token2; ++ SECURITY_ATTRIBUTES sa; ++ DWORD size, index; ++ PSID psid; ++ ++ if (!pDuplicateTokenEx || !pConvertStringSidToSidA || !pAddAccessAllowedAceEx || !pGetAce || !pSetEntriesInAclW) ++ { ++ win_skip("Some functions not available\n"); ++ return; ++ } ++ ++ /* Test whether we can create tokens with security descriptors */ ++ ret = OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &token); ++ ok(ret, "OpenProcessToken failed with error %u\n", GetLastError()); ++ ++ ret = InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION); ++ ok(ret, "InitializeSecurityDescriptor failed with %u\n", GetLastError()); ++ ++ ret = InitializeAcl(pAcl, 256, ACL_REVISION); ++ ok(ret, "InitializeAcl failed with %u\n", GetLastError()); ++ ++ ret = pConvertStringSidToSidA("S-1-5-6", &psid); ++ ok(ret, "ConvertStringSidToSidA failed with %u\n", GetLastError()); ++ ++ ret = pAddAccessAllowedAceEx(pAcl, ACL_REVISION, NO_PROPAGATE_INHERIT_ACE, GENERIC_ALL, psid); ++ ok(ret, "AddAccessAllowedAceEx failed with %u\n", GetLastError()); ++ ++ ret = SetSecurityDescriptorDacl(sd, TRUE, pAcl, FALSE); ++ ok(ret, "SetSecurityDescriptorDacl failed with %u\n", GetLastError()); ++ ++ sa.nLength = sizeof(SECURITY_ATTRIBUTES); ++ sa.lpSecurityDescriptor = sd; ++ sa.bInheritHandle = FALSE; ++ ++ ret = pDuplicateTokenEx(token, MAXIMUM_ALLOWED, &sa, SecurityImpersonation, TokenImpersonation, &token2); ++ ok(ret, "DuplicateTokenEx failed with %u\n", GetLastError()); ++ ++ ret = GetKernelObjectSecurity(token2, DACL_SECURITY_INFORMATION, NULL, 0, &size); ++ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, ++ "GetKernelObjectSecurity failed with %u\n", GetLastError()); ++ ++ sd2 = HeapAlloc(GetProcessHeap(), 0, size); ++ ret = GetKernelObjectSecurity(token2, DACL_SECURITY_INFORMATION, sd2, size, &size); ++ ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError()); ++ ++ pAcl2 = (void *)0xdeadbeef; ++ present = FALSE; ++ defaulted = TRUE; ++ ret = GetSecurityDescriptorDacl(sd2, &present, &pAcl2, &defaulted); ++ ok(ret, "GetSecurityDescriptorDacl failed with %u\n", GetLastError()); ++ ok(present, "pAcl2 not present\n"); ++ ok(pAcl2 != (void *)0xdeadbeef, "pAcl2 not set\n"); ++ ok(pAcl2->AceCount == 1, "Expected 1 ACEs, got %d\n", pAcl2->AceCount); ++ ok(!defaulted, "pAcl2 defaulted\n"); ++ ++ index = 0; ++ found = FALSE; ++ while (pGetAce( pAcl2, index++, (void **)&ace )) ++ { ++ if (ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE && EqualSid(&ace->SidStart, psid)) ++ { ++ found = TRUE; ++ ok(ace->Header.AceFlags == NO_PROPAGATE_INHERIT_ACE, ++ "Expected NO_PROPAGATE_INHERIT_ACE as flags, got %x\n", ace->Header.AceFlags); ++ } ++ } ++ ok(found, "Could not find access allowed ace\n"); ++ ++ HeapFree( GetProcessHeap(), 0, sd2); ++ ++ LocalFree(psid); ++ ++ CloseHandle(token2); ++ CloseHandle(token); ++} ++ + START_TEST(security) + { + init(); +@@ -7185,4 +7269,5 @@ START_TEST(security) + test_GetSidIdentifierAuthority(); + test_pseudo_tokens(); + test_GetExplicitEntriesFromAclW(); ++ test_token_security_descriptor(); + } +-- +2.11.0 + diff --git a/patches/server-LABEL_SECURITY_INFORMATION/0006-advapi32-tests-Show-that-tokens-do-not-inherit-secur.patch b/patches/server-LABEL_SECURITY_INFORMATION/0006-advapi32-tests-Show-that-tokens-do-not-inherit-secur.patch new file mode 100644 index 00000000..64165fc8 --- /dev/null +++ b/patches/server-LABEL_SECURITY_INFORMATION/0006-advapi32-tests-Show-that-tokens-do-not-inherit-secur.patch @@ -0,0 +1,75 @@ +From a4cefc05b12f5461daf5dcaaeaa144dc15db8b39 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Thu, 12 Jan 2017 05:31:31 +0100 +Subject: advapi32/tests: Show that tokens do not inherit security descriptors + during duplication. + +--- + dlls/advapi32/tests/security.c | 42 +++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 41 insertions(+), 1 deletion(-) + +diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c +index 8af1d0604a4..a2d0538b491 100644 +--- a/dlls/advapi32/tests/security.c ++++ b/dlls/advapi32/tests/security.c +@@ -7144,7 +7144,7 @@ static void test_token_security_descriptor(void) + char buffer_acl[256]; + ACL *pAcl = (ACL *)&buffer_acl, *pAcl2; + BOOL defaulted, present, ret, found; +- HANDLE token, token2; ++ HANDLE token, token2, token3; + SECURITY_ATTRIBUTES sa; + DWORD size, index; + PSID psid; +@@ -7214,8 +7214,48 @@ static void test_token_security_descriptor(void) + + HeapFree( GetProcessHeap(), 0, sd2); + ++ /* Duplicate token without security attributes. ++ * Tokens do not inherit the security descriptor when calling DuplicateToken, ++ * see https://blogs.msdn.microsoft.com/oldnewthing/20160512-00/?p=93447 ++ */ ++ ret = pDuplicateTokenEx(token2, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenImpersonation, &token3); ++ ok(ret, "DuplicateTokenEx failed with %u\n", GetLastError()); ++ ++ ret = GetKernelObjectSecurity(token3, DACL_SECURITY_INFORMATION, NULL, 0, &size); ++ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, ++ "GetKernelObjectSecurity failed with %u\n", GetLastError()); ++ ++ sd2 = HeapAlloc(GetProcessHeap(), 0, size); ++ ret = GetKernelObjectSecurity(token3, DACL_SECURITY_INFORMATION, sd2, size, &size); ++ ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError()); ++ ++ pAcl2 = (void *)0xdeadbeef; ++ present = FALSE; ++ defaulted = TRUE; ++ ret = GetSecurityDescriptorDacl(sd2, &present, &pAcl2, &defaulted); ++ ok(ret, "GetSecurityDescriptorDacl failed with %u\n", GetLastError()); ++ todo_wine ++ ok(present, "pAcl2 not present\n"); ++ ok(pAcl2 != (void *)0xdeadbeef, "pAcl2 not set\n"); ++ ok(!defaulted, "pAcl2 defaulted\n"); ++ ++ if (pAcl2) ++ { ++ index = 0; ++ found = FALSE; ++ while (pGetAce( pAcl2, index++, (void **)&ace )) ++ { ++ if (ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE && EqualSid(&ace->SidStart, psid)) ++ found = TRUE; ++ } ++ ok(!found, "Access allowed ace got inherited!\n"); ++ } ++ ++ HeapFree(GetProcessHeap(), 0, sd2); ++ + LocalFree(psid); + ++ CloseHandle(token3); + CloseHandle(token2); + CloseHandle(token); + } +-- +2.11.0 + diff --git a/patches/server-LABEL_SECURITY_INFORMATION/0007-advapi32-tests-Show-that-tokens-do-not-inherit-dacls.patch b/patches/server-LABEL_SECURITY_INFORMATION/0007-advapi32-tests-Show-that-tokens-do-not-inherit-dacls.patch new file mode 100644 index 00000000..bb65dad1 --- /dev/null +++ b/patches/server-LABEL_SECURITY_INFORMATION/0007-advapi32-tests-Show-that-tokens-do-not-inherit-dacls.patch @@ -0,0 +1,187 @@ +From df7287c73f6031de82dc674ea6338037537f0012 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Thu, 12 Jan 2017 05:37:42 +0100 +Subject: advapi32/tests: Show that tokens do not inherit dacls while creating + child processes. + +--- + dlls/advapi32/tests/security.c | 133 +++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 129 insertions(+), 4 deletions(-) + +diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c +index a2d0538b491..05b0c73edd6 100644 +--- a/dlls/advapi32/tests/security.c ++++ b/dlls/advapi32/tests/security.c +@@ -7141,12 +7141,15 @@ static void test_token_security_descriptor(void) + ACCESS_ALLOWED_ACE *ace; + char buffer_sd[SECURITY_DESCRIPTOR_MIN_LENGTH]; + SECURITY_DESCRIPTOR *sd = (SECURITY_DESCRIPTOR *)&buffer_sd, *sd2; +- char buffer_acl[256]; +- ACL *pAcl = (ACL *)&buffer_acl, *pAcl2; ++ char buffer_acl[256], buffer[MAX_PATH]; ++ ACL *pAcl = (ACL *)&buffer_acl, *pAcl2, *pAclChild; + BOOL defaulted, present, ret, found; + HANDLE token, token2, token3; ++ EXPLICIT_ACCESSW exp_access; ++ PROCESS_INFORMATION info; + SECURITY_ATTRIBUTES sa; +- DWORD size, index; ++ DWORD size, index, retd; ++ STARTUPINFOA startup; + PSID psid; + + if (!pDuplicateTokenEx || !pConvertStringSidToSidA || !pAddAccessAllowedAceEx || !pGetAce || !pSetEntriesInAclW) +@@ -7253,6 +7256,76 @@ static void test_token_security_descriptor(void) + + HeapFree(GetProcessHeap(), 0, sd2); + ++ /* When creating a child process, the process does only inherit the ++ * Token of the parent, but not the DACL of the token. ++ */ ++ ret = GetKernelObjectSecurity(token, DACL_SECURITY_INFORMATION, NULL, 0, &size); ++ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, ++ "GetKernelObjectSecurity failed with %u\n", GetLastError()); ++ ++ sd2 = HeapAlloc(GetProcessHeap(), 0, size); ++ ret = GetKernelObjectSecurity(token, DACL_SECURITY_INFORMATION, sd2, size, &size); ++ ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError()); ++ ++ pAcl2 = (void *)0xdeadbeef; ++ present = FALSE; ++ defaulted = TRUE; ++ ret = GetSecurityDescriptorDacl(sd2, &present, &pAcl2, &defaulted); ++ ok(ret, "GetSecurityDescriptorDacl failed with %u\n", GetLastError()); ++ todo_wine ++ ok(present, "pAcl2 not present\n"); ++ ok(pAcl2 != (void *)0xdeadbeef, "pAcl2 not set\n"); ++ ok(!defaulted, "pAcl2 defaulted\n"); ++ ++ /* check that the ace we add for testing does not already exist! */ ++ if (pAcl2) ++ { ++ index = 0; ++ found = FALSE; ++ while (pGetAce( pAcl2, index++, (void **)&ace )) ++ { ++ if (ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE && EqualSid(&ace->SidStart, psid)) ++ found = TRUE; ++ } ++ ok(!found, "Test ace does already exist!\n"); ++ } ++ ++ exp_access.grfAccessPermissions = GENERIC_ALL; ++ exp_access.grfAccessMode = GRANT_ACCESS; ++ exp_access.grfInheritance = NO_PROPAGATE_INHERIT_ACE; ++ exp_access.Trustee.pMultipleTrustee = NULL; ++ exp_access.Trustee.TrusteeForm = TRUSTEE_IS_SID; ++ exp_access.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; ++ exp_access.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; ++ exp_access.Trustee.ptstrName = (void*)psid; ++ ++ retd = pSetEntriesInAclW(1, &exp_access, pAcl2, &pAclChild); ++ ok(retd == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", retd); ++ ++ memset(sd, 0, sizeof(buffer_sd)); ++ ret = InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION); ++ ok(ret, "InitializeSecurityDescriptor failed with %u\n", GetLastError()); ++ ++ ret = SetSecurityDescriptorDacl(sd, TRUE, pAclChild, FALSE); ++ ok(ret, "SetSecurityDescriptorDacl failed with %u\n", GetLastError()); ++ ++ ret = SetKernelObjectSecurity(token, DACL_SECURITY_INFORMATION, sd); ++ ok(ret, "SetKernelObjectSecurity failed with %u\n", GetLastError()); ++ ++ /* start child process with our modified token */ ++ memset(&startup, 0, sizeof(startup)); ++ startup.cb = sizeof(startup); ++ startup.dwFlags = STARTF_USESHOWWINDOW; ++ startup.wShowWindow = SW_SHOWNORMAL; ++ ++ sprintf(buffer, "%s tests/security.c test_token_sd", myARGV[0]); ++ ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info); ++ ok(ret, "CreateProcess failed with error %u\n", GetLastError()); ++ winetest_wait_child_process(info.hProcess); ++ CloseHandle(info.hProcess); ++ CloseHandle(info.hThread); ++ ++ LocalFree(pAclChild); + LocalFree(psid); + + CloseHandle(token3); +@@ -7260,6 +7333,53 @@ static void test_token_security_descriptor(void) + CloseHandle(token); + } + ++static void test_child_token_sd(void) ++{ ++ BOOL ret, present, defaulted, found; ++ ACCESS_ALLOWED_ACE *ace_acc; ++ SECURITY_DESCRIPTOR *sd; ++ DWORD size, index; ++ HANDLE token; ++ ACL *pAcl; ++ PSID psid; ++ ++ ret = pConvertStringSidToSidA("S-1-5-6", &psid); ++ ok(ret, "ConvertStringSidToSidA failed with %u\n", GetLastError()); ++ ++ ret = OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &token); ++ ok(ret, "OpenProcessToken failed with error %u\n", GetLastError()); ++ ++ ret = GetKernelObjectSecurity(token, DACL_SECURITY_INFORMATION, NULL, 0, &size); ++ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, ++ "GetKernelObjectSecurity failed with %u\n", GetLastError()); ++ ++ sd = HeapAlloc(GetProcessHeap(), 0, size); ++ ret = GetKernelObjectSecurity(token, DACL_SECURITY_INFORMATION, sd, size, &size); ++ ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError()); ++ ++ pAcl = NULL; ++ present = FALSE; ++ defaulted = TRUE; ++ ret = GetSecurityDescriptorDacl(sd, &present, &pAcl, &defaulted); ++ ok(ret, "GetSecurityDescriptorSacl failed with %u\n", GetLastError()); ++ ++ index = 0; ++ found = FALSE; ++ if (present && pAcl) ++ { ++ ok(pAcl->AceCount > 0, "Expected at least one ACE\n"); ++ while (pGetAce( pAcl, index++, (void **)&ace_acc )) ++ { ++ if (ace_acc->Header.AceType == ACCESS_ALLOWED_ACE_TYPE && EqualSid(&ace_acc->SidStart, psid)) ++ found = TRUE; ++ } ++ } ++ ok(!found, "The ACE should not haven been inherited from the parent\n"); ++ ++ LocalFree(psid); ++ HeapFree(GetProcessHeap(), 0, sd); ++} ++ + START_TEST(security) + { + init(); +@@ -7267,7 +7387,10 @@ START_TEST(security) + + if (myARGC >= 3) + { +- test_process_security_child(); ++ if (!strcmp(myARGV[2], "test_token_sd")) ++ test_child_token_sd(); ++ else ++ test_process_security_child(); + return; + } + test_kernel_objects_security(); +@@ -7309,5 +7432,7 @@ START_TEST(security) + test_GetSidIdentifierAuthority(); + test_pseudo_tokens(); + test_GetExplicitEntriesFromAclW(); ++ ++ /* must be the last test, modifies process token */ + test_token_security_descriptor(); + } +-- +2.11.0 + diff --git a/patches/server-LABEL_SECURITY_INFORMATION/0008-advapi32-tests-Show-that-tokens-do-not-inherit-sacls.patch b/patches/server-LABEL_SECURITY_INFORMATION/0008-advapi32-tests-Show-that-tokens-do-not-inherit-sacls.patch new file mode 100644 index 00000000..413a3f8d --- /dev/null +++ b/patches/server-LABEL_SECURITY_INFORMATION/0008-advapi32-tests-Show-that-tokens-do-not-inherit-sacls.patch @@ -0,0 +1,106 @@ +From cbb1140c5de91c1e82414729b72918fb1a9ffd90 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Thu, 12 Jan 2017 05:45:33 +0100 +Subject: advapi32/tests: Show that tokens do not inherit sacls / mandatory + labels while creating child processes. + +--- + dlls/advapi32/tests/security.c | 61 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 61 insertions(+) + +diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c +index 05b0c73edd6..8f0cff78695 100644 +--- a/dlls/advapi32/tests/security.c ++++ b/dlls/advapi32/tests/security.c +@@ -7138,6 +7138,8 @@ static void test_GetExplicitEntriesFromAclW(void) + + static void test_token_security_descriptor(void) + { ++ static SID low_level = {SID_REVISION, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY}, ++ {SECURITY_MANDATORY_LOW_RID}}; + ACCESS_ALLOWED_ACE *ace; + char buffer_sd[SECURITY_DESCRIPTOR_MIN_LENGTH]; + SECURITY_DESCRIPTOR *sd = (SECURITY_DESCRIPTOR *)&buffer_sd, *sd2; +@@ -7312,6 +7314,28 @@ static void test_token_security_descriptor(void) + ret = SetKernelObjectSecurity(token, DACL_SECURITY_INFORMATION, sd); + ok(ret, "SetKernelObjectSecurity failed with %u\n", GetLastError()); + ++ /* The security label is also not inherited */ ++ if (pAddMandatoryAce) ++ { ++ ret = InitializeAcl(pAcl, 256, ACL_REVISION); ++ ok(ret, "InitializeAcl failed with %u\n", GetLastError()); ++ ++ ret = pAddMandatoryAce(pAcl, ACL_REVISION, 0, SYSTEM_MANDATORY_LABEL_NO_WRITE_UP, &low_level); ++ ok(ret, "AddMandatoryAce failed with %u\n", GetLastError()); ++ ++ memset(sd, 0, sizeof(buffer_sd)); ++ ret = InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION); ++ ok(ret, "InitializeSecurityDescriptor failed with %u\n", GetLastError()); ++ ++ ret = SetSecurityDescriptorSacl(sd, TRUE, pAcl, FALSE); ++ ok(ret, "SetSecurityDescriptorSacl failed with %u\n", GetLastError()); ++ ++ ret = SetKernelObjectSecurity(token, LABEL_SECURITY_INFORMATION, sd); ++ ok(ret, "SetKernelObjectSecurity failed with %u\n", GetLastError()); ++ } ++ else ++ win_skip("SYSTEM_MANDATORY_LABEL not supported\n"); ++ + /* start child process with our modified token */ + memset(&startup, 0, sizeof(startup)); + startup.cb = sizeof(startup); +@@ -7335,6 +7359,9 @@ static void test_token_security_descriptor(void) + + static void test_child_token_sd(void) + { ++ static SID low_level = {SID_REVISION, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY}, ++ {SECURITY_MANDATORY_LOW_RID}}; ++ SYSTEM_MANDATORY_LABEL_ACE *ace_label; + BOOL ret, present, defaulted, found; + ACCESS_ALLOWED_ACE *ace_acc; + SECURITY_DESCRIPTOR *sd; +@@ -7378,6 +7405,40 @@ static void test_child_token_sd(void) + + LocalFree(psid); + HeapFree(GetProcessHeap(), 0, sd); ++ ++ if (!pAddMandatoryAce) ++ { ++ win_skip("SYSTEM_MANDATORY_LABEL not supported\n"); ++ return; ++ } ++ ++ ret = GetKernelObjectSecurity(token, LABEL_SECURITY_INFORMATION, NULL, 0, &size); ++ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, ++ "GetKernelObjectSecurity failed with %u\n", GetLastError()); ++ ++ sd = HeapAlloc(GetProcessHeap(), 0, size); ++ ret = GetKernelObjectSecurity(token, LABEL_SECURITY_INFORMATION, sd, size, &size); ++ ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError()); ++ ++ pAcl = NULL; ++ present = FALSE; ++ defaulted = TRUE; ++ ret = GetSecurityDescriptorSacl(sd, &present, &pAcl, &defaulted); ++ ok(ret, "GetSecurityDescriptorSacl failed with %u\n", GetLastError()); ++ ++ index = 0; ++ found = FALSE; ++ if (present && pAcl) ++ { ++ while (pGetAce( pAcl, index++, (void **)&ace_label )) ++ { ++ if (ace_label->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE && EqualSid(&ace_label->SidStart, &low_level)) ++ found = TRUE; ++ } ++ } ++ ok(!found, "Low integrity level should not have been inherited\n"); ++ ++ HeapFree(GetProcessHeap(), 0, sd); + } + + START_TEST(security) +-- +2.11.0 + diff --git a/patches/server-LABEL_SECURITY_INFORMATION/0009-server-Assign-a-default-label-high-to-all-tokens.patch b/patches/server-LABEL_SECURITY_INFORMATION/0009-server-Assign-a-default-label-high-to-all-tokens.patch new file mode 100644 index 00000000..a0f7ab25 --- /dev/null +++ b/patches/server-LABEL_SECURITY_INFORMATION/0009-server-Assign-a-default-label-high-to-all-tokens.patch @@ -0,0 +1,196 @@ +From 43ddf2395d512c436fb8912c81d8596f6a16aaab Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Thu, 12 Jan 2017 05:58:02 +0100 +Subject: server: Assign a default label (high) to all tokens. + +--- + dlls/advapi32/tests/security.c | 42 ++++++++++++++++++++++++++++++++- + server/process.c | 7 ++++++ + server/security.h | 2 ++ + server/token.c | 53 ++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 103 insertions(+), 1 deletion(-) + +diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c +index 8f0cff78695..44321553226 100644 +--- a/dlls/advapi32/tests/security.c ++++ b/dlls/advapi32/tests/security.c +@@ -6436,6 +6436,8 @@ static void test_integrity(void) + {SECURITY_MANDATORY_LOW_RID}}; + static SID medium_level = {SID_REVISION, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY}, + {SECURITY_MANDATORY_MEDIUM_RID}}; ++ static SID high_level = {SID_REVISION, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY}, ++ {SECURITY_MANDATORY_HIGH_RID}}; + SYSTEM_MANDATORY_LABEL_ACE *ace; + char buffer_sd[SECURITY_DESCRIPTOR_MIN_LENGTH]; + SECURITY_DESCRIPTOR *sd2, *sd = (SECURITY_DESCRIPTOR *)&buffer_sd; +@@ -6657,6 +6659,45 @@ static void test_integrity(void) + + HeapFree(GetProcessHeap(), 0, sd2); + CloseHandle(handle); ++ ++ ret = OpenProcessToken(GetCurrentProcess(), READ_CONTROL, &handle); ++ ok(ret, "got %d with %d (expected TRUE)\n", ret, GetLastError()); ++ ++ ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, NULL, 0, &size); ++ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, ++ "GetKernelObjectSecurity failed with %u\n", GetLastError()); ++ ++ sd2 = HeapAlloc(GetProcessHeap(), 0, size); ++ ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd2, size, &size); ++ ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError()); ++ ++ sAcl = (void *)0xdeadbeef; ++ present = FALSE; ++ defaulted = TRUE; ++ ret = GetSecurityDescriptorSacl(sd2, &present, &sAcl, &defaulted); ++ ok(ret, "GetSecurityDescriptorSacl failed with %u\n", GetLastError()); ++ ok(present, "sAcl not present\n"); ++ ok(sAcl != (void *)0xdeadbeef, "sAcl not set\n"); ++ ok(sAcl->AceCount == 1, "Expected 1 ACEs, got %d\n", sAcl->AceCount); ++ ok(!defaulted, "sAcl defaulted\n"); ++ ++ index = 0; ++ found = FALSE; ++ while (pGetAce( sAcl, index++, (void **)&ace )) ++ { ++ if (ace->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE && ++ (EqualSid(&ace->SidStart, &medium_level) || EqualSid(&ace->SidStart, &high_level))) ++ { ++ found = TRUE; ++ ok(ace->Header.AceFlags == 0, "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 flag, got %x\n", ace->Mask); ++ } ++ } ++ ok(found, "Could not find medium/high mandatory label\n"); ++ ++ HeapFree(GetProcessHeap(), 0, sd2); ++ CloseHandle(handle); + } + + static void test_AdjustTokenPrivileges(void) +@@ -7274,7 +7315,6 @@ static void test_token_security_descriptor(void) + defaulted = TRUE; + ret = GetSecurityDescriptorDacl(sd2, &present, &pAcl2, &defaulted); + ok(ret, "GetSecurityDescriptorDacl failed with %u\n", GetLastError()); +- todo_wine + ok(present, "pAcl2 not present\n"); + ok(pAcl2 != (void *)0xdeadbeef, "pAcl2 not set\n"); + ok(!defaulted, "pAcl2 defaulted\n"); +diff --git a/server/process.c b/server/process.c +index f476cfaf0fe..eaf61eaea99 100644 +--- a/server/process.c ++++ b/server/process.c +@@ -574,6 +574,13 @@ struct thread *create_process( int fd, struct thread *parent_thread, int inherit + } + if (!process->handles || !process->token) goto error; + ++ /* Assign high security label to token. The default would be medium, but wine provides ++ * admin access to all applications, so high makes more sense. For further information: ++ * "Default integrity level" at https://msdn.microsoft.com/en-us/library/bb625963.aspx ++ */ ++ if (!token_assign_label( process->token, security_high_label_sid )) ++ goto error; ++ + /* create the main thread */ + if (pipe( request_pipe ) == -1) + { +diff --git a/server/security.h b/server/security.h +index 0342f643187..ee927f91a3d 100644 +--- a/server/security.h ++++ b/server/security.h +@@ -48,11 +48,13 @@ extern const PSID security_local_system_sid; + extern const PSID security_builtin_users_sid; + extern const PSID security_builtin_admins_sid; + extern const PSID security_domain_users_sid; ++extern const PSID security_high_label_sid; + + + /* token functions */ + + extern struct token *token_create_admin(void); ++extern int token_assign_label( struct token *token, PSID label ); + extern struct token *token_duplicate( struct token *src_token, unsigned primary, + int impersonation_level, const struct security_descriptor *sd ); + extern int token_check_privileges( struct token *token, int all_required, +diff --git a/server/token.c b/server/token.c +index 74a97bb1319..99a62de0ffa 100644 +--- a/server/token.c ++++ b/server/token.c +@@ -70,6 +70,7 @@ static const SID interactive_sid = { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, + static const SID anonymous_logon_sid = { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_ANONYMOUS_LOGON_RID } }; + static const SID authenticated_user_sid = { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_AUTHENTICATED_USER_RID } }; + static const SID local_system_sid = { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_LOCAL_SYSTEM_RID } }; ++static const SID high_label_sid = { SID_REVISION, 1, { SECURITY_MANDATORY_LABEL_AUTHORITY }, { SECURITY_MANDATORY_HIGH_RID } }; + static const struct /* same fields as struct SID */ + { + BYTE Revision; +@@ -108,6 +109,7 @@ const PSID security_local_user_sid = (PSID)&local_user_sid; + const PSID security_builtin_admins_sid = (PSID)&builtin_admins_sid; + const PSID security_builtin_users_sid = (PSID)&builtin_users_sid; + const PSID security_domain_users_sid = (PSID)&domain_users_sid; ++const PSID security_high_label_sid = (PSID)&high_label_sid; + + static luid_t prev_luid_value = { 1000, 0 }; + +@@ -631,6 +633,57 @@ struct sid_data + unsigned int subauth[MAX_SUBAUTH_COUNT]; + }; + ++static struct security_descriptor *create_security_label_sd( PSID label_sid ) ++{ ++ size_t sid_len = security_sid_len( label_sid ); ++ size_t sacl_size = sizeof(ACL) + FIELD_OFFSET(SYSTEM_MANDATORY_LABEL_ACE, SidStart) + sid_len; ++ size_t sd_size = sizeof(struct security_descriptor) + sacl_size; ++ SYSTEM_MANDATORY_LABEL_ACE *smla; ++ struct security_descriptor *sd; ++ ACL *sacl; ++ ++ sd = mem_alloc( sd_size ); ++ if (!sd) return NULL; ++ ++ sd->control = SE_SACL_PRESENT; ++ sd->owner_len = 0; ++ sd->group_len = 0; ++ sd->sacl_len = sacl_size; ++ sd->dacl_len = 0; ++ ++ sacl = (ACL *)(sd + 1); ++ sacl->AclRevision = ACL_REVISION; ++ sacl->Sbz1 = 0; ++ sacl->AclSize = sacl_size; ++ sacl->AceCount = 1; ++ sacl->Sbz2 = 0; ++ ++ smla = (SYSTEM_MANDATORY_LABEL_ACE *)(sacl + 1); ++ smla->Header.AceType = SYSTEM_MANDATORY_LABEL_ACE_TYPE; ++ smla->Header.AceFlags = 0; ++ smla->Header.AceSize = FIELD_OFFSET(SYSTEM_MANDATORY_LABEL_ACE, SidStart) + sid_len; ++ smla->Mask = SYSTEM_MANDATORY_LABEL_NO_WRITE_UP; ++ memcpy( &smla->SidStart, label_sid, sid_len ); ++ ++ assert( sd_is_valid( sd, sd_size ) ); ++ return sd; ++} ++ ++int token_assign_label( struct token *token, PSID label ) ++{ ++ struct security_descriptor *sd; ++ int ret = 0; ++ ++ if ((sd = create_security_label_sd( label ))) ++ { ++ /* FIXME: this overwrites the complete SACL, not only the label */ ++ ret = set_sd_defaults_from_token( &token->obj, sd, SACL_SECURITY_INFORMATION, token ); ++ free( sd ); ++ } ++ ++ return ret; ++} ++ + struct token *token_create_admin( void ) + { + struct token *token = NULL; +-- +2.11.0 + diff --git a/patches/server-LABEL_SECURITY_INFORMATION/definition b/patches/server-LABEL_SECURITY_INFORMATION/definition new file mode 100644 index 00000000..8fd1aafd --- /dev/null +++ b/patches/server-LABEL_SECURITY_INFORMATION/definition @@ -0,0 +1,5 @@ +Fixes: Implement support for LABEL_SECURITY_INFORMATION +Depends: advapi32-AddMandatoryAce +Depends: advapi32-GetExplicitEntriesFromAclW +Depends: server-Stored_ACLs +Depends: server-Misc_ACL