|
| 1 | +From 0fe67435935cc5724ff6eb9c4ca4120c58a15765 Mon Sep 17 00:00:00 2001 |
| 2 | +From: Ozan Tezcan < [email protected]> |
| 3 | +Date: Wed, 14 May 2025 11:02:30 +0300 |
| 4 | +Subject: [PATCH] Retry accept() even if accepted connection reports an error |
| 5 | + (CVE-2025-48367) |
| 6 | + |
| 7 | +Upstream Patch Link: https://github.com/redis/redis/commit/0fe67435935cc5724ff6eb9c4ca4120c58a15765.patch |
| 8 | + |
| 9 | +In case of accept4() returns an error, we should check errno value and |
| 10 | +decide if we should retry accept4() without waiting next event loop iteration. |
| 11 | +--- |
| 12 | + src/anet.c | 24 ++++++++++++++++++++++++ |
| 13 | + src/anet.h | 2 +- |
| 14 | + src/cluster.c | 2 ++ |
| 15 | + src/networking.c | 6 ++++++ |
| 16 | + 4 files changed, 33 insertions(+), 1 deletion(-) |
| 17 | + |
| 18 | +diff --git a/src/anet.c b/src/anet.c |
| 19 | +index 91f61718ef3..2e42fc572c3 100644 |
| 20 | +--- a/src/anet.c |
| 21 | ++++ b/src/anet.c |
| 22 | +@@ -594,3 +594,27 @@ int anetFormatFdAddr(int fd, char *buf, size_t buf_len, int fd_to_str_type) { |
| 23 | + anetFdToString(fd,ip,sizeof(ip),&port,fd_to_str_type); |
| 24 | + return anetFormatAddr(buf, buf_len, ip, port); |
| 25 | + } |
| 26 | ++ |
| 27 | ++/* This function must be called after accept4() fails. It returns 1 if 'err' |
| 28 | ++ * indicates accepted connection faced an error, and it's okay to continue |
| 29 | ++ * accepting next connection by calling accept4() again. Other errors either |
| 30 | ++ * indicate programming errors, e.g. calling accept() on a closed fd or indicate |
| 31 | ++ * a resource limit has been reached, e.g. -EMFILE, open fd limit has been |
| 32 | ++ * reached. In the latter case, caller might wait until resources are available. |
| 33 | ++ * See accept4() documentation for details. */ |
| 34 | ++int anetAcceptFailureNeedsRetry(int err) { |
| 35 | ++ if (err == ECONNABORTED) |
| 36 | ++ return 1; |
| 37 | ++ |
| 38 | ++#if defined(__linux__) |
| 39 | ++ /* For details, see 'Error Handling' section on |
| 40 | ++ * https://man7.org/linux/man-pages/man2/accept.2.html */ |
| 41 | ++ if (err == ENETDOWN || err == EPROTO || err == ENOPROTOOPT || |
| 42 | ++ err == EHOSTDOWN || err == ENONET || err == EHOSTUNREACH || |
| 43 | ++ err == EOPNOTSUPP || err == ENETUNREACH) |
| 44 | ++ { |
| 45 | ++ return 1; |
| 46 | ++ } |
| 47 | ++#endif |
| 48 | ++ return 0; |
| 49 | ++} |
| 50 | +diff --git a/src/anet.h b/src/anet.h |
| 51 | +index 2a685cc0169..adedaf3e1a8 100644 |
| 52 | +--- a/src/anet.h |
| 53 | ++++ b/src/anet.h |
| 54 | +@@ -72,5 +72,5 @@ int anetFdToString(int fd, char *ip, size_t ip_len, int *port, int fd_to_str_typ |
| 55 | + int anetKeepAlive(char *err, int fd, int interval); |
| 56 | + int anetFormatAddr(char *fmt, size_t fmt_len, char *ip, int port); |
| 57 | + int anetFormatFdAddr(int fd, char *buf, size_t buf_len, int fd_to_str_type); |
| 58 | +- |
| 59 | ++int anetAcceptFailureNeedsRetry(int err); |
| 60 | + #endif |
| 61 | +diff --git a/src/cluster.c b/src/cluster.c |
| 62 | +index 8807fe2c8c3..030897c6ab1 100644 |
| 63 | +--- a/src/cluster.c |
| 64 | ++++ b/src/cluster.c |
| 65 | +@@ -691,6 +691,8 @@ void clusterAcceptHandler(aeEventLoop *el, int fd, void *privdata, int mask) { |
| 66 | + while(max--) { |
| 67 | + cfd = anetTcpAccept(server.neterr, fd, cip, sizeof(cip), &cport); |
| 68 | + if (cfd == ANET_ERR) { |
| 69 | ++ if (anetAcceptFailureNeedsRetry(errno)) |
| 70 | ++ continue; |
| 71 | + if (errno != EWOULDBLOCK) |
| 72 | + serverLog(LL_VERBOSE, |
| 73 | + "Error accepting cluster node: %s", server.neterr); |
| 74 | +diff --git a/src/networking.c b/src/networking.c |
| 75 | +index 11891d3e970..2598a58baa8 100644 |
| 76 | +--- a/src/networking.c |
| 77 | ++++ b/src/networking.c |
| 78 | +@@ -1190,6 +1190,8 @@ void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask) { |
| 79 | + while(max--) { |
| 80 | + cfd = anetTcpAccept(server.neterr, fd, cip, sizeof(cip), &cport); |
| 81 | + if (cfd == ANET_ERR) { |
| 82 | ++ if (anetAcceptFailureNeedsRetry(errno)) |
| 83 | ++ continue; |
| 84 | + if (errno != EWOULDBLOCK) |
| 85 | + serverLog(LL_WARNING, |
| 86 | + "Accepting client connection: %s", server.neterr); |
| 87 | +@@ -1211,6 +1213,8 @@ void acceptTLSHandler(aeEventLoop *el, int fd, void *privdata, int mask) { |
| 88 | + while(max--) { |
| 89 | + cfd = anetTcpAccept(server.neterr, fd, cip, sizeof(cip), &cport); |
| 90 | + if (cfd == ANET_ERR) { |
| 91 | ++ if (anetAcceptFailureNeedsRetry(errno)) |
| 92 | ++ continue; |
| 93 | + if (errno != EWOULDBLOCK) |
| 94 | + serverLog(LL_WARNING, |
| 95 | + "Accepting client connection: %s", server.neterr); |
| 96 | +@@ -1231,6 +1235,8 @@ void acceptUnixHandler(aeEventLoop *el, int fd, void *privdata, int mask) { |
| 97 | + while(max--) { |
| 98 | + cfd = anetUnixAccept(server.neterr, fd); |
| 99 | + if (cfd == ANET_ERR) { |
| 100 | ++ if (anetAcceptFailureNeedsRetry(errno)) |
| 101 | ++ continue; |
| 102 | + if (errno != EWOULDBLOCK) |
| 103 | + serverLog(LL_WARNING, |
| 104 | + "Accepting client connection: %s", server.neterr); |
0 commit comments