-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Reject non-empty directories for new WSLC session storage #40655
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
7b5b423
d88f735
ba8a228
81268fa
5762bb3
e5aa1ba
48ed435
8c99886
d8f44ff
b3b908b
61a3c6b
45b2731
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,6 +34,7 @@ using wsl::windows::service::wslc::WSLCVirtualMachine; | |
| constexpr auto c_containerdStorage = "/var/lib/docker"; | ||
| constexpr auto c_containerdSocket = "/run/containerd/containerd.sock"; | ||
| constexpr auto c_dockerdReadyLogLine = "API listen on /var/run/docker.sock"; | ||
| constexpr auto c_storageVhdFilename = L"storage.vhdx"; | ||
| constexpr DWORD c_processTerminateTimeoutMs = 30 * 1000; | ||
| constexpr DWORD c_processKillTimeoutMs = 10 * 1000; | ||
|
|
||
|
|
@@ -285,6 +286,57 @@ try | |
| TraceLoggingValue(m_displayName.c_str(), "DisplayName"), | ||
| TraceLoggingValue(Settings->CreatorPid, "CreatorPid")); | ||
|
|
||
| // Validate storage path before creating VM resources (Terminate() would clobber the error). | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What causes Terminate() to clobber the error in that case ? |
||
| if (Settings->StoragePath != nullptr) | ||
| { | ||
| std::filesystem::path storagePath{Settings->StoragePath}; | ||
| THROW_HR_WITH_USER_ERROR_IF(E_INVALIDARG, Localization::MessagePathNotAbsolute(Settings->StoragePath), !storagePath.is_absolute()); | ||
|
|
||
| // MSVC's std::filesystem sets ec to ERROR_FILE_NOT_FOUND / ERROR_PATH_NOT_FOUND | ||
| // for non-existent paths. Filter those out — only throw on real failures. | ||
| auto throwOnRealFsError = [](const std::error_code& ec, const std::filesystem::path& path, const char* op) { | ||
| if (ec && ec.value() != ERROR_FILE_NOT_FOUND && ec.value() != ERROR_PATH_NOT_FOUND) | ||
| { | ||
| THROW_IF_WIN32_ERROR_MSG(ec.value(), "%hs failed for %ls", op, path.c_str()); | ||
| } | ||
| }; | ||
|
|
||
| std::error_code ec; | ||
| const auto vhdPath = storagePath / c_storageVhdFilename; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: We could set m_storageVhdPath here so we don't need to duplicate this in ConfigureStorage()
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Asking because I think we should keep that logic in ConfigureStorage if possible, because there we already check if the VHD exists or not, so we could have the logic to fail if the directory is not empty there, which should help simplify this |
||
| const bool vhdExists = std::filesystem::exists(vhdPath, ec); | ||
| throwOnRealFsError(ec, vhdPath, "exists"); | ||
|
|
||
|
beena352 marked this conversation as resolved.
|
||
| THROW_HR_WITH_USER_ERROR_IF( | ||
| HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), | ||
| Localization::MessageWslcSessionStorageNotFound(Settings->StoragePath), | ||
| !vhdExists && WI_IsFlagSet(Settings->StorageFlags, WSLCSessionStorageFlagsNoCreate)); | ||
|
|
||
| // Only check emptiness for new sessions. Existing sessions are identified by their VHD. | ||
| if (!vhdExists) | ||
| { | ||
| const bool isDir = std::filesystem::is_directory(storagePath, ec); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we always call is_empty, and look at is_empty's error on failure so we don't need to specifically handle the isDir vs !isDir case ourselves ? |
||
| throwOnRealFsError(ec, storagePath, "is_directory"); | ||
|
|
||
| if (isDir) | ||
| { | ||
| const bool empty = std::filesystem::is_empty(storagePath, ec); | ||
| THROW_IF_WIN32_ERROR_MSG(ec.value(), "is_empty failed for %ls", storagePath.c_str()); | ||
|
|
||
| THROW_HR_WITH_USER_ERROR_IF(E_INVALIDARG, Localization::MessageWslcSessionStorageMustBeEmpty(storagePath.c_str()), !empty); | ||
| } | ||
| else | ||
| { | ||
| const bool pathExists = std::filesystem::exists(storagePath, ec); | ||
| throwOnRealFsError(ec, storagePath, "exists"); | ||
|
|
||
| THROW_HR_WITH_USER_ERROR_IF(E_INVALIDARG, Localization::MessageWslcSessionStorageNotADirectory(storagePath.c_str()), pathExists); | ||
|
|
||
| std::filesystem::create_directories(storagePath, ec); | ||
| THROW_IF_WIN32_ERROR_MSG(ec.value(), "create_directories failed for %ls", storagePath.c_str()); | ||
| } | ||
|
beena352 marked this conversation as resolved.
beena352 marked this conversation as resolved.
|
||
| } | ||
| } | ||
|
|
||
| // Create the VM. | ||
| m_virtualMachine.emplace(Vm, Settings, m_sessionTerminatingEvent.get()); | ||
|
|
||
|
|
@@ -356,10 +408,9 @@ void WSLCSession::ConfigureStorage(const WSLCSessionInitSettings& Settings, PSID | |
| return; | ||
| } | ||
|
|
||
| // Storage path validation is done in Initialize() before any VM resources are created. | ||
| std::filesystem::path storagePath{Settings.StoragePath}; | ||
| THROW_HR_WITH_USER_ERROR_IF(E_INVALIDARG, Localization::MessagePathNotAbsolute(Settings.StoragePath), !storagePath.is_absolute()); | ||
|
|
||
| m_storageVhdPath = storagePath / "storage.vhdx"; | ||
| m_storageVhdPath = storagePath / c_storageVhdFilename; | ||
|
|
||
| std::string diskDevice; | ||
| std::optional<ULONG> diskLun{}; | ||
|
|
@@ -388,15 +439,10 @@ void WSLCSession::ConfigureStorage(const WSLCSessionInitSettings& Settings, PSID | |
| "Failed to attach vhd: %ls", | ||
| m_storageVhdPath.c_str()); | ||
|
|
||
| THROW_HR_WITH_USER_ERROR_IF( | ||
| HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), | ||
| Localization::MessageWslcSessionStorageNotFound(Settings.StoragePath), | ||
| WI_IsFlagSet(Settings.StorageFlags, WSLCSessionStorageFlagsNoCreate)); | ||
|
|
||
| // If the VHD wasn't found, create it. | ||
| WSL_LOG("CreateStorageVhd", TraceLoggingValue(m_storageVhdPath.c_str(), "StorageVhdPath")); | ||
|
|
||
| std::filesystem::create_directories(storagePath); | ||
|
|
||
| wsl::core::filesystem::CreateVhd(m_storageVhdPath.c_str(), Settings.MaximumStorageSizeMb * _1MB, UserSid, false, false); | ||
| vhdCreated = true; | ||
|
beena352 marked this conversation as resolved.
|
||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: This could be changed to just THROW_HR, since we know it's a failed HRESULT