!64 fix CVE-2023-4785
From: @sherlock2010 Reviewed-by: @sunsuwan Signed-off-by: @sunsuwan
This commit is contained in:
commit
9e05e86ff9
303
backport-iomgr-EventEngine-Improve-server-handling-o.patch
Normal file
303
backport-iomgr-EventEngine-Improve-server-handling-o.patch
Normal file
@ -0,0 +1,303 @@
|
||||
From f44cddbebae95935fa640aa19ed5d5786de2aafa Mon Sep 17 00:00:00 2001
|
||||
From: AJ Heller <hork@google.com>
|
||||
Date: Wed, 12 Jul 2023 15:12:56 -0700
|
||||
Subject: [PATCH] [backport][iomgr][EventEngine] Improve server handling of
|
||||
file descriptor exhaustion (#33670)
|
||||
|
||||
Backport of #33656
|
||||
---
|
||||
src/core/BUILD | 1 +
|
||||
.../event_engine/posix_engine/posix_engine.h | 1 +
|
||||
.../posix_engine/posix_engine_listener.cc | 30 +++++++++++
|
||||
.../posix_engine/posix_engine_listener.h | 3 ++
|
||||
src/core/lib/iomgr/tcp_server_posix.cc | 53 ++++++++++++++-----
|
||||
src/core/lib/iomgr/tcp_server_utils_posix.h | 12 +++++
|
||||
.../iomgr/tcp_server_utils_posix_common.cc | 21 ++++++++
|
||||
7 files changed, 107 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/src/core/BUILD b/src/core/BUILD
|
||||
index 3f8ef0d054..d4ae087542 100644
|
||||
--- a/src/core/BUILD
|
||||
+++ b/src/core/BUILD
|
||||
@@ -1908,6 +1908,7 @@ grpc_cc_library(
|
||||
"posix_event_engine_tcp_socket_utils",
|
||||
"socket_mutator",
|
||||
"status_helper",
|
||||
+ "time",
|
||||
"//:event_engine_base_hdrs",
|
||||
"//:gpr",
|
||||
],
|
||||
diff --git a/src/core/lib/event_engine/posix_engine/posix_engine.h b/src/core/lib/event_engine/posix_engine/posix_engine.h
|
||||
index afeda404a7..3a49d65699 100644
|
||||
--- a/src/core/lib/event_engine/posix_engine/posix_engine.h
|
||||
+++ b/src/core/lib/event_engine/posix_engine/posix_engine.h
|
||||
@@ -196,6 +196,7 @@ class PosixEventEngine final : public PosixEventEngineWithFdSupport,
|
||||
const DNSResolver::ResolverOptions& options) override;
|
||||
void Run(Closure* closure) override;
|
||||
void Run(absl::AnyInvocable<void()> closure) override;
|
||||
+ // Caution!! The timer implementation cannot create any fds. See #20418.
|
||||
TaskHandle RunAfter(Duration when, Closure* closure) override;
|
||||
TaskHandle RunAfter(Duration when,
|
||||
absl::AnyInvocable<void()> closure) override;
|
||||
diff --git a/src/core/lib/event_engine/posix_engine/posix_engine_listener.cc b/src/core/lib/event_engine/posix_engine/posix_engine_listener.cc
|
||||
index b395bff00d..39f3141afd 100644
|
||||
--- a/src/core/lib/event_engine/posix_engine/posix_engine_listener.cc
|
||||
+++ b/src/core/lib/event_engine/posix_engine/posix_engine_listener.cc
|
||||
@@ -23,7 +23,10 @@
|
||||
#include <sys/socket.h> // IWYU pragma: keep
|
||||
#include <unistd.h> // IWYU pragma: keep
|
||||
|
||||
+#include <atomic>
|
||||
#include <string>
|
||||
+#include <tuple>
|
||||
+#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/functional/any_invocable.h"
|
||||
@@ -41,6 +44,7 @@
|
||||
#include "src/core/lib/event_engine/posix_engine/tcp_socket_utils.h"
|
||||
#include "src/core/lib/event_engine/tcp_socket_utils.h"
|
||||
#include "src/core/lib/gprpp/status_helper.h"
|
||||
+#include "src/core/lib/gprpp/time.h"
|
||||
#include "src/core/lib/iomgr/socket_mutator.h"
|
||||
|
||||
namespace grpc_event_engine {
|
||||
@@ -136,6 +140,32 @@ void PosixEngineListenerImpl::AsyncConnectionAcceptor::NotifyOnAccept(
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
continue;
|
||||
+ case EMFILE:
|
||||
+ // When the process runs out of fds, accept4() returns EMFILE. When
|
||||
+ // this happens, the connection is left in the accept queue until
|
||||
+ // either a read event triggers the on_read callback, or time has
|
||||
+ // passed and the accept should be re-tried regardless. This callback
|
||||
+ // is not cancelled, so a spurious wakeup may occur even when there's
|
||||
+ // nothing to accept. This is not a performant code path, but if an fd
|
||||
+ // limit has been reached, the system is likely in an unhappy state
|
||||
+ // regardless.
|
||||
+ GRPC_LOG_EVERY_N_SEC(1, GPR_ERROR, "%s",
|
||||
+ "File descriptor limit reached. Retrying.");
|
||||
+ handle_->NotifyOnRead(notify_on_accept_);
|
||||
+ // Do not schedule another timer if one is already armed.
|
||||
+ if (retry_timer_armed_.exchange(true)) return;
|
||||
+ // Hold a ref while the retry timer is waiting, to prevent listener
|
||||
+ // destruction and the races that would ensue.
|
||||
+ Ref();
|
||||
+ std::ignore =
|
||||
+ engine_->RunAfter(grpc_core::Duration::Seconds(1), [this]() {
|
||||
+ retry_timer_armed_.store(false);
|
||||
+ if (!handle_->IsHandleShutdown()) {
|
||||
+ handle_->SetReadable();
|
||||
+ }
|
||||
+ Unref();
|
||||
+ });
|
||||
+ return;
|
||||
case EAGAIN:
|
||||
case ECONNABORTED:
|
||||
handle_->NotifyOnRead(notify_on_accept_);
|
||||
diff --git a/src/core/lib/event_engine/posix_engine/posix_engine_listener.h b/src/core/lib/event_engine/posix_engine/posix_engine_listener.h
|
||||
index 4bf793b197..ababb97846 100644
|
||||
--- a/src/core/lib/event_engine/posix_engine/posix_engine_listener.h
|
||||
+++ b/src/core/lib/event_engine/posix_engine/posix_engine_listener.h
|
||||
@@ -121,6 +121,9 @@ class PosixEngineListenerImpl
|
||||
ListenerSocketsContainer::ListenerSocket socket_;
|
||||
EventHandle* handle_;
|
||||
PosixEngineClosure* notify_on_accept_;
|
||||
+ // Tracks the status of a backup timer to retry accept4 calls after file
|
||||
+ // descriptor exhaustion.
|
||||
+ std::atomic<bool> retry_timer_armed_{false};
|
||||
};
|
||||
class ListenerAsyncAcceptors : public ListenerSocketsContainer {
|
||||
public:
|
||||
diff --git a/src/core/lib/iomgr/tcp_server_posix.cc b/src/core/lib/iomgr/tcp_server_posix.cc
|
||||
index dbe7bec338..c0cea6769e 100644
|
||||
--- a/src/core/lib/iomgr/tcp_server_posix.cc
|
||||
+++ b/src/core/lib/iomgr/tcp_server_posix.cc
|
||||
@@ -16,13 +16,17 @@
|
||||
//
|
||||
//
|
||||
|
||||
+#include <grpc/support/port_platform.h>
|
||||
+
|
||||
+#include <utility>
|
||||
+
|
||||
+#include <grpc/support/atm.h>
|
||||
+
|
||||
// FIXME: "posix" files shouldn't be depending on _GNU_SOURCE
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
-#include <grpc/support/port_platform.h>
|
||||
-
|
||||
#include "src/core/lib/iomgr/port.h"
|
||||
|
||||
#ifdef GRPC_POSIX_SOCKET_TCP_SERVER
|
||||
@@ -45,6 +49,7 @@
|
||||
|
||||
#include <grpc/byte_buffer.h>
|
||||
#include <grpc/event_engine/endpoint_config.h>
|
||||
+#include <grpc/event_engine/event_engine.h>
|
||||
#include <grpc/support/alloc.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpc/support/sync.h>
|
||||
@@ -75,6 +80,8 @@
|
||||
#include "src/core/lib/transport/error_utils.h"
|
||||
|
||||
static std::atomic<int64_t> num_dropped_connections{0};
|
||||
+static constexpr grpc_core::Duration kRetryAcceptWaitTime{
|
||||
+ grpc_core::Duration::Seconds(1)};
|
||||
|
||||
using ::grpc_event_engine::experimental::EndpointConfig;
|
||||
using ::grpc_event_engine::experimental::EventEngine;
|
||||
@@ -339,22 +346,38 @@ static void on_read(void* arg, grpc_error_handle err) {
|
||||
if (fd < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
- } else if (errno == EAGAIN || errno == ECONNABORTED ||
|
||||
- errno == EWOULDBLOCK) {
|
||||
+ }
|
||||
+ // When the process runs out of fds, accept4() returns EMFILE. When this
|
||||
+ // happens, the connection is left in the accept queue until either a
|
||||
+ // read event triggers the on_read callback, or time has passed and the
|
||||
+ // accept should be re-tried regardless. This callback is not cancelled,
|
||||
+ // so a spurious wakeup may occur even when there's nothing to accept.
|
||||
+ // This is not a performant code path, but if an fd limit has been
|
||||
+ // reached, the system is likely in an unhappy state regardless.
|
||||
+ if (errno == EMFILE) {
|
||||
+ GRPC_LOG_EVERY_N_SEC(1, GPR_ERROR, "%s",
|
||||
+ "File descriptor limit reached. Retrying.");
|
||||
+ grpc_fd_notify_on_read(sp->emfd, &sp->read_closure);
|
||||
+ if (gpr_atm_full_xchg(&sp->retry_timer_armed, true)) return;
|
||||
+ grpc_timer_init(&sp->retry_timer,
|
||||
+ grpc_core::Timestamp::Now() + kRetryAcceptWaitTime,
|
||||
+ &sp->retry_closure);
|
||||
+ return;
|
||||
+ }
|
||||
+ if (errno == EAGAIN || errno == ECONNABORTED || errno == EWOULDBLOCK) {
|
||||
grpc_fd_notify_on_read(sp->emfd, &sp->read_closure);
|
||||
return;
|
||||
+ }
|
||||
+ gpr_mu_lock(&sp->server->mu);
|
||||
+ if (!sp->server->shutdown_listeners) {
|
||||
+ gpr_log(GPR_ERROR, "Failed accept4: %s",
|
||||
+ grpc_core::StrError(errno).c_str());
|
||||
} else {
|
||||
- gpr_mu_lock(&sp->server->mu);
|
||||
- if (!sp->server->shutdown_listeners) {
|
||||
- gpr_log(GPR_ERROR, "Failed accept4: %s",
|
||||
- grpc_core::StrError(errno).c_str());
|
||||
- } else {
|
||||
- // if we have shutdown listeners, accept4 could fail, and we
|
||||
- // needn't notify users
|
||||
- }
|
||||
- gpr_mu_unlock(&sp->server->mu);
|
||||
- goto error;
|
||||
+ // if we have shutdown listeners, accept4 could fail, and we
|
||||
+ // needn't notify users
|
||||
}
|
||||
+ gpr_mu_unlock(&sp->server->mu);
|
||||
+ goto error;
|
||||
}
|
||||
|
||||
if (sp->server->memory_quota->IsMemoryPressureHigh()) {
|
||||
@@ -547,6 +570,7 @@ static grpc_error_handle clone_port(grpc_tcp_listener* listener,
|
||||
sp->port_index = listener->port_index;
|
||||
sp->fd_index = listener->fd_index + count - i;
|
||||
GPR_ASSERT(sp->emfd);
|
||||
+ grpc_tcp_server_listener_initialize_retry_timer(sp);
|
||||
while (listener->server->tail->next != nullptr) {
|
||||
listener->server->tail = listener->server->tail->next;
|
||||
}
|
||||
@@ -780,6 +804,7 @@ static void tcp_server_shutdown_listeners(grpc_tcp_server* s) {
|
||||
if (s->active_ports) {
|
||||
grpc_tcp_listener* sp;
|
||||
for (sp = s->head; sp; sp = sp->next) {
|
||||
+ grpc_timer_cancel(&sp->retry_timer);
|
||||
grpc_fd_shutdown(sp->emfd, GRPC_ERROR_CREATE("Server shutdown"));
|
||||
}
|
||||
}
|
||||
diff --git a/src/core/lib/iomgr/tcp_server_utils_posix.h b/src/core/lib/iomgr/tcp_server_utils_posix.h
|
||||
index 26cef0209f..de5a888cff 100644
|
||||
--- a/src/core/lib/iomgr/tcp_server_utils_posix.h
|
||||
+++ b/src/core/lib/iomgr/tcp_server_utils_posix.h
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "src/core/lib/iomgr/resolve_address.h"
|
||||
#include "src/core/lib/iomgr/socket_utils_posix.h"
|
||||
#include "src/core/lib/iomgr/tcp_server.h"
|
||||
+#include "src/core/lib/iomgr/timer.h"
|
||||
#include "src/core/lib/resource_quota/memory_quota.h"
|
||||
|
||||
// one listening port
|
||||
@@ -52,6 +53,11 @@ typedef struct grpc_tcp_listener {
|
||||
// identified while iterating through 'next'.
|
||||
struct grpc_tcp_listener* sibling;
|
||||
int is_sibling;
|
||||
+ // If an accept4() call fails, a timer is started to drain the accept queue in
|
||||
+ // case no further connection attempts reach the gRPC server.
|
||||
+ grpc_closure retry_closure;
|
||||
+ grpc_timer retry_timer;
|
||||
+ gpr_atm retry_timer_armed;
|
||||
} grpc_tcp_listener;
|
||||
|
||||
// the overall server
|
||||
@@ -139,4 +145,10 @@ grpc_error_handle grpc_tcp_server_prepare_socket(
|
||||
// Ruturn true if the platform supports ifaddrs
|
||||
bool grpc_tcp_server_have_ifaddrs(void);
|
||||
|
||||
+// Initialize (but don't start) the timer and callback to retry accept4() on a
|
||||
+// listening socket after file descriptors have been exhausted. This must be
|
||||
+// called when creating a new listener.
|
||||
+void grpc_tcp_server_listener_initialize_retry_timer(
|
||||
+ grpc_tcp_listener* listener);
|
||||
+
|
||||
#endif // GRPC_SRC_CORE_LIB_IOMGR_TCP_SERVER_UTILS_POSIX_H
|
||||
diff --git a/src/core/lib/iomgr/tcp_server_utils_posix_common.cc b/src/core/lib/iomgr/tcp_server_utils_posix_common.cc
|
||||
index 574fd02d0d..a32f542c4a 100644
|
||||
--- a/src/core/lib/iomgr/tcp_server_utils_posix_common.cc
|
||||
+++ b/src/core/lib/iomgr/tcp_server_utils_posix_common.cc
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#include <grpc/support/port_platform.h>
|
||||
|
||||
+#include <grpc/support/atm.h>
|
||||
+
|
||||
#include "src/core/lib/iomgr/port.h"
|
||||
|
||||
#ifdef GRPC_POSIX_SOCKET_TCP_SERVER_UTILS_COMMON
|
||||
@@ -81,6 +83,24 @@ static int get_max_accept_queue_size(void) {
|
||||
return s_max_accept_queue_size;
|
||||
}
|
||||
|
||||
+static void listener_retry_timer_cb(void* arg, grpc_error_handle err) {
|
||||
+ // Do nothing if cancelled.
|
||||
+ if (!err.ok()) return;
|
||||
+ grpc_tcp_listener* listener = static_cast<grpc_tcp_listener*>(arg);
|
||||
+ gpr_atm_no_barrier_store(&listener->retry_timer_armed, false);
|
||||
+ if (!grpc_fd_is_shutdown(listener->emfd)) {
|
||||
+ grpc_fd_set_readable(listener->emfd);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void grpc_tcp_server_listener_initialize_retry_timer(
|
||||
+ grpc_tcp_listener* listener) {
|
||||
+ gpr_atm_no_barrier_store(&listener->retry_timer_armed, false);
|
||||
+ grpc_timer_init_unset(&listener->retry_timer);
|
||||
+ GRPC_CLOSURE_INIT(&listener->retry_closure, listener_retry_timer_cb, listener,
|
||||
+ grpc_schedule_on_exec_ctx);
|
||||
+}
|
||||
+
|
||||
static grpc_error_handle add_socket_to_server(grpc_tcp_server* s, int fd,
|
||||
const grpc_resolved_address* addr,
|
||||
unsigned port_index,
|
||||
@@ -112,6 +132,7 @@ static grpc_error_handle add_socket_to_server(grpc_tcp_server* s, int fd,
|
||||
sp->server = s;
|
||||
sp->fd = fd;
|
||||
sp->emfd = grpc_fd_create(fd, name.c_str(), true);
|
||||
+ grpc_tcp_server_listener_initialize_retry_timer(sp);
|
||||
|
||||
// Check and set fd as prellocated
|
||||
if (grpc_tcp_server_pre_allocated_fd(s) == fd) {
|
||||
--
|
||||
2.33.0
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
Name: grpc
|
||||
Version: 1.54.2
|
||||
Release: 1
|
||||
Release: 2
|
||||
Summary: A modern, open source high performance RPC framework that can run in any environment
|
||||
License: ASL 2.0
|
||||
URL: https://www.grpc.io
|
||||
@ -12,6 +12,7 @@ Source0: https://github.com/grpc/grpc/archive/v%{version}/%{name}-%{versio
|
||||
|
||||
Patch0006: repair-pkgconfig-path.patch
|
||||
Patch0007: add-secure-compile-option-in-Makefile.patch
|
||||
Patch0008: backport-iomgr-EventEngine-Improve-server-handling-o.patch
|
||||
|
||||
BuildRequires: gcc-c++ pkgconfig protobuf-devel protobuf-compiler
|
||||
BuildRequires: openssl-devel c-ares-devel gtest-devel zlib-devel gperftools-devel
|
||||
@ -148,6 +149,12 @@ cd ../..
|
||||
%{python3_sitearch}/grpcio-%{version}-py*
|
||||
|
||||
%changelog
|
||||
* Thu Sep 14 2023 zhouyihang <zhouyihang3@h-partners.com> - 1.54.2-2
|
||||
- Type:CVE
|
||||
- ID:CVE-2023-4785
|
||||
- SUG:NA
|
||||
- DESC:fix CVE-2023-4785
|
||||
|
||||
* Thu Aug 03 2023 zhouyihang <zhouyihang3@h-partners.com> - 1.54.2-1
|
||||
- Type:requirement
|
||||
- ID:NA
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user