Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion eng/native/configurecompiler.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -325,9 +325,18 @@ if(CLR_CMAKE_HOST_LINUX)
add_compile_options($<$<COMPILE_LANGUAGE:ASM>:-Wa,--noexecstack>)
add_linker_flag(-Wl,--build-id=sha1)
add_linker_flag(-Wl,-z,relro,-z,now)
elseif(CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_OPENBSD)
elseif(CLR_CMAKE_HOST_FREEBSD)
add_compile_options($<$<COMPILE_LANGUAGE:ASM>:-Wa,--noexecstack>)
add_linker_flag("-Wl,--build-id=sha1")
elseif(CLR_CMAKE_HOST_OPENBSD)
add_compile_options($<$<COMPILE_LANGUAGE:ASM>:-Wa,--noexecstack>)
add_linker_flag("-Wl,--build-id=sha1")
# OpenBSD's ld.so can't resolve native TLS relocs in a .so; rely on clang's default
# emulated TLS (don't pass -fno-emulated-tls).
# Allow W+X mappings (JIT) via the PT_OPENBSD_WXNEEDED note; needs a wxallowed mount.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to enable this? Is W^X broken on OpenBSD?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Short: One or two PAL tests were failing on OpenBSD due to W^X restrictions, so I remounted the /home filesystem with wxallowed and added this linker flag to make them pass.

Long:
This is OpenBSD-specific. Unlike Linux or FreeBSD, OpenBSD enforces W^X strictly and requires both a binary opt-in (-z wxneeded) and a filesystem opt-in (wxallowed) for W+X mappings to be permitted.

The reason for -z wxneeded is that parts of the PAL/JIT may need to create mappings that are temporarily W+X.

With wxneeded, the kernel allows those mappings only when the process is running on a filesystem mounted with wxallowed. If it is not, the mapping request fails at runtime when that code path is reached (i.e., when JIT/codegen tries to allocate executable memory). It does not affect process startup by itself.

So in practice we expect two modes:

  • On systems with wxallowed: app will use W+X mappings when needed.
  • On systems without wxallowed: user will set DOTNET_EnableWriteXorExecute=0, and the app will avoid W+X mappings entirely.

In a follow-up, for systems without wxallowed, we could detect this automatically on OpenBSD using filesystem mount flags, for example:

bool EnableWriteXorExecute(void)
{
    struct statfs buf;
    return statfs(minipal_getexepath(), &buf) == 0 &&
       (buf.f_flags & MNT_WXALLOWED);
}

(I had too many patches in flight and this was getting long, so I skipped doing this right away)

add_linker_flag("-Wl,-z,wxneeded")
# The PAL's hand-written asm lacks endbr64 landing pads, so disable branch-target CFI.
add_linker_flag("-Wl,-z,nobtcfi")
elseif(CLR_CMAKE_HOST_SUNOS)
add_compile_options($<$<COMPILE_LANGUAGE:ASM>:-Wa,--noexecstack>)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector")
Expand Down Expand Up @@ -847,6 +856,20 @@ else(CLR_CMAKE_TARGET_UNIX)
add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:IGNORE_DEFAULT_TARGET_OS>>>:TARGET_WINDOWS>)
endif(CLR_CMAKE_TARGET_UNIX)

# OpenBSD only exposes its libunwind symbols through the LLVM C++ runtime
# (libc++/libc++abi), so default to those there. An explicit selection via
# CLR_CMAKE_CXX_STANDARD_LIBRARY/CLR_CMAKE_CXX_ABI_LIBRARY (applied by the cross
# toolchain file) still takes precedence.
if(CLR_CMAKE_TARGET_OPENBSD)
if(NOT CLR_CMAKE_CXX_STANDARD_LIBRARY)
add_compile_options($<$<COMPILE_LANG_AND_ID:CXX,Clang>:--stdlib=libc++>)
add_link_options($<$<LINK_LANG_AND_ID:CXX,Clang>:--stdlib=libc++>)
endif()
if(NOT CLR_CMAKE_CXX_ABI_LIBRARY)
add_link_options("LINKER:-lc++abi")
endif()
endif()

if(CLR_CMAKE_HOST_UNIX_ARM)
if (NOT DEFINED CLR_ARM_FPU_TYPE)
set(CLR_ARM_FPU_TYPE vfpv3)
Expand Down
8 changes: 7 additions & 1 deletion eng/native/functions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,13 @@ function(find_unwind_libs UnwindLibs)
find_library(UNWIND NAMES unwind)

