From 3ac72e4a5dd6203414408e8d54d545ec704d76e2 Mon Sep 17 00:00:00 2001 From: Brennan Date: Mon, 12 May 2025 16:30:21 -0700 Subject: [PATCH 1/3] [IIS] Manually parse exe bitness --- .../CommonLib/HostFxrResolver.cpp | 66 ++++++++++++++++--- .../CommonLib/HostFxrResolver.h | 2 + 2 files changed, 58 insertions(+), 10 deletions(-) diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.cpp b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.cpp index eea76ef70a35..776e3fbc42b9 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.cpp @@ -393,7 +393,7 @@ HostFxrResolver::GetAbsolutePathToDotnetFromHostfxr(const fs::path& hostfxrPath) // Tries to call where.exe to find the location of dotnet.exe. // Will check that the bitness of dotnet matches the current // worker process bitness. -// Returns true if a valid dotnet was found, else false.R +// Returns true if a valid dotnet was found, else false. // std::optional HostFxrResolver::InvokeWhereToFindDotnet() @@ -416,7 +416,6 @@ HostFxrResolver::InvokeWhereToFindDotnet() STRU struDotnetSubstring; STRU struDotnetLocationsString; DWORD dwNumBytesRead = 0; - DWORD dwBinaryType = 0; INT index = 0; INT prevIndex = 0; std::optional result; @@ -521,14 +520,7 @@ HostFxrResolver::InvokeWhereToFindDotnet() LOG_INFOF(L"Processing entry '%ls'", struDotnetSubstring.QueryStr()); - if (LOG_LAST_ERROR_IF(!GetBinaryTypeW(struDotnetSubstring.QueryStr(), &dwBinaryType))) - { - continue; - } - - LOG_INFOF(L"Binary type %d", dwBinaryType); - - if (fIsCurrentProcess64Bit == (dwBinaryType == SCS_64BIT_BINARY)) + if (fIsCurrentProcess64Bit == IsX64(struDotnetSubstring.QueryStr())) { // The bitness of dotnet matched with the current worker process bitness. return std::make_optional(struDotnetSubstring.QueryStr()); @@ -539,6 +531,60 @@ HostFxrResolver::InvokeWhereToFindDotnet() return result; } +BOOL HostFxrResolver::IsX64(const WCHAR* dotnetPath) +{ + std::ifstream file(dotnetPath, std::ios::binary); + if (!file.is_open()) + { + LOG_INFOF(L"Failed to open file %ls", dotnetPath); + return false; + } + + // Read the DOS header + IMAGE_DOS_HEADER dosHeader; + file.read(reinterpret_cast(&dosHeader), sizeof(dosHeader)); + if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE) // 'MZ' + { + LOG_INFOF(L"%ls is not a valid executable file (missing MZ header).", dotnetPath); + return false; + } + + // Seek to the PE header + file.seekg(dosHeader.e_lfanew, std::ios::beg); + + // Read the PE header + DWORD peSignature; + file.read(reinterpret_cast(&peSignature), sizeof(peSignature)); + if (peSignature != IMAGE_NT_SIGNATURE) // 'PE\0\0' + { + LOG_INFOF(L"%ls is not a valid PE file (missing PE header).", dotnetPath); + return false; + } + + // Read the file header + IMAGE_FILE_HEADER fileHeader; + file.read(reinterpret_cast(&fileHeader), sizeof(fileHeader)); + + // Read the optional header magic field + WORD magic; + file.read(reinterpret_cast(&magic), sizeof(magic)); + + // Determine the architecture based on the magic value + if (magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + LOG_INFOF(L"%ls is 32-bit", dotnetPath); + return false; + } + else if (magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) + { + LOG_INFOF(L"%ls is 64-bit", dotnetPath); + return true; + } + + LOG_INFOF(L"%ls is unknown architecture %i", dotnetPath, fileHeader.Machine); + return false; +} + std::optional HostFxrResolver::GetAbsolutePathToDotnetFromProgramFiles() { diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.h b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.h index 519f6df52c97..08ec650aec54 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.h @@ -74,6 +74,8 @@ class HostFxrResolver const std::filesystem::path & requestedPath ); + static BOOL IsX64(const WCHAR* dotnetPath); + struct LocalFreeDeleter { void operator ()(_In_ LPWSTR* ptr) const From a52751b83b11b4669dbc93102e11acd7852be997 Mon Sep 17 00:00:00 2001 From: Brennan Date: Tue, 13 May 2025 17:15:58 -0700 Subject: [PATCH 2/3] init --- .../AspNetCoreModuleV2/CommonLib/HostFxrResolver.cpp | 10 +++++----- src/Servers/IIS/build/Build.Lib.Settings | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.cpp b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.cpp index 776e3fbc42b9..5a7aed693b33 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.cpp @@ -197,7 +197,7 @@ HostFxrResolver::TryGetHostFxrPath( size_t size = MAX_PATH * 2; hostfxrPath.resize(size); - get_hostfxr_parameters params; + get_hostfxr_parameters params{}; params.size = sizeof(get_hostfxr_parameters); params.assembly_path = applicationPath.c_str(); params.dotnet_root = dotnetRoot.c_str(); @@ -541,7 +541,7 @@ BOOL HostFxrResolver::IsX64(const WCHAR* dotnetPath) } // Read the DOS header - IMAGE_DOS_HEADER dosHeader; + IMAGE_DOS_HEADER dosHeader{}; file.read(reinterpret_cast(&dosHeader), sizeof(dosHeader)); if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE) // 'MZ' { @@ -553,7 +553,7 @@ BOOL HostFxrResolver::IsX64(const WCHAR* dotnetPath) file.seekg(dosHeader.e_lfanew, std::ios::beg); // Read the PE header - DWORD peSignature; + DWORD peSignature{}; file.read(reinterpret_cast(&peSignature), sizeof(peSignature)); if (peSignature != IMAGE_NT_SIGNATURE) // 'PE\0\0' { @@ -562,11 +562,11 @@ BOOL HostFxrResolver::IsX64(const WCHAR* dotnetPath) } // Read the file header - IMAGE_FILE_HEADER fileHeader; + IMAGE_FILE_HEADER fileHeader{}; file.read(reinterpret_cast(&fileHeader), sizeof(fileHeader)); // Read the optional header magic field - WORD magic; + WORD magic{}; file.read(reinterpret_cast(&magic), sizeof(magic)); // Determine the architecture based on the magic value diff --git a/src/Servers/IIS/build/Build.Lib.Settings b/src/Servers/IIS/build/Build.Lib.Settings index 0dcba8c2011a..9327eb363771 100644 --- a/src/Servers/IIS/build/Build.Lib.Settings +++ b/src/Servers/IIS/build/Build.Lib.Settings @@ -9,7 +9,7 @@ - false + true _LIB;%(PreprocessorDefinitions) true From e47874a61679faed823bbb9340896c5c66b0b3c7 Mon Sep 17 00:00:00 2001 From: Brennan Date: Mon, 19 May 2025 16:47:49 -0700 Subject: [PATCH 3/3] fb --- .../IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.cpp b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.cpp index 5a7aed693b33..8233d68a115e 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.cpp @@ -533,10 +533,12 @@ HostFxrResolver::InvokeWhereToFindDotnet() BOOL HostFxrResolver::IsX64(const WCHAR* dotnetPath) { + // Errors while reading from the file shouldn't throw unless + // file.exception(bits) is set std::ifstream file(dotnetPath, std::ios::binary); if (!file.is_open()) { - LOG_INFOF(L"Failed to open file %ls", dotnetPath); + LOG_TRACEF(L"Failed to open file %ls", dotnetPath); return false; } @@ -545,7 +547,7 @@ BOOL HostFxrResolver::IsX64(const WCHAR* dotnetPath) file.read(reinterpret_cast(&dosHeader), sizeof(dosHeader)); if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE) // 'MZ' { - LOG_INFOF(L"%ls is not a valid executable file (missing MZ header).", dotnetPath); + LOG_TRACEF(L"%ls is not a valid executable file (missing MZ header).", dotnetPath); return false; } @@ -557,7 +559,7 @@ BOOL HostFxrResolver::IsX64(const WCHAR* dotnetPath) file.read(reinterpret_cast(&peSignature), sizeof(peSignature)); if (peSignature != IMAGE_NT_SIGNATURE) // 'PE\0\0' { - LOG_INFOF(L"%ls is not a valid PE file (missing PE header).", dotnetPath); + LOG_TRACEF(L"%ls is not a valid PE file (missing PE header).", dotnetPath); return false; }