| 4040 | } |
| 4041 | |
| 4042 | static bool win_file_acl_secure(win_security_t *security, HANDLE file, DWORD mutation) { |
| 4043 | PACL dacl = NULL; |
| 4044 | PSECURITY_DESCRIPTOR descriptor = NULL; |
| 4045 | DWORD status = security->get_security_info(file, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, |
| 4046 | NULL, NULL, &dacl, NULL, &descriptor); |
| 4047 | ACL_SIZE_INFORMATION information; |
| 4048 | memset(&information, 0, sizeof(information)); |
| 4049 | bool secure = |
| 4050 | status == ERROR_SUCCESS && descriptor && dacl && security->is_valid_acl(dacl) && |
| 4051 | security->get_acl_information(dacl, &information, sizeof(information), AclSizeInformation); |
| 4052 | enum { |
| 4053 | WIN_FILE_ACE_ALLOW = 0x00, |
| 4054 | WIN_FILE_ACE_DENY = 0x01, |
| 4055 | WIN_FILE_ACE_DENY_OBJECT = 0x06, |
| 4056 | WIN_FILE_ACE_DENY_CALLBACK = 0x0a, |
| 4057 | WIN_FILE_ACE_DENY_CALLBACK_OBJECT = 0x0c, |
| 4058 | }; |
| 4059 | for (DWORD index = 0U; secure && index < information.AceCount; index++) { |
| 4060 | void *opaque = NULL; |
| 4061 | if (!security->get_ace(dacl, index, &opaque) || !opaque) { |
| 4062 | secure = false; |
| 4063 | break; |
| 4064 | } |
| 4065 | ACE_HEADER *header = opaque; |
| 4066 | if (header->AceType == WIN_FILE_ACE_DENY || header->AceType == WIN_FILE_ACE_DENY_OBJECT || |
| 4067 | header->AceType == WIN_FILE_ACE_DENY_CALLBACK || |
| 4068 | header->AceType == WIN_FILE_ACE_DENY_CALLBACK_OBJECT) { |
| 4069 | continue; |
| 4070 | } |
| 4071 | size_t sid_offset = offsetof(ACCESS_ALLOWED_ACE, SidStart); |
| 4072 | if (header->AceType != WIN_FILE_ACE_ALLOW || (size_t)header->AceSize < sid_offset + 8U) { |
| 4073 | secure = false; |
| 4074 | break; |
| 4075 | } |
| 4076 | const ACCESS_ALLOWED_ACE *ace = opaque; |
| 4077 | if ((ace->Mask & mutation) == 0U) { |
| 4078 | continue; |
| 4079 | } |
| 4080 | const uint8_t *sid = (const uint8_t *)&ace->SidStart; |
| 4081 | size_t sid_capacity = (size_t)header->AceSize - sid_offset; |
| 4082 | bool creator_owner_inherit_only = (header->AceFlags & INHERIT_ONLY_ACE) != 0U; |
| 4083 | if (!win_bounded_sid_trusted(security, sid, sid_capacity, creator_owner_inherit_only)) { |
| 4084 | /* Name the untrusted identity class so a harness/profile ACL leak |
| 4085 | * (an inherited Users / Authenticated Users / Everyone ACE) is |
| 4086 | * distinguishable from a genuinely hostile grant. */ |
| 4087 | const char *sid_class = |
| 4088 | security->is_well_known_sid((PSID)sid, WinBuiltinUsersSid) ? "BUILTIN\\Users" |
| 4089 | : security->is_well_known_sid((PSID)sid, WinAuthenticatedUserSid) |
| 4090 | ? "Authenticated Users" |
| 4091 | : security->is_well_known_sid((PSID)sid, WinWorldSid) ? "Everyone" |
| 4092 | : security->is_well_known_sid((PSID)sid, WinInteractiveSid) ? "INTERACTIVE" |
| 4093 | : "other"; |
| 4094 | /* Print the raw SID too: an "other" class is a specific account, |
| 4095 | * and only its string form identifies the harness/profile leak. */ |
| 4096 | wchar_t *sid_text = NULL; |
| 4097 | char sid_utf8[96] = "<unprintable>"; |
| 4098 | if (ConvertSidToStringSidW((PSID)sid, &sid_text) && sid_text) { |
| 4099 | (void)WideCharToMultiByte(CP_UTF8, 0, sid_text, -1, sid_utf8, (int)sizeof(sid_utf8), |
no test coverage detected