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
6 changes: 6 additions & 0 deletions .wolfssl_known_macro_extras
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,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
Expand All @@ -234,6 +235,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
Expand Down Expand Up @@ -315,6 +317,7 @@ ID_TRNG
IGNORE_KEY_EXTENSIONS
IGNORE_NETSCAPE_CERT_TYPE
INCLUDE_uxTaskGetStackHighWaterMark
IN_CLOEXEC
INTEGRITY
INTIMEVER
IOTSAFE_NO_GETDATA
Expand Down Expand Up @@ -468,6 +471,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
Expand All @@ -477,6 +481,7 @@ OS_WINDOWS
OTHERBOARD
OTHER_BOARD
PEER_INFO
PERF_FLAG_FD_CLOEXEC
PKA_ECC_SCALAR_MUL_IN_B_COEFF
PLATFORMIO
PLUTON_CRYPTO_ECC
Expand Down Expand Up @@ -519,6 +524,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
Expand Down
77 changes: 74 additions & 3 deletions src/crl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1659,13 +1659,19 @@ static int SwapLists(WOLFSSL_CRL* crl)
#include <sys/time.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

#ifdef __MACH__
#define XEVENT_MODE O_EVTONLY
#elif defined(__FreeBSD__)
#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
Comment on lines +1670 to +1672
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

Defining O_CLOEXEC as 0 means open(...|O_CLOEXEC) will silently omit close-on-exec when the macro is missing, and the EINVAL retry path won’t run. Prefer compile-time branching: if O_CLOEXEC is unavailable, open() without it and set FD_CLOEXEC via fcntl() (best-effort).

Suggested change
/* Fall back to no-op if O_CLOEXEC is unavailable on this platform. */
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#ifdef O_CLOEXEC
#define XOPEN_CLOEXEC(path, flags) open((path), (flags) | O_CLOEXEC)
#else
static int XOpenCloexec(const char* path, int flags)
{
int fd = open(path, flags);
if (fd >= 0) {
int fdFlags = fcntl(fd, F_GETFD);
if (fdFlags >= 0) {
(void)fcntl(fd, F_SETFD, fdFlags | FD_CLOEXEC);
}
}
return fd;
}
#define XOPEN_CLOEXEC(path, flags) XOpenCloexec((path), (flags))

Copilot uses AI. Check for mistakes.
#endif


/* we need a unique kqueue user filter fd for crl in case user is doing custom
* events too */
Expand Down Expand Up @@ -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);
Expand All @@ -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) {
Comment on lines +1740 to +1744
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

If O_CLOEXEC is unavailable at compile time and replaced with 0, this open(... | O_CLOEXEC) call will succeed without CLOEXEC and the EINVAL fallback won’t execute. Add a compile-time fallback that sets FD_CLOEXEC via fcntl() after a successful open() when O_CLOEXEC isn’t supported by headers/platform.

Copilot uses AI. Check for mistakes.
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);
Expand All @@ -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)
Expand Down Expand Up @@ -1801,6 +1834,13 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg)
#include <sys/inotify.h>
#include <sys/eventfd.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

/* Fall back to no-op if EFD_CLOEXEC is unavailable. */
#ifndef EFD_CLOEXEC
#define EFD_CLOEXEC 0
Comment on lines +1840 to +1842
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

If EFD_CLOEXEC is missing and replaced with 0, eventfd(0, EFD_CLOEXEC) will succeed without CLOEXEC and the EINVAL fallback will never run. Use compile-time branching: when EFD_CLOEXEC is unavailable, call eventfd(0, 0) and set FD_CLOEXEC via fcntl() (best-effort).

Suggested change
/* Fall back to no-op if EFD_CLOEXEC is unavailable. */
#ifndef EFD_CLOEXEC
#define EFD_CLOEXEC 0
#ifndef EFD_CLOEXEC
/*
* Older platforms may not provide EFD_CLOEXEC. In that case, create the
* eventfd without it and set FD_CLOEXEC with fcntl() as a best-effort
* fallback.
*/
static int wolfssl_eventfd_cloexec_fallback(unsigned int initval, int flags)
{
int fd;
int fdFlags;
(void)flags;
fd = eventfd(initval, 0);
if (fd >= 0) {
fdFlags = fcntl(fd, F_GETFD);
if (fdFlags >= 0) {
(void)fcntl(fd, F_SETFD, fdFlags | FD_CLOEXEC);
}
}
return fd;
}
#define EFD_CLOEXEC 0
#define eventfd(initval, flags) \
wolfssl_eventfd_cloexec_fallback((initval), (flags))

