Skip to content

Commit 81d1b99

Browse files
committed
retry accept on transient errors (CVE-2025-48367) (#2315)
Signed-off-by: Ran Shidlansik <[email protected]>
1 parent a7ca229 commit 81d1b99

File tree

6 files changed

+36
-0
lines changed

6 files changed

+36
-0
lines changed

src/anet.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,37 @@ int anetUnixServer(char *err, char *path, mode_t perm, int backlog, char *group)
639639
return s;
640640
}
641641

642+
/* For some error cases indicates transient errors and accept can be retried
643+
* in order to serve other pending connections. This function should be called with the last errno,
644+
* right after anetTcpaccept or anetUnixAccept returned an error in order to retry them. */
645+
int anetRetryAcceptOnError(int err) {
646+
/* This is a transient error which can happen, for example, when
647+
* a client initiates a TCP handshake (SYN),
648+
* the server receives and queues it in the pending connections queue (the SYN queue),
649+
* but before accept() is called, the connection is aborted.
650+
* in such cases we can continue accepting other connections. ß*/
651+
if (err == ECONNABORTED)
652+
return 1;
653+
654+
#if defined(__linux__)
655+
/* https://www.man7.org/linux/man-pages/man2/accept4.2 suggests that:
656+
* Linux accept() (and accept4()) passes already-pending network
657+
errors on the new socket as an error code from accept(). This
658+
behavior differs from other BSD socket implementations. For
659+
reliable operation the application should detect the network
660+
errors defined for the protocol after accept() and treat them like
661+
EAGAIN by retrying. In the case of TCP/IP, these are ENETDOWN,
662+
EPROTO, ENOPROTOOPT, EHOSTDOWN, ENONET, EHOSTUNREACH, EOPNOTSUPP,
663+
and ENETUNREACH. */
664+
if (err == ENETDOWN || err == EPROTO || err == ENOPROTOOPT ||
665+
err == EHOSTDOWN || err == ENONET || err == EHOSTUNREACH ||
666+
err == EOPNOTSUPP || err == ENETUNREACH) {
667+
return 1;
668+
}
669+
#endif
670+
return 0;
671+
}
672+
642673
/* Accept a connection and also make sure the socket is non-blocking, and CLOEXEC.
643674
* returns the new socket FD, or -1 on error. */
644675
static int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *len) {

src/anet.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,5 +74,6 @@ int anetPipe(int fds[2], int read_flags, int write_flags);
7474
int anetSetSockMarkId(char *err, int fd, uint32_t id);
7575
int anetGetError(int fd);
7676
int anetIsFifo(char *filepath);
77+
int anetRetryAcceptOnError(int err);
7778

7879
#endif

src/cluster_legacy.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1504,6 +1504,7 @@ void clusterAcceptHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
15041504
while (max--) {
15051505
cfd = anetTcpAccept(server.neterr, fd, cip, sizeof(cip), &cport);
15061506
if (cfd == ANET_ERR) {
1507+
if (anetRetryAcceptOnError(errno)) continue;
15071508
if (errno != EWOULDBLOCK) serverLog(LL_VERBOSE, "Error accepting cluster node: %s", server.neterr);
15081509
return;
15091510
}

src/socket.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ static void connSocketAcceptHandler(aeEventLoop *el, int fd, void *privdata, int
322322
while (max--) {
323323
cfd = anetTcpAccept(server.neterr, fd, cip, sizeof(cip), &cport);
324324
if (cfd == ANET_ERR) {
325+
if (anetRetryAcceptOnError(errno)) continue;
325326
if (errno != EWOULDBLOCK) serverLog(LL_WARNING, "Accepting client connection: %s", server.neterr);
326327
return;
327328
}

src/tls.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,7 @@ static void tlsAcceptHandler(aeEventLoop *el, int fd, void *privdata, int mask)
788788
while (max--) {
789789
cfd = anetTcpAccept(server.neterr, fd, cip, sizeof(cip), &cport);
790790
if (cfd == ANET_ERR) {
791+
if (anetRetryAcceptOnError(errno)) continue;
791792
if (errno != EWOULDBLOCK) serverLog(LL_WARNING, "Accepting client connection: %s", server.neterr);
792793
return;
793794
}

src/unix.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ static void connUnixAcceptHandler(aeEventLoop *el, int fd, void *privdata, int m
107107
while (max--) {
108108
cfd = anetUnixAccept(server.neterr, fd);
109109
if (cfd == ANET_ERR) {
110+
if (anetRetryAcceptOnError(errno)) continue;
110111
if (errno != EWOULDBLOCK) serverLog(LL_WARNING, "Accepting client connection: %s", server.neterr);
111112
return;
112113
}

0 commit comments

Comments
 (0)