if(UNWIND STREQUAL UNWIND-NOTFOUND)
message(FATAL_ERROR "Cannot find libunwind. Try installing libunwind8-dev or libunwind-devel.")
if(CLR_CMAKE_TARGET_OPENBSD)
# On OpenBSD the libunwind symbols are provided by the C++ ABI library
# (libc++abi), so a standalone libunwind is not expected.
set(UNWIND "")
else()
message(FATAL_ERROR "Cannot find libunwind. Try installing libunwind8-dev or libunwind-devel.")
endif()
endif()

set(${UnwindLibs} ${UNWIND_LIBS} ${UNWIND} PARENT_SCOPE)
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/gc/unix/gcenv.unix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1013,11 +1013,13 @@ static size_t GetCurrentVirtualMemorySize()
// non zero if it has succeeded, GetVirtualMemoryMaxAddress() if not available
size_t GCToOSInterface::GetVirtualMemoryLimit()
{
#ifdef RLIMIT_AS
rlimit addressSpaceLimit;
if ((getrlimit(RLIMIT_AS, &addressSpaceLimit) == 0) && (addressSpaceLimit.rlim_cur != RLIM_INFINITY))
{
return addressSpaceLimit.rlim_cur;
}
#endif // RLIMIT_AS

// No virtual memory limit
return GetVirtualMemoryMaxAddress();
Expand Down
10 changes: 10 additions & 0 deletions src/coreclr/hosts/corerun/corerun.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,16 @@ class platform_specific_actions final
#include <link.h>
#include <elf.h>
#include <cstring>

// glibc defines the ElfW() macro to select the native-width Elf type, but some
// libcs (e.g. OpenBSD) don't provide it. Fall back to the appropriate fixed-width type.
#ifndef ElfW
#if defined(TARGET_64BIT)
#define ElfW(type) Elf64_##type
#else
#define ElfW(type) Elf32_##type
#endif
#endif // ElfW
#endif

// CMake generated
Expand Down
11 changes: 5 additions & 6 deletions src/coreclr/inc/check.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

// ---------------------------------------------------------------------------
// Check.h
//

//
// Assertion checking infrastructure
// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -663,7 +662,7 @@ CHECK CheckAligned(UINT value, UINT alignment);
CHECK CheckAligned(ULONG value, UINT alignment);
#endif
CHECK CheckAligned(UINT64 value, UINT alignment);
#ifdef __APPLE__
#if defined(__APPLE__) || defined(__OpenBSD__)
CHECK CheckAligned(SIZE_T value, UINT alignment);
#endif
CHECK CheckAligned(const void *address, UINT alignment);
Expand All @@ -673,7 +672,7 @@ CHECK CheckOverflow(UINT value1, UINT value2);
CHECK CheckOverflow(ULONG value1, ULONG value2);
#endif
CHECK CheckOverflow(UINT64 value1, UINT64 value2);
#ifdef __APPLE__
#if defined(__APPLE__) || defined(__OpenBSD__)
CHECK CheckOverflow(SIZE_T value1, SIZE_T value2);
#endif
#ifndef __wasm__
Expand All @@ -689,15 +688,15 @@ CHECK CheckUnderflow(UINT value1, UINT value2);
CHECK CheckUnderflow(ULONG value1, ULONG value2);
#endif
CHECK CheckUnderflow(UINT64 value1, UINT64 value2);
#ifdef __APPLE__
#if defined(__APPLE__) || defined(__OpenBSD__)
CHECK CheckUnderflow(SIZE_T value1, SIZE_T value2);
#endif
CHECK CheckUnderflow(const void *address, UINT offset);
#if defined(_MSC_VER)
CHECK CheckUnderflow(const void *address, ULONG offset);
#endif
CHECK CheckUnderflow(const void *address, UINT64 offset);
#ifdef __APPLE__
#if defined(__APPLE__) || defined(__OpenBSD__)
CHECK CheckUnderflow(const void *address, SIZE_T offset);
#endif
CHECK CheckUnderflow(const void *address, void *address2);
Expand Down
11 changes: 5 additions & 6 deletions src/coreclr/inc/check.inl
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ inline CHECK CheckAligned(UINT64 value, UINT alignment)
CHECK_OK;
}

