@@ -142,6 +142,7 @@ struct wolfip_fd_entry {
142142 uint8_t in_use ;
143143 uint8_t pending_tokens ; /* Bitset of queued event bytes in the pipe */
144144 uint16_t events ; /* Events armed for current poll/select */
145+ uint32_t generation ; /* Bumped on every alloc; detects slot reuse */
145146};
146147
147148#define WOLFIP_TOKEN_R (1u << 0)
@@ -177,6 +178,7 @@ static void wolfip_drain_pipe_locked(struct wolfip_fd_entry *entry)
177178}
178179
179180static struct wolfip_fd_entry wolfip_fd_entries [WOLFIP_MAX_PUBLIC_FDS ];
181+ static uint32_t wolfip_fd_generation ; /* Monotonic; bumped under wolfIP_mutex on each alloc */
180182static int tcp_entry_for_slot [MAX_TCPSOCKETS ];
181183static int udp_entry_for_slot [MAX_UDPSOCKETS ];
182184static int icmp_entry_for_slot [MAX_ICMPSOCKETS ];
@@ -196,6 +198,7 @@ enum wolfip_dns_wait_type {
196198struct wolfip_dns_wait_ctx {
197199 pthread_mutex_t mutex ;
198200 pthread_cond_t cond ;
201+ int busy ;
199202 int pending ;
200203 enum wolfip_dns_wait_type type ;
201204 int status ;
@@ -207,6 +210,7 @@ static struct wolfip_dns_wait_ctx dns_wait_ctx = {
207210 PTHREAD_MUTEX_INITIALIZER ,
208211 PTHREAD_COND_INITIALIZER ,
209212 0 ,
213+ 0 ,
210214 DNS_WAIT_NONE ,
211215 0 ,
212216 0 ,
@@ -393,6 +397,7 @@ static int wolfip_fd_alloc(int internal_fd, int nonblock)
393397 }
394398 idx = pipefds [0 ];
395399 memset (& wolfip_fd_entries [idx ], 0 , sizeof (wolfip_fd_entries [idx ]));
400+ wolfip_fd_entries [idx ].generation = ++ wolfip_fd_generation ;
396401 wolfip_fd_entries [idx ].internal_fd = internal_fd ;
397402 wolfip_fd_entries [idx ].public_fd = pipefds [0 ];
398403 wolfip_fd_entries [idx ].pipe_write = pipefds [1 ];
@@ -449,9 +454,15 @@ static int wolfip_wait_for_event_locked(struct wolfip_fd_entry *entry, short wai
449454{
450455 struct pollfd pfd ;
451456 char want ;
457+ uint32_t start_gen ;
458+ int start_fd ;
452459
453460 if (!entry )
454461 return - EINVAL ;
462+ /* Snapshot the slot identity so we can detect a concurrent close()/reuse
463+ * across the mutex-drop window below. */
464+ start_gen = entry -> generation ;
465+ start_fd = entry -> internal_fd ;
455466 want = (wait_events & POLLOUT ) ? 'w' : 'r' ;
456467 entry -> events = (uint16_t )wait_events ;
457468 wolfIP_register_callback (IPSTACK , entry -> internal_fd , poller_callback , IPSTACK );
@@ -481,6 +492,15 @@ static int wolfip_wait_for_event_locked(struct wolfip_fd_entry *entry, short wai
481492 return - EINTR ;
482493 }
483494 pthread_mutex_lock (& wolfIP_mutex );
495+ /* While the mutex was dropped a concurrent close() may have released
496+ * this slot, and a subsequent socket()/accept() may have reused the
497+ * same public fd for an unrelated connection. The caller still holds
498+ * the stale internal_fd it captured before blocking; signal EBADF so
499+ * it does not read/write the reused slot's data. */
500+ if (!entry -> in_use || entry -> generation != start_gen ||
501+ entry -> internal_fd != start_fd ) {
502+ return - EBADF ;
503+ }
484504 if (poll_ret < 0 ) {
485505 return - errno ;
486506 }
@@ -518,7 +538,7 @@ static int wolfip_wait_for_event_locked(struct wolfip_fd_entry *entry, short wai
518538 if (__wolfip_internal >= 0) { \
519539 int __wolfip_retval = wolfIP_sock_##call(IPSTACK, __wolfip_internal, ## __VA_ARGS__); \
520540 if (__wolfip_retval < 0) { \
521- errno = __wolfip_retval; \
541+ errno = - __wolfip_retval; \
522542 pthread_mutex_unlock(&wolfIP_mutex); \
523543 return -1; \
524544 } \
@@ -565,7 +585,7 @@ static int wolfip_wait_for_event_locked(struct wolfip_fd_entry *entry, short wai
565585 } \
566586 } while (__wolfip_retval == -EAGAIN); \
567587 if (__wolfip_retval < 0) { \
568- errno = __wolfip_retval; \
588+ errno = - __wolfip_retval; \
569589 pthread_mutex_unlock(&wolfIP_mutex); \
570590 return -1; \
571591 } \
@@ -715,10 +735,11 @@ static int wolfip_dns_error_to_eai(int err)
715735static int wolfip_dns_begin_wait (enum wolfip_dns_wait_type type )
716736{
717737 pthread_mutex_lock (& dns_wait_ctx .mutex );
718- if (dns_wait_ctx .pending ) {
738+ if (dns_wait_ctx .busy ) {
719739 pthread_mutex_unlock (& dns_wait_ctx .mutex );
720740 return EAI_AGAIN ;
721741 }
742+ dns_wait_ctx .busy = 1 ;
722743 dns_wait_ctx .pending = 1 ;
723744 dns_wait_ctx .type = type ;
724745 dns_wait_ctx .status = EAI_FAIL ;
@@ -731,6 +752,7 @@ static void wolfip_dns_abort_wait(int status)
731752{
732753 pthread_mutex_lock (& dns_wait_ctx .mutex );
733754 dns_wait_ctx .pending = 0 ;
755+ dns_wait_ctx .busy = 0 ;
734756 dns_wait_ctx .type = DNS_WAIT_NONE ;
735757 dns_wait_ctx .status = status ;
736758 pthread_cond_signal (& dns_wait_ctx .cond );
@@ -748,13 +770,16 @@ static int wolfip_dns_wait(enum wolfip_dns_wait_type type, uint32_t *ip_out, cha
748770 int err = pthread_cond_timedwait (& dns_wait_ctx .cond , & dns_wait_ctx .mutex , & ts );
749771 if (err == ETIMEDOUT ) {
750772 dns_wait_ctx .pending = 0 ;
773+ dns_wait_ctx .busy = 0 ;
751774 dns_wait_ctx .type = DNS_WAIT_NONE ;
752775 pthread_mutex_unlock (& dns_wait_ctx .mutex );
753776 return EAI_AGAIN ;
754777 }
755778 }
756779 if (dns_wait_ctx .type != type ) {
757780 int status = dns_wait_ctx .status ? dns_wait_ctx .status : EAI_FAIL ;
781+ dns_wait_ctx .type = DNS_WAIT_NONE ;
782+ dns_wait_ctx .busy = 0 ;
758783 pthread_mutex_unlock (& dns_wait_ctx .mutex );
759784 return status ;
760785 }
@@ -766,6 +791,7 @@ static int wolfip_dns_wait(enum wolfip_dns_wait_type type, uint32_t *ip_out, cha
766791 wolfip_strlcpy (name_out , dns_wait_ctx .name , name_len );
767792 }
768793 dns_wait_ctx .type = DNS_WAIT_NONE ;
794+ dns_wait_ctx .busy = 0 ;
769795 pthread_mutex_unlock (& dns_wait_ctx .mutex );
770796 return status ;
771797}
@@ -1476,6 +1502,12 @@ static int wolfip_accept_common(int sockfd, struct sockaddr *addr, socklen_t *ad
14761502 if (entry ) {
14771503 int internal_ret ;
14781504 int public_fd ;
1505+ uint32_t start_gen ;
1506+ int start_fd ;
1507+ /* Snapshot the listener slot's identity so we can detect a concurrent
1508+ * close()/reuse across the mutex-drop window in the poll loop below. */
1509+ start_gen = entry -> generation ;
1510+ start_fd = entry -> internal_fd ;
14791511 if (!want_nonblock )
14801512 want_nonblock = wolfip_fd_is_nonblock (sockfd );
14811513 do {
@@ -1494,8 +1526,15 @@ static int wolfip_accept_common(int sockfd, struct sockaddr *addr, socklen_t *ad
14941526 pthread_mutex_unlock (& wolfIP_mutex );
14951527 host_poll (& pfd , 1 , -1 );
14961528 pthread_mutex_lock (& wolfIP_mutex );
1529+ /* While the mutex was dropped a concurrent close() may have
1530+ * released this slot, and a subsequent socket()/accept() may
1531+ * have reused the same public fd for an unrelated connection.
1532+ * The bare in_use check below cannot tell the slot apart from
1533+ * the original listener, so verify the snapshotted identity to
1534+ * avoid accepting on the wrong internal socket. */
14971535 entry = wolfip_entry_from_public (sockfd );
1498- if (!entry ) {
1536+ if (!entry || entry -> generation != start_gen ||
1537+ entry -> internal_fd != start_fd ) {
14991538 errno = EBADF ;
15001539 pthread_mutex_unlock (& wolfIP_mutex );
15011540 return -1 ;
@@ -1505,7 +1544,7 @@ static int wolfip_accept_common(int sockfd, struct sockaddr *addr, socklen_t *ad
15051544 }
15061545 } while (internal_ret == - EAGAIN );
15071546 if (internal_ret < 0 ) {
1508- errno = internal_ret ;
1547+ errno = - internal_ret ;
15091548 pthread_mutex_unlock (& wolfIP_mutex );
15101549 return -1 ;
15111550 }
0 commit comments