| 4357 | } |
| 4358 | |
| 4359 | static bool win_runtime_directory_secure(const wchar_t *runtime_dir) { |
| 4360 | win_security_t security; |
| 4361 | if (!win_security_init(&security)) { |
| 4362 | return false; |
| 4363 | } |
| 4364 | bool created = CreateDirectoryW(runtime_dir, &security.directory_attributes) != 0; |
| 4365 | if (!created && GetLastError() != ERROR_ALREADY_EXISTS) { |
| 4366 | win_security_destroy(&security); |
| 4367 | return false; |
| 4368 | } |
| 4369 | DWORD attributes = GetFileAttributesW(runtime_dir); |
| 4370 | if (attributes == INVALID_FILE_ATTRIBUTES || (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0 || |
| 4371 | (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { |
| 4372 | win_security_destroy(&security); |
| 4373 | return false; |
| 4374 | } |
| 4375 | HANDLE directory = |
| 4376 | CreateFileW(runtime_dir, READ_CONTROL | WRITE_DAC | WRITE_OWNER, |
| 4377 | FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, |
| 4378 | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); |
| 4379 | bool can_write_owner = directory != INVALID_HANDLE_VALUE; |
| 4380 | if (!can_write_owner) { |
| 4381 | directory = |
| 4382 | CreateFileW(runtime_dir, READ_CONTROL | WRITE_DAC, |
| 4383 | FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, |
| 4384 | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); |
| 4385 | } |
| 4386 | if (directory == INVALID_HANDLE_VALUE) { |
| 4387 | win_security_destroy(&security); |
| 4388 | return false; |
| 4389 | } |
| 4390 | BY_HANDLE_FILE_INFORMATION file_info; |
| 4391 | bool valid_handle = GetFileInformationByHandle(directory, &file_info) != 0 && |
| 4392 | (file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0 && |
| 4393 | (file_info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0; |
| 4394 | bool owner_exact = valid_handle && win_file_owner_secure(&security, directory, true); |
| 4395 | /* One-time normalization of the admin-group default-owner artifact: a |
| 4396 | * directory created by plain mkdir under an Administrators-default-owner |
| 4397 | * token (standard policy on Windows Server) is born owned by BUILTIN\ |
| 4398 | * Administrators even though it is this account's own private dir. A |
| 4399 | * TRUSTED owner (the launcher's directory policy: SYSTEM, Administrators, |
| 4400 | * TrustedInstaller) is re-stamped to the exact token user inside the same |
| 4401 | * repair that already re-protects the DACL; any other owner remains |
| 4402 | * refused, and the final validation below still demands the exact user. */ |
| 4403 | bool owner_ok = owner_exact || (valid_handle && can_write_owner && |
| 4404 | win_file_owner_secure(&security, directory, false)); |
| 4405 | /* Re-stamp only when the directory is not ALREADY correct. |
| 4406 | * |
| 4407 | * This used to fire on every process start, whether or not anything was |
| 4408 | * wrong. Two costs, both observed in the field: |
| 4409 | * |
| 4410 | * - It rewrites the security descriptor of a directory that already has |
| 4411 | * the right one, and Windows propagates that to children. #1601 counted |
| 4412 | * ELEVEN "Security change" USN records against a single _config.db in |
| 4413 | * one day, none of which changed anything. |
| 4414 | * - Every rewrite is a window. #1620 loses an atomic publish to exactly |
| 4415 | * this: MoveFileEx needs DELETE on the destination, and a concurrent |
| 4416 | * re-protect of the parent is a chance to be refused for a state that is |
no test coverage detected