#if defined(__APPLE__) || defined(__wasm__)
#if defined(__APPLE__) || defined(__wasm__) || defined(__OpenBSD__)
inline CHECK CheckAligned(SIZE_T value, UINT alignment)
{
STATIC_CONTRACT_WRAPPER;
Expand Down Expand Up @@ -192,7 +192,7 @@ inline CHECK CheckOverflow(UINT64 value1, UINT64 value2)
CHECK_OK;
}

#ifdef __APPLE__
#if defined(__APPLE__) || defined(__OpenBSD__)
inline CHECK CheckOverflow(SIZE_T value1, SIZE_T value2)
{
CHECK(value1 + value2 >= value1);
Expand Down Expand Up @@ -237,7 +237,7 @@ inline CHECK CheckOverflow(const void *address, UINT64 offset)
CHECK_OK;
}

#if defined(__APPLE__) || defined(__wasm__)
#if defined(__APPLE__) || defined(__wasm__) || defined(__OpenBSD__)
inline CHECK CheckOverflow(const void *address, SIZE_T offset)
{
CHECK((UINT64) address + offset >= (UINT64) address);
Expand Down Expand Up @@ -271,7 +271,7 @@ inline CHECK CheckUnderflow(UINT64 value1, UINT64 value2)
CHECK_OK;
}

#ifdef __APPLE__
#if defined(__APPLE__) || defined(__OpenBSD__)
inline CHECK CheckUnderflow(SIZE_T value1, SIZE_T value2)
{
CHECK(value1 - value2 <= value1);
Expand Down Expand Up @@ -316,7 +316,7 @@ inline CHECK CheckUnderflow(const void *address, UINT64 offset)
CHECK_OK;
}

#if defined(__APPLE__) || defined(__wasm__)
#if defined(__APPLE__) || defined(__wasm__) || defined(__OpenBSD__)
inline CHECK CheckUnderflow(const void *address, SIZE_T offset)
{
// SIZE_T is 32bit on wasm32
Expand Down Expand Up @@ -371,4 +371,3 @@ inline CHECK CheckBounds(const void *rangeBase, UINT32 rangeSize, UINT32 offset,
}

#endif // CHECK_INL_

9 changes: 5 additions & 4 deletions src/coreclr/inc/clrtypes.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

// ================================================================================
// Standard primitive types for CLR code
//
Expand Down Expand Up @@ -275,7 +276,7 @@ inline UINT64 AlignUp(UINT64 value, UINT alignment)
return (value+alignment-1)&~(UINT64)(alignment-1);
}

#if defined(__APPLE__) || defined(__wasm__)
#if defined(__APPLE__) || defined(__wasm__) || defined(__OpenBSD__)
inline SIZE_T AlignUp(SIZE_T value, UINT alignment)
{
STATIC_CONTRACT_LEAF;
Expand Down Expand Up @@ -316,7 +317,7 @@ inline uintptr_t AlignDown(uintptr_t value, UINT alignment)
}
#endif

#ifdef __APPLE__
#if defined(__APPLE__) || defined(__OpenBSD__)
inline SIZE_T AlignDown(SIZE_T value, UINT alignment)
{
STATIC_CONTRACT_LEAF;
Expand Down Expand Up @@ -345,7 +346,7 @@ inline UINT AlignmentPad(UINT64 value, UINT alignment)
return (UINT) (AlignUp(value, alignment) - value);
}

#if defined(__APPLE__) || defined(__wasm__)
#if defined(__APPLE__) || defined(__wasm__) || defined(__OpenBSD__)
inline UINT AlignmentPad(SIZE_T value, UINT alignment)
{
STATIC_CONTRACT_WRAPPER;
Expand Down Expand Up @@ -378,7 +379,7 @@ inline UINT AlignmentTrim(UINT64 value, UINT alignment)
return ((UINT)value)&(alignment-1);
}

#if defined(__APPLE__) || defined(__wasm__)
#if defined(__APPLE__) || defined(__wasm__) || defined(__OpenBSD__)
inline UINT AlignmentTrim(SIZE_T value, UINT alignment)
{
STATIC_CONTRACT_LEAF;
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/inc/pedecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ inline CHECK CheckOverflow(RVA value1, COUNT_T value2)
#define IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE 0x4644
#elif defined(__FreeBSD__)
#define IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE 0xADC4
#elif defined(__OpenBSD__)
#define IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE 0xADC5
#elif defined(__linux__)
#define IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE 0x7B79
#elif defined(__NetBSD__)
Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/jit/compiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,12 @@ inline unsigned genLog2(uint64_t value)
return BitOperations::BitScanForward(value);
}

