diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index ba5e47ef67e..55b2a113316 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -218,6 +218,7 @@ DTLS_RECEIVEFROM_NO_TIMEOUT_ON_INVALID_PEER ECCSI_ORDER_MORE_BITS_THAN_PRIME ECC_DUMP_OID ECDHE_SIZE +EFD_CLOEXEC ENABLED_BSDKM_REGISTER ENABLE_SECURE_SOCKETS_LOGS ESP32 @@ -233,6 +234,7 @@ ETHERNET_AVAILABLE ETHERNET_H EV_TRIGGER EXTERNAL_LOADER_APP +FD_CLOEXEC FIPS_OPTEST_FULL_RUN_AT_MODULE_INIT FORCE_FAILURE_GETRANDOM FP_ECC_CONTROL @@ -314,6 +316,7 @@ ID_TRNG IGNORE_KEY_EXTENSIONS IGNORE_NETSCAPE_CERT_TYPE INCLUDE_uxTaskGetStackHighWaterMark +IN_CLOEXEC INTEGRITY INTIMEVER IOTSAFE_NO_GETDATA @@ -466,6 +469,7 @@ NO_WOLFSSL_XILINX_TAG_MALLOC NRF52 NRF52_SERIES NRF_ERROR_MODULE_ALREADY_INITIALIZED +O_CLOEXEC OLD_HELLO_ALLOWED OPENSSL_EXTRA_BSD OPENSSL_EXTRA_NO_ASN1 @@ -475,6 +479,7 @@ OS_WINDOWS OTHERBOARD OTHER_BOARD PEER_INFO +PERF_FLAG_FD_CLOEXEC PKA_ECC_SCALAR_MUL_IN_B_COEFF PLATFORMIO PLUTON_CRYPTO_ECC @@ -517,6 +522,7 @@ SL_SE_KEY_TYPE_ECC_X25519 SL_SE_KEY_TYPE_ECC_X448 SL_SE_PRF_HMAC_SHA1 SNIFFER_SINGLE_SESSION_CACHE +SOCK_CLOEXEC SOFTDEVICE_PRESENT SO_NOSIGPIPE SO_REUSEPORT diff --git a/src/crl.c b/src/crl.c index 62c207de526..ef4674fd3ff 100644 --- a/src/crl.c +++ b/src/crl.c @@ -1659,6 +1659,7 @@ static int SwapLists(WOLFSSL_CRL* crl) #include #include #include +#include #ifdef __MACH__ #define XEVENT_MODE O_EVTONLY @@ -1666,6 +1667,11 @@ static int SwapLists(WOLFSSL_CRL* crl) #define XEVENT_MODE O_RDONLY #endif +/* Fall back to no-op if O_CLOEXEC is unavailable on this platform. */ +#ifndef O_CLOEXEC + #define O_CLOEXEC 0 +#endif + /* we need a unique kqueue user filter fd for crl in case user is doing custom * events too */ @@ -1710,6 +1716,13 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) SignalSetup(crl, MONITOR_SETUP_E); return NULL; } +#ifdef FD_CLOEXEC + { + int fdFlags = fcntl(crl->mfd, F_GETFD); + if (fdFlags >= 0) + (void)fcntl(crl->mfd, F_SETFD, fdFlags | FD_CLOEXEC); + } +#endif /* listen for custom shutdown event */ EV_SET(&change, CRL_CUSTOM_FD, EVFILT_USER, EV_ADD, 0, 0, NULL); @@ -1724,7 +1737,17 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) fDER = -1; if (crl->monitors[0].path) { - fPEM = open(crl->monitors[0].path, XEVENT_MODE); + fPEM = open(crl->monitors[0].path, XEVENT_MODE | O_CLOEXEC); + #ifdef FD_CLOEXEC + if (fPEM == -1 && errno == EINVAL) { + fPEM = open(crl->monitors[0].path, XEVENT_MODE); + if (fPEM >= 0) { + int fdFlags = fcntl(fPEM, F_GETFD); + if (fdFlags >= 0) + (void)fcntl(fPEM, F_SETFD, fdFlags | FD_CLOEXEC); + } + } + #endif if (fPEM == -1) { WOLFSSL_MSG("PEM event dir open failed"); SignalSetup(crl, MONITOR_SETUP_E); @@ -1734,7 +1757,17 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) } if (crl->monitors[1].path) { - fDER = open(crl->monitors[1].path, XEVENT_MODE); + fDER = open(crl->monitors[1].path, XEVENT_MODE | O_CLOEXEC); + #ifdef FD_CLOEXEC + if (fDER == -1 && errno == EINVAL) { + fDER = open(crl->monitors[1].path, XEVENT_MODE); + if (fDER >= 0) { + int fdFlags = fcntl(fDER, F_GETFD); + if (fdFlags >= 0) + (void)fcntl(fDER, F_SETFD, fdFlags | FD_CLOEXEC); + } + } + #endif if (fDER == -1) { WOLFSSL_MSG("DER event dir open failed"); if (fPEM != -1) @@ -1801,6 +1834,13 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) #include #include #include +#include +#include + +/* Fall back to no-op if EFD_CLOEXEC is unavailable. */ +#ifndef EFD_CLOEXEC + #define EFD_CLOEXEC 0 +#endif #ifndef max @@ -1836,14 +1876,45 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) WOLFSSL_ENTER("DoMonitor"); - crl->mfd = eventfd(0, 0); /* our custom shutdown event */ + crl->mfd = eventfd(0, EFD_CLOEXEC); /* our custom shutdown event */ +#ifdef FD_CLOEXEC + if (crl->mfd < 0 && errno == EINVAL) { + crl->mfd = eventfd(0, 0); + if (crl->mfd >= 0) { + int fdFlags = fcntl(crl->mfd, F_GETFD); + if (fdFlags >= 0) + (void)fcntl(crl->mfd, F_SETFD, fdFlags | FD_CLOEXEC); + } + } +#endif if (crl->mfd < 0) { WOLFSSL_MSG("eventfd failed"); SignalSetup(crl, MONITOR_SETUP_E); return NULL; } +#ifdef IN_CLOEXEC + notifyFd = inotify_init1(IN_CLOEXEC); + if (notifyFd < 0 && (errno == ENOSYS || errno == EINVAL)) { + notifyFd = inotify_init(); + #ifdef FD_CLOEXEC + if (notifyFd >= 0) { + int fdFlags = fcntl(notifyFd, F_GETFD); + if (fdFlags >= 0) + (void)fcntl(notifyFd, F_SETFD, fdFlags | FD_CLOEXEC); + } + #endif + } +#else notifyFd = inotify_init(); + #ifdef FD_CLOEXEC + if (notifyFd >= 0) { + int fdFlags = fcntl(notifyFd, F_GETFD); + if (fdFlags >= 0) + (void)fcntl(notifyFd, F_SETFD, fdFlags | FD_CLOEXEC); + } + #endif +#endif if (notifyFd < 0) { WOLFSSL_MSG("inotify failed"); (void)close(crl->mfd); diff --git a/src/ssl.c b/src/ssl.c index 58cd6701c02..23ceec475ea 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -19568,6 +19568,9 @@ int wolfSSL_RAND_write_file(const char* fname) defined(HAVE_SYS_UN_H) #define WOLFSSL_EGD_NBLOCK 0x01 #include + #ifndef SOCK_CLOEXEC + #define SOCK_CLOEXEC 0 + #endif #endif /* This collects entropy from the path nm and seeds the global PRNG with it. @@ -19601,7 +19604,17 @@ int wolfSSL_RAND_egd(const char* nm) return WOLFSSL_FATAL_ERROR; } - fd = socket(AF_UNIX, SOCK_STREAM, 0); + fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); +#ifdef FD_CLOEXEC + if (fd < 0 && errno == EINVAL) { + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd >= 0) { + int fdFlags = fcntl(fd, F_GETFD); + if (fdFlags >= 0) + (void)fcntl(fd, F_SETFD, fdFlags | FD_CLOEXEC); + } + } +#endif if (fd < 0) { WOLFSSL_MSG("Error creating socket"); WC_FREE_VAR_EX(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); diff --git a/src/wolfio.c b/src/wolfio.c index c6ffe7da11b..14ec999b24e 100644 --- a/src/wolfio.c +++ b/src/wolfio.c @@ -24,6 +24,15 @@ #define WOLFSSL_STRERROR_BUFFER_SIZE 256 #endif +/* Enable GNU extensions for accept4() on Linux/glibc. Must be defined + * before any system headers are included. Excluded for Zephyr and other + * embedded RTOSes whose libc layers conflict with glibc-style definitions + * (e.g., Zephyr's socket_select.h vs. glibc's fd_set). */ +#if (defined(__linux__) || defined(__ANDROID__)) && \ + !defined(WOLFSSL_ZEPHYR) && !defined(_GNU_SOURCE) + #define _GNU_SOURCE 1 +#endif + #include #ifndef WOLFCRYPT_ONLY @@ -42,6 +51,12 @@ #include #include +/* SOCK_CLOEXEC sets close-on-exec atomically when the socket is created; + * fall back to a no-op flag value where it isn't supported. */ +#ifndef SOCK_CLOEXEC + #define SOCK_CLOEXEC 0 +#endif + #ifdef NUCLEUS_PLUS_2_3 /* Holds last Nucleus networking error number */ int Nucleus_Net_Errno; @@ -1494,7 +1509,17 @@ int wolfIO_TcpConnect(SOCKET_T* sockfd, const char* ip, word16 port, int to_sec) } #endif - *sockfd = (SOCKET_T)socket(addr.ss_family, SOCK_STREAM, 0); + *sockfd = (SOCKET_T)socket(addr.ss_family, SOCK_STREAM | SOCK_CLOEXEC, 0); +#if !defined(USE_WINDOWS_API) && defined(FD_CLOEXEC) + if (*sockfd <= SOCKET_INVALID && errno == EINVAL) { + *sockfd = (SOCKET_T)socket(addr.ss_family, SOCK_STREAM, 0); + if (*sockfd > SOCKET_INVALID) { + int fdFlags = fcntl(*sockfd, F_GETFD); + if (fdFlags >= 0) + (void)fcntl(*sockfd, F_SETFD, fdFlags | FD_CLOEXEC); + } + } +#endif #ifdef USE_WINDOWS_API if (*sockfd == SOCKET_INVALID) #else @@ -1572,12 +1597,32 @@ int wolfIO_TcpBind(SOCKET_T* sockfd, word16 port) sin->sin6_family = AF_INET6; sin->sin6_addr = in6addr_any; sin->sin6_port = XHTONS(port); - *sockfd = (SOCKET_T)socket(AF_INET6, SOCK_STREAM, 0); + *sockfd = (SOCKET_T)socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0); +#if defined(FD_CLOEXEC) + if (*sockfd <= SOCKET_INVALID && errno == EINVAL) { + *sockfd = (SOCKET_T)socket(AF_INET6, SOCK_STREAM, 0); + if (*sockfd > SOCKET_INVALID) { + int fdFlags = fcntl(*sockfd, F_GETFD); + if (fdFlags >= 0) + (void)fcntl(*sockfd, F_SETFD, fdFlags | FD_CLOEXEC); + } + } +#endif #else sin->sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_ANY; sin->sin_port = XHTONS(port); - *sockfd = (SOCKET_T)socket(AF_INET, SOCK_STREAM, 0); + *sockfd = (SOCKET_T)socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0); +#if defined(FD_CLOEXEC) + if (*sockfd <= SOCKET_INVALID && errno == EINVAL) { + *sockfd = (SOCKET_T)socket(AF_INET, SOCK_STREAM, 0); + if (*sockfd > SOCKET_INVALID) { + int fdFlags = fcntl(*sockfd, F_GETFD); + if (fdFlags >= 0) + (void)fcntl(*sockfd, F_SETFD, fdFlags | FD_CLOEXEC); + } + } +#endif #endif #ifdef USE_WINDOWS_API @@ -1623,7 +1668,31 @@ int wolfIO_TcpBind(SOCKET_T* sockfd, word16 port) #ifdef HAVE_SOCKADDR int wolfIO_TcpAccept(SOCKET_T sockfd, SOCKADDR* peer_addr, XSOCKLENT* peer_len) { - return (int)accept(sockfd, peer_addr, peer_len); + int fd; +#if !defined(USE_WINDOWS_API) && !defined(WOLFSSL_ZEPHYR) && \ + (defined(__linux__) || defined(__ANDROID__)) + fd = (int)accept4(sockfd, peer_addr, peer_len, SOCK_CLOEXEC); + if (fd < 0 && (errno == ENOSYS || errno == EINVAL)) { + fd = (int)accept(sockfd, peer_addr, peer_len); + #ifdef FD_CLOEXEC + if (fd >= 0) { + int fdFlags = fcntl(fd, F_GETFD); + if (fdFlags >= 0) + (void)fcntl(fd, F_SETFD, fdFlags | FD_CLOEXEC); + } + #endif + } +#else + fd = (int)accept(sockfd, peer_addr, peer_len); +#if defined(FD_CLOEXEC) && !defined(USE_WINDOWS_API) + if (fd >= 0) { + int fdFlags = fcntl(fd, F_GETFD); + if (fdFlags >= 0) + (void)fcntl(fd, F_SETFD, fdFlags | FD_CLOEXEC); + } +#endif +#endif + return fd; } #endif /* HAVE_SOCKADDR */ diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index 3b3c4159d9e..bd10a7d5d51 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -1574,16 +1574,34 @@ static const char* bench_result_words3[][5] = { #include #include #include + #include + #include + + #ifndef PERF_FLAG_FD_CLOEXEC + #define PERF_FLAG_FD_CLOEXEC (1UL << 3) + #endif static THREAD_LS_T word64 begin_cycles; static THREAD_LS_T word64 total_cycles; static THREAD_LS_T int cycles = -1; static THREAD_LS_T struct perf_event_attr atr; + /* Try with PERF_FLAG_FD_CLOEXEC first; on older kernels (< 3.14) this + * fails with EINVAL, so fall back to flags=0 and set FD_CLOEXEC via + * fcntl() as a best-effort. */ #define INIT_CYCLE_COUNTER do { \ atr.type = PERF_TYPE_HARDWARE; \ atr.config = PERF_COUNT_HW_CPU_CYCLES; \ - cycles = (int)syscall(__NR_perf_event_open, &atr, 0, -1, -1, 0); \ + cycles = (int)syscall(__NR_perf_event_open, &atr, 0, -1, -1, \ + PERF_FLAG_FD_CLOEXEC); \ + if (cycles < 0 && errno == EINVAL) { \ + cycles = (int)syscall(__NR_perf_event_open, &atr, 0, -1, -1, 0); \ + if (cycles >= 0) { \ + int _fdFlags = fcntl(cycles, F_GETFD); \ + if (_fdFlags >= 0) \ + (void)fcntl(cycles, F_SETFD, _fdFlags | FD_CLOEXEC); \ + } \ + } \ } while (0); #define BEGIN_CYCLES read(cycles, &begin_cycles, sizeof(begin_cycles)); diff --git a/wolfcrypt/src/port/af_alg/afalg_hash.c b/wolfcrypt/src/port/af_alg/afalg_hash.c index 429bb7d04b4..890b0fe5e81 100644 --- a/wolfcrypt/src/port/af_alg/afalg_hash.c +++ b/wolfcrypt/src/port/af_alg/afalg_hash.c @@ -19,6 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ +#if defined(__linux__) && !defined(_GNU_SOURCE) + #define _GNU_SOURCE 1 +#endif + #include #if defined(WOLFSSL_AFALG_HASH) || (defined(WOLFSSL_AFALG_XILINX_SHA3) \ @@ -26,6 +30,8 @@ #include #include +#include +#include static const char WC_TYPE_HASH[] = "hash"; @@ -223,8 +229,33 @@ static int AfalgHashCopy(wolfssl_AFALG_Hash* src, wolfssl_AFALG_Hash* dst) } #endif - dst->rdFd = accept(src->rdFd, NULL, 0); - dst->alFd = accept(src->alFd, NULL, 0); +#if defined(__linux__) && defined(SOCK_CLOEXEC) + dst->rdFd = accept4(src->rdFd, NULL, NULL, SOCK_CLOEXEC); + if (dst->rdFd < 0 && (errno == ENOSYS || errno == EINVAL)) { + dst->rdFd = accept(src->rdFd, NULL, NULL); + #ifdef FD_CLOEXEC + if (dst->rdFd >= 0) { + int fdFlags = fcntl(dst->rdFd, F_GETFD); + if (fdFlags >= 0) + (void)fcntl(dst->rdFd, F_SETFD, fdFlags | FD_CLOEXEC); + } + #endif + } + dst->alFd = accept4(src->alFd, NULL, NULL, SOCK_CLOEXEC); + if (dst->alFd < 0 && (errno == ENOSYS || errno == EINVAL)) { + dst->alFd = accept(src->alFd, NULL, NULL); + #ifdef FD_CLOEXEC + if (dst->alFd >= 0) { + int fdFlags = fcntl(dst->alFd, F_GETFD); + if (fdFlags >= 0) + (void)fcntl(dst->alFd, F_SETFD, fdFlags | FD_CLOEXEC); + } + #endif + } +#else + dst->rdFd = accept(src->rdFd, NULL, NULL); + dst->alFd = accept(src->alFd, NULL, NULL); +#endif if (dst->rdFd == WC_SOCK_NOTSET || dst->alFd == WC_SOCK_NOTSET) { AfalgHashFree(dst); diff --git a/wolfcrypt/src/port/af_alg/wc_afalg.c b/wolfcrypt/src/port/af_alg/wc_afalg.c index b5a1f878ad5..818c6318886 100644 --- a/wolfcrypt/src/port/af_alg/wc_afalg.c +++ b/wolfcrypt/src/port/af_alg/wc_afalg.c @@ -19,12 +19,23 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ +#if defined(__linux__) && !defined(_GNU_SOURCE) + #define _GNU_SOURCE 1 +#endif + #include #if defined(WOLFSSL_AFALG) || defined(WOLFSSL_AFALG_XILINX) #include #include +#include +#include +#include + +#ifndef SOCK_CLOEXEC + #define SOCK_CLOEXEC 0 +#endif /* Sets the type of socket address to use */ @@ -56,7 +67,24 @@ int wc_Afalg_Accept(struct sockaddr_alg* in, int inSz, int sock) return WC_AFALG_SOCK_E; } - return accept(sock, NULL, 0); +#if defined(__linux__) + { + int fd = accept4(sock, NULL, NULL, SOCK_CLOEXEC); + if (fd < 0 && (errno == ENOSYS || errno == EINVAL)) { + fd = accept(sock, NULL, NULL); + #ifdef FD_CLOEXEC + if (fd >= 0) { + int fdFlags = fcntl(fd, F_GETFD); + if (fdFlags >= 0) + (void)fcntl(fd, F_SETFD, fdFlags | FD_CLOEXEC); + } + #endif + } + return fd; + } +#else + return accept(sock, NULL, NULL); +#endif } @@ -66,7 +94,18 @@ int wc_Afalg_Socket(void) { int sock; - if ((sock = socket(AF_ALG, SOCK_SEQPACKET, 0)) < 0) { + sock = socket(AF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); +#ifdef FD_CLOEXEC + if (sock < 0 && errno == EINVAL) { + sock = socket(AF_ALG, SOCK_SEQPACKET, 0); + if (sock >= 0) { + int fdFlags = fcntl(sock, F_GETFD); + if (fdFlags >= 0) + (void)fcntl(sock, F_SETFD, fdFlags | FD_CLOEXEC); + } + } +#endif + if (sock < 0) { WOLFSSL_MSG("Failed to get AF_ALG socket"); return WC_AFALG_SOCK_E; } diff --git a/wolfcrypt/src/port/caam/wolfcaam_qnx.c b/wolfcrypt/src/port/caam/wolfcaam_qnx.c index 71d5cbfb61e..f6942f3e04e 100644 --- a/wolfcrypt/src/port/caam/wolfcaam_qnx.c +++ b/wolfcrypt/src/port/caam/wolfcaam_qnx.c @@ -36,6 +36,10 @@ #include +#ifndef O_CLOEXEC + #define O_CLOEXEC 0 +#endif + /* for devctl use */ int caamFd = -1; static wolfSSL_Mutex caamMutex; @@ -48,7 +52,7 @@ int wc_CAAMInitInterface() return -1; } - caamFd = open("/dev/wolfCrypt", O_RDWR); + caamFd = open("/dev/wolfCrypt", O_RDWR | O_CLOEXEC); if (caamFd < 0) { WOLFSSL_MSG("Could not open /dev/wolfCrypt"); return -1; diff --git a/wolfcrypt/src/port/devcrypto/wc_devcrypto.c b/wolfcrypt/src/port/devcrypto/wc_devcrypto.c index 21fb9808000..4c8719df8e6 100644 --- a/wolfcrypt/src/port/devcrypto/wc_devcrypto.c +++ b/wolfcrypt/src/port/devcrypto/wc_devcrypto.c @@ -26,11 +26,27 @@ static volatile int fd; #include +#include + +#ifndef O_CLOEXEC + #define O_CLOEXEC 0 +#endif int wc_DevCryptoInit(void) { /* create descriptor */ - if ((fd = open("/dev/crypto", O_RDWR, 0)) < 0) { + fd = open("/dev/crypto", O_RDWR | O_CLOEXEC, 0); +#ifdef FD_CLOEXEC + if (fd < 0 && errno == EINVAL) { + fd = open("/dev/crypto", O_RDWR, 0); + if (fd >= 0) { + int fdFlags = fcntl(fd, F_GETFD); + if (fdFlags >= 0) + (void)fcntl(fd, F_SETFD, fdFlags | FD_CLOEXEC); + } + } +#endif + if (fd < 0) { WOLFSSL_MSG("Error opening /dev/crypto is cryptodev module loaded?"); return WC_DEVCRYPTO_E; } diff --git a/wolfcrypt/src/port/intel/quickassist_mem.c b/wolfcrypt/src/port/intel/quickassist_mem.c index 63d01d9f325..fe007e90786 100644 --- a/wolfcrypt/src/port/intel/quickassist_mem.c +++ b/wolfcrypt/src/port/intel/quickassist_mem.c @@ -57,6 +57,11 @@ #include #include #include +#include + +#ifndef O_CLOEXEC + #define O_CLOEXEC 0 +#endif #ifdef SAL_IOMMU_CODE #include @@ -714,7 +719,17 @@ CpaStatus qaeMemInit(void) { if (g_qaeMemFd < 0) { #ifndef QAT_V2 - g_qaeMemFd = open(QAE_MEM, O_RDWR); + g_qaeMemFd = open(QAE_MEM, O_RDWR | O_CLOEXEC); + #ifdef FD_CLOEXEC + if (g_qaeMemFd < 0 && errno == EINVAL) { + g_qaeMemFd = open(QAE_MEM, O_RDWR); + if (g_qaeMemFd >= 0) { + int fdFlags = fcntl(g_qaeMemFd, F_GETFD); + if (fdFlags >= 0) + (void)fcntl(g_qaeMemFd, F_SETFD, fdFlags | FD_CLOEXEC); + } + } + #endif if (g_qaeMemFd < 0) { printf("unable to open %s %d\n", QAE_MEM, g_qaeMemFd); return CPA_STATUS_FAIL; diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index 9fa318c7608..0567e5c3102 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -204,8 +204,8 @@ This library contains implementation for the random number generator. #elif defined(WOLFSSL_MAX3266X) || defined(WOLFSSL_MAX3266X_OLD) #include "wolfssl/wolfcrypt/port/maxim/max3266x.h" #else + #include #if defined(WOLFSSL_GETRANDOM) || defined(HAVE_GETRANDOM) - #include #include #endif /* include headers that may be needed to get good seed */ @@ -213,6 +213,30 @@ This library contains implementation for the random number generator. #ifndef EBSNET #include #endif + /* O_CLOEXEC is preferred (atomic close-on-exec at open() time) but + * is unavailable on older kernels and some platforms; fall back to a + * no-op so the | flag has no effect. */ + #ifndef O_CLOEXEC + #define O_CLOEXEC 0 + #endif + + /* Try open() with O_CLOEXEC; if the running kernel rejects O_CLOEXEC + * (EINVAL), retry without it and set FD_CLOEXEC via fcntl(). */ + static WC_INLINE int wc_open_cloexec(const char* path, int flags) + { + int fd = open(path, flags | O_CLOEXEC); + #ifdef FD_CLOEXEC + if (fd < 0 && errno == EINVAL) { + fd = open(path, flags); + if (fd >= 0) { + int fdFlags = fcntl(fd, F_GETFD); + if (fdFlags >= 0) + (void)fcntl(fd, F_SETFD, fdFlags | FD_CLOEXEC); + } + } + #endif + return fd; + } #endif #if defined(WOLFSSL_SILABS_SE_ACCEL) @@ -3829,7 +3853,7 @@ int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) if (!os->seedFdOpen) { #ifndef NO_DEV_URANDOM /* way to disable use of /dev/urandom */ - os->fd = open("/dev/urandom", O_RDONLY); + os->fd = wc_open_cloexec("/dev/urandom", O_RDONLY); #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG("opened /dev/urandom."); #endif /* DEBUG_WOLFSSL */ @@ -3837,7 +3861,7 @@ int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) #endif /* NO_DEV_URANDOM */ { /* may still have /dev/random */ - os->fd = open("/dev/random", O_RDONLY); + os->fd = wc_open_cloexec("/dev/random", O_RDONLY); #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG("opened /dev/random."); #endif /* DEBUG_WOLFSSL */ @@ -3855,7 +3879,7 @@ int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) } #else /* WOLFSSL_KEEP_RNG_SEED_FD_OPEN */ #ifndef NO_DEV_URANDOM /* way to disable use of /dev/urandom */ - os->fd = open("/dev/urandom", O_RDONLY); + os->fd = wc_open_cloexec("/dev/urandom", O_RDONLY); #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG("opened /dev/urandom."); #endif /* DEBUG_WOLFSSL */ @@ -3863,7 +3887,7 @@ int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) #endif /* !NO_DEV_URANDOM */ { /* may still have /dev/random */ - os->fd = open("/dev/random", O_RDONLY); + os->fd = wc_open_cloexec("/dev/random", O_RDONLY); #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG("opened /dev/random."); #endif /* DEBUG_WOLFSSL */ @@ -3940,11 +3964,25 @@ int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) #if defined(CUSTOM_RAND_GENERATE_BLOCK) && defined(WOLFSSL_KCAPI) #include +#include +#ifndef O_CLOEXEC + #define O_CLOEXEC 0 +#endif int wc_hwrng_generate_block(byte *output, word32 sz) { int fd; int ret = 0; - fd = open("/dev/hwrng", O_RDONLY); + fd = open("/dev/hwrng", O_RDONLY | O_CLOEXEC); +#ifdef FD_CLOEXEC + if (fd == -1 && errno == EINVAL) { + fd = open("/dev/hwrng", O_RDONLY); + if (fd >= 0) { + int fdFlags = fcntl(fd, F_GETFD); + if (fdFlags >= 0) + (void)fcntl(fd, F_SETFD, fdFlags | FD_CLOEXEC); + } + } +#endif if (fd == -1) return OPEN_RAN_E; while(sz)