Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(master) h2o: ABI-breaking patch for CVE-2023-44487, plus dnsdist bump #34

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libs/h2o/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk

PKG_NAME:=h2o
PKG_VERSION:=2.2.6
PKG_RELEASE:=14
PKG_RELEASE:=15

PKG_SOURCE_URL:=https://codeload.github.com/h2o/h2o/tar.gz/v${PKG_VERSION}?
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
Expand Down
203 changes: 203 additions & 0 deletions libs/h2o/patches/900-cve-2023-44487.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
commit d07b601a5549798f8e500582336756e04dfd25c5
Author: Remi Gacogne <[email protected]>
Date: Tue Oct 10 15:47:57 2023 +0200

[http2] delay processing requests upon observing suspicious behavior

Backport of 94fbc54b6c9309912fe3d53e7b63408bbe9a1b0d to v2.2.x

--- a/include/h2o.h
+++ b/include/h2o.h
@@ -378,6 +378,10 @@ struct st_h2o_globalconf_t {
* list of callbacks
*/
h2o_protocol_callbacks_t callbacks;
+ /**
+ * milliseconds to delay processing requests when suspicious behavior is detected
+ */
+ uint64_t dos_delay;
} http2;

struct {
@@ -590,6 +594,10 @@ struct st_h2o_context_t {
* timeout entry used for graceful shutdown
*/
h2o_timeout_entry_t _graceful_shutdown_timeout;
+ /*
+ * dos timeout
+ */
+ h2o_timeout_t dos_delay_timeout;
struct {
/**
* counter for http2 errors internally emitted by h2o
--- a/include/h2o/http2_internal.h
+++ b/include/h2o/http2_internal.h
@@ -179,6 +179,7 @@ struct st_h2o_http2_stream_t {
h2o_linklist_t link;
h2o_http2_scheduler_openref_t scheduler;
} _refs;
+ unsigned reset_by_peer : 1;
h2o_send_state_t send_state; /* state of the ostream, only used in push mode */
/* placed at last since it is large and has it's own ctor */
h2o_req_t req;
@@ -232,6 +233,13 @@ struct st_h2o_http2_conn_t {
} _write;
h2o_cache_t *push_memo;
h2o_http2_casper_t *casper;
+ /**
+ * DoS mitigation; the idea here is to delay processing requests when observing suspicious behavior
+ */
+ struct {
+ h2o_timeout_entry_t process_delay;
+ size_t reset_budget; /* RST_STREAM frames are considered suspicious when this value goes down to zero */
+ } dos_mitigation;
};

int h2o_http2_update_peer_settings(h2o_http2_settings_t *settings, const uint8_t *src, size_t len, const char **err_desc);
--- a/lib/core/config.c
+++ b/lib/core/config.c
@@ -196,6 +196,7 @@ void h2o_config_init(h2o_globalconf_t *c
config->http2.latency_optimization.min_rtt = 50; // milliseconds
config->http2.latency_optimization.max_additional_delay = 10;
config->http2.latency_optimization.max_cwnd = 65535;
+ config->http2.dos_delay = 100; /* 100ms processing delay when observing suspicious behavior */
config->http2.callbacks = H2O_HTTP2_CALLBACKS;
// config->mimemap = h2o_mimemap_create();

--- a/lib/core/configurator.c
+++ b/lib/core/configurator.c
@@ -531,6 +531,12 @@ static int on_config_http2_casper(h2o_co
return 0;
}

+
+static int on_config_http2_dos_delay(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node)
+{
+ return config_timeout(cmd, node, &ctx->globalconf->http2.dos_delay);
+}
+
static int assert_is_mimetype(h2o_configurator_command_t *cmd, yoml_t *node)
{
if (node->type != YOML_TYPE_SCALAR) {
@@ -910,6 +916,9 @@ void h2o_configurator__init_core(h2o_glo
on_config_http2_push_preload);
h2o_configurator_define_command(&c->super, "http2-casper", H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_HOST,
on_config_http2_casper);
+ h2o_configurator_define_command(&c->super, "http2-dos-delay",
+ H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR,
+ on_config_http2_dos_delay);
h2o_configurator_define_command(&c->super, "file.mime.settypes",
(H2O_CONFIGURATOR_FLAG_ALL_LEVELS & ~H2O_CONFIGURATOR_FLAG_EXTENSION) |
H2O_CONFIGURATOR_FLAG_EXPECT_MAPPING,
--- a/lib/core/context.c
+++ b/lib/core/context.c
@@ -101,6 +101,7 @@ void h2o_context_init(h2o_context_t *ctx
h2o_linklist_init_anchor(&ctx->http1._conns);
h2o_timeout_init(ctx->loop, &ctx->http2.idle_timeout, config->http2.idle_timeout);
h2o_timeout_init(ctx->loop, &ctx->http2.graceful_shutdown_timeout, config->http2.graceful_shutdown_timeout);
+ h2o_timeout_init(ctx->loop, &ctx->http2.dos_delay_timeout, config->http2.dos_delay);
h2o_linklist_init_anchor(&ctx->http2._conns);
ctx->proxy.client_ctx.loop = loop;
h2o_timeout_init(ctx->loop, &ctx->proxy.io_timeout, config->proxy.io_timeout);
@@ -146,6 +147,7 @@ void h2o_context_dispose(h2o_context_t *
h2o_timeout_dispose(ctx->loop, &ctx->http1.req_timeout);
h2o_timeout_dispose(ctx->loop, &ctx->http2.idle_timeout);
h2o_timeout_dispose(ctx->loop, &ctx->http2.graceful_shutdown_timeout);
+ h2o_timeout_dispose(ctx->loop, &ctx->http2.dos_delay_timeout);
h2o_timeout_dispose(ctx->loop, &ctx->proxy.io_timeout);
/* what should we do here? assert(!h2o_linklist_is_empty(&ctx->http2._conns); */

--- a/lib/http2/connection.c
+++ b/lib/http2/connection.c
@@ -161,7 +161,6 @@ static void update_idle_timeout(h2o_http
h2o_timeout_unlink(&conn->_timeout_entry);

if (conn->num_streams.pull.half_closed + conn->num_streams.push.half_closed == 0) {
- assert(h2o_linklist_is_empty(&conn->_pending_reqs));
conn->_timeout_entry.cb = on_idle_timeout;
h2o_timeout_link(conn->super.ctx->loop, &conn->super.ctx->http2.idle_timeout, &conn->_timeout_entry);
}
@@ -175,6 +174,9 @@ static int can_run_requests(h2o_http2_co

static void run_pending_requests(h2o_http2_conn_t *conn)
{
+ if (h2o_timeout_is_linked(&conn->dos_mitigation.process_delay))
+ return;
+
while (!h2o_linklist_is_empty(&conn->_pending_reqs) && can_run_requests(conn)) {
/* fetch and detach a pending stream */
h2o_http2_stream_t *stream = H2O_STRUCT_FROM_MEMBER(h2o_http2_stream_t, _refs.link, conn->_pending_reqs.next);
@@ -226,6 +228,16 @@ void h2o_http2_conn_unregister_stream(h2
assert(h2o_http2_scheduler_is_open(&stream->_refs.scheduler));
h2o_http2_scheduler_close(&stream->_refs.scheduler);

+ /* Decrement reset_budget if the stream was reset by peer, otherwise increment. By doing so, we penalize connections that
+ * generate resets for >50% of requests. */
+ if (stream->reset_by_peer) {
+ if (conn->dos_mitigation.reset_budget > 0)
+ --conn->dos_mitigation.reset_budget;
+ } else {
+ if (conn->dos_mitigation.reset_budget < conn->super.ctx->globalconf->http2.max_concurrent_requests_per_connection)
+ ++conn->dos_mitigation.reset_budget;
+ }
+
switch (stream->state) {
case H2O_HTTP2_STREAM_STATE_IDLE:
case H2O_HTTP2_STREAM_STATE_RECV_HEADERS:
@@ -272,6 +284,8 @@ void close_connection_now(h2o_http2_conn
h2o_hpack_dispose_header_table(&conn->_output_header_table);
assert(h2o_linklist_is_empty(&conn->_pending_reqs));
h2o_timeout_unlink(&conn->_timeout_entry);
+ if (h2o_timeout_is_linked(&conn->dos_mitigation.process_delay))
+ h2o_timeout_unlink(&conn->dos_mitigation.process_delay);
h2o_buffer_dispose(&conn->_write.buf);
if (conn->_write.buf_in_flight != NULL)
h2o_buffer_dispose(&conn->_write.buf_in_flight);
@@ -797,11 +811,19 @@ static int handle_rst_stream_frame(h2o_h
return H2O_HTTP2_ERROR_PROTOCOL;
}

- stream = h2o_http2_conn_get_stream(conn, frame->stream_id);
- if (stream != NULL) {
+ if ((stream = h2o_http2_conn_get_stream(conn, frame->stream_id)) == NULL)
+ return 0;
+
/* reset the stream */
+ stream->reset_by_peer = 1;
h2o_http2_stream_reset(conn, stream);
- }
+
+ /* setup process delay if we've just ran out of reset budget */
+ if (conn->dos_mitigation.reset_budget == 0 && conn->super.ctx->globalconf->http2.dos_delay != 0 &&
+ !h2o_timeout_is_linked(&conn->dos_mitigation.process_delay))
+ h2o_timeout_link(conn->super.ctx->loop, &conn->super.ctx->http2.dos_delay_timeout,
+ &conn->dos_mitigation.process_delay);
+
/* TODO log */

return 0;
@@ -1204,6 +1226,14 @@ static h2o_iovec_t log_priority_actual_w
return h2o_iovec_init(s, len);
}

+static void on_dos_process_delay(h2o_timeout_entry_t *timer)
+{
+ h2o_http2_conn_t *conn = H2O_STRUCT_FROM_MEMBER(h2o_http2_conn_t, dos_mitigation.process_delay, timer);
+
+ assert(!h2o_timeout_is_linked(&conn->dos_mitigation.process_delay));
+ run_pending_requests(conn);
+}
+
static h2o_http2_conn_t *create_conn(h2o_context_t *ctx, h2o_hostconf_t **hosts, h2o_socket_t *sock, struct timeval connected_at)
{
static const h2o_conn_callbacks_t callbacks = {
@@ -1240,6 +1270,9 @@ static h2o_http2_conn_t *create_conn(h2o
conn->_write.timeout_entry.cb = emit_writereq;
h2o_http2_window_init(&conn->_write.window, &conn->peer_settings);

+ conn->dos_mitigation.process_delay.cb = on_dos_process_delay;
+ conn->dos_mitigation.reset_budget = conn->super.ctx->globalconf->http2.max_concurrent_requests_per_connection;
+
return conn;
}

35 changes: 35 additions & 0 deletions libs/h2o/patches/901-bump-soname.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
commit e47cd15ff1fec9211088c809cb92593800dd4da2
Author: Peter van Dijk <[email protected]>
Date: Wed Oct 11 11:39:48 2023 +0200

bump soname

--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -29,9 +29,9 @@ SET(VERSION_MINOR "2")
SET(VERSION_PATCH "6")
SET(VERSION_PRERELEASE "")
SET(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}${VERSION_PRERELEASE}")
-SET(LIBRARY_VERSION_MAJOR "0")
-SET(LIBRARY_VERSION_MINOR "13")
-SET(LIBRARY_VERSION_PATCH "6")
+SET(LIBRARY_VERSION_MAJOR "1")
+SET(LIBRARY_VERSION_MINOR "0")
+SET(LIBRARY_VERSION_PATCH "0")
SET(LIBRARY_VERSION "${LIBRARY_VERSION_MAJOR}.${LIBRARY_VERSION_MINOR}.${LIBRARY_VERSION_PATCH}${VERSION_PRERELEASE}")
SET(LIBRARY_SOVERSION "${LIBRARY_VERSION_MAJOR}.${LIBRARY_VERSION_MINOR}")

--- a/include/h2o/version.h
+++ b/include/h2o/version.h
@@ -28,8 +28,8 @@
#define H2O_VERSION_MINOR 2
#define H2O_VERSION_PATCH 6

-#define H2O_LIBRARY_VERSION_MAJOR 0
-#define H2O_LIBRARY_VERSION_MINOR 13
-#define H2O_LIBRARY_VERSION_PATCH 6
+#define H2O_LIBRARY_VERSION_MAJOR 1
+#define H2O_LIBRARY_VERSION_MINOR 0
+#define H2O_LIBRARY_VERSION_PATCH 0

#endif
4 changes: 2 additions & 2 deletions net/dnsdist/Makefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
include $(TOPDIR)/rules.mk

PKG_NAME:=dnsdist
PKG_VERSION:=1.8.1
PKG_VERSION:=1.8.2
PKG_RELEASE:=1

PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
PKG_SOURCE_URL:=https://downloads.powerdns.com/releases/
PKG_HASH:=05f356fcce29c4ece03c2d8df046adff3aaab0b036d6801c1a311c6d5bb3c07f
PKG_HASH:=6688f09b2c52f9bf935f0769f4ee28dd0760e5622dade7b3f4e6fa3776f07ab8

PKG_MAINTAINER:=Peter van Dijk <[email protected]>
PKG_LICENSE:=GPL-2.0-only
Expand Down
Loading