#ifdef __APPLE__
#if defined(__APPLE__) || defined(__OpenBSD__)
inline unsigned genLog2(size_t value)
{
return genLog2((uint64_t)value);
}
#endif // __APPLE__
#endif // __APPLE__ || __OpenBSD__

// Given an unsigned 64-bit value, returns the lower 32-bits in unsigned format
//
Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/jit/jit.h
Original file line number Diff line number Diff line change
Expand Up @@ -731,12 +731,12 @@ inline size_t unsigned_abs(ssize_t x)
return ((size_t)std::abs((int64_t)x));
}

#ifdef __APPLE__
#if defined(__APPLE__) || defined(__OpenBSD__)
inline size_t unsigned_abs(int64_t x)
{
return ((size_t)std::abs(x));
}
#endif // __APPLE__
#endif // __APPLE__ || __OpenBSD__
#endif // TARGET_64BIT

/*****************************************************************************/
Expand Down
4 changes: 3 additions & 1 deletion src/coreclr/minipal/Unix/doublemapping.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
//

#include <stddef.h>
#include <sys/mman.h>
Expand Down Expand Up @@ -102,6 +101,8 @@ bool VMToOSInterface::CreateDoubleMemoryMapper(void** pHandle, size_t *pMaxExecu
// Clip the maximum double mapped memory size to 1/4 of the virtual address space limit.
// When such a limit is set, GC reserves 1/2 of it, so we need to leave something
// for the rest of the process.
#ifdef RLIMIT_AS
// OpenBSD has no address-space rlimit (RLIMIT_AS), so this clipping is skipped there.
struct rlimit virtualAddressSpaceLimit;
if ((getrlimit(RLIMIT_AS, &virtualAddressSpaceLimit) == 0) && (virtualAddressSpaceLimit.rlim_cur != RLIM_INFINITY))
{
Expand All @@ -111,6 +112,7 @@ bool VMToOSInterface::CreateDoubleMemoryMapper(void** pHandle, size_t *pMaxExecu
maxDoubleMappedMemorySize = virtualAddressSpaceLimit.rlim_cur;
}
}
#endif // RLIMIT_AS

// Clip the maximum double mapped memory size to the file size limit
struct rlimit fileSizeLimit;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ The .NET Foundation licenses this file to you under the MIT license.
<CppLibCreator>ar</CppLibCreator>
<_SymbolPrefix Condition="'$(_IsApplePlatform)' == 'true'">_</_SymbolPrefix>
<LinkerFlavor Condition="'$(LinkerFlavor)' == '' and '$(_targetOS)' == 'freebsd'">lld</LinkerFlavor>
<LinkerFlavor Condition="'$(LinkerFlavor)' == '' and '$(_targetOS)' == 'openbsd'">lld</LinkerFlavor>
<LinkerFlavor Condition="'$(LinkerFlavor)' == '' and '$(_linuxLibcFlavor)' == 'bionic'">lld</LinkerFlavor>
<LinkerFlavor Condition="'$(LinkerFlavor)' == '' and '$(_targetOS)' == 'android'">lld</LinkerFlavor>
<LinkerFlavor Condition="'$(LinkerFlavor)' == '' and '$(_targetOS)' == 'linux'">bfd</LinkerFlavor>
Expand Down Expand Up @@ -65,6 +66,7 @@ The .NET Foundation licenses this file to you under the MIT license.
<TargetTriple Condition="'$(CrossCompileArch)' != '' and '$(_IsAlpineExitCode)' != '0'">$(CrossCompileArch)-linux-$(CrossCompileAbi)</TargetTriple>
<TargetTriple Condition="'$(CrossCompileArch)' != '' and '$(_IsAlpineExitCode)' == '0'">$(CrossCompileArch)-alpine-linux-$(CrossCompileAbi)</TargetTriple>
<TargetTriple Condition="'$(CrossCompileArch)' != '' and ($(CrossCompileRid.StartsWith('freebsd')))">$(CrossCompileArch)-unknown-freebsd12</TargetTriple>
<TargetTriple Condition="'$(CrossCompileArch)' != '' and ($(CrossCompileRid.StartsWith('openbsd')))">$(CrossCompileArch)-unknown-openbsd</TargetTriple>

<SharedLibraryInstallName Condition="'$(SharedLibraryInstallName)' == '' and '$(_IsApplePlatform)' == 'true' and '$(NativeLib)' == 'Shared'">@rpath/$(NativeBinaryPrefix)$(TargetName)$(NativeBinaryExt)</SharedLibraryInstallName>

Expand Down Expand Up @@ -222,14 +224,14 @@ The .NET Foundation licenses this file to you under the MIT license.

<ItemGroup>
<NativeSystemLibrary Include="stdc++" Condition="'$(LinkStandardCPlusPlusLibrary)' == 'true'" />
<NativeSystemLibrary Include="dl" />
<NativeSystemLibrary Include="dl" Condition="'$(_targetOS)' != 'openbsd'" />
<NativeSystemLibrary Include="objc" Condition="'$(_IsApplePlatform)' == 'true'" />
<NativeSystemLibrary Include="swiftCore" Condition="'$(_IsApplePlatform)' == 'true'" />
<NativeSystemLibrary Include="swiftFoundation" Condition="'$(_IsApplePlatform)' == 'true'" />
<NativeSystemLibrary Include="z" Condition="'$(UseSystemZlib)' == 'true'" />
<NativeSystemLibrary Include="brotlienc;brotlidec;brotlicommon" Condition="'$(UseSystemBrotli)' == 'true'" />
<NativeSystemLibrary Include="zstd" Condition="'$(UseSystemZstd)' == 'true'" />
<NativeSystemLibrary Include="rt" Condition="'$(_IsApplePlatform)' != 'true' and '$(_linuxLibcFlavor)' != 'bionic'" />
<NativeSystemLibrary Include="rt" Condition="'$(_IsApplePlatform)' != 'true' and '$(_linuxLibcFlavor)' != 'bionic' and '$(_targetOS)' != 'openbsd'" />
<NativeSystemLibrary Include="log" Condition="'$(_linuxLibcFlavor)' == 'bionic'" />
<NativeSystemLibrary Include="icucore" Condition="'$(_IsApplePlatform)' == 'true'" />
<NativeSystemLibrary Include="m" />
Expand Down Expand Up @@ -267,6 +269,10 @@ The .NET Foundation licenses this file to you under the MIT license.
<!-- binskim warning BA3011 The BIND_NOW flag is missing -->
<LinkerArg Include="-Wl,-z,now" Condition="'$(_IsApplePlatform)' != 'true'" Shim="true" />
<LinkerArg Include="-Wl,-z,stack-size=$(IlcDefaultStackSize)" Condition="'$(IlcDefaultStackSize)' != ''" Shim="true" />
<!-- OpenBSD enforces IBT/BTCFI on amd64. NativeAOT codegen is not endbr64-instrumented, so
indirect branches (e.g. switch jump tables) to non-endbr64 targets fault with SIGILL.
Opt out of branch-target CFI enforcement via the PT_OPENBSD_NOBTCFI program header. -->
<LinkerArg Include="-Wl,-z,nobtcfi" Condition="'$(_targetOS)' == 'openbsd'" />
<!-- this workaround can be deleted once the minimum supported glibc version
(runtime's official build machine's glibc version) is at least 2.33
see https://github.com/bminor/glibc/commit/99468ed45f5a58f584bab60364af937eb6f8afda -->
Expand Down
6 changes: 6 additions & 0 deletions src/coreclr/nativeaot/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ if(CLR_CMAKE_TARGET_ANDROID)
set(FEATURE_JAVAMARSHAL 1)
endif()

if(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).
add_definitions(-DFEATURE_EMULATED_TLS)
endif()

if(NOT DEFINED FEATURE_JAVAMARSHAL)
set(FEATURE_JAVAMARSHAL $<IF:$<CONFIG:Debug,Checked>,1,0>)
endif()
Expand Down
5 changes: 4 additions & 1 deletion src/coreclr/nativeaot/Runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,10 @@ if(CLR_CMAKE_TARGET_WIN32)
add_compile_options($<$<COMPILE_LANGUAGE:ASM_MASM>:/safeseh>)
endif()
else()
if(NOT CLR_CMAKE_TARGET_APPLE AND NOT CLR_CMAKE_TARGET_ARCH_WASM)
# OpenBSD marks the main executable's read-only segments immutable (mimmutable) at load,
# so the runtime cannot mprotect the read-only GS cookie page to writable to initialize it.
# Keep the cookie in writable memory there, like Apple.
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()
include(unix/configure.cmake)
Expand Down
Loading
Loading