From 91ad1213b419a0e84905772005076535c23c5648 Mon Sep 17 00:00:00 2001 From: Chunmei Xu Date: Tue, 7 May 2024 14:05:33 +0800 Subject: [PATCH] fix CVE-2023-4785 Signed-off-by: Chunmei Xu --- ...ventEngine-Improve-server-handling-o.patch | 232 ++++++++++++++++++ grpc.spec | 29 ++- 2 files changed, 249 insertions(+), 12 deletions(-) create mode 100644 1000-backport-iomgr-EventEngine-Improve-server-handling-o.patch diff --git a/1000-backport-iomgr-EventEngine-Improve-server-handling-o.patch b/1000-backport-iomgr-EventEngine-Improve-server-handling-o.patch new file mode 100644 index 0000000..fce9f19 --- /dev/null +++ b/1000-backport-iomgr-EventEngine-Improve-server-handling-o.patch @@ -0,0 +1,232 @@ +From cf1fdec53afb3bebb50b8239f1b912ff9586a468 Mon Sep 17 00:00:00 2001 +From: Chunmei Xu +Date: Mon, 6 May 2024 20:01:02 +0800 +Subject: [PATCH] [backport][iomgr][EventEngine] Improve server handling of + file descriptor exhaustion (#33672) + +Backport of #33656 + +format from https://github.com/grpc/grpc/commit/1d85b01fc1930b8ce0d991a8ab55f6863efa2211 +fix CVE-2023-4785 + +Signed-off-by: Chunmei Xu +--- + src/core/lib/gprpp/time.h | 12 ++++ + src/core/lib/iomgr/tcp_server_posix.cc | 56 ++++++++++++++----- + src/core/lib/iomgr/tcp_server_utils_posix.h | 14 ++++- + .../iomgr/tcp_server_utils_posix_common.cc | 21 +++++++ + 4 files changed, 88 insertions(+), 15 deletions(-) + +diff --git a/src/core/lib/gprpp/time.h b/src/core/lib/gprpp/time.h +index 2c5cb42060..02097628b8 100644 +--- a/src/core/lib/gprpp/time.h ++++ b/src/core/lib/gprpp/time.h +@@ -30,6 +30,18 @@ + #include "src/core/lib/gpr/time_precise.h" + #include "src/core/lib/gpr/useful.h" + ++#define GRPC_LOG_EVERY_N_SEC(n, severity, format, ...) \ ++ do { \ ++ static std::atomic prev{0}; \ ++ uint64_t now = grpc_core::Timestamp::FromTimespecRoundDown( \ ++ gpr_now(GPR_CLOCK_MONOTONIC)) \ ++ .milliseconds_after_process_epoch(); \ ++ if (prev == 0 || now - prev > (n)*1000) { \ ++ prev = now; \ ++ gpr_log(severity, format, __VA_ARGS__); \ ++ } \ ++ } while (0) ++ + namespace grpc_core { + + namespace time_detail { +diff --git a/src/core/lib/iomgr/tcp_server_posix.cc b/src/core/lib/iomgr/tcp_server_posix.cc +index 7ea6b3f4e9..48f712fd0e 100644 +--- a/src/core/lib/iomgr/tcp_server_posix.cc ++++ b/src/core/lib/iomgr/tcp_server_posix.cc +@@ -16,13 +16,17 @@ + * + */ + +-/* FIXME: "posix" files shouldn't be depending on _GNU_SOURCE */ ++#include ++ ++#include ++ ++#include ++ ++// FIXME: "posix" files shouldn't be depending on _GNU_SOURCE + #ifndef _GNU_SOURCE + #define _GNU_SOURCE + #endif + +-#include +- + #include "src/core/lib/iomgr/port.h" + + #ifdef GRPC_POSIX_SOCKET_TCP_SERVER +@@ -43,6 +47,9 @@ + #include "absl/strings/str_cat.h" + #include "absl/strings/str_format.h" + ++#include ++#include ++#include + #include + #include + #include +@@ -61,8 +68,11 @@ + #include "src/core/lib/iomgr/tcp_server_utils_posix.h" + #include "src/core/lib/iomgr/unix_sockets_posix.h" + #include "src/core/lib/resource_quota/api.h" ++#include "src/core/lib/transport/error_utils.h" + + static std::atomic num_dropped_connections{0}; ++static constexpr grpc_core::Duration kRetryAcceptWaitTime{ ++ grpc_core::Duration::Seconds(1)}; + + static grpc_error_handle tcp_server_create(grpc_closure* shutdown_complete, + const grpc_channel_args* args, +@@ -206,21 +216,37 @@ 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::ExecCtx::Get()->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", strerror(errno)); + } else { +- gpr_mu_lock(&sp->server->mu); +- if (!sp->server->shutdown_listeners) { +- gpr_log(GPR_ERROR, "Failed accept4: %s", strerror(errno)); +- } 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()) { +@@ -414,6 +440,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; + } +@@ -586,6 +613,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_FROM_STATIC_STRING("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 79527c2461..aaa9a1ae28 100644 +--- a/src/core/lib/iomgr/tcp_server_utils_posix.h ++++ b/src/core/lib/iomgr/tcp_server_utils_posix.h +@@ -25,6 +25,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 */ +@@ -47,6 +48,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 */ +@@ -126,4 +132,10 @@ grpc_error_handle grpc_tcp_server_prepare_socket( + /* Ruturn true if the platform supports ifaddrs */ + bool grpc_tcp_server_have_ifaddrs(void); + +-#endif /* GRPC_CORE_LIB_IOMGR_TCP_SERVER_UTILS_POSIX_H */ ++/* 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 549d01bff3..2dae238a76 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 + ++#include ++ + #include "src/core/lib/iomgr/port.h" + + #ifdef GRPC_POSIX_SOCKET_TCP_SERVER_UTILS_COMMON +@@ -80,6 +82,25 @@ 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 != GRPC_ERROR_NONE) return; ++ grpc_tcp_listener* listener = static_cast(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, +-- +2.32.0.3.g01195cf9f + diff --git a/grpc.spec b/grpc.spec index 31acf13..5e95587 100644 --- a/grpc.spec +++ b/grpc.spec @@ -1,4 +1,4 @@ -%define anolis_release 2 +%define anolis_release 3 %global cpp_std 17 %global gtest_url https://github.com/google/googletest @@ -124,6 +124,8 @@ Patch: grpc-1.48.0-python-grpcio_tests-DynamicStubTest-hang.patch Patch: %{forgeurl}/pull/31671.patch Patch: 0001-http2-Dont-drop-connections-on-metadata-limit-exceed.patch +Patch: 1000-backport-iomgr-EventEngine-Improve-server-handling-o.patch + Requires: grpc-data = %{version}-%{release} Provides: bundled(upb) Provides: bundled(utf8_range) @@ -209,8 +211,8 @@ For rendered HTML documentation, please see https://grpc.io/docs/. Summary: C++ language bindings for gRPC # License: same as base package -Requires: grpc%{?_isa} = %{version}-%{release} -Requires: grpc-cpp%{?_isa} = %{version}-%{release} +Requires: grpc = %{version}-%{release} +Requires: grpc-cpp = %{version}-%{release} Provides: bundled(upb) Provides: bundled(utf8_range) @@ -223,8 +225,8 @@ C++ language bindings for gRPC. Summary: Protocol buffers compiler plugins for gRPC # License: same as base package -Requires: grpc%{?_isa} = %{version}-%{release} -Requires: grpc-cpp%{?_isa} = %{version}-%{release} +Requires: grpc = %{version}-%{release} +Requires: grpc-cpp = %{version}-%{release} Requires: protobuf-compiler Provides: bundled(upb) @@ -238,8 +240,8 @@ Plugins to the protocol buffers compiler to generate gRPC sources. Summary: Command-line tool for gRPC # License: same as base package -Requires: grpc%{?_isa} = %{version}-%{release} -Requires: grpc-cpp%{?_isa} = %{version}-%{release} +Requires: grpc = %{version}-%{release} +Requires: grpc-cpp = %{version}-%{release} Provides: bundled(upb) Provides: bundled(utf8_range) @@ -261,13 +263,13 @@ The command line tool can do the following things: %package devel Summary: Development files for gRPC library -Requires: grpc%{?_isa} = %{version}-%{release} -Requires: grpc-cpp%{?_isa} = %{version}-%{release} -Requires: grpc-plugins%{?_isa} = %{version}-%{release} -Requires: kernel-headers%{?_isa} +Requires: grpc = %{version}-%{release} +Requires: grpc-cpp = %{version}-%{release} +Requires: grpc-plugins = %{version}-%{release} +Requires: kernel-headers Requires: pkgconfig(protobuf) Requires: pkgconfig(gmock) -Requires: abseil-cpp-devel%{?_isa} +Requires: abseil-cpp-devel Requires: pkgconfig(re2) Requires: cmake(c-ares) Requires: pkgconfig(zlib) @@ -811,6 +813,9 @@ hardlink -v '%{buildroot}%{_pkgdocdir}/examples/' %{python3_sitelib}/grpcio_testing-%{pyversion}-py%{python3_version}.egg-info/ %changelog +* Mon May 06 2024 Chunmei Xu - 1.48.4-3 +- fix CVE-2023-4785 + * Thu Dec 28 2023 Chunmei Xu - 1.48.4-2 - rebuild with protobuf-3.20.2 -- Gitee