From 443d7c2e76d046a5b78112c2faef1ddb9162b2c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rimas=20Misevi=C4=8Dius?= Date: Sat, 25 Nov 2023 13:40:23 +0200 Subject: [PATCH] Disallow "?" and "." hostnames in UNC paths Because "\\?\" means Win32 file namespace and "\\.\" means Win32 device namespace. --- include/upa/url.h | 25 +++++++++++++++++-------- test/test-url.cpp | 2 ++ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/include/upa/url.h b/include/upa/url.h index dc930fe..4bac797 100644 --- a/include/upa/url.h +++ b/include/upa/url.h @@ -2967,13 +2967,22 @@ inline bool is_unc_path(const CharT* first, const CharT* last) ++path_components_count; - // Do not accept a Windows drive letter from the first UNC path - // component, because it is not a valid host name - if (path_components_count == 1 && - pcend - start == 2 && - detail::is_windows_drive(start[0], start[1])) - return false; - + // Check the first UNC path component (hostname) + if (path_components_count == 1) { + switch (pcend - start) { + case 1: + // Do not allow "?" and "." hostnames, because "\\?\" means Win32 file + // namespace and "\\.\" means Win32 device namespace + if (start[0] == '?' || start[0] == '.') + return false; + break; + case 2: + // Do not allow Windows drive letter, because it is not a valid hostname + if (detail::is_windows_drive(start[0], start[1])) + return false; + break; + } + } if (pcend == last) break; start = pcend + 1; // skip '\' } @@ -3129,7 +3138,7 @@ inline std::string path_from_file_url(const url& file_url, file_path_format form } else { // format == file_path_format::windows if (is_host) { - // UNC path cannot have "." hostname, because "\\.\" means DOS devices namespace + // UNC path cannot have "." hostname, because "\\.\" means Win32 device namespace if (hostname == ".") throw url_error(validation_errc::file_url_unsupported_host, "UNC path cannot have \".\" hostname"); // UNC path diff --git a/test/test-url.cpp b/test/test-url.cpp index b3e522b..78a2c89 100644 --- a/test/test-url.cpp +++ b/test/test-url.cpp @@ -641,6 +641,8 @@ TEST_CASE("url_from_file_path") { CHECK_THROWS_AS(upa::url_from_file_path(std::string{ '\\', '\\', 'h', '\\', 'a', '\0', 'b' }), upa::url_error); CHECK_THROWS_AS(upa::url_from_file_path("\\\\C:\\path"), upa::url_error); CHECK_THROWS_AS(upa::url_from_file_path("\\\\C|\\path"), upa::url_error); + CHECK_THROWS_AS(upa::url_from_file_path("\\\\?\\UNC\\?\\name"), upa::url_error); + CHECK_THROWS_AS(upa::url_from_file_path("\\\\?\\UNC\\.\\name"), upa::url_error); // invalid hostname CHECK_THROWS_AS(upa::url_from_file_path("\\\\a b\\path"), upa::url_error); // unsupported pathes