From 5dd1eb7739099af9002d4099a8ac9896efc24e6d Mon Sep 17 00:00:00 2001 From: Eric Blankenhorn Date: Tue, 7 Apr 2026 17:07:14 -0500 Subject: [PATCH 1/6] Use O_CLOEXEC to avoid race conditions --- src/crl.c | 13 ++++++++++--- src/ssl.c | 2 +- src/wolfio.c | 13 +++++++++---- wolfcrypt/benchmark/benchmark.c | 7 ++++++- wolfcrypt/src/port/af_alg/afalg_hash.c | 5 +++++ wolfcrypt/src/port/af_alg/wc_afalg.c | 6 +++++- wolfcrypt/src/port/caam/wolfcaam_qnx.c | 2 +- wolfcrypt/src/port/devcrypto/wc_devcrypto.c | 2 +- wolfcrypt/src/port/intel/quickassist_mem.c | 2 +- wolfcrypt/src/random.c | 10 +++++----- wolfssl/wolfcrypt/wc_port.h | 20 ++++++++++++++++++++ 11 files changed, 64 insertions(+), 18 deletions(-) diff --git a/src/crl.c b/src/crl.c index 62c207de526..43b2c880055 100644 --- a/src/crl.c +++ b/src/crl.c @@ -1710,6 +1710,9 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) SignalSetup(crl, MONITOR_SETUP_E); return NULL; } +#ifdef FD_CLOEXEC + (void)fcntl(crl->mfd, F_SETFD, FD_CLOEXEC); +#endif /* listen for custom shutdown event */ EV_SET(&change, CRL_CUSTOM_FD, EVFILT_USER, EV_ADD, 0, 0, NULL); @@ -1724,7 +1727,7 @@ 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 | WC_CLOEXEC); if (fPEM == -1) { WOLFSSL_MSG("PEM event dir open failed"); SignalSetup(crl, MONITOR_SETUP_E); @@ -1734,7 +1737,7 @@ 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 | WC_CLOEXEC); if (fDER == -1) { WOLFSSL_MSG("DER event dir open failed"); if (fPEM != -1) @@ -1836,14 +1839,18 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) WOLFSSL_ENTER("DoMonitor"); - crl->mfd = eventfd(0, 0); /* our custom shutdown event */ + crl->mfd = eventfd(0, WC_EFD_CLOEXEC); /* our custom shutdown event */ if (crl->mfd < 0) { WOLFSSL_MSG("eventfd failed"); SignalSetup(crl, MONITOR_SETUP_E); return NULL; } +#ifdef IN_CLOEXEC + notifyFd = inotify_init1(IN_CLOEXEC); +#else notifyFd = inotify_init(); +#endif if (notifyFd < 0) { WOLFSSL_MSG("inotify failed"); (void)close(crl->mfd); diff --git a/src/ssl.c b/src/ssl.c index 58cd6701c02..7f4d25fe8e1 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -19601,7 +19601,7 @@ int wolfSSL_RAND_egd(const char* nm) return WOLFSSL_FATAL_ERROR; } - fd = socket(AF_UNIX, SOCK_STREAM, 0); + fd = socket(AF_UNIX, SOCK_STREAM | WC_SOCK_CLOEXEC, 0); 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..71ee6bc99aa 100644 --- a/src/wolfio.c +++ b/src/wolfio.c @@ -1494,7 +1494,7 @@ 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 | WC_SOCK_CLOEXEC, 0); #ifdef USE_WINDOWS_API if (*sockfd == SOCKET_INVALID) #else @@ -1572,12 +1572,12 @@ 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 | WC_SOCK_CLOEXEC, 0); #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 | WC_SOCK_CLOEXEC, 0); #endif #ifdef USE_WINDOWS_API @@ -1623,7 +1623,12 @@ 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 = (int)accept(sockfd, peer_addr, peer_len); +#if defined(FD_CLOEXEC) && !defined(USE_WINDOWS_API) + if (fd >= 0) + (void)fcntl(fd, F_SETFD, FD_CLOEXEC); +#endif + return fd; } #endif /* HAVE_SOCKADDR */ diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index 3b3c4159d9e..d229ce82737 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -1575,6 +1575,10 @@ static const char* bench_result_words3[][5] = { #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; @@ -1583,7 +1587,8 @@ static const char* bench_result_words3[][5] = { #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); \ } 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..cf455eade3b 100644 --- a/wolfcrypt/src/port/af_alg/afalg_hash.c +++ b/wolfcrypt/src/port/af_alg/afalg_hash.c @@ -223,8 +223,13 @@ static int AfalgHashCopy(wolfssl_AFALG_Hash* src, wolfssl_AFALG_Hash* dst) } #endif +#if defined(__linux__) && defined(SOCK_CLOEXEC) + dst->rdFd = accept4(src->rdFd, NULL, 0, SOCK_CLOEXEC); + dst->alFd = accept4(src->alFd, NULL, 0, SOCK_CLOEXEC); +#else dst->rdFd = accept(src->rdFd, NULL, 0); dst->alFd = accept(src->alFd, NULL, 0); +#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..c28e17f2717 100644 --- a/wolfcrypt/src/port/af_alg/wc_afalg.c +++ b/wolfcrypt/src/port/af_alg/wc_afalg.c @@ -56,7 +56,11 @@ int wc_Afalg_Accept(struct sockaddr_alg* in, int inSz, int sock) return WC_AFALG_SOCK_E; } +#if defined(__linux__) && defined(SOCK_CLOEXEC) + return accept4(sock, NULL, 0, SOCK_CLOEXEC); +#else return accept(sock, NULL, 0); +#endif } @@ -66,7 +70,7 @@ int wc_Afalg_Socket(void) { int sock; - if ((sock = socket(AF_ALG, SOCK_SEQPACKET, 0)) < 0) { + if ((sock = socket(AF_ALG, SOCK_SEQPACKET | WC_SOCK_CLOEXEC, 0)) < 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..da00188007b 100644 --- a/wolfcrypt/src/port/caam/wolfcaam_qnx.c +++ b/wolfcrypt/src/port/caam/wolfcaam_qnx.c @@ -48,7 +48,7 @@ int wc_CAAMInitInterface() return -1; } - caamFd = open("/dev/wolfCrypt", O_RDWR); + caamFd = open("/dev/wolfCrypt", O_RDWR | WC_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..c39c8761b9c 100644 --- a/wolfcrypt/src/port/devcrypto/wc_devcrypto.c +++ b/wolfcrypt/src/port/devcrypto/wc_devcrypto.c @@ -30,7 +30,7 @@ static volatile int fd; int wc_DevCryptoInit(void) { /* create descriptor */ - if ((fd = open("/dev/crypto", O_RDWR, 0)) < 0) { + if ((fd = open("/dev/crypto", O_RDWR | WC_CLOEXEC, 0)) < 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..f8401c09b86 100644 --- a/wolfcrypt/src/port/intel/quickassist_mem.c +++ b/wolfcrypt/src/port/intel/quickassist_mem.c @@ -714,7 +714,7 @@ CpaStatus qaeMemInit(void) { if (g_qaeMemFd < 0) { #ifndef QAT_V2 - g_qaeMemFd = open(QAE_MEM, O_RDWR); + g_qaeMemFd = open(QAE_MEM, O_RDWR | WC_CLOEXEC); 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..aacc1a87ee0 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -3829,7 +3829,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 = open("/dev/urandom", O_RDONLY | WC_CLOEXEC); #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG("opened /dev/urandom."); #endif /* DEBUG_WOLFSSL */ @@ -3837,7 +3837,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 = open("/dev/random", O_RDONLY | WC_CLOEXEC); #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG("opened /dev/random."); #endif /* DEBUG_WOLFSSL */ @@ -3855,7 +3855,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 = open("/dev/urandom", O_RDONLY | WC_CLOEXEC); #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG("opened /dev/urandom."); #endif /* DEBUG_WOLFSSL */ @@ -3863,7 +3863,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 = open("/dev/random", O_RDONLY | WC_CLOEXEC); #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG("opened /dev/random."); #endif /* DEBUG_WOLFSSL */ @@ -3944,7 +3944,7 @@ 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 | WC_CLOEXEC); if (fd == -1) return OPEN_RAN_E; while(sz) diff --git a/wolfssl/wolfcrypt/wc_port.h b/wolfssl/wolfcrypt/wc_port.h index ade6b6c1da8..c5b6fd81c16 100644 --- a/wolfssl/wolfcrypt/wc_port.h +++ b/wolfssl/wolfcrypt/wc_port.h @@ -1860,6 +1860,26 @@ WOLFSSL_ABI WOLFSSL_API int wolfCrypt_Cleanup(void); #define WC_GENERATE_SEED_DEFAULT wc_GenerateSeed #endif +/* Close-on-exec flag macros for FD-creating syscalls. + * Prevents library-internal FDs from leaking into child processes + * across fork()+exec() in multithreaded programs. Falls back to 0 + * (no-op) on platforms that lack support. */ +#ifdef O_CLOEXEC + #define WC_CLOEXEC O_CLOEXEC +#else + #define WC_CLOEXEC 0 +#endif +#ifdef SOCK_CLOEXEC + #define WC_SOCK_CLOEXEC SOCK_CLOEXEC +#else + #define WC_SOCK_CLOEXEC 0 +#endif +#ifdef EFD_CLOEXEC + #define WC_EFD_CLOEXEC EFD_CLOEXEC +#else + #define WC_EFD_CLOEXEC 0 +#endif + #ifdef __cplusplus } /* extern "C" */ #endif From fd052e143cc4471fe26a19c4ad0c2d0fc52f8166 Mon Sep 17 00:00:00 2001 From: Eric Blankenhorn Date: Wed, 8 Apr 2026 08:18:14 -0500 Subject: [PATCH 2/6] Changes from review --- .wolfssl_known_macro_extras | 3 +++ src/wolfio.c | 21 ++++++++++++++++++--- wolfcrypt/benchmark/benchmark.c | 15 +++++++++++++-- wolfcrypt/src/port/af_alg/afalg_hash.c | 8 ++++---- wolfcrypt/src/port/af_alg/wc_afalg.c | 4 ++-- 5 files changed, 40 insertions(+), 11 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index ba5e47ef67e..a37668ce3c4 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -314,6 +314,7 @@ ID_TRNG IGNORE_KEY_EXTENSIONS IGNORE_NETSCAPE_CERT_TYPE INCLUDE_uxTaskGetStackHighWaterMark +IN_CLOEXEC INTEGRITY INTIMEVER IOTSAFE_NO_GETDATA @@ -466,6 +467,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 @@ -517,6 +519,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/wolfio.c b/src/wolfio.c index 71ee6bc99aa..fb0e0ddad59 100644 --- a/src/wolfio.c +++ b/src/wolfio.c @@ -24,6 +24,12 @@ #define WOLFSSL_STRERROR_BUFFER_SIZE 256 #endif +/* Enable GNU extensions for accept4() on Linux/glibc. Must be defined + * before any system headers are included. */ +#if !defined(_WIN32) && !defined(_GNU_SOURCE) + #define _GNU_SOURCE 1 +#endif + #include #ifndef WOLFCRYPT_ONLY @@ -1623,10 +1629,19 @@ int wolfIO_TcpBind(SOCKET_T* sockfd, word16 port) #ifdef HAVE_SOCKADDR int wolfIO_TcpAccept(SOCKET_T sockfd, SOCKADDR* peer_addr, XSOCKLENT* peer_len) { - int fd = (int)accept(sockfd, peer_addr, peer_len); + int fd; +#if !defined(USE_WINDOWS_API) && defined(SOCK_CLOEXEC) && \ + (defined(__linux__) || defined(__ANDROID__)) + fd = (int)accept4(sockfd, peer_addr, peer_len, SOCK_CLOEXEC); +#else + fd = (int)accept(sockfd, peer_addr, peer_len); #if defined(FD_CLOEXEC) && !defined(USE_WINDOWS_API) - if (fd >= 0) - (void)fcntl(fd, F_SETFD, FD_CLOEXEC); + if (fd >= 0) { + int fdFlags = fcntl(fd, F_GETFD); + if (fdFlags >= 0) + (void)fcntl(fd, F_SETFD, fdFlags | FD_CLOEXEC); + } +#endif #endif return fd; } diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index d229ce82737..371af457772 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -1584,11 +1584,22 @@ static const char* bench_result_words3[][5] = { 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, \ - PERF_FLAG_FD_CLOEXEC); \ + 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 cf455eade3b..ec1c7be1a88 100644 --- a/wolfcrypt/src/port/af_alg/afalg_hash.c +++ b/wolfcrypt/src/port/af_alg/afalg_hash.c @@ -224,11 +224,11 @@ static int AfalgHashCopy(wolfssl_AFALG_Hash* src, wolfssl_AFALG_Hash* dst) #endif #if defined(__linux__) && defined(SOCK_CLOEXEC) - dst->rdFd = accept4(src->rdFd, NULL, 0, SOCK_CLOEXEC); - dst->alFd = accept4(src->alFd, NULL, 0, SOCK_CLOEXEC); + dst->rdFd = accept4(src->rdFd, NULL, NULL, SOCK_CLOEXEC); + dst->alFd = accept4(src->alFd, NULL, NULL, SOCK_CLOEXEC); #else - dst->rdFd = accept(src->rdFd, NULL, 0); - dst->alFd = accept(src->alFd, NULL, 0); + 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) { diff --git a/wolfcrypt/src/port/af_alg/wc_afalg.c b/wolfcrypt/src/port/af_alg/wc_afalg.c index c28e17f2717..d2839efc838 100644 --- a/wolfcrypt/src/port/af_alg/wc_afalg.c +++ b/wolfcrypt/src/port/af_alg/wc_afalg.c @@ -57,9 +57,9 @@ int wc_Afalg_Accept(struct sockaddr_alg* in, int inSz, int sock) } #if defined(__linux__) && defined(SOCK_CLOEXEC) - return accept4(sock, NULL, 0, SOCK_CLOEXEC); + return accept4(sock, NULL, NULL, SOCK_CLOEXEC); #else - return accept(sock, NULL, 0); + return accept(sock, NULL, NULL); #endif } From b6087b677cccd7362ef5572538916dd9a243f99d Mon Sep 17 00:00:00 2001 From: Eric Blankenhorn Date: Wed, 8 Apr 2026 08:31:21 -0500 Subject: [PATCH 3/6] Fix Zephyr build --- src/wolfio.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/wolfio.c b/src/wolfio.c index fb0e0ddad59..107fa98c53a 100644 --- a/src/wolfio.c +++ b/src/wolfio.c @@ -25,8 +25,11 @@ #endif /* Enable GNU extensions for accept4() on Linux/glibc. Must be defined - * before any system headers are included. */ -#if !defined(_WIN32) && !defined(_GNU_SOURCE) + * 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(__ZEPHYR__) && !defined(_GNU_SOURCE) #define _GNU_SOURCE 1 #endif @@ -1630,8 +1633,8 @@ int wolfIO_TcpBind(SOCKET_T* sockfd, word16 port) int wolfIO_TcpAccept(SOCKET_T sockfd, SOCKADDR* peer_addr, XSOCKLENT* peer_len) { int fd; -#if !defined(USE_WINDOWS_API) && defined(SOCK_CLOEXEC) && \ - (defined(__linux__) || defined(__ANDROID__)) +#if !defined(USE_WINDOWS_API) && !defined(__ZEPHYR__) && \ + defined(SOCK_CLOEXEC) && (defined(__linux__) || defined(__ANDROID__)) fd = (int)accept4(sockfd, peer_addr, peer_len, SOCK_CLOEXEC); #else fd = (int)accept(sockfd, peer_addr, peer_len); From b0c5f233f6d9840ef4252159683a0426ddb9a5f8 Mon Sep 17 00:00:00 2001 From: Eric Blankenhorn Date: Wed, 8 Apr 2026 13:49:07 -0500 Subject: [PATCH 4/6] Updates from review --- .wolfssl_known_macro_extras | 3 +++ src/crl.c | 24 ++++++++++++++++++--- src/ssl.c | 5 ++++- src/wolfio.c | 16 +++++++++----- wolfcrypt/benchmark/benchmark.c | 1 + wolfcrypt/src/port/af_alg/wc_afalg.c | 7 +++++- wolfcrypt/src/port/caam/wolfcaam_qnx.c | 6 +++++- wolfcrypt/src/port/devcrypto/wc_devcrypto.c | 6 +++++- wolfcrypt/src/port/intel/quickassist_mem.c | 6 +++++- wolfcrypt/src/random.c | 19 +++++++++++----- wolfssl/wolfcrypt/wc_port.h | 20 ----------------- 11 files changed, 75 insertions(+), 38 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index a37668ce3c4..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 @@ -477,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 diff --git a/src/crl.c b/src/crl.c index 43b2c880055..78155cfe0c9 100644 --- a/src/crl.c +++ b/src/crl.c @@ -1666,6 +1666,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 */ @@ -1727,7 +1732,7 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) fDER = -1; if (crl->monitors[0].path) { - fPEM = open(crl->monitors[0].path, XEVENT_MODE | WC_CLOEXEC); + fPEM = open(crl->monitors[0].path, XEVENT_MODE | O_CLOEXEC); if (fPEM == -1) { WOLFSSL_MSG("PEM event dir open failed"); SignalSetup(crl, MONITOR_SETUP_E); @@ -1737,7 +1742,7 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) } if (crl->monitors[1].path) { - fDER = open(crl->monitors[1].path, XEVENT_MODE | WC_CLOEXEC); + fDER = open(crl->monitors[1].path, XEVENT_MODE | O_CLOEXEC); if (fDER == -1) { WOLFSSL_MSG("DER event dir open failed"); if (fPEM != -1) @@ -1804,6 +1809,12 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) #include #include #include +#include + +/* Fall back to no-op if EFD_CLOEXEC is unavailable. */ +#ifndef EFD_CLOEXEC + #define EFD_CLOEXEC 0 +#endif #ifndef max @@ -1839,7 +1850,7 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) WOLFSSL_ENTER("DoMonitor"); - crl->mfd = eventfd(0, WC_EFD_CLOEXEC); /* our custom shutdown event */ + crl->mfd = eventfd(0, EFD_CLOEXEC); /* our custom shutdown event */ if (crl->mfd < 0) { WOLFSSL_MSG("eventfd failed"); SignalSetup(crl, MONITOR_SETUP_E); @@ -1850,6 +1861,13 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) notifyFd = inotify_init1(IN_CLOEXEC); #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"); diff --git a/src/ssl.c b/src/ssl.c index 7f4d25fe8e1..653cb47e074 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,7 @@ int wolfSSL_RAND_egd(const char* nm) return WOLFSSL_FATAL_ERROR; } - fd = socket(AF_UNIX, SOCK_STREAM | WC_SOCK_CLOEXEC, 0); + fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); 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 107fa98c53a..d3f5d263910 100644 --- a/src/wolfio.c +++ b/src/wolfio.c @@ -29,7 +29,7 @@ * 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(__ZEPHYR__) && !defined(_GNU_SOURCE) + !defined(WOLFSSL_ZEPHYR) && !defined(_GNU_SOURCE) #define _GNU_SOURCE 1 #endif @@ -51,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; @@ -1503,7 +1509,7 @@ int wolfIO_TcpConnect(SOCKET_T* sockfd, const char* ip, word16 port, int to_sec) } #endif - *sockfd = (SOCKET_T)socket(addr.ss_family, SOCK_STREAM | WC_SOCK_CLOEXEC, 0); + *sockfd = (SOCKET_T)socket(addr.ss_family, SOCK_STREAM | SOCK_CLOEXEC, 0); #ifdef USE_WINDOWS_API if (*sockfd == SOCKET_INVALID) #else @@ -1581,12 +1587,12 @@ 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 | WC_SOCK_CLOEXEC, 0); + *sockfd = (SOCKET_T)socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0); #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 | WC_SOCK_CLOEXEC, 0); + *sockfd = (SOCKET_T)socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0); #endif #ifdef USE_WINDOWS_API @@ -1633,7 +1639,7 @@ int wolfIO_TcpBind(SOCKET_T* sockfd, word16 port) int wolfIO_TcpAccept(SOCKET_T sockfd, SOCKADDR* peer_addr, XSOCKLENT* peer_len) { int fd; -#if !defined(USE_WINDOWS_API) && !defined(__ZEPHYR__) && \ +#if !defined(USE_WINDOWS_API) && !defined(WOLFSSL_ZEPHYR) && \ defined(SOCK_CLOEXEC) && (defined(__linux__) || defined(__ANDROID__)) fd = (int)accept4(sockfd, peer_addr, peer_len, SOCK_CLOEXEC); #else diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index 371af457772..805c337839b 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -1574,6 +1574,7 @@ static const char* bench_result_words3[][5] = { #include #include #include + #include #ifndef PERF_FLAG_FD_CLOEXEC #define PERF_FLAG_FD_CLOEXEC (1UL << 3) diff --git a/wolfcrypt/src/port/af_alg/wc_afalg.c b/wolfcrypt/src/port/af_alg/wc_afalg.c index d2839efc838..e53e39644ee 100644 --- a/wolfcrypt/src/port/af_alg/wc_afalg.c +++ b/wolfcrypt/src/port/af_alg/wc_afalg.c @@ -25,6 +25,11 @@ #include #include +#include + +#ifndef SOCK_CLOEXEC + #define SOCK_CLOEXEC 0 +#endif /* Sets the type of socket address to use */ @@ -70,7 +75,7 @@ int wc_Afalg_Socket(void) { int sock; - if ((sock = socket(AF_ALG, SOCK_SEQPACKET | WC_SOCK_CLOEXEC, 0)) < 0) { + if ((sock = socket(AF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0)) < 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 da00188007b..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 | WC_CLOEXEC); + 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 c39c8761b9c..186c6ee306e 100644 --- a/wolfcrypt/src/port/devcrypto/wc_devcrypto.c +++ b/wolfcrypt/src/port/devcrypto/wc_devcrypto.c @@ -27,10 +27,14 @@ static volatile int fd; #include +#ifndef O_CLOEXEC + #define O_CLOEXEC 0 +#endif + int wc_DevCryptoInit(void) { /* create descriptor */ - if ((fd = open("/dev/crypto", O_RDWR | WC_CLOEXEC, 0)) < 0) { + if ((fd = open("/dev/crypto", O_RDWR | O_CLOEXEC, 0)) < 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 f8401c09b86..8f4205f888f 100644 --- a/wolfcrypt/src/port/intel/quickassist_mem.c +++ b/wolfcrypt/src/port/intel/quickassist_mem.c @@ -58,6 +58,10 @@ #include #include +#ifndef O_CLOEXEC + #define O_CLOEXEC 0 +#endif + #ifdef SAL_IOMMU_CODE #include #endif @@ -714,7 +718,7 @@ CpaStatus qaeMemInit(void) { if (g_qaeMemFd < 0) { #ifndef QAT_V2 - g_qaeMemFd = open(QAE_MEM, O_RDWR | WC_CLOEXEC); + g_qaeMemFd = open(QAE_MEM, O_RDWR | O_CLOEXEC); 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 aacc1a87ee0..65801ea3006 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -213,6 +213,12 @@ 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 #endif #if defined(WOLFSSL_SILABS_SE_ACCEL) @@ -3829,7 +3835,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 | WC_CLOEXEC); + os->fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG("opened /dev/urandom."); #endif /* DEBUG_WOLFSSL */ @@ -3837,7 +3843,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 | WC_CLOEXEC); + os->fd = open("/dev/random", O_RDONLY | O_CLOEXEC); #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG("opened /dev/random."); #endif /* DEBUG_WOLFSSL */ @@ -3855,7 +3861,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 | WC_CLOEXEC); + os->fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG("opened /dev/urandom."); #endif /* DEBUG_WOLFSSL */ @@ -3863,7 +3869,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 | WC_CLOEXEC); + os->fd = open("/dev/random", O_RDONLY | O_CLOEXEC); #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG("opened /dev/random."); #endif /* DEBUG_WOLFSSL */ @@ -3940,11 +3946,14 @@ int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) #if defined(CUSTOM_RAND_GENERATE_BLOCK) && defined(WOLFSSL_KCAPI) #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 | WC_CLOEXEC); + fd = open("/dev/hwrng", O_RDONLY | O_CLOEXEC); if (fd == -1) return OPEN_RAN_E; while(sz) diff --git a/wolfssl/wolfcrypt/wc_port.h b/wolfssl/wolfcrypt/wc_port.h index c5b6fd81c16..ade6b6c1da8 100644 --- a/wolfssl/wolfcrypt/wc_port.h +++ b/wolfssl/wolfcrypt/wc_port.h @@ -1860,26 +1860,6 @@ WOLFSSL_ABI WOLFSSL_API int wolfCrypt_Cleanup(void); #define WC_GENERATE_SEED_DEFAULT wc_GenerateSeed #endif -/* Close-on-exec flag macros for FD-creating syscalls. - * Prevents library-internal FDs from leaking into child processes - * across fork()+exec() in multithreaded programs. Falls back to 0 - * (no-op) on platforms that lack support. */ -#ifdef O_CLOEXEC - #define WC_CLOEXEC O_CLOEXEC -#else - #define WC_CLOEXEC 0 -#endif -#ifdef SOCK_CLOEXEC - #define WC_SOCK_CLOEXEC SOCK_CLOEXEC -#else - #define WC_SOCK_CLOEXEC 0 -#endif -#ifdef EFD_CLOEXEC - #define WC_EFD_CLOEXEC EFD_CLOEXEC -#else - #define WC_EFD_CLOEXEC 0 -#endif - #ifdef __cplusplus } /* extern "C" */ #endif From 3fb83aadd2388d72a139bb83ea4434c293dafd4d Mon Sep 17 00:00:00 2001 From: Eric Blankenhorn Date: Fri, 10 Apr 2026 13:33:44 -0500 Subject: [PATCH 5/6] Fixes from review --- src/crl.c | 6 +++++- src/wolfio.c | 2 +- wolfcrypt/src/port/af_alg/afalg_hash.c | 4 ++++ wolfcrypt/src/port/af_alg/wc_afalg.c | 6 +++++- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/crl.c b/src/crl.c index 78155cfe0c9..9e602163e7c 100644 --- a/src/crl.c +++ b/src/crl.c @@ -1716,7 +1716,11 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) return NULL; } #ifdef FD_CLOEXEC - (void)fcntl(crl->mfd, F_SETFD, 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 */ diff --git a/src/wolfio.c b/src/wolfio.c index d3f5d263910..aa4c625b63a 100644 --- a/src/wolfio.c +++ b/src/wolfio.c @@ -1640,7 +1640,7 @@ int wolfIO_TcpAccept(SOCKET_T sockfd, SOCKADDR* peer_addr, XSOCKLENT* peer_len) { int fd; #if !defined(USE_WINDOWS_API) && !defined(WOLFSSL_ZEPHYR) && \ - defined(SOCK_CLOEXEC) && (defined(__linux__) || defined(__ANDROID__)) + (defined(__linux__) || defined(__ANDROID__)) fd = (int)accept4(sockfd, peer_addr, peer_len, SOCK_CLOEXEC); #else fd = (int)accept(sockfd, peer_addr, peer_len); diff --git a/wolfcrypt/src/port/af_alg/afalg_hash.c b/wolfcrypt/src/port/af_alg/afalg_hash.c index ec1c7be1a88..415815eacbc 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) \ diff --git a/wolfcrypt/src/port/af_alg/wc_afalg.c b/wolfcrypt/src/port/af_alg/wc_afalg.c index e53e39644ee..aa8bc4ff53e 100644 --- a/wolfcrypt/src/port/af_alg/wc_afalg.c +++ b/wolfcrypt/src/port/af_alg/wc_afalg.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) || defined(WOLFSSL_AFALG_XILINX) @@ -61,7 +65,7 @@ int wc_Afalg_Accept(struct sockaddr_alg* in, int inSz, int sock) return WC_AFALG_SOCK_E; } -#if defined(__linux__) && defined(SOCK_CLOEXEC) +#if defined(__linux__) return accept4(sock, NULL, NULL, SOCK_CLOEXEC); #else return accept(sock, NULL, NULL); From 88207762c18dd0a395f6f9612749ff6c5fd7f4d3 Mon Sep 17 00:00:00 2001 From: Eric Blankenhorn Date: Fri, 10 Apr 2026 16:31:16 -0500 Subject: [PATCH 6/6] Fixes from review --- src/crl.c | 42 +++++++++++++++++++++ src/ssl.c | 10 +++++ src/wolfio.c | 40 ++++++++++++++++++++ wolfcrypt/benchmark/benchmark.c | 1 + wolfcrypt/src/port/af_alg/afalg_hash.c | 22 +++++++++++ wolfcrypt/src/port/af_alg/wc_afalg.c | 30 ++++++++++++++- wolfcrypt/src/port/devcrypto/wc_devcrypto.c | 14 ++++++- wolfcrypt/src/port/intel/quickassist_mem.c | 11 ++++++ wolfcrypt/src/random.c | 39 ++++++++++++++++--- 9 files changed, 201 insertions(+), 8 deletions(-) diff --git a/src/crl.c b/src/crl.c index 9e602163e7c..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 @@ -1737,6 +1738,16 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) if (crl->monitors[0].path) { 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); @@ -1747,6 +1758,16 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) if (crl->monitors[1].path) { 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) @@ -1814,6 +1835,7 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) #include #include #include +#include /* Fall back to no-op if EFD_CLOEXEC is unavailable. */ #ifndef EFD_CLOEXEC @@ -1855,6 +1877,16 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) WOLFSSL_ENTER("DoMonitor"); 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); @@ -1863,6 +1895,16 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) #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 diff --git a/src/ssl.c b/src/ssl.c index 653cb47e074..23ceec475ea 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -19605,6 +19605,16 @@ int wolfSSL_RAND_egd(const char* nm) } 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 aa4c625b63a..14ec999b24e 100644 --- a/src/wolfio.c +++ b/src/wolfio.c @@ -1510,6 +1510,16 @@ int wolfIO_TcpConnect(SOCKET_T* sockfd, const char* ip, word16 port, int to_sec) #endif *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 @@ -1588,11 +1598,31 @@ int wolfIO_TcpBind(SOCKET_T* sockfd, word16 port) sin->sin6_addr = in6addr_any; sin->sin6_port = XHTONS(port); *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 | 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 @@ -1642,6 +1672,16 @@ int wolfIO_TcpAccept(SOCKET_T sockfd, SOCKADDR* peer_addr, XSOCKLENT* peer_len) #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) diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index 805c337839b..bd10a7d5d51 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -1575,6 +1575,7 @@ static const char* bench_result_words3[][5] = { #include #include #include + #include #ifndef PERF_FLAG_FD_CLOEXEC #define PERF_FLAG_FD_CLOEXEC (1UL << 3) diff --git a/wolfcrypt/src/port/af_alg/afalg_hash.c b/wolfcrypt/src/port/af_alg/afalg_hash.c index 415815eacbc..890b0fe5e81 100644 --- a/wolfcrypt/src/port/af_alg/afalg_hash.c +++ b/wolfcrypt/src/port/af_alg/afalg_hash.c @@ -30,6 +30,8 @@ #include #include +#include +#include static const char WC_TYPE_HASH[] = "hash"; @@ -229,7 +231,27 @@ static int AfalgHashCopy(wolfssl_AFALG_Hash* src, wolfssl_AFALG_Hash* dst) #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); diff --git a/wolfcrypt/src/port/af_alg/wc_afalg.c b/wolfcrypt/src/port/af_alg/wc_afalg.c index aa8bc4ff53e..818c6318886 100644 --- a/wolfcrypt/src/port/af_alg/wc_afalg.c +++ b/wolfcrypt/src/port/af_alg/wc_afalg.c @@ -30,6 +30,8 @@ #include #include #include +#include +#include #ifndef SOCK_CLOEXEC #define SOCK_CLOEXEC 0 @@ -66,7 +68,20 @@ int wc_Afalg_Accept(struct sockaddr_alg* in, int inSz, int sock) } #if defined(__linux__) - return accept4(sock, NULL, NULL, SOCK_CLOEXEC); + { + 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 @@ -79,7 +94,18 @@ int wc_Afalg_Socket(void) { int sock; - if ((sock = socket(AF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 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/devcrypto/wc_devcrypto.c b/wolfcrypt/src/port/devcrypto/wc_devcrypto.c index 186c6ee306e..4c8719df8e6 100644 --- a/wolfcrypt/src/port/devcrypto/wc_devcrypto.c +++ b/wolfcrypt/src/port/devcrypto/wc_devcrypto.c @@ -26,6 +26,7 @@ static volatile int fd; #include +#include #ifndef O_CLOEXEC #define O_CLOEXEC 0 @@ -34,7 +35,18 @@ static volatile int fd; int wc_DevCryptoInit(void) { /* create descriptor */ - if ((fd = open("/dev/crypto", O_RDWR | O_CLOEXEC, 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 8f4205f888f..fe007e90786 100644 --- a/wolfcrypt/src/port/intel/quickassist_mem.c +++ b/wolfcrypt/src/port/intel/quickassist_mem.c @@ -57,6 +57,7 @@ #include #include #include +#include #ifndef O_CLOEXEC #define O_CLOEXEC 0 @@ -719,6 +720,16 @@ CpaStatus qaeMemInit(void) if (g_qaeMemFd < 0) { #ifndef QAT_V2 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 65801ea3006..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 */ @@ -219,6 +219,24 @@ This library contains implementation for the random number generator. #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) @@ -3835,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 | O_CLOEXEC); + os->fd = wc_open_cloexec("/dev/urandom", O_RDONLY); #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG("opened /dev/urandom."); #endif /* DEBUG_WOLFSSL */ @@ -3843,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 | O_CLOEXEC); + os->fd = wc_open_cloexec("/dev/random", O_RDONLY); #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG("opened /dev/random."); #endif /* DEBUG_WOLFSSL */ @@ -3861,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 | O_CLOEXEC); + os->fd = wc_open_cloexec("/dev/urandom", O_RDONLY); #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG("opened /dev/urandom."); #endif /* DEBUG_WOLFSSL */ @@ -3869,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 | O_CLOEXEC); + os->fd = wc_open_cloexec("/dev/random", O_RDONLY); #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG("opened /dev/random."); #endif /* DEBUG_WOLFSSL */ @@ -3946,6 +3964,7 @@ 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 @@ -3954,6 +3973,16 @@ int wc_hwrng_generate_block(byte *output, word32 sz) int fd; int ret = 0; 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)