From 03fbb8c9f28d687b9efabcda6e3bd8701d8cdf9f Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Wed, 19 Aug 2026 13:30:50 -0700 Subject: [PATCH 1/2] Fix outstanding Coverity findings --- src/port/posix/bsd_socket.c | 170 ++++++++++++++++------------ src/test/test_posix_errno.c | 146 ++++++++++++++++++++++++ src/test/test_ttl_expired.c | 42 +++++-- src/test/unit/unit.c | 1 + src/test/unit/unit_tests_dns_dhcp.c | 6 + src/wolfip.c | 5 +- 6 files changed, 284 insertions(+), 86 deletions(-) diff --git a/src/port/posix/bsd_socket.c b/src/port/posix/bsd_socket.c index 60f1a2ab..5d0bc76b 100644 --- a/src/port/posix/bsd_socket.c +++ b/src/port/posix/bsd_socket.c @@ -116,6 +116,9 @@ static int (*host_poll) (struct pollfd *fds, nfds_t nfds, int timeout); static int (*host_select) (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); static int (*host_fcntl) (int fd, int cmd, ...); +#define WOLFIP_HOST_CALL(call) \ + __atomic_load_n(&host_##call, __ATOMIC_ACQUIRE) + #define WOLFIP_MAX_PUBLIC_FDS 256 static int wolfip_ifindex_user_to_stack(int ifindex) @@ -173,7 +176,7 @@ static void wolfip_drain_pipe_locked(struct wolfip_fd_entry *entry) char c; if (!entry) return; - while (host_read(entry->public_fd, &c, 1) > 0) + while (WOLFIP_HOST_CALL(read)(entry->public_fd, &c, 1) > 0) wolfip_consume_token_locked(entry, c); } @@ -367,11 +370,11 @@ static int wolfip_fd_alloc(int internal_fd, int nonblock) if (pipe(pipefds) < 0) { return -errno; } - if (host_fcntl) { - host_fcntl(pipefds[0], F_SETFD, FD_CLOEXEC); - host_fcntl(pipefds[1], F_SETFD, FD_CLOEXEC); - host_fcntl(pipefds[0], F_SETFL, O_NONBLOCK); - host_fcntl(pipefds[1], F_SETFL, O_NONBLOCK); + if (WOLFIP_HOST_CALL(fcntl)) { + WOLFIP_HOST_CALL(fcntl)(pipefds[0], F_SETFD, FD_CLOEXEC); + WOLFIP_HOST_CALL(fcntl)(pipefds[1], F_SETFD, FD_CLOEXEC); + WOLFIP_HOST_CALL(fcntl)(pipefds[0], F_SETFL, O_NONBLOCK); + WOLFIP_HOST_CALL(fcntl)(pipefds[1], F_SETFL, O_NONBLOCK); } else { /* Resolve the real libc fcntl via dlsym to avoid recursing into our * interposed fcntl(), which would deadlock on wolfIP_mutex. */ @@ -381,17 +384,17 @@ static int wolfip_fd_alloc(int internal_fd, int nonblock) real_fcntl(pipefds[1], F_SETFD, FD_CLOEXEC) < 0 || real_fcntl(pipefds[0], F_SETFL, O_NONBLOCK) < 0 || real_fcntl(pipefds[1], F_SETFL, O_NONBLOCK) < 0) { - if (host_close) { - host_close(pipefds[0]); - host_close(pipefds[1]); + if (WOLFIP_HOST_CALL(close)) { + WOLFIP_HOST_CALL(close)(pipefds[0]); + WOLFIP_HOST_CALL(close)(pipefds[1]); } return -errno; } } if (pipefds[0] < 0 || pipefds[0] >= WOLFIP_MAX_PUBLIC_FDS || wolfip_fd_entries[pipefds[0]].in_use) { - if (host_close) { - host_close(pipefds[0]); - host_close(pipefds[1]); + if (WOLFIP_HOST_CALL(close)) { + WOLFIP_HOST_CALL(close)(pipefds[0]); + WOLFIP_HOST_CALL(close)(pipefds[1]); } return -EMFILE; } @@ -416,9 +419,9 @@ static void wolfip_fd_release(int public_fd) if (public_fd < 0 || public_fd >= WOLFIP_MAX_PUBLIC_FDS) return; if (wolfip_fd_entries[public_fd].in_use) { - if (host_close) { - host_close(wolfip_fd_entries[public_fd].public_fd); - host_close(wolfip_fd_entries[public_fd].pipe_write); + if (WOLFIP_HOST_CALL(close)) { + WOLFIP_HOST_CALL(close)(wolfip_fd_entries[public_fd].public_fd); + WOLFIP_HOST_CALL(close)(wolfip_fd_entries[public_fd].pipe_write); } wolfip_fd_detach_internal(wolfip_fd_entries[public_fd].internal_fd); } @@ -486,7 +489,7 @@ static int wolfip_wait_for_event_locked(struct wolfip_fd_entry *entry, short wai } pthread_mutex_unlock(&wolfIP_mutex); - poll_ret = host_poll(&pfd, 1, timeout_ms); + poll_ret = WOLFIP_HOST_CALL(poll)(&pfd, 1, timeout_ms); if (poll_ret < 0 && errno == EINTR) { pthread_mutex_lock(&wolfIP_mutex); return -EINTR; @@ -507,7 +510,7 @@ static int wolfip_wait_for_event_locked(struct wolfip_fd_entry *entry, short wai if (poll_ret == 0) { return -ETIMEDOUT; } - while (host_read(entry->public_fd, &c, 1) > 0) { + while (WOLFIP_HOST_CALL(read)(entry->public_fd, &c, 1) > 0) { wolfip_consume_token_locked(entry, c); if (c == want || c == 'h' || c == 'e') wake = 1; @@ -521,20 +524,27 @@ static int wolfip_wait_for_event_locked(struct wolfip_fd_entry *entry, short wai #define swap_socketcall(call, name) \ { \ const char *msg; \ - if (host_##call == NULL) { \ - *(void **)(&host_##call) = dlsym(RTLD_NEXT, name); \ - if ((msg = dlerror()) != NULL) \ + void *sym; \ + if (WOLFIP_HOST_CALL(call) == NULL) { \ + dlerror(); \ + sym = dlsym(RTLD_NEXT, name); \ + msg = dlerror(); \ + if (msg != NULL) \ fprintf (stderr, "%s: dlsym(%s): %s\n", "wolfIP", name, msg); \ + else \ + __atomic_store_n(&host_##call, (__typeof__(host_##call))sym, \ + __ATOMIC_RELEASE); \ } \ } #define conditional_steal_call(call, user_fd, ...) \ if(in_the_stack) { \ - return host_##call(user_fd, ## __VA_ARGS__); \ + return WOLFIP_HOST_CALL(call)(user_fd, ## __VA_ARGS__); \ } else { \ - int __wolfip_internal = wolfip_fd_internal_from_public(user_fd); \ + int __wolfip_internal; \ pthread_mutex_lock(&wolfIP_mutex); \ + __wolfip_internal = wolfip_fd_internal_from_public(user_fd); \ if (__wolfip_internal >= 0) { \ int __wolfip_retval = wolfIP_sock_##call(IPSTACK, __wolfip_internal, ## __VA_ARGS__); \ if (__wolfip_retval < 0) { \ @@ -547,16 +557,17 @@ static int wolfip_wait_for_event_locked(struct wolfip_fd_entry *entry, short wai return __wolfip_retval; \ } else { \ pthread_mutex_unlock(&wolfIP_mutex); \ - return host_##call(user_fd, ## __VA_ARGS__); \ + return WOLFIP_HOST_CALL(call)(user_fd, ## __VA_ARGS__); \ } \ } #define conditional_steal_blocking_call(call, user_fd, wait_events, ...) \ if(in_the_stack) { \ - return host_##call(user_fd, ## __VA_ARGS__); \ + return WOLFIP_HOST_CALL(call)(user_fd, ## __VA_ARGS__); \ } else { \ - int __wolfip_internal = wolfip_fd_internal_from_public(user_fd); \ + int __wolfip_internal; \ pthread_mutex_lock(&wolfIP_mutex); \ + __wolfip_internal = wolfip_fd_internal_from_public(user_fd); \ if (__wolfip_internal >= 0) { \ int __wolfip_retval; \ int __wolfip_nonblock = wolfip_fd_is_nonblock(user_fd); \ @@ -594,7 +605,7 @@ static int wolfip_wait_for_event_locked(struct wolfip_fd_entry *entry, short wai return __wolfip_retval; \ }else { \ pthread_mutex_unlock(&wolfIP_mutex); \ - return host_##call(user_fd, ## __VA_ARGS__); \ + return WOLFIP_HOST_CALL(call)(user_fd, ## __VA_ARGS__); \ } \ } @@ -1062,13 +1073,13 @@ int fcntl(int fd, int cmd, ...) { } va_end(ap); if (in_the_stack) { - return host_fcntl(fd, cmd, arg); + return WOLFIP_HOST_CALL(fcntl)(fd, cmd, arg); } else { pthread_mutex_lock(&wolfIP_mutex); ret = wolfIP_sock_fcntl(IPSTACK, fd, cmd, arg); if (ret == -WOLFIP_EINVAL) { pthread_mutex_unlock(&wolfIP_mutex); - return host_fcntl(fd, cmd, arg); + return WOLFIP_HOST_CALL(fcntl)(fd, cmd, arg); } pthread_mutex_unlock(&wolfIP_mutex); if (ret < 0) { @@ -1105,8 +1116,8 @@ void poller_callback(int fd, uint16_t event, void *arg) return; } } - if (host_write) - wr = host_write(entry->pipe_write, &c, 1); + if (WOLFIP_HOST_CALL(write)) + wr = WOLFIP_HOST_CALL(write)(entry->pipe_write, &c, 1); else wr = write(entry->pipe_write, &c, 1); if (wr > 0) { @@ -1115,10 +1126,10 @@ void poller_callback(int fd, uint16_t event, void *arg) } if (wr < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { /* Keep at least one token in the pipe: drop one stale byte then retry. */ - if (host_read(entry->public_fd, &discard, 1) > 0) + if (WOLFIP_HOST_CALL(read)(entry->public_fd, &discard, 1) > 0) wolfip_consume_token_locked(entry, discard); - if (host_write) - wr = host_write(entry->pipe_write, &c, 1); + if (WOLFIP_HOST_CALL(write)) + wr = WOLFIP_HOST_CALL(write)(entry->pipe_write, &c, 1); else wr = write(entry->pipe_write, &c, 1); if (wr > 0) @@ -1135,7 +1146,7 @@ int wolfIP_sock_poll(struct wolfIP *ipstack, struct pollfd *fds, nfds_t nfds, in nfds_t i; int ret; if (in_the_stack) { - return host_poll(fds, nfds, timeout); + return WOLFIP_HOST_CALL(poll)(fds, nfds, timeout); } for (i = 0; i < nfds; i++) { struct wolfip_fd_entry *entry = wolfip_entry_from_public(fds[i].fd); @@ -1149,7 +1160,7 @@ int wolfIP_sock_poll(struct wolfIP *ipstack, struct pollfd *fds, nfds_t nfds, in fds[i].fd = entry->public_fd; } pthread_mutex_unlock(&wolfIP_mutex); - ret = host_poll(fds, nfds, timeout); + ret = WOLFIP_HOST_CALL(poll)(fds, nfds, timeout); pthread_mutex_lock(&wolfIP_mutex); if (ret > 0) { for (i = 0; i < nfds; i++) { @@ -1159,7 +1170,7 @@ int wolfIP_sock_poll(struct wolfIP *ipstack, struct pollfd *fds, nfds_t nfds, in if (!entry) continue; if (fds[i].revents & POLLIN) { - while (host_read(entry->public_fd, &c, 1) > 0) { + while (WOLFIP_HOST_CALL(read)(entry->public_fd, &c, 1) > 0) { wolfip_consume_token_locked(entry, c); if (c == 'r') revents |= POLLIN; @@ -1187,7 +1198,8 @@ int wolfIP_sock_select(struct wolfIP *ipstack, int nfds, fd_set *readfds, fd_set int ret; int maxfd = nfds - 1; if (in_the_stack) { - return host_select(nfds, readfds, writefds, exceptfds, timeout); + return WOLFIP_HOST_CALL(select)(nfds, readfds, writefds, exceptfds, + timeout); } /* Arm callbacks for sockets present in fd_sets */ for (i = 0; i < WOLFIP_MAX_PUBLIC_FDS; i++) { @@ -1210,7 +1222,8 @@ int wolfIP_sock_select(struct wolfIP *ipstack, int nfds, fd_set *readfds, fd_set maxfd = entry->public_fd; } pthread_mutex_unlock(&wolfIP_mutex); - ret = host_select(maxfd + 1, readfds, writefds, exceptfds, timeout); + ret = WOLFIP_HOST_CALL(select)(maxfd + 1, readfds, writefds, exceptfds, + timeout); pthread_mutex_lock(&wolfIP_mutex); if (ret > 0) { int idx; @@ -1226,7 +1239,7 @@ int wolfIP_sock_select(struct wolfIP *ipstack, int nfds, fd_set *readfds, fd_set if ((readfds && FD_ISSET(entry->public_fd, readfds)) || (writefds && FD_ISSET(entry->public_fd, writefds)) || (exceptfds && FD_ISSET(entry->public_fd, exceptfds))) { - while (host_read(entry->public_fd, &c, 1) > 0) { + while (WOLFIP_HOST_CALL(read)(entry->public_fd, &c, 1) > 0) { wolfip_consume_token_locked(entry, c); if (c == 'r') saw_r = 1; @@ -1266,13 +1279,15 @@ int ioctl(int fd, unsigned long request, ...) argp = (void *)arg; if (in_the_stack) { - return host_ioctl ? host_ioctl(fd, request, arg) : -1; + return WOLFIP_HOST_CALL(ioctl) ? + WOLFIP_HOST_CALL(ioctl)(fd, request, arg) : -1; } if (request == SIOCGIFINDEX || request == SIOCGIFHWADDR || request == SIOCGIFADDR) { struct wolfip_fd_entry *entry = wolfip_entry_from_public(fd); if (!entry) { - return host_ioctl ? host_ioctl(fd, request, arg) : -1; + return WOLFIP_HOST_CALL(ioctl) ? + WOLFIP_HOST_CALL(ioctl)(fd, request, arg) : -1; } ifr = (struct ifreq *)argp; if (!ifr) { @@ -1351,13 +1366,15 @@ int ioctl(int fd, unsigned long request, ...) return 0; } - return host_ioctl ? host_ioctl(fd, request, arg) : -1; + return WOLFIP_HOST_CALL(ioctl) ? + WOLFIP_HOST_CALL(ioctl)(fd, request, arg) : -1; } int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { int ret; if (in_the_stack) { - return host_select(nfds, readfds, writefds, exceptfds, timeout); + return WOLFIP_HOST_CALL(select)(nfds, readfds, writefds, exceptfds, + timeout); } else { pthread_mutex_lock(&wolfIP_mutex); ret = wolfIP_sock_select(IPSTACK, nfds, readfds, writefds, exceptfds, timeout); @@ -1371,15 +1388,15 @@ int socket(int domain, int type, int protocol) { int internal_fd; int public_fd; if (in_the_stack) { - return host_socket(domain, type, protocol); + return WOLFIP_HOST_CALL(socket)(domain, type, protocol); } #if !WOLFIP_PACKET_SOCKETS if (domain == AF_PACKET) - return host_socket(domain, type, protocol); + return WOLFIP_HOST_CALL(socket)(domain, type, protocol); #endif #if !WOLFIP_RAWSOCKETS if (base_type == SOCK_RAW) - return host_socket(domain, type, protocol); + return WOLFIP_HOST_CALL(socket)(domain, type, protocol); #endif pthread_mutex_lock(&wolfIP_mutex); internal_fd = wolfIP_sock_socket(IPSTACK, domain, base_type, protocol); @@ -1405,10 +1422,11 @@ int listen(int sockfd, int backlog) { int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { if (in_the_stack) { - return host_bind(sockfd, addr, addrlen); + return WOLFIP_HOST_CALL(bind)(sockfd, addr, addrlen); } else { - int internal_fd = wolfip_fd_internal_from_public(sockfd); + int internal_fd; pthread_mutex_lock(&wolfIP_mutex); + internal_fd = wolfip_fd_internal_from_public(sockfd); if (internal_fd >= 0) { int ret; if (addr && addrlen >= sizeof(struct wolfIP_sockaddr_ll) && @@ -1432,7 +1450,7 @@ int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { return ret; } else { pthread_mutex_unlock(&wolfIP_mutex); - return host_bind(sockfd, addr, addrlen); + return WOLFIP_HOST_CALL(bind)(sockfd, addr, addrlen); } } } @@ -1457,7 +1475,7 @@ int close(int sockfd) { int ret; struct wolfip_fd_entry *entry; if (in_the_stack) { - return host_close(sockfd); + return WOLFIP_HOST_CALL(close)(sockfd); } pthread_mutex_lock(&wolfIP_mutex); entry = wolfip_entry_from_public(sockfd); @@ -1474,7 +1492,7 @@ int close(int sockfd) { return ret; } pthread_mutex_unlock(&wolfIP_mutex); - return host_close(sockfd); + return WOLFIP_HOST_CALL(close)(sockfd); } /* Blocking calls */ @@ -1486,8 +1504,8 @@ static int wolfip_accept_common(int sockfd, struct sockaddr *addr, socklen_t *ad if (in_the_stack) { if (flags) - return host_accept4(sockfd, addr, addrlen, flags); - return host_accept(sockfd, addr, addrlen); + return WOLFIP_HOST_CALL(accept4)(sockfd, addr, addrlen, flags); + return WOLFIP_HOST_CALL(accept)(sockfd, addr, addrlen); } pthread_mutex_lock(&wolfIP_mutex); entry = wolfip_entry_from_public(sockfd); @@ -1516,7 +1534,7 @@ static int wolfip_accept_common(int sockfd, struct sockaddr *addr, socklen_t *ad pfd.events = POLLIN; pfd.revents = 0; pthread_mutex_unlock(&wolfIP_mutex); - host_poll(&pfd, 1, -1); + WOLFIP_HOST_CALL(poll)(&pfd, 1, -1); pthread_mutex_lock(&wolfIP_mutex); /* While the mutex was dropped a concurrent close() may have * released this slot, and a subsequent socket()/accept() may @@ -1552,8 +1570,8 @@ static int wolfip_accept_common(int sockfd, struct sockaddr *addr, socklen_t *ad } pthread_mutex_unlock(&wolfIP_mutex); if (flags) - return host_accept4(sockfd, addr, addrlen, flags); - return host_accept(sockfd, addr, addrlen); + return WOLFIP_HOST_CALL(accept4)(sockfd, addr, addrlen, flags); + return WOLFIP_HOST_CALL(accept)(sockfd, addr, addrlen); } int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { @@ -1570,10 +1588,12 @@ int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *addrlen) { if (in_the_stack) { - return host_recvfrom(sockfd, buf, len, flags, addr, addrlen); + return WOLFIP_HOST_CALL(recvfrom)(sockfd, buf, len, flags, addr, + addrlen); } else { - int internal_fd = wolfip_fd_internal_from_public(sockfd); + int internal_fd; pthread_mutex_lock(&wolfIP_mutex); + internal_fd = wolfip_fd_internal_from_public(sockfd); if (internal_fd >= 0) { ssize_t ret; int nonblock = wolfip_fd_is_nonblock(sockfd); @@ -1616,7 +1636,8 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr * return -1; } else { pthread_mutex_unlock(&wolfIP_mutex); - return host_recvfrom(sockfd, buf, len, flags, addr, addrlen); + return WOLFIP_HOST_CALL(recvfrom)(sockfd, buf, len, flags, addr, + addrlen); } } } @@ -1640,7 +1661,7 @@ int getaddrinfo(const char *node, const char *service, const struct addrinfo *hi struct in_addr ipv4; char canon[256]; if (in_the_stack || !res) { - return host_getaddrinfo(node, service, hints, res); + return WOLFIP_HOST_CALL(getaddrinfo)(node, service, hints, res); } if (!node) { struct in_addr local_ip; @@ -1721,7 +1742,7 @@ void freeaddrinfo(struct addrinfo *res) { if (wolfip_take_gai_alloc(res)) { wolfip_free_addrinfo_list(res); } else { - host_freeaddrinfo(res); + WOLFIP_HOST_CALL(freeaddrinfo)(res); } } @@ -1737,13 +1758,15 @@ ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct const struct sockaddr *use_addr = addr; if (in_the_stack) { - return host_sendto(sockfd, buf, len, flags, addr, addrlen); + return WOLFIP_HOST_CALL(sendto)(sockfd, buf, len, flags, addr, + addrlen); } pthread_mutex_lock(&wolfIP_mutex); internal_fd = wolfip_fd_internal_from_public(sockfd); if (internal_fd < 0) { pthread_mutex_unlock(&wolfIP_mutex); - return host_sendto(sockfd, buf, len, flags, addr, addrlen); + return WOLFIP_HOST_CALL(sendto)(sockfd, buf, len, flags, addr, + addrlen); } nonblock = wolfip_fd_is_nonblock(sockfd); is_stream = IS_SOCKET_TCP(internal_fd) ? 1 : 0; @@ -1765,8 +1788,6 @@ ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct } if (ret == -EAGAIN) { if (nonblock) { - if (sent > 0) - break; errno = EAGAIN; pthread_mutex_unlock(&wolfIP_mutex); return -1; @@ -1815,13 +1836,13 @@ ssize_t send(int sockfd, const void *buf, size_t len, int flags) { size_t sent = 0; if (in_the_stack) { - return host_send(sockfd, buf, len, flags); + return WOLFIP_HOST_CALL(send)(sockfd, buf, len, flags); } pthread_mutex_lock(&wolfIP_mutex); internal_fd = wolfip_fd_internal_from_public(sockfd); if (internal_fd < 0) { pthread_mutex_unlock(&wolfIP_mutex); - return host_send(sockfd, buf, len, flags); + return WOLFIP_HOST_CALL(send)(sockfd, buf, len, flags); } nonblock = wolfip_fd_is_nonblock(sockfd); entry = wolfip_entry_from_public(sockfd); @@ -1835,8 +1856,6 @@ ssize_t send(int sockfd, const void *buf, size_t len, int flags) { } if (ret == -EAGAIN) { if (nonblock) { - if (sent > 0) - break; errno = EAGAIN; pthread_mutex_unlock(&wolfIP_mutex); return -1; @@ -1873,13 +1892,13 @@ ssize_t write(int sockfd, const void *buf, size_t len) { size_t sent = 0; if (in_the_stack) { - return host_write(sockfd, buf, len); + return WOLFIP_HOST_CALL(write)(sockfd, buf, len); } pthread_mutex_lock(&wolfIP_mutex); internal_fd = wolfip_fd_internal_from_public(sockfd); if (internal_fd < 0) { pthread_mutex_unlock(&wolfIP_mutex); - return host_write(sockfd, buf, len); + return WOLFIP_HOST_CALL(write)(sockfd, buf, len); } nonblock = wolfip_fd_is_nonblock(sockfd); entry = wolfip_entry_from_public(sockfd); @@ -1893,8 +1912,6 @@ ssize_t write(int sockfd, const void *buf, size_t len) { } if (ret == -EAGAIN) { if (nonblock) { - if (sent > 0) - break; errno = EAGAIN; pthread_mutex_unlock(&wolfIP_mutex); return -1; @@ -1925,7 +1942,7 @@ ssize_t write(int sockfd, const void *buf, size_t len) { int poll(struct pollfd *fds, nfds_t nfds, int timeout) { int ret; if (in_the_stack) { - return host_poll(fds, nfds, timeout); + return WOLFIP_HOST_CALL(poll)(fds, nfds, timeout); } else { pthread_mutex_lock(&wolfIP_mutex); ret = wolfIP_sock_poll(IPSTACK, fds, nfds, timeout); @@ -1991,6 +2008,7 @@ static int wolfip_validate_ipv4(const char *s) void __attribute__((constructor)) init_wolfip_posix() { struct in_addr host_stack_ip; + struct wolfIP *thread_ipstack; const char *host_stack_ip_str; const char *wolfip_ip_str; const char *wolfip_mask_str; @@ -2092,10 +2110,12 @@ void __attribute__((constructor)) init_wolfip_posix() { } wolfIP_ipconfig_set(IPSTACK, atoip4(wolfip_ip_str), atoip4(wolfip_mask_str), atoip4(host_stack_ip_str)); + thread_ipstack = IPSTACK; pthread_mutex_unlock(&wolfIP_mutex); fprintf(stderr, "IP: manually configured - %s\n", wolfip_ip_str); /* Avoid penalizing startup fairness across stacks: once init is done, * hand control to the poll thread immediately. */ - pthread_create(&wolfIP_thread, NULL, wolfIP_sock_posix_ip_loop, IPSTACK); + pthread_create(&wolfIP_thread, NULL, wolfIP_sock_posix_ip_loop, + thread_ipstack); in_the_stack = 0; } diff --git a/src/test/test_posix_errno.c b/src/test/test_posix_errno.c index 60d81ed6..13e2a615 100644 --- a/src/test/test_posix_errno.c +++ b/src/test/test_posix_errno.c @@ -28,6 +28,8 @@ #include #include +#include +#include #include #include #include @@ -38,6 +40,146 @@ * passthrough pointers populated, which is all this test needs. */ #include "../port/posix/bsd_socket.c" +enum { + HOST_CALL_READERS = 4, + HOST_CALL_RACE_ITERATIONS = 10000, + FD_RACE_ITERATIONS = 1000 +}; + +static int race_ready; +static int race_start; +static int host_call_observed; +static int fd_race_fd; +static int fd_race_failed; + +static void race_wait_for_start(void) +{ + __atomic_add_fetch(&race_ready, 1, __ATOMIC_ACQ_REL); + while (!__atomic_load_n(&race_start, __ATOMIC_ACQUIRE)) + sched_yield(); +} + +static void race_start_threads(int count) +{ + while (__atomic_load_n(&race_ready, __ATOMIC_ACQUIRE) != count) + sched_yield(); + __atomic_store_n(&race_start, 1, __ATOMIC_RELEASE); +} + +static void race_reset(void) +{ + __atomic_store_n(&race_ready, 0, __ATOMIC_RELEASE); + __atomic_store_n(&race_start, 0, __ATOMIC_RELEASE); +} + +static void *host_call_publisher(void *arg) +{ + int i; + + (void)arg; + race_wait_for_start(); + for (i = 0; i < HOST_CALL_RACE_ITERATIONS; i++) { + __atomic_store_n(&host_getpeername, NULL, __ATOMIC_RELEASE); + swap_socketcall(getpeername, "getpeername"); + } + return NULL; +} + +static void *host_call_reader(void *arg) +{ + int i; + + (void)arg; + race_wait_for_start(); + for (i = 0; i < HOST_CALL_RACE_ITERATIONS; i++) { + if (WOLFIP_HOST_CALL(getpeername) != NULL) + __atomic_add_fetch(&host_call_observed, 1, __ATOMIC_RELAXED); + } + return NULL; +} + +static void test_host_call_publication(void) +{ + pthread_t publisher; + pthread_t readers[HOST_CALL_READERS]; + int i; + + race_reset(); + __atomic_store_n(&host_call_observed, 0, __ATOMIC_RELEASE); + assert(pthread_create(&publisher, NULL, host_call_publisher, NULL) == 0); + for (i = 0; i < HOST_CALL_READERS; i++) + assert(pthread_create(&readers[i], NULL, host_call_reader, NULL) == 0); + race_start_threads(HOST_CALL_READERS + 1); + assert(pthread_join(publisher, NULL) == 0); + for (i = 0; i < HOST_CALL_READERS; i++) + assert(pthread_join(readers[i], NULL) == 0); + assert(WOLFIP_HOST_CALL(getpeername) != NULL); + assert(__atomic_load_n(&host_call_observed, __ATOMIC_ACQUIRE) > 0); +} + +static void *fd_race_caller(void *arg) +{ + struct sockaddr_in peer; + socklen_t peerlen; + int fd; + int i; + + (void)arg; + in_the_stack = 0; + race_wait_for_start(); + for (i = 0; i < FD_RACE_ITERATIONS; i++) { + fd = __atomic_load_n(&fd_race_fd, __ATOMIC_ACQUIRE); + peerlen = sizeof(peer); + getpeername(fd, (struct sockaddr *)&peer, &peerlen); + } + return NULL; +} + +static void *fd_race_reallocator(void *arg) +{ + int fd; + int i; + + (void)arg; + in_the_stack = 0; + race_wait_for_start(); + for (i = 0; i < FD_RACE_ITERATIONS; i++) { + fd = __atomic_load_n(&fd_race_fd, __ATOMIC_ACQUIRE); + if (close(fd) != 0) { + __atomic_store_n(&fd_race_failed, 1, __ATOMIC_RELEASE); + break; + } + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) { + __atomic_store_n(&fd_race_failed, 1, __ATOMIC_RELEASE); + break; + } + __atomic_store_n(&fd_race_fd, fd, __ATOMIC_RELEASE); + } + return NULL; +} + +static void test_fd_lookup_synchronization(void) +{ + pthread_t caller; + pthread_t reallocator; + int fd; + + race_reset(); + __atomic_store_n(&fd_race_failed, 0, __ATOMIC_RELEASE); + fd = socket(AF_INET, SOCK_STREAM, 0); + assert(fd >= 0); + __atomic_store_n(&fd_race_fd, fd, __ATOMIC_RELEASE); + assert(pthread_create(&caller, NULL, fd_race_caller, NULL) == 0); + assert(pthread_create(&reallocator, NULL, fd_race_reallocator, NULL) == 0); + race_start_threads(2); + assert(pthread_join(caller, NULL) == 0); + assert(pthread_join(reallocator, NULL) == 0); + assert(__atomic_load_n(&fd_race_failed, __ATOMIC_ACQUIRE) == 0); + fd = __atomic_load_n(&fd_race_fd, __ATOMIC_ACQUIRE); + assert(close(fd) == 0); +} + int main(void) { struct sockaddr_in peer; @@ -67,7 +209,11 @@ int main(void) /* ...and errno must be a real positive errno value, never the raw negative * wolfIP code (the F-4950 defect). */ assert(errno > 0); + assert(close(fd) == 0); printf("F-4950 regression test passed\n"); + test_host_call_publication(); + test_fd_lookup_synchronization(); + printf("POSIX concurrency regression tests passed\n"); return 0; } diff --git a/src/test/test_ttl_expired.c b/src/test/test_ttl_expired.c index 090cd5e5..5e39664a 100644 --- a/src/test/test_ttl_expired.c +++ b/src/test/test_ttl_expired.c @@ -23,6 +23,7 @@ #include #include +#include #include #ifndef ETH_P_IP #define ETH_P_IP ETHERTYPE_IP @@ -115,17 +116,40 @@ static uint16_t ones_csum(const void *buf, size_t len) uint32_t wolfIP_getrandom(void) { uint32_t ret; + size_t offset = 0; + ssize_t n; + int fd; + #ifdef __linux__ - { - ssize_t n; - do { - n = getrandom(&ret, sizeof(ret), 0); - } while (n < 0 && errno == EINTR); - if (n == (ssize_t)sizeof(ret)) - return ret; - } + do { + n = getrandom(&ret, sizeof(ret), 0); + } while (n < 0 && errno == EINTR); + if (n == (ssize_t)sizeof(ret)) + return ret; #endif - ret = (uint32_t)rand(); + + fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) { + perror("open /dev/urandom"); + abort(); + } + while (offset < sizeof(ret)) { + n = read(fd, (uint8_t *)&ret + offset, sizeof(ret) - offset); + if (n > 0) { + offset += (size_t)n; + } + else if (n < 0 && errno == EINTR) { + continue; + } + else { + break; + } + } + close(fd); + if (offset != sizeof(ret)) { + fprintf(stderr, "Failed to read /dev/urandom\n"); + abort(); + } return ret; } diff --git a/src/test/unit/unit.c b/src/test/unit/unit.c index 529eadf3..3f0abf84 100644 --- a/src/test/unit/unit.c +++ b/src/test/unit/unit.c @@ -423,6 +423,7 @@ Suite *wolf_suite(void) tcase_add_test(tc_utils, test_dhcp_timer_cb_send_failure_does_not_consume_retry_budget); tcase_add_test(tc_utils, test_dhcp_client_init_and_bound); tcase_add_test(tc_utils, test_dhcp_client_init_bind_failure_closes_socket); + tcase_add_test(tc_utils, test_dhcp_send_request_rejects_null_stack); tcase_add_test(tc_utils, test_dhcp_send_request_renewing_sets_ciaddr_and_rebind_deadline); tcase_add_test(tc_utils, test_dhcp_send_request_rebinding_broadcasts_to_lease_expiry); tcase_add_test(tc_utils, test_dhcp_send_request_send_failure_retries_next_tick); diff --git a/src/test/unit/unit_tests_dns_dhcp.c b/src/test/unit/unit_tests_dns_dhcp.c index c62a845a..68de7929 100644 --- a/src/test/unit/unit_tests_dns_dhcp.c +++ b/src/test/unit/unit_tests_dns_dhcp.c @@ -971,6 +971,12 @@ START_TEST(test_sock_connect_tcp_filter_drop) } END_TEST +START_TEST(test_dhcp_send_request_rejects_null_stack) +{ + ck_assert_int_eq(dhcp_send_request(NULL), -1); +} +END_TEST + START_TEST(test_dhcp_send_request_renewing_sets_ciaddr_and_rebind_deadline) { struct wolfIP s; diff --git a/src/wolfip.c b/src/wolfip.c index e5f898b5..5ca8a4b8 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -8653,7 +8653,7 @@ static int dhcp_send_request(struct wolfIP *s) struct dhcp_msg req; struct dhcp_option *opt = (struct dhcp_option *)(req.options); struct wolfIP_sockaddr_in sin; - struct ipconf *primary = wolfIP_primary_ipconf(s); + struct ipconf *primary; uint64_t retry_at = 0; int renewing = 0; int rebinding = 0; @@ -8663,7 +8663,8 @@ static int dhcp_send_request(struct wolfIP *s) if (!s) return -1; - retry_at = s ? (s->last_tick + 1U) : 0; + primary = wolfIP_primary_ipconf(s); + retry_at = s->last_tick + 1U; renewing = (s->dhcp_state == DHCP_RENEWING); rebinding = (s->dhcp_state == DHCP_REBINDING); From c003b7bf379c83ab2c96dc02716c01beecd1b5fe Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Wed, 19 Aug 2026 14:40:41 -0700 Subject: [PATCH 2/2] Serialize POSIX ioctl stack access --- src/port/posix/bsd_socket.c | 45 +++++++++++++++++++++++++------------ src/test/test_posix_errno.c | 11 +++++++++ 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/src/port/posix/bsd_socket.c b/src/port/posix/bsd_socket.c index 5d0bc76b..f57c0a36 100644 --- a/src/port/posix/bsd_socket.c +++ b/src/port/posix/bsd_socket.c @@ -1271,7 +1271,9 @@ int ioctl(int fd, unsigned long request, ...) uintptr_t arg; void *argp; struct ifreq *ifr; + struct wolfip_fd_entry *entry; int i; + int ret = -1; va_start(ap, request); arg = va_arg(ap, uintptr_t); @@ -1283,20 +1285,27 @@ int ioctl(int fd, unsigned long request, ...) WOLFIP_HOST_CALL(ioctl)(fd, request, arg) : -1; } - if (request == SIOCGIFINDEX || request == SIOCGIFHWADDR || request == SIOCGIFADDR) { - struct wolfip_fd_entry *entry = wolfip_entry_from_public(fd); + if (request == SIOCGIFINDEX || request == SIOCGIFHWADDR || + request == SIOCGIFADDR || request == SIOCGARP) { + pthread_mutex_lock(&wolfIP_mutex); + entry = wolfip_entry_from_public(fd); if (!entry) { + pthread_mutex_unlock(&wolfIP_mutex); return WOLFIP_HOST_CALL(ioctl) ? WOLFIP_HOST_CALL(ioctl)(fd, request, arg) : -1; } + } + + if (request == SIOCGIFINDEX || request == SIOCGIFHWADDR || + request == SIOCGIFADDR) { ifr = (struct ifreq *)argp; if (!ifr) { errno = EINVAL; - return -1; + goto wolfip_ioctl_exit; } if (ifr->ifr_name[0] == '\0') { errno = ENODEV; - return -1; + goto wolfip_ioctl_exit; } for (i = 0; i < WOLFIP_MAX_INTERFACES; i++) { struct wolfIP_ll_dev *ll = wolfIP_getdev_ex(IPSTACK, (unsigned int)i); @@ -1306,11 +1315,13 @@ int ioctl(int fd, unsigned long request, ...) continue; if (request == SIOCGIFINDEX) { ifr->ifr_ifindex = wolfip_ifindex_stack_to_user(i); - return 0; + ret = 0; + goto wolfip_ioctl_exit; } else if (request == SIOCGIFHWADDR) { ifr->ifr_hwaddr.sa_family = ARPHRD_ETHER; memcpy(ifr->ifr_hwaddr.sa_data, ll->mac, 6); - return 0; + ret = 0; + goto wolfip_ioctl_exit; } else if (request == SIOCGIFADDR) { struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr; ip4 ip = 0, mask = 0, gw = 0; @@ -1318,11 +1329,12 @@ int ioctl(int fd, unsigned long request, ...) wolfIP_ipconfig_get_ex(IPSTACK, (unsigned int)i, &ip, &mask, &gw); sin->sin_family = AF_INET; sin->sin_addr.s_addr = ee32(ip); - return 0; + ret = 0; + goto wolfip_ioctl_exit; } } errno = ENODEV; - return -1; + goto wolfip_ioctl_exit; } if (request == SIOCGARP) { @@ -1330,15 +1342,14 @@ int ioctl(int fd, unsigned long request, ...) struct sockaddr_in *pa; uint8_t mac[6]; unsigned int if_idx; - int ret; if (!ar) { errno = EINVAL; - return -1; + goto wolfip_ioctl_exit; } if (ar->arp_pa.sa_family != AF_INET) { errno = EAFNOSUPPORT; - return -1; + goto wolfip_ioctl_exit; } pa = (struct sockaddr_in *)&ar->arp_pa; if_idx = 0; @@ -1352,22 +1363,28 @@ int ioctl(int fd, unsigned long request, ...) } if (if_idx >= WOLFIP_MAX_INTERFACES) { errno = ENODEV; - return -1; + goto wolfip_ioctl_exit; } } ret = wolfIP_arp_lookup_ex(IPSTACK, if_idx, ee32(pa->sin_addr.s_addr), mac); if (ret < 0) { errno = ENXIO; - return -1; + ret = -1; + goto wolfip_ioctl_exit; } ar->arp_ha.sa_family = ARPHRD_ETHER; memcpy(ar->arp_ha.sa_data, mac, 6); ar->arp_flags = ATF_COM; - return 0; + ret = 0; + goto wolfip_ioctl_exit; } return WOLFIP_HOST_CALL(ioctl) ? WOLFIP_HOST_CALL(ioctl)(fd, request, arg) : -1; + +wolfip_ioctl_exit: + pthread_mutex_unlock(&wolfIP_mutex); + return ret; } int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { diff --git a/src/test/test_posix_errno.c b/src/test/test_posix_errno.c index 13e2a615..6010747a 100644 --- a/src/test/test_posix_errno.c +++ b/src/test/test_posix_errno.c @@ -48,6 +48,7 @@ enum { static int race_ready; static int race_start; +static int host_call_done; static int host_call_observed; static int fd_race_fd; static int fd_race_failed; @@ -82,6 +83,7 @@ static void *host_call_publisher(void *arg) __atomic_store_n(&host_getpeername, NULL, __ATOMIC_RELEASE); swap_socketcall(getpeername, "getpeername"); } + __atomic_store_n(&host_call_done, 1, __ATOMIC_RELEASE); return NULL; } @@ -95,6 +97,10 @@ static void *host_call_reader(void *arg) if (WOLFIP_HOST_CALL(getpeername) != NULL) __atomic_add_fetch(&host_call_observed, 1, __ATOMIC_RELAXED); } + while (!__atomic_load_n(&host_call_done, __ATOMIC_ACQUIRE)) + sched_yield(); + if (WOLFIP_HOST_CALL(getpeername) != NULL) + __atomic_add_fetch(&host_call_observed, 1, __ATOMIC_RELAXED); return NULL; } @@ -105,6 +111,7 @@ static void test_host_call_publication(void) int i; race_reset(); + __atomic_store_n(&host_call_done, 0, __ATOMIC_RELEASE); __atomic_store_n(&host_call_observed, 0, __ATOMIC_RELEASE); assert(pthread_create(&publisher, NULL, host_call_publisher, NULL) == 0); for (i = 0; i < HOST_CALL_READERS; i++) @@ -119,6 +126,7 @@ static void test_host_call_publication(void) static void *fd_race_caller(void *arg) { + struct ifreq ifr; struct sockaddr_in peer; socklen_t peerlen; int fd; @@ -131,6 +139,9 @@ static void *fd_race_caller(void *arg) fd = __atomic_load_n(&fd_race_fd, __ATOMIC_ACQUIRE); peerlen = sizeof(peer); getpeername(fd, (struct sockaddr *)&peer, &peerlen); + memset(&ifr, 0, sizeof(ifr)); + memcpy(ifr.ifr_name, "wtcp0", sizeof("wtcp0")); + ioctl(fd, SIOCGIFINDEX, &ifr); } return NULL; }