Discard BOM header when parsing the Windows 'hosts' file (#13079)
* Discard BOM header when parsing the Windows 'hosts' file * Cleanup after tests * Format
Blue committed
Jun 10, 2025 at 15:04 UTC
5fd4ffb064ec3ab73c045e2bf86194c18180079f
4 files changed
+39
-8
src/windows/common/filesystem.cpp
+8
-6
@@ -874,16 +874,18 @@ std::filesystem::path wsl::windows::common::filesystem::GetTempFolderPath(_In_ H
874
return GetLocalAppDataPath(userToken) / L"temp";
875
}
876
877
-std::string wsl::windows::common::filesystem::GetWindowsHosts()
877
+std::string wsl::windows::common::filesystem::GetWindowsHosts(const std::filesystem::path& Path)
878
{
879
- // Parse the Windows hosts file.
880
- std::wstring SystemDirectory;
881
- THROW_IF_FAILED(wil::GetSystemDirectoryW(SystemDirectory));
882
-
883
- auto Path = std::filesystem::path(std::move(SystemDirectory)) / L"drivers" / L"etc" / L"hosts";
879
std::ifstream Stream(Path.c_str());
880
THROW_HR_IF_MSG(E_FAIL, (Stream.bad() || !Stream.is_open()), "errno = %d", errno);
881
882
+ // Discard any BOM header.
883
+ int potentialHeader[] = {Stream.get(), Stream.get(), Stream.get()};
884
+ if (potentialHeader[0] != 0xEF || potentialHeader[1] != 0xBB || potentialHeader[2] != 0xBF)
885
+ {
886
+ Stream.seekg(0); // Reset the position to beginning of the file if no BOM header is found.
887
+ }
888
+
889
std::string WindowsHosts;
890
std::string Line;
891
while (std::getline(Stream, Line))
src/windows/common/filesystem.hpp
+1
-1
@@ -156,7 +156,7 @@ std::filesystem::path GetTempFilename();
156
157
std::filesystem::path GetTempFolderPath(_In_ HANDLE userToken);
158
159
-std::string GetWindowsHosts();
159
+std::string GetWindowsHosts(const std::filesystem::path& Path);
160
161
/// <summary>
162
/// Opens a directory handle with read/execute, optionally also write, & full sharing. The path
src/windows/common/helpers.cpp
+7
-1
@@ -294,7 +294,13 @@ std::vector<gsl::byte> wsl::windows::common::helpers::GenerateConfigurationMessa
294
// N.B. failures generating the hosts string are non-fatal.
295
try
296
{
297
- windowsHosts = filesystem::GetWindowsHosts();
297
+
298
+ // Parse the Windows hosts file.
299
+ std::wstring SystemDirectory;
300
+ THROW_IF_FAILED(wil::GetSystemDirectoryW(SystemDirectory));
301
+
302
+ windowsHosts =
303
+ filesystem::GetWindowsHosts(std::filesystem::path(std::move(SystemDirectory)) / L"drivers" / L"etc" / L"hosts");
304
}
305
CATCH_LOG()
306
}
test/windows/UnitTests.cpp
+23
@@ -5995,5 +5995,28 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n",
5995
VERIFY_ARE_EQUAL(err, L"");
5996
}
5997
5998
+ TEST_METHOD(EtcHostsParsing)
5999
+ {
6000
+ constexpr auto inputFileName = L"test-etc-hosts.txt";
6001
+
6002
+ auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, []() { DeleteFile(inputFileName); });
6003
+
6004
+ auto validate = [](const std::string& Input, const std::string& ExpectedOutput) {
6005
+ wil::unique_handle inputFile{CreateFile(inputFileName, GENERIC_WRITE, FILE_SHARE_READ, nullptr, CREATE_ALWAYS, 0, nullptr)};
6006
+
6007
+ VERIFY_IS_TRUE(WriteFile(inputFile.get(), Input.c_str(), static_cast<DWORD>(Input.size()), nullptr, nullptr));
6008
+
6009
+ auto output = wsl::windows::common::filesystem::GetWindowsHosts(inputFileName);
6010
+
6011
+ VERIFY_ARE_EQUAL(ExpectedOutput, output);
6012
+ };
6013
+
6014
+ validate("127.0.0.1 microsoft.com", "127.0.0.1\tmicrosoft.com\n");
6015
+ validate("\xEF\xBB\xBF 127.0.0.1 microsoft.com", "127.0.0.1\tmicrosoft.com\n"); // Validate that BOM headers are ignored.
6016
+ validate("#Comment 127.0.0.1 microsoft.com windows.microsoft.com\n#AnotherComment", "");
6017
+ validate(
6018
+ "#Comment 127.0.0.1 microsoft.com windows.microsoft.com\n#AnotherComment\n127.0.0.1 wsl.dev", "127.0.0.1\twsl.dev\n");
6019
+ }
6020
+
6021
}; // namespace UnitTests
6022
} // namespace UnitTests