| 3964 | } |
| 3965 | |
| 3966 | static bool win_file_acl_secure(win_security_t *security, HANDLE file, DWORD mutation) { |
| 3967 | PACL dacl = NULL; |
| 3968 | PSECURITY_DESCRIPTOR descriptor = NULL; |
| 3969 | DWORD status = security->get_security_info(file, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, |
| 3970 | NULL, NULL, &dacl, NULL, &descriptor); |
| 3971 | ACL_SIZE_INFORMATION information; |
| 3972 | memset(&information, 0, sizeof(information)); |
| 3973 | bool secure = |
| 3974 | status == ERROR_SUCCESS && descriptor && dacl && security->is_valid_acl(dacl) && |
| 3975 | security->get_acl_information(dacl, &information, sizeof(information), AclSizeInformation); |
| 3976 | enum { |
| 3977 | WIN_FILE_ACE_ALLOW = 0x00, |
| 3978 | WIN_FILE_ACE_DENY = 0x01, |
| 3979 | WIN_FILE_ACE_DENY_OBJECT = 0x06, |
| 3980 | WIN_FILE_ACE_DENY_CALLBACK = 0x0a, |
| 3981 | WIN_FILE_ACE_DENY_CALLBACK_OBJECT = 0x0c, |
| 3982 | }; |
| 3983 | for (DWORD index = 0U; secure && index < information.AceCount; index++) { |
| 3984 | void *opaque = NULL; |
| 3985 | if (!security->get_ace(dacl, index, &opaque) || !opaque) { |
| 3986 | secure = false; |
| 3987 | break; |
| 3988 | } |
| 3989 | ACE_HEADER *header = opaque; |
| 3990 | if (header->AceType == WIN_FILE_ACE_DENY || header->AceType == WIN_FILE_ACE_DENY_OBJECT || |
| 3991 | header->AceType == WIN_FILE_ACE_DENY_CALLBACK || |
| 3992 | header->AceType == WIN_FILE_ACE_DENY_CALLBACK_OBJECT) { |
| 3993 | continue; |
| 3994 | } |
| 3995 | size_t sid_offset = offsetof(ACCESS_ALLOWED_ACE, SidStart); |
| 3996 | if (header->AceType != WIN_FILE_ACE_ALLOW || (size_t)header->AceSize < sid_offset + 8U) { |
| 3997 | secure = false; |
| 3998 | break; |
| 3999 | } |
| 4000 | const ACCESS_ALLOWED_ACE *ace = opaque; |
| 4001 | if ((ace->Mask & mutation) == 0U) { |
| 4002 | continue; |
| 4003 | } |
| 4004 | const uint8_t *sid = (const uint8_t *)&ace->SidStart; |
| 4005 | size_t sid_capacity = (size_t)header->AceSize - sid_offset; |
| 4006 | bool creator_owner_inherit_only = (header->AceFlags & INHERIT_ONLY_ACE) != 0U; |
| 4007 | if (!win_bounded_sid_trusted(security, sid, sid_capacity, creator_owner_inherit_only)) { |
| 4008 | /* Name the untrusted identity class so a harness/profile ACL leak |
| 4009 | * (an inherited Users / Authenticated Users / Everyone ACE) is |
| 4010 | * distinguishable from a genuinely hostile grant. */ |
| 4011 | const char *sid_class = |
| 4012 | security->is_well_known_sid((PSID)sid, WinBuiltinUsersSid) ? "BUILTIN\\Users" |
| 4013 | : security->is_well_known_sid((PSID)sid, WinAuthenticatedUserSid) |
| 4014 | ? "Authenticated Users" |
| 4015 | : security->is_well_known_sid((PSID)sid, WinWorldSid) ? "Everyone" |
| 4016 | : security->is_well_known_sid((PSID)sid, WinInteractiveSid) ? "INTERACTIVE" |
| 4017 | : "other"; |
| 4018 | /* Print the raw SID too: an "other" class is a specific account, |
| 4019 | * and only its string form identifies the harness/profile leak. */ |
| 4020 | wchar_t *sid_text = NULL; |
| 4021 | char sid_utf8[96] = "<unprintable>"; |
| 4022 | if (ConvertSidToStringSidW((PSID)sid, &sid_text) && sid_text) { |
| 4023 | (void)WideCharToMultiByte(CP_UTF8, 0, sid_text, -1, sid_utf8, (int)sizeof(sid_utf8), |
no test coverage detected