Copilot uses AI. Check for mistakes.
#endif


#ifndef max
Expand Down Expand Up @@ -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) {
Comment on lines +1879 to +1883
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

This runtime EINVAL fallback won’t fire when EFD_CLOEXEC is unavailable at compile time (because the first call becomes eventfd(0, 0) and succeeds). Consider a compile-time fallback path that sets FD_CLOEXEC via fcntl() after eventfd() whenever EFD_CLOEXEC isn’t defined/supported.

Copilot uses AI. Check for mistakes.
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);
Expand Down
17 changes: 16 additions & 1 deletion src/ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -19568,6 +19568,11 @@ int wolfSSL_RAND_write_file(const char* fname)
defined(HAVE_SYS_UN_H)
#define WOLFSSL_EGD_NBLOCK 0x01
#include <sys/un.h>
#include <errno.h>
#include <fcntl.h>
#ifndef SOCK_CLOEXEC
#define SOCK_CLOEXEC 0
#endif
Comment on lines +19573 to +19575
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

Defining SOCK_CLOEXEC to 0 makes the close-on-exec logic ineffective on systems where the macro isn’t available: the socket() call won’t request CLOEXEC and the EINVAL fallback won’t run. Prefer compile-time branching (use SOCK_CLOEXEC when available; otherwise set FD_CLOEXEC with fcntl() after socket creation).

Copilot uses AI. Check for mistakes.
#endif

/* This collects entropy from the path nm and seeds the global PRNG with it.
Expand Down Expand Up @@ -19601,7 +19606,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);
}
Comment on lines +19613 to +19617
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

wolfSSL_RAND_egd(): this path uses fcntl(), F_GETFD/F_SETFD and FD_CLOEXEC, but src/ssl.c doesn’t include <fcntl.h>. Add the include under the same feature guards so the code compiles cleanly (and so FD_CLOEXEC/F_GETFD are defined).

Copilot uses AI. Check for mistakes.
}
#endif
if (fd < 0) {
WOLFSSL_MSG("Error creating socket");
WC_FREE_VAR_EX(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
Expand Down
77 changes: 73 additions & 4 deletions src/wolfio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 <wolfssl/wolfcrypt/libwolfssl_sources.h>

#ifndef WOLFCRYPT_ONLY
Expand All @@ -42,6 +51,12 @@
#include <wolfssl/wolfio.h>
#include <wolfssl/wolfcrypt/logging.h>

/* 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
Comment on lines +54 to +58
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

Defining SOCK_CLOEXEC to 0 means socket(...|SOCK_CLOEXEC) won’t request close-on-exec on platforms where the macro is missing, and the EINVAL fallback will never run. Instead of a 0 define, use compile-time branching: if SOCK_CLOEXEC is unavailable, call socket() without it and then set FD_CLOEXEC via fcntl() (best-effort).

Suggested change
/* 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
/* SOCK_CLOEXEC sets close-on-exec atomically when the socket is created.
* Do not define it to 0 when unavailable; socket creation code must branch
* at compile time and use a non-SOCK_CLOEXEC path on platforms that do not
* provide the flag. */

Copilot uses AI. Check for mistakes.

#ifdef NUCLEUS_PLUS_2_3
/* Holds last Nucleus networking error number */
int Nucleus_Net_Errno;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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(USE_WINDOWS_API) && 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(USE_WINDOWS_API) && 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
Expand Down Expand Up @@ -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 */

Expand Down
20 changes: 19 additions & 1 deletion wolfcrypt/benchmark/benchmark.c
Original file line number Diff line number Diff line change
Expand Up @@ -1574,16 +1574,34 @@ static const char* bench_result_words3[][5] = {
#include <linux/perf_event.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

#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));
Expand Down
Loading
Loading