diff --git a/src/coreclr/nativeaot/Runtime/eventpipe/CMakeLists.txt b/src/coreclr/nativeaot/Runtime/eventpipe/CMakeLists.txt index a6bedd8e2254d9..930ff5cf9f086a 100644 --- a/src/coreclr/nativeaot/Runtime/eventpipe/CMakeLists.txt +++ b/src/coreclr/nativeaot/Runtime/eventpipe/CMakeLists.txt @@ -9,33 +9,41 @@ set(AOT_EVENTPIPE_SHIM_DIR "${CMAKE_CURRENT_SOURCE_DIR}") set (CONTAINER_SOURCES "") set (CONTAINER_HEADERS "") +set (MINIPAL_SOURCES "") set (EVENTPIPE_SOURCES "") set (EVENTPIPE_HEADERS "") set (GEN_EVENTPIPE_SOURCES "") set (SHARED_CONTAINERS_SOURCE_PATH "${CLR_SRC_NATIVE_DIR}/containers") set (SHARED_EVENTPIPE_SOURCE_PATH "${CLR_SRC_NATIVE_DIR}/eventpipe") +set (SHARED_MINIPAL_SOURCE_PATH "${CLR_SRC_NATIVE_DIR}/minipal") include (${SHARED_EVENTPIPE_SOURCE_PATH}/eventpipe.cmake) include (${SHARED_CONTAINERS_SOURCE_PATH}/containers.cmake) if(CLR_CMAKE_HOST_WIN32) list(APPEND SHARED_DIAGNOSTIC_SERVER_SOURCES - ds-ipc-pal-namedpipe.c + ds-ipc-pal-namedpipe.c ) list(APPEND SHARED_DIAGNOSTIC_SERVER_HEADERS - ds-ipc-pal-namedpipe.h + ds-ipc-pal-namedpipe.h ) endif(CLR_CMAKE_HOST_WIN32) if(CLR_CMAKE_HOST_UNIX) list(APPEND SHARED_DIAGNOSTIC_SERVER_SOURCES - ds-ipc-pal-socket.c + ds-ipc-pal-socket.c ) list(APPEND SHARED_DIAGNOSTIC_SERVER_HEADERS - ds-ipc-pal-socket.h + ds-ipc-pal-socket.h ) + + include(${CLR_SRC_NATIVE_DIR}/minipal/configure.cmake) + list(APPEND MINIPAL_SOURCES + random.c + ) + endif(CLR_CMAKE_HOST_UNIX) list(APPEND EVENTPIPE_SOURCES @@ -50,6 +58,7 @@ list(APPEND EVENTPIPE_HEADERS addprefix(CONTAINER_SOURCES ${SHARED_CONTAINERS_SOURCE_PATH} "${SHARED_CONTAINER_SOURCES}") addprefix(CONTAINER_HEADERS ${SHARED_CONTAINERS_SOURCE_PATH} "${SHARED_CONTAINER_HEADERS}") +addprefix(MINIPAL_SOURCES ${SHARED_MINIPAL_SOURCE_PATH} "${MINIPAL_SOURCES}") addprefix(EVENTPIPE_SOURCES ${SHARED_EVENTPIPE_SOURCE_PATH} "${EVENTPIPE_SOURCES}") addprefix(EVENTPIPE_HEADERS ${SHARED_EVENTPIPE_SOURCE_PATH} "${EVENTPIPE_HEADERS}") @@ -125,6 +134,7 @@ list(APPEND EVENTPIPE_SOURCES ${GEN_EVENTPIPE_SOURCES} ${CONTAINER_SOURCES} ${CONTAINER_HEADERS} + ${MINIPAL_SOURCES} ) list(APPEND AOT_EVENTPIPE_DISABLED_SOURCES diff --git a/src/coreclr/nativeaot/Runtime/eventpipe/ds-rt-aot.h b/src/coreclr/nativeaot/Runtime/eventpipe/ds-rt-aot.h index 811a39b574f96c..18c87534751488 100644 --- a/src/coreclr/nativeaot/Runtime/eventpipe/ds-rt-aot.h +++ b/src/coreclr/nativeaot/Runtime/eventpipe/ds-rt-aot.h @@ -181,13 +181,8 @@ ds_rt_generate_core_dump ( { STATIC_CONTRACT_NOTHROW; - ds_ipc_result_t result = DS_IPC_E_FAIL; - uint32_t flags = ds_generate_core_dump_command_payload_get_flags(payload); - // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase - // TODO: Generate an exception dump - // PalDebugBreak(); - - return 0; + // Eventpipe driven core_dump is not currently supported in NativeAOT + return DS_IPC_E_NOTSUPPORTED; } /* diff --git a/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.cpp b/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.cpp index b1d3520409c923..617f146e743253 100644 --- a/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.cpp +++ b/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.cpp @@ -17,6 +17,8 @@ #include #endif +#include + #include "gcenv.h" #ifndef DIRECTORY_SEPARATOR_CHAR @@ -237,8 +239,6 @@ ep_rt_aot_atomic_inc_int64_t (volatile int64_t *value) { STATIC_CONTRACT_NOTHROW; - // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase - // TODO: Consider replacing with a new PalInterlockedIncrement64 service int64_t currentValue; do { currentValue = *value; @@ -252,8 +252,6 @@ int64_t ep_rt_aot_atomic_dec_int64_t (volatile int64_t *value) { STATIC_CONTRACT_NOTHROW; - // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase - // TODO: Consider replacing with a new PalInterlockedDecrement64 service int64_t currentValue; do { currentValue = *value; @@ -366,8 +364,7 @@ ep_rt_aot_thread_create ( STATIC_CONTRACT_NOTHROW; EP_ASSERT (thread_func != NULL); - // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase - // TODO: Fill in the outgoing id if any callers ever need it + // Note that none of the callers examine the return id in any way if (id) *reinterpret_cast(id) = 0xffffffff; @@ -789,6 +786,47 @@ void ep_rt_aot_os_environment_get_utf16 (dn_vector_ptr_t *env_array) #endif } +void ep_rt_aot_create_activity_id (uint8_t *activity_id, uint32_t activity_id_len) +{ + // We call CoCreateGuid for windows, and use a random generator for non-windows + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (activity_id != NULL); + EP_ASSERT (activity_id_len == EP_ACTIVITY_ID_SIZE); +#ifdef HOST_WIN32 + CoCreateGuid (reinterpret_cast(activity_id)); +#else + if(minipal_get_cryptographically_secure_random_bytes(activity_id, activity_id_len)==-1) + { + *activity_id=0; + return; + } + + const uint16_t version_mask = 0xF000; + const uint16_t random_guid_version = 0x4000; + const uint8_t clock_seq_hi_and_reserved_mask = 0xC0; + const uint8_t clock_seq_hi_and_reserved_value = 0x80; + + // Modify bits indicating the type of the GUID + uint8_t *activity_id_c = activity_id + sizeof (uint32_t) + sizeof (uint16_t); + uint8_t *activity_id_d = activity_id + sizeof (uint32_t) + sizeof (uint16_t) + sizeof (uint16_t); + + uint16_t c; + memcpy (&c, activity_id_c, sizeof (c)); + + uint8_t d; + memcpy (&d, activity_id_d, sizeof (d)); + + // time_hi_and_version + c = ((c & ~version_mask) | random_guid_version); + // clock_seq_hi_and_reserved + d = ((d & ~clock_seq_hi_and_reserved_mask) | clock_seq_hi_and_reserved_value); + + memcpy (activity_id_c, &c, sizeof (c)); + memcpy (activity_id_d, &d, sizeof (d)); +#endif +} + + #ifdef EP_CHECKED_BUILD void ep_rt_aot_lock_requires_lock_held (const ep_rt_lock_handle_t *lock) diff --git a/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.h b/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.h index 33deac1b7fd79c..d992ef818adafb 100644 --- a/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.h +++ b/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.h @@ -52,8 +52,7 @@ extern void ep_rt_aot_thread_exited (void); -// shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase -// TODO: The NativeAOT ALIGN_UP is defined in a tangled manner that generates linker errors if +// The NativeAOT ALIGN_UP is defined in a tangled manner that generates linker errors if // it is used here; instead, define a version tailored to the existing usage in the shared // EventPipe code. static inline uint8_t* _rt_aot_align_up(uint8_t* val, uintptr_t alignment) @@ -322,10 +321,7 @@ ep_rt_method_get_simple_assembly_name ( { STATIC_CONTRACT_NOTHROW; - // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase - // TODO: Design MethodDesc and method name services if/when needed - //PalDebugBreak(); - + // NativeAOT does not support method_desc operations return false; } @@ -337,10 +333,7 @@ ep_rt_method_get_full_name ( ep_char8_t *name, size_t name_len) { - // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase - // TODO: Design MethodDesc and method name services if/when needed - //PalDebugBreak(); - + // NativeAOT does not support method_desc operations return false; } @@ -611,11 +604,9 @@ EventPipeWaitHandle ep_rt_wait_event_get_wait_handle (ep_rt_wait_event_handle_t *wait_event) { STATIC_CONTRACT_NOTHROW; - // EP_ASSERT (wait_event != NULL && wait_event->event != NULL); - // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase - // TODO: NativeAOT CLREventStatic doesn't have GetHandleUNHOSTED - // PalDebugBreak(); + // This is not reached in the current product + abort(); return 0; } @@ -673,41 +664,8 @@ ep_rt_create_activity_id ( uint8_t *activity_id, uint32_t activity_id_len) { - STATIC_CONTRACT_NOTHROW; - EP_ASSERT (activity_id != NULL); - EP_ASSERT (activity_id_len == EP_ACTIVITY_ID_SIZE); - - // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase - // TODO: Implement a way to generate a real Guid - // CoCreateGuid (reinterpret_cast(activity_id)); - - // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase - // TODO: Using roughly Mono's implementation but Mono randomly generates this, hardcoding for now - uint8_t data1[] = {0x67,0xac,0x33,0xf1,0x8d,0xed,0x41,0x01,0xb4,0x26,0xc9,0xb7,0x94,0x35,0xf7,0x8a}; - memcpy (activity_id, data1, EP_ACTIVITY_ID_SIZE); - - const uint16_t version_mask = 0xF000; - const uint16_t random_guid_version = 0x4000; - const uint8_t clock_seq_hi_and_reserved_mask = 0xC0; - const uint8_t clock_seq_hi_and_reserved_value = 0x80; - - // Modify bits indicating the type of the GUID - uint8_t *activity_id_c = activity_id + sizeof (uint32_t) + sizeof (uint16_t); - uint8_t *activity_id_d = activity_id + sizeof (uint32_t) + sizeof (uint16_t) + sizeof (uint16_t); - - uint16_t c; - memcpy (&c, activity_id_c, sizeof (c)); - - uint8_t d; - memcpy (&d, activity_id_d, sizeof (d)); - - // time_hi_and_version - c = ((c & ~version_mask) | random_guid_version); - // clock_seq_hi_and_reserved - d = ((d & ~clock_seq_hi_and_reserved_mask) | clock_seq_hi_and_reserved_value); - - memcpy (activity_id_c, &c, sizeof (c)); - memcpy (activity_id_d, &d, sizeof (d)); + extern void ep_rt_aot_create_activity_id (uint8_t *activity_id, uint32_t activity_id_len); + ep_rt_aot_create_activity_id(activity_id, activity_id_len); } static @@ -716,9 +674,9 @@ bool ep_rt_is_running (void) { STATIC_CONTRACT_NOTHROW; - // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase - // TODO: Does NativeAot have the concept of EEStarted - // PalDebugBreak(); + + // This is only used to check if the profiler can be attached + // Profiler attach is not supported in NativeAOT return false; } @@ -730,11 +688,7 @@ ep_rt_execute_rundown (dn_vector_ptr_t *execution_checkpoints) { STATIC_CONTRACT_NOTHROW; - //TODO: Write execution checkpoint rundown events. - // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase - // TODO: EventPipe Configuration values - RhConfig? - // (CLRConfig::INTERNAL_EventPipeCircularMB) - // PalDebugBreak(); + // NativeAOT does not currently support rundown } /* @@ -770,8 +724,6 @@ EP_RT_DEFINE_THREAD_FUNC (ep_rt_thread_aot_start_session_or_sampling_thread) ep_rt_thread_params_t* thread_params = reinterpret_cast(data); - // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase - // TODO: Implement thread creation/management if needed. // The session and sampling threads both assert that the incoming thread handle is // non-null, but do not necessarily rely on it otherwise; just pass a meaningless non-null // value until testing shows that a meaningful value is needed. @@ -806,9 +758,7 @@ inline void ep_rt_set_server_name(void) { - // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase - // TODO: Need to set name for the thread - // ::SetThreadName(GetCurrentThread(), W(".NET EventPipe")); + // This is optional, decorates the thread name with EventPipe specific information } @@ -1544,10 +1494,7 @@ ep_rt_thread_setup (void) { STATIC_CONTRACT_NOTHROW; - // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase - // TODO: Implement thread creation/management if needed - // Thread* thread_handle = SetupThreadNoThrow (); - // EP_ASSERT (thread_handle != NULL); + // Likely not needed and do nothing until testing shows to be required } static diff --git a/src/native/libs/Common/pal_config.h.in b/src/native/libs/Common/pal_config.h.in index a5ce0ce2a46d4b..42837a9a557d08 100644 --- a/src/native/libs/Common/pal_config.h.in +++ b/src/native/libs/Common/pal_config.h.in @@ -51,7 +51,6 @@ #cmakedefine01 HAVE_SCHED_GETCPU #cmakedefine01 HAVE_PTHREAD_SETCANCELSTATE #cmakedefine01 HAVE_GNU_LIBNAMES_H -#cmakedefine01 HAVE_ARC4RANDOM_BUF #cmakedefine01 KEVENT_HAS_VOID_UDATA #cmakedefine01 HAVE_FDS_BITS #cmakedefine01 HAVE_PRIVATE_FDS_BITS diff --git a/src/native/libs/System.Native/CMakeLists.txt b/src/native/libs/System.Native/CMakeLists.txt index 2c6249cc516273..35fa5693e9fce9 100644 --- a/src/native/libs/System.Native/CMakeLists.txt +++ b/src/native/libs/System.Native/CMakeLists.txt @@ -14,6 +14,16 @@ if (CLR_CMAKE_TARGET_OSX) add_definitions(-D_DARWIN_C_SOURCE) endif () +set (MINIPAL_SOURCES "") +set (SHARED_MINIPAL_SOURCE_PATH "${CLR_SRC_NATIVE_DIR}/minipal") + +include(${CLR_SRC_NATIVE_DIR}/minipal/configure.cmake) +list(APPEND MINIPAL_SOURCES + random.c +) + +addprefix(MINIPAL_SOURCES ${SHARED_MINIPAL_SOURCE_PATH} "${MINIPAL_SOURCES}") + set(NATIVE_SOURCES pal_errno.c pal_interfaceaddresses.c @@ -30,6 +40,10 @@ set(NATIVE_SOURCES pal_sysctl.c ) +list(APPEND NATIVE_SOURCES + ${MINIPAL_SOURCES} +) + if (NOT CLR_CMAKE_TARGET_WASI) list (APPEND NATIVE_SOURCES pal_dynamicload.c diff --git a/src/native/libs/System.Native/pal_random.c b/src/native/libs/System.Native/pal_random.c index bdacacb7828d5e..cf4abbeeeb395a 100644 --- a/src/native/libs/System.Native/pal_random.c +++ b/src/native/libs/System.Native/pal_random.c @@ -1,21 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(__APPLE__) && __APPLE__ -#include -#endif - -#include "pal_config.h" #include "pal_random.h" +#include /* @@ -25,37 +12,7 @@ Generate random bytes. The generated bytes are not cryptographically strong. void SystemNative_GetNonCryptographicallySecureRandomBytes(uint8_t* buffer, int32_t bufferLength) { - assert(buffer != NULL); - -#if HAVE_ARC4RANDOM_BUF - arc4random_buf(buffer, (size_t)bufferLength); -#else - long num = 0; - static bool sInitializedMRand; - - // Fall back to the secure version - SystemNative_GetCryptographicallySecureRandomBytes(buffer, bufferLength); - - if (!sInitializedMRand) - { - srand48((long int)time(NULL)); - sInitializedMRand = true; - } - - // always xor srand48 over the whole buffer to get some randomness - // in case /dev/urandom is not really random - - for (int i = 0; i < bufferLength; i++) - { - if (i % 4 == 0) - { - num = lrand48(); - } - - *(buffer + i) ^= num; - num >>= 8; - } -#endif // HAVE_ARC4RANDOM_BUF + minipal_get_non_cryptographically_secure_random_bytes(buffer, bufferLength); } /* @@ -66,88 +23,5 @@ Return 0 on success, -1 on failure. */ int32_t SystemNative_GetCryptographicallySecureRandomBytes(uint8_t* buffer, int32_t bufferLength) { - assert(buffer != NULL); - -#ifdef __EMSCRIPTEN__ - extern int32_t dotnet_browser_entropy(uint8_t* buffer, int32_t bufferLength); - static bool sMissingBrowserCrypto; - if (!sMissingBrowserCrypto) - { - int32_t bff = dotnet_browser_entropy(buffer, bufferLength); - if (bff == -1) - sMissingBrowserCrypto = true; - else - return 0; - } -#elif defined(__APPLE__) && __APPLE__ - CCRNGStatus status = CCRandomGenerateBytes(buffer, bufferLength); - - if (status == kCCSuccess) - { - return 0; - } - else - { - return -1; - } -#else - - static volatile int rand_des = -1; - static bool sMissingDevURandom; - - if (!sMissingDevURandom) - { - if (rand_des == -1) - { - int fd; - - do - { -#if HAVE_O_CLOEXEC - fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); -#else - fd = open("/dev/urandom", O_RDONLY); - fcntl(fd, F_SETFD, FD_CLOEXEC); -#endif - } - while ((fd == -1) && (errno == EINTR)); - - if (fd != -1) - { - int expected = -1; - if (!__atomic_compare_exchange_n(&rand_des, &expected, fd, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) - { - // Another thread has already set the rand_des - close(fd); - } - } - else if (errno == ENOENT) - { - sMissingDevURandom = true; - } - } - - if (rand_des != -1) - { - int32_t offset = 0; - do - { - ssize_t n = read(rand_des, buffer + offset , (size_t)(bufferLength - offset)); - if (n == -1) - { - if (errno == EINTR) - { - continue; - } - return -1; - } - - offset += n; - } - while (offset != bufferLength); - return 0; - } - } -#endif - return -1; + return minipal_get_cryptographically_secure_random_bytes(buffer, bufferLength); } diff --git a/src/native/libs/configure.cmake b/src/native/libs/configure.cmake index cbaac692f26301..a1e151de76d957 100644 --- a/src/native/libs/configure.cmake +++ b/src/native/libs/configure.cmake @@ -254,11 +254,6 @@ check_include_files( gnu/lib-names.h HAVE_GNU_LIBNAMES_H) -check_symbol_exists( - arc4random_buf - "stdlib.h" - HAVE_ARC4RANDOM_BUF) - check_symbol_exists( TIOCGWINSZ "sys/ioctl.h" diff --git a/src/native/minipal/configure.cmake b/src/native/minipal/configure.cmake index c7b7715c1d78aa..97153932a7b878 100644 --- a/src/native/minipal/configure.cmake +++ b/src/native/minipal/configure.cmake @@ -1,7 +1,11 @@ include(CheckFunctionExists) include(CheckIncludeFiles) +include(CheckSymbolExists) check_include_files("sys/auxv.h;asm/hwcap.h" HAVE_AUXV_HWCAP_H) check_function_exists(sysctlbyname HAVE_SYSCTLBYNAME) +check_symbol_exists(arc4random_buf "stdlib.h" HAVE_ARC4RANDOM_BUF) +check_symbol_exists(O_CLOEXEC fcntl.h HAVE_O_CLOEXEC) + configure_file(${CMAKE_CURRENT_LIST_DIR}/minipalconfig.h.in ${CMAKE_CURRENT_BINARY_DIR}/minipalconfig.h) diff --git a/src/native/minipal/minipalconfig.h.in b/src/native/minipal/minipalconfig.h.in index b84247632ab00e..b1d7261eb45600 100644 --- a/src/native/minipal/minipalconfig.h.in +++ b/src/native/minipal/minipalconfig.h.in @@ -1,7 +1,9 @@ #ifndef HAVE_MINIPAL_MINIPALCONFIG_H #define HAVE_MINIPAL_MINIPALCONFIG_H +#cmakedefine01 HAVE_ARC4RANDOM_BUF #cmakedefine01 HAVE_AUXV_HWCAP_H +#cmakedefine01 HAVE_O_CLOEXEC #cmakedefine01 HAVE_SYSCTLBYNAME #endif diff --git a/src/native/minipal/random.c b/src/native/minipal/random.c new file mode 100644 index 00000000000000..2a0f57d53163a5 --- /dev/null +++ b/src/native/minipal/random.c @@ -0,0 +1,153 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(__APPLE__) && __APPLE__ +#include +#endif + +#include "minipalconfig.h" +#include "random.h" + +/* + +Generate random bytes. The generated bytes are not cryptographically strong. + +*/ + +void minipal_get_non_cryptographically_secure_random_bytes(uint8_t* buffer, int32_t bufferLength) +{ + assert(buffer != NULL); + +#if HAVE_ARC4RANDOM_BUF + arc4random_buf(buffer, (size_t)bufferLength); +#else + long num = 0; + static bool sInitializedMRand; + + // Fall back to the secure version + minipal_get_cryptographically_secure_random_bytes(buffer, bufferLength); + + if (!sInitializedMRand) + { + srand48((long int)time(NULL)); + sInitializedMRand = true; + } + + // always xor srand48 over the whole buffer to get some randomness + // in case /dev/urandom is not really random + + for (int i = 0; i < bufferLength; i++) + { + if (i % 4 == 0) + { + num = lrand48(); + } + + *(buffer + i) ^= num; + num >>= 8; + } +#endif // HAVE_ARC4RANDOM_BUF +} + +/* + +Generate cryptographically strong random bytes. + +Return 0 on success, -1 on failure. +*/ +int32_t minipal_get_cryptographically_secure_random_bytes(uint8_t* buffer, int32_t bufferLength) +{ + assert(buffer != NULL); + +#ifdef __EMSCRIPTEN__ + extern int32_t dotnet_browser_entropy(uint8_t* buffer, int32_t bufferLength); + static bool sMissingBrowserCrypto; + if (!sMissingBrowserCrypto) + { + int32_t bff = dotnet_browser_entropy(buffer, bufferLength); + if (bff == -1) + sMissingBrowserCrypto = true; + else + return 0; + } +#elif defined(__APPLE__) && __APPLE__ + CCRNGStatus status = CCRandomGenerateBytes(buffer, bufferLength); + + if (status == kCCSuccess) + { + return 0; + } + else + { + return -1; + } +#else + + static volatile int rand_des = -1; + static bool sMissingDevURandom; + + if (!sMissingDevURandom) + { + if (rand_des == -1) + { + int fd; + + do + { +#if HAVE_O_CLOEXEC + fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); +#else + fd = open("/dev/urandom", O_RDONLY); + fcntl(fd, F_SETFD, FD_CLOEXEC); +#endif + } + while ((fd == -1) && (errno == EINTR)); + + if (fd != -1) + { + int expected = -1; + if (!__atomic_compare_exchange_n(&rand_des, &expected, fd, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) + { + // Another thread has already set the rand_des + close(fd); + } + } + else if (errno == ENOENT) + { + sMissingDevURandom = true; + } + } + + if (rand_des != -1) + { + int32_t offset = 0; + do + { + ssize_t n = read(rand_des, buffer + offset , (size_t)(bufferLength - offset)); + if (n == -1) + { + if (errno == EINTR) + { + continue; + } + return -1; + } + + offset += n; + } + while (offset != bufferLength); + return 0; + } + } +#endif + return -1; +} diff --git a/src/native/minipal/random.h b/src/native/minipal/random.h new file mode 100644 index 00000000000000..4296fd0a5742b1 --- /dev/null +++ b/src/native/minipal/random.h @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#ifndef HAVE_MINIPAL_RANDOM_H +#define HAVE_MINIPAL_RANDOM_H + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +/** + * Generate random bytes. The generated bytes are not cryptographically strong. + */ +void minipal_get_non_cryptographically_secure_random_bytes(uint8_t* buffer, int32_t bufferLength); + +/** + * Generate cryptographically strong random bytes. + * + * Return 0 on success, -1 on failure. + */ +int32_t minipal_get_cryptographically_secure_random_bytes(uint8_t* buffer, int32_t bufferLength); + + +#ifdef __cplusplus +} +#endif // __cplusplus +#endif /* HAVE_MINIPAL_RANDOM_H */