From dd353b2418a1fc537b85c284e2cd7bbcb4907acc Mon Sep 17 00:00:00 2001 From: Steve Pfister Date: Sat, 29 Aug 2026 11:47:37 -0400 Subject: [PATCH 1/2] Disable read-only GS cookie protection on Apple platforms InitGSCookie() places s_gsCookie in Apple's __DATA_CONST,__const segment (via READONLY_ATTR/const) and then temporarily calls ClrVirtualProtect(PAGE_READWRITE) to initialize it. Apple marks the whole __DATA_CONST segment immutable at load, so that mprotect call fails with ERROR_INVALID_ACCESS, and coreclr_initialize returns HRESULT 0x8007000C. This is most visible when hosting CoreCLR inside Apple's stock LLDB with PAL_MachExceptionMode set to avoid Apple's guarded Mach exception ports. NativeAOT hit the same issue and fixed it in #99173 by disabling FEATURE_READONLY_GS_COOKIE on Apple (src/coreclr/nativeaot/Runtime). Mirror that fix for CoreCLR: keep s_gsCookie in ordinary writable data and skip the now-unnecessary protection transitions in InitGSCookie() on TARGET_APPLE, while keeping the existing read-only placement and randomized initialization on all other platforms. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- src/coreclr/vm/ceemain.cpp | 4 ++++ src/coreclr/vm/vars.cpp | 4 ++++ src/coreclr/vm/vars.hpp | 10 ++++++++++ 3 files changed, 18 insertions(+) diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index e1c06d2c629797..188cdb9abd50b4 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -470,6 +470,7 @@ void InitGSCookie() volatile GSCookie * pGSCookiePtr = GetProcessGSCookiePtr(); +#ifdef FEATURE_READONLY_GS_COOKIE // The GS cookie is stored in a read only data segment DWORD oldProtection; if(!ClrVirtualProtect((LPVOID)pGSCookiePtr, sizeof(GSCookie), PAGE_READWRITE, &oldProtection)) @@ -481,6 +482,7 @@ void InitGSCookie() // PAL layer is unable to extract old protection for regions that were not allocated using VirtualAlloc oldProtection = PAGE_READONLY; #endif // TARGET_UNIX +#endif // FEATURE_READONLY_GS_COOKIE #ifndef TARGET_UNIX // The GSCookie cannot be in a writeable page @@ -507,10 +509,12 @@ void InitGSCookie() val ++; *pGSCookiePtr = val; +#ifdef FEATURE_READONLY_GS_COOKIE if(!ClrVirtualProtect((LPVOID)pGSCookiePtr, sizeof(GSCookie), oldProtection, &oldProtection)) { ThrowLastError(); } +#endif // FEATURE_READONLY_GS_COOKIE } Volatile g_bIsGarbageCollectorFullyInitialized = FALSE; diff --git a/src/coreclr/vm/vars.cpp b/src/coreclr/vm/vars.cpp index 57046ff71c5a8b..ae813d80f56c72 100644 --- a/src/coreclr/vm/vars.cpp +++ b/src/coreclr/vm/vars.cpp @@ -252,7 +252,11 @@ void OBJECTREF_EnumMemoryRegions(OBJECTREF ref) // // We need the following to be the compiler's notion of volatile. // +#ifdef FEATURE_READONLY_GS_COOKIE extern "C" RAW_KEYWORD(volatile) const GSCookie s_gsCookie = 0; +#else +extern "C" RAW_KEYWORD(volatile) GSCookie s_gsCookie = 0; +#endif #else __GlobalVal< GSCookie > s_gsCookie(&DacGlobals::dac__s_gsCookie); diff --git a/src/coreclr/vm/vars.hpp b/src/coreclr/vm/vars.hpp index 6960585b9e7482..d78923ae1d06c2 100644 --- a/src/coreclr/vm/vars.hpp +++ b/src/coreclr/vm/vars.hpp @@ -593,12 +593,22 @@ typedef DPTR(GSCookie) PTR_GSCookie; #define READONLY_ATTR __attribute__((READONLY_ATTR_ARGS)) #endif +// Apple's __DATA_CONST segment is immutable at runtime, so InitGSCookie's ClrVirtualProtect +// call fails there (see nativeaot/Runtime for the same FEATURE_READONLY_GS_COOKIE guard). +#ifndef TARGET_APPLE +#define FEATURE_READONLY_GS_COOKIE +#endif + #ifndef DACCESS_COMPILE // const is so that it gets placed in the .text section (which is read-only) // volatile is so that accesses to it do not get optimized away because of the const // +#ifdef FEATURE_READONLY_GS_COOKIE extern "C" RAW_KEYWORD(volatile) READONLY_ATTR const GSCookie s_gsCookie; +#else +extern "C" RAW_KEYWORD(volatile) GSCookie s_gsCookie; +#endif inline GSCookie * GetProcessGSCookiePtr() { return const_cast(&s_gsCookie); } From 7c38ab0e120ce645b9cde93c41611aa191c28f63 Mon Sep 17 00:00:00 2001 From: Steve Pfister Date: Sat, 29 Aug 2026 21:33:04 -0400 Subject: [PATCH 2/2] Align GS cookie protection platforms with NativeAOT Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9556d45f-1583-4d9b-a093-81d771aa8349 --- src/coreclr/vm/CMakeLists.txt | 4 ++++ src/coreclr/vm/vars.hpp | 6 ------ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/coreclr/vm/CMakeLists.txt b/src/coreclr/vm/CMakeLists.txt index bcc0a0d6e791cc..ce4b849c84750d 100644 --- a/src/coreclr/vm/CMakeLists.txt +++ b/src/coreclr/vm/CMakeLists.txt @@ -17,6 +17,10 @@ include_directories(${CLR_SRC_NATIVE_DIR}/libs/Common) add_definitions(-DUNICODE) add_definitions(-D_UNICODE) +if(NOT CLR_CMAKE_TARGET_APPLE AND NOT CLR_CMAKE_TARGET_ARCH_WASM AND NOT CLR_CMAKE_TARGET_OPENBSD) + add_definitions(-DFEATURE_READONLY_GS_COOKIE) +endif() + if(CLR_CMAKE_TARGET_ANDROID OR CLR_CMAKE_TARGET_OPENBSD) # OpenBSD's ld.so cannot resolve native TLS relocations in shared objects and has no # __tls_get_addr, so the runtime must use emulated TLS (like Android). diff --git a/src/coreclr/vm/vars.hpp b/src/coreclr/vm/vars.hpp index d78923ae1d06c2..c590a30a80bf63 100644 --- a/src/coreclr/vm/vars.hpp +++ b/src/coreclr/vm/vars.hpp @@ -593,12 +593,6 @@ typedef DPTR(GSCookie) PTR_GSCookie; #define READONLY_ATTR __attribute__((READONLY_ATTR_ARGS)) #endif -// Apple's __DATA_CONST segment is immutable at runtime, so InitGSCookie's ClrVirtualProtect -// call fails there (see nativeaot/Runtime for the same FEATURE_READONLY_GS_COOKIE guard). -#ifndef TARGET_APPLE -#define FEATURE_READONLY_GS_COOKIE -#endif - #ifndef DACCESS_COMPILE // const is so that it gets placed in the .text section (which is read-only) // volatile is so that accesses to it do not get optimized away